GStreamer нулевая копия дублирование буфера только для чтения

#python #python-3.x #gstreamer #gstreamer-1.0 #python-gstreamer

#python #python-3.x #gstreamer #gstreamer-1.0 #python-gstreamer

Вопрос:

У меня есть конвейер GStreamer с appsink

 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
  

Я извлекаю образец из appsink, затем получаю буфер, сопоставляю его только для чтения и сохраняю информацию о карте (для последующего доступа к необработанной памяти).

 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
  

Я хотел бы получить фреймы из appsink, а затем отправить их в выходные конвейеры без копирования. Каков наилучший подход для этого? (в моем случае один конвейер не подходит).

Ответ №1:

Ответ не мой, я получил его по IRC-каналу #gstreamer:

В документации говорится следующее:

AppSrc.push_buffer(buffer): добавляет буфер в очередь буферов, которые элемент appsrc отправит в исходную панель. Эта функция становится владельцем буфера.

Это было то, что ввело меня в заблуждение. В Python нужно легко передавать один и тот же буфер нескольким приложениям.

Ответ №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() что-нибудь в свой код.

Комментарии:

1. Дорогая Энн, вы уверены, что отправили свой ответ в нужную ветку? Я не вижу связи между моим вопросом и вашим ответом.

2. @Broothy Отредактировано, чтобы объяснить связи.

3. Дорогая Энн, спасибо за разъяснение. Вы правы, это проблема синхронизации потоков. Но этот поток является внутренним GStreamer, к нему нельзя получить доступ за пределами библиотеки. Рассматриваемый поток продолжает выполняться после выполнения self.__src.push_buffer(buf) вызова. Обратный вызов или другая точка синхронизации были бы полезны, но GStreamer не предлагает такого механизма. Это очень специфичная для GStreamer проблема, ее нельзя решить с помощью упомянутого метода.