mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-21 18:02:35 +01:00
Allow for testing keyframe cut
This means a button for toggling whether -ss should be before -i or after (default) See discussion #13 and #79 Also some text/button enchancements
This commit is contained in:
parent
197c2f9418
commit
31c8b86e50
@ -57,7 +57,7 @@ function handleProgress(process, cutDuration, onProgress) {
|
||||
|
||||
async function cut({
|
||||
customOutDir, filePath, format, cutFrom, cutTo, cutToApparent, videoDuration, rotation,
|
||||
includeAllStreams, onProgress, stripAudio,
|
||||
includeAllStreams, onProgress, stripAudio, keyframeCut,
|
||||
}) {
|
||||
const ext = path.extname(filePath) || `.${format}`;
|
||||
const cutSpecification = `${util.formatDuration(cutFrom, true)}-${util.formatDuration(cutToApparent, true)}`;
|
||||
@ -72,18 +72,32 @@ async function cut({
|
||||
const cutFromArgs = cutFrom === 0 ? [] : ['-ss', cutFrom];
|
||||
const cutToArgs = cutTo === undefined || cutTo === videoDuration ? [] : ['-t', cutDuration];
|
||||
|
||||
const inputCutArgs = keyframeCut ? [
|
||||
...cutFromArgs,
|
||||
'-i', filePath,
|
||||
...cutToArgs,
|
||||
'-avoid_negative_ts', 'make_zero',
|
||||
] : [
|
||||
'-i', filePath,
|
||||
...cutFromArgs,
|
||||
...cutToArgs,
|
||||
];
|
||||
|
||||
const rotationArgs = rotation !== undefined ? ['-metadata:s:v:0', `rotate=${rotation}`] : [];
|
||||
const ffmpegArgs = [
|
||||
'-i', filePath, '-y',
|
||||
...inputCutArgs,
|
||||
|
||||
...(stripAudio ? ['-an'] : ['-acodec', 'copy']),
|
||||
|
||||
'-vcodec', 'copy',
|
||||
'-scodec', 'copy',
|
||||
...cutFromArgs, ...cutToArgs,
|
||||
|
||||
...(includeAllStreams ? ['-map', '0'] : []),
|
||||
'-map_metadata', '0',
|
||||
|
||||
...rotationArgs,
|
||||
'-f', format,
|
||||
outPath,
|
||||
|
||||
'-f', format, '-y', outPath,
|
||||
];
|
||||
|
||||
console.log('ffmpeg', ffmpegArgs.join(' '));
|
||||
@ -108,8 +122,7 @@ async function html5ify(filePath, outPath, encodeVideo) {
|
||||
|
||||
const ffmpegArgs = [
|
||||
'-i', filePath, ...videoArgs, '-an',
|
||||
'-y',
|
||||
outPath,
|
||||
'-y', outPath,
|
||||
];
|
||||
|
||||
console.log('ffmpeg', ffmpegArgs.join(' '));
|
||||
|
@ -103,6 +103,7 @@ class App extends React.Component {
|
||||
includeAllStreams: false,
|
||||
captureFormat: 'jpeg',
|
||||
customOutDir: undefined,
|
||||
keyframeCut: false,
|
||||
};
|
||||
|
||||
this.state = {
|
||||
@ -316,15 +317,12 @@ class App extends React.Component {
|
||||
async cutClick() {
|
||||
if (this.state.working) return alert('I\'m busy');
|
||||
|
||||
const cutStartTime = this.state.cutStartTime;
|
||||
const cutEndTime = this.state.cutEndTime;
|
||||
const filePath = this.state.filePath;
|
||||
const outputDir = this.state.customOutDir;
|
||||
const fileFormat = this.state.fileFormat;
|
||||
const videoDuration = this.state.duration;
|
||||
const {
|
||||
cutStartTime, cutEndTime, filePath, customOutDir, fileFormat, duration, includeAllStreams,
|
||||
stripAudio, keyframeCut,
|
||||
} = this.state;
|
||||
|
||||
const rotation = this.isRotationSet() ? this.getRotation() : undefined;
|
||||
const includeAllStreams = this.state.includeAllStreams;
|
||||
const stripAudio = this.state.stripAudio;
|
||||
|
||||
if (!this.isCutRangeValid()) {
|
||||
return alert('Start time must be before end time');
|
||||
@ -333,16 +331,17 @@ class App extends React.Component {
|
||||
this.setState({ working: true });
|
||||
try {
|
||||
return await ffmpeg.cut({
|
||||
customOutDir: outputDir,
|
||||
customOutDir,
|
||||
filePath,
|
||||
format: fileFormat,
|
||||
cutFrom: cutStartTime,
|
||||
cutTo: cutEndTime,
|
||||
cutToApparent: this.getApparentCutEndTime(),
|
||||
videoDuration,
|
||||
videoDuration: duration,
|
||||
rotation,
|
||||
includeAllStreams,
|
||||
stripAudio,
|
||||
keyframeCut,
|
||||
onProgress: progress => this.onCutProgress(progress),
|
||||
});
|
||||
} catch (err) {
|
||||
@ -547,6 +546,13 @@ class App extends React.Component {
|
||||
</div>
|
||||
|
||||
<div className="right-menu">
|
||||
<button
|
||||
title={`Cut mode ${this.state.keyframeCut ? 'nearest keyframe cut' : 'normal cut'}`}
|
||||
onClick={withBlur(() => this.setState({ keyframeCut: !this.state.keyframeCut }))}
|
||||
>
|
||||
{this.state.keyframeCut ? 'kc' : 'nc'}
|
||||
</button>
|
||||
|
||||
<button
|
||||
title={`Set output streams. Current: ${this.state.includeAllStreams ? 'include (and cut) all streams' : 'include only primary streams'}`}
|
||||
onClick={withBlur(() => this.toggleIncludeAllStreams())}
|
||||
@ -555,7 +561,7 @@ class App extends React.Component {
|
||||
</button>
|
||||
|
||||
<button
|
||||
title={`Delete audio? Current: ${this.state.stripAudio ? 'delete audio tracks' : "don't delete audio tracks"}`}
|
||||
title={`Delete audio? Current: ${this.state.stripAudio ? 'delete audio tracks' : 'keep audio tracks'}`}
|
||||
onClick={withBlur(() => this.setState({ stripAudio: !this.state.stripAudio }))}
|
||||
>
|
||||
{this.state.stripAudio ? 'da' : 'ka'}
|
||||
@ -572,7 +578,7 @@ class App extends React.Component {
|
||||
title={`Custom output dir (cancel to restore default). Current: ${this.getOutputDir() || 'Not set (use input dir)'}`}
|
||||
onClick={withBlur(() => this.setOutputDir())}
|
||||
>
|
||||
{this.getOutputDir() ? `...${this.getOutputDir().substr(-10)}` : 'OUTDIR'}
|
||||
{this.getOutputDir() ? 'cd' : 'id'}
|
||||
</button>
|
||||
|
||||
<i
|
||||
|
Loading…
Reference in New Issue
Block a user