1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-22 10:22:31 +01:00

suppor timecode running time #211

This commit is contained in:
Mikael Finstad 2020-02-14 13:48:58 +08:00
parent 4d5d6aad86
commit 085b72591e
5 changed files with 38 additions and 10 deletions

View File

@ -55,7 +55,7 @@ const TimelineSeg = ({
role="button"
tabIndex="0"
onClick={onThisSegClick}
title={`${formatDuration(cutEndTime - cutStartTime)}`}
title={`${formatDuration({ seconds: cutEndTime - cutStartTime })}`}
/>
)}
{cutEndTime !== undefined && (

View File

@ -23,7 +23,7 @@ async function captureFrame(customOutDir, filePath, video, currentTime, captureF
const buf = getFrameFromVideo(video, captureFormat);
const ext = mime.extension(buf.mimetype);
const time = formatDuration(currentTime, true);
const time = formatDuration({ seconds: currentTime, fileNameFriendly: true });
const outPath = getOutPath(customOutDir, filePath, `${time}.${ext}`);
await fs.writeFileAsync(outPath, buf);

View File

@ -136,7 +136,7 @@ async function cutMultiple({
// eslint-disable-next-line no-restricted-syntax,no-unused-vars
for (const { cutFrom, cutTo, cutToApparent } of segments) {
const ext = path.extname(filePath) || `.${format}`;
const cutSpecification = `${formatDuration(cutFrom, true)}-${formatDuration(cutToApparent, true)}`;
const cutSpecification = `${formatDuration({ seconds: cutFrom, fileNameFriendly: true })}-${formatDuration({ seconds: cutToApparent, fileNameFriendly: true })}`;
const outPath = getOutPath(customOutDir, filePath, `${cutSpecification}${ext}`);

View File

@ -100,6 +100,7 @@ const App = memo(() => {
const [rotationPreviewRequested, setRotationPreviewRequested] = useState(false);
const [filePath, setFilePath] = useState('');
const [playbackRate, setPlaybackRate] = useState(1);
const [detectedFps, setDetectedFps] = useState();
// Global state
const [stripAudio, setStripAudio] = useState(false);
@ -109,6 +110,7 @@ const App = memo(() => {
const [keyframeCut, setKeyframeCut] = useState(true);
const [autoMerge, setAutoMerge] = useState(false);
const [helpVisible, setHelpVisible] = useState(false);
const [timecodeShowFrames, setTimecodeShowFrames] = useState(false);
const resetState = useCallback(() => {
const video = getVideo();
@ -134,6 +136,7 @@ const App = memo(() => {
setRotationPreviewRequested(false);
setFilePath(''); // Setting video src="" prevents memory leak in chromium
setPlaybackRate(1);
setDetectedFps();
}, []);
useEffect(() => () => {
@ -148,6 +151,10 @@ const App = memo(() => {
setCutSegments(cloned);
}, [currentSeg, cutSegments]);
function formatTimecode(sec) {
return formatDuration({ seconds: sec, fps: timecodeShowFrames ? detectedFps : undefined });
}
const setCutStart = useCallback(() => setCutTime('start', currentTime), [setCutTime, currentTime]);
const setCutEnd = useCallback(() => setCutTime('end', currentTime), [setCutTime, currentTime]);
@ -462,7 +469,18 @@ const App = memo(() => {
return;
}
const { streams: newStreams } = await ffmpeg.getAllStreams(fp);
const { streams } = await ffmpeg.getAllStreams(fp);
// console.log('streams', streams);
streams.find((stream) => {
const match = typeof stream.avg_frame_rate === 'string' && stream.avg_frame_rate.match(/^([0-9]+)\/([0-9]+)$/);
if (stream.codec_type === 'video' && match) {
const fps = parseInt(match[1], 10) / parseInt(match[2], 10);
setDetectedFps(fps);
return true;
}
return false;
});
setFileNameTitle(fp);
setFilePath(fp);
@ -473,7 +491,7 @@ const App = memo(() => {
setHtml5FriendlyPath(html5FriendlyPathRequested);
} else if (
!(await checkExistingHtml5FriendlyFile(fp, 'slow') || await checkExistingHtml5FriendlyFile(fp, 'fast'))
&& !doesPlayerSupportFile(newStreams)
&& !doesPlayerSupportFile(streams)
) {
await createDummyVideo(fp);
}
@ -573,7 +591,7 @@ const App = memo(() => {
async function setStartOffset() {
const newStartTimeOffset = await promptTimeOffset(
startTimeOffset !== undefined ? formatDuration(startTimeOffset) : undefined,
startTimeOffset !== undefined ? formatDuration({ seconds: startTimeOffset }) : undefined,
);
if (newStartTimeOffset === undefined) return;
@ -663,7 +681,7 @@ const App = memo(() => {
onChange={e => handleCutTimeInput(e.target.value)}
value={isCutTimeManualSet()
? cutTimeManual
: formatDuration(cutTime + startTimeOffset)}
: formatDuration({ seconds: cutTime + startTimeOffset })}
/>
);
}
@ -769,7 +787,7 @@ const App = memo(() => {
/>
))}
<div id="current-time-display">{formatDuration(offsetCurrentTime)}</div>
<div id="current-time-display">{formatTimecode(offsetCurrentTime)}</div>
</div>
</Hammer>
@ -885,6 +903,14 @@ const App = memo(() => {
{round(playbackRate, 1) || 1}
</span>
<button
type="button"
title={`Average FPS (${timecodeShowFrames ? 'FPS fraction' : 'millisecond fraction'})`}
onClick={withBlur(() => setTimecodeShowFrames(v => !v))}
>
{detectedFps ? round(detectedFps, 1) || 1 : '-'}
</button>
<button
style={{ ...infoSpanStyle, background: segBgColor, color: 'white' }}
disabled={cutSegments.length < 2}

View File

@ -6,7 +6,7 @@ const swal = require('sweetalert2');
const randomColor = require('./random-color');
function formatDuration(_seconds, fileNameFriendly) {
function formatDuration({ seconds: _seconds, fileNameFriendly, fps }) {
const seconds = _seconds || 0;
const minutes = seconds / 60;
const hours = minutes / 60;
@ -14,7 +14,9 @@ function formatDuration(_seconds, fileNameFriendly) {
const hoursPadded = _.padStart(Math.floor(hours), 2, '0');
const minutesPadded = _.padStart(Math.floor(minutes % 60), 2, '0');
const secondsPadded = _.padStart(Math.floor(seconds) % 60, 2, '0');
const msPadded = _.padStart(Math.floor((seconds - Math.floor(seconds)) * 1000), 3, '0');
const msPadded = fps != null
? _.padStart(Math.floor((seconds * fps) % fps), 2, '0')
: _.padStart(Math.floor((seconds - Math.floor(seconds)) * 1000), 3, '0');
// Be nice to filenames and use .
const delim = fileNameFriendly ? '.' : ':';