Mr.ZZ
Mr.ZZ

Reputation: 368

ffmpeg progress percentage in php

ffmpeg.php

$sCmd = "ffmpeg -i ".$image." -i ".$music." video.avi 1> progress.txt";
$proc = popen($sCmd." 2>&1", "r");

progress.php

$content = @file_get_contents('progress.txt');
if($content){
    preg_match("/Duration: (.*?), start:/", $content, $matches);
    $rawDuration = $matches[1];
    $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;
    preg_match_all("/time=(.*?) bitrate/", $content, $matches);
    $rawTime = array_pop($matches);
    if (is_array($rawTime)){$rawTime = array_pop($rawTime);}
    $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;
    $progress = round(($time/$duration) * 100);
    echo $progress;
}

progress.php final output was always 100, so it was easy with jquery to hide progress and show download button.

BUT after changing ffmpeg.php with this command:

$sCmd = "ffmpeg -loop 1 -r 1 -i ".$image." -i ".$music." -c:a copy -shortest video.avi 1> progress.txt";
$proc = popen($sCmd." 2>&1", "r");

progress.php output is different numbers above 100(thousands) and jquery can't figure out ffmpeg process finished or not.

How to get 100 when ffmpeg finishs working? I think i need some changes in progress.php because final result in progress.txt is longer than before.

Upvotes: 1

Views: 1735

Answers (1)

albert
albert

Reputation: 4468

I would recommend using symfony process component https://symfony.com/doc/current/components/process.html .

You have multiple options:

Flushing progress while the process has not finished

This allow you to start an async process and check if it has finished or not.

$process = new Process('ffmpeg -i ".$image." -i ".$music." video.avi 1> progress.txt');
$process->run(function ($type, $data) {
    echo $data;
    fflush();
});

A more complicated way is to get the process ID and check if that process is still alive with subsequent requests.

Return a response with the process id and update REDIS/cache/database with the progress

A more complicated way is to get the process ID and check if that process is still alive with subsequent requests.

// Setup process and an std output that updates redis
$process=new Process(...);
//Start process
$process->start(function ($type, $data) use ($redisService, $process){
    $pid=$process->getPid();
    $redisService->received($pid, $type, $data);
});
$pid=$process->getPid();
return JsonResponse(["pid"=>$pid, "running"=>$process->isRunning()]);

Upvotes: 1

Related Questions