2017-12-07 66 views
0

私は以下の作業パイプラインを持っています。コマンドラインツールgst-launch-1.0と機能gst_parse_launch()の両方を使用してテストされ、どちらの場合でも動作します。CコードでGStreamer teeを実装する方法

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 

私はコード内で手動で設定しようとしましたが、私は今、次のようなエラーにこだわっ(アプリケーションが開きますが、何の映像は表示されません):

エラーから受け取りました要素videotestsrc0:内部データフローエラー。

デバッグ情報:gstbasesrc.c(2948):gst_base_src_loop(): /GstPipeline:pipeline0/GstVideoTestSrc:videotestsrc0:ストリーミングタスク は、私は交渉ではない、その理由(-4)

を一時停止QtアプリケーションでGStreamerを使用し、glimagesinkはビデオをQMLタイプにリンクします。 GStreamerに関連するすべてのコードは、GStreamerというGStreamerクラスにあります。問題がどこかにあると思われる場合に備えて、cppファイル全体が以下に掲載されています。私は非関連コードをお詫び申し上げます。

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

すべてのメンバー変数は、.hファイルで定義されています。

ビンにティー要素を追加してパイプラインでリンクすると、ビデオが期待どおりに画面に表示されます。だから、私はティー要素のパッドを台無しにしていると思う。

私はGStreamersのドキュメントのチュートリアルに従っています。なぜ動作しないのか分かりません。

誰かが助けてくれることを願っています。

答えて

1

ここで提供されているgst-launchラインとアプリケーションコードの違いは、glimagesinkの代わりにqmlglsinkエレメントを使用したことです。

問題はqmlglsinkのみRGBAフォーマットされたビデオがバッファRGBAフォーマットされたビデオ・バッファを受け付けないteeの他の支店でjpegencを受け入れるということです。これにより、teeの両方のブランチでサポートされている共通形式がないため、ネゴシエーションの問題が発生します。

修正はteeの両方の分岐が同じビデオフォーマットをネゴシエートできるようにする前にqmlglsinkjpegencglcolorconvert要素または前videoconvert要素を追加することです。

サイドノート:glimagesinkには内部でglupload ! glcolorconvert ! actual-sinkが含まれていますので、既にビデオフォーマットを変換しています。

+0

ありがとうございました!!!!私はこれを数日間苦労しており、これでそれが解決されました。 – KMK

関連する問題