FFMPEG与Python的子进程

12 投票
6 回答
24685 浏览
提问于 2025-04-15 14:29

我正在尝试为 FFMPEG 写一个图形界面(gui)。我使用 Python 的 subprocess 模块来为每个转换创建一个 ffmpeg 进程。这一切运行得很好,但我还想知道转换的进度,比如它是否失败了等等。我想我可以通过访问进程的标准输出(stdout)来实现这一点,方法如下:

调用 subprocess.Popen()

# Convert - Calls FFMPEG with current settings. (in a seperate
# thread.)
def convert(self):
    # Check if options are valid
    if self.input == "" or self.output == "":
        return False

# Make the command string
ffmpegString = self.makeString()

# Try to open with these settings
try:
    self.ffmpeg = subprocess.Popen(ffmpegString, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
    self.error.append("OSError: ")
except ValueError:
    self.error.append("ValueError: Couldn't call FFMPEG with these parameters")

# Convert process should be running now.

然后读取 stdout

convert = Convert()
convert.input = "test.ogv"
convert.output = "test.mp4"
convert.output_size = (0, 0)

convert.convert()

while 1:
    print convert.ffmpeg.stdout.readline()

这样做是可行的,但 ffmpeg 的状态没有显示出来。我猜这可能和 ffmpeg 刷新状态的方式有关。有没有办法可以访问到它呢?

相关问题:

6 个回答

3

我觉得你不能用readline,因为ffmpeg从来不会输出一整行,它是通过写入\r(回车符)来更新状态,然后再写一遍这一行。

size=      68kB time=0.39 bitrate=1412.1kbits/s    \rsize=    2786kB time=16.17 bitrate=1411.2kbits/s    \rsize=    5472kB time=31.76 bitrate=1411.2kbits/s    \r\n

如果你仔细看看上面那一行,你会发现只有一个\n,而这个\n是在文件转换完成时才会打印出来。

12

只需要在你的 subprocess.Popen 这一行后面加上 ,universal_newlines=True 就可以了。

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)

现在你可以在循环中得到每一行数据,像这样:

frame= 1900 fps=453 q=18.6 Lsize=    3473kB time=00:01:16.08 bitrate= 373.9kbits/s

使用 time= 的值来判断进度的百分比。

8

我经常发现,用subprocess读取标准输出(或者标准错误输出)时会遇到一些问题,这些问题主要是因为缓冲区的原因,解决起来很麻烦。当我确实需要从子进程读取这些输出时,我最喜欢的解决办法是用pexpect来代替subprocess,如果是在Windows系统上,可以用wexpect

撰写回答