mssdemux: pad exposing initial implementation
authorThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 14 Nov 2012 20:19:35 +0000 (17:19 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 8 May 2013 00:05:10 +0000 (21:05 -0300)
Does some basic parsing of the stream caps and adds a pad for
each stream detected in the manifest

ext/smoothstreaming/gstmssdemux.c
ext/smoothstreaming/gstmssdemux.h
ext/smoothstreaming/gstmssmanifest.c
ext/smoothstreaming/gstmssmanifest.h

index 9fb1daf..eeefe57 100644 (file)
@@ -122,12 +122,26 @@ gst_mss_demux_init (GstMssDemux * mssdemux, GstMssDemuxClass * klass)
 static void
 gst_mss_demux_reset (GstMssDemux * mssdemux)
 {
+  GSList *iter;
   if (mssdemux->manifest_buffer) {
     gst_buffer_unref (mssdemux->manifest_buffer);
+    mssdemux->manifest_buffer = NULL;
+  }
+
+  for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) {
+    GstMssDemuxStream *stream = iter->data;
+    gst_element_remove_pad (GST_ELEMENT_CAST (mssdemux), stream->pad);
+    g_free (stream);
   }
+  g_slist_free (mssdemux->streams);
+  mssdemux->streams = NULL;
+
   if (mssdemux->manifest) {
     gst_mss_manifest_free (mssdemux->manifest);
+    mssdemux->manifest = NULL;
   }
+
+  mssdemux->n_videos = mssdemux->n_audios = 0;
 }
 
 static void
@@ -222,12 +236,62 @@ gst_mss_demux_create_streams (GstMssDemux * mssdemux)
   }
 
   for (iter = streams; iter; iter = g_slist_next (iter)) {
+    gchar *name;
+    GstPad *srcpad = NULL;
+    GstMssDemuxStream *stream = NULL;
     GstMssManifestStream *manifeststream = iter->data;
     GstMssManifestStreamType streamtype;
 
     streamtype = gst_mss_manifest_stream_get_type (manifeststream);
     GST_DEBUG_OBJECT (mssdemux, "Found stream of type: %s",
         gst_mss_manifest_stream_type_name (streamtype));
+
+    /* TODO use stream's name as the pad name? */
+    if (streamtype == MSS_STREAM_TYPE_VIDEO) {
+      name = g_strdup_printf ("video_%02u", mssdemux->n_videos++);
+      srcpad =
+          gst_pad_new_from_static_template (&gst_mss_demux_videosrc_template,
+          name);
+      g_free (name);
+    } else if (streamtype == MSS_STREAM_TYPE_AUDIO) {
+      name = g_strdup_printf ("audio_%02u", mssdemux->n_audios++);
+      srcpad =
+          gst_pad_new_from_static_template (&gst_mss_demux_audiosrc_template,
+          name);
+      g_free (name);
+    }
+
+    if (!srcpad) {
+      GST_WARNING_OBJECT (mssdemux, "Ignoring unknown type stream");
+      continue;
+    }
+
+    stream = g_new (GstMssDemuxStream, 1);
+    stream->pad = srcpad;
+    stream->manifest_stream = manifeststream;
+    mssdemux->streams = g_slist_append (mssdemux->streams, stream);
+
+  }
+}
+
+static void
+gst_mss_demux_expose_stream (GstMssDemux * mssdemux, GstMssDemuxStream * stream)
+{
+  GstCaps *caps;
+  GstPad *pad = stream->pad;
+
+  caps = gst_mss_manifest_stream_get_caps (stream->manifest_stream);
+
+  if (caps) {
+    gst_pad_set_caps (pad, caps);
+    gst_caps_unref (caps);
+
+    gst_pad_set_active (pad, TRUE);
+    GST_INFO_OBJECT (mssdemux, "Adding srcpad %s:%s with caps %" GST_PTR_FORMAT,
+        GST_DEBUG_PAD_NAME (pad), caps);
+    gst_element_add_pad (GST_ELEMENT_CAST (mssdemux), pad);
+  } else {
+    GST_WARNING_OBJECT (mssdemux, "Not exposing stream of unrecognized format");
   }
 }
 
@@ -237,6 +301,7 @@ gst_mss_demux_process_manifest (GstMssDemux * mssdemux)
   GstQuery *query;
   gchar *uri = NULL;
   gboolean ret;
+  GSList *iter;
 
   g_return_if_fail (mssdemux->manifest_buffer != NULL);
   g_return_if_fail (mssdemux->manifest == NULL);
@@ -258,4 +323,7 @@ gst_mss_demux_process_manifest (GstMssDemux * mssdemux)
   }
 
   gst_mss_demux_create_streams (mssdemux);
+  for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) {
+    gst_mss_demux_expose_stream (mssdemux, iter->data);
+  }
 }
index 52f872b..2b14134 100644 (file)
@@ -45,9 +45,16 @@ GST_DEBUG_CATEGORY_EXTERN (mssdemux_debug);
 
 #define GST_MSS_DEMUX_CAST(obj) ((GstMssDemux *)(obj))
 
+typedef struct _GstMssDemuxStream GstMssDemuxStream;
 typedef struct _GstMssDemux GstMssDemux;
 typedef struct _GstMssDemuxClass GstMssDemuxClass;
 
+struct _GstMssDemuxStream {
+  GstPad *pad;
+
+  GstMssManifestStream *manifest_stream;
+};
+
 struct _GstMssDemux {
   GstElement element;
 
@@ -57,6 +64,10 @@ struct _GstMssDemux {
   GstBuffer *manifest_buffer;
 
   GstMssManifest *manifest;
+
+  GSList *streams;
+  guint n_videos;
+  guint n_audios;
 };
 
 struct _GstMssDemuxClass {
index 3e0096d..f71270f 100644 (file)
@@ -30,6 +30,8 @@
 struct _GstMssManifestStream
 {
   xmlNodePtr xmlnode;
+
+  gint selectedQualityIndex;
 };
 
 struct _GstMssManifest
@@ -98,6 +100,133 @@ gst_mss_manifest_stream_get_type (GstMssManifestStream * stream)
   return ret;
 }
 
+static GstCaps *
+_gst_mss_manifest_stream_video_caps_from_fourcc (gchar * fourcc)
+{
+  if (!fourcc)
+    return NULL;
+
+  if (strcmp (fourcc, "H264") == 0) {
+    return gst_caps_new_simple ("video/x-h264", NULL);
+  }
+  return NULL;
+}
+
+static GstCaps *
+_gst_mss_manifest_stream_audio_caps_from_fourcc (gchar * fourcc)
+{
+  if (!fourcc)
+    return NULL;
+
+  if (strcmp (fourcc, "AACL") == 0) {
+    return gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 4,
+        NULL);
+  }
+  return NULL;
+}
+
+static GstCaps *
+_gst_mss_manifest_stream_video_caps_from_qualitylevel_xml (xmlNodePtr node)
+{
+  GstCaps *caps;
+  GstStructure *structure;
+  gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
+  gchar *max_width = (gchar *) xmlGetProp (node, (xmlChar *) "MaxWidth");
+  gchar *max_height = (gchar *) xmlGetProp (node, (xmlChar *) "MaxHeight");
+  gchar *codec_data =
+      (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
+
+  caps = _gst_mss_manifest_stream_video_caps_from_fourcc (fourcc);
+  if (!caps)
+    goto end;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (max_width)
+    gst_structure_set (structure, "width", G_TYPE_INT, atoi (max_width), NULL);
+  if (max_height)
+    gst_structure_set (structure, "height", G_TYPE_INT, atoi (max_height),
+        NULL);
+
+  if (codec_data) {
+    GValue *value = g_new0 (GValue, 1);
+    g_value_init (value, GST_TYPE_BUFFER);
+    gst_value_deserialize (value, (gchar *) codec_data);
+    gst_structure_take_value (structure, "codec_data", value);
+  }
+
+end:
+  g_free (fourcc);
+  g_free (max_width);
+  g_free (max_height);
+  g_free (codec_data);
+
+  return caps;
+}
+
+static GstCaps *
+_gst_mss_manifest_stream_audio_caps_from_qualitylevel_xml (xmlNodePtr node)
+{
+  GstCaps *caps;
+  GstStructure *structure;
+  gchar *fourcc = (gchar *) xmlGetProp (node, (xmlChar *) "FourCC");
+  gchar *channels = (gchar *) xmlGetProp (node, (xmlChar *) "Channels");
+  gchar *rate = (gchar *) xmlGetProp (node, (xmlChar *) "SamplingRate");
+  gchar *codec_data =
+      (gchar *) xmlGetProp (node, (xmlChar *) "CodecPrivateData");
+
+  caps = _gst_mss_manifest_stream_audio_caps_from_fourcc (fourcc);
+  if (!caps)
+    goto end;
+
+  structure = gst_caps_get_structure (caps, 0);
+
+  if (channels)
+    gst_structure_set (structure, "channels", G_TYPE_INT, atoi (channels),
+        NULL);
+  if (rate)
+    gst_structure_set (structure, "rate", G_TYPE_INT, atoi (rate), NULL);
+
+  if (codec_data) {
+    GValue *value = g_new0 (GValue, 1);
+    g_value_init (value, GST_TYPE_BUFFER);
+    gst_value_deserialize (value, (gchar *) codec_data);
+    gst_structure_take_value (structure, "codec_data", value);
+  }
+
+end:
+  g_free (fourcc);
+  g_free (channels);
+  g_free (rate);
+  g_free (codec_data);
+
+  return caps;
+}
+
+GstCaps *
+gst_mss_manifest_stream_get_caps (GstMssManifestStream * stream)
+{
+  GstMssManifestStreamType streamtype =
+      gst_mss_manifest_stream_get_type (stream);
+
+  /* TODO properly get the stream */
+  xmlNodePtr qualitylevel = stream->xmlnode->children;
+  while (strcmp ((gchar *) qualitylevel->name, "QualityLevel")) {
+    qualitylevel = qualitylevel->next;
+  }
+
+  if (streamtype == MSS_STREAM_TYPE_VIDEO)
+    return
+        _gst_mss_manifest_stream_video_caps_from_qualitylevel_xml
+        (qualitylevel);
+  else if (streamtype == MSS_STREAM_TYPE_AUDIO)
+    return
+        _gst_mss_manifest_stream_audio_caps_from_qualitylevel_xml
+        (qualitylevel);
+
+  return NULL;
+}
+
 const gchar *
 gst_mss_manifest_stream_type_name (GstMssManifestStreamType streamtype)
 {
index 21b860a..bbe907d 100644 (file)
@@ -43,6 +43,7 @@ void gst_mss_manifest_free (GstMssManifest * manifest);
 GSList * gst_mss_manifest_get_streams (GstMssManifest * manifest);
 
 GstMssManifestStreamType gst_mss_manifest_stream_get_type (GstMssManifestStream *stream);
+GstCaps * gst_mss_manifest_stream_get_caps (GstMssManifestStream * stream);
 
 const gchar * gst_mss_manifest_stream_type_name (GstMssManifestStreamType streamtype);