ffmpeg可以显示进度条吗?

Paw*_*Rao 56 ffmpeg progress-bar

我正在使用ffmpeg将.avi文件转换为.flv文件.由于转换文件需要很长时间,我想显示进度条.有人可以指导我如何去做同样的事情.

我知道ffmpeg不得不在文本文件中输出进度,我必须使用ajax调用来读取它.但是如何让ffmpeg将进度输出到文本文件?

非常感谢你.

小智 32

我已经玩了好几天了.那个"ffmpegprogress"的东西有所帮助,但是很难用到我的设置,并且很难阅读代码.

为了显示ffmpeg的进度,您需要执行以下操作:

  1. 从php运行ffmpeg命令而不等待响应(对我来说,这是最难的部分)
  2. 告诉ffmpeg将其输出发送到文件
  3. 从前端(AJAX,Flash,无论如何)直接命中该文件或者可以从ffmpeg的输出中取出进度的php文件.

以下是我解决每个部分的方法:

我从"ffmpegprogress"得到了以下想法.这就是他所做的:一个PHP文件通过http套接字调用另一个.第二个实际运行"exec",第一个文件挂起就可以了.对我来说,他的实施过于复杂.他正在使用"fsockopen".我喜欢CURL.所以这就是我做的:

$url = "http://".$_SERVER["HTTP_HOST"]."/path/to/exec/exec.php";
curl_setopt($curlH, CURLOPT_URL, $url);
$postData = "&cmd=".urlencode($cmd);
$postData .= "&outFile=".urlencode("path/to/output.txt");
curl_setopt($curlH, CURLOPT_POST, TRUE);
curl_setopt($curlH, CURLOPT_POSTFIELDS, $postData);

curl_setopt($curlH, CURLOPT_RETURNTRANSFER, TRUE);

// # this is the key!
curl_setopt($curlH, CURLOPT_TIMEOUT, 1);
$result = curl_exec($curlH);
Run Code Online (Sandbox Code Playgroud)

将CURLOPT_TIMEOUT设置为1意味着它将等待1秒钟以进行响应.优选地,这将更低.还有CURLOPT_TIMEOUT_MS需要几毫秒,但它对我不起作用.

1秒后,CURL挂起,但exec命令仍然运行.第1部分解决了.

顺便说一句 - 有些人建议使用"nohup"命令.但这似乎对我不起作用.

*也!在您的服务器上有一个可以直接在命令行上执行代码的php文件是一个明显的安全风险.您应该有一个密码,或以某种方式编码帖子数据.

2.上面的"exec.php"脚本还必须告诉ffmpeg输出到文件.这是代码:

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

注意"1> path/to/output.txt 2>&1".我不是命令行专家,但从我能说的这句话说"将正常输出发送到此文件,并将错误发送到同一个地方".查看此网址以获取更多信息:http://tldp.org/LDP/abs/html/io-redirection.html

3.从前端调用一个php脚本,为其提供output.txt文件的位置.那个php文件将从文本文件中取出进度.这是我如何做到的:

// # 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 current time
preg_match_all("/time=(.*?) bitrate/", $content, $matches); 

$last = array_pop($matches);
// # this is needed if there is more than one match
if (is_array($last)) {
    $last = array_pop($last);
}

$curTime = floatval($last);


// # finally, progress is easy
$progress = $curTime/$duration;
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.


bal*_*zar 25

俄语中有一篇文章描述了如何解决您的问题.

重点是Duration在编码之前捕获time=...值并在编码期间捕获值.

--skipped--
Duration: 00:00:24.9, start: 0.000000, bitrate: 331 kb/s
--skipped--
frame=   41 q=7.0 size=     116kB time=1.6 bitrate= 579.7kbits/s
frame=   78 q=12.0 size=     189kB time=3.1 bitrate= 497.2kbits/s
frame=  115 q=13.0 size=     254kB time=4.6 bitrate= 452.3kbits/s
--skipped--
Run Code Online (Sandbox Code Playgroud)

  • 我去看文章期待与俄罗斯人稍微挣扎但是阅读起来非常容易. (7认同)

mou*_*iel 19

FFmpeg使用stdout输出媒体数据,使用stderr输出日志/进度信息.您只需将stderr重定向到文件或能够处理它的进程的stdin.

使用unix shell时,这类似于:

ffmpeg {ffmpeg arguments} 2> logFile
Run Code Online (Sandbox Code Playgroud)

要么

ffmpeg {ffmpeg arguments} 2| processFFmpegLog
Run Code Online (Sandbox Code Playgroud)

无论如何,您必须将ffmpeg作为单独的线程或进程运行.

  • 如果我问这个问题,我很乐意接受你的回答. (2认同)
  • 对不起,我不懂.NET. (2认同)

小智 15

如果使用pipeview命令,则非常简单.要做到这一点,转换

ffmpeg -i input.avi {arguments}
Run Code Online (Sandbox Code Playgroud)

pv input.avi | ffmpeg -i pipe:0 -v warning {arguments}
Run Code Online (Sandbox Code Playgroud)

无需编码!

  • 请注意`ffmpeg`将无法编码来自`stdin`的视频,这些视频不能像元数据最后的`*.mov`文件那样流式传输.原因是`ffmpeg`无法寻找管道上的元数据.在将每个输入文件传送到`ffmpeg`之前,你必须对每个输入文件进行`qt-faststart`. (6认同)

Geo*_*aph 12

如果您只需要隐藏所有信息并显示默认进度(如最后一行中的 ffmpeg),您可以使用-stats选项:

ffmpeg -v warning -hide_banner -stats ${your_params}
Run Code Online (Sandbox Code Playgroud)


sid*_*eys 11

可悲的是,ffmpeg它本身仍然无法显示进度条——而且,许多上述基于 bash 或 python 的权宜之计解决方案已经过时且无法正常工作。

因此,我建议尝试一下全新的ffmpeg-progressbar-cli

ffmpeg-progressbar-cli 截屏视频

它是ffmpeg可执行文件的包装器,显示一个彩色的、居中的进度条和剩余时间。

此外,它是开源的,基于 Node.js 并积极开发,处理大多数提到的怪癖(完全披露:我是它目前的首席开发人员)。

  • 2020年更新,时间越长才算活跃。最后一次提交到 master 是在 2018 年 11 月,有 9 个开放问题,3 个开放拉取请求。 (3认同)
  • @TanishqBanyal 为 ffmpeg 进度条传递的正确标志是什么?我在文档/互联网中找不到该选项? (3认同)

ilu*_*pra 9

你可以用ffmpeg这个 -progress论点来做nc

WATCHER_PORT=9998

DURATION= $(ffprobe -select_streams v:0 -show_entries "stream=duration" \
    -of compact $INPUT_FILE | sed 's!.*=\(.*\)!\1!g')

nc -l $WATCHER_PORT | while read; do
    sed -n 's/out_time=\(.*\)/\1 of $DURATION/p')
done &

ffmpeg -y -i $INPUT_FILE -progress localhost:$WATCHER_PORT $OUTPUT_ARGS
Run Code Online (Sandbox Code Playgroud)

  • 这看起来像是最好的解决方案.您可以通过`ffmpeg -v warning -progress/dev/stdout -i in.mp4 out.mp4`将进度信息传递给`stdout`,以便每秒获得一次进度更新.如果你只需要一个百分比,你就可以在开始编码之前以秒为单位'ffprobe -v quiet -print_format json -show_format in.mp4`中的`duration`然后`| awk -F"="'/ out_time_ms/{print $ 2}'`仅获取ms的当前持续时间,其中`progress = total_duration*100*1000/current_duration`. (3认同)
  • 我不知道您可以将进度路由到文件;如果是这样的话,你可以用`sed`制作一个fifo然后就可以了。 (2认同)

gle*_*len 6

我发现ffpbPython 包 ( pip install ffpb) 可以将参数透明地传递给 FFmpeg。由于其坚固性,不需要太多维护。最新版本于 2019 年 4 月 29 日发布。

https://github.com/althonos/ffpb


All*_*nde 1

调用 php 的系统函数会阻塞该线程,因此您需要生成 1 个 HTTP 请求来执行转换,并生成另一个轮询请求来读取正在生成的 txt 文件。

或者,更好的是,客户提交视频进行转换,然后另一个进程负责执行转换。这样客户端的连接在等待系统调用终止时不会超时。轮询的方式与上述相同。

  • 但为什么要使用文本文件呢?一定有更好的方法。您是否必须为每次上传创建一个新的文本文件? (3认同)