javascript - Node.js - Buffer Data til Ffmpeg

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg brugte Node.js og Ffmpeg til at oprette animationer. Fordi jeg forsøgte at undgå tredjeparts avi/mp4-parsere, besluttede jeg at output animationen som rå rgb24 datafil og derefter bruge noget program til at konvertere det til mp4-fil.


Jeg fandt ud af, at Ffmpeg er fri og åben kilde, som kan gøre præcis det. Så jeg lavede en Node.js-applikation, som tildeler en Buffer af størrelse 1920 x 1080 x 3 (bredde gange højde gange antal bytes pr pixel), så lavede jeg et renderingskontekstbibliotek, og endelig animerede jeg rammen ved frame og gemme hver ramme consecutivelly i en binær fil (ved hjælp af fs modul).


Så påkaldte jeg Ffmpeg at konvertere det til mp4-fil, og det virker meget godt. Animationer er ret nemme at lave, og Ffmpeg gør sit job korrekt.


Det eneste problem er imidlertid, at det er meget langsomt og spiser plads på harddisken. Jeg vil gerne lave meget lange animationer (mere end en time). Den endelige mp4-fil er relativelly lille, men rå videofil er ekstremt stor. Omkring halvfems procent af hver ramme er sorte pixels, så Ffmpeg comress det meget godt, men rå fil kan ikke komprimeres, og det tager undertiden mor ethan 100 Gigabyte. Der er også meget unødvendig dobbelt behandling af samme data. For det første behandler jeg det i Node.js for at gemme data til fil, og så læser Ffmpeg det for at konvertere det til mp4. Der er meget unødvendigt arbejde.


Så jeg leder efter en måde (og jeg er ganske sikker på, at det er muligt, men jeg fandt ikke en måde at gøre det endnu) for at udstille rå videodata (en ramme ad gangen) til Ffmpeg-processen (uden gemmer alt på harddisken).


Mit mål er at gøre følgende:



  1. Åbn Ffmpeg-proces

  2. Afgiv en ramme i Node.js

  3. Uddata raw byte stream til Ffmpeg

  4. Vent til Ffmpeg at kode det og tilføje til mp4-fil

  5. Lad Ffmpeg vente på min Node.js-proces for at gøre næste ramme






Er der en måde at opnå det på? Jeg ser virkelig ikke en grund til postkode, fordi min nuværende kode ikke har noget at gøre med det spørgsmål, jeg spørger her. Jeg kæmper ikke med syntaksfejl eller implementeringsproblemer . Nej, i stedet ved jeg bare hvilke parametre der skal overføres til Ffmpeg-processen for at opnå det, jeg har allerede forklaret.


Jeg har søgt i dokumentation for at finde ud af, hvilke parametre jeg skal overføre til Ffmpeg-processen for at lade den læse rådata fra stdin i stedet for fil, og også at vente til min Node.js-proces giver næste ramme (så at deaktivere tid begrænsning) fordi det kan tage mere end 24 timer at foretage en ramme, hvorfor Ffmpeg-processen skal vente uden tidsbegrænsning. Jeg fandt derimod ikke noget i dokumentationen.


Jeg ved, hvordan man skriver til stdin fra Node.js og lignende tekniske ting, så det er ikke nødvendigt at forklare det. Det eneste spørgsmål her:



  1. Hvilke parametre skal passere til Ffmpeg?

  2. Skal jeg oprette Ffmpeg-proces (ved hjælp af child\_process) med nogle specielle muligheder?






Tak på forhånd. Venligst, tag det let, dette er mit første spørgsmål! :)

Bedste reference


Som foreslået af @Mulvya og @estus, er den korrekte parameter -i - (for at aktivere input fra stdin):


'use strict';

var cp = require('child\_process');

var proc = cp.spawn('ffmpeg', [
  '-hide\_banner',
  '-f', 'rawvideo',
  '-pix\_fmt', 'rgb24',
  '-s', '2x2',
  '-i', '-',
  '1.png'
]);

proc.stdin.write(Buffer.from([
  255, 0, 0,
  0, 255, 0,
  0, 255, 255,
  255, 0, 255
]));

proc.stdin.end();

proc.stderr.pipe(process.stdout);


Det producerer dette billede:

resultat

Det virker også til animationer.


Tak fyrene for at hjælpe!