From 4a20c1ac009b5ca23e6cf46cca42f8d62b334c64 Mon Sep 17 00:00:00 2001 From: Mikael Finstad Date: Sun, 17 May 2020 20:24:44 +0800 Subject: [PATCH] Add experimental flag setting #336 --- public/configStore.js | 1 + src/App.jsx | 14 ++++++++++---- src/HelpSheet.jsx | 3 ++- src/Settings.jsx | 13 ++++++++++++- src/ffmpeg.js | 17 ++++++++++++----- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/public/configStore.js b/public/configStore.js index 9f9e2f7f..f0ed4654 100644 --- a/public/configStore.js +++ b/public/configStore.js @@ -14,6 +14,7 @@ const defaults = { autoSaveProjectFile: true, wheelSensitivity: 0.2, language: undefined, + ffmpegExperimental: false, }, }; diff --git a/src/App.jsx b/src/App.jsx index 92906b7c..335bfa4f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -223,6 +223,8 @@ const App = memo(() => { useEffect(() => safeSetConfig('invertTimelineScroll', invertTimelineScroll), [invertTimelineScroll]); const [language, setLanguage] = useState(configStore.get('language')); useEffect(() => safeSetConfig('language', language), [language]); + const [ffmpegExperimental, setFfmpegExperimental] = useState(configStore.get('ffmpegExperimental')); + useEffect(() => safeSetConfig('ffmpegExperimental', ffmpegExperimental), [ffmpegExperimental]); useEffect(() => { i18n.changeLanguage(language || fallbackLng).catch(console.error); @@ -633,7 +635,7 @@ const App = memo(() => { const outPath = getOutPath(newCustomOutDir, firstPath, `merged${ext}`); // console.log('merge', paths); - await ffmpegMergeFiles({ paths, outPath, allStreams, onProgress: setCutProgress }); + await ffmpegMergeFiles({ paths, outPath, allStreams, ffmpegExperimental, onProgress: setCutProgress }); openDirToast({ icon: 'success', dirPath: outputDir, text: i18n.t('Files merged!') }); } catch (err) { errorToast(i18n.t('Failed to merge files. Make sure they are all of the exact same codecs')); @@ -642,7 +644,7 @@ const App = memo(() => { setWorking(); setCutProgress(); } - }, [assureOutDirAccess, outputDir]); + }, [assureOutDirAccess, outputDir, ffmpegExperimental]); const toggleCaptureFormat = useCallback(() => setCaptureFormat(f => (f === 'png' ? 'jpeg' : 'png')), []); const toggleKeyframeCut = useCallback(() => setKeyframeCut((val) => { @@ -1009,6 +1011,7 @@ const App = memo(() => { onProgress: setCutProgress, appendFfmpegCommandLog, shortestFlag, + ffmpegExperimental, }); if (outFiles.length > 1 && autoMerge) { @@ -1021,6 +1024,7 @@ const App = memo(() => { outFormat: fileFormat, isCustomFormatSelected, segmentPaths: outFiles, + ffmpegExperimental, onProgress: setCutProgress, }); } @@ -1059,7 +1063,7 @@ const App = memo(() => { working, duration, filePath, keyframeCut, autoMerge, customOutDir, fileFormat, haveInvalidSegs, copyFileStreams, numStreamsToCopy, exportExtraStreams, nonCopiedExtraStreams, outputDir, shortestFlag, isCustomFormatSelected, - fileFormatData, mainStreams, + fileFormatData, mainStreams, ffmpegExperimental, ]); const capture = useCallback(async () => { @@ -1718,6 +1722,8 @@ const App = memo(() => { setTimecodeShowFrames={setTimecodeShowFrames} askBeforeClose={askBeforeClose} setAskBeforeClose={setAskBeforeClose} + ffmpegExperimental={ffmpegExperimental} + setFfmpegExperimental={setFfmpegExperimental} invertTimelineScroll={invertTimelineScroll} setInvertTimelineScroll={setInvertTimelineScroll} language={language} @@ -1728,7 +1734,7 @@ const App = memo(() => { renderCaptureFormatButton={renderCaptureFormatButton} onWheelTunerRequested={onWheelTunerRequested} /> - ), [AutoExportToggler, askBeforeClose, autoMerge, autoSaveProjectFile, customOutDir, invertCutSegments, keyframeCut, renderCaptureFormatButton, renderOutFmt, timecodeShowFrames, changeOutDir, onWheelTunerRequested, language, invertTimelineScroll]); + ), [AutoExportToggler, askBeforeClose, autoMerge, autoSaveProjectFile, customOutDir, invertCutSegments, keyframeCut, renderCaptureFormatButton, renderOutFmt, timecodeShowFrames, changeOutDir, onWheelTunerRequested, language, invertTimelineScroll, ffmpegExperimental, setFfmpegExperimental]); useEffect(() => { if (!isStoreBuild) loadMifiLink().then(setMifiLink); diff --git a/src/HelpSheet.jsx b/src/HelpSheet.jsx index b70ae7cf..d10059ce 100644 --- a/src/HelpSheet.jsx +++ b/src/HelpSheet.jsx @@ -37,7 +37,8 @@ const HelpSheet = memo(({
  • Try both Keyframe cut and Normal cut modes
  • Try to set the start-cutpoint a few frames before or after the nearest keyframe (may also solve audio sync issues)
  • Try to disable some Tracks
  • -
  • Try a different output format
  • +
  • Try a different Output format
  • +
  • Try to enable the Experimental Flag in Settings
  • diff --git a/src/Settings.jsx b/src/Settings.jsx index b097ea0b..0c380341 100644 --- a/src/Settings.jsx +++ b/src/Settings.jsx @@ -7,7 +7,7 @@ const Settings = memo(({ changeOutDir, customOutDir, autoMerge, setAutoMerge, keyframeCut, setKeyframeCut, invertCutSegments, setInvertCutSegments, autoSaveProjectFile, setAutoSaveProjectFile, timecodeShowFrames, setTimecodeShowFrames, askBeforeClose, setAskBeforeClose, renderOutFmt, AutoExportToggler, renderCaptureFormatButton, onWheelTunerRequested, language, setLanguage, - invertTimelineScroll, setInvertTimelineScroll, + invertTimelineScroll, setInvertTimelineScroll, ffmpegExperimental, setFfmpegExperimental, }) => { const { t } = useTranslation(); @@ -113,6 +113,17 @@ const Settings = memo(({ + + {t('Enable experimental ffmpeg features flag?')} + + setFfmpegExperimental(e.target.checked)} + /> + + + {t('Auto save project file?')}
    diff --git a/src/ffmpeg.js b/src/ffmpeg.js index 17d2e881..2d1c11f6 100644 --- a/src/ffmpeg.js +++ b/src/ffmpeg.js @@ -205,7 +205,7 @@ function getMovFlags(outFormat) { } async function cut({ - filePath, outFormat, cutFrom, cutTo, videoDuration, rotation, + filePath, outFormat, cutFrom, cutTo, videoDuration, rotation, ffmpegExperimental, onProgress, copyFileStreams, keyframeCut, outPath, appendFfmpegCommandLog, shortestFlag, }) { const cuttingStart = isCuttingStart(cutFrom); @@ -253,6 +253,9 @@ async function cut({ // See https://github.com/mifi/lossless-cut/issues/170 '-ignore_unknown', + // https://superuser.com/questions/543589/information-about-ffmpeg-command-line-options + ...(ffmpegExperimental ? ['-strict', 'experimental'] : []), + ...rotationArgs, '-f', outFormat, '-y', outPath, @@ -279,7 +282,7 @@ function getOutFileExtension({ isCustomFormatSelected, outFormat, filePath }) { export async function cutMultiple({ customOutDir, filePath, segments: segmentsUnsorted, videoDuration, rotation, onProgress, keyframeCut, copyFileStreams, outFormat, isCustomFormatSelected, - appendFfmpegCommandLog, shortestFlag, + appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, }) { const segments = sortBy(segmentsUnsorted, 'cutFrom'); const singleProgresses = {}; @@ -317,6 +320,7 @@ export async function cutMultiple({ // eslint-disable-next-line no-loop-func onProgress: progress => onSingleProgress(i, progress), appendFfmpegCommandLog, + ffmpegExperimental, }); outFiles.push(outPath); @@ -435,7 +439,7 @@ export async function html5ifyDummy(filePath, outPath, onProgress) { await transferTimestamps(filePath, outPath); } -export async function mergeFiles({ paths, outPath, allStreams, outFormat, onProgress = () => {} }) { +export async function mergeFiles({ paths, outPath, allStreams, outFormat, ffmpegExperimental, onProgress = () => {} }) { console.log('Merging files', { paths }, 'to', outPath); const durations = await pMap(paths, getDuration, { concurrency: 1 }); @@ -458,6 +462,9 @@ export async function mergeFiles({ paths, outPath, allStreams, outFormat, onProg // See https://github.com/mifi/lossless-cut/issues/170 '-ignore_unknown', + // https://superuser.com/questions/543589/information-about-ffmpeg-command-line-options + ...(ffmpegExperimental ? ['-strict', 'experimental'] : []), + ...(outFormat ? ['-f', outFormat] : []), '-y', outPath, ]; @@ -480,12 +487,12 @@ export async function mergeFiles({ paths, outPath, allStreams, outFormat, onProg console.log(result.stdout); } -export async function autoMergeSegments({ customOutDir, sourceFile, isCustomFormatSelected, outFormat, segmentPaths, onProgress }) { +export async function autoMergeSegments({ customOutDir, sourceFile, isCustomFormatSelected, outFormat, segmentPaths, ffmpegExperimental, onProgress }) { const ext = getOutFileExtension({ isCustomFormatSelected, outFormat, filePath: sourceFile }); const fileName = `cut-merged-${new Date().getTime()}${ext}`; const outPath = getOutPath(customOutDir, sourceFile, fileName); - await mergeFiles({ paths: segmentPaths, outPath, outFormat, allStreams: true, onProgress }); + await mergeFiles({ paths: segmentPaths, outPath, outFormat, allStreams: true, ffmpegExperimental, onProgress }); await pMap(segmentPaths, path => fs.unlink(path), { concurrency: 5 }); }