【问题标题】:ffmpeg corruption when piping input from stdin从标准输入管道输入时ffmpeg损坏
【发布时间】:2019-09-11 05:17:01
【问题描述】:

我有一个程序可以生成图像并从中创建视频。目前可行的是一次创建所有图像,然后在子进程中运行 FFmpeg 并通过标准输入管道图像以创建视频:

cmd = ['ffmpeg', '-y',
       '-s', '{}x{}'.format(OUTPUT_WIDTH, OUTPUT_HEIGHT),
       '-r', str(OUTPUT_VIDEO_FPS),
       '-an',
       '-pix_fmt', colour,
       '-c:v', 'rawvideo', '-f', 'rawvideo',
       '-i', '-',
       '-vcodec', 'libx264',
       '-pix_fmt', 'yuv420p',
       '-preset', 'medium', OUTPUT_VIDEO_PATH]

out_frames = []
for i in range(num_frames):
    out_frame = render_frame(...)
    out_frames.append(out_frame)

with _call_subprocess(sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, stdout=DEVNULL)) as pipe:
    for frame_no, frame in enumerate(out_frames):
        pipe.stdin.write(frame)

但是,当我有数千张图片无法全部放入内存时,这将变得不可行,因为子进程 fork 调用请求了太多内存并失败了。我的解决方案是在程序开始时分叉(避免内存错误),然后在创建帧时将它们通过管道传输到标准输入:

cmd = ['ffmpeg', '-y',
       '-s', '{}x{}'.format(OUTPUT_WIDTH, OUTPUT_HEIGHT),
       '-r', str(OUTPUT_VIDEO_FPS),
       '-an',
       '-pix_fmt', colour,
       '-c:v', 'rawvideo', '-f', 'rawvideo',
       '-i', '-',
       '-vcodec', 'libx264',
       '-pix_fmt', 'yuv420p',
       '-preset', 'medium', OUTPUT_VIDEO_PATH]

with _call_subprocess(sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, stdout=DEVNULL)) as pipe:
    for i in range(num_frames):
        out_frame = render_frame(...)
        pipe.stdin.write(out_frame)

但是,ffmpeg 的输出现在已损坏。我很确定这与以下事实有关到标准输入,输出也损坏了!

cmd = ['ffmpeg', '-y',
       '-s', '{}x{}'.format(OUTPUT_WIDTH, OUTPUT_HEIGHT),
       '-r', str(OUTPUT_VIDEO_FPS),
       '-an',
       '-pix_fmt', colour,
       '-c:v', 'rawvideo', '-f', 'rawvideo',
       '-i', '-',
       '-vcodec', 'libx264',
       '-pix_fmt', 'yuv420p',
       '-preset', 'medium', OUTPUT_VIDEO_PATH]

out_frames = []
for i in range(num_frames):
    out_frame = render_frame(...)
    out_frames.append(out_frame)

with _call_subprocess(sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, stdout=DEVNULL)) as pipe:
    for frame_no, frame in enumerate(out_frames):
        time.sleep(1) # <------------------- This sleep ruins everything!!
        pipe.stdin.write(frame)

但是我不确定是什么导致了这个或如何解决它(FFmpeg 是否以某种方式轮询一个空管道然后被它损坏?我不明白子进程通信是如何工作的......)。任何帮助将不胜感激。

【问题讨论】:

  • ffmpeg 是否足够聪明,不会在 stdin 读取数据时从标准输入读取键盘命令?如果没有,-nostdin 可能会有所帮助
  • 试过-nostdin,没有运气:/
  • 什么是 OUTPUT_VIDEO_PATH?扩展将确定容器类型,这可能会影响事物。
  • 最后一帧后,需要关闭管道,等待ffmpeg完成。
  • _call_subprocess 是一个上下文管理器,它关闭流并在其 finally 块中的子进程上调用 wait

标签: python linux ffmpeg subprocess pipe


【解决方案1】:

不确定为什么会这样,但是将运行 FFmpeg 的 sp.Popen 调用从 sp.Popen(cmd, stdin=sp.PIPE, stderr=sp.PIPE, stdout=DEVNULL) 更改为 sp.Popen(cmd, stdin=sp.PIPE, stderr=DEVNULL, stdout=DEVNULL) 有效。我猜这和this SO question about piping issues with stderr有关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    • 2017-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多