Jimbo Jimbo - 4 months ago 181
PHP Question

ffmpeg Progress Bar - Encoding Percentage in PHP

I've written a whole system in PHP and bash on the server to convert and stream videos in HTML5 on my VPS. The conversion is done by ffmpeg in the background and the contents is output to block.txt.

Having looked at the following posts:

Can ffmpeg show a progress bar?

and

ffmpeg video encoding progress bar

amongst others, I can't find a working example.

I need to grab the currently encoded progress as a percentage.

The first post I linked above gives:

$log = @file_get_contents('block.txt');

preg_match("/Duration:([^,]+)/", $log, $matches);
list($hours,$minutes,$seconds,$mili) = split(":",$matches[1]);
$seconds = (($hours * 3600) + ($minutes * 60) + $seconds);
$seconds = round($seconds);

$page = join("",file("$txt"));
$kw = explode("time=", $page);
$last = array_pop($kw);
$values = explode(' ', $last);
$curTime = round($values[0]);
$percent_extracted = round((($curTime * 100)/($seconds)));

echo $percent_extracted;


The $percent_extracted variable echoes zero, and as maths is not my strong point, I really don't know how to progress here.

Here's one line from the ffmpeg output from block.txt (if it's helpful)


time=00:19:25.16 bitrate= 823.0kbits/s frame=27963 fps= 7 q=0.0 size=
117085kB time=00:19:25.33 bitrate= 823.1kbits/s frame=27967 fps= 7
q=0.0 size= 117085kB time=00:19:25.49 bitrate= 823.0kbits/s
frame=27971 fps= 7 q=0.0 size= 117126kB


Please help me output this percentage, once done I can create my own progress bar. Thanks.

Answer

Okay, I've found what I needed - and hopefully this helps someone else as well!

First and foremost, you want to output the ffmpeg data to a text file on the server.

ffmpeg -i path/to/input.mov -vcodec videocodec -acodec audiocodec path/to/output.flv 1> block.txt 2>&1

So, the ffmpeg output is block.txt. Now in PHP, let's do this!

$content = @file_get_contents('../block.txt');

if($content){
    //get duration of source
    preg_match("/Duration: (.*?), start:/", $content, $matches);

    $rawDuration = $matches[1];

    //rawDuration is in 00:00:00.00 format. This converts it to seconds.
    $ar = array_reverse(explode(":", $rawDuration));
    $duration = floatval($ar[0]);
    if (!empty($ar[1])) $duration += intval($ar[1]) * 60;
    if (!empty($ar[2])) $duration += intval($ar[2]) * 60 * 60;

    //get the time in the file that is already encoded
    preg_match_all("/time=(.*?) bitrate/", $content, $matches);

    $rawTime = array_pop($matches);

    //this is needed if there is more than one match
    if (is_array($rawTime)){$rawTime = array_pop($rawTime);}

    //rawTime is in 00:00:00.00 format. This converts it to seconds.
    $ar = array_reverse(explode(":", $rawTime));
    $time = floatval($ar[0]);
    if (!empty($ar[1])) $time += intval($ar[1]) * 60;
    if (!empty($ar[2])) $time += intval($ar[2]) * 60 * 60;

    //calculate the progress
    $progress = round(($time/$duration) * 100);

    echo "Duration: " . $duration . "<br>";
    echo "Current Time: " . $time . "<br>";
    echo "Progress: " . $progress . "%";

}

This outputs the percentage of time left.

You can have this as the only piece of text echoed out to a page, and from another page you can perform an AJAX request using jQuery to grab this piece of text and output it into a div, for example, to update on your page every 10 seconds. :)