我目前正在调用ffmpeg
从视频文件中提取二进制数据流,然后将该二进制数据放入列表中。此数据流中有很多数据,大约 4,000 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)
我应该使用其他数据结构吗?
-
一次一个字节地从管道中读取数据确实效率低下。你应该阅读更大的块。
正如您所注意到的,执行子进程, 然后在不等待子进程完成的情况下终止父进程将导致管道错误断开,子进程将失败。
如果操作系统缓冲区被填满(即,如果您不像您的情况那样从管道读取),调用
subprocess.call(cmd, stdout=subprocess.PIPE)
将阻止/停止编写器。Queue
只要您一次不读取一个字节就可以了