_id: video_processing author: Anton Breslavskii | https://github.com/breslavsky description: Using FFmpeg process videos readme: Fix ffmpeg fluent title: en=Video processing;ru=Работа с видео url: https://huggingface.co/PiperMy/Node-Packages/resolve/main/video_processing.yaml version: 3 nodes: split_video_by_frames: _id: split_video_by_frames arrange: x: 120 y: 120 category: _id: video_processing title: "title: en=Video processing;ru=Обработка видео" environment: {} inputs: video: order: 1 title: en=Video;ru=Видео type: video required: true fps: order: 2 title: en=Frame rate;ru=Частота кадров type: integer min: 1 max: 60 step: 1 default: 12 outputs: frames: title: en=Frames;ru=Кадры type: image[] package: video_processing script: |- export async function run({ inputs }) { const { video, fps } = inputs; const { FatalError, NextNode } = DEFINITIONS; const ffmpeg = require('fluent-ffmpeg'); const path = require('path'); const fs = require('fs/promises'); const { fileTypeFromBuffer } = require('file-type'); const frames = []; await useTempFolder(async (tmpFolder) => { const { data } = await download(video); const { ext } = await fileTypeFromBuffer(data); const videoPath = path.join(tmpFolder, `source.${ext}`); await fs.writeFile(videoPath, data); await new Promise((resolve, reject) => { ffmpeg(videoPath) .outputOptions([ `-r ${fps || 12}`, '-q:v 1' ]) .output(`${tmpFolder}/%05d.jpg`) .on('start', (cmd) => console.log(cmd)) .on('end', () => resolve()) .on('error', (err) => reject(new FatalError(err))) .run(); }); const files = await fs.readdir(tmpFolder); for (const file of files) { if (file.endsWith('jpg')) { frames.push(await fs.readFile(path.join(tmpFolder, file))); } } }); return NextNode.from({ outputs: { frames } }); } source: catalog title: en=Split video by frames;ru=Разбить видео по кадрам version: 1 join_frames_to_video: _id: join_frames_to_video arrange: x: 480 y: 120 category: _id: video_processing title: "title: en=Video processing;ru=Обработка видео" execution: deferred inputs: frames: order: 1 title: en=Frames;ru=Кадры type: image[] required: true fps: order: 2 title: en=Frame rate;ru=Частота кадров type: integer min: 1 max: 60 step: 1 default: 12 outputs: video: title: en=Video;ru=Видео type: video package: video_processing script: |- export async function run({ inputs }) { const { frames, fps = 12 } = inputs; const { FatalError, NextNode } = DEFINITIONS; const ffmpeg = require('fluent-ffmpeg'); const path = require('path'); const fs = require('fs/promises'); let output; await useTempFolder(async (tmpFolder) => { const buffers = (await Promise.all(frames.map(frame => download(frame)))).map(({ data }) => data); for (let i = 0; i < buffers.length; i++) { const fileName = path.join(tmpFolder, `${String(i).padStart(5, '0')}.jpg`); await fs.writeFile(fileName, buffers[i]); } const outputPath = path.join(tmpFolder, 'output.mp4'); await new Promise((resolve, reject) => { ffmpeg() .input(path.join(tmpFolder, '%05d.jpg')) .inputFPS(fps) .outputFPS(fps) .outputOptions([ '-c:v libx264', '-pix_fmt yuv420p', '-crf 23' ]) .output(outputPath) .on('start', cmd => console.log(cmd)) .on('end', resolve) .on('error', err => reject(new FatalError(err))) .run(); }); output = await fs.readFile(outputPath); }); return NextNode.from({ outputs: { video: output } }); } source: catalog title: en=Join frames to video;ru=Собрать кадры в видео version: 1