| _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 | |