mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-25 03:33:14 +01:00
Implement lossless rotation
Allow for setting rotation metadata
This commit is contained in:
parent
988584591a
commit
7962e174e6
@ -29,6 +29,7 @@ For more information about supported formats / codecs, see https://www.chromium.
|
||||
- Drag drop a video file into player to load or use <kbd>⌘</kbd>/<kbd>CTRL</kbd>+<kbd>O</kbd>.
|
||||
- Press <kbd>SPACE</kbd> to play/pause
|
||||
- Select the cut start and end time. Press <kbd>I</kbd> to select the start time, <kbd>O</kbd> to select the end time for the cut.
|
||||
- Press the rotation button if you want to set rotation metadata
|
||||
- Press the scissors button to export the slice
|
||||
- Press the camera button to take a snapshot
|
||||
|
||||
|
@ -55,7 +55,7 @@ function handleProgress(process, cutDuration, onProgress) {
|
||||
});
|
||||
}
|
||||
|
||||
async function cut(customOutDir, filePath, format, cutFrom, cutTo, onProgress) {
|
||||
async function cut(customOutDir, filePath, format, cutFrom, cutTo, rotation, onProgress) {
|
||||
const extWithoutDot = path.extname(filePath) || `.${format}`;
|
||||
const ext = `.${extWithoutDot}`;
|
||||
const duration = `${util.formatDuration(cutFrom)}-${util.formatDuration(cutTo)}`;
|
||||
@ -66,11 +66,12 @@ async function cut(customOutDir, filePath, format, cutFrom, cutTo, onProgress) {
|
||||
|
||||
// https://github.com/mifi/lossless-cut/issues/50
|
||||
const cutFromArgs = cutFrom === 0 ? [] : ['-ss', cutFrom];
|
||||
|
||||
const rotationArgs = rotation !== undefined ? ['-metadata:s:v:0', `rotate=${rotation}`] : [];
|
||||
const ffmpegArgs = [
|
||||
'-i', filePath, '-y', '-vcodec', 'copy', '-acodec', 'copy',
|
||||
...cutFromArgs, '-t', cutTo - cutFrom,
|
||||
'-map_metadata', '0',
|
||||
...rotationArgs,
|
||||
'-f', format,
|
||||
outPath,
|
||||
];
|
||||
|
@ -92,6 +92,7 @@ class App extends React.Component {
|
||||
cutEndTime: undefined,
|
||||
fileFormat: undefined,
|
||||
captureFormat: 'jpeg',
|
||||
rotation: 360,
|
||||
};
|
||||
|
||||
this.state = _.cloneDeep(defaultState);
|
||||
@ -198,6 +199,24 @@ class App extends React.Component {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getRotation() {
|
||||
return this.state.rotation;
|
||||
}
|
||||
|
||||
getRotationStr() {
|
||||
return `${this.getRotation()}°`;
|
||||
}
|
||||
|
||||
isRotationSet() {
|
||||
// 360 means we don't modify rotation
|
||||
return this.state.rotation !== 360;
|
||||
}
|
||||
|
||||
increaseRotation() {
|
||||
const rotation = (this.state.rotation + 90) % 450;
|
||||
this.setState({ rotation });
|
||||
}
|
||||
|
||||
toggleCaptureFormat() {
|
||||
const isPng = this.state.captureFormat === 'png';
|
||||
this.setState({ captureFormat: isPng ? 'jpeg' : 'png' });
|
||||
@ -255,6 +274,8 @@ class App extends React.Component {
|
||||
const cutStartTime = this.state.cutStartTime;
|
||||
const cutEndTime = this.state.cutEndTime;
|
||||
const filePath = this.state.filePath;
|
||||
const rotation = this.isRotationSet() ? this.getRotation() : undefined;
|
||||
|
||||
if (cutStartTime === undefined || cutEndTime === undefined) {
|
||||
return alert('Please select both start and end time');
|
||||
}
|
||||
@ -272,6 +293,7 @@ class App extends React.Component {
|
||||
fileFormat,
|
||||
cutStartTime,
|
||||
cutEndTime,
|
||||
rotation,
|
||||
progress => this.onCutProgress(progress),
|
||||
);
|
||||
} catch (err) {
|
||||
@ -415,6 +437,13 @@ class App extends React.Component {
|
||||
</div>
|
||||
|
||||
<div className="right-menu">
|
||||
<button
|
||||
title={`Set output rotation. Current: ${this.isRotationSet() ? this.getRotationStr() : 'Don\'t modify'}`}
|
||||
onClick={withBlur(() => this.increaseRotation())}
|
||||
>
|
||||
{this.isRotationSet() ? this.getRotationStr() : '-°'}
|
||||
</button>
|
||||
|
||||
<button
|
||||
title={`Custom output dir (cancel to restore default). Current: ${this.getOutputDir() || 'Not set (use input dir)'}`}
|
||||
onClick={withBlur(() => this.setOutputDir())}
|
||||
|
Loading…
Reference in New Issue
Block a user