mirror of
https://github.com/iib0011/omni-tools.git
synced 2025-11-07 09:24:55 +05:30
Merge pull request #256 from njfletcher215/trim-on-video-to-gif
added option to concurrently trim video
This commit is contained in:
commit
f889de8068
1 changed files with 65 additions and 7 deletions
|
|
@ -1,8 +1,11 @@
|
||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import * as Yup from 'yup';
|
||||||
import ToolContent from '@components/ToolContent';
|
import ToolContent from '@components/ToolContent';
|
||||||
import { ToolComponentProps } from '@tools/defineTool';
|
import { ToolComponentProps } from '@tools/defineTool';
|
||||||
import { GetGroupsType } from '@components/options/ToolOptions';
|
import { GetGroupsType } from '@components/options/ToolOptions';
|
||||||
|
import TextFieldWithDesc from '@components/options/TextFieldWithDesc';
|
||||||
|
import { updateNumberField } from '@utils/string';
|
||||||
import { InitialValuesType } from './types';
|
import { InitialValuesType } from './types';
|
||||||
import ToolVideoInput from '@components/input/ToolVideoInput';
|
import ToolVideoInput from '@components/input/ToolVideoInput';
|
||||||
import ToolFileResult from '@components/result/ToolFileResult';
|
import ToolFileResult from '@components/result/ToolFileResult';
|
||||||
|
|
@ -13,9 +16,19 @@ import { fetchFile } from '@ffmpeg/util';
|
||||||
const initialValues: InitialValuesType = {
|
const initialValues: InitialValuesType = {
|
||||||
quality: 'mid',
|
quality: 'mid',
|
||||||
fps: '10',
|
fps: '10',
|
||||||
scale: '320:-1:flags=bicubic'
|
scale: '320:-1:flags=bicubic',
|
||||||
|
start: 0,
|
||||||
|
end: 100
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validationSchema = Yup.object({
|
||||||
|
start: Yup.number().min(0, 'Start time must be positive'),
|
||||||
|
end: Yup.number().min(
|
||||||
|
Yup.ref('start'),
|
||||||
|
'End time must be greater than start time'
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
export default function VideoToGif({
|
export default function VideoToGif({
|
||||||
title,
|
title,
|
||||||
longDescription
|
longDescription
|
||||||
|
|
@ -26,14 +39,16 @@ export default function VideoToGif({
|
||||||
|
|
||||||
const compute = (values: InitialValuesType, input: File | null) => {
|
const compute = (values: InitialValuesType, input: File | null) => {
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
const { fps, scale } = values;
|
const { fps, scale, start, end } = values;
|
||||||
let ffmpeg: FFmpeg | null = null;
|
let ffmpeg: FFmpeg | null = null;
|
||||||
let ffmpegLoaded = false;
|
let ffmpegLoaded = false;
|
||||||
|
|
||||||
const convertVideoToGif = async (
|
const convertVideoToGif = async (
|
||||||
file: File,
|
file: File,
|
||||||
fps: string,
|
fps: string,
|
||||||
scale: string
|
scale: string,
|
||||||
|
start: number,
|
||||||
|
end: number
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
|
|
@ -58,6 +73,10 @@ export default function VideoToGif({
|
||||||
await ffmpeg.exec([
|
await ffmpeg.exec([
|
||||||
'-i',
|
'-i',
|
||||||
fileName,
|
fileName,
|
||||||
|
'-ss',
|
||||||
|
start.toString(),
|
||||||
|
'-to',
|
||||||
|
end.toString(),
|
||||||
'-vf',
|
'-vf',
|
||||||
`fps=${fps},scale=${scale},palettegen`,
|
`fps=${fps},scale=${scale},palettegen`,
|
||||||
'palette.png'
|
'palette.png'
|
||||||
|
|
@ -68,6 +87,10 @@ export default function VideoToGif({
|
||||||
fileName,
|
fileName,
|
||||||
'-i',
|
'-i',
|
||||||
'palette.png',
|
'palette.png',
|
||||||
|
'-ss',
|
||||||
|
start.toString(),
|
||||||
|
'-to',
|
||||||
|
end.toString(),
|
||||||
'-filter_complex',
|
'-filter_complex',
|
||||||
`fps=${fps},scale=${scale}[x];[x][1:v]paletteuse`,
|
`fps=${fps},scale=${scale}[x];[x][1:v]paletteuse`,
|
||||||
outputName
|
outputName
|
||||||
|
|
@ -92,7 +115,7 @@ export default function VideoToGif({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
convertVideoToGif(input, fps, scale);
|
convertVideoToGif(input, fps, scale, start, end);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGroups: GetGroupsType<InitialValuesType> | null = ({
|
const getGroups: GetGroupsType<InitialValuesType> | null = ({
|
||||||
|
|
@ -141,6 +164,28 @@ export default function VideoToGif({
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Timestamps',
|
||||||
|
component: (
|
||||||
|
<Box>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
onOwnChange={(value) =>
|
||||||
|
updateNumberField(value, 'start', updateField)
|
||||||
|
}
|
||||||
|
value={values.start}
|
||||||
|
label="Start Time"
|
||||||
|
sx={{ mb: 2, backgroundColor: 'background.paper' }}
|
||||||
|
/>
|
||||||
|
<TextFieldWithDesc
|
||||||
|
onOwnChange={(value) =>
|
||||||
|
updateNumberField(value, 'end', updateField)
|
||||||
|
}
|
||||||
|
value={values.end}
|
||||||
|
label="End Time"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -148,9 +193,22 @@ export default function VideoToGif({
|
||||||
<ToolContent
|
<ToolContent
|
||||||
title={title}
|
title={title}
|
||||||
input={input}
|
input={input}
|
||||||
inputComponent={
|
renderCustomInput={({ start, end }, setFieldValue) => {
|
||||||
<ToolVideoInput value={input} onChange={setInput} title="Input Video" />
|
return (
|
||||||
}
|
<ToolVideoInput
|
||||||
|
value={input}
|
||||||
|
onChange={setInput}
|
||||||
|
title={'Input Video'}
|
||||||
|
showTrimControls={true}
|
||||||
|
onTrimChange={(start, end) => {
|
||||||
|
setFieldValue('start', start);
|
||||||
|
setFieldValue('end', end);
|
||||||
|
}}
|
||||||
|
trimStart={start}
|
||||||
|
trimEnd={end}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
resultComponent={
|
resultComponent={
|
||||||
loading ? (
|
loading ? (
|
||||||
<ToolFileResult
|
<ToolFileResult
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue