fix logic issue with smart cut

closes #1483
pull/1474/head
Mikael Finstad 4 years ago
parent 5347dbdff0
commit 9130924e14
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -187,10 +187,6 @@ const App = memo(() => {
ffmpegSetCustomFfPath(customFfPath); ffmpegSetCustomFfPath(customFfPath);
}, [customFfPath]); }, [customFfPath]);
const {
concatFiles, html5ifyDummy, cutMultiple, autoConcatCutSegments, html5ify, fixInvalidDuration,
} = useFfmpegOperations({ filePath, enableTransferTimestamps });
const outSegTemplateOrDefault = outSegTemplate || defaultOutSegTemplate; const outSegTemplateOrDefault = outSegTemplate || defaultOutSegTemplate;
useEffect(() => { useEffect(() => {
@ -348,8 +344,8 @@ const App = memo(() => {
}, [isFileOpened]); }, [isFileOpened]);
const { const {
cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeCutSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, onViewSegmentTags, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, onLabelSegment, splitCurrentSegment, createNumSegments, createFixedDurationSegments, createRandomSegments, apparentCutSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, currentApparentCutSeg, inverseCutSegments, clearSegments, loadCutSegments, isSegmentSelected, setCutTime, getSegApparentEnd, setCurrentSegIndex, onLabelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, removeSelectedSegments, setDeselectedSegmentIds, onSelectSegmentsByLabel, toggleSegmentSelected, selectOnlySegment, getApparentCutSegmentById, selectedSegments, selectedSegmentsOrInverse, nonFilteredSegmentsOrInverse, cutSegments, cutSegmentsHistory, createSegmentsFromKeyframes, shuffleSegments, detectBlackScenes, detectSilentScenes, detectSceneChanges, removeCutSegment, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, shiftAllSegmentTimes, alignSegmentTimesToKeyframes, onViewSegmentTags, updateSegOrder, updateSegOrders, reorderSegsByStartTime, addSegment, setCutStart, setCutEnd, onLabelSegment, splitCurrentSegment, createNumSegments, createFixedDurationSegments, createRandomSegments, apparentCutSegments, haveInvalidSegs, currentSegIndexSafe, currentCutSeg, currentApparentCutSeg, inverseCutSegments, clearSegments, loadCutSegments, isSegmentSelected, setCutTime, setCurrentSegIndex, onLabelSelectedSegments, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, toggleCurrentSegmentSelected, removeSelectedSegments, setDeselectedSegmentIds, onSelectSegmentsByLabel, toggleSegmentSelected, selectOnlySegment, getApparentCutSegmentById, selectedSegments, selectedSegmentsOrInverse, nonFilteredSegmentsOrInverse, segmentsToExport,
} = useSegments({ filePath, workingRef, setWorking, setCutProgress, mainVideoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments }); } = useSegments({ filePath, workingRef, setWorking, setCutProgress, mainVideoStream, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly });
const jumpSegStart = useCallback((index) => userSeekAbs(apparentCutSegments[index].start), [apparentCutSegments, userSeekAbs]); const jumpSegStart = useCallback((index) => userSeekAbs(apparentCutSegments[index].start), [apparentCutSegments, userSeekAbs]);
const jumpSegEnd = useCallback((index) => userSeekAbs(apparentCutSegments[index].end), [apparentCutSegments, userSeekAbs]); const jumpSegEnd = useCallback((index) => userSeekAbs(apparentCutSegments[index].end), [apparentCutSegments, userSeekAbs]);
@ -679,6 +675,13 @@ const App = memo(() => {
if (!hideAllNotifications) toast.fire({ icon: 'info', text: i18n.t('Loaded existing preview file: {{ fileName }}', { fileName }) }); if (!hideAllNotifications) toast.fire({ icon: 'info', text: i18n.t('Loaded existing preview file: {{ fileName }}', { fileName }) });
}, [hideAllNotifications]); }, [hideAllNotifications]);
const areWeCutting = useMemo(() => segmentsToExport.some(({ start, end }) => isCuttingStart(start) || isCuttingEnd(end, duration)), [duration, segmentsToExport]);
const needSmartCut = !!(areWeCutting && enableSmartCut);
const {
concatFiles, html5ifyDummy, cutMultiple, autoConcatCutSegments, html5ify, fixInvalidDuration,
} = useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut });
const html5ifyAndLoad = useCallback(async (cod, fp, speed, hv, ha) => { const html5ifyAndLoad = useCallback(async (cod, fp, speed, hv, ha) => {
const usesDummyVideo = ['fastest-audio', 'fastest-audio-remux', 'fastest'].includes(speed); const usesDummyVideo = ['fastest-audio', 'fastest-audio-remux', 'fastest'].includes(speed);
console.log('html5ifyAndLoad', { speed, hasVideo: hv, hasAudio: ha, usesDummyVideo }); console.log('html5ifyAndLoad', { speed, hasVideo: hv, hasAudio: ha, usesDummyVideo });
@ -1024,15 +1027,6 @@ const App = memo(() => {
} }
}, [isFileOpened, cleanupChoices, askForCleanupChoices, cleanupFiles, setWorking]); }, [isFileOpened, cleanupChoices, askForCleanupChoices, cleanupFiles, setWorking]);
const segmentsToExport = useMemo(() => {
if (!segmentsToChaptersOnly) return selectedSegmentsOrInverse;
// segmentsToChaptersOnly is a special mode where all segments will be simply written out as chapters to one file: https://github.com/mifi/lossless-cut/issues/993#issuecomment-1037927595
// Chapters export mode: Emulate a single segment with no cuts (full timeline)
return [{ start: 0, end: getSegApparentEnd({}) }];
}, [selectedSegmentsOrInverse, getSegApparentEnd, segmentsToChaptersOnly]);
const areWeCutting = useMemo(() => segmentsToExport.some(({ start, end }) => isCuttingStart(start) || isCuttingEnd(end, duration)), [duration, segmentsToExport]);
const generateOutSegFileNames = useCallback(({ segments = segmentsToExport, template, forceSafeOutputFileName }) => ( const generateOutSegFileNames = useCallback(({ segments = segmentsToExport, template, forceSafeOutputFileName }) => (
segments.map((segment, i) => { segments.map((segment, i) => {
const { start, end, name = '' } = segment; const { start, end, name = '' } = segment;
@ -1124,7 +1118,6 @@ const App = memo(() => {
dispositionByStreamId, dispositionByStreamId,
chapters: chaptersToAdd, chapters: chaptersToAdd,
detectedFps, detectedFps,
enableSmartCut,
enableOverwriteOutput, enableOverwriteOutput,
}); });
@ -1207,7 +1200,7 @@ const App = memo(() => {
setWorking(); setWorking();
setCutProgress(); setCutProgress();
} }
}, [numStreamsToCopy, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, segmentsToExport, getOutSegError, cutMultiple, outputDir, customOutDir, fileFormat, duration, isRotationSet, effectiveRotation, copyFileStreams, allFilesMeta, keyframeCut, shortestFlag, ffmpegExperimental, preserveMovData, preserveMetadataOnMerge, movFastStart, avoidNegativeTs, customTagsByFile, customTagsByStreamId, dispositionByStreamId, detectedFps, enableSmartCut, enableOverwriteOutput, willMerge, exportConfirmEnabled, mainFileFormatData, mainStreams, exportExtraStreams, areWeCutting, hideAllNotifications, cleanupChoices, cleanupFiles, selectedSegmentsOrInverse, segmentsToChapters, invertCutSegments, autoConcatCutSegments, isCustomFormatSelected, autoDeleteMergedSegments, nonCopiedExtraStreams, filePath, handleExportFailed]); }, [numStreamsToCopy, setWorking, segmentsToChaptersOnly, outSegTemplateOrDefault, generateOutSegFileNames, segmentsToExport, getOutSegError, cutMultiple, outputDir, customOutDir, fileFormat, duration, isRotationSet, effectiveRotation, copyFileStreams, allFilesMeta, keyframeCut, shortestFlag, ffmpegExperimental, preserveMovData, preserveMetadataOnMerge, movFastStart, avoidNegativeTs, customTagsByFile, customTagsByStreamId, dispositionByStreamId, detectedFps, enableOverwriteOutput, willMerge, exportConfirmEnabled, mainFileFormatData, mainStreams, exportExtraStreams, areWeCutting, hideAllNotifications, cleanupChoices, cleanupFiles, selectedSegmentsOrInverse, segmentsToChapters, invertCutSegments, autoConcatCutSegments, isCustomFormatSelected, autoDeleteMergedSegments, nonCopiedExtraStreams, filePath, handleExportFailed]);
const onExportPress = useCallback(async () => { const onExportPress = useCallback(async () => {
if (!filePath || workingRef.current || segmentsToExport.length < 1) return; if (!filePath || workingRef.current || segmentsToExport.length < 1) return;
@ -2394,7 +2387,7 @@ const App = memo(() => {
)} )}
</SideSheet> </SideSheet>
<ExportConfirm filePath={filePath} areWeCutting={areWeCutting} nonFilteredSegmentsOrInverse={nonFilteredSegmentsOrInverse} selectedSegments={selectedSegmentsOrInverse} segmentsToExport={segmentsToExport} willMerge={willMerge} visible={exportConfirmVisible} onClosePress={closeExportConfirm} onExportConfirm={onExportConfirm} renderOutFmt={renderOutFmt} outputDir={outputDir} numStreamsTotal={numStreamsTotal} numStreamsToCopy={numStreamsToCopy} setStreamsSelectorShown={setStreamsSelectorShown} outFormat={fileFormat} setOutSegTemplate={setOutSegTemplate} outSegTemplate={outSegTemplateOrDefault} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} getOutSegError={getOutSegError} mainCopiedThumbnailStreams={mainCopiedThumbnailStreams} /> <ExportConfirm filePath={filePath} areWeCutting={areWeCutting} nonFilteredSegmentsOrInverse={nonFilteredSegmentsOrInverse} selectedSegments={selectedSegmentsOrInverse} segmentsToExport={segmentsToExport} willMerge={willMerge} visible={exportConfirmVisible} onClosePress={closeExportConfirm} onExportConfirm={onExportConfirm} renderOutFmt={renderOutFmt} outputDir={outputDir} numStreamsTotal={numStreamsTotal} numStreamsToCopy={numStreamsToCopy} setStreamsSelectorShown={setStreamsSelectorShown} outFormat={fileFormat} setOutSegTemplate={setOutSegTemplate} outSegTemplate={outSegTemplateOrDefault} generateOutSegFileNames={generateOutSegFileNames} currentSegIndexSafe={currentSegIndexSafe} getOutSegError={getOutSegError} mainCopiedThumbnailStreams={mainCopiedThumbnailStreams} needSmartCut={needSmartCut} />
<LastCommandsSheet <LastCommandsSheet
visible={lastCommandsVisible} visible={lastCommandsVisible}

@ -45,7 +45,7 @@ const ExportConfirm = memo(({
areWeCutting, selectedSegments, segmentsToExport, willMerge, visible, onClosePress, onExportConfirm, areWeCutting, selectedSegments, segmentsToExport, willMerge, visible, onClosePress, onExportConfirm,
outFormat, renderOutFmt, outputDir, numStreamsTotal, numStreamsToCopy, setStreamsSelectorShown, outSegTemplate, outFormat, renderOutFmt, outputDir, numStreamsTotal, numStreamsToCopy, setStreamsSelectorShown, outSegTemplate,
setOutSegTemplate, generateOutSegFileNames, filePath, currentSegIndexSafe, getOutSegError, nonFilteredSegmentsOrInverse, setOutSegTemplate, generateOutSegFileNames, filePath, currentSegIndexSafe, getOutSegError, nonFilteredSegmentsOrInverse,
mainCopiedThumbnailStreams, mainCopiedThumbnailStreams, needSmartCut,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -186,9 +186,9 @@ const ExportConfirm = memo(({
<li> <li>
{t('Smart cut (experimental):')} <Button height={20} onClick={() => setEnableSmartCut((v) => !v)}>{enableSmartCut ? t('Yes') : t('No')}</Button> {t('Smart cut (experimental):')} <Button height={20} onClick={() => setEnableSmartCut((v) => !v)}>{enableSmartCut ? t('Yes') : t('No')}</Button>
<HelpIcon onClick={onSmartCutHelpPress} /> <HelpIcon onClick={onSmartCutHelpPress} />
{enableSmartCut && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" title={i18n.t('Experimental functionality has been activated!')} />} {needSmartCut && <WarningSignIcon verticalAlign="middle" color="warning" marginLeft=".3em" title={i18n.t('Experimental functionality has been activated!')} />}
</li> </li>
{!enableSmartCut && ( {!needSmartCut && (
<li> <li>
{t('Cut mode:')} <KeyframeCutButton /> {t('Cut mode:')} <KeyframeCutButton />
<HelpIcon onClick={onKeyframeCutHelpPress} /> {!keyframeCut && <span style={warningStyle}>{t('Note: Keyframe cut is recommended for most common files')}</span>} <HelpIcon onClick={onKeyframeCutHelpPress} /> {!keyframeCut && <span style={warningStyle}>{t('Note: Keyframe cut is recommended for most common files')}</span>}
@ -210,7 +210,7 @@ const ExportConfirm = memo(({
</> </>
)} )}
{!enableSmartCut && ( {!needSmartCut && (
<li> <li>
&quot;avoid_negative_ts&quot; &quot;avoid_negative_ts&quot;
<Select height={20} value={avoidNegativeTs} onChange={(e) => setAvoidNegativeTs(e.target.value)} style={{ marginLeft: 5 }}> <Select height={20} value={avoidNegativeTs} onChange={(e) => setAvoidNegativeTs(e.target.value)} style={{ marginLeft: 5 }}>

@ -55,7 +55,7 @@ const tryDeleteFiles = async (paths) => pMap(paths, (path) => {
fs.unlink(path).catch((err) => console.error('Failed to delete', path, err)); fs.unlink(path).catch((err) => console.error('Failed to delete', path, err));
}, { concurrency: 5 }); }, { concurrency: 5 });
function useFfmpegOperations({ filePath, enableTransferTimestamps }) { function useFfmpegOperations({ filePath, enableTransferTimestamps, needSmartCut }) {
const optionalTransferTimestamps = useCallback(async (...args) => { const optionalTransferTimestamps = useCallback(async (...args) => {
if (enableTransferTimestamps) await transferTimestamps(...args); if (enableTransferTimestamps) await transferTimestamps(...args);
}, [enableTransferTimestamps]); }, [enableTransferTimestamps]);
@ -324,7 +324,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
outputDir, customOutDir, segments, segmentsFileNames, videoDuration, rotation, detectedFps, outputDir, customOutDir, segments, segmentsFileNames, videoDuration, rotation, detectedFps,
onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat, onProgress: onTotalProgress, keyframeCut, copyFileStreams, allFilesMeta, outFormat,
appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, avoidNegativeTs, appendFfmpegCommandLog, shortestFlag, ffmpegExperimental, preserveMovData, movFastStart, avoidNegativeTs,
customTagsByFile, customTagsByStreamId, dispositionByStreamId, chapters, preserveMetadataOnMerge, enableSmartCut, customTagsByFile, customTagsByStreamId, dispositionByStreamId, chapters, preserveMetadataOnMerge,
enableOverwriteOutput, enableOverwriteOutput,
}) => { }) => {
console.log('customTagsByFile', customTagsByFile); console.log('customTagsByFile', customTagsByFile);
@ -350,7 +350,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
async function maybeSmartCutSegment({ start: desiredCutFrom, end: cutTo }, i) { async function maybeSmartCutSegment({ start: desiredCutFrom, end: cutTo }, i) {
const getSegmentOutPath = () => join(outputDir, segmentsFileNames[i]); const getSegmentOutPath = () => join(outputDir, segmentsFileNames[i]);
if (!enableSmartCut) { if (!needSmartCut) {
// old fashioned way // old fashioned way
const outPath = getSegmentOutPath(); const outPath = getSegmentOutPath();
await checkOverwrite(outPath); await checkOverwrite(outPath);
@ -365,9 +365,9 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
const streamsToCopyFromMainFile = copyFileStreams.find(({ path }) => path === filePath).streamIds const streamsToCopyFromMainFile = copyFileStreams.find(({ path }) => path === filePath).streamIds
.map((streamId) => streams.find((stream) => stream.index === streamId)); .map((streamId) => streams.find((stream) => stream.index === streamId));
const { cutFrom: encodeCutTo, needsSmartCut, videoCodec, videoBitrate, videoStreamIndex, videoTimebase } = await getSmartCutParams({ path: filePath, videoDuration, desiredCutFrom, streams: streamsToCopyFromMainFile }); const { cutFrom: encodeCutTo, segmentNeedsSmartCut, videoCodec, videoBitrate, videoStreamIndex, videoTimebase } = await getSmartCutParams({ path: filePath, videoDuration, desiredCutFrom, streams: streamsToCopyFromMainFile });
if (needsSmartCut && !detectedFps) throw new Error('Smart cut is not possible when FPS is unknown'); if (segmentNeedsSmartCut && !detectedFps) throw new Error('Smart cut is not possible when FPS is unknown');
console.log('Smart cut on video stream', videoStreamIndex); console.log('Smart cut on video stream', videoStreamIndex);
@ -385,7 +385,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
// If we are cutting within two keyframes, just encode the whole part and return that // If we are cutting within two keyframes, just encode the whole part and return that
// See https://github.com/mifi/lossless-cut/pull/1267#issuecomment-1236381740 // See https://github.com/mifi/lossless-cut/pull/1267#issuecomment-1236381740
if (needsSmartCut && encodeCutTo > cutTo) { if (segmentNeedsSmartCut && encodeCutTo > cutTo) {
const outPath = getSegmentOutPath(); const outPath = getSegmentOutPath();
await checkOverwrite(outPath); await checkOverwrite(outPath);
await cutEncodeSmartPartWrapper({ cutFrom: desiredCutFrom, cutTo, outPath }); await cutEncodeSmartPartWrapper({ cutFrom: desiredCutFrom, cutTo, outPath });
@ -394,7 +394,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
const ext = getOutFileExtension({ isCustomFormatSelected: true, outFormat, filePath }); const ext = getOutFileExtension({ isCustomFormatSelected: true, outFormat, filePath });
const smartCutMainPartOutPath = needsSmartCut const smartCutMainPartOutPath = segmentNeedsSmartCut
? getSuffixedOutPath({ customOutDir, filePath, nameSuffix: `smartcut-segment-copy-${i}${ext}` }) ? getSuffixedOutPath({ customOutDir, filePath, nameSuffix: `smartcut-segment-copy-${i}${ext}` })
: getSegmentOutPath(); : getSegmentOutPath();
@ -402,7 +402,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
const smartCutSegmentsToConcat = [smartCutEncodedPartOutPath, smartCutMainPartOutPath]; const smartCutSegmentsToConcat = [smartCutEncodedPartOutPath, smartCutMainPartOutPath];
if (!needsSmartCut) await checkOverwrite(smartCutMainPartOutPath); if (!segmentNeedsSmartCut) await checkOverwrite(smartCutMainPartOutPath);
// for smart cut we need to use keyframe cut here, and no avoid_negative_ts // for smart cut we need to use keyframe cut here, and no avoid_negative_ts
await cutSingle({ await cutSingle({
@ -410,7 +410,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
}); });
// OK, just return the single cut file (we may need smart cut in other segments though) // OK, just return the single cut file (we may need smart cut in other segments though)
if (!needsSmartCut) return smartCutMainPartOutPath; if (!segmentNeedsSmartCut) return smartCutMainPartOutPath;
try { try {
const frameDuration = 1 / detectedFps; const frameDuration = 1 / detectedFps;
@ -438,7 +438,7 @@ function useFfmpegOperations({ filePath, enableTransferTimestamps }) {
} finally { } finally {
if (chaptersPath) await tryDeleteFiles([chaptersPath]); if (chaptersPath) await tryDeleteFiles([chaptersPath]);
} }
}, [concatFiles, cutSingle, filePath]); }, [concatFiles, cutSingle, filePath, needSmartCut]);
const autoConcatCutSegments = useCallback(async ({ customOutDir, isCustomFormatSelected, outFormat, segmentPaths, ffmpegExperimental, onProgress, preserveMovData, movFastStart, autoDeleteMergedSegments, chapterNames, preserveMetadataOnMerge, appendFfmpegCommandLog }) => { const autoConcatCutSegments = useCallback(async ({ customOutDir, isCustomFormatSelected, outFormat, segmentPaths, ffmpegExperimental, onProgress, preserveMovData, movFastStart, autoDeleteMergedSegments, chapterNames, preserveMetadataOnMerge, appendFfmpegCommandLog }) => {
const ext = getOutFileExtension({ isCustomFormatSelected, outFormat, filePath }); const ext = getOutFileExtension({ isCustomFormatSelected, outFormat, filePath });

@ -18,7 +18,7 @@ import { maxSegmentsAllowed } from '../util/constants';
export default ({ export default ({
filePath, workingRef, setWorking, setCutProgress, mainVideoStream, filePath, workingRef, setWorking, setCutProgress, mainVideoStream,
duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, duration, getRelevantTime, maxLabelLength, checkFileOpened, invertCutSegments, segmentsToChaptersOnly,
}) => { }) => {
// Segment related state // Segment related state
const segCounterRef = useRef(0); const segCounterRef = useRef(0);
@ -441,6 +441,14 @@ export default ({
const selectedSegmentsOrInverse = useMemo(() => (invertCutSegments ? inverseCutSegments : selectedSegments), [inverseCutSegments, invertCutSegments, selectedSegments]); const selectedSegmentsOrInverse = useMemo(() => (invertCutSegments ? inverseCutSegments : selectedSegments), [inverseCutSegments, invertCutSegments, selectedSegments]);
const nonFilteredSegmentsOrInverse = useMemo(() => (invertCutSegments ? inverseCutSegments : apparentCutSegments), [invertCutSegments, inverseCutSegments, apparentCutSegments]); const nonFilteredSegmentsOrInverse = useMemo(() => (invertCutSegments ? inverseCutSegments : apparentCutSegments), [invertCutSegments, inverseCutSegments, apparentCutSegments]);
const segmentsToExport = useMemo(() => {
// segmentsToChaptersOnly is a special mode where all segments will be simply written out as chapters to one file: https://github.com/mifi/lossless-cut/issues/993#issuecomment-1037927595
// Chapters export mode: Emulate a single segment with no cuts (full timeline)
if (segmentsToChaptersOnly) return [{ start: 0, end: getSegApparentEnd({}) }];
return selectedSegmentsOrInverse;
}, [selectedSegmentsOrInverse, getSegApparentEnd, segmentsToChaptersOnly]);
const removeSelectedSegments = useCallback(() => removeSegments(selectedSegmentsRaw.map((seg) => seg.segId)), [removeSegments, selectedSegmentsRaw]); const removeSelectedSegments = useCallback(() => removeSegments(selectedSegmentsRaw.map((seg) => seg.segId)), [removeSegments, selectedSegmentsRaw]);
const selectOnlySegment = useCallback((seg) => setDeselectedSegmentIds(Object.fromEntries(cutSegments.filter((s) => s.segId !== seg.segId).map((s) => [s.segId, true]))), [cutSegments]); const selectOnlySegment = useCallback((seg) => setDeselectedSegmentIds(Object.fromEntries(cutSegments.filter((s) => s.segId !== seg.segId).map((s) => [s.segId, true]))), [cutSegments]);
@ -490,7 +498,8 @@ export default ({
selectedSegments, selectedSegments,
selectedSegmentsOrInverse, selectedSegmentsOrInverse,
nonFilteredSegmentsOrInverse, nonFilteredSegmentsOrInverse,
getSegApparentEnd, segmentsToExport,
setCurrentSegIndex, setCurrentSegIndex,
setDeselectedSegmentIds, setDeselectedSegmentIds,

@ -24,7 +24,7 @@ export async function getSmartCutParams({ path, videoDuration, desiredCutFrom, s
return { return {
cutFrom: keyframeAtExactTime.time, cutFrom: keyframeAtExactTime.time,
videoStreamIndex: videoStream.index, videoStreamIndex: videoStream.index,
needsSmartCut: false, segmentNeedsSmartCut: false,
}; };
} }
@ -59,7 +59,7 @@ export async function getSmartCutParams({ path, videoDuration, desiredCutFrom, s
return { return {
cutFrom: nextKeyframe.time, cutFrom: nextKeyframe.time,
videoStreamIndex: videoStream.index, videoStreamIndex: videoStream.index,
needsSmartCut: true, segmentNeedsSmartCut: true,
videoCodec, videoCodec,
videoBitrate: Math.floor(videoBitrate), videoBitrate: Math.floor(videoBitrate),
videoTimebase: timebase, videoTimebase: timebase,

Loading…
Cancel
Save