2017-12-07 6 views
0

implementieren Ich habe die folgende funktionierende Pipeline. Es wurde mit dem Befehlszeilentool gst-launch-1.0 und der Funktion gst_parse_launch() getestet und funktioniert in beiden Fällen.Wie man GStreamer tee in C-Code

videotestsrc  ! video/x-raw,width=640,height=480 ! videocrop left=80 right=80 ! tee name=t ! queue ! glupload ! glimagesink t. ! queue ! jpegenc ! avimux ! filesink location=output.avi 

Ich habe versucht, ihn manuell in Code einzurichten, aber ich bin jetzt auf dem folgenden Fehler stecken (die Anwendung geöffnet wird, aber kein Video angezeigt wird):

Fehler, die von Element videotestsrc0: Interner Datenflussfehler.

Debugging-Informationen: gstbasesrc.c (2948): gst_base_src_loop(): /GstPipeline: pipeline0/GstVideoTestSrc: videotestsrc0: Streaming Aufgabe pausiert, Grund nicht verhandelt (-4)

Ich bin Wenn Sie GStreamer in einer Qt-Anwendung verwenden, wird der Video-Link mit dem Qimeslink mit einem QML-Typ verknüpft. Der gesamte zu GStreamer gehörende Code befindet sich in einer GStreamer-Klasse namens GStreamer. Die gesamte cpp-Datei wird unten veröffentlicht, falls das Problem irgendwo liegt, würde ich nicht raten. Ich entschuldige mich für nicht relevanten Code.

static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data); 

GStreamer::GStreamer(QQuickItem *parent) : QQuickItem(parent) 
{ 
    qDebug() << "Constructed GSteamer";   
}  

void GStreamer::createPipeline() 
{ 
    qDebug() << "Creating pipeline";  

    if(m_source.isEmpty()){ 
     qDebug() << "Error: Missing source property for GStreamer component"; 
     return; 
    } 

    if(m_videoItem.isEmpty()){ 
     qDebug() << "Error: Missing videoItem property for GStreamer component"; 
     return; 
    } 

    m_pipeline = gst_pipeline_new(NULL); 
    m_sink = NULL; 

    QByteArray ba = m_source.toLatin1(); 
    m_src = gst_element_factory_make(ba.data(), NULL); 
    g_assert(m_src); 


    m_filter = gst_element_factory_make("capsfilter", "filter"); 
    g_assert(m_filter); 

    g_object_set(G_OBJECT (m_filter), "caps", gst_caps_new_simple("video/x-raw", 
     "width", G_TYPE_INT, 640, 
     "height", G_TYPE_INT, 480, 
     NULL), 
    NULL); 

    m_convert = gst_element_factory_make("videoconvert", NULL); 
    g_assert(m_convert); 

    m_crop = gst_element_factory_make("videocrop", "crop"); 
    g_assert(m_crop); 

    g_object_set(G_OBJECT (m_crop), "left", 80, "right", 80, NULL); 

    // Tee 
    m_tee = gst_element_factory_make("tee", "videotee"); 
    g_assert(m_tee); 

    // Display queue 
    m_displayQueue = gst_element_factory_make("queue", "displayQueue"); 
    g_assert(m_displayQueue);  

    m_upload = gst_element_factory_make("glupload", NULL); 
    g_assert(m_upload);  

    m_sink = gst_element_factory_make("qmlglsink", NULL); 
    g_assert(m_sink); 

    // Record queue 
    m_recordQueue = gst_element_factory_make("queue", "recordQueue"); 
    g_assert(m_recordQueue); 

    m_encode = gst_element_factory_make("jpegenc", NULL); 
    g_assert(m_encode); 

    m_mux = gst_element_factory_make("avimux", NULL); 
    g_assert(m_mux); 

    m_filesink = gst_element_factory_make("filesink", NULL); 
    g_assert(m_filesink); 

    g_object_set(G_OBJECT(m_filesink), "location", "output.avi", NULL);  

    gst_bin_add_many(GST_BIN (m_pipeline), m_src, m_filter, m_convert, m_crop, m_upload, m_sink, NULL); 
    gst_bin_add_many(GST_BIN(m_pipeline), m_tee, m_displayQueue, m_recordQueue, m_encode, m_mux, m_filesink, NULL); 

    // If I only link this simple pipeline, it works fine 
    /* 
    if(!gst_element_link_many(m_src, m_filter, m_convert, m_crop, m_upload, m_sink, NULL)){ 
     qDebug() << "Unable to link source"; 
    } 
    */ 

    if(!gst_element_link_many(m_src, m_filter, m_convert, m_crop, m_tee, NULL)){ 
     qDebug() << "Unable to link source"; 
    } 
    if(!gst_element_link_many(m_displayQueue, m_upload, m_sink, NULL)){ 
     qDebug() << "Unable to link display queue"; 
    } 
    if(!gst_element_link_many(m_recordQueue, m_encode, m_mux, m_filesink, NULL)){ 
     qDebug() << "Unable to link record queue"; 
    }  

    GstPad *teeDisplayPad = gst_element_get_request_pad(m_tee, "src_%u"); 
    GstPad *queueDisplayPad = gst_element_get_static_pad(m_displayQueue, "sink"); 

    GstPad *teeRecordPad = gst_element_get_request_pad(m_tee, "src_%u"); 
    GstPad *queueRecordPad = gst_element_get_static_pad(m_recordQueue, "sink"); 

    if(gst_pad_link(teeDisplayPad, queueDisplayPad) != GST_PAD_LINK_OK){ 
     qDebug() << "Unable to link display tee"; 
    } 

    if(gst_pad_link(teeRecordPad, queueRecordPad) != GST_PAD_LINK_OK){ 
     qDebug() << "Unable to link record tee"; 
    } 

    //gst_object_unref(teeDisplayPad); 
    gst_object_unref(queueDisplayPad); 
    //gst_object_unref(teeRecordPad); 
    gst_object_unref(queueRecordPad);  

    QQuickItem *videoItem = window()->findChild<QQuickItem *> (m_videoItem); 
    g_object_set(m_sink, "widget", videoItem, NULL); 

    // This will call gst_element_set_state(m_pipeline, GST_STATE_PLAYING) when the window is ready 
    window()->scheduleRenderJob (new SetPlaying (m_pipeline), QQuickWindow::BeforeSynchronizingStage);  

    m_bus = gst_element_get_bus(m_pipeline); 

    gst_bus_add_watch(m_bus, busCallback, m_loop); 
    gst_object_unref(m_bus); 

    m_loop = g_main_loop_new(NULL, false); 
    g_main_loop_run(m_loop);  
} 

static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data){ 
    qDebug() << "Callback function reached"; 
    switch(GST_MESSAGE_TYPE(message)){ 
     case GST_MESSAGE_ERROR: 
      GError *error; 
      gchar *debugInfo; 
      gst_message_parse_error(message, &error, &debugInfo); 
      qDebug() << "Error received from element" << GST_OBJECT_NAME(message->src) << ":" << error->message; 
      qDebug() << "Debugging information:" << (debugInfo ? debugInfo : "none"); 
      //g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (m_message->src), error->message); 
      //g_printerr ("Debugging information: %s\n", debugInfo ? debugInfo : "none"); 
      g_clear_error (&error); 
      g_free (debugInfo); 

      g_main_loop_quit(static_cast<GMainLoop *>(data)); 
      break; 
     case GST_MESSAGE_EOS: 
      qDebug() << "End-Of-Stream reached."; 
      g_main_loop_quit(static_cast<GMainLoop *>(data)); 
      break; 
     default: 
      qDebug() << "Unexpected message received."; 
      break; 
     } 
    return true;  
} 

/** 
The rest of the code is probably not relevant. It contains 
only destructor and some getters and setters. 
**/ 

GStreamer::~GStreamer() 
{ 
    gst_object_unref(m_bus); 
    gst_element_set_state(m_pipeline, GST_STATE_NULL); 
    gst_object_unref(m_pipeline); 
} 

QString GStreamer::source() const 
{ 
    return m_source; 
} 

void GStreamer::setSource(const QString &source) 
{ 
    if(source != m_source){ 
     m_source = source; 
    } 
} 

QString GStreamer::videoItem() const 
{ 
    return m_videoItem; 
} 

void GStreamer::setVideoItem(const QString &videoItem) 
{ 
    if(videoItem != m_videoItem){ 
     m_videoItem = videoItem; 
    } 
} 

Alle Mitgliedsvariablen sind in der .h-Datei definiert.

Wenn ich das Abzweigungselement nicht zur Bin hinzufüge und es in der Pipeline verlinke, wird das Video erwartungsgemäß auf dem Bildschirm angezeigt. Also schätze ich, dass ich die Pads auf dem Tee-Element vermasselt habe.

Ich habe die Tutorials in GStreamers Dokumentation verfolgt, so dass ich nicht verstehe, warum es nicht funktioniert.

Hoffe, dass jemand helfen kann.

Antwort

1

Ok, also der Unterschied zwischen der gst-Startlinie und dem Anwendungscode ist die Verwendung des qmlglsink Elements anstelle von glimagesink.

Das Problem ist, dass qmlglsink nur RGBA formatierte Videopuffer übernimmt jedoch die jpegenc in den anderen Zweig des tee nicht RGBA Puffer formatiert Video akzeptieren. Dies führt zu einem Verhandlungsproblem, da kein gemeinsames Format von beiden Zweigen der tee unterstützt wird.

Der Fix ist ein videoconvert Element vor jpegenc oder einem glcolorconvert Element vor qmlglsink hinzuzufügen, so dass beide Zweige des tee das gleiche Videoformat aushandeln kann.

Seitennotiz: glimagesink enthält eine glupload ! glcolorconvert ! actual-sink intern, also konvertiert Videoformate bereits.

+0

Vielen Dank !!!! Ich kämpfe seit Tagen damit und das hat es gelöst. – KMK