从 ffmpeg 获取实时输出以在进度条中使用(PyQt4,stdout)
我已经查看了很多问题,但仍然无法完全弄清楚。我正在使用 PyQt,并且希望运行 ffmpeg -i file.mp4 file.avi 并在流式传输时获取输出,以便我可以创建进度条。
我看过这些问题: ffmpeg可以显示进度条吗? 从子进程实时捕获标准
输出我能够看到rsync 命令,使用以下代码:
import subprocess, time, os, sys
cmd = "rsync -vaz -P source/ dest/"
p, line = True, 'start'
p = subprocess.Popen(cmd,
shell=True,
bufsize=64,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
for line in p.stdout:
print("OUTPUT>>> " + str(line.rstrip()))
p.stdout.flush()
但是当我将命令更改为 ffmpeg -i file.mp4 file.avi 时,我没有收到任何输出。我猜这与标准输出/输出缓冲有关,但我对如何读取看起来像
frame= 51 fps= 27 q=31.0 Lsize= 769kB time=2.04 bitrate=3092.8kbits/s
我可以用来找出进度的行感到困惑。
有人可以向我展示一个如何将此信息从 ffmpeg 获取到 python 的示例,无论是否使用 PyQt(如果可能)
编辑: 我最终采用了 jlp 的解决方案,我的代码如下所示:
#!/usr/bin/python
import pexpect
cmd = 'ffmpeg -i file.MTS file.avi'
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([
pexpect.EOF,
"frame= *\d+",
'(.+)'
])
while True:
i = thread.expect_list(cpl, timeout=None)
if i == 0: # EOF
print "the sub process exited"
break
elif i == 1:
frame_number = thread.match.group(0)
print frame_number
thread.close
elif i == 2:
#unknown_line = thread.match.group(0)
#print unknown_line
pass
给出了以下输出:
started ffmpeg -i file.MTS file.avi
frame= 13
frame= 31
frame= 48
frame= 64
frame= 80
frame= 97
frame= 115
frame= 133
frame= 152
frame= 170
frame= 188
frame= 205
frame= 220
frame= 226
the sub process exited
完美!
I've looked at a number of questions but still can't quite figure this out. I'm using PyQt, and am hoping to run ffmpeg -i file.mp4 file.avi
and get the output as it streams so I can create a progress bar.
I've looked at these questions:
Can ffmpeg show a progress bar?
catching stdout in realtime from subprocess
I'm able to see the output of a rsync command, using this code:
import subprocess, time, os, sys
cmd = "rsync -vaz -P source/ dest/"
p, line = True, 'start'
p = subprocess.Popen(cmd,
shell=True,
bufsize=64,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
for line in p.stdout:
print("OUTPUT>>> " + str(line.rstrip()))
p.stdout.flush()
But when I change the command to ffmpeg -i file.mp4 file.avi
I receive no output. I'm guessing this has something to do with stdout / output buffering, but I'm stuck as to how to read the line that looks like
frame= 51 fps= 27 q=31.0 Lsize= 769kB time=2.04 bitrate=3092.8kbits/s
Which I could use to figure out progress.
Can someone show me an example of how to get this info from ffmpeg into python, with or without the use of PyQt (if possible)
EDIT:
I ended up going with jlp's solution, my code looked like this:
#!/usr/bin/python
import pexpect
cmd = 'ffmpeg -i file.MTS file.avi'
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([
pexpect.EOF,
"frame= *\d+",
'(.+)'
])
while True:
i = thread.expect_list(cpl, timeout=None)
if i == 0: # EOF
print "the sub process exited"
break
elif i == 1:
frame_number = thread.match.group(0)
print frame_number
thread.close
elif i == 2:
#unknown_line = thread.match.group(0)
#print unknown_line
pass
Which gives this output:
started ffmpeg -i file.MTS file.avi
frame= 13
frame= 31
frame= 48
frame= 64
frame= 80
frame= 97
frame= 115
frame= 133
frame= 152
frame= 170
frame= 188
frame= 205
frame= 220
frame= 226
the sub process exited
Perfect!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
在这种捕获 ffmpeg 状态输出(进入 STDERR)的特定情况下,这个问题为我解决了这个问题: FFMPEG 和 Python 子进程
技巧是将
universal_newlines=True
添加到subprocess.Popen()
调用中,因为ffmpeg 的输出实际上是无缓冲的,但带有换行符。另请注意,在此代码示例中,STDERR 状态输出直接重定向到
subprocess.STDOUT
In this specific case for capturing ffmpeg's status output (which goes to STDERR), this SO question solved it for me: FFMPEG and Pythons subprocess
The trick is to add
universal_newlines=True
to thesubprocess.Popen()
call, because ffmpeg's output is in fact unbuffered but comes with newline-characters.Also note that in this code sample the STDERR status output is directly redirected to
subprocess.STDOUT
我发现从子进程获取动态反馈/输出的唯一方法是使用类似 pexpect 的东西:
被调用的子进程 foo.sh 只是等待 10 到 20 秒之间的随机时间,下面是它的代码:
您将需要使用一些与从 ffmpeg 获得的输出相匹配的正则表达式,并对其进行某种计算以显示进度条,但这至少会为您提供来自 ffmpeg 的无缓冲输出。
The only way I've found to get dynamic feedback/output from a child process is to use something like pexpect:
the called sub process foo.sh just waits a random amount of time between 10 and 20 seconds, here's the code for it:
You'll want to use some regular expression that matches the output you're getting from ffmpeg and does some kind of calculation on it to show the progress bar, but this will at least get you the unbuffered output from ffmpeg.
stderr
,而不是stdout
。如果您只想打印输出行,就像上面的示例一样,那么只需这样做:
请注意,ffmpeg chat 的行以
\r
终止,因此它将覆盖同一条线!我认为这意味着您无法像处理 rsync 示例那样迭代p.stderr
中的行。要构建自己的进度条,您可能需要自己处理阅读,这应该可以帮助您开始:stderr
, notstdout
.If all you want to do is print the output line, like in your example above, then simply this will do:
Note that the line of ffmpeg chat is terminated with
\r
, so it will overwrite in the same line! I think this means you can't iterate over the lines inp.stderr
, as you do with your rsync example. To build your own progress bar, then, you may need to handle the reading yourself, this should get you started:我编写了一个专用包,为您提供了 Python 中 ffmpeg 进度的生成器函数:
ffmpeg-进度产量
。只需运行:
然后,只需执行:
请注意,这仅适用于预先知道持续时间的输入文件。
I wrote a dedicated package that gives you a generator function for ffmpeg progress in Python:
ffmpeg-progress-yield
.Simply run:
Then, simply do:
Note that this only works for input files where the duration is known in advance.
这个答案对我不起作用:/这是我的做法。
它来自我的项目 KoalaBeatzHunter。
享受!
接下来,您还需要 3 个函数来实现它。
最后你做到了:
希望这会有所帮助!
This answers didn't worked for me :/ Here is the way I did it.
Its from my project KoalaBeatzHunter.
Enjoy!
Next, you need 3 more functions to implement it.
And finally you do:
Hope this will help!
您还可以使用 PyQt4 的 QProcess(如原始问题中所要求的)通过将 QProcess 中的插槽连接到 QTextEdit 或其他内容来非常清楚地完成此操作。我对 python 和 pyqt 还很陌生,但我是这样做的:
You can also do it pretty clearly with PyQt4's QProcess (as asked in the original question) by connecting a slot from the QProcess to a QTextEdit or whatever. I'm still pretty new to python and pyqt but here's how I just managed to do it:
ffmpeg-python github 上有一个示例 - 对于 Windows 机器(使用 unix 套接字),不能开箱即用... https://github.com/kkroening/ffmpeg-python/blob/master/examples/show_progress.py
一个简单的(IMO,更好...:))视频转换器脚本,带有进度(ffmpeg-python 和 tqdm_rich):
https://gist.github.com/pbouill/fddf767221b47f83c97d7813c03569c4
无需覆盖 sys.stdout/stderr,然后像某些 tqdm 文档建议的那样恢复以获取子进程输出/拦截控制台输出(https://github.com/tqdm/tqdm/blob/master/examples/ redirect_print.py)。
只需通过提供输入文件路径来创建视频转换器实例:
如果未提供输出路径,则输出视频将放置在与输入文件相同的目录中,并附加“-converted.mp4”。您也可以调整输出/转换 kwargs...默认情况下它使用:
例如,
您可以通过在调用“转换”时提供进度指标选择来基于视频时间的进度报告或基于帧的进度报告:
您可以转换所有内容在脚本目录中,只需调用:(
也可以指定输入目录、输出目录、output_kwargs 作为此函数的关键字参数)
希望这有帮助!
There's an example on the ffmpeg-python github -- doesn't work out of the box for windows machines machines (uses unix sockets)... https://github.com/kkroening/ffmpeg-python/blob/master/examples/show_progress.py
A simple, (IMO, better... :)) video converter script w/ progress (ffmpeg-python and tqdm_rich) here:
https://gist.github.com/pbouill/fddf767221b47f83c97d7813c03569c4
No need to overwrite sys.stdout/stderr then revert like some of the tqdm documentation suggests for grabbing subprocess outputs/intercepting console outputs (https://github.com/tqdm/tqdm/blob/master/examples/redirect_print.py).
Just create a video converter instance by supplying an input file path:
If no output path is supplied, output video will be placed in the same dir as the input file with "-converted.mp4" appended. You can adjust the output/conversion kwargs as well... by default it's using:
e.g.
You can video-time based progress report, or frame-based progress report by supplying a progress metric choice when calling "convert":
You can convert everything in the script directory by simply calling:
(can also specify input dir, output dir, output_kwargs as keyword arguments to this function)
Hope this helps!
如果您有持续时间(也可以从 FFMPEG 输出中获取),您可以通过在编码时读取经过的时间(时间)输出来计算进度。
一个简单的例子:
If you have the duration (Which you can also get from the FFMPEG output) you can calculate the progress by reading the elapsed time (time) output when encoding.
A simple example:
在我看来,通过使用 ffmpeg 的 -progress url (global) 选项,解决方案实际上很简单:
文件
progress.log
将附加实时进度信息(更新周期使用 -stats_period 选项设置)。该信息将如下所示:
根据此信息,可以计算进度。
程序员博客中有更详细的示例
Looks to me that the solution is actually simple by using the -progress url (global) option of ffmpeg:
The file
progress.log
will be appended with progress information in real time (The update period is set using -stats_period option)The information will look like this:
From this information it is possible to calculate the progress.
A more detailed example in Programster's Blog