From 37c8b30a118240ff981dd5fa6519ee0ee06c6454 Mon Sep 17 00:00:00 2001 From: nevolodia Date: Sun, 25 May 2025 13:38:23 +0200 Subject: [PATCH] Crop video logic added. --- src/pages/tools/video/crop-video/service.ts | 63 +++++++++++++++++++++ src/pages/tools/video/crop-video/types.ts | 6 ++ 2 files changed, 69 insertions(+) create mode 100644 src/pages/tools/video/crop-video/service.ts create mode 100644 src/pages/tools/video/crop-video/types.ts diff --git a/src/pages/tools/video/crop-video/service.ts b/src/pages/tools/video/crop-video/service.ts new file mode 100644 index 0000000..0d16341 --- /dev/null +++ b/src/pages/tools/video/crop-video/service.ts @@ -0,0 +1,63 @@ +import { FFmpeg } from '@ffmpeg/ffmpeg'; +import { fetchFile } from '@ffmpeg/util'; +import { InitialValuesType } from './types'; + +const ffmpeg = new FFmpeg(); + +export async function getVideoDimensions( + file: File +): Promise<{ width: number; height: number }> { + return new Promise((resolve, reject) => { + const video = document.createElement('video'); + const url = URL.createObjectURL(file); + + video.onloadedmetadata = () => { + URL.revokeObjectURL(url); + resolve({ + width: video.videoWidth, + height: video.videoHeight + }); + }; + + video.onerror = () => { + URL.revokeObjectURL(url); + reject(new Error('Failed to load video metadata')); + }; + + video.src = url; + }); +} + +export async function cropVideo( + input: File, + options: InitialValuesType +): Promise { + if (!ffmpeg.loaded) { + await ffmpeg.load({ + wasmURL: + 'https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.9/dist/esm/ffmpeg-core.wasm' + }); + } + + const inputName = 'input.mp4'; + const outputName = 'output.mp4'; + await ffmpeg.writeFile(inputName, await fetchFile(input)); + + const args = []; + + args.push('-i', inputName); + args.push( + '-vf', + `crop=${options.width}:${options.height}:${options.x}:${options.y}` + ); + args.push('-c:v', 'libx264', '-preset', 'ultrafast', outputName); + + await ffmpeg.exec(args); + + const croppedData = await ffmpeg.readFile(outputName); + return await new File( + [new Blob([croppedData], { type: 'video/mp4' })], + `${input.name.replace(/\.[^/.]+$/, '')}_cropped.mp4`, + { type: 'video/mp4' } + ); +} diff --git a/src/pages/tools/video/crop-video/types.ts b/src/pages/tools/video/crop-video/types.ts new file mode 100644 index 0000000..60ee53d --- /dev/null +++ b/src/pages/tools/video/crop-video/types.ts @@ -0,0 +1,6 @@ +export type InitialValuesType = { + x: number; + y: number; + width: number; + height: number; +};