'use strict';
const { spawn } = require('child_process');
const M4F = require('mp4frag');
const P2J = require('pipe2jpeg');
const mp4fragMain = new M4F();
const mp4fragSub = new M4F();
const pipe2jpegFull = new P2J();
const pipe2jpegDownscaled = new P2J();
let segmentCounterMain = 0;
let segmentCounterSub = 0;
let jpegCounterFull = 0;
let jpegCounterDownscaled = 0;
mp4fragMain.on('segment', (data) => {
console.log('segment main', ++segmentCounterMain, data.length);
});
mp4fragSub.on('segment', (data) => {
console.log('segment sub', ++segmentCounterSub, data.length);
});
pipe2jpegFull.on('jpeg', (data) => {
console.log('jpeg full', ++jpegCounterFull, data.length);
});
pipe2jpegDownscaled.on('jpeg', (data) => {
console.log('jpeg downscaled', ++jpegCounterDownscaled, data.length);
});
const params = [
'-hide_banner',
'-progress',
'pipe:1',
'-loglevel',
'quiet',
'-hwaccel',
'rpi',
'-c:v',
'h264_mmal',
/*
1st input, rtsp sub stream
*/
// format rtsp
'-f',
'rtsp',
// use tcp (some ip cams can only use udp)
'-rtsp_transport',
'tcp',
// input ip cam
'-i',
'rtsp://192.168.1.4:554/user=admin_password=pass_channel=1_stream=1.sdp',
/*
2nd input, rtsp main stream
*/
// format rtsp
'-f',
'rtsp',
// use tcp (some ip cams can only use udp)
'-rtsp_transport',
'tcp',
// input ip cam
'-i',
'rtsp://192.168.1.4:554/user=admin_password=pass_channel=1_stream=0.sdp',
/*
create filter that will use sub stream to create jpegs (full and scaled), throttled to 1 fps
1. use 1st input [0:v:0]
2. throttle fps [throttled]
3. split output [full][split]
4. down scale [downscaled]
*/
'-filter_complex',
'[0:v:0] fps=fps=1 [throttled]; [throttled] split=2 [full][split]; [split] scale=iw/3:-1:flags=bicubic:out_range=jpeg [downscaled]',
/*
1st output, rtsp sub stream copied and muxed to fragmented mp4
*/
// map 1st input's video
'-map',
'0:v:0',
// no audio
'-an',
// video codec copy(no encoding)
'-c:v',
'copy',
// format mp4
'-f',
'mp4',
// make mp4 cross-browser compatible with media source extension
'-movflags',
'+frag_keyframe+empty_moov+default_base_moof',
// send to pipe:3, will be received by ffmpeg.stdio[3].pipe(mp4fragSub)
'pipe:3',
/*
2nd output, full sized jpeg
*/
// map full sized jpeg
'-map',
'[full]',
// no audio
'-an',
// video codec mjpeg
'-c:v',
'mjpeg',
// video quality
'-q:v',
'15',
// format image2pipe
'-f',
'image2pipe',
// send to pipe:4, wil be received by ffmpeg.stdio[4].pipe(pipe2jpegFull)
'pipe:4',
/*
3rd output, down scaled jpeg
*/
// map down scaled jpeg
'-map',
'[downscaled]',
// no audio
'-an',
// video codec mjpeg
'-c:v',
'mjpeg',
// video quality
'-q:v',
'15',
// format image2pipe
'-f',
'image2pipe',
// send to pipe:5, wil be received by ffmpeg.stdio[5].pipe(pipe2jpegDownscaled)
'pipe:5',
/*
4th output, rtsp main stream copied and muxed to fragmented mp4
*/
// map 2nd input's video
'-map',
'1:v:0',
// no audio
'-an',
// video codec copy
'-c:v',
'copy',
// format mp4
'-f',
'mp4',
// make mp4 cross-browser compatible with media source extension
'-movflags',
'+frag_keyframe+empty_moov+default_base_moof',
// send to pipe:6, will be received by ffmpeg.stdio[6].pipe(mp4fragMain)
'pipe:6',
];
const ffmpeg = spawn('ffmpeg', params, { stdio: ['ignore', 'pipe', 'inherit', 'pipe', 'pipe', 'pipe', 'pipe'] });
ffmpeg.stdio[1].on('data', (data) => {
console.log(`\npipe:1\n${data.toString()}`);
});
ffmpeg.stdio[3].pipe(mp4fragSub);
ffmpeg.stdio[4].pipe(pipe2jpegFull);
ffmpeg.stdio[5].pipe(pipe2jpegDownscaled);
ffmpeg.stdio[6].pipe(mp4fragMain);
Hi, could you please explain how to use this code? I need a solution to record video (rtsp in h264 format) from an IP camera and found your link in several post inside node-red forum. At the moment I'm able to display the video using this command in an exec node:
ffmpeg -f rtsp -i "rtsp://.................." -r 5 -f image2pipe pipe:1
I've tryed several solution but without success
Thanks a lot