Ffmpeg Progress Bar - Encoding Percentage in PHP

ffmpeg Progress Bar - Encoding Percentage in PHP

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. :)

FFMPEG (2.5.7 ) Progress Bar from PHP

Short answer:

Before you run the ffMPEG command here, you should run the following command, and that will give you the duration.

ffmpeg -i file.flv 2>&1 | grep "Duration"
Duration: 00:39:43.08, start: 0.040000, bitrate: 386 kb/s

You can then preg_match that wtih '/Duration: ([0-9]{*}):([0-9]{2}):([0-9]{2}).([0-9]{2})/' to get h, m, s and .s into variables.

Long Answer

There is another way you can handle. As opposed to using php-ffmpeg, simply work out what commands you need and run them directly using popen() (http://php.net/manual/en/function.popen.php) or proc_open() (http://php.net/manual/en/function.proc-open.php)

$cmd = "/path/to/ffmpeg -options";
$proc = popen($cmd, 'r');
while (!feof($proc))
{
echo fread($proc, 4096);
@flush();
}
pclose($proc);

This will essentially hold the process open for you as the command runs, and grabs output from the screen as it happens.

So run it twice; once for the duration, and a second time for the actual conversion. You can then process the output line by line, and save progress to another file/database which can be read by other processes.

Remember to set the PHP timeout to > time it takes to process the file.

what is the good function php to deal with ffmpeg and progress bar

My approach was something like this

$sCmd = "ffmpeg -i infile.mp4 ... -report outfile.mp4 > /var/log/ffmpeg.log";
$proc = popen($sCmd." 2>&1", "r");
$read = fread($proc, 2096);
pclose($proc);

Here is little bit modified code from one of my older projects. I hope it will give You some inspiration:

<?php
//get so far encoded time
public function getEncodedTime(){

$FFMPEGLog = file_get_contents('ffmpeg.log');
$times = explode('time=', $FFMPEGLog);
$ctime = count($times)-1;
$timed = explode(' bitrate=', $times[$ctime]);
//print_r($timed);
$nEncTime = $timed[0];
list($h, $m, $s) = explode(":", $nEncTime);
$s = ceil($s); // 21.40 seconds => 22 seconds
$nEncTime = hms2sec($h, $m, $s);

return $nEncTime;

}

//covert H:i:s time to seconds
public function hms2sec ($h, $m, $s) {

//list($h, $m, $s) = explode (":", $hms);
$seconds = 0;
$seconds += (intval((string)$h) * 3600);
$seconds += (intval((string)$m) * 60);
$seconds += (intval((string)$s));
return $seconds;

}

//get total length of file
public function getTotalTime()
{
$play_time_sec = 0;

$lines = file('ffmpeg.log');
foreach ($lines as $line_num => $line) {
if(strpos($line, 'Duration') !== false) {
$line = explode("Duration: ", $line);
$line = explode(",", $line[1]);
$line = explode(":", $line[0]);

$play_time_sec = 0;
$play_time_sec += intval((string)$line[0]) * 60 * 60; // hour
$play_time_sec += intval((string)$line[1]) * 60; // minute
$play_time_sec += intval((string)round($line[2])); // second
break;
}
}

return $play_time_sec;
}

//get percents completed:
public function getPercentsComplete()
{

$sFileContents = file_get_contents('ffmpeg.log');
if(stripos($sFileContents, 'No more inputs to read from, finishing') !== false) {
return 100;
}

$nTotalTime = getTotalTime();
$nEncodedTime = getEncodedTime();

if($nEncodedTime <= 0)
return 0;

if($nEncodedTime >= $nTotalTime)
return 100;

$nPercentsComplete = round(($nEncodedTime/$nTotalTime)*100);

return $nPercentsComplete;
}

Showing in-video visual progress bar with FFMPEG?

Here's a simple 3 second example using an animated overlay:

progress bar example

ffmpeg -i input.mp4 -filter_complex "color=c=red:s=1280x10[bar];[0][bar]overlay=-w+(w/10)*t:H-h:shortest=1" -c:a copy output.mp4

What you will have to change:

  • In the color filter I used 1280 as an example to match the width of input.mp4. You can use ffprobe to get the width or the scale2ref filter to resize to match input.mp4.

  • In the overlay filter I used 10 as an example for the total duration in seconds of input.mp4. You can use ffprobe to get the duration.



Related Topics



Leave a reply



Submit