Created
August 17, 2020 18:06
-
-
Save kevinGodell/43bd6d075d15bca6ac5a1c1c11f4e947 to your computer and use it in GitHub Desktop.
Revisions
-
kevinGodell created this gist
Aug 17, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,236 @@ # Raspberry Pi 4 Model B Rev 1.1 (4GB) ## ffmpeg hardware decoding experiment ### modifications (needed for hardware decoding multiple video streams) - gpu_mem=512 was set in /boot/config.txt ### dependencies - [mp4frag](https://www.npmjs.com/package/mp4frag) (used for parsing the piped mp4 from ffmpeg) - [pipe2jpeg](https://www.npmjs.com/package/pipe2jpeg) (used for parsing the piped jpeg from ffmpeg) ### description - copies main and sub streams from rtsp ip cam and muxes to individual fragmented mp4 - h264_mmal codec used for decoding rtsp sub stream - encodes full sized and downscaled jpegs from rtsp sub stream ### results - uses ~ 10% cpu load (will vary based on input video sizes and output jpeg sizes and framerate) ### source ```js '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); ```