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

我用PHP编写了一个完整的系统,然后在服务器上运行,在我的VPS上转换和stream式处理HTML5中的video。 转换是由ffmpeg在后台完成的,内容输出到block.txt

看了以下post:

ffmpeg能显示进度条吗?

ffmpegvideo编码进度条

其中,我找不到一个工作的例子。

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

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

$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_extractedvariables回声为零,而math不是我的强项,我真的不知道如何在这里进步。

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

时间= 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时间= 00:19:25.49 bitrate = 823.0kbits / s frame = 27971 fps = 7 q = 0.0 size = 117126kB

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

好吧,我已经find了我需要的东西 – 希望这也能帮助别人!

首先,您要将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现在有一个进度选项,可以让输出更容易parsing。

ffmpeg -progress block.txt -i path / to / input.mov -vcodec videocodec -acodec audiocodec path / 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);
宽度= $ {streams_stream_0_width};
高度= $ {streams_stream_0_height};
帧= $ {streams_stream_0_nb_frames};
videoduration = $ {streams_stream_0_duration};
audioduration = $ {streams_stream_1_duration};
编解码器= $ {streams_stream_0_codec_name};
echo $ width,$ height,$ frames,$ videoduration,$ audioduration,$ codec;

-of flate = s = _表示将每个name = value放在一个单独的行中。 -show_entries告诉它显示下面的条目(-show_streams的stream,-show_format的格式等等)stream = …表示从-show_streams输出中显示这些条目。 尝试以下看看有什么可用的:

ffprobe -show_streams path / to / input.mov

进度文件的输出大约每秒添加一次。 编码完成后的内容如下所示。 在我的脚本中,每秒一次,我把文件放到一个数组中,并以相反的顺序遍历数组,只使用我find的两个“progress”行之间的第一个[last before reversal]之间的内容,以便我使用来自文件末尾的最新信息。 可能有更好的方法。 这是从一个没有audio的MP4,所以只有一个stream。

帧= 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来读取文件。 下面的例子使用dojo.request进行AJAX,但是也可以使用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);