Search code examples
node.jsffmpegjpegmjpegwebm

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.


Solution

  • 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);