g_main_loop_run阻塞Qthread并且不允许停止视频
g_main_loop_run blocks the Qthread and does not allow to stop video
我为gstreamer创建了一个单独的类来流式传输视频
这个类通过使用moveToThread()在单独的线程上运行
我正在使用Qt5.5进行开发
当我在主线程上发出startcommand时,Qthread启动,gstreamer使用g_main_loop_run
来流式传输视频。这绝对行得通。但不知何故,g_main_loop_run
阻塞了线程,当我从主线程发出停止视频的信号时,它不会执行gstreamer类中的slot。
有人能告诉我如何解决这个问题吗?我可以用其他命令替换g_main_loop_r
un,也可以使用g_main_loop_quit( gloop )
;以另一种方式。
void StreamingVideo::slotStartStream() // this slot called on start of thread from main thread
{
if( !isElementsLinked() )
{
qDebug() << " we are emitting in dummy server ";
//emit sigFailed( "elementsFailed" ); // WILL CONNECT IT WITH MAIN GUI ONXCE CODE IS FINISHED
return;
}
gst_bus_add_watch( bus, busCall, gloop );
gst_object_unref( bus );
//proper adding to pipe
gst_bin_add_many( GST_BIN( pipeline ), source, capsFilter, conv, videoRate, capsFilterRate,
clockDisplay, videoEnc, udpSink, NULL
);
//proper linking:
gst_element_link_many( source, capsFilter, conv, videoRate, capsFilterRate, clockDisplay, videoEnc, udpSink, NULL );
g_print("Linked all the Elements togethern");
gst_element_set_state( pipeline, GST_STATE_PLAYING );
// Iterate
g_print ("Running...n");
emit sigStartStream(); // signal to main thread to issue success command . works fine
g_main_loop_run( gloop );
g_print ("Returned, stopping playbackn");
//gst_element_set_state (pipeline, GST_STATE_NULL);
if( g_main_loop_is_running( gloop ) )
{
qDebug() << " in g_main_loop_is_runnung emiting signal ";
emit sigStartStream();
}
if( !g_main_loop_is_running( gloop) )
{
qDebug() << "in not gmain running thread id";
qDebug() << QThread::currentThreadId();
}
}
void StreamingVideo::slotStopStream() // THIS SLOT IS NOT CALLED WHEN VIDEO RUNNING
{
qDebug() << " we are planning to stop streaming stramingVideo::slotStopStream ";
g_print ("Returned, stopping playbackn");
g_main_loop_quit( gloop );
gst_element_set_state (pipeline, GST_STATE_NULL);
// g_main_loop_quit( gloop );
releaseMemory();
emit sigStopStream(); // signal to main thread to issue message saying video has stopped.
}
//主线程中的某个位置
threadStreaming = new QThread();
streamVideo = new StreamingVideo( "127.0.0.1"); // we will automate this ip address later on
streamVideo->moveToThread( threadStreaming );
connect( threadStreaming, SIGNAL( started() ), streamVideo, SLOT( slotStartStream() ) );
connect( streamVideo, SIGNAL( sigStopStream() ), threadStreaming, SLOT( quit() ) );
connect( streamVideo, SIGNAL( sigStopStream() ), streamVideo, SLOT(deleteLater() ) );
connect( threadStreaming, SIGNAL( finished() ), threadStreaming, SLOT(deleteLater() ) );
connect( streamVideo, SIGNAL( sigStartStream() ), this, SLOT( slotTrueStreamRun() ) );
connect( streamVideo, SIGNAL( sigStopStream() ), this, SLOT( slotFalseStreamRun() ) );
connect( this, SIGNAL( sigMopsCamStopCmd() ), streamVideo, SLOT(slotStopStream() ) );
threadStreaming->start();
不需要依赖GMainLoop
。管道在没有g_main_loop_run()
的情况下应该运行得很好。
这里需要注意的一点是,您的主Qt应用程序循环必须轮询管道的总线以获取消息,或者使用gst_bus_set_sync_handler
为总线设置回调函数,以便在消息到达时调用该总线。稍后,您必须注意,该函数是从管道线程调用的,而不是从应用程序线程调用的。不过在这里发射信号应该没问题。
如果你想采用线程方式,你必须在你的应用程序中手动创建一个运行GMainLoop
的线程。也有可能——不过,对我来说,以上看起来更简单、更干净。
免责声明:我对GLib/GTK一无所知,但我很快就在谷歌上搜索到了——一些灵感来自于这篇SO文章,为单独的g_main_loop和位于https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-超时添加
问题是,您要处理两个事件循环——线程的Qt事件循环,它在QThread::run ()
中隐式输入,以及GLib循环,它是在slotStartStream ()
中手动输入的。你从主线程发送的所有Qt信号都必须经过Qt调度器——所以你必须给Qt一些处理它们的机会,这意味着GLib循环需要定期将控制权移交给Qt。因此,我们的想法是:安装一个GLib将定期调用的回调(例如,一个简单的计时器),并从该回调中为Qt发出一个processEvents ()
函数来完成它的工作。
我会试试这样的东西:
gboolean myCallback (gpointer user_data)
{
// The Qt thread is passed as a parameter during callback installation
QThread* workerThread = reinterpret_cast<QThread*> (user_data);
// Access the Qt thread's event dispatcher...
QAbstractEventDispatcher* disp = workerThread->eventDispatcher ();
// ...and let it do its work
disp->processEvents (QEventLoop::AllEvents);
return G_SOURCE_CONTINUE;
}
void StreamingVideo::slotStartStream ()
{
[...]
g_print ("Running...n");
// Install callback to intertwine Qt's thread-local eventloop with our GLib loop
g_timeout_add (50, myCallback, QThread::currentThread ());
emit sigStartStream(); // signal to main thread to issue success command . works fine
g_main_loop_run( gloop );
g_print ("Returned, stopping playbackn");
[...]
现在,我不知道这是否解决了您的所有问题(事实上,我很确定它不会:-),但我认为您至少会看到,在这些修改之后,您的slotStopStream ()
实际上会被调用(在工作线程的范围内)。
总而言之,这是一个相当地狱般的设置,但它可能只是起作用。
在Qt应用程序中不需要使用glib的GMainLoop。Qt有自己版本的GMainLoop(QEventLoop),您可以将其视为exec()方法。
例如,如果你有一个QGuiApplication类/派生类,你可以调用它的exec()方法来启动它的主事件循环。http://doc.qt.io/qt-5/qguiapplication.html#exec
类似地,如果你有一个QThread类/派生类,你可以调用它的exec()方法来启动它的本地事件循环。http://doc.qt.io/qt-4.8/qthread.html#exec
总之,任何需要事件循环来触发其进程的glib代码(例如g_bus_own_name,在glib中,你需要调用GMainLoop才能启动dbus。如果你把它放在Qt代码中,你只需要调用exec(),而不需要处理GMainLoop。
长话短说,只有一个事件循环,但不同的组织(例如gnome、qt)会进行不同的实现。
感谢OP提出了一个关于GLib/Qt互操作的重要问题,该问题在互联网上没有得到充分的报道。这就是GMainLoop
在QThread
中的工作方式:
QObject context;
QThread thread;
void* arvMainLoop;
...
context.moveToThread(&thread);
QObject::connect(&thread, &QThread::started, &context, [&]()
{
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
arvMainLoop = reinterpret_cast<void*>(loop);
GMainContext* context = g_main_loop_get_context(loop);
// TODO Maybe make interruption checks less frequent here.
while (!thread.isInterruptionRequested())
g_main_context_iteration(context, FALSE);
g_main_loop_quit(loop);
});
thread.start();
...
thread.requestInterruption();
thread.quit();
thread.wait();
GMainLoop* loop = reinterpret_cast<GMainLoop*>(arvMainLoop);
g_main_loop_unref(loop);
- 为什么 Clang 不允许"and"作为函数名称?
- 不允许在向量中添加更多元素
- std::带有自定义缓冲区的 iostream 不允许我写入
- Visual Studio 2017 不允许我创建 C++ 专用模板
- 返回时不允许隐式转换
- 为什么 c++(g++) 不允许模板返回类型和函数名称之间有空格?
- 错误:(-210:不支持的格式或格式组合)功能'create'中的硬件视频解码器不支持视频源
- 为什么 c++ 不允许(自动)强制转换?
- 为什么 c++11 不允许使用自动
- 为什么不允许成员函数和非成员函数之间的函数重载?
- 为什么不允许使用可变长度数组作为向量元素?
- 余数除法和不允许除以零 (c++) 时遇到问题
- C++从外部类继承的嵌套类;不允许使用不完整的类型
- 在 c++ 中三元运算符中不允许继续(关键字)吗?
- 为什么在指向对象的迭代器上调用函数不允许我更改对象本身?
- 错误:在第 6 行'{'标记之前,此处不允许使用函数定义
- 不允许在类定义之外重写
- 不允许运算符 const 参数调用 const 成员函数
- E0322:不允许使用抽象类类型 " " 的对象
- g_main_loop_run阻塞Qthread并且不允许停止视频