g_main_loop_run阻止了Qthread并且不允许停止视频

时间:2015-12-17 01:31:43

标签: c++ multithreading qt gstreamer qthread

我为gstreamer创建了一个单独的类来传输视频 该类使用moveToThread()在单独的线程上运行 我正在使用Qt5.5进行开发 当我在主线程上发出startcommand时,Qthread启动,gstreamer使用g_main_loop_run来传输视频。这绝对没问题。但不知何故g_main_loop_run阻塞了线程,当我发出信号从主线程停止视频时,它不会在gstreamer类中执行槽。

有人可以建议我如何解决这个问题吗?要么我可以用其他命令替换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 together\n");
    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 playback\n");
    //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 playback\n");
    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();

4 个答案:

答案 0 :(得分:2)

无需依赖GMainLoop。管道应该运行得很好而没有g_main_loop_run()

你需要注意的一件事是你的主要Qt应用程序循环要么必须轮询管道总线以获取消息,要么使用gst_bus_set_sync_handler来设置要调用的总线的回调函数消息到达时对于后者,您必须知道此函数然后从管道的线程而不是应用程序的线程调用。这里发出的信号应该没问题。

如果你想采用线程方式,你必须在运行GMainLoop的应用程序中手动创建一个线程。也可能 - 上面看起来对我来说更简单,更清洁。

答案 1 :(得分:0)

免责声明:我对GLib / GTK一无所知,但我快速搜索了一下 - 一些灵感来自这篇SO add callback for separate g_main_loophttps://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add

的文档

问题在于你正在处理两个事件循环 - 线程的Qt事件循环(隐式输入QThread::run ()内部)和GLib循环(您在{{1}内手动输入) }。您从主线程发送的所有Qt信号必须通过Qt调度程序 - 因此您必须给Qt一些处理它们的机会,这意味着GLib循环需要定期将控制权移交给Qt。所以我的想法是:安装一个GLib将定期调用的回调(例如一个简单的计时器),并从该回调中发出一个slotStartStream ()函数,让Qt完成它的工作。

我会尝试这样的事情:

processEvents ()

现在,我不知道这是否能解决你所有的问题(实际上我很确定它不会:-)),但我认为你至少会看到你的{事实上,{1}}将在这些修改之后被调用(在工作线程的范围内)。

总而言之,这是一个相当神奇的设置,但它可能会起作用。

答案 2 :(得分:0)

没有必要在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)实现了不同的实现

答案 3 :(得分:0)

感谢OP提出了有关GLib / Qt互操作的重要问题,该问题在Internet上没有充分介绍。 =TRIM(LEFT(SUBSTITUTE(MID(A3,FIND("-",A3,1)+1,99)," ",REPT(" ",99)),40))+0GMainLoop中对我的工作方式如下:

QThread