gstreamer code for playing avi file is hanging

前端 未结 1 1707
遇见更好的自我
遇见更好的自我 2020-12-17 05:39

I am new to gstremaer. I have written a code for playing avi file using gstreamer. But on executing the code it just hangs after a while, I am unable to debug whats

相关标签:
1条回答
  • 2020-12-17 06:09

    Your code is wrong in several ways, that is why my answer is so long.

    First of all, gst_pipeline_new returns GstElement* not GstPipeline*:

    -  pipeline = gst_pipeline_new("PIPELINE");
    +  GstElement *pipeline = gst_pipeline_new("PIPELINE");
       Bin = GST_BIN(pipeline);
    -  bus = gst_pipeline_get_bus(pipeline);
    +  bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    

    Then, your pipeline is wrong: you trying to decode both streams (audio and video) with one decodebin but you need two. Create it and don't forget to add it to the bin:

       videoqueue = gst_element_factory_make("queue","Queue for video");
    +  audio_decoder = gst_element_factory_make("decodebin","a_decodebin");
       video_decoder = gst_element_factory_make("decodebin","decoderbin");//"Vorbis audio decoder","vorbis");
    
    -  gst_bin_add_many(Bin,demuxer,audioqueue,videoqueue,audio_convertor,video_decoder,video_convertor,audio_sink,video_sink,NULL);
    +  gst_bin_add_many(
    +    Bin,
    +    demuxer,
    +    audioqueue,videoqueue,
    +    audio_decoder,audio_convertor,
    +    video_decoder,video_convertor,
    +    audio_sink,video_sink,
    +    NULL);
    

    And, by the way, it's better to use decodebin2 as decodebin is deprecated.

    Then you linking some elements dynamically: demuxer to queue and decodebin to convertors. Hence you should not create link between decodebin and convertors with gst_element_link_many:

       gst_element_link(source,demuxer);
    -  gst_element_link_many(audioqueue,video_decoder,audio_convertor,audio_sink,NULL);
    -  gst_element_link_many(videoqueue,video_decoder,video_convertor,video_sink,NULL);
    +  gst_element_link_many(audioqueue,audio_decoder,NULL);
    +  gst_element_link_many(audio_convertor,audio_sink,NULL);
    +  gst_element_link_many(videoqueue,video_decoder,NULL);
    +  gst_element_link_many(video_convertor,video_sink,NULL);
    

    And of course, as we added audio_decoder decodebin, we need to handle it's pad creation signal:

    +  g_signal_connect(audio_decoder,"new-decoded-pad",G_CALLBACK(dynamic_decodepad),NULL);
       g_signal_connect(video_decoder,"new-decoded-pad",G_CALLBACK(dynamic_decodepad),NULL);
    

    And now we are at the most interesting part.

    void dynamic_addpad(GstElement *element, GstPad *pad, gpointer data)
    {
      GstPad *audiodemuxsink;
      GstPad *videodemuxsink;
      GstElement *decoder = (GstElement *)data;
      g_print(" In dynamic ADDING PAD\n");
    
      audiodemuxsink = gst_element_get_static_pad(audioqueue,"sink");
      gst_pad_link(pad,audiodemuxsink );
      videodemuxsink = gst_element_get_static_pad(videoqueue,"sink");
      gst_pad_link(pad,videodemuxsink );
      g_print(" In dynamic ADDING PAD2\n");
    }
    

    This is completely wrong! dynamic_addpad is called on each pad creation. avidemux commonly creates two pads (one for each data stream): "audio_00" and "video_00". So, dynamic_addpad will be called twice and we need to distinguish what to link depending on pad name:

    void dynamic_addpad(GstElement *element, GstPad *pad, gpointer data)
    {
      char* pad_name = gst_pad_get_name(pad);
      g_print(" In dynamic ADDING PAD %s\n", pad_name);
    
      if (g_str_has_prefix(pad_name,"audio")) {
        GstPad *audiodemuxsink = gst_element_get_static_pad(audioqueue,"sink");
        gst_pad_link(pad,audiodemuxsink );
      }
      else if (g_str_has_prefix(pad_name,"video")) {
        GstPad *videodemuxsink = gst_element_get_static_pad(videoqueue,"sink");
        gst_pad_link(pad,videodemuxsink );
      }
      g_free (pad_name);
    }
    

    Almost the same is for dynamic_decodepad. As it's only one src pad is created by decodebin, it will be easier to create separate handlers for video_decoder and audio_decoder.
    But for pedagogical reasons I will do it in one function. Now we can distinguish which element to connect to pad by it's caps.

    void dynamic_decodepad (GstElement* object, GstPad* pad, gboolean arg1,gpointer user_data)
    {
      GstPad* videoconvertsink = gst_element_get_static_pad(video_convertor,"sink");
      if (gst_pad_can_link(pad,videoconvertsink)) {
        gst_pad_link(pad,videoconvertsink);
      }
    
      GstPad* audioconvertsink  = gst_element_get_static_pad(audio_convertor,"sink");
      if (gst_pad_can_link(pad,audioconvertsink)) {
        gst_pad_link(pad,audioconvertsink);
      }
    }
    

    gst_pad_can_link will not work in dynamic_addpath because it's possible to connect query element both to "audio_00" and "video_00".

    That's it. Don't hesitate to ask if you have other questions.

    0 讨论(0)
提交回复
热议问题