Question

I have an ip webcam which provides an MJPEG stream. I can successfully transcode and save that stream with ffmpeg under OSX. The following gives me pretty much what I want:

ffmpeg -f mjpeg -i "http://user:pass@10.0.1.200/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4

That will start an FFMPEG session and begin saving the live stream to my test.mp4 file. pressing q will quit ffmpeg and save the file.

I would like to programmatically start & stop the recording using a PHP or Bash shell script. I have tried the following:

<?php

$pid = pcntl_fork();

if($pid == -1){
    die("could not fork"); 
}elseif($pid){
    // we are the parent...
    print $pid.' started recording. waiting 10 seconds...';
    sleep(10); // Wait 10 seconds

    print_r(shell_exec("kill ".$pid)); // Kill the child recording process

    echo 'done';
    exit(); 
}else{
    // we are the child process. call ffmpeg.
    exec('../lib/ffmpeg -f mjpeg -i "http://user:pass@10.0.1.200/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4');
}

But there are two problems:

  1. The ffmpeg process does not end/die (probably because its forked again)
  2. When I manually kill the ffmpeg process, the video file is not readable
Was it helpful?

Solution

So I was doing a combination of things wrong.

For starters, I needed to push the output form ffmpeg to a log file and also tell it to overwrite my temp file without prompting using the -y argument.

So instead of

ffmpeg -f mjpeg -i "http://user:pass@10.0.1.200/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4

I am now using

ffmpeg -y -f mjpeg -i "http://user:pass@10.0.1.200/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4 </dev/null >/dev/null 2>/tmp/ffmpeg.log &

The second problem was that I wasn't waiting long enough before sending the kill command to ffmpeg, and so a corrupt file was being created.

By adding the -t (for time limit) argument with 1 second, I determined that it takes an average of 15 seconds for ffmpeg to record 1 second of video. Increasing the time limit to 10 seconds made the average increase to 25 seconds, so it seems that on my server at least, theres 14 seconds of overhead. By increasing my sleep command in my php script to 30 seconds, I was able to get a useable video file.

So having PHP kill the ffmpeg process results in an unknown (or approximate at best) recording time length which is completely dependent on CPU power, network bandwidth, etc.

Thats a bit of a bummer because I had hoped to be able to increase the recording length depending on some external variables (I have insteon motion sensors feeding a database, i would like to record until the motion stops).

In any event, here is a working PHP script in case it helps someone in the future:

<?php
print date('H:i:s')."\nStarted recording. waiting 60 seconds...\n";
exec('../lib/ffmpeg -y -f mjpeg -i "http://user:pass@10.0.1.200/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4 </dev/null >/dev/null 2>/tmp/ffmpeg.log &');
sleep(60); // Wait long enough before killing, otherwise the video will be corrupt!

shell_exec('pkill ffmpeg'); // find and kill    
echo "done\n\n";
exit(); 
?>

OTHER TIPS

Send a SIGQUIT signal to the background process to terminate the ffmpeg command normally.

Just use

kill -s QUIT $PID

and the process will finish with a non-corrupted MP4 video file.

Send the "q" key:

process.StandardInput.WriteLine("q");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top