mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-21 09:52:33 +01:00
allow customising preservation
of map_metadata and chapters fixes #2176 see #1027
This commit is contained in:
parent
789f857e26
commit
8024884363
@ -106,6 +106,9 @@ const defaults: Config = {
|
||||
wheelSensitivity: 0.2,
|
||||
language: undefined,
|
||||
ffmpegExperimental: false,
|
||||
preserveChapters: true,
|
||||
preserveMetadata: 'default',
|
||||
preserveMetadataOnMerge: false,
|
||||
preserveMovData: false,
|
||||
movFastStart: true,
|
||||
avoidNegativeTs: 'make_zero',
|
||||
@ -113,7 +116,6 @@ const defaults: Config = {
|
||||
hideOsNotifications: undefined,
|
||||
autoLoadTimecode: false,
|
||||
segmentsToChapters: false,
|
||||
preserveMetadataOnMerge: false,
|
||||
simpleMode: true,
|
||||
outSegTemplate: undefined,
|
||||
mergedFileTemplate: undefined,
|
||||
|
@ -171,7 +171,7 @@ function App() {
|
||||
const allUserSettings = useUserSettingsRoot();
|
||||
|
||||
const {
|
||||
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMovData, setPreserveMovData, movFastStart, setMovFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, hideOsNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, mergedFileTemplate, setMergedFileTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, mouseWheelFrameSeekModifierKey, mouseWheelKeyframeSeekModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames,
|
||||
captureFormat, setCaptureFormat, customOutDir, setCustomOutDir, keyframeCut, setKeyframeCut, preserveMetadata, preserveChapters, preserveMovData, movFastStart, avoidNegativeTs, autoMerge, timecodeFormat, invertCutSegments, setInvertCutSegments, autoExportExtraStreams, askBeforeClose, enableAskForImportChapters, enableAskForFileOpenAction, playbackVolume, setPlaybackVolume, autoSaveProjectFile, wheelSensitivity, invertTimelineScroll, language, ffmpegExperimental, hideNotifications, hideOsNotifications, autoLoadTimecode, autoDeleteMergedSegments, exportConfirmEnabled, setExportConfirmEnabled, segmentsToChapters, preserveMetadataOnMerge, simpleMode, setSimpleMode, outSegTemplate, setOutSegTemplate, mergedFileTemplate, setMergedFileTemplate, keyboardSeekAccFactor, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart, outFormatLocked, setOutFormatLocked, safeOutputFileName, setSafeOutputFileName, enableAutoHtml5ify, segmentsToChaptersOnly, keyBindings, setKeyBindings, resetKeyBindings, enableSmartCut, customFfPath, storeProjectInWorkingDir, setStoreProjectInWorkingDir, enableOverwriteOutput, mouseWheelZoomModifierKey, mouseWheelFrameSeekModifierKey, mouseWheelKeyframeSeekModifierKey, captureFrameMethod, captureFrameQuality, captureFrameFileNameFormat, enableNativeHevc, cleanupChoices, setCleanupChoices, darkMode, setDarkMode, preferStrongColors, outputFileNameMinZeroPadding, cutFromAdjustmentFrames,
|
||||
} = allUserSettings;
|
||||
|
||||
const { working, setWorking, workingRef, abortWorking } = useLoading();
|
||||
@ -238,10 +238,6 @@ function App() {
|
||||
return newVal;
|
||||
}), [setExportConfirmEnabled, showNotification]);
|
||||
|
||||
const toggleSegmentsToChapters = useCallback(() => setSegmentsToChapters((v) => !v), [setSegmentsToChapters]);
|
||||
|
||||
const togglePreserveMetadataOnMerge = useCallback(() => setPreserveMetadataOnMerge((v) => !v), [setPreserveMetadataOnMerge]);
|
||||
|
||||
const toggleShowKeyframes = useCallback(() => {
|
||||
setKeyframesEnabled((old) => {
|
||||
const enabled = !old;
|
||||
@ -429,10 +425,6 @@ function App() {
|
||||
return newVal;
|
||||
}), [showNotification, setKeyframeCut]);
|
||||
|
||||
const togglePreserveMovData = useCallback(() => setPreserveMovData((val) => !val), [setPreserveMovData]);
|
||||
|
||||
const toggleMovFastStart = useCallback(() => setMovFastStart((val) => !val), [setMovFastStart]);
|
||||
|
||||
const toggleSimpleMode = useCallback(() => setSimpleMode((v) => {
|
||||
showNotification({ text: v ? i18n.t('Advanced view has been enabled. You will now also see non-essential buttons and functions') : i18n.t('Advanced view disabled. You will now see only the most essential buttons and functions') });
|
||||
const newValue = !v;
|
||||
@ -477,8 +469,8 @@ function App() {
|
||||
}, [ensureAccessToSourceDir, getProjectFileSavePath, setStoreProjectInWorkingDir, storeProjectInWorkingDir]);
|
||||
|
||||
const userSettingsContext = useMemo<UserSettingsContextType>(() => ({
|
||||
...allUserSettings, toggleCaptureFormat, changeOutDir, toggleKeyframeCut, togglePreserveMovData, toggleMovFastStart, toggleExportConfirmEnabled, toggleSegmentsToChapters, togglePreserveMetadataOnMerge, toggleSimpleMode, toggleSafeOutputFileName, effectiveExportMode,
|
||||
}), [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleMovFastStart, togglePreserveMetadataOnMerge, togglePreserveMovData, toggleSafeOutputFileName, toggleSegmentsToChapters, toggleSimpleMode]);
|
||||
...allUserSettings, toggleCaptureFormat, changeOutDir, toggleKeyframeCut, toggleExportConfirmEnabled, toggleSimpleMode, toggleSafeOutputFileName, effectiveExportMode,
|
||||
}), [allUserSettings, changeOutDir, effectiveExportMode, toggleCaptureFormat, toggleExportConfirmEnabled, toggleKeyframeCut, toggleSafeOutputFileName, toggleSimpleMode]);
|
||||
|
||||
const segColorsContext = useMemo(() => ({
|
||||
getSegColor: (seg: SegmentColorIndex) => {
|
||||
@ -804,10 +796,12 @@ function App() {
|
||||
effectiveExportMode,
|
||||
outSegTemplate,
|
||||
mergedFileTemplate,
|
||||
preserveMetadata,
|
||||
preserveChapters,
|
||||
};
|
||||
|
||||
openSendReportDialog(err, state);
|
||||
}, [commonSettings, copyStreamIdsByFile, cutSegments, effectiveExportMode, externalFilesMeta, fileFormat, filePath, mainFileFormatData, mainStreams, mergedFileTemplate, outSegTemplate, rotation, shortestFlag]);
|
||||
}, [commonSettings, copyStreamIdsByFile, cutSegments, effectiveExportMode, externalFilesMeta, fileFormat, filePath, mainFileFormatData, mainStreams, mergedFileTemplate, outSegTemplate, preserveChapters, preserveMetadata, rotation, shortestFlag]);
|
||||
|
||||
const openSendConcatReportDialogWithState = useCallback(async (err: unknown, reportState?: object) => {
|
||||
const state = { ...commonSettings, ...reportState };
|
||||
@ -1025,8 +1019,10 @@ function App() {
|
||||
onProgress: setProgress,
|
||||
shortestFlag,
|
||||
ffmpegExperimental,
|
||||
preserveMovData,
|
||||
preserveMetadata,
|
||||
preserveMetadataOnMerge,
|
||||
preserveMovData,
|
||||
preserveChapters,
|
||||
movFastStart,
|
||||
avoidNegativeTs,
|
||||
customTagsByFile,
|
||||
@ -1134,7 +1130,7 @@ function App() {
|
||||
setWorking(undefined);
|
||||
setProgress(undefined);
|
||||
}
|
||||
}, [filePath, numStreamsToCopy, segmentsToExport, haveInvalidSegs, workingRef, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, cutMultiple, outputDir, customOutDir, fileFormat, duration, isRotationSet, effectiveRotation, copyFileStreams, allFilesMeta, keyframeCut, shortestFlag, ffmpegExperimental, preserveMovData, preserveMetadataOnMerge, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, detectedFps, willMerge, enableOverwriteOutput, exportConfirmEnabled, mainFileFormatData, mainStreams, exportExtraStreams, areWeCutting, hideAllNotifications, cleanupChoices.cleanupAfterExport, cleanupFilesWithDialog, selectedSegmentsOrInverse, mergedFileTemplateOrDefault, segmentsToChapters, invertCutSegments, generateMergedFileNames, autoConcatCutSegments, autoDeleteMergedSegments, nonCopiedExtraStreams, showOsNotification, handleExportFailed]);
|
||||
}, [filePath, numStreamsToCopy, segmentsToExport, haveInvalidSegs, workingRef, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, cutMultiple, outputDir, customOutDir, fileFormat, duration, isRotationSet, effectiveRotation, copyFileStreams, allFilesMeta, keyframeCut, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMetadataOnMerge, preserveMovData, preserveChapters, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, detectedFps, willMerge, enableOverwriteOutput, exportConfirmEnabled, mainFileFormatData, mainStreams, exportExtraStreams, areWeCutting, hideAllNotifications, cleanupChoices.cleanupAfterExport, cleanupFilesWithDialog, selectedSegmentsOrInverse, mergedFileTemplateOrDefault, segmentsToChapters, invertCutSegments, generateMergedFileNames, autoConcatCutSegments, autoDeleteMergedSegments, nonCopiedExtraStreams, showOsNotification, handleExportFailed]);
|
||||
|
||||
const onExportPress = useCallback(async () => {
|
||||
if (!filePath) return;
|
||||
|
@ -9,8 +9,6 @@ import type { SweetAlertIcon } from 'sweetalert2';
|
||||
|
||||
import ExportButton from './ExportButton';
|
||||
import ExportModeButton from './ExportModeButton';
|
||||
import PreserveMovDataButton from './PreserveMovDataButton';
|
||||
import MovFastStartButton from './MovFastStartButton';
|
||||
import ToggleExportConfirm from './ToggleExportConfirm';
|
||||
import FileNameTemplateEditor from './FileNameTemplateEditor';
|
||||
import HighlightedText, { highlightedTextStyle } from './HighlightedText';
|
||||
@ -26,7 +24,7 @@ import styles from './ExportConfirm.module.css';
|
||||
import { InverseCutSegment, SegmentToExport } from '../types';
|
||||
import { defaultMergedFileTemplate, defaultOutSegTemplate, GenerateOutFileNames } from '../util/outputNameTemplate';
|
||||
import { FFprobeStream } from '../../../../ffprobe';
|
||||
import { AvoidNegativeTs } from '../../../../types';
|
||||
import { AvoidNegativeTs, PreserveMetadata } from '../../../../types';
|
||||
import TextInput from './TextInput';
|
||||
|
||||
|
||||
@ -95,7 +93,13 @@ function ExportConfirm({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, movFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, toggleSegmentsToChapters, preserveMetadataOnMerge, togglePreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput, ffmpegExperimental, setFfmpegExperimental, cutFromAdjustmentFrames, setCutFromAdjustmentFrames } = useUserSettings();
|
||||
const { changeOutDir, keyframeCut, toggleKeyframeCut, preserveMovData, setPreserveMovData, preserveMetadata, setPreserveMetadata, preserveChapters, setPreserveChapters, movFastStart, setMovFastStart, avoidNegativeTs, setAvoidNegativeTs, autoDeleteMergedSegments, exportConfirmEnabled, toggleExportConfirmEnabled, segmentsToChapters, setSegmentsToChapters, preserveMetadataOnMerge, setPreserveMetadataOnMerge, enableSmartCut, setEnableSmartCut, effectiveExportMode, enableOverwriteOutput, setEnableOverwriteOutput, ffmpegExperimental, setFfmpegExperimental, cutFromAdjustmentFrames, setCutFromAdjustmentFrames } = useUserSettings();
|
||||
|
||||
const togglePreserveChapters = useCallback(() => setPreserveChapters((val) => !val), [setPreserveChapters]);
|
||||
const togglePreserveMovData = useCallback(() => setPreserveMovData((val) => !val), [setPreserveMovData]);
|
||||
const toggleMovFastStart = useCallback(() => setMovFastStart((val) => !val), [setMovFastStart]);
|
||||
const toggleSegmentsToChapters = useCallback(() => setSegmentsToChapters((v) => !v), [setSegmentsToChapters]);
|
||||
const togglePreserveMetadataOnMerge = useCallback(() => setPreserveMetadataOnMerge((v) => !v), [setPreserveMetadataOnMerge]);
|
||||
|
||||
const isMov = ffmpegIsMov(outFormat);
|
||||
const isIpod = outFormat === 'ipod';
|
||||
@ -120,10 +124,18 @@ function ExportConfirm({
|
||||
|
||||
const showHelpText = useCallback(({ icon = 'info', timer = 10000, text }: { icon?: SweetAlertIcon, timer?: number, text: string }) => toast.fire({ icon, timer, text }), []);
|
||||
|
||||
const onPreserveChaptersPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Whether to preserve chapters from source file.') });
|
||||
}, []);
|
||||
|
||||
const onPreserveMovDataHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Preserve all MOV/MP4 metadata tags (e.g. EXIF, GPS position etc.) from source file? Note that some players have trouble playing back files where all metadata is preserved, like iTunes and other Apple software') });
|
||||
}, []);
|
||||
|
||||
const onPreserveMetadataHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Whether to preserve metadata from source file. Default: Global (file metadata), per-track and per-chapter metadata will be copied. Non-global: Only per-track and per-chapter metadata will be copied. None: No metadata will be copied') });
|
||||
}, []);
|
||||
|
||||
const onMovFastStartHelpPress = useCallback(() => {
|
||||
toast.fire({ icon: 'info', timer: 10000, text: i18n.t('Enabling this will allow faster playback of the exported file. This makes processing use 3 times as much export I/O, which is negligible for small files but might slow down exporting of large files.') });
|
||||
}, []);
|
||||
@ -354,7 +366,7 @@ function ExportConfirm({
|
||||
{t('Enable MOV Faststart?')}
|
||||
</td>
|
||||
<td>
|
||||
<MovFastStartButton />
|
||||
<Switch checked={movFastStart} onCheckedChange={toggleMovFastStart} />
|
||||
{isIpod && !movFastStart && <div style={warningStyle}>{t('For the ipod format, it is recommended to activate this option')}</div>}
|
||||
</td>
|
||||
<td>
|
||||
@ -366,13 +378,41 @@ function ExportConfirm({
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Preserve chapters')}
|
||||
</td>
|
||||
<td>
|
||||
<Switch checked={preserveChapters} onCheckedChange={togglePreserveChapters} />
|
||||
</td>
|
||||
<td>
|
||||
<HelpIcon onClick={onPreserveChaptersPress} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Preserve metadata')}
|
||||
</td>
|
||||
<td>
|
||||
<Select value={preserveMetadata} onChange={(e) => setPreserveMetadata(e.target.value as PreserveMetadata)} style={{ height: 20, marginLeft: 5 }}>
|
||||
<option value={'default' as PreserveMetadata}>{t('Default')}</option>
|
||||
<option value={'none' satisfies PreserveMetadata}>{t('None')}</option>
|
||||
<option value={'nonglobal' satisfies PreserveMetadata}>{t('Non-global')}</option>
|
||||
</Select>
|
||||
</td>
|
||||
<td>
|
||||
<HelpIcon onClick={onPreserveMetadataHelpPress} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
{t('Preserve all MP4/MOV metadata?')}
|
||||
{isIpod && preserveMovData && <div style={warningStyle}>{t('For the ipod format, it is recommended to deactivate this option')}</div>}
|
||||
</td>
|
||||
<td>
|
||||
<PreserveMovDataButton />
|
||||
<Switch checked={preserveMovData} onCheckedChange={togglePreserveMovData} />
|
||||
</td>
|
||||
<td>
|
||||
{isIpod && preserveMovData ? (
|
||||
|
@ -1,15 +0,0 @@
|
||||
import { memo } from 'react';
|
||||
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
import Switch from './Switch';
|
||||
|
||||
|
||||
function MovFastStartButton() {
|
||||
const { movFastStart, toggleMovFastStart } = useUserSettings();
|
||||
|
||||
return (
|
||||
<Switch checked={movFastStart} onCheckedChange={toggleMovFastStart} />
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(MovFastStartButton);
|
@ -1,15 +0,0 @@
|
||||
import { memo } from 'react';
|
||||
|
||||
import useUserSettings from '../hooks/useUserSettings';
|
||||
import Switch from './Switch';
|
||||
|
||||
|
||||
function PreserveMovDataButton() {
|
||||
const { preserveMovData, togglePreserveMovData } = useUserSettings();
|
||||
|
||||
return (
|
||||
<Switch checked={preserveMovData} onCheckedChange={togglePreserveMovData} />
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(PreserveMovDataButton);
|
@ -4,15 +4,12 @@ import Color from 'color';
|
||||
import useUserSettingsRoot from './hooks/useUserSettingsRoot';
|
||||
import { ExportMode, SegmentColorIndex } from './types';
|
||||
|
||||
|
||||
export type UserSettingsContextType = ReturnType<typeof useUserSettingsRoot> & {
|
||||
toggleCaptureFormat: () => void,
|
||||
changeOutDir: () => Promise<void>,
|
||||
toggleKeyframeCut: (showMessage?: boolean) => void,
|
||||
togglePreserveMovData: () => void,
|
||||
toggleMovFastStart: () => void,
|
||||
toggleExportConfirmEnabled: () => void,
|
||||
toggleSegmentsToChapters: () => void,
|
||||
togglePreserveMetadataOnMerge: () => void,
|
||||
toggleSimpleMode: () => void,
|
||||
toggleSafeOutputFileName: () => void,
|
||||
effectiveExportMode: ExportMode,
|
||||
|
@ -10,7 +10,7 @@ import { getMapStreamsArgs, getStreamIdsToCopy } from '../util/streams';
|
||||
import { getSmartCutParams } from '../smartcut';
|
||||
import { isDurationValid } from '../segments';
|
||||
import { FFprobeStream } from '../../../../ffprobe';
|
||||
import { AvoidNegativeTs, Html5ifyMode } from '../../../../types';
|
||||
import { AvoidNegativeTs, Html5ifyMode, PreserveMetadata } from '../../../../types';
|
||||
import { AllFilesMeta, Chapter, CopyfileStreams, CustomTagsByFile, ParamsByStreamId, SegmentToExport } from '../types';
|
||||
|
||||
const { join, resolve, dirname } = window.require('path');
|
||||
@ -233,14 +233,14 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
|
||||
const losslessCutSingle = useCallback(async ({
|
||||
keyframeCut: ssBeforeInput, avoidNegativeTs, copyFileStreams, cutFrom, cutTo, chaptersPath, onProgress, outPath,
|
||||
videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, detectedFps,
|
||||
videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMovData, preserveChapters, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, detectedFps,
|
||||
}: {
|
||||
keyframeCut: boolean,
|
||||
avoidNegativeTs: AvoidNegativeTs | undefined,
|
||||
copyFileStreams: CopyfileStreams,
|
||||
cutFrom: number,
|
||||
cutTo: number,
|
||||
chaptersPath?: string | undefined,
|
||||
chaptersPath: string | undefined,
|
||||
onProgress: (p: number) => void,
|
||||
outPath: string,
|
||||
videoDuration: number | undefined,
|
||||
@ -249,7 +249,9 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
outFormat: string,
|
||||
shortestFlag: boolean,
|
||||
ffmpegExperimental: boolean,
|
||||
preserveMetadata: PreserveMetadata,
|
||||
preserveMovData: boolean,
|
||||
preserveChapters: boolean,
|
||||
movFastStart: boolean,
|
||||
customTagsByFile: CustomTagsByFile,
|
||||
paramsByStreamId: ParamsByStreamId,
|
||||
@ -360,6 +362,19 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
return ret;
|
||||
})();
|
||||
|
||||
function getPreserveMetadata() {
|
||||
if (preserveMetadata === 'default') return ['-map_metadata', '0']; // todo isn't this ffmpeg default and can be omitted? https://stackoverflow.com/a/67508734/6519037
|
||||
if (preserveMetadata === 'none') return ['-map_metadata', '-1'];
|
||||
if (preserveMetadata === 'nonglobal') return ['-map_metadata:g', '-1']; // https://superuser.com/a/1546267/658247
|
||||
return [];
|
||||
}
|
||||
|
||||
function getPreserveChapters() {
|
||||
if (chaptersPath) return ['-map_chapters', String(chaptersInputIndex)];
|
||||
if (!preserveChapters) return ['-map_chapters', '-1']; // https://github.com/mifi/lossless-cut/issues/2176
|
||||
return []; // default: includes chapters from input
|
||||
}
|
||||
|
||||
const ffmpegArgs = [
|
||||
'-hide_banner',
|
||||
// No progress if we set loglevel warning :(
|
||||
@ -371,9 +386,9 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
|
||||
...mapStreamsArgs,
|
||||
|
||||
'-map_metadata', '0',
|
||||
...getPreserveMetadata(),
|
||||
|
||||
...(chaptersPath ? ['-map_chapters', String(chaptersInputIndex)] : []),
|
||||
...getPreserveChapters(),
|
||||
|
||||
...(shortestFlag ? ['-shortest'] : []),
|
||||
|
||||
@ -404,7 +419,7 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
}, [appendFfmpegCommandLog, cutFromAdjustmentFrames, filePath, getOutputPlaybackRateArgs, shouldSkipExistingFile, treatInputFileModifiedTimeAsStart, treatOutputFileModifiedTimeAsStart]);
|
||||
|
||||
const cutMultiple = useCallback(async ({
|
||||
outputDir, customOutDir, segments, outSegFileNames, videoDuration, rotation, detectedFps, onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, chapters, preserveMetadataOnMerge,
|
||||
outputDir, customOutDir, segments, outSegFileNames, videoDuration, rotation, detectedFps, onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMetadataOnMerge, preserveMovData, preserveChapters, movFastStart, avoidNegativeTs, customTagsByFile, paramsByStreamId, chapters,
|
||||
}: {
|
||||
outputDir: string,
|
||||
customOutDir: string | undefined,
|
||||
@ -420,13 +435,15 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
outFormat: string | undefined,
|
||||
shortestFlag: boolean,
|
||||
ffmpegExperimental: boolean,
|
||||
preserveMetadata: PreserveMetadata,
|
||||
preserveMovData: boolean,
|
||||
preserveMetadataOnMerge: boolean,
|
||||
preserveChapters: boolean,
|
||||
movFastStart: boolean,
|
||||
avoidNegativeTs: AvoidNegativeTs | undefined,
|
||||
customTagsByFile: CustomTagsByFile,
|
||||
paramsByStreamId: ParamsByStreamId,
|
||||
chapters: Chapter[] | undefined,
|
||||
preserveMetadataOnMerge,
|
||||
}) => {
|
||||
console.log('customTagsByFile', customTagsByFile);
|
||||
console.log('paramsByStreamId', paramsByStreamId);
|
||||
@ -456,7 +473,7 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
const outPath = await makeSegmentOutPath();
|
||||
invariant(outFormat != null);
|
||||
await losslessCutSingle({
|
||||
cutFrom: desiredCutFrom, cutTo, chaptersPath, outPath, copyFileStreams, keyframeCut, avoidNegativeTs, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, paramsByStreamId, onProgress: (progress) => onSingleProgress(i, progress),
|
||||
cutFrom: desiredCutFrom, cutTo, chaptersPath, outPath, copyFileStreams, keyframeCut, avoidNegativeTs, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMovData, preserveChapters, movFastStart, customTagsByFile, paramsByStreamId, onProgress: (progress) => onSingleProgress(i, progress),
|
||||
});
|
||||
return outPath;
|
||||
}
|
||||
@ -519,7 +536,7 @@ function useFfmpegOperations({ filePath, treatInputFileModifiedTimeAsStart, trea
|
||||
|
||||
// for smart cut we need to use keyframe cut here, and no avoid_negative_ts
|
||||
await losslessCutSingle({
|
||||
cutFrom: losslessCutFrom, cutTo, chaptersPath, outPath: losslessPartOutPath, copyFileStreams: copyFileStreamsFiltered, keyframeCut: true, avoidNegativeTs: undefined, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, onProgress,
|
||||
cutFrom: losslessCutFrom, cutTo, chaptersPath, outPath: losslessPartOutPath, copyFileStreams: copyFileStreamsFiltered, keyframeCut: true, avoidNegativeTs: undefined, videoDuration, rotation, allFilesMeta, outFormat, shortestFlag, ffmpegExperimental, preserveMetadata, preserveMovData, preserveChapters, movFastStart, customTagsByFile, paramsByStreamId, videoTimebase, onProgress,
|
||||
});
|
||||
|
||||
// OK, just return the single cut file (we may need smart cut in other segments though)
|
||||
|
@ -47,8 +47,14 @@ export default () => {
|
||||
useEffect(() => safeSetConfig({ customOutDir }), [customOutDir]);
|
||||
const [keyframeCut, setKeyframeCut] = useState(safeGetConfigInitial('keyframeCut'));
|
||||
useEffect(() => safeSetConfig({ keyframeCut }), [keyframeCut]);
|
||||
const [preserveMetadata, setPreserveMetadata] = useState(safeGetConfigInitial('preserveMetadata'));
|
||||
useEffect(() => safeSetConfig({ preserveMetadata }), [preserveMetadata]);
|
||||
const [preserveMetadataOnMerge, setPreserveMetadataOnMerge] = useState(safeGetConfigInitial('preserveMetadataOnMerge'));
|
||||
useEffect(() => safeSetConfig({ preserveMetadataOnMerge }), [preserveMetadataOnMerge]);
|
||||
const [preserveMovData, setPreserveMovData] = useState(safeGetConfigInitial('preserveMovData'));
|
||||
useEffect(() => safeSetConfig({ preserveMovData }), [preserveMovData]);
|
||||
const [preserveChapters, setPreserveChapters] = useState(safeGetConfigInitial('preserveChapters'));
|
||||
useEffect(() => safeSetConfig({ preserveChapters }), [preserveChapters]);
|
||||
const [movFastStart, setMovFastStart] = useState(safeGetConfigInitial('movFastStart'));
|
||||
useEffect(() => safeSetConfig({ movFastStart }), [movFastStart]);
|
||||
const [avoidNegativeTs, setAvoidNegativeTs] = useState(safeGetConfigInitial('avoidNegativeTs'));
|
||||
@ -91,8 +97,6 @@ export default () => {
|
||||
useEffect(() => safeSetConfig({ exportConfirmEnabled }), [exportConfirmEnabled]);
|
||||
const [segmentsToChapters, setSegmentsToChapters] = useState(safeGetConfigInitial('segmentsToChapters'));
|
||||
useEffect(() => safeSetConfig({ segmentsToChapters }), [segmentsToChapters]);
|
||||
const [preserveMetadataOnMerge, setPreserveMetadataOnMerge] = useState(safeGetConfigInitial('preserveMetadataOnMerge'));
|
||||
useEffect(() => safeSetConfig({ preserveMetadataOnMerge }), [preserveMetadataOnMerge]);
|
||||
const [simpleMode, setSimpleMode] = useState(safeGetConfigInitial('simpleMode'));
|
||||
useEffect(() => safeSetConfig({ simpleMode }), [simpleMode]);
|
||||
const [outSegTemplate, setOutSegTemplate] = useState(safeGetConfigInitial('outSegTemplate'));
|
||||
@ -180,8 +184,14 @@ export default () => {
|
||||
setCustomOutDir,
|
||||
keyframeCut,
|
||||
setKeyframeCut,
|
||||
preserveMetadata,
|
||||
setPreserveMetadata,
|
||||
preserveMetadataOnMerge,
|
||||
setPreserveMetadataOnMerge,
|
||||
preserveMovData,
|
||||
setPreserveMovData,
|
||||
preserveChapters,
|
||||
setPreserveChapters,
|
||||
movFastStart,
|
||||
setMovFastStart,
|
||||
avoidNegativeTs,
|
||||
@ -224,8 +234,6 @@ export default () => {
|
||||
setExportConfirmEnabled,
|
||||
segmentsToChapters,
|
||||
setSegmentsToChapters,
|
||||
preserveMetadataOnMerge,
|
||||
setPreserveMetadataOnMerge,
|
||||
simpleMode,
|
||||
setSimpleMode,
|
||||
outSegTemplate,
|
||||
|
6
types.ts
6
types.ts
@ -44,6 +44,8 @@ export type AvoidNegativeTs = 'make_zero' | 'auto' | 'make_non_negative' | 'disa
|
||||
|
||||
export type ModifierKey = 'ctrl' | 'shift' | 'alt' | 'meta';
|
||||
|
||||
export type PreserveMetadata = 'default' | 'nonglobal' | 'none'
|
||||
|
||||
|
||||
export interface Config {
|
||||
captureFormat: CaptureFormat,
|
||||
@ -65,6 +67,9 @@ export interface Config {
|
||||
wheelSensitivity: number,
|
||||
language: LanguageKey | undefined,
|
||||
ffmpegExperimental: boolean,
|
||||
preserveChapters: boolean,
|
||||
preserveMetadata: PreserveMetadata,
|
||||
preserveMetadataOnMerge: boolean,
|
||||
preserveMovData: boolean,
|
||||
movFastStart: boolean,
|
||||
avoidNegativeTs: AvoidNegativeTs,
|
||||
@ -72,7 +77,6 @@ export interface Config {
|
||||
hideOsNotifications: 'all' | undefined,
|
||||
autoLoadTimecode: boolean,
|
||||
segmentsToChapters: boolean,
|
||||
preserveMetadataOnMerge: boolean,
|
||||
simpleMode: boolean,
|
||||
outSegTemplate: string | undefined,
|
||||
mergedFileTemplate: string | undefined,
|
||||
|
Loading…
Reference in New Issue
Block a user