allow merge with multi cut

should cover #98
pull/124/head
Mikael Finstad 8 years ago
parent a2be8b8e41
commit e16d235a38

@ -54,14 +54,9 @@ function handleProgress(process, cutDuration, onProgress) {
}
async function cut({
customOutDir, filePath, format, cutFrom, cutTo, cutToApparent, videoDuration, rotation,
includeAllStreams, onProgress, stripAudio, keyframeCut,
filePath, format, cutFrom, cutTo, cutToApparent, videoDuration, rotation,
includeAllStreams, onProgress, stripAudio, keyframeCut, outPath,
}) {
const ext = path.extname(filePath) || `.${format}`;
const cutSpecification = `${formatDuration(cutFrom, true)}-${formatDuration(cutToApparent, true)}`;
const outPath = getOutPath(customOutDir, filePath, `${cutSpecification}${ext}`);
console.log('Cutting from', cutFrom, 'to', cutToApparent);
const cutDuration = cutToApparent - cutFrom;
@ -121,11 +116,19 @@ async function cutMultiple({
return onProgress((sum(Object.values(singleProgresses)) / segments.length));
}
const outFiles = [];
let i = 0;
// eslint-disable-next-line no-restricted-syntax
for (const { cutFrom, cutTo, cutToApparent } of segments) {
const ext = path.extname(filePath) || `.${format}`;
const cutSpecification = `${formatDuration(cutFrom, true)}-${formatDuration(cutToApparent, true)}`;
const outPath = getOutPath(customOutDir, filePath, `${cutSpecification}${ext}`);
// eslint-disable-next-line no-await-in-loop
await cut({
outPath,
customOutDir,
filePath,
format,
@ -140,8 +143,13 @@ async function cutMultiple({
// eslint-disable-next-line no-loop-func
onProgress: progress => onSingleProgress(i, progress),
});
outFiles.push(outPath);
i += 1;
}
return outFiles;
}
async function html5ify(filePath, outPath, encodeVideo) {
@ -166,10 +174,7 @@ async function html5ify(filePath, outPath, encodeVideo) {
await transferTimestamps(filePath, outPath);
}
async function mergeFiles(paths) {
const firstPath = paths[0];
const ext = path.extname(firstPath);
const outPath = `${firstPath}-merged${ext}`;
async function mergeFiles(paths, outPath) {
console.log('Merging files', { paths }, 'to', outPath);
// https://blog.yo1.dog/fix-for-ffmpeg-protocol-not-on-whitelist-error-for-urls/
@ -196,6 +201,19 @@ async function mergeFiles(paths) {
console.log(result.stdout);
}
async function mergeAnyFiles(paths) {
const firstPath = paths[0];
const ext = path.extname(firstPath);
const outPath = `${firstPath}-merged${ext}`;
return mergeFiles(paths, outPath);
}
async function autoMergeSegments({ customOutDir, sourceFile, segmentPaths }) {
const ext = path.extname(sourceFile);
const outPath = getOutPath(customOutDir, sourceFile, `cut-merged-${new Date().getTime()}${ext}`);
return mergeFiles(segmentPaths, outPath);
}
/**
* ffmpeg only supports encoding certain formats, and some of the detected input
* formats are not the same as the names used for encoding.
@ -311,6 +329,7 @@ module.exports = {
cutMultiple,
getFormat,
html5ify,
mergeFiles,
mergeAnyFiles,
autoMergeSegments,
extractAllStreams,
};

@ -95,6 +95,7 @@ const globalState = {
captureFormat: 'jpeg',
customOutDir: undefined,
keyframeCut: true,
autoMerge: false,
};
class App extends React.Component {
@ -169,7 +170,7 @@ class App extends React.Component {
// TODO customOutDir ?
// console.log('merge', paths);
await ffmpeg.mergeFiles(paths);
await ffmpeg.mergeAnyFiles(paths);
} catch (err) {
errorToast('Failed to merge files. Make sure they are all of the exact same format and codecs');
console.error('Failed to merge files', err);
@ -343,6 +344,8 @@ class App extends React.Component {
toggleKeyframeCut = () => this.setState(({ keyframeCut }) => ({ keyframeCut: !keyframeCut }));
toggleAutoMerge = () => this.setState(({ autoMerge }) => ({ autoMerge: !autoMerge }));
addCutSegment = () => {
const { cutSegments, currentTime, duration } = this.state;
@ -424,7 +427,7 @@ class App extends React.Component {
cutClick = async () => {
const {
filePath, customOutDir, fileFormat, duration, includeAllStreams,
stripAudio, keyframeCut, working, cutSegments,
stripAudio, keyframeCut, autoMerge, working, cutSegments,
} = this.state;
if (working) {
@ -451,7 +454,7 @@ class App extends React.Component {
cutToApparent: this.getApparentCutEndTime(i),
}));
await ffmpeg.cutMultiple({
const outFiles = await ffmpeg.cutMultiple({
customOutDir,
filePath,
format: fileFormat,
@ -463,6 +466,16 @@ class App extends React.Component {
segments,
onProgress: this.onCutProgress,
});
if (outFiles.length > 1 && autoMerge) {
this.onCutProgress(0); // TODO
await ffmpeg.autoMergeSegments({
customOutDir,
sourceFile: filePath,
segmentPaths: outFiles,
});
}
} catch (err) {
console.error('stdout:', err.stdout);
console.error('stderr:', err.stderr);
@ -471,6 +484,7 @@ class App extends React.Component {
errorToast('Whoops! ffmpeg was unable to cut this video. It may be of an unknown format or codec combination');
return;
}
showFfmpegFail(err);
} finally {
this.setState({ working: false });
@ -565,7 +579,7 @@ class App extends React.Component {
const {
working, filePath, duration: durationRaw, cutProgress, currentTime, playing,
fileFormat, playbackRate, keyframeCut, includeAllStreams, stripAudio, captureFormat,
helpVisible, currentSeg, cutSegments,
helpVisible, currentSeg, cutSegments, autoMerge,
} = this.state;
const duration = durationRaw || 1;
@ -764,11 +778,19 @@ class App extends React.Component {
<button
type="button"
title={`Add cut segment ${currentSeg + 1}`}
title="Add cut segment"
onClick={withBlur(() => this.addCutSegment())}
>
c+
</button>
<button
type="button"
title={`Auto merge segments to one file after export? ${autoMerge ? 'Auto merge enabled' : 'No merging'}`}
onClick={withBlur(this.toggleAutoMerge)}
>
{autoMerge ? 'am' : 'nm'}
</button>
</div>
<div className="right-menu">

Loading…
Cancel
Save