1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-21 18:02:35 +01:00

improve playback rate

instead always show it in the bottom bar

closes #2109
This commit is contained in:
Mikael Finstad 2024-08-15 13:23:02 +02:00
parent 343ab5a644
commit 016f4ce1b7
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
2 changed files with 26 additions and 18 deletions

View File

@ -116,7 +116,6 @@ function App() {
// Per project state // Per project state
const [commandedTime, setCommandedTime] = useState(0); const [commandedTime, setCommandedTime] = useState(0);
const [ffmpegCommandLog, setFfmpegCommandLog] = useState<FfmpegCommandLog>([]); const [ffmpegCommandLog, setFfmpegCommandLog] = useState<FfmpegCommandLog>([]);
const [previewFilePath, setPreviewFilePath] = useState<string>(); const [previewFilePath, setPreviewFilePath] = useState<string>();
const [working, setWorkingState] = useState<{ text: string, abortController?: AbortController | undefined }>(); const [working, setWorkingState] = useState<{ text: string, abortController?: AbortController | undefined }>();
const [usingDummyVideo, setUsingDummyVideo] = useState(false); const [usingDummyVideo, setUsingDummyVideo] = useState(false);
@ -149,6 +148,7 @@ function App() {
const [exportConfirmVisible, setExportConfirmVisible] = useState(false); const [exportConfirmVisible, setExportConfirmVisible] = useState(false);
const [cacheBuster, setCacheBuster] = useState(0); const [cacheBuster, setCacheBuster] = useState(0);
const [mergedOutFileName, setMergedOutFileName] = useState<string>(); const [mergedOutFileName, setMergedOutFileName] = useState<string>();
const [playbackRate, setPlaybackRateState] = useState(1);
const [outputPlaybackRate, setOutputPlaybackRateState] = useState(1); const [outputPlaybackRate, setOutputPlaybackRateState] = useState(1);
const { fileFormat, setFileFormat, detectedFileFormat, setDetectedFileFormat, isCustomFormatSelected } = useFileFormatState(); const { fileFormat, setFileFormat, detectedFileFormat, setDetectedFileFormat, isCustomFormatSelected } = useFileFormatState();
@ -221,9 +221,14 @@ function App() {
const videoRef = useRef<ChromiumHTMLVideoElement>(null); const videoRef = useRef<ChromiumHTMLVideoElement>(null);
const videoContainerRef = useRef<HTMLDivElement>(null); const videoContainerRef = useRef<HTMLDivElement>(null);
const setOutputPlaybackRate = useCallback((v: number) => { const setPlaybackRate = useCallback((rate: number) => {
setOutputPlaybackRateState(v); if (videoRef.current) videoRef.current.playbackRate = rate;
if (videoRef.current) videoRef.current.playbackRate = v; setPlaybackRateState(rate);
}, []);
const setOutputPlaybackRate = useCallback((rate: number) => {
setOutputPlaybackRateState(rate);
if (videoRef.current) videoRef.current.playbackRate = rate;
}, []); }, []);
const isFileOpened = !!filePath; const isFileOpened = !!filePath;
@ -832,7 +837,7 @@ function App() {
const video = videoRef.current; const video = videoRef.current;
setCommandedTime(0); setCommandedTime(0);
video!.currentTime = 0; video!.currentTime = 0;
video!.playbackRate = 1; setPlaybackRate(1);
// setWorking(); // setWorking();
setPreviewFilePath(undefined); setPreviewFilePath(undefined);
@ -872,7 +877,7 @@ function App() {
setOutputPlaybackRateState(1); setOutputPlaybackRateState(1);
cancelRenderThumbnails(); cancelRenderThumbnails();
}, [cutSegmentsHistory, clearSegments, setFileFormat, setDetectedFileFormat, setDeselectedSegmentIds, resetMergedOutFileName, cancelRenderThumbnails]); }, [setPlaybackRate, cutSegmentsHistory, clearSegments, setFileFormat, setDetectedFileFormat, setDeselectedSegmentIds, resetMergedOutFileName, cancelRenderThumbnails]);
const showUnsupportedFileMessage = useCallback(() => { const showUnsupportedFileMessage = useCallback(() => {
@ -993,7 +998,7 @@ function App() {
// This was added to re-sync time if file gets reloaded #1674 - but I had to remove this because it broke loop-selected-segments https://github.com/mifi/lossless-cut/discussions/1785#discussioncomment-7852134 // This was added to re-sync time if file gets reloaded #1674 - but I had to remove this because it broke loop-selected-segments https://github.com/mifi/lossless-cut/discussions/1785#discussioncomment-7852134
// if (Math.abs(commandedTimeRef.current - video.currentTime) > 1) video.currentTime = commandedTimeRef.current; // if (Math.abs(commandedTimeRef.current - video.currentTime) > 1) video.currentTime = commandedTimeRef.current;
if (resetPlaybackRate) video!.playbackRate = outputPlaybackRate; if (resetPlaybackRate) setPlaybackRate(outputPlaybackRate);
video?.play().catch((err) => { video?.play().catch((err) => {
if (err instanceof Error && err.name === 'AbortError' && 'code' in err && err.code === 20) { // Probably "DOMException: The play() request was interrupted by a call to pause()." if (err instanceof Error && err.name === 'AbortError' && 'code' in err && err.code === 20) { // Probably "DOMException: The play() request was interrupted by a call to pause()."
console.error(err); console.error(err);
@ -1001,7 +1006,7 @@ function App() {
showPlaybackFailedMessage(); showPlaybackFailedMessage();
} }
}); });
}, [filePath, outputPlaybackRate]); }, [filePath, outputPlaybackRate, setPlaybackRate]);
const togglePlay = useCallback(({ resetPlaybackRate, requestPlaybackMode }: { resetPlaybackRate?: boolean, requestPlaybackMode?: PlaybackMode } | undefined = {}) => { const togglePlay = useCallback(({ resetPlaybackRate, requestPlaybackMode }: { resetPlaybackRate?: boolean, requestPlaybackMode?: PlaybackMode } | undefined = {}) => {
playbackModeRef.current = requestPlaybackMode; playbackModeRef.current = requestPlaybackMode;
@ -1512,7 +1517,7 @@ function App() {
const extractCurrentSegmentFramesAsImages = useCallback(() => extractSegmentFramesAsImages([currentCutSeg?.segId]), [currentCutSeg?.segId, extractSegmentFramesAsImages]); const extractCurrentSegmentFramesAsImages = useCallback(() => extractSegmentFramesAsImages([currentCutSeg?.segId]), [currentCutSeg?.segId, extractSegmentFramesAsImages]);
const extractSelectedSegmentsFramesAsImages = useCallback(() => extractSegmentFramesAsImages(selectedSegments.map((seg) => seg.segId)), [extractSegmentFramesAsImages, selectedSegments]); const extractSelectedSegmentsFramesAsImages = useCallback(() => extractSegmentFramesAsImages(selectedSegments.map((seg) => seg.segId)), [extractSegmentFramesAsImages, selectedSegments]);
const changePlaybackRate = useCallback((dir: number, rateMultiplier?: number) => { const userChangePlaybackRate = useCallback((dir: number, rateMultiplier?: number) => {
if (compatPlayerEnabled) { if (compatPlayerEnabled) {
toast.fire({ title: i18n.t('Unable to change playback rate right now'), timer: 1000 }); toast.fire({ title: i18n.t('Unable to change playback rate right now'), timer: 1000 });
return; return;
@ -1523,10 +1528,9 @@ function App() {
video!.play(); video!.play();
} else { } else {
const newRate = adjustRate(video!.playbackRate, dir, rateMultiplier); const newRate = adjustRate(video!.playbackRate, dir, rateMultiplier);
showNotification({ title: `${i18n.t('Playback rate:')} ${Math.round(newRate * 100)}%`, timer: 1000 }); setPlaybackRate(newRate);
video!.playbackRate = newRate;
} }
}, [compatPlayerEnabled, showNotification]); }, [compatPlayerEnabled, setPlaybackRate]);
const loadEdlFile = useCallback(async ({ path, type, append }: { path: string, type: EdlFileType, append?: boolean }) => { const loadEdlFile = useCallback(async ({ path, type, append }: { path: string, type: EdlFileType, append?: boolean }) => {
console.log('Loading EDL file', type, path, append); console.log('Loading EDL file', type, path, append);
@ -2226,10 +2230,10 @@ function App() {
toggleLoopSelectedSegments, toggleLoopSelectedSegments,
play: () => play(), play: () => play(),
pause, pause,
reducePlaybackRate: () => changePlaybackRate(-1), reducePlaybackRate: () => userChangePlaybackRate(-1),
reducePlaybackRateMore: () => changePlaybackRate(-1, 2), reducePlaybackRateMore: () => userChangePlaybackRate(-1, 2),
increasePlaybackRate: () => changePlaybackRate(1), increasePlaybackRate: () => userChangePlaybackRate(1),
increasePlaybackRateMore: () => changePlaybackRate(1, 2), increasePlaybackRateMore: () => userChangePlaybackRate(1, 2),
timelineToggleComfortZoom, timelineToggleComfortZoom,
captureSnapshot, captureSnapshot,
captureSnapshotAsCoverArt, captureSnapshotAsCoverArt,
@ -2341,7 +2345,7 @@ function App() {
}; };
return ret; return ret;
}, [toggleLoopSelectedSegments, pause, timelineToggleComfortZoom, captureSnapshot, captureSnapshotAsCoverArt, setCutStart, setCutEnd, cleanupFilesDialog, splitCurrentSegment, focusSegmentAtCursor, increaseRotation, goToTimecode, jumpCutStart, jumpCutEnd, jumpTimelineStart, jumpTimelineEnd, batchOpenSelectedFile, closeBatch, addSegment, duplicateCurrentSegment, onExportPress, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, reorderSegsByStartTime, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, createFixedDurationSegments, createNumSegments, createRandomSegments, alignSegmentTimesToKeyframes, shuffleSegments, clearSegments, toggleSegmentsList, toggleStreamsSelector, extractAllStreams, convertFormatBatch, concatBatch, toggleCaptureFormat, toggleStripAudio, toggleStripThumbnail, askStartTimeOffset, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, editCurrentSegmentTags, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, tryFixInvalidDuration, shiftAllSegmentTimes, toggleMuted, copySegmentsToClipboard, handleShowStreamsSelectorClick, openFilesDialog, openDirDialog, toggleSettings, createSegmentsFromKeyframes, toggleWaveformMode, toggleShowThumbnails, toggleShowKeyframes, showIncludeExternalStreamsDialog, toggleFullscreenVideo, checkFileOpened, apparentCutSegments, seekRel, keyboardSeekAccFactor, togglePlay, play, changePlaybackRate, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, seekRelPercent, seekClosestKeyframe, shortStep, jumpSeg, setCurrentSegIndex, cutSegments.length, zoomRel, batchFileJump, removeCutSegment, currentSegIndexSafe, cutSegmentsHistory, onLabelSegment, toggleLastCommands, userHtml5ifyCurrentFile, toggleKeyframeCut, setPlaybackVolume, closeFileWithConfirm, openSendReportDialogWithState, detectBlackScenes, detectSilentScenes, detectSceneChanges]); }, [toggleLoopSelectedSegments, pause, timelineToggleComfortZoom, captureSnapshot, captureSnapshotAsCoverArt, setCutStart, setCutEnd, cleanupFilesDialog, splitCurrentSegment, focusSegmentAtCursor, increaseRotation, goToTimecode, jumpCutStart, jumpCutEnd, jumpTimelineStart, jumpTimelineEnd, batchOpenSelectedFile, closeBatch, addSegment, duplicateCurrentSegment, onExportPress, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, reorderSegsByStartTime, invertAllSegments, fillSegmentsGaps, combineOverlappingSegments, combineSelectedSegments, createFixedDurationSegments, createNumSegments, createRandomSegments, alignSegmentTimesToKeyframes, shuffleSegments, clearSegments, toggleSegmentsList, toggleStreamsSelector, extractAllStreams, convertFormatBatch, concatBatch, toggleCaptureFormat, toggleStripAudio, toggleStripThumbnail, askStartTimeOffset, deselectAllSegments, selectAllSegments, selectOnlyCurrentSegment, editCurrentSegmentTags, toggleCurrentSegmentSelected, invertSelectedSegments, removeSelectedSegments, tryFixInvalidDuration, shiftAllSegmentTimes, toggleMuted, copySegmentsToClipboard, handleShowStreamsSelectorClick, openFilesDialog, openDirDialog, toggleSettings, createSegmentsFromKeyframes, toggleWaveformMode, toggleShowThumbnails, toggleShowKeyframes, showIncludeExternalStreamsDialog, toggleFullscreenVideo, checkFileOpened, apparentCutSegments, seekRel, keyboardSeekAccFactor, togglePlay, play, userChangePlaybackRate, keyboardNormalSeekSpeed, keyboardSeekSpeed2, keyboardSeekSpeed3, seekRelPercent, seekClosestKeyframe, shortStep, jumpSeg, setCurrentSegIndex, cutSegments.length, zoomRel, batchFileJump, removeCutSegment, currentSegIndexSafe, cutSegmentsHistory, onLabelSegment, toggleLastCommands, userHtml5ifyCurrentFile, toggleKeyframeCut, setPlaybackVolume, closeFileWithConfirm, openSendReportDialogWithState, detectBlackScenes, detectSilentScenes, detectSceneChanges]);
const getKeyboardAction = useCallback((action: MainKeyboardAction) => mainActions[action], [mainActions]); const getKeyboardAction = useCallback((action: MainKeyboardAction) => mainActions[action], [mainActions]);
@ -2890,6 +2894,7 @@ function App() {
setOutputPlaybackRate={setOutputPlaybackRate} setOutputPlaybackRate={setOutputPlaybackRate}
formatTimecode={formatTimecode} formatTimecode={formatTimecode}
parseTimecode={parseTimecode} parseTimecode={parseTimecode}
playbackRate={playbackRate}
/> />
</div> </div>

View File

@ -193,7 +193,7 @@ function BottomBar({
darkMode, setDarkMode, darkMode, setDarkMode,
toggleShowThumbnails, toggleWaveformMode, waveformMode, showThumbnails, toggleShowThumbnails, toggleWaveformMode, waveformMode, showThumbnails,
outputPlaybackRate, setOutputPlaybackRate, outputPlaybackRate, setOutputPlaybackRate,
formatTimecode, parseTimecode, formatTimecode, parseTimecode, playbackRate,
}: { }: {
zoom: number, zoom: number,
setZoom: Dispatch<SetStateAction<number>>, setZoom: Dispatch<SetStateAction<number>>,
@ -242,6 +242,7 @@ function BottomBar({
setOutputPlaybackRate: (v: number) => void, setOutputPlaybackRate: (v: number) => void,
formatTimecode: FormatTimecode, formatTimecode: FormatTimecode,
parseTimecode: ParseTimecode, parseTimecode: ParseTimecode,
playbackRate: number,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { getSegColor } = useSegColors(); const { getSegColor } = useSegColors();
@ -468,6 +469,8 @@ function BottomBar({
)} )}
<IoMdSpeedometer title={t('Change FPS')} style={{ padding: '0 .2em', fontSize: '1.3em' }} role="button" onClick={handleChangePlaybackRateClick} /> <IoMdSpeedometer title={t('Change FPS')} style={{ padding: '0 .2em', fontSize: '1.3em' }} role="button" onClick={handleChangePlaybackRateClick} />
<div title={t('Playback rate')} style={{ color: 'var(--gray11)', fontSize: '.7em', marginLeft: '.1em' }}>{playbackRate.toFixed(1)}</div>
</> </>
)} )}