【问题标题】:Python: Strange hanging behavior when piping large stdout of a subprocessPython:管道子进程的大型标准输出时出现奇怪的挂起行为
【发布时间】:2018-02-14 08:53:57
【问题描述】:

我目前正在调用ffmpeg 从视频文件中提取二进制数据流,然后将该二进制数据放入列表中。这个数据流中有很多数据,大约4000 kb。这是代码

# write and call ffmpeg command, piping stdout
cmd = "ffmpeg -i video.mpg -map 0:1 -c copy -f data -"
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)

# read from stdout, byte by byte
li = []
for char in iter(lambda: proc.stdout.read(1), ""):
    li.append(char)

这很好用。但是,如果我从stdout 中取出我正在阅读的部分,它会开始工作但随后挂起:

cmd = "ffmpeg -i video.mpg -map 0:1 -c copy -f data -"
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
time.sleep(10)

我必须在末尾添加time.sleep(10),否则进程将在subprocess之前结束,导致此错误:

av_interleaved_write_frame(): Invalid argument
Error writing trailer of pipe:: Invalid argument
size=       0kB time=00:00:00.00 bitrate=N/A speed=N/A
video:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ove
rhead: 0.000000%
Conversion failed!

调用subprocess.call(cmd, stdout=subprocess.PIPE)subprocess.call(cmd) 也会导致挂起(后者只会在控制台中显示stdout,而前者不会)。

stdout 读取是否有防止这种挂起(比如缓冲区被清除),或者我在不知不觉中在其他地方引入了错误?我担心这么小的变化会导致程序崩溃;它不会激发很大的信心。

此代码的另一个问题是我需要从另一个线程的列表中读取。这可能意味着我需要使用Queue。但是当我执行下面的代码时,它需要 11 秒而不是 3 秒与列表等效:

cmd = "ffmpeg -i video.mpg -loglevel panic -hide_banner -map 0:1 -c copy -f data -"
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)

q = Queue()

for char in iter(lambda: proc.stdout.read(1), ""):
    q.put(char)

我应该使用其他数据结构吗?

【问题讨论】:

  • 不确定,但尝试添加选项 -nostdin
  • 添加 -nostdin 的好主意,因为它是一个子进程。然而,并没有解决这个问题。

标签: python ffmpeg subprocess pipe stdout


【解决方案1】:
  1. 一次从管道读取一个字节的数据确实效率低下。你应该阅读更大的块。

  2. 执行子进程然后终止父进程而不等待子进程完成将导致管道中断错误,并且子进程将失败,正如您所注意到的。

  3. 如果操作系统缓冲区被填满(即,如果您不像您的情况那样从管道读取),则调用 subprocess.call(cmd, stdout=subprocess.PIPE) 将阻塞/停止写入器。

  4. Queue 没问题,只要你不一次读取一个字节

【讨论】:

  • 我一次读取一个字节的原因是因为我一次解码一个字节的数据。我会试着想一个更好的方法来做到这一点。
猜你喜欢
  • 2018-03-11
  • 1970-01-01
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-20
  • 2012-03-13
  • 1970-01-01
相关资源
最近更新 更多