Reproducing a mjpeg stream works with gst-launch but not in code

Omsitelta santi.rpalma at gmail.com
Fri Jun 24 11:39:40 UTC 2016


I'm trying to reproduce a mjpeg stream from a intercom (but it's equivalent
to a IP camera). 

*Using gst-launch in the console works fine:*

    gst-launch-1.0 souphttpsrc
location="http://192.168.1.191/api/camera/snapshot?width=640&height=480&fps=10"
timeout=5 ! multipartdemux !  jpegdec ! videoconvert ! ximagesink

However, when I try to build an application to do this, it doesn't work.

*My code:*

    #include <gst/gst.h>
    #include <glib.h>  
    
    /* Structure to contain all our information, so we can pass it to
callbacks */
    typedef struct _CustomData {
      GstElement *pipeline;
      GstElement *source;
      GstElement *v_demux;
      GstElement *v_decoder;
      GstElement *v_convert;
      GstElement *v_sink;
    } CustomData;
        
    /* Handler for the pad-added signal */
    static void pad_added_handler (GstElement *src, GstPad *pad, CustomData
*data);
    
    /** Main function */
    int main(int argc, char *argv[]) {
      CustomData data;
      GstBus *bus;
      GstMessage *msg;
      GstStateChangeReturn ret;
      gboolean terminate = FALSE;
    
      /* Initialize GStreamer */
      gst_init (&argc, &argv);
        
      /* Create the elements
       *
       * souphttpsrc -> multipartdemux  (~>) jpegdec  -> videoconvert  ->
ximagesink
       *
       * ~> Sometimes pad
       *
       * */
      data.source = gst_element_factory_make ("souphttpsrc",
"video_source");
      data.v_demux = gst_element_factory_make ("multipartdemux",
"video_demux");
      data.v_decoder = gst_element_factory_make ("jpegdec",
"video_decoder");
      data.v_convert = gst_element_factory_make ("videoconvert",
"video_convert");
      data.v_sink = gst_element_factory_make ("ximagesink", "video_sink");
    
    
      /* Create the empty pipeline */
      data.pipeline = gst_pipeline_new ("new-pipeline");
    
      if (!data.pipeline || !data.source ||
          !data.v_demux || !data.v_decoder || !data.v_convert ||
!data.v_sink ) {
        g_printerr ("Not all elements could be created.\n");
        return -1;
      }
    
      /* Configure elements */
      g_object_set(G_OBJECT(data.source), "location", argv[1], NULL);
      g_object_set(G_OBJECT(data.source), "timeout", 5, NULL);
    
      /* Link all elements that can be automatically linked because they
have "Always" pads */
      gst_bin_add_many (GST_BIN (data.pipeline), data.source,
          data.v_demux, data.v_decoder, data.v_convert, data.v_sink,
          NULL);
      if (gst_element_link_many (data.source, data.v_demux, NULL) != TRUE ||
          gst_element_link_many (data.v_decoder, data.v_convert,
data.v_sink, NULL) != TRUE ) {
        g_printerr ("Elements could not be linked.\n");
        gst_object_unref (data.pipeline);
        return -1;
      }
    
      /* Connect to the pad-added signal */
      g_signal_connect (data.v_demux, "pad-added", G_CALLBACK
(pad_added_handler), &data);
    
      /* Start playing */
      ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
      if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr ("Unable to set the pipeline to the playing state.\n");
        gst_object_unref (data.pipeline);
        return -1;
      }
    
      /* Listen to the bus */
      bus = gst_element_get_bus (data.pipeline);
      do {
        msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
            GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR |
GST_MESSAGE_EOS);
    
        /* Parse message */
        if (msg != NULL) {
          GError *err;
          gchar *debug_info;
    
          switch (GST_MESSAGE_TYPE (msg)) {
            case GST_MESSAGE_ERROR:
              gst_message_parse_error (msg, &err, &debug_info);
              g_printerr ("Error received from element %s: %s\n",
GST_OBJECT_NAME (msg->src), err->message);
              g_printerr ("Debugging information: %s\n", debug_info ?
debug_info : "none");
              g_clear_error (&err);
              g_free (debug_info);
              terminate = TRUE;
              break;
            case GST_MESSAGE_EOS:
              g_print ("End-Of-Stream reached.\n");
              terminate = TRUE;
              break;
            case GST_MESSAGE_STATE_CHANGED:
              /* We are only interested in state-changed messages from the
pipeline */
              if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) {
                GstState old_state, new_state, pending_state;
                gst_message_parse_state_changed (msg, &old_state,
&new_state, &pending_state);
                g_print ("Pipeline state changed from %s to %s:\n",
                    gst_element_state_get_name (old_state),
gst_element_state_get_name (new_state));
              }
              break;
            default:
              /* We should not reach here */
              g_printerr ("Unexpected message received.\n");
              break;
          }
          gst_message_unref (msg);
        }
      } while (!terminate);
    
      /* Free resources */
      gst_object_unref (bus);
      gst_element_set_state (data.pipeline, GST_STATE_NULL);
      gst_object_unref (data.pipeline);
      return 0;
    }
    
    /* This function will be called by the pad-added signal */
    static void pad_added_handler (GstElement *src, GstPad *new_pad,
CustomData *data) {
      GstPad *sink_pad = NULL;
      GstPadLinkReturn ret;
      GstCaps *new_pad_caps = NULL;
      GstStructure *new_pad_struct = NULL;
      const gchar *new_pad_type = NULL;
    
      g_print ("Received new pad '%s' from '%s':\n", GST_PAD_NAME (new_pad),
GST_ELEMENT_NAME (src));
    
      /* Get information of the new pad's type */
      new_pad_caps = gst_pad_get_current_caps (new_pad);
      new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
      new_pad_type = gst_structure_get_name (new_pad_struct);
    
      /* Get pad from the correspondent converter */
      if (g_str_has_prefix (new_pad_type, "video")) {
        sink_pad = gst_element_get_static_pad (data->v_decoder, "sink");
      } else {
        g_print ("  It has type '%s' -> So exit\n", new_pad_type);
        return;
      }
    
      /* If our converter is already linked, we have nothing to do here */
      if (gst_pad_is_linked (sink_pad)) {
        g_print ("  We are already linked. Ignoring.\n");
        gst_object_unref (sink_pad);
        return;
      }
      
      ret = gst_pad_link (new_pad, sink_pad);
      if (GST_PAD_LINK_FAILED (ret)) {
        g_print ("  Type is '%s' but link failed.\n", new_pad_type);
      } else {
        g_print ("  Link succeeded (type '%s').\n", new_pad_type);
      }
       
      /* Unreference the new pad's caps, if we got them */
      if (new_pad_caps != NULL) {
        gst_caps_unref (new_pad_caps);
      }
    
      /* Unreference the sink pad */
      if (sink_pad != NULL) {
        gst_object_unref (sink_pad);
      }
    }



*The output when I run the program:*

    Pipeline state changed from NULL to READY:
    Pipeline state changed from READY to PAUSED:
    Error received from element video_demux: Could not demultiplex stream.
    Debugging information: multipartdemux.c(475): multipart_parse_header ():
/GstPipeline:new-pipeline/GstMultipartDemux:video_demux:
    Boundary not found in the multipart header


    
Any idea what am I missing?

Thanks in advance.



--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/Reproducing-a-mjpeg-stream-works-with-gst-launch-but-not-in-code-tp4678232.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.


More information about the gstreamer-devel mailing list