2015-12-17 30 views
10

Ho creato una classe separata per gstreamer per lo streaming di video.
Questa classe viene eseguita su thread separato utilizzando moveToThread().
Sto usando Qt5.5 per lo sviluppo.
Quando si esegue startcommand su thread principale, Qthread si avvia e gstreamer utilizza g_main_loop_run per lo streaming di video. Questo funziona assolutamente bene. Ma in qualche modo g_main_loop_run blocca il thread e quando invio il segnale per fermare il video dal thread principale, non esegue lo slot nella classe gstreamer.g_main_loop_run blocca il Qthread e non consente di arrestare il video

Qualcuno può consigliarmi come risolvere il problema? O posso sostituire g_main_loop_r un con qualche altro comando o può essere utilizzato g_main_loop_quit(gloop); in un altro modo.

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. 
} 

// da qualche parte nel thread principale

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(); 
+1

perché non utilizzare QMediaPlayer invece di provare a mettere insieme Qt e Gtk +? – MrEricSir

+0

Sfortunatamente, il req del progetto utilizza solo gstreamer-0.10 n con qt. Lol – samprat

+0

Quindi non puoi usare gstreamer senza g_main_loop_run? – dtech

risposta

0

Diniego: Non so nulla di GLib/GTK, ma quello che ho subito cercato su google - qualche ispirazione è venuta da questo SO inviare add callback for separate g_main_loop e il docu al https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#g-timeout-add

Il problema è che hai a che fare con due loop di eventi: il ciclo di eventi Qt per il thread, immesso implicitamente all'interno di QThread::run() e il ciclo di GLib, che inserisci manualmente all'interno del tuo slotStartStream(). Tutti i segnali Qt inviati dal thread principale devono passare attraverso il dispatcher Qt, quindi devi dare a Qt qualche possibilità di processarli, e ciò significa che il ciclo di GLib deve passare periodicamente il controllo a Qt. Quindi l'idea è: installare un callback (ad esempio un semplice timer) che GLib chiamerà periodicamente, e da tale callback emettere una funzione processEvents() per Qt per fare il suo lavoro.

vorrei provare qualcosa di simile:

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 playback\n"); 

    [...] 

Ora, io non so se che risolve tutti i vostri problemi (in realtà sono abbastanza sicuro che non si :-)), ma io pensa che almeno vedrai che il tuo slotStopStream() sarà chiamato (nell'ambito del thread di lavoro) dopo quelle modifiche.

Tutto sommato, è un setup piuttosto infernale, ma potrebbe funzionare.

+0

In realtà, dopo la modifica al mio codice, va all'interno di slotStopStream ma dopo aver eseguito g_main_loop_quit, il video continua a non fermarsi – samprat

2

Non è necessario fare affidamento su un GMainLoop. La pipeline dovrebbe funzionare perfettamente senza uno g_main_loop_run().

L'unica cosa da notare qui è che il ciclo principale dell'applicazione Qt dovrà interrogare il bus della pipeline per i messaggi OPPURE usare gst_bus_set_sync_handler per impostare una funzione di richiamata per il bus da chiamare quando arrivano i messaggi. Per i successivi devi essere consapevole che questa funzione viene quindi chiamata dal thread della pipeline e non da quella dell'applicazione. Emettere segnali qui dovrebbe andare bene però.

Se si desidera passare alla modalità thread, è necessario creare manualmente un thread nell'applicazione che esegue GMainLoop. Inoltre possibile - quanto sopra sembra il modo più facile e più pulito per me però.

0

Non è necessario utilizzare GMainLoop di glib all'interno di un'applicazione Qt. Qt ha la sua versione di GMainLoop (QEventLoop) che puoi semplicemente pensare come metodo exec().

Ad esempio, se si dispone di una classe QGuiApplication/derivata, è possibile chiamare il relativo metodo exec() per avviare il ciclo di eventi principale. http://doc.qt.io/qt-5/qguiapplication.html#exec

Analogamente, se si dispone di una classe QThread/classe derivata, è possibile chiamare il relativo metodo exec() per avviare il ciclo di eventi locale. http://doc.qt.io/qt-4.8/qthread.html#exec

Sintesi, alcun codice glib che ha bisogno di un ciclo di eventi per far scattare il suo processo (ad esempio g_bus_own_name, in glib è necessario chiamare GMainLoop in modo che il dbus per iniziare. Se si mette questo in un codice di Qt, solo tu bisogno di chiamare exec() invece di trattare con GMainLoop.

per rendere lunga storia breve, c'è solo un ciclo di eventi, ma diverse implementazioni sono fatte da diversa organizzazione (ad esempio gnome, qt)