GStreamer и Qt оба используют тип GLib.MainContext
для асинхронной обработки сообщений между отправителями и получателями 1 . По умолчанию сообщения GStreamer и Qt передаются через глобальный экземпляр MainContext по умолчанию, доступный через GLib.MainContext.default()
. Когда сообщения отправляются, будь то из пользовательского ввода, из конвейера или где-либо еще, они изначально хранятся в очереди сообщений. Qt регулярно выполняет итерацию MainContext, который извлекает сообщения из очереди и отправляет их любым слушателям. Вот почему вы можете получать сообщения от вашего конвейера GStreamer, когда конвейер запускается в потоке пользовательского интерфейса.
Однако, когда Qt запускает новый QThread, также создает новый объект MainContext и устанавливаетэто как контекст по умолчанию для этого потока . Когда вы создаете конвейер GStreamer в QThread, ваш конвейер и наблюдатель регистрируются в этом контексте вместо глобального значения по умолчанию. Qt не выполняет итерацию MainContext QThread автоматически для вас, поэтому сообщения не будут получены, если вы сами не выполните итерацию контекста . Это можно сделать, вызвав QCoreApplication.processEvents()
в QThread.
class MakePipelineThread(QThread):
def run(self):
global pipeline
pipeline = Gst.parse_launch("videotestsrc ! xvimagesink")
pipeline.bus.add_watch(GLib.PRIORITY_DEFAULT, on_pipeline_message)
pipeline.set_state(Gst.State.PLAYING)
# Process events until the pipeline reaches the null state
_, state, _ = pipeline.get_state(Gst.CLOCK_TIME_NONE)
while state != Gst.State.NULL:
QCoreApplication.processEvents()
_, state, _ = pipeline.get_state(Gst.CLOCK_TIME_NONE)
Это, конечно, означает, что QThread будет работать до тех пор, пока работает конвейер, а не останавливаться, как только конвейер будет построен.
В качестве альтернативы вы можете использовать set_sync_handler
вместо add_watch
. Это заставляет шину немедленно выполнить обратный вызов в том же потоке, который отправил сообщение, а не отправлять сообщение асинхронно через MainContext.
class MakePipelineThread(QThread):
def run(self):
global pipeline
pipeline = Gst.parse_launch("videotestsrc ! xvimagesink")
pipeline.bus.set_sync_handler(on_pipeline_message)
pipeline.set_state(Gst.State.PLAYING)
Это устраняет необходимость полной итерации MainContext, но это означает, чтоВаш обратный вызов будет выполняться в одном из потоковых потоков GStreamer и заблокирует этот поток от выполнения другой работы во время выполнения обратного вызова.
1 Некоторые платформы могут компилировать Qt безПоддержка GLib, в этом случае Qt будет использовать свою собственную систему обработки событий. В этом случае эта проблема не возникнет, пока приложение выполняет итерацию самого глобального контекста по умолчанию. Вы можете установить переменную окружения QT_NO_GLIB
в 1, чтобы Qt не использовал GLib во время выполнения.