当我同时运行多个gstreamer进程时,我无法从appsrc保存到filesink。只有一个gstreamer进程才能正确写入,而其他进程将写入几乎空的文件。在filesink操作期间似乎存在写入争用。
注意:我在MAC OS 10.11.6上使用gstreamer1.0(v1.8.2)和python3(v3.5.2)。
以下是我的代码实际执行的操作:
在后台,我正在从单个视频流中读取帧,将每个帧转换为大小为1920x800x3的BGR numpy数组,并将每个帧存储在循环缓冲区中。我已经构建了一个“gstreamer_writer函数”,它从这个循环缓冲区中读取帧,将帧转换为字节流,并将此流提供给appsrc。
这可以通过实例化一个新的多进程(multiprocessing.Process)并将其指向“gstreamer_writer函数”来实现。这对于单个多进程/函数调用完全正常。 Appsrc正确地输入字节流,我使用以下gstreamer管道将这些BGR帧保存为带有h264编码的mp4:
appsrc format=3 name=app emit-signals=true do-timestamp=true is-live=true blocksize=4608000 max-bytes=0 caps=video/x-raw,format=BGR,width=1920,height=800 ! videoconvert ! video/x-raw,format=I420,width=1920,height=800 ! vtenc_h264 ! mp4mux ! filesink location=test1.mp4
但是,如果我实例化两个或多个多进程并将它们指向该函数,则只有一个filesink可以正常工作。例如,如果一个正在写入“test1.mp4”而另一个正在写入“test2.mp4”,则其中一个视频将被正确写入而另一个将失败并写入几乎为空的mp4(~500kb)。它并不总是相同的mp4,50%的时间test1.mp4被正确写入,50%的时间test2.mp4被正确写入。看起来有某种竞争条件或写入争用阻止了两个mp4被正确写入文件。
需要注意的一点是,每个多进程都从同一个环缓冲区访问相同的帧。我认为这可能导致了gstreamer的问题。但是,如果我使用autovideosink显示流而不是将它们写入文件,我可以显示尽可能多的流/多进程。这意味着数据正在通过管道正确传递,并且只在写入阶段失败。我使用gstreamer命令测试了这个:
appsrc format=3 name=app emit-signals=true do-timestamp=true is-live=true blocksize=4608000 max-bytes=0 caps=video/x-raw,format=BGR,width=1920,height=800 ! videoconvert ! video/x-raw,format=I420,width=1920,height=800 ! vtenc_h264 ! avdec_h264 ! autovideosink
如果有人对我如何解决这个问题有任何建议,我将不胜感激。我希望这是一个简单的改变,但你永远不会知道gstreamer!
谢谢!
答案 0 :(得分:0)
评论太长了,如果我是正确的话,这可以解决你的问题..
在filesink之前添加队列:
appsrc format=3 name=app emit-signals=true do-timestamp=true is-live=true blocksize=4608000 max-bytes=0 caps=video/x-raw,format=BGR,width=1920,height=800 ! videoconvert ! video/x-raw,format=I420,width=1920,height=800 ! queue ! vtenc_h264 ! mp4mux ! queue ! filesink location=test1.mp4
队列有两个功能: +在使用元素之前创建一个缓冲区(编码器是 - 它在开始编码之前需要很多帧) +将进一步处理分成新线程 - 以便filesink在新线程中处理数据。
HTH