Я пытаюсь зациклить воспроизведение видео, используя gstreamer и его привязки к python.Первой попыткой было перехватить EOS message и сгенерировать сообщение о поиске для конвейера:
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst
import time
if not Gst.init_check()[0]:
print("gstreamer initialization failed")
source0 = Gst.ElementFactory.make("filesrc", "source0")
assert source0 is not None
source0.set_property("location", "video0.mp4")
qtdemux0 = Gst.ElementFactory.make("qtdemux", "demux0")
assert qtdemux0 is not None
decoder0 = Gst.ElementFactory.make("nxvideodec", "video_decoder0")
assert decoder0 is not None
def demux0_pad_added(demux, pad):
if pad.name == 'video_0': # We expect exactly first one video stream
pad.link(decoder0.get_static_pad("sink"))
qtdemux0.connect("pad-added", demux0_pad_added)
video_sink = Gst.ElementFactory.make("nxvideosink", "video_sink")
assert video_sink is not None
pipeline0 = Gst.Pipeline()
assert pipeline0 is not None
pipeline0.add(source0)
pipeline0.add(qtdemux0)
pipeline0.add(decoder0)
pipeline0.add(video_sink)
source0.link(qtdemux0)
"""qtdemux0 -> decoder0 dynamic linking"""
decoder0.link(video_sink)
######################################################
def main():
message_bus = pipeline0.get_bus()
pipeline0.set_state(Gst.State.PLAYING)
while True:
if message_bus.have_pending(): # Working without glib mainloop
message = message_bus.pop()
if message.type == Gst.MessageType.EOS: # End-Of-Stream: loop the video, seek to beginning
pipeline0.seek(1.0,
Gst.Format.TIME,
Gst.SeekFlags.FLUSH,
Gst.SeekType.SET, 0,
Gst.SeekType.NONE, 0)
elif message.type == Gst.MessageType.ERROR:
print("ERROR", message)
break
time.sleep(0.01) # Tried 0.001 - same result
if __name__ == "__main__":
main()
И это на самом деле работает довольно хорошо, за исключением одной вещи - поиск в начале не совсем гладкий.Я вижу крошечный сбой.Поскольку видео представляет собой бесконечную анимацию, этот крошечный глюк действительно становится заметным.Моя вторая попытка состояла в том, чтобы использовать очередь для декодированных кадров и перехватить событие EOS :
import gi
gi.require_version("Gst", "1.0")
from gi.repository import Gst
import time
if not Gst.init_check()[0]:
print("gstreamer initialization failed")
source0 = Gst.ElementFactory.make("filesrc", "source0")
assert source0 is not None
source0.set_property("location", "video0.mp4")
qtdemux0 = Gst.ElementFactory.make("qtdemux", "demux0")
assert qtdemux0 is not None
decoder0 = Gst.ElementFactory.make("nxvideodec", "video_decoder0")
assert decoder0 is not None
def demux0_pad_added(demux, pad):
if pad.name == 'video_0': # We expect exactly first one video stream
pad.link(decoder0.get_static_pad("sink"))
qtdemux0.connect("pad-added", demux0_pad_added)
queue = Gst.ElementFactory.make("queue", "queue")
assert queue is not None
video_sink = Gst.ElementFactory.make("nxvideosink", "video_sink")
assert video_sink is not None
pipeline0 = Gst.Pipeline()
assert pipeline0 is not None
pipeline0.add(source0)
pipeline0.add(qtdemux0)
pipeline0.add(decoder0)
pipeline0.add(queue)
pipeline0.add(video_sink)
source0.link(qtdemux0)
"""qtdemux0 -> decoder0 dynamic linking"""
decoder0.link(queue)
queue.link(video_sink)
######################################################
def cb_event(pad, info, *user_data):
event = info.get_event()
if event is not None and event.type == Gst.EventType.EOS:
decoder0.seek(1.0,
Gst.Format.TIME,
Gst.SeekFlags.FLUSH,
Gst.SeekType.SET, 0,
Gst.SeekType.NONE, 0)
return Gst.PadProbeReturn.DROP
return Gst.PadProbeReturn.PASS
def main():
dec0_src_pad = decoder0.get_static_pad("src")
dec0_src_pad.add_probe(Gst.PadProbeType.BLOCK | Gst.PadProbeType.EVENT_DOWNSTREAM, cb_event)
message_bus = pipeline0.get_bus()
pipeline0.set_state(Gst.State.PLAYING)
while True:
# do nothing
time.sleep(1)
if __name__ == "__main__":
main()
После первого события EOS воспроизведение просто остановилось.Я пробовал несколько разных вещей, таких как: pass событие EOS, drop EOS и добавление смещения на панель исходного кода декодера, отправка события поиска в сам конвейер и другие.Но я не могу заставить это работать.
В попытке понять, я также попытался включить режим отладки и написать свой собственный журнал активности конвейера, используя пробники.Режим отладки был не очень полезен, журнал очень громоздкий и пропускает некоторые детали.Мой собственный журнал включает в себя восходящие / нисходящие события и информацию о синхронизации буферов.Тем не менее, я до сих пор не могу понять, что не так и как заставить его работать.
Очевидно, я не просто что-то упустил, но не понимаю какой-то фундаментальной вещи о том, как работает конвейер gstreamer.
Итак, вопрос: Что мне делать со второй версией кода, чтобы она заработала?
Дополнительный вопрос: Существуют ли какие-либо инструменты или методы, чтобы получить четкое представление о том, что происходит внутри конвейера и его элементов?
Я буду очень признателен за подробные ответы.Для меня важнее понять , что я делаю неправильно, чем просто заставить программу работать.
ps Программа работает под GNU / Linux на плате NanoPi S2.Видео хранится в контейнере MP4 (без звука) и сжимается с помощью h264.Пожалуйста, не стесняйтесь размещать примеры кода на любом языке, не обязательно Python.