moeiscool moeiscool - 1 year ago 132
Node.js Question

ffmpeg jpeg stream to webm only creates a file .webm with 1 frame (snapshot) or empty .webm file (mjpeg)

my problem is that when i try to turn a series of jpegs into a webm video. I either get a webm file with a single frame or a webm file with nothing in it (0 kb).

var fs = require('fs');
var path = require('path');

var outStream = fs.createWriteStream(__dirname+'/output.webm');
var ffmpeg = require('fluent-ffmpeg');


this one is a mjpeg stream URL. it produces a file with nothing.

//var proc = new ffmpeg({source:'http://xxx.xxx.xxx.xxx/goform/stream?cmd=get&channel=0',timeout:0})


this one is a snapshot URL. it produces a file with a single frame.

var proc = new ffmpeg({source:'http://xxx.xxx.xxx.xxx/snapshot/view0.jpg',timeout:0})

.fromFormat('mjpeg')
.size('2048x1536')
.toFormat('webm')
.withVideoBitrate('800k')
.withFps(20)


I have tried to use pipe instead but no dice :(

//.pipe(outStream,{end:false});
.writeToStream(outStream,{end:false})


any help is appreciated.

at this point i am up for using a basic shell command with exec but when i try that i just get errors also. Yes, it goes without saying I am a noob.

Side note:

I have tried things like zoneminder but it just breaks with our cameras and the number of cameras. so i am making a bare bones solution to record them. With our current cloud service we are missing very important moments and its costing more in energy and time.

Answer Source

thanks everyone that had a look and tried to figure it out :)

i have had some success with this method. It essentially works off a snapshot URL instead of the MJPEG. this uses request. but you could technically use anything since the method is using a pipe. image2pipe.

var spawn = require('child_process').spawn;
var request = require('request');
var args = '-f image2pipe -r 1 -vcodec mjpeg -i - -f webm -r 1 test3.webm';
var encoder = spawn('ffmpeg', args.split(' '));
encoder.stderr.pipe(process.stdout);
var interval = function(){
    request('http://xxx.xxx.xxx.xxx/snapshot/view0.jpg',function(er){
        if(er){console.log(er)}
        setTimeout(function(){interval()},1000)
    }).pipe(encoder.stdin,{end:false})
}
interval();

i could have used setInterval but i only wanted it to try again after it finished the request.

EDIT: it turns out my camera was down when i was trying to use the method in the initial questions so im not sure if it works... but i know this does for MJPEG

var spawn = require('child_process').spawn;
var args = '-f mjpeg -framerate 1 -i http://xxx.xxx.xxx.xxx/goform/stream?cmd=get&channel=0 -vcodec libvpx -framerate 1 -bitrate 256k video_file.webm -y';
console.log(args)
var encoder = spawn('ffmpeg', args.split(' '));
encoder.stderr.pipe(process.stdout);