ffmpeg进度条-PHP中的编码百分比


ffmpeg Progress Bar - Encoding Percentage in PHP

我在服务器上用PHP和bash编写了一个完整的系统,用于在我的VPS上转换和流式传输HTML5视频。转换由ffmpeg在后台完成,内容输出到block.txt.

看过以下帖子:

ffmpeg可以显示进度条吗?

ffmpeg视频编码进度条

除此之外,我找不到一个可行的例子。

我需要获取当前编码的进度百分比。

我在上面链接的第一篇文章给出了:

$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;

$percent_extracted变量的回声为零,由于数学不是我的强项,我真的不知道如何在这里进步。

这是block.txt的ffmpeg输出中的一行(如果有用的话)

时间=00:19:25.16比特率=823.0kbits/s帧=27963帧/秒=7 q=0.0大小=117085kB时间=00:19:25.33比特率=823.1kbits/s帧=27967 fps=7q=0.0大小=117085kB时间=00:19:25.49比特率=823.0kbits/s帧=27971帧/秒=7 q=0.0大小=117126kB

请帮我输出这个百分比,一旦完成,我可以创建自己的进度条。谢谢

好吧,我找到了我需要的东西,希望这也能帮助其他人!

首先,您需要将ffmpeg数据输出到服务器上的文本文件中

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

所以,ffmpeg的输出是block.txt。现在在PHP中,让我们这样做吧

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

这将输出剩余时间的百分比。

您可以将其作为回显到页面的唯一一段文本,也可以从另一个页面使用jQuery执行AJAX请求,获取这段文本并将其输出到div中,例如,每隔10秒更新一次页面。:)

ffmpeg现在有了一个进度选项,可以更容易地解析输出

ffmpeg-progress block.txt-i路径/to/input.mov-vcodec视频编解码器-acodec音频编解码器路径/to/output.flv 2>&1

在你开始编码之前,你可以获得总的帧数,以及许多其他信息(这就是bash的功能。我是一名Perl程序员,所以我不知道如何将这些信息输入到你的PHP脚本中)。

eval$(ffprobe-of-flat=s=_-show_entries stream=height,width,nb_frames,duration,codec_name path/to/input.mov)
width=${streams_stream_0_width}
height=${streams_stream_0_height}
frames=${streams_stream_0_nb_frames}
视频持续时间=${streams_stream_0_duration}
音频持续时间=${streams_stream_1_duration}
编解码器=${streams_stream_0_codec_name}
echo$width,$height,$frames,$videoduration,$audiodation,$codec;

-flate=s=_表示将每个名称=值放在单独的一行上-show_entries告诉它显示以下内容中的条目(stream for-show_streams,format for-shhow_format,etc.)stream=。。。表示显示-show_streams输出中的那些项目。尝试以下操作查看可用内容:

ffprobe-show_streams路径/到/input.mov

进度文件的输出大约每秒添加一次。编码完成后的内容如下所示。在我的脚本中,我每秒一次将文件放入数组中,并以相反的顺序遍历数组,只使用我找到的第一行[反转前的最后一行]和两行"进度"之间的内容,这样我就使用了文件末尾的最新信息。也许还有更好的方法。这是来自一个没有音频的mp4,所以只有一个流

帧=86
fps=0.0
stream_0_0_q=23.0
total_size=103173
out_time_ms=1120000
out_time=00:00:01.120000
dup_frames=0
drop_frames=0
进度=继续
帧=142
fps=140.9
stream_0_0_q=23.0
total_size=415861
out_time_ms=3360000
out_time=00:00:03.360000
dup_frames=0
drop_frames=0
进度=继续
框架=185
fps=121.1
stream_0_0_q=23.0
total_size=1268982
out_time_ms=5080000
out_time=00:00:05.080000
dup_frames=0
drop_frames=0
进度=继续
帧=225
fps=110.9
stream_0_0_q=23.0
total_size=2366000
out_time_ms=6680000
out_time=00:00:06.680000
dup_frames=0
drop_frames=0
进度=继续
帧=262
fps=103.4
stream_0_0_q=23.0
total_size=3810570
out_time_ms=8160000
out_time=00:00:08.160000
dup_frames=0
drop_frames=0
进度=继续
帧=299
fps=84.9
stream_0_0_q=-1.0
total_size=6710373
out_time_ms=11880000
out_time=00:00:11.880000
dup_frames=0
drop_frames=0
进度=结束

如果javascript更新进度条,javascript可以"直接"执行步骤2:

[此示例需要dojo]


1 php:开始转换并将状态写入文本文件-示例语法:

exec("ffmpeg -i path/to/input.mov path/to/output.flv 1>path/to/output.txt 2>&1");

对于第二部分,我们只需要javascript来读取文件。下面的例子使用了AJAX的dojo.request,但您也可以使用jQuery或vanilla或其他任何东西:

[2]js:从文件获取进度

var _progress = function(i){
    i++;
    // THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] : 
    var logfile = 'path/to/output.txt';
/* (example requires dojo) */
request.post(logfile).then( function(content){
// AJAX success
    var duration = 0, time = 0, progress = 0;
    var result = {};
    // get duration of source
    var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
    if( matches.length>0 ){
        var rawDuration = matches[1];
        // convert rawDuration from 00:00:00.00 to seconds.
        var ar = rawDuration.split(":").reverse();
        duration = parseFloat(ar[0]);
        if (ar[1]) duration += parseInt(ar[1]) * 60;
        if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
        // get the time 
        matches = content.match(/time=(.*?) bitrate/g);
        console.log( matches );
        if( matches.length>0 ){
            var rawTime = matches.pop();
            // needed if there is more than one match
            if (lang.isArray(rawTime)){ 
                rawTime = rawTime.pop().replace('time=','').replace(' bitrate',''); 
            } else {
                rawTime = rawTime.replace('time=','').replace(' bitrate','');
            }
            // convert rawTime from 00:00:00.00 to seconds.
            ar = rawTime.split(":").reverse();
            time = parseFloat(ar[0]);
            if (ar[1]) time += parseInt(ar[1]) * 60;
            if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
            //calculate the progress
            progress = Math.round((time/duration) * 100);
        }
        result.status = 200;
        result.duration = duration;
        result.current  = time;
        result.progress = progress;
        console.log(result);
        /* UPDATE YOUR PROGRESSBAR HERE with above values ... */
        if(progress==0 && i>20){
            // TODO err - giving up after 8 sec. no progress - handle progress errors here
            console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }'); 
            return;
        } else if(progress<100){ 
            setTimeout(function(){ _progress(i); }, 400);
        }
    } else if( content.indexOf('Permission denied') > -1) {
        // TODO - err - ffmpeg is not executable ...
        console.log('{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }');    
    } 
},
function(err){
// AJAX error
    if(i<20){
        // retry
        setTimeout(function(){ _progress(0); }, 400);
    } else {
        console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }');
        console.log( err ); 
    }
    return; 
});
}
setTimeout(function(){ _progress(0); }, 800);