From 70500dca7ad151e3857acb4438fc6ac15fe636bd Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 11 Jul 2018 23:47:43 -0700 Subject: [PATCH] Allow JPEG API (and other JPEG based outputs) with CUDA with coProcessor - a second FFmpeg process is launched to create the JPEG and PAM data. - currently stream channels are not offloaded --- camera.js | 957 +++++++++++++++++++++++++------------------ languages/en_CA.json | 3 + 2 files changed, 568 insertions(+), 392 deletions(-) diff --git a/camera.js b/camera.js index 7627e9ce..9c87e373 100644 --- a/camera.js +++ b/camera.js @@ -520,7 +520,7 @@ s.getRequest = function(url,callback){ // s.systemLog("Get Snapshot Error", e); }); } -s.kill=function(x,e,p){ +s.kill = function(x,e,p){ if(s.group[e.ke]&&s.group[e.ke].mon[e.id]&&s.group[e.ke].mon[e.id].spawn !== undefined){ if(s.group[e.ke].mon[e.id].spawn){ s.group[e.ke].mon[e.id].allowStdinWrite = false @@ -536,9 +536,14 @@ s.kill=function(x,e,p){ delete(s.group[e.ke].mon[e.id].p2p) delete(s.group[e.ke].mon[e.id].pamDiff) try{ - s.group[e.ke].mon[e.id].spawn.removeListener('end',s.group[e.ke].mon[e.id].spawn_exit); - s.group[e.ke].mon[e.id].spawn.removeListener('exit',s.group[e.ke].mon[e.id].spawn_exit); - delete(s.group[e.ke].mon[e.id].spawn_exit); + s.group[e.ke].mon[e.id].spawn.removeListener('end',s.group[e.ke].mon[e.id].spawn_exit); + s.group[e.ke].mon[e.id].spawn.removeListener('exit',s.group[e.ke].mon[e.id].spawn_exit); + delete(s.group[e.ke].mon[e.id].spawn_exit); + }catch(er){} + try{ + s.group[e.ke].mon[e.id].coSpawnProcessor.removeListener('end',s.group[e.ke].mon[e.id].coSpawnProcessorExit); + s.group[e.ke].mon[e.id].coSpawnProcessor.removeListener('exit',s.group[e.ke].mon[e.id].coSpawnProcessorExit); + delete(s.group[e.ke].mon[e.id].coSpawnProcessorExit); }catch(er){} } clearTimeout(s.group[e.ke].mon[e.id].checker); @@ -552,6 +557,9 @@ s.kill=function(x,e,p){ clearTimeout(s.group[e.ke].mon[e.id].record.capturing); // if(s.group[e.ke].mon[e.id].record.request){s.group[e.ke].mon[e.id].record.request.abort();delete(s.group[e.ke].mon[e.id].record.request);} }; + if(s.group[e.ke].mon[e.id].coSpawnProcessor){ + s.group[e.ke].mon[e.id].coSpawnProcessor.kill('SIGTERM') + } if(s.group[e.ke].mon[e.id].childNode){ s.cx({f:'kill',d:s.init('noReference',e)},s.group[e.ke].mon[e.id].childNodeId) }else{ @@ -1317,256 +1325,372 @@ s.splitForFFPMEG = function (ffmpegCommandAsString) { return p; }, {a: ['']}).a }; -s.ffmpeg=function(e){ - //create input map - var createFFmpegMap = function(arrayOfMaps){ - //e.details.input_map_choices.stream - var string = ''; - if(e.details.input_maps && e.details.input_maps.length > 0){ - if(arrayOfMaps && arrayOfMaps instanceof Array && arrayOfMaps.length>0){ - arrayOfMaps.forEach(function(v){ - if(v.map==='')v.map='0' - string += ' -map '+v.map - }) - }else{ - string += ' -map 0:0' - } - } - return string; - } - var createInputMap = function(number,input){ - //fulladdress - Full Input Path - //`x` is an object used to contain temporary values. - var x = {} - x.cust_input = '' - x.hwaccel = '' - if(input.cust_input&&input.cust_input!==''){x.cust_input+=' '+input.cust_input;} - //input - analyze duration - if(input.aduration&&input.aduration!==''){x.cust_input+=' -analyzeduration '+input.aduration}; - //input - probe size - if(input.probesize&&input.probesize!==''){x.cust_input+=' -probesize '+input.probesize}; - //input - stream loop (good for static files/lists) - if(input.stream_loop==='1'){x.cust_input+=' -stream_loop -1'}; - //input - fps - if(x.cust_input.indexOf('-r ')===-1&&input.sfps&&input.sfps!==''){ - input.sfps=parseFloat(input.sfps); - if(isNaN(input.sfps)){input.sfps=1} - x.cust_input+=' -r '+input.sfps - } - //input - is mjpeg - if(input.type==='mjpeg'){ - if(x.cust_input.indexOf('-f ')===-1){ - x.cust_input+=' -f mjpeg' - } - //input - frames per second - x.cust_input+=' -reconnect 1'; - }else - //input - is h264 has rtsp in address and transport method is chosen - if((input.type==='h264'||input.type==='mp4')&&input.fulladdress.indexOf('rtsp://')>-1&&input.rtsp_transport!==''&&input.rtsp_transport!=='no'){ - x.cust_input += ' -rtsp_transport '+input.rtsp_transport; - }else - if((input.type==='mp4'||input.type==='mjpeg')&&x.cust_input.indexOf('-re')===-1){ - x.cust_input += ' -re' - } - //hardware acceleration - if(input.accelerator&&input.accelerator==='1'){ - if(input.hwaccel&&input.hwaccel!==''){ - x.hwaccel+=' -hwaccel '+input.hwaccel; - } - if(input.hwaccel_vcodec&&input.hwaccel_vcodec!==''&&input.hwaccel_vcodec!=='auto'&&input.hwaccel_vcodec!=='no'){ - x.hwaccel+=' -c:v '+input.hwaccel_vcodec; - } - if(input.hwaccel_device&&input.hwaccel_device!==''){ - switch(input.hwaccel){ - case'vaapi': - x.hwaccel+=' -vaapi_device '+input.hwaccel_device+' -hwaccel_output_format vaapi'; - break; - default: - x.hwaccel+=' -hwaccel_device '+input.hwaccel_device; - break; - } - } - } - //custom - input flags - return x.hwaccel+x.cust_input+' -i "'+input.fulladdress+'"'; - } - //create sub stream channel - var createStreamChannel = function(number,channel){ - //`x` is an object used to contain temporary values. - var x = { - pipe:'' - } - if(!number||number==''){ - x.channel_sdir = e.sdir; +s.createFFmpegMap = function(e,arrayOfMaps){ + //`e` is the monitor object + var string = ''; + if(e.details.input_maps && e.details.input_maps.length > 0){ + if(arrayOfMaps && arrayOfMaps instanceof Array && arrayOfMaps.length>0){ + arrayOfMaps.forEach(function(v){ + if(v.map==='')v.map='0' + string += ' -map '+v.map + }) }else{ - x.channel_sdir = e.sdir+'channel'+number+'/'; - if (!fs.existsSync(x.channel_sdir)){ - fs.mkdirSync(x.channel_sdir); + string += ' -map 0:0' + } + } + return string; +} +s.createInputMap = function(e,number,input){ + //`e` is the monitor object + //`x` is an object used to contain temporary values. + var x = {} + x.cust_input = '' + x.hwaccel = '' + if(input.cust_input&&input.cust_input!==''){x.cust_input+=' '+input.cust_input;} + //input - analyze duration + if(input.aduration&&input.aduration!==''){x.cust_input+=' -analyzeduration '+input.aduration}; + //input - probe size + if(input.probesize&&input.probesize!==''){x.cust_input+=' -probesize '+input.probesize}; + //input - stream loop (good for static files/lists) + if(input.stream_loop==='1'){x.cust_input+=' -stream_loop -1'}; + //input - fps + if(x.cust_input.indexOf('-r ')===-1&&input.sfps&&input.sfps!==''){ + input.sfps=parseFloat(input.sfps); + if(isNaN(input.sfps)){input.sfps=1} + x.cust_input+=' -r '+input.sfps + } + //input - is mjpeg + if(input.type==='mjpeg'){ + if(x.cust_input.indexOf('-f ')===-1){ + x.cust_input+=' -f mjpeg' + } + //input - frames per second + x.cust_input+=' -reconnect 1'; + }else + //input - is h264 has rtsp in address and transport method is chosen + if((input.type==='h264'||input.type==='mp4')&&input.fulladdress.indexOf('rtsp://')>-1&&input.rtsp_transport!==''&&input.rtsp_transport!=='no'){ + x.cust_input += ' -rtsp_transport '+input.rtsp_transport; + }else + if((input.type==='mp4'||input.type==='mjpeg')&&x.cust_input.indexOf('-re')===-1){ + x.cust_input += ' -re' + } + //hardware acceleration + if(input.accelerator&&input.accelerator==='1'){ + if(input.hwaccel&&input.hwaccel!==''){ + x.hwaccel+=' -hwaccel '+input.hwaccel; + } + if(input.hwaccel_vcodec&&input.hwaccel_vcodec!==''&&input.hwaccel_vcodec!=='auto'&&input.hwaccel_vcodec!=='no'){ + x.hwaccel+=' -c:v '+input.hwaccel_vcodec; + } + if(input.hwaccel_device&&input.hwaccel_device!==''){ + switch(input.hwaccel){ + case'vaapi': + x.hwaccel+=' -vaapi_device '+input.hwaccel_device+' -hwaccel_output_format vaapi'; + break; + default: + x.hwaccel+=' -hwaccel_device '+input.hwaccel_device; + break; } } - x.stream_video_filters=[] - //stream - frames per second - if(channel.stream_vcodec!=='copy'){ - if(!channel.stream_fps||channel.stream_fps===''){ - switch(channel.stream_type){ - case'rtmp': - channel.stream_fps=30 - break; - default: + } + //custom - input flags + return x.hwaccel+x.cust_input+' -i "'+input.fulladdress+'"'; +} +//create sub stream channel +s.createStreamChannel = function(e,number,channel){ + //`e` is the monitor object + //`x` is an object used to contain temporary values. + var x = { + pipe:'' + } + if(!number||number==''){ + x.channel_sdir = e.sdir; + }else{ + x.channel_sdir = e.sdir+'channel'+number+'/'; + if (!fs.existsSync(x.channel_sdir)){ + fs.mkdirSync(x.channel_sdir); + } + } + x.stream_video_filters=[] + //stream - frames per second + if(channel.stream_vcodec!=='copy'){ + if(!channel.stream_fps||channel.stream_fps===''){ + switch(channel.stream_type){ + case'rtmp': + channel.stream_fps=30 + break; + default: // channel.stream_fps=5 - break; - } + break; } } - if(channel.stream_fps&&channel.stream_fps!==''){x.stream_fps=' -r '+channel.stream_fps}else{x.stream_fps=''} + } + if(channel.stream_fps&&channel.stream_fps!==''){x.stream_fps=' -r '+channel.stream_fps}else{x.stream_fps=''} - //stream - hls vcodec - if(channel.stream_vcodec&&channel.stream_vcodec!=='no'){ - if(channel.stream_vcodec!==''){x.stream_vcodec=' -c:v '+channel.stream_vcodec}else{x.stream_vcodec=' -c:v libx264'} - }else{ - x.stream_vcodec=''; + //stream - hls vcodec + if(channel.stream_vcodec&&channel.stream_vcodec!=='no'){ + if(channel.stream_vcodec!==''){x.stream_vcodec=' -c:v '+channel.stream_vcodec}else{x.stream_vcodec=' -c:v libx264'} + }else{ + x.stream_vcodec=''; + } + //stream - hls acodec + if(channel.stream_acodec!=='no'){ + if(channel.stream_acodec&&channel.stream_acodec!==''){x.stream_acodec=' -c:a '+channel.stream_acodec}else{x.stream_acodec=''} + }else{ + x.stream_acodec=' -an'; + } + //stream - resolution + if(channel.stream_scale_x&&channel.stream_scale_x!==''&&channel.stream_scale_y&&channel.stream_scale_y!==''){ + x.dimensions = channel.stream_scale_x+'x'+channel.stream_scale_y; + } + //stream - hls segment time + if(channel.hls_time&&channel.hls_time!==''){x.hls_time=channel.hls_time}else{x.hls_time="2"} + //hls list size + if(channel.hls_list_size&&channel.hls_list_size!==''){x.hls_list_size=channel.hls_list_size}else{x.hls_list_size=2} + //stream - custom flags + if(channel.cust_stream&&channel.cust_stream!==''){x.cust_stream=' '+channel.cust_stream}else{x.cust_stream=''} + //stream - preset + if(channel.preset_stream&&channel.preset_stream!==''){x.preset_stream=' -preset '+channel.preset_stream;}else{x.preset_stream=''} + //hardware acceleration + if(e.details.accelerator&&e.details.accelerator==='1'){ + if(e.details.hwaccel&&e.details.hwaccel!==''){ + x.hwaccel+=' -hwaccel '+e.details.hwaccel; } - //stream - hls acodec - if(channel.stream_acodec!=='no'){ - if(channel.stream_acodec&&channel.stream_acodec!==''){x.stream_acodec=' -c:a '+channel.stream_acodec}else{x.stream_acodec=''} - }else{ - x.stream_acodec=' -an'; + if(e.details.hwaccel_vcodec&&e.details.hwaccel_vcodec!==''){ + x.hwaccel+=' -c:v '+e.details.hwaccel_vcodec; } - //stream - resolution - if(channel.stream_scale_x&&channel.stream_scale_x!==''&&channel.stream_scale_y&&channel.stream_scale_y!==''){ - x.dimensions = channel.stream_scale_x+'x'+channel.stream_scale_y; - } - //stream - hls segment time - if(channel.hls_time&&channel.hls_time!==''){x.hls_time=channel.hls_time}else{x.hls_time="2"} - //hls list size - if(channel.hls_list_size&&channel.hls_list_size!==''){x.hls_list_size=channel.hls_list_size}else{x.hls_list_size=2} - //stream - custom flags - if(channel.cust_stream&&channel.cust_stream!==''){x.cust_stream=' '+channel.cust_stream}else{x.cust_stream=''} - //stream - preset - if(channel.preset_stream&&channel.preset_stream!==''){x.preset_stream=' -preset '+channel.preset_stream;}else{x.preset_stream=''} - //hardware acceleration - if(e.details.accelerator&&e.details.accelerator==='1'){ - if(e.details.hwaccel&&e.details.hwaccel!==''){ - x.hwaccel+=' -hwaccel '+e.details.hwaccel; + if(e.details.hwaccel_device&&e.details.hwaccel_device!==''){ + switch(e.details.hwaccel){ + case'vaapi': + x.hwaccel+=' -vaapi_device '+e.details.hwaccel_device+' -hwaccel_output_format vaapi'; + break; + default: + x.hwaccel+=' -hwaccel_device '+e.details.hwaccel_device; + break; } - if(e.details.hwaccel_vcodec&&e.details.hwaccel_vcodec!==''){ - x.hwaccel+=' -c:v '+e.details.hwaccel_vcodec; - } - if(e.details.hwaccel_device&&e.details.hwaccel_device!==''){ - switch(e.details.hwaccel){ - case'vaapi': - x.hwaccel+=' -vaapi_device '+e.details.hwaccel_device+' -hwaccel_output_format vaapi'; - break; - default: - x.hwaccel+=' -hwaccel_device '+e.details.hwaccel_device; - break; - } - } - // else{ - // if(e.details.hwaccel==='vaapi'){ - // x.hwaccel+=' -hwaccel_device 0'; - // } - // } } +// else{ +// if(e.details.hwaccel==='vaapi'){ +// x.hwaccel+=' -hwaccel_device 0'; +// } +// } + } - if(channel.rotate_stream&&channel.rotate_stream!==""&&channel.rotate_stream!=="no"){ - x.stream_video_filters.push('transpose='+channel.rotate_stream); - } - //stream - video filter - if(channel.svf&&channel.svf!==''){ - x.stream_video_filters.push(channel.svf) - } - if(x.stream_video_filters.length>0){ - var string = x.stream_video_filters.join(',').trim() - if(string===''){ - x.stream_video_filters='' - }else{ - x.stream_video_filters=' -vf '+string - } - }else{ + if(channel.rotate_stream&&channel.rotate_stream!==""&&channel.rotate_stream!=="no"){ + x.stream_video_filters.push('transpose='+channel.rotate_stream); + } + //stream - video filter + if(channel.svf&&channel.svf!==''){ + x.stream_video_filters.push(channel.svf) + } + if(x.stream_video_filters.length>0){ + var string = x.stream_video_filters.join(',').trim() + if(string===''){ x.stream_video_filters='' + }else{ + x.stream_video_filters=' -vf '+string } - if(e.details.input_map_choices&&e.details.input_map_choices.record){ - //add input feed map - x.pipe += createFFmpegMap(e.details.input_map_choices['stream_channel-'+(number-config.pipeAddition)]) - } - if(channel.stream_vcodec!=='copy'){ - x.cust_stream+=x.stream_fps - } - switch(channel.stream_type){ - case'mp4': - x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Poseidon Stream" -reset_timestamps 1' - if(channel.stream_vcodec!=='copy'){ - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; - x.cust_stream+=x.preset_stream - x.cust_stream+=x.stream_video_filters - } - x.pipe+=' -f mp4'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:'+number; - break; - case'rtmp': - x.rtmp_server_url=s.checkCorrectPathEnding(channel.rtmp_server_url); - if(channel.stream_vcodec!=='copy'){ - if(channel.stream_vcodec==='libx264'){ - channel.stream_vcodec = 'h264' - } - if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; - x.cust_stream+=x.preset_stream - if(channel.stream_v_br&&channel.stream_v_br!==''){x.cust_stream+=' -b:v '+channel.stream_v_br} - } - if(channel.stream_vcodec!=='no'&&channel.stream_vcodec!==''){ - x.cust_stream+=' -vcodec '+channel.stream_vcodec - } - if(channel.stream_acodec!=='copy'){ - if(!channel.stream_acodec||channel.stream_acodec===''||channel.stream_acodec==='no'){ - channel.stream_acodec = 'aac' - } - if(!channel.stream_a_br||channel.stream_a_br===''){channel.stream_a_br='128k'} - x.cust_stream+=' -ab '+channel.stream_a_br - } - if(channel.stream_acodec!==''){ - x.cust_stream+=' -acodec '+channel.stream_acodec - } - x.pipe+=' -f flv'+x.stream_video_filters+x.cust_stream+' "'+x.rtmp_server_url+channel.rtmp_stream_key+'"'; - break; - case'h264': - if(channel.stream_vcodec!=='copy'){ - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; - x.cust_stream+=x.preset_stream - x.cust_stream+=x.stream_video_filters - } - x.pipe+=' -f mpegts'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:'+number; - break; - case'flv': - if(channel.stream_vcodec!=='copy'){ - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; - x.cust_stream+=x.preset_stream - x.cust_stream+=x.stream_video_filters - } - x.pipe+=' -f flv'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:'+number; - break; - case'hls': - if(channel.stream_vcodec!=='h264_vaapi'&&channel.stream_vcodec!=='copy'){ - if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; - if(x.cust_stream.indexOf('-tune')===-1){x.cust_stream+=' -tune zerolatency'} - if(x.cust_stream.indexOf('-g ')===-1){x.cust_stream+=' -g 1'} - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - x.cust_stream+=x.stream_video_filters - } - x.pipe+=x.preset_stream+x.stream_acodec+x.stream_vcodec+' -f hls'+x.cust_stream+' -hls_time '+x.hls_time+' -hls_list_size '+x.hls_list_size+' -start_number 0 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+x.channel_sdir+'s.m3u8"'; - break; - case'mjpeg': - if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -q:v '+channel.stream_quality; + }else{ + x.stream_video_filters='' + } + if(e.details.input_map_choices&&e.details.input_map_choices.record){ + //add input feed map + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices['stream_channel-'+(number-config.pipeAddition)]) + } + if(channel.stream_vcodec!=='copy'){ + x.cust_stream+=x.stream_fps + } + switch(channel.stream_type){ + case'mp4': + x.cust_stream+=' -movflags +frag_keyframe+empty_moov+default_base_moof -metadata title="Poseidon Stream" -reset_timestamps 1' + if(channel.stream_vcodec!=='copy'){ if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - x.pipe+=' -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:'+number; + if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; + x.cust_stream+=x.preset_stream + x.cust_stream+=x.stream_video_filters + } + x.pipe+=' -f mp4'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:'+number; + break; + case'rtmp': + x.rtmp_server_url=s.checkCorrectPathEnding(channel.rtmp_server_url); + if(channel.stream_vcodec!=='copy'){ + if(channel.stream_vcodec==='libx264'){ + channel.stream_vcodec = 'h264' + } + if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; + x.cust_stream+=x.preset_stream + if(channel.stream_v_br&&channel.stream_v_br!==''){x.cust_stream+=' -b:v '+channel.stream_v_br} + } + if(channel.stream_vcodec!=='no'&&channel.stream_vcodec!==''){ + x.cust_stream+=' -vcodec '+channel.stream_vcodec + } + if(channel.stream_acodec!=='copy'){ + if(!channel.stream_acodec||channel.stream_acodec===''||channel.stream_acodec==='no'){ + channel.stream_acodec = 'aac' + } + if(!channel.stream_a_br||channel.stream_a_br===''){channel.stream_a_br='128k'} + x.cust_stream+=' -ab '+channel.stream_a_br + } + if(channel.stream_acodec!==''){ + x.cust_stream+=' -acodec '+channel.stream_acodec + } + x.pipe+=' -f flv'+x.stream_video_filters+x.cust_stream+' "'+x.rtmp_server_url+channel.rtmp_stream_key+'"'; + break; + case'h264': + if(channel.stream_vcodec!=='copy'){ + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; + x.cust_stream+=x.preset_stream + x.cust_stream+=x.stream_video_filters + } + x.pipe+=' -f mpegts'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:'+number; + break; + case'flv': + if(channel.stream_vcodec!=='copy'){ + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; + x.cust_stream+=x.preset_stream + x.cust_stream+=x.stream_video_filters + } + x.pipe+=' -f flv'+x.stream_acodec+x.stream_vcodec+x.cust_stream+' pipe:'+number; + break; + case'hls': + if(channel.stream_vcodec!=='h264_vaapi'&&channel.stream_vcodec!=='copy'){ + if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -crf '+channel.stream_quality; + if(x.cust_stream.indexOf('-tune')===-1){x.cust_stream+=' -tune zerolatency'} + if(x.cust_stream.indexOf('-g ')===-1){x.cust_stream+=' -g 1'} + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + x.cust_stream+=x.stream_video_filters + } + x.pipe+=x.preset_stream+x.stream_acodec+x.stream_vcodec+' -f hls'+x.cust_stream+' -hls_time '+x.hls_time+' -hls_list_size '+x.hls_list_size+' -start_number 0 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+x.channel_sdir+'s.m3u8"'; + break; + case'mjpeg': + if(channel.stream_quality && channel.stream_quality !== '')x.cust_stream+=' -q:v '+channel.stream_quality; + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + x.pipe+=' -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:'+number; + break; + default: + x.pipe='' + break; + } + return x.pipe +} +s.ffmpegCoProcessor = function(e){ + if(e.coProcessor === false)return; + var x = {} + //x.input is the input and connection + if(e.details.loglevel&&e.details.loglevel!==''){x.loglevel='-loglevel '+e.details.loglevel;}else{x.loglevel='-loglevel error'} + x.input = x.loglevel+' -re -i '+e.sdir+'cpuOnly.m3u8' + + //x.pipe is the stream out methods + x.cust_input='' + x.cust_detect=' ' + x.stream_video_filters=[] + x.hwaccel='' + x.pipe='' + //main stream frames + //stream - timestamp + if(e.details.stream_timestamp&&e.details.stream_timestamp=="1"&&e.details.vcodec!=='copy'){ + //font + if(e.details.stream_timestamp_font&&e.details.stream_timestamp_font!==''){x.stream_timestamp_font=e.details.stream_timestamp_font}else{x.stream_timestamp_font='/usr/share/fonts/truetype/freefont/FreeSans.ttf'} + //position x + if(e.details.stream_timestamp_x&&e.details.stream_timestamp_x!==''){x.stream_timestamp_x=e.details.stream_timestamp_x}else{x.stream_timestamp_x='(w-tw)/2'} + //position y + if(e.details.stream_timestamp_y&&e.details.stream_timestamp_y!==''){x.stream_timestamp_y=e.details.stream_timestamp_y}else{x.stream_timestamp_y='0'} + //text color + if(e.details.stream_timestamp_color&&e.details.stream_timestamp_color!==''){x.stream_timestamp_color=e.details.stream_timestamp_color}else{x.stream_timestamp_color='white'} + //box color + if(e.details.stream_timestamp_box_color&&e.details.stream_timestamp_box_color!==''){x.stream_timestamp_box_color=e.details.stream_timestamp_box_color}else{x.stream_timestamp_box_color='0x00000000@1'} + //text size + if(e.details.stream_timestamp_font_size&&e.details.stream_timestamp_font_size!==''){x.stream_timestamp_font_size=e.details.stream_timestamp_font_size}else{x.stream_timestamp_font_size='10'} + + x.stream_video_filters.push('drawtext=fontfile='+x.stream_timestamp_font+':text=\'%{localtime}\':x='+x.stream_timestamp_x+':y='+x.stream_timestamp_y+':fontcolor='+x.stream_timestamp_color+':box=1:boxcolor='+x.stream_timestamp_box_color+':fontsize='+x.stream_timestamp_font_size); + } + //stream - watermark for -vf + if(e.details.stream_watermark&&e.details.stream_watermark=="1"&&e.details.stream_watermark_location&&e.details.stream_watermark_location!==''){ + switch(e.details.stream_watermark_position){ + case'tl'://top left + x.stream_watermark_position='10:10' break; - default: - x.pipe='' + case'tr'://top right + x.stream_watermark_position='main_w-overlay_w-10:10' + break; + case'bl'://bottom left + x.stream_watermark_position='10:main_h-overlay_h-10' + break; + default://bottom right + x.stream_watermark_position='(main_w-overlay_w-10)/2:(main_h-overlay_h-10)/2' break; } - return x.pipe + x.stream_video_filters.push('movie='+e.details.stream_watermark_location+'[watermark],[in][watermark]overlay='+x.stream_watermark_position+'[out]'); + } + //stream - rotation + if(e.details.rotate_stream&&e.details.rotate_stream!==""&&e.details.rotate_stream!=="no"&&e.details.stream_vcodec!=='copy'){ + x.stream_video_filters.push('transpose='+e.details.rotate_stream); + } + if(e.details.svf&&e.details.svf!==''){ + x.stream_video_filters.push(e.details.svf) + } + if(x.stream_video_filters.length>0){ + x.stream_video_filters=' -vf '+x.stream_video_filters.join(',') + }else{ + x.stream_video_filters='' + } + if(e.details.cust_stream&&e.details.cust_stream!==''){x.cust_stream=' '+e.details.cust_stream}else{x.cust_stream=''} + if(e.details.stream_fps&&e.details.stream_fps!==''){x.stream_fps=' -r '+e.details.stream_fps}else{x.stream_fps=''} + if(e.details.stream_vcodec!=='copy'){ + x.cust_stream+=x.stream_fps + } + switch(e.details.stream_type){ + case'mjpeg': + if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + x.pipe += ' -an -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:1'; + break; + case'b64':case'':case undefined:case null://base64 + if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + x.pipe += ' -an -c:v mjpeg -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1'; + break; + } + //detector frames + if(!e.details.detector_fps||e.details.detector_fps===''){e.details.detector_fps=2} + if(e.details.detector_scale_x&&e.details.detector_scale_x!==''&&e.details.detector_scale_y&&e.details.detector_scale_y!==''){x.dratio=' -s '+e.details.detector_scale_x+'x'+e.details.detector_scale_y}else{x.dratio=' -s 320x240'} + if(e.details.cust_detect&&e.details.cust_detect!==''){x.cust_detect+=e.details.cust_detect;} + if(e.details.detector_pam==='1'){ + x.pipe += ' -an -c:v pam -pix_fmt gray -f image2pipe -r '+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3' + if(e.details.detector_use_detect_object === '1'){ + //for object detection + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector) + x.pipe += ' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:4'; + } + }else{ + x.pipe+=' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3'; + } + //snapshot frames + if(e.details.snap === '1'){ + if(!e.details.snap_fps || e.details.snap_fps === ''){e.details.snap_fps = 1} + if(e.details.snap_vf && e.details.snap_vf !== ''){x.snap_vf=' -vf '+e.details.snap_vf}else{x.snap_vf=''} + if(e.details.snap_scale_x && e.details.snap_scale_x !== '' && e.details.snap_scale_y && e.details.snap_scale_y !== ''){x.snap_ratio = ' -s '+e.details.snap_scale_x+'x'+e.details.snap_scale_y}else{x.snap_ratio=''} + if(e.details.cust_snap && e.details.cust_snap !== ''){x.cust_snap = ' '+e.details.cust_snap}else{x.cust_snap=''} + x.pipe += ' -update 1 -r '+e.details.snap_fps+x.cust_snap+x.snap_ratio+x.snap_vf+' "'+e.sdir+'s.jpg" -y'; + } + x.stdioPipes = []; + var times = config.pipeAddition; + if(e.details.stream_channels){ + times+=e.details.stream_channels.length + } + for(var i=0; i < times; i++){ + x.stdioPipes.push('pipe') + } + var commandString = x.input+x.pipe + s.group[e.ke].mon[e.mid].coProcessorCmd = commandString + return spawn(config.ffmpegDir,s.splitForFFPMEG((commandString).replace(/\s+/g,' ').trim()),{detached: true,stdio:x.stdioPipes}) +} +s.ffmpeg = function(e){ + e.coProcessor = false + if(e.details.accelerator === '1'){ + e.coProcessor = true } //set X for temporary values so we don't break our main monitor object. var x={tmp:''}; @@ -1793,7 +1917,7 @@ s.ffmpeg=function(e){ //stream - pipe build if(e.details.input_map_choices&&e.details.input_map_choices.stream){ //add input feed map - x.pipe += createFFmpegMap(e.details.input_map_choices.stream) + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.stream) } if(e.details.stream_vcodec!=='copy'){ x.cust_stream+=x.stream_fps @@ -1829,19 +1953,25 @@ s.ffmpeg=function(e){ x.pipe+=x.preset_stream+x.stream_acodec+x.stream_vcodec+' -f hls'+x.cust_stream+' -hls_time '+x.hls_time+' -hls_list_size '+x.hls_list_size+' -start_number 0 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'s.m3u8"'; break; case'mjpeg': - if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - x.pipe+=' -an -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:1'; + if(e.coProcessor === false){ + if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + x.pipe+=' -an -c:v mjpeg -f mpjpeg -boundary_tag shinobi'+x.cust_stream+x.stream_video_filters+' pipe:1'; + } break; case'pam': - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; - x.pipe+=' -an -c:v pam -pix_fmt rgba -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1'; + if(e.coProcessor === false){ + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; + x.pipe+=' -an -c:v pam -pix_fmt rgba -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1'; + } break; case'b64':case'':case undefined:case null://base64 - if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; - if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} - x.pipe+=' -an -c:v mjpeg -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1'; + if(e.coProcessor === false){ + if(e.details.stream_quality && e.details.stream_quality !== '')x.cust_stream+=' -q:v '+e.details.stream_quality; + if(x.dimensions && x.cust_stream.indexOf('-s ')===-1){x.cust_stream+=' -s '+x.dimensions} + x.pipe+=' -an -c:v mjpeg -f image2pipe'+x.cust_stream+x.stream_video_filters+' pipe:1'; + } break; default: x.pipe='' @@ -1849,56 +1979,64 @@ s.ffmpeg=function(e){ } if(e.details.stream_channels){ e.details.stream_channels.forEach(function(v,n){ - x.pipe+=createStreamChannel(n+config.pipeAddition,v) + x.pipe += s.createStreamChannel(e,n+config.pipeAddition,v) }) } //detector - plugins, motion if(e.details.detector==='1'&&e.details.detector_send_frames==='1'){ - if(e.details.input_map_choices&&e.details.input_map_choices.detector){ - //add input feed map - x.pipe += createFFmpegMap(e.details.input_map_choices.detector) - } - if(!e.details.detector_fps||e.details.detector_fps===''){e.details.detector_fps=2} - if(e.details.detector_scale_x&&e.details.detector_scale_x!==''&&e.details.detector_scale_y&&e.details.detector_scale_y!==''){x.dratio=' -s '+e.details.detector_scale_x+'x'+e.details.detector_scale_y}else{x.dratio=' -s 320x240'} - if(e.details.cust_detect&&e.details.cust_detect!==''){x.cust_detect+=e.details.cust_detect;} - if(e.details.detector_pam==='1'){ - x.pipe+=' -an -c:v pam -pix_fmt gray -f image2pipe -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3' - if(e.details.detector_use_detect_object === '1'){ - //for object detection - x.pipe += createFFmpegMap(e.details.input_map_choices.detector) - x.pipe += ' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:4'; + if(e.details.accelerator !== '1'){ + if(e.details.input_map_choices&&e.details.input_map_choices.detector){ + //add input feed map + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector) + } + if(!e.details.detector_fps||e.details.detector_fps===''){e.details.detector_fps=2} + if(e.details.detector_scale_x&&e.details.detector_scale_x!==''&&e.details.detector_scale_y&&e.details.detector_scale_y!==''){x.dratio=' -s '+e.details.detector_scale_x+'x'+e.details.detector_scale_y}else{x.dratio=' -s 320x240'} + if(e.details.cust_detect&&e.details.cust_detect!==''){x.cust_detect+=e.details.cust_detect;} + if(e.details.detector_pam==='1'){ + x.pipe+=' -an -c:v pam -pix_fmt gray -f image2pipe -r '+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3' + if(e.details.detector_use_detect_object === '1'){ + //for object detection + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector) + x.pipe += ' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:4'; + } + }else{ + x.pipe+=' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3'; } - }else{ - x.pipe+=' -f singlejpeg -vf fps='+e.details.detector_fps+x.cust_detect+x.dratio+' pipe:3'; } } //api - snapshot bin/ cgi.bin (JPEG Mode) - if(e.details.snap==='1'){ + if(e.details.snap === '1'){ if(e.details.input_map_choices&&e.details.input_map_choices.snap){ //add input feed map - x.pipe += createFFmpegMap(e.details.input_map_choices.snap) + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.snap) + } + if(e.details.accelerator !== '1'){ + if(!e.details.snap_fps || e.details.snap_fps === ''){e.details.snap_fps = 1} + if(e.details.snap_vf && e.details.snap_vf !== ''){x.snap_vf=' -vf '+e.details.snap_vf}else{x.snap_vf=''} + if(e.details.snap_scale_x && e.details.snap_scale_x !== '' && e.details.snap_scale_y && e.details.snap_scale_y !== ''){x.snap_ratio = ' -s '+e.details.snap_scale_x+'x'+e.details.snap_scale_y}else{x.snap_ratio=''} + if(e.details.cust_snap && e.details.cust_snap !== ''){x.cust_snap = ' '+e.details.cust_snap}else{x.cust_snap=''} + x.pipe+=' -update 1 -r '+e.details.snap_fps+x.cust_snap+x.snap_ratio+x.snap_vf+' "'+e.sdir+'s.jpg" -y'; } - if(!e.details.snap_fps||e.details.snap_fps===''){e.details.snap_fps=1} - if(e.details.snap_vf&&e.details.snap_vf!==''){x.snap_vf=' -vf '+e.details.snap_vf}else{x.snap_vf=''} - if(e.details.snap_scale_x&&e.details.snap_scale_x!==''&&e.details.snap_scale_y&&e.details.snap_scale_y!==''){x.snap_ratio=' -s '+e.details.snap_scale_x+'x'+e.details.snap_scale_y}else{x.snap_ratio=''} - if(e.details.cust_snap&&e.details.cust_snap!==''){x.cust_snap=' '+e.details.cust_snap;}else{x.cust_snap=''} - x.pipe+=' -update 1 -r '+e.details.snap_fps+x.cust_snap+x.snap_ratio+x.snap_vf+' "'+e.sdir+'s.jpg" -y'; } //Traditional Recording Buffer if(e.details.detector=='1'&&e.details.detector_trigger=='1'&&e.details.detector_record_method==='sip'){ if(e.details.input_map_choices&&e.details.input_map_choices.detector_sip_buffer){ //add input feed map - x.pipe += createFFmpegMap(e.details.input_map_choices.detector_sip_buffer) + x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector_sip_buffer) } x.detector_buffer_filters=[] if(!e.details.detector_buffer_vcodec||e.details.detector_buffer_vcodec===''||e.details.detector_buffer_vcodec==='auto'){ - switch(e.type){ - case'h264':case'hls':case'mp4': - e.details.detector_buffer_vcodec = 'copy' - break; - default: - e.details.detector_buffer_vcodec = 'libx264' - break; + if(e.details.accelerator === '1' && e.details.hwaccel_vcodec === 'cuvid' && e.details.hwaccel_vcodec === ('h264_cuvid' || 'hevc_cuvid' || 'mjpeg_cuvid' || 'mpeg4_cuvid')){ + e.details.detector_buffer_vcodec = 'h264_nvenc' + }else{ + switch(e.type){ + case'h264':case'hls':case'mp4': + e.details.detector_buffer_vcodec = 'copy' + break; + default: + e.details.detector_buffer_vcodec = 'libx264' + break; + } } } if(!e.details.detector_buffer_acodec||e.details.detector_buffer_acodec===''||e.details.detector_buffer_acodec==='auto'){ @@ -1945,6 +2083,10 @@ s.ffmpeg=function(e){ } x.pipe+=x.detector_buffer_fps+x.detector_buffer_acodec+' -c:v '+e.details.detector_buffer_vcodec+' -f hls -tune '+e.details.detector_buffer_tune+' -g '+e.details.detector_buffer_g+' -hls_time '+e.details.detector_buffer_hls_time+' -hls_list_size '+e.details.detector_buffer_hls_list_size+' -start_number '+e.details.detector_buffer_start_number+' -live_start_index '+e.details.detector_buffer_live_start_index+' -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'detectorStream.m3u8"' } + if(e.coProcessor === true){ + // the coProcessor ffmpeg consumes this HLS stream (no audio, frames only) + x.pipe += ' -q:v 1 -an -c:v copy -f hls -tune zerolatency -g 1 -hls_time 2 -hls_list_size 3 -start_number 0 -live_start_index 3 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'cpuOnly.m3u8"' + } //custom - output if(e.details.custom_output&&e.details.custom_output!==''){x.pipe+=' '+e.details.custom_output;} //custom - input flags @@ -1955,7 +2097,7 @@ s.ffmpeg=function(e){ if(e.mode==='record'){ if(e.details.input_map_choices&&e.details.input_map_choices.record){ //add input feed map - x.record_string += createFFmpegMap(e.details.input_map_choices.record) + x.record_string += s.createFFmpegMap(e,e.details.input_map_choices.record) } //if h264, hls, mp4, or local add the audio codec flag switch(e.type){ @@ -1998,7 +2140,7 @@ s.ffmpeg=function(e){ //add extra input maps if(e.details.input_maps){ e.details.input_maps.forEach(function(v,n){ - x.ffmpegCommandString += createInputMap(n+1,v) + x.ffmpegCommandString += s.createInputMap(e,n+1,v) }) } //add recording and stream outputs @@ -2614,7 +2756,7 @@ s.camera=function(x,e,cn,tx){ e.frames=0; if(!s.group[e.ke].mon[e.id].record){s.group[e.ke].mon[e.id].record={yes:1}}; //launch ffmpeg (main) - s.group[e.ke].mon[e.id].spawn = s.ffmpeg(e); + s.group[e.ke].mon[e.id].spawn = s.ffmpeg(e) if(e.type === 'dashcam'){ setTimeout(function(){ s.group[e.ke].mon[e.id].allowStdinWrite = true @@ -2637,17 +2779,7 @@ s.camera=function(x,e,cn,tx){ } s.group[e.ke].mon[e.id].spawn.on('end',s.group[e.ke].mon[e.id].spawn_exit) s.group[e.ke].mon[e.id].spawn.on('exit',s.group[e.ke].mon[e.id].spawn_exit) - // -// s.group[e.ke].mon[e.id].spawn.stdio[5].on('data',function(data){ -// data = data.toString(); -// console.log('---') -// var json = {} -// data.split('\n').forEach(function(v){ -// var vv = v.split('=') -// json[vv[0]] = vv[1] -// }) -// console.log(json) -// }) + //emitter for mjpeg if(!e.details.stream_mjpeg_clients||e.details.stream_mjpeg_clients===''||isNaN(e.details.stream_mjpeg_clients)===false){e.details.stream_mjpeg_clients=20;}else{e.details.stream_mjpeg_clients=parseInt(e.details.stream_mjpeg_clients)} s.group[e.ke].mon[e.id].emitter = new events.EventEmitter().setMaxListeners(e.details.stream_mjpeg_clients); @@ -2735,114 +2867,120 @@ s.camera=function(x,e,cn,tx){ s.ocvTx({f:'init_monitor',id:e.id,ke:e.ke}) //frames from motion detect if(e.details.detector_pam==='1'){ - var width, - height, - globalSensitivity, - fullFrame = false - if(s.group[e.ke].mon_conf[e.id].details.detector_scale_x===''||s.group[e.ke].mon_conf[e.id].details.detector_scale_y===''){ - width = s.group[e.ke].mon_conf[e.id].details.detector_scale_x; - height = s.group[e.ke].mon_conf[e.id].details.detector_scale_y; - }else{ - width = e.width - height = e.height - } - if(e.details.detector_sensitivity===''){ - globalSensitivity = 10 - }else{ - globalSensitivity = parseInt(e.details.detector_sensitivity) - } - if(e.details.detector_frame==='1'){ - fullFrame={ - name:'FULL_FRAME', - sensitivity:globalSensitivity, - points:[ - [0,0], - [0,height], - [width,height], - [width,0] - ] - }; - } - var regions = s.createPamDiffRegionArray(s.group[e.ke].mon_conf[e.id].details.cords,globalSensitivity,fullFrame); - if(!s.group[e.ke].mon[e.id].noiseFilterArray)s.group[e.ke].mon[e.id].noiseFilterArray = {} - var noiseFilterArray = s.group[e.ke].mon[e.id].noiseFilterArray - Object.keys(regions.notForPam).forEach(function(name){ - if(!noiseFilterArray[name])noiseFilterArray[name]=[]; - }) - s.group[e.ke].mon[e.id].pamDiff = new PamDiff({grayscale: 'luminosity', regions : regions.forPam}); - s.group[e.ke].mon[e.id].p2p = new P2P(); - var sendTrigger = function(trigger){ - var detectorObject = { - f:'trigger', - id:e.id, - ke:e.ke, - name:trigger.name, - details:{ - plug:'built-in', + var createPamDiffEngine = function(){ + var width, + height, + globalSensitivity, + fullFrame = false + if(s.group[e.ke].mon_conf[e.id].details.detector_scale_x===''||s.group[e.ke].mon_conf[e.id].details.detector_scale_y===''){ + width = s.group[e.ke].mon_conf[e.id].details.detector_scale_x; + height = s.group[e.ke].mon_conf[e.id].details.detector_scale_y; + }else{ + width = e.width + height = e.height + } + if(e.details.detector_sensitivity===''){ + globalSensitivity = 10 + }else{ + globalSensitivity = parseInt(e.details.detector_sensitivity) + } + if(e.details.detector_frame==='1'){ + fullFrame={ + name:'FULL_FRAME', + sensitivity:globalSensitivity, + points:[ + [0,0], + [0,height], + [width,height], + [width,0] + ] + }; + } + var regions = s.createPamDiffRegionArray(s.group[e.ke].mon_conf[e.id].details.cords,globalSensitivity,fullFrame); + if(!s.group[e.ke].mon[e.id].noiseFilterArray)s.group[e.ke].mon[e.id].noiseFilterArray = {} + var noiseFilterArray = s.group[e.ke].mon[e.id].noiseFilterArray + Object.keys(regions.notForPam).forEach(function(name){ + if(!noiseFilterArray[name])noiseFilterArray[name]=[]; + }) + s.group[e.ke].mon[e.id].pamDiff = new PamDiff({grayscale: 'luminosity', regions : regions.forPam}); + s.group[e.ke].mon[e.id].p2p = new P2P(); + var sendTrigger = function(trigger){ + var detectorObject = { + f:'trigger', + id:e.id, + ke:e.ke, name:trigger.name, - reason:'motion', - confidence:trigger.percent, - }, - plates:[], - imgHeight:height, - imgWidth:width - } - detectorObject.doObjectDetection = (s.ocv && e.details.detector_use_detect_object === '1') - s.camera('motion',detectorObject) - if(detectorObject.doObjectDetection === true){ - s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:s.group[e.ke].mon[e.id].lastJpegDetectorFrame}); - } - } - var filterTheNoise = function(trigger){ - if(noiseFilterArray[trigger.name].length > 2){ - var thePreviousTriggerPercent = noiseFilterArray[trigger.name][noiseFilterArray[trigger.name].length - 1]; - var triggerDifference = trigger.percent - thePreviousTriggerPercent; - var noiseRange = e.details.detector_noise_filter_range - if(!noiseRange || noiseRange === ''){ - noiseRange = 6 + details:{ + plug:'built-in', + name:trigger.name, + reason:'motion', + confidence:trigger.percent, + }, + plates:[], + imgHeight:height, + imgWidth:width } - noiseRange = parseFloat(noiseRange) - if(((trigger.percent - thePreviousTriggerPercent) < noiseRange)||(thePreviousTriggerPercent - trigger.percent) > -noiseRange){ + detectorObject.doObjectDetection = (s.ocv && e.details.detector_use_detect_object === '1') + s.camera('motion',detectorObject) + if(detectorObject.doObjectDetection === true){ + s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:s.group[e.ke].mon[e.id].lastJpegDetectorFrame}); + } + } + var filterTheNoise = function(trigger){ + if(noiseFilterArray[trigger.name].length > 2){ + var thePreviousTriggerPercent = noiseFilterArray[trigger.name][noiseFilterArray[trigger.name].length - 1]; + var triggerDifference = trigger.percent - thePreviousTriggerPercent; + var noiseRange = e.details.detector_noise_filter_range + if(!noiseRange || noiseRange === ''){ + noiseRange = 6 + } + noiseRange = parseFloat(noiseRange) + if(((trigger.percent - thePreviousTriggerPercent) < noiseRange)||(thePreviousTriggerPercent - trigger.percent) > -noiseRange){ + noiseFilterArray[trigger.name].push(trigger.percent); + } + }else{ noiseFilterArray[trigger.name].push(trigger.percent); } + if(noiseFilterArray[trigger.name].length > 10){ + noiseFilterArray[trigger.name] = noiseFilterArray[trigger.name].splice(1,10) + } + var theNoise = 0; + noiseFilterArray[trigger.name].forEach(function(v,n){ + theNoise += v; + }) + theNoise = theNoise / noiseFilterArray[trigger.name].length; + // console.log(noiseFilterArray[trigger.name]) + // console.log(theNoise) + var triggerPercentWithoutNoise = trigger.percent - theNoise; + if(triggerPercentWithoutNoise > regions.notForPam[trigger.name].sensitivity){ + sendTrigger(trigger); + } + } + if(e.details.detector_noise_filter==='1'){ + s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => { + data.trigger.forEach(filterTheNoise) + }) }else{ - noiseFilterArray[trigger.name].push(trigger.percent); - } - if(noiseFilterArray[trigger.name].length > 10){ - noiseFilterArray[trigger.name] = noiseFilterArray[trigger.name].splice(1,10) - } - var theNoise = 0; - noiseFilterArray[trigger.name].forEach(function(v,n){ - theNoise += v; - }) - theNoise = theNoise / noiseFilterArray[trigger.name].length; -// console.log(noiseFilterArray[trigger.name]) -// console.log(theNoise) - var triggerPercentWithoutNoise = trigger.percent - theNoise; - if(triggerPercentWithoutNoise > regions.notForPam[trigger.name].sensitivity){ - sendTrigger(trigger); + s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => { + data.trigger.forEach(sendTrigger) + }) } } - if(e.details.detector_noise_filter==='1'){ - s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => { - data.trigger.forEach(filterTheNoise) - }) - }else{ - s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => { - data.trigger.forEach(sendTrigger) - }) - } - - s.group[e.ke].mon[e.id].spawn.stdio[3].pipe(s.group[e.ke].mon[e.id].p2p).pipe(s.group[e.ke].mon[e.id].pamDiff) - if(e.details.detector_use_detect_object === '1'){ - s.group[e.ke].mon[e.id].spawn.stdio[4].on('data',function(d){ - s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d - }) - } + if(e.coProcessor === false){ + createPamDiffEngine() + s.group[e.ke].mon[e.id].spawn.stdio[3].pipe(s.group[e.ke].mon[e.id].p2p).pipe(s.group[e.ke].mon[e.id].pamDiff) + if(e.details.detector_use_detect_object === '1'){ + s.group[e.ke].mon[e.id].spawn.stdio[4].on('data',function(d){ + s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d + }) + } + } }else{ - s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){ - s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d}); - }) + if(e.coProcessor === false){ + s.group[e.ke].mon[e.id].spawn.stdio[3].on('data',function(d){ + s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d}); + }) + } } } //frames to stream @@ -2896,7 +3034,11 @@ s.camera=function(x,e,cn,tx){ break; } if(e.frame_to_stream){ - s.group[e.ke].mon[e.id].spawn.stdout.on('data',e.frame_to_stream); + if(e.coProcessor === true && e.details.stream_type === ('b64'||'mjpeg')){ + + }else{ + s.group[e.ke].mon[e.id].spawn.stdout.on('data',e.frame_to_stream) + } } if(e.details.stream_channels&&e.details.stream_channels!==''){ var createStreamEmitter = function(channel,number){ @@ -3024,6 +3166,37 @@ s.camera=function(x,e,cn,tx){ s.log(e,{type:"FFMPEG STDERR",msg:d}) }); } + if(e.coProcessor === true){ + var coSpawnLauncher = function(){ + if(s.group[e.ke].mon[e.id].started === 1){ + s.group[e.ke].mon[e.id].coSpawnProcessor = s.ffmpegCoProcessor(e) + s.group[e.ke].mon[e.id].coSpawnProcessorExit = function(){ + s.log(e,{type:lang['coProcess Unexpected Exit'],msg:{msg:lang['coProcess Crashed for Monitor']+' : '+e.id,cmd:s.group[e.ke].mon[e.id].coProcessorCmd}}); + setTimeout(coSpawnLauncher,2000) + } + s.group[e.ke].mon[e.id].coSpawnProcessor.on('end',s.group[e.ke].mon[e.id].coSpawnProcessorExit) + s.group[e.ke].mon[e.id].coSpawnProcessor.on('exit',s.group[e.ke].mon[e.id].coSpawnProcessorExit) + s.group[e.ke].mon[e.id].coSpawnProcessor.stderr.on('data',function(d){ + d=d.toString(); + s.log(e,{type:lang.coProcessor,msg:d}); + }) + if(e.frame_to_stream){ + s.group[e.ke].mon[e.id].coSpawnProcessor.stdout.on('data',e.frame_to_stream) + } + if(e.details.detector === '1'){ + if(e.details.detector_pam === '1'){ + createPamDiffEngine() + s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].pipe(s.group[e.ke].mon[e.id].p2p).pipe(s.group[e.ke].mon[e.id].pamDiff) + }else{ + s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].on('data',function(d){ + s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d}); + }) + } + } + } + } + setTimeout(coSpawnLauncher,5000) + } }else{ s.log(e,{type:lang["Ping Failed"],msg:lang.skipPingText1}); errorFatal("Ping Failed");return; diff --git a/languages/en_CA.json b/languages/en_CA.json index 1fd09bcb..810a572c 100644 --- a/languages/en_CA.json +++ b/languages/en_CA.json @@ -521,8 +521,11 @@ "NoMotionEmailText1": "No Motion for", "NoMotionEmailText2": "There hasn't been any motion detected on camera for", "Monitor Name": "Monitor Name", + "coProcessor": "coProcessor", "Process Unexpected Exit": "Process Unexpected Exit", + "coProcess Unexpected Exit": "coProcess Unexpected Exit", "Process Crashed for Monitor": "Process Crashed for Monitor", + "coProcess Crashed for Monitor": "coProcess Crashed for Monitor", "FFmpegCantStart": "FFmpeg Couldn't Start", "FFmpegCantStartText": "The recording engine for this camera could not start. There may be something wrong with your camera configuration. If there are any logs other than this one please post them in the Issues on Github.", "JPEG Error": "JPEG Error",