Shinobi/libs/ffmpeg.js

159 lines
6.6 KiB
JavaScript

const fs = require('fs');
const spawn = require('child_process').spawn;
const execSync = require('child_process').execSync;
module.exports = async (s,config,lang,onFinish) => {
const {
sanitizedFfmpegCommand,
createPipeArray,
splitForFFMPEG,
checkForWindows,
checkForUnix,
checkStaticBuilds,
checkVersion,
checkHwAccelMethods,
} = require('./ffmpeg/utils.js')(s,config,lang)
const {
buildMainInput,
buildMainStream,
buildJpegApiOutput,
buildMainRecording,
buildAudioDetector,
buildMainDetector,
buildEventRecordingOutput,
buildTimelapseOutput,
} = require('./ffmpeg/builders.js')(s,config,lang)
if(config.ffmpegBinary)config.ffmpegDir = config.ffmpegBinary
s.ffmpeg = function(e){
try{
const activeMonitor = s.group[e.ke].activeMonitors[e.mid];
const dataPortToken = s.gid(10);
s.dataPortTokens[dataPortToken] = {
type: 'cameraThread',
ke: e.ke,
mid: e.mid,
}
const ffmpegCommand = [`-progress pipe:5`];
const allOutputs = [
buildMainStream(e),
buildJpegApiOutput(e),
buildMainRecording(e),
buildAudioDetector(e),
buildMainDetector(e),
buildEventRecordingOutput(e),
buildTimelapseOutput(e),
];
if(allOutputs.filter(output => !!output).length > 0){
return new Promise((resolve) => {
var hasResolved = false
function completeResolve(data){
if(!hasResolved){
hasResolved = true
resolve(data)
}
}
try{
([
buildMainInput(e),
]).concat(allOutputs).forEach(function(commandStringPart){
ffmpegCommand.push(commandStringPart)
})
s.onFfmpegCameraStringCreationExtensions.forEach(function(extender){
extender(e,ffmpegCommand)
})
const stdioPipes = createPipeArray(e)
const ffmpegCommandString = ffmpegCommand.join(' ')
//hold ffmpeg command for log stream
activeMonitor.ffmpeg = sanitizedFfmpegCommand(e,ffmpegCommandString)
//clean the string of spatial impurities and split for spawn()
const ffmpegCommandParsed = splitForFFMPEG(ffmpegCommandString)
try{
fs.rmSync(e.sdir + 'cmd.txt')
}catch(err){
}
fs.writeFileSync(e.sdir + 'cmd.txt',JSON.stringify({
dataPortToken: dataPortToken,
cmd: ffmpegCommandParsed,
pipes: stdioPipes.length,
rawMonitorConfig: s.group[e.ke].rawMonitorConfigurations[e.id],
globalInfo: {
config: config,
isAtleatOneDetectorPluginConnected: s.isAtleatOneDetectorPluginConnected
}
},null,3),'utf8')
var cameraCommandParams = [
config.monitorDaemonPath ? config.monitorDaemonPath : __dirname + '/cameraThread/singleCamera.js',
config.ffmpegDir,
e.sdir + 'cmd.txt'
]
const cameraProcess = spawn('node',cameraCommandParams,{detached: true,stdio: stdioPipes})
if(config.debugLog === true && config.debugLogMonitors === true){
cameraProcess.stderr.on('data',(data) => {
const string = data.toString()
var checkLog = function(x){return string.indexOf(x)>-1}
switch(true){
case checkLog('pkt->duration = 0'):
case checkLog('[hls @'):
case checkLog('Past duration'):
case checkLog('Last message repeated'):
case checkLog('Non-monotonous DTS'):
case checkLog('NULL @'):
case checkLog('RTP: missed'):
case checkLog('deprecated pixel format used'):
if(!config.debugLogMonitorsVerbose){
return;
}
break;
}
console.log(`${e.ke} ${e.name} (${e.mid})`)
console.log(data.toString())
})
}
completeResolve(cameraProcess)
}catch(err){
completeResolve(null)
s.systemLog(err)
return null
}
})
}else{
return null
}
}catch(err){
s.systemLog(err)
return null
}
}
if(!config.ffmpegDir){
if(s.isWin){
const windowsCheck = checkForWindows()
if(!windowsCheck.ok){
const staticBuildCheck = await checkStaticBuilds()
if(!staticBuildCheck.ok){
console.log(staticBuildCheck.msg)
console.log('No FFmpeg found.')
}
}
}else{
const staticBuildCheck = await checkStaticBuilds()
if(!staticBuildCheck.ok){
const unixCheck = checkForUnix()
if(!unixCheck.ok){
console.log(staticBuildCheck.msg.join('\n'))
console.log(unixCheck.msg)
console.log('No FFmpeg found.')
}
}else if(staticBuildCheck.msg.length > 0){
console.log(staticBuildCheck.msg.join('\n'))
}
}
}
checkVersion()
checkHwAccelMethods()
s.onFFmpegLoadedExtensions.forEach(function(extender){
extender()
})
onFinish()
}