How to programmatically start/stop FFMPEG stream transcoding

22,299

Solution 1

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:[email protected]/nphMotionJpeg?Resolution=640x480&Quality=Standard" -b:v 1500k -vcodec libx264 /tmp/test.mp4

I am now using

ffmpeg -y -f mjpeg -i "http://user:[email protected]/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:[email protected]/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(); 
?>

Solution 2

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.

Share:
22,299
Paul Wieland
Author by

Paul Wieland

I have been developing web sites, web applications &amp; Intranets since the age of 13 and so have become quite proficient with LAMP. In the last 5 years I have dabbled in iOS development. For the last 3 years in SAP. My hobbies include kitesurfing and photography.

Updated on December 10, 2020

Comments

  • Paul Wieland
    Paul Wieland over 3 years

    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:[email protected]/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:[email protected]/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