1

Possible Duplicate:
Run a ffmpeg process in the background

I was wondering if there's any easy way to runn and ffmpeg process in the background so people can leave the page. And if you do that, then tell if the ffmpeg process is running, and when it's done, update the database to "finished". I'll post my code if I need to. Thanks! Here's the code on the processing page:

<?php
$name = $_FILES['upload_file']['name'];
$type = $_FILES['upload_file']['type'];
$size = $_FILES['upload_file']['size'];
$tmpname = $_FILES['upload_file']['tmp_name'];

if (!$title) {
    $title = $name;
}

if (!$description) {
    $description = "No description available.";
}

$string = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',10)),0,10);
$videoname = "$string.mp4";
$date = date("F d, Y"); // October 09, 2010
$srcFile = $tmpname;
mkdir("users/$usercode/uploads/$string");
mkdir("users/$usercode/uploads/$string/HD");
mkdir("users/$usercode/uploads/$string/regular");
mkdir("users/$usercode/uploads/$string/mobile_upload");
mkdir("users/$usercode/uploads/$string/thumbnails");
$destFile1 = "/users/$usercode/uploads/$string/HD/$string.mp4";
$destFile2 = "/users/$usercode/uploads/$string/regular/$string.mp4";
$destFile3 = "/users/$usercode/uploads/$string/mobile_upload/$string.mp4";
$ffmpegPath = "/usr/local/bin/ffmpeg"; 
$flvtool2Path = "/usr/bin/flvtool2";
$yamdiPath = "/usr/bin/yamdi";
$mp4boxPath = "/usr/local/bin/MP4Box";
// Create our FFMPEG-PHP class 
$ffmpegObj = new ffmpeg_movie($srcFile); 
// Save our needed variables 
$srcWidth = $ffmpegObj->getFrameWidth(); 
$srcHeight = $ffmpegObj->getFrameHeight(); 
$srcFPS = $ffmpegObj->getFrameRate(); 
$srcAB = $ffmpegObj->getAudioBitRate();  
$srcAR = $ffmpegObj->getAudioSampleRate(); 
$res = $srcWidth . "x" . $srcHeight; 
// Call our convert using exec() 
$iphone1 = getcwd().$destFile1;
$iphone2 = getcwd().$destFile2;
$iphone3 = getcwd().$destFile3;
$low = "854x480";
$local_img = "/users/$usercode/uploads/$string/thumbnails/$string.jpg";
$img = getcwd().$local_img;
$img = preg_replace('/ /','\ ',$img); 
$thumb = "$string.jpg"; 
$cmd = "$ffmpegPath -i $tmpname 2>&1";  
if (preg_match('/Duration: ((\d+):(\d+):(\d+))/s', `$cmd`, $time)) {  
    $total = ($time[2] * 3600) + ($time[3] * 60) + $time[4];  
    $interval = rand(0, $total);  
}  

$img = shell_exec("$ffmpegPath -ss $interval -i $tmpname 2>&1 -s 120x90 -f mjpeg -vframes 1 $img");


if ($srcWidth >= 1280 && $srcHeight >= 720) {
    $out1 = shell_exec("$ffmpegPath -i $tmpname -f mp4 -vcodec libx264 -vpre normal -ab $srcAB -ar $srcAR -b 5000k -r $srcFPS -s $res -acodec libfaac $iphone1");
    $out2 = shell_exec("$mp4boxPath -inter 0.5 $iphone1");
    $out3 = shell_exec("$ffmpegPath -i $tmpname -f mp4 -vcodec libx264 -vpre normal -ab $srcAB -ar $srcAR -b 2000k -r $srcFPS -s $low -acodec libfaac $iphone2");
    $out4 = shell_exec("$mp4boxPath -inter 0.5 $iphone2");
    $out5 = shell_exec("$ffmpegPath -i $tmpname -f mp4 -vcodec libx264 -vpre slow -ab 64k -ar 44100 -b 500k -r 30 -s $low -acodec libfaac $iphone3");
    $out6 = shell_exec("$mp4boxPath -inter 0.5 $iphone3");
    echo 1;
}
else {
    $out3 = shell_exec("$ffmpegPath -i $tmpname -f mp4 -vcodec libx264 -vpre normal -ab 64k -ar 44100 -b 500k -r 30 -s $low -acodec libfaac $iphone2");
    $out4 = shell_exec("$mp4boxPath -inter 0.5 $iphone2");
    $out5 = shell_exec("$ffmpegPath -i $tmpname -f mp4 -vcodec libx264 -vpre slow -ab 64k -ar 44100 -b 500k -r 30 -s $low -acodec libfaac $iphone3");
    $out6 = shell_exec("$mp4boxPath -inter 0.5 $iphone3");          
    echo 1;
}
function generate_random($number_of_characters)
{
        $characters = array();
        $randomchar = "";
        $x = 0;
        for($i = 48; $i < 123; $i++)
        {
                if(ctype_alnum(chr($i)))
                {
                        $characters[$x] = chr($i);
                        $x++;
                }
        }
        for($i = 0; $i < $number_of_characters; $i++)
        {
                $randomchar .= $characters[rand(0, count($characters) - 1)];
        }
        return $randomchar;
}
?>
Community
  • 1
  • 1
toms900
  • 11
  • 1
  • 3
  • It's generally always a good idea to post the code. :) – jimp Sep 27 '12 at 02:44
  • I think your answer is here: http://stackoverflow.com/questions/1198052/run-a-ffmpeg-process-in-the-background?rq=1 – jimp Sep 27 '12 at 02:47
  • Ya, I tried looking at that, but I don't quite understand how I would be able to implement that into my existing code :/ – toms900 Sep 27 '12 at 02:51
  • Thank you! I've been trying to figure this out for a while haha. Everything else works, just this one little thing! :) – toms900 Sep 27 '12 at 02:57
  • 2
    Your code is terribly insecure. You are **wide open** to SQL injection, and you **will be hacked** if you haven't already. Learn to use prepared queries with PDO or equivalent to avoid this problem. In addition, it isn't clear what `$usercode` is, but you might be opening up yourself to troubles where folks can execute and do whatever they want on your server while they're at it. – Brad Sep 27 '12 at 02:57

1 Answers1

1

First of all, your code is very subject to SQL injection attacks and shell argument attacks. You need to escape all of your input to SQL and the shell commands!

I think this would be a standard approach to solving this problem:

  1. Write your ffmpeg "job" to a database tuple. Note the job number, which would be the tuple's primary key. At this time the "status" needs to be something other than "complete."
  2. Move all of your ffmpeg processing code to a helper PHP script. By helper, I simply mean another script. Call it something like "ffmpeg_job_processor.php".
  3. Run that script in the background with a call to exec('php ffmpeg_job_processor.php '.escapeshellarg($jobNumber).' > /dev/null &'); The script will load the job from the database by ID, do all the processing, and when it's done it will update the database to "complete."
  4. A web-based job monitor page could easily display the job status by looking up the same tuple by ID.

The trick is executing the second PHP script in the background so it will release your calling PHP script to continue on without blocking. You'll have to pipe your stdout to /dev/null (Linux box) and using the backgrounding operator &.

Some more good information is here: Run a ffmpeg process in the background

Community
  • 1
  • 1
jimp
  • 16,999
  • 3
  • 27
  • 36
  • Any suggestions on how to patch the SQL things up? This is some old code I found and was hoping to get it working again. – toms900 Sep 27 '12 at 03:07
  • The mysql extension is deprecated, but if you want to keep using it you must quote all SQL query arguments with `mysql_real_escape_string`. – jimp Sep 27 '12 at 03:08
  • Looks like I've got some patching up to do! Thank's guys for the feedback! – toms900 Sep 27 '12 at 03:16
  • No problem! And don't forget `escapeshellarg` for all those shell commands if any of them are constructed from external input. Even if they aren't, it is good practice anyway. – jimp Sep 27 '12 at 03:19