3

I'm trying to use FFMPEG to make some works with video on the server, and something I need to do is to get the progress of the process.

I searched a little and I found this solution which tells to write the log into a file and then reading and parsing it.

The problem

What is driving me crazy is that I tell FFMPEG - with exec - (process A) to write the log into a file, but when I try to read it - with file_get_contents() - (process B) it does not show the contents until process A is finished (or interrupted the PHP script).

So, when process A finishes or it says "PHP script timeout", then I can read the file as times as I want, refreshing the page (process B) and showing the contents at the time.

What I've tried

I've tried to use fopen() to create the file with w, w+ and a parameters, using - and without using - fclose(). I've tried to use also flock() just in case it gets faster to read to process B if it knows it's already locked and does not have to wait, but then FFMPEG is not able to write into the file.

I've searched for multithreading too, but I think there must be an easier and simpler way.

I've used also CURL and HTTP context, as this link suggests, but no luck.

I've tried, too, to use PHP-FFMPEG but it's not supporting the last FFMPEG version, so I cannot use it.

When I said before "(or interrupted the PHP script)" is because I tried to wait and, when PHP got a timeout, process B worked alright and the file was still updating.

The code

Process A (fileA.php)

exec('ffmpeg -y -i input_file.mp4 output_file.avi 2> C:\Full\Path\To\File\log.txt 1>&2');

Process B (fileB.php)

$content = file_get_contents($file);

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 . "%";

}

The process

I just open fileA.php on a Chrome tab and, after a few seconds, I open fileB.php on another Chrome tab (and it stays as loading).

What I need

I need to be able to load the file and show the information I want to show while the file is being written (by exec and FFMPEG or other PHP scripts), so I can update the progress percentage with some AJAX calls.

Extra information

At this point, I'm using PHP 5.4 on a IIS 7.5 with Windows 7 Professional.

Thank you everyone for your time, help and patience!

Best regards.

Community
  • 1
  • 1
Unapedra
  • 1,649
  • 2
  • 20
  • 33
  • Have you verified that the `Log.txt` gets written and filled with content before Process A finishes? – maxhb Feb 01 '16 at 13:36
  • Yes! It gets! I can, in fact, open the file with Notepad and see the text, and it still gets written if I close it and open it again. – Unapedra Feb 01 '16 at 14:06
  • However, in case it does not get written, I should see a blank screen because the script has already loaded all the content (it is, none), but I get a "loading" screen until process A crashes or finishes... – Unapedra Feb 01 '16 at 15:36

1 Answers1

0

It seems that is working now. After so many tries without working, the only modification I did that seems to get sense is writing session_write_close() before calling the exec command. So, following my example, it would be something like:

session_write_close();
exec('ffmpeg -y -i input_file.mp4 output_file.avi 2> C:\Full\Path\To\File\log.txt 1>&2');

Now, I'd be very pleased if someone told me if this makes any sense or if it has to do with something else I cannot see.

Thank you!

Unapedra
  • 1,649
  • 2
  • 20
  • 33
  • Now it's not working again at some points... it randomly works and stops working. I will try to check my IIS and PHP configurations, because I can not understand nothing. Thank you everyone for your time, anyway! – Unapedra Feb 02 '16 at 12:41