【问题标题】:GStreamer zero copy read only buffer duplicationGStreamer 零拷贝只读缓冲区复制
【发布时间】:2020-11-09 08:32:23
【问题描述】:

我有一个带有应用程序接收器的 GStreamer 管道

filesrc location=test.mp4 ! decodebin ! video/x-raw ! queue max-size-bytes=0 max-size-time=100000000 ! appsink name=appSink sync=false max-buffers=1 drop=false

我从应用程序接收器中提取样本,然后获取缓冲区,将其映射为只读并存储映射信息(以便稍后访问原始内存)。

sample: Gst.Sample = self.__sink.pull_sample()
self.__buffer: Gst.Buffer = sample.get_buffer()
self.__buffer_map: Gst.MapInfo = self.__buffer.map(Gst.MapFlags.READ)

然后我想在输出管道中使用相同的数据(不复制它),例如:

appsrc name=appSrc block=true ! video/x-raw,format=(string)NV12,width=1920,height=1080,framerate=30/1 ! videoconvert ! ximagesink

要做到这一点,这是我能想到的最好的:

shared_buffer_memory = self.__buffer.get_all_memory()
buf = Gst.Buffer.new()
buf.insert_memory(-1, shared_buffer_memory)
self.__src.push_buffer(buf)
#sleep(0.05) 

如果我这样做,我会正确看到第一帧,但所有其他帧都是绿色的。没关系,因为 buf 的底层内存超出范围并同时释放。如果我将 sleep(0.05) 放在 push_buffer 之后,它会显示所有帧,但我认为缓冲区后面的内存是双重释放的:

** (python3.9:6745): CRITICAL **: 09:23:54.645: gst_vaapi_image_unmap: assertion 'image != NULL' failed

我想从应用程序接收器中获取帧,然后将它们推送到输出管道而不进行复制。这样做的最佳方法是什么? (在我的情况下,单个管道不适合)。

【问题讨论】:

    标签: python python-3.x gstreamer gstreamer-1.0 python-gstreamer


    【解决方案1】:

    答案不是我的,我是在#gstreamer IRC 频道上得到的:

    documentation 表示以下内容:

    AppSrc.push_buffer(buffer):将一个缓冲区添加到缓冲区队列中 appsrc 元素将推送到其源板。 这个函数需要 缓冲区的所有权。

    这就是误导我的原因。在 Python 中,应该可以轻松地将同一个缓冲区推送到多个 AppSrc。

    【讨论】:

      【解决方案2】:

      这似乎是一个你想在继续编写代码之前完成的线程,例如:

      from threading import Thread
      from time import sleep
      
      def a():
          print('start')
          sleep(1)
          print('middle')
          sleep(1)
          print('end')
      c = Thread(target=a)
      print('Hello')
      c.start()
      print('Bye')
      sleep(3)
      

      输出:

      Hello
      startBye
      
      middle
      end
      

      假设c 是线程,您可以找到一种方法将c.join() 添加到您的代码中的某一行,这样程序就会知道在继续程序之前等待进程完成:

      from threading import Thread
      from time import sleep
      
      def a():
          print('start')
          sleep(1)
          print('middle')
          sleep(1)
          print('end')
      c = Thread(target=a)
      print('Hello')
      c.start()
      a.join()
      print('Bye')
      sleep(3)
      

      输出:

      Hello
      start
      middle
      end
      Bye
      

      更新

      查看代码结构:

      shared_buffer_memory = self.__buffer.get_all_memory()
      buf = Gst.Buffer.new()
      buf.insert_memory(-1, shared_buffer_memory)
      self.__src.push_buffer(buf)
      #sleep(0.05) 
      

      您说它 sleep(0.05) 一起工作,但没有它就无法正常工作。可能发生的原因是因为线程。为了使其工作,您需要通过在代码中的某处添加 .join() 来反转线程的效果。

      【讨论】:

      • 亲爱的 Ann,您确定您将答案发布到了正确的线程吗?我看不出我的问题和你的答案之间的联系。
      • @Broothy 已编辑以解释连接。
      • 亲爱的安,感谢您的澄清。这是一个线程同步问题,你是对的。但是该线程是 GStreamer 内部的,无法在 lib 外部访问。在我执行self.__src.push_buffer(buf) 调用后,有问题的线程继续运行。回调或其他同步点会有所帮助,但 GStreamer 不提供这种机制。这是一个非常 GStreamer 特有的问题,无法用上述方法解决。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      • 1970-01-01
      • 2017-09-22
      • 1970-01-01
      • 2016-05-07
      • 1970-01-01
      • 2023-04-05
      相关资源
      最近更新 更多