From bdb764fc13a2d5f71bc1b98a4297f6ec92c84011 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Wed, 31 Mar 2021 15:14:58 +0700 Subject: [PATCH] use license free codecs for html5ify --- src/App.jsx | 10 ++++++---- src/ffmpeg.js | 10 +++++----- src/hooks/useFfmpegOperations.js | 30 +++++++++++++++++++++--------- src/util.js | 1 + 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 5b03c679..2d3d07d0 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -52,7 +52,7 @@ import { getOutPath, toast, errorToast, showFfmpegFail, setFileNameTitle, getOutDir, withBlur, checkDirWriteAccess, dirExists, openDirToast, isMasBuild, isStoreBuild, dragPreventer, doesPlayerSupportFile, isDurationValid, isWindows, filenamify, getOutFileExtension, generateSegFileName, defaultOutSegTemplate, - hasDuplicates, havePermissionToReadFile, + hasDuplicates, havePermissionToReadFile, isMac, } from './util'; import { formatDuration } from './util/duration'; import { askForOutDir, askForImportChapters, createNumSegments, createFixedDurationSegments, promptTimeOffset, askForHtml5ifySpeed, askForYouTubeInput, askForFileOpenAction, confirmExtractAllStreamsDialog, cleanupFilesDialog, showDiskFull, showCutFailedDialog, labelSegmentDialog, openYouTubeChaptersDialog, showMergeDialog, showOpenAndMergeDialog, openAbout } from './dialogs'; @@ -1126,7 +1126,8 @@ const App = memo(() => { }, [playing, canvasPlayerEnabled]); const getHtml5ifiedPath = useCallback((cod, fp, type) => { - const ext = type === 'fastest-audio' ? 'mkv' : 'mp4'; + // See also inside ffmpegHtml5ify + const ext = (isMac && ['slowest', 'slow', 'slow-audio'].includes(type)) ? 'mp4' : 'mkv'; return getOutPath(cod, fp, `html5ified-${type}.${ext}`); }, []); @@ -1569,9 +1570,9 @@ const App = memo(() => { let audio; if (ha) { if (speed === 'slowest') audio = 'hq'; - else if (speed === 'slow-audio') audio = 'lq-aac'; + else if (speed === 'slow-audio') audio = 'lq'; else if (speed === 'fast-audio') audio = 'copy'; - else if (speed === 'fastest-audio') audio = 'lq-flac'; + else if (speed === 'fastest-audio') audio = 'silent-audio'; } let video; @@ -1961,6 +1962,7 @@ const App = memo(() => { // if (isDev) load({ filePath: '/Users/mifi/Downloads/inp.MOV', customOutDir }); }, []); + // TODO fastest-audio shows muted const VolumeIcon = muted || dummyVideoPath ? FaVolumeMute : FaVolumeUp; useEffect(() => { diff --git a/src/ffmpeg.js b/src/ffmpeg.js index 48f1c66e..a21f966b 100644 --- a/src/ffmpeg.js +++ b/src/ffmpeg.js @@ -5,7 +5,7 @@ import moment from 'moment'; import i18n from 'i18next'; import Timecode from 'smpte-timecode'; -import { getOutPath, isDurationValid, getExtensionForFormat } from './util'; +import { getOutPath, isDurationValid, getExtensionForFormat, isMac, isWindows } from './util'; const execa = window.require('execa'); const { join } = window.require('path'); @@ -13,7 +13,6 @@ const fileType = window.require('file-type'); const readChunk = window.require('read-chunk'); const readline = window.require('readline'); const isDev = window.require('electron-is-dev'); -const os = window.require('os'); export function getFfCommandLine(cmd, args) { @@ -22,13 +21,14 @@ export function getFfCommandLine(cmd, args) { } function getFfPath(cmd) { - const platform = os.platform(); + // Testing non-mac setup on mac: + // return `node_modules/ffmpeg-ffprobe-static/${cmd}`; - if (platform === 'darwin') { + if (isMac) { return isDev ? `ffmpeg-mac/${cmd}` : join(window.process.resourcesPath, cmd); } - const exeName = platform === 'win32' ? `${cmd}.exe` : cmd; + const exeName = isWindows ? `${cmd}.exe` : cmd; return isDev ? `node_modules/ffmpeg-ffprobe-static/${exeName}` : join(window.process.resourcesPath, `node_modules/ffmpeg-ffprobe-static/${exeName}`); diff --git a/src/hooks/useFfmpegOperations.js b/src/hooks/useFfmpegOperations.js index c852fc07..509ff8f5 100644 --- a/src/hooks/useFfmpegOperations.js +++ b/src/hooks/useFfmpegOperations.js @@ -4,11 +4,10 @@ import flatMapDeep from 'lodash/flatMapDeep'; import sum from 'lodash/sum'; import pMap from 'p-map'; -import { getOutPath, transferTimestamps, getOutFileExtension, getOutDir } from '../util'; +import { getOutPath, transferTimestamps, getOutFileExtension, getOutDir, isMac } from '../util'; import { isCuttingStart, isCuttingEnd, handleProgress, getFfCommandLine, getFfmpegPath, getDuration, runFfmpeg, createChaptersFromSegments } from '../ffmpeg'; const execa = window.require('execa'); -const os = window.require('os'); const { join } = window.require('path'); const fs = window.require('fs-extra'); const stringToStream = window.require('string-to-stream'); @@ -268,14 +267,19 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) { let videoArgs; let audioArgs; - const isMac = os.platform() === 'darwin'; + // h264/aac_at: No licensing when using HW encoder (Video/Audio Toolbox on Mac) + // https://github.com/mifi/lossless-cut/issues/372#issuecomment-810766512 switch (video) { case 'hq': { if (isMac) { videoArgs = ['-vf', 'format=yuv420p', '-allow_sw', '1', '-vcodec', 'h264', '-b:v', '15M']; } else { - videoArgs = ['-vf', 'format=yuv420p', '-vcodec', 'libx264', '-profile:v', 'high', '-preset:v', 'slow', '-crf', '17']; + // AV1 is very slow + // videoArgs = ['-vf', 'scale=-2:400,format=yuv420p', '-sws_flags', 'neighbor', '-vcodec', 'libaom-av1', '-crf', '30', '-cpu-used', '8']; + // Theora is a bit faster but not that much + // videoArgs = ['-vf', '-c:v', 'libtheora', '-qscale:v', '1']; + videoArgs = ['-vf', 'format=yuv420p', '-c:v', 'libvpx-vp9', '-crf', '30', '-b:v', '0', '-row-mt', '1']; } break; } @@ -283,7 +287,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) { if (isMac) { videoArgs = ['-vf', 'scale=-2:400,format=yuv420p', '-allow_sw', '1', '-sws_flags', 'lanczos', '-vcodec', 'h264', '-b:v', '1500k']; } else { - videoArgs = ['-vf', 'scale=-2:400,format=yuv420p', '-sws_flags', 'neighbor', '-vcodec', 'libx264', '-profile:v', 'baseline', '-x264opts', 'level=3.0', '-preset:v', 'ultrafast', '-crf', '28']; + videoArgs = ['-vf', 'scale=-2:400,format=yuv420p', '-sws_flags', 'neighbor', '-c:v', 'libtheora', '-qscale:v', '1']; } break; } @@ -298,15 +302,23 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) { switch (audio) { case 'hq': { - audioArgs = ['-acodec', 'aac', '-b:a', '192k']; + if (isMac) { + audioArgs = ['-acodec', 'aac_at', '-b:a', '192k']; + } else { + audioArgs = ['-acodec', 'flac']; + } break; } - case 'lq-flac': { + case 'silent-audio': { audioArgs = ['-acodec', 'flac', '-ar', '11025', '-ac', '2']; break; } - case 'lq-aac': { - audioArgs = ['-acodec', 'aac', '-ar', '44100', '-ac', '2', '-b:a', '96k']; + case 'lq': { + if (isMac) { + audioArgs = ['-acodec', 'aac_at', '-ar', '44100', '-ac', '2', '-b:a', '96k']; + } else { + audioArgs = ['-acodec', 'flac', '-ar', '11025', '-ac', '2']; + } break; } case 'copy': { diff --git a/src/util.js b/src/util.js index d21a447f..ce7a4f69 100644 --- a/src/util.js +++ b/src/util.js @@ -120,6 +120,7 @@ export const isDurationValid = (duration) => Number.isFinite(duration) && durati const platform = os.platform(); export const isWindows = platform === 'win32'; +export const isMac = platform === 'darwin'; export function getExtensionForFormat(format) { const ext = {