FFMPEG和Pythons子进程

时间:2009-09-21 16:49:40

标签: python ffmpeg subprocess

我正在为FFMPEG写一个gui。我正在使用pythons子进程为我想要的每个转换创建一个ffmpeg进程。这样做很好,但我也想要一种方法来获得转换的进度,无论是否失败等等。我想我可以通过访问进程的标准输出这样做:

致电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 个答案:

答案 0 :(得分:8)

由于缓冲问题难以解决,我经常注意到使用子进程读取标准输出(甚至标准错误!)时出现问题。我最喜欢的解决方案,当我需要从子进程中读取这样的stdout / stderr时,切换到使用而不是subprocesspexpect(或者,在Windows上,wexpect)。

答案 1 :(得分:6)

简单地添加,universal_newlines = True到您的subprocess.Popen行。

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 =值确定百分比进度。

答案 2 :(得分:3)

我认为你不能使用readline,因为ffmpeg从不打印一行,通过写\ r(carrige return)更新状态然后再写一行。

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,并且在文件转换完成后会打印出来。

答案 3 :(得分:2)

由于ffmpeg将未刷新的数据写入stderr,因此必须使用fcntl将stderr文件描述符设置为非阻塞。

    fcntl.fcntl(
        pipe.stderr.fileno(),
        fcntl.F_SETFL,
        fcntl.fcntl(pipe.stderr.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK,
    )

然后使用select循环读取数据

    while True:
        readx = select.select([pipe.stderr.fileno()], [], [])[0]
        if readx:
            chunk = pipe.stderr.read()

完整示例请转到here

答案 4 :(得分:-1)

<强> FFMPEG:

FFMPEG在stderr界面上输出所有状态文本(在命令行上手动运行时看到的内容)。为了捕获来自ffmpeg的输出,您需要观察stderr接口 - 或者像示例一样重定向它。

检查stderr上的输出:

这是另一种尝试从stderr读取的方法,而不是在调用Popen时重定向它

Python中的Popen class有一个名为stderr的文件对象,您可以像访问stdout一样访问它。我在想你的循环看起来像这样:

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

免责声明:我没有在Python中对此进行测试,但我使用Java制作了类似的应用程序。

答案 5 :(得分:-2)

heroku config:set NPM_CONFIG_PRODUCTION=false