Jas*_*eil 22 python subprocess ffmpeg stdout pyqt
我看了很多问题,但仍然无法弄清楚这一点.我正在使用PyQt,我希望运行ffmpeg -i file.mp4 file.avi并获取输出,因为我可以创建一个进度条.
我看过这些问题: ffmpeg可以显示进度条吗? 从子进程实时捕获stdout
我能够使用以下代码查看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()
Run Code Online (Sandbox Code Playgroud)
但是当我更改命令时,ffmpeg -i file.mp4 file.avi我没有收到任何输出.我猜这与stdout/output缓冲有关,但是我不知道如何读取看起来像的行
frame= 51 fps= 27 q=31.0 Lsize= 769kB time=2.04 bitrate=3092.8kbits/s
Run Code Online (Sandbox Code Playgroud)
我可以用来计算进度.
有人可以告诉我一个如何从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
Run Code Online (Sandbox Code Playgroud)
这给出了这个输出:
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
Run Code Online (Sandbox Code Playgroud)
完善!
小智 15
在捕获ffmpeg状态输出(转到STDERR)的特定情况下,这个SO问题为我解决了:FFMPEG和Pythons子进程
诀窍是添加universal_newlines=True到subprocess.Popen()调用,因为ffmpeg的输出实际上是无缓冲的,但带有换行符.
cmd = "ffmpeg -i in.mp4 -y out.avi"
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,universal_newlines=True)
for line in process.stdout:
print(line)
Run Code Online (Sandbox Code Playgroud)
另请注意,在此代码示例中,STDERR状态输出将直接重定向到 subprocess.STDOUT
jlp*_*jlp 14
我发现从子进程获得动态反馈/输出的唯一方法是使用像pexpect这样的东西:
#! /usr/bin/python
import pexpect
cmd = "foo.sh"
thread = pexpect.spawn(cmd)
print "started %s" % cmd
cpl = thread.compile_pattern_list([pexpect.EOF,
'waited (\d+)'])
while True:
i = thread.expect_list(cpl, timeout=None)
if i == 0: # EOF
print "the sub process exited"
break
elif i == 1:
waited_time = thread.match.group(1)
print "the sub process waited %d seconds" % int(waited_time)
thread.close()
Run Code Online (Sandbox Code Playgroud)
被调用的子进程foo.sh只需等待10到20秒之间的随机时间,这里是代码:
#! /bin/sh
n=5
while [ $n -gt 0 ]; do
ns=`date +%N`
p=`expr $ns % 10 + 10`
sleep $p
echo waited $p
n=`expr $n - 1`
done
Run Code Online (Sandbox Code Playgroud)
你需要使用一些与你从ffmpeg获得的输出相匹配的正则表达式,并对它进行某种计算以显示进度条,但这至少可以获得ffmpeg的无缓冲输出.