【问题标题】:FFMPEG and Pythons subprocessFFMPEG 和 Pythons 子进程
【发布时间】:2010-11-30 03:27:01
【问题描述】:

我正在尝试为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 刷新它的方式有关。有没有办法访问它?

【问题讨论】:

    标签: python ffmpeg subprocess


    【解决方案1】:

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

    【讨论】:

    • 你的两个链接都失效了,请修复它们。
    【解决方案2】:

    只需将 ,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= 值来确定百分比进度。

    【讨论】:

    • 有趣的解决方案,但添加了一些 Popen 的缓冲问题。如果您正在寻找实时编码监控,则无法直接使用。
    【解决方案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 并且在文件完成转换时打印出来。

    【讨论】:

    • 你可以做 readline,但你只有在完成后才能得到该行的最终版本......
    【解决方案4】:

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

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

    然后循环使用select读取数据

    而真: readx = select.select([pipe.stderr.fileno()], [], [])[0] 如果读取: 块 = pipe.stderr.read()

    如需完整示例,请转到 here

    【讨论】:

    • 我不确定这是否仍然正确...我在 py2.7 上的 ffmpeg 的当前版本中仅在 stderr 上执行 readline 即可获得渐进式输出:for line in proc.stderr: print line proc.stderr.flush()
    • 啊不,嗯,有点。我在编码期间没有获得frame= xxx 状态输出的渐进式输出(因为这是一个反复更新的行),但我看到元数据行然后它阻塞直到编码完成,只显示最后的状态更新,然后它显示剩余的摘要行。
    【解决方案5】:

    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 制作了一个类似的应用程序。

    【讨论】:

    • Gorgapor,你确定他是吗?
    • 是的,stderr在代码片段中重定向到subprocess.Popen这一行——当然如果不使用代码片段下的滚动条也可以截掉...
    【解决方案6】:
    ffmpegCommand='''
    ffmpeg
    -f lavfi
    -i anullsrc=channel_layout=1c:sample_rate=11025
    -rtsp_transport tcp
    -rtsp_transport udp
    -rtsp_transport http
    -thread_queue_size 32000
    -i rtsp://xxx.xxx.xxx.xxx:554/user=admin&password=xxx&channel=1&stream=1.sdp?real_stream
    -reconnect 1
    -reconnect_at_eof 1
    -reconnect_streamed 1
    -reconnect_delay_max 4294
    -tune zerolatency
    -c:v copy
    -c:a aac
    -bufsize 6000k
    -f flv rtmp://a.rtmp.youtube.com/live2/xxx-xxx-xxx-xxx'''
    cmd=ffmpegCommand.split()
    # "universal newline support" This will cause to interpret \n, \r\n and \r     equally, each as a newline.
    
    p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True)
    while True:    
            print(p.stderr.readline().rstrip('\r\n'))
    

    【讨论】:

      猜你喜欢
      • 2012-07-06
      • 2017-03-02
      • 2020-05-19
      • 2014-11-15
      • 2017-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-20
      相关资源
      最近更新 更多