diff --git a/ext/smoothstreaming/gstmssdemux.c b/ext/smoothstreaming/gstmssdemux.c index 9fb1daf5ec..eeefe57db6 100644 --- a/ext/smoothstreaming/gstmssdemux.c +++ b/ext/smoothstreaming/gstmssdemux.c @@ -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); + } } diff --git a/ext/smoothstreaming/gstmssdemux.h b/ext/smoothstreaming/gstmssdemux.h index 52f872b0af..2b14134d46 100644 --- a/ext/smoothstreaming/gstmssdemux.h +++ b/ext/smoothstreaming/gstmssdemux.h @@ -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 { diff --git a/ext/smoothstreaming/gstmssmanifest.c b/ext/smoothstreaming/gstmssmanifest.c index 3e0096d5bd..f71270ffe0 100644 --- a/ext/smoothstreaming/gstmssmanifest.c +++ b/ext/smoothstreaming/gstmssmanifest.c @@ -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) { diff --git a/ext/smoothstreaming/gstmssmanifest.h b/ext/smoothstreaming/gstmssmanifest.h index 21b860a2d4..bbe907dab4 100644 --- a/ext/smoothstreaming/gstmssmanifest.h +++ b/ext/smoothstreaming/gstmssmanifest.h @@ -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);