From 0cd3938345d245954c37d58904364444fab8cef7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 23 Apr 2015 17:22:11 +0200 Subject: [PATCH] adaptivedemux: Allow subclasses to override how a new manifest would be downloaded --- ext/dash/gstdashdemux.c | 8 ++- ext/hls/gsthlsdemux.c | 9 +-- ext/smoothstreaming/gstmssdemux.c | 9 ++- ext/smoothstreaming/gstmssmanifest.c | 3 +- gst-libs/gst/adaptivedemux/gstadaptivedemux.c | 81 ++++++++++++++++----------- gst-libs/gst/adaptivedemux/gstadaptivedemux.h | 16 +++++- 6 files changed, 80 insertions(+), 46 deletions(-) diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index e2d5dc7..1b18ec1 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -214,7 +214,7 @@ static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * static gint64 gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux); static GstFlowReturn -gst_dash_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buf); +gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux, GstBuffer * buf); static gint64 gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream * stream); @@ -354,7 +354,8 @@ gst_dash_demux_class_init (GstDashDemuxClass * klass) gstadaptivedemux_class->seek = gst_dash_demux_seek; gstadaptivedemux_class->process_manifest = gst_dash_demux_process_manifest; - gstadaptivedemux_class->update_manifest = gst_dash_demux_update_manifest; + gstadaptivedemux_class->update_manifest_data = + gst_dash_demux_update_manifest_data; gstadaptivedemux_class->get_manifest_update_interval = gst_dash_demux_get_manifest_update_interval; @@ -1145,7 +1146,8 @@ gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux) } static GstFlowReturn -gst_dash_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer) +gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux, + GstBuffer * buffer) { GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux); GstMpdClient *new_client = NULL; diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c index 8da415b..f9d353d 100644 --- a/ext/hls/gsthlsdemux.c +++ b/ext/hls/gsthlsdemux.c @@ -100,8 +100,8 @@ static gint64 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux * demux); static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf); -static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux, - GstBuffer * buf); +static GstFlowReturn gst_hls_demux_update_manifest_data (GstAdaptiveDemux * + demux, GstBuffer * buf); static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek); static gboolean gst_hls_demux_start_fragment (GstAdaptiveDemux * demux, @@ -186,7 +186,8 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass) adaptivedemux_class->get_manifest_update_interval = gst_hls_demux_get_manifest_update_interval; adaptivedemux_class->process_manifest = gst_hls_demux_process_manifest; - adaptivedemux_class->update_manifest = gst_hls_demux_update_manifest; + adaptivedemux_class->update_manifest_data = + gst_hls_demux_update_manifest_data; adaptivedemux_class->reset = gst_hls_demux_reset; adaptivedemux_class->seek = gst_hls_demux_seek; adaptivedemux_class->stream_has_next_fragment = @@ -400,7 +401,7 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek) } static GstFlowReturn -gst_hls_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buf) +gst_hls_demux_update_manifest_data (GstAdaptiveDemux * demux, GstBuffer * buf) { GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux); if (!gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL)) diff --git a/ext/smoothstreaming/gstmssdemux.c b/ext/smoothstreaming/gstmssdemux.c index 90cfac1..8f10d7d 100644 --- a/ext/smoothstreaming/gstmssdemux.c +++ b/ext/smoothstreaming/gstmssdemux.c @@ -135,7 +135,8 @@ static gboolean gst_mss_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek); static gint64 gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux); static GstFlowReturn -gst_mss_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer); +gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux, + GstBuffer * buffer); static void gst_mss_demux_class_init (GstMssDemuxClass * klass) @@ -188,7 +189,8 @@ gst_mss_demux_class_init (GstMssDemuxClass * klass) gst_mss_demux_stream_select_bitrate; gstadaptivedemux_class->stream_update_fragment_info = gst_mss_demux_stream_update_fragment_info; - gstadaptivedemux_class->update_manifest = gst_mss_demux_update_manifest; + gstadaptivedemux_class->update_manifest_data = + gst_mss_demux_update_manifest_data; GST_DEBUG_CATEGORY_INIT (mssdemux_debug, "mssdemux", 0, "mssdemux plugin"); } @@ -546,7 +548,8 @@ gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux) } static GstFlowReturn -gst_mss_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer) +gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux, + GstBuffer * buffer) { GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux); diff --git a/ext/smoothstreaming/gstmssmanifest.c b/ext/smoothstreaming/gstmssmanifest.c index 7254e4d..e92e3da 100644 --- a/ext/smoothstreaming/gstmssmanifest.c +++ b/ext/smoothstreaming/gstmssmanifest.c @@ -724,7 +724,8 @@ _gst_mss_stream_audio_caps_from_qualitylevel_xml (GstMssStreamQuality * q) gst_structure_set (structure, "rate", G_TYPE_INT, rate, NULL); if (q->bitrate) - gst_structure_set (structure, "bitrate", G_TYPE_INT, (int) q->bitrate, NULL); + gst_structure_set (structure, "bitrate", G_TYPE_INT, (int) q->bitrate, + NULL); if (codec_data) gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, codec_data, diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c index 4b356f8..033a434 100644 --- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c +++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c @@ -106,7 +106,7 @@ enum GstAdaptiveDemuxFlowReturn struct _GstAdaptiveDemuxPrivate { GstAdapter *input_adapter; - GstBuffer *manifest_buffer; + gboolean have_manifest; GstUriDownloader *downloader; @@ -167,6 +167,8 @@ gst_adaptive_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream); static GstFlowReturn gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux); +static GstFlowReturn +gst_adaptive_demux_update_manifest_default (GstAdaptiveDemux * demux); static gboolean gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux); static void gst_adaptive_demux_advance_period (GstAdaptiveDemux * demux); @@ -314,6 +316,7 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass) klass->data_received = gst_adaptive_demux_stream_data_received_default; klass->finish_fragment = gst_adaptive_demux_stream_finish_fragment_default; + klass->update_manifest = gst_adaptive_demux_update_manifest_default; } static void @@ -419,6 +422,7 @@ gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent, gboolean query_res; gboolean ret = TRUE; gsize available; + GstBuffer *manifest_buffer; demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux); available = gst_adapter_available (demux->priv->input_adapter); @@ -460,16 +464,19 @@ gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent, gst_query_unref (query); /* Let the subclass parse the manifest */ - demux->priv->manifest_buffer = + manifest_buffer = gst_adapter_take_buffer (demux->priv->input_adapter, available); - if (!demux_class->process_manifest (demux, demux->priv->manifest_buffer)) { + if (!demux_class->process_manifest (demux, manifest_buffer)) { /* In most cases, this will happen if we set a wrong url in the * source element and we have received the 404 HTML response instead of * the manifest */ GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid manifest."), (NULL)); ret = FALSE; + } else { + demux->priv->have_manifest = TRUE; } + gst_buffer_unref (manifest_buffer); gst_element_post_message (GST_ELEMENT_CAST (demux), gst_message_new_element (GST_OBJECT_CAST (demux), @@ -578,10 +585,7 @@ gst_adaptive_demux_reset (GstAdaptiveDemux * demux) demux->manifest_base_uri = NULL; gst_adapter_clear (demux->priv->input_adapter); - if (demux->priv->manifest_buffer) { - gst_buffer_unref (demux->priv->manifest_buffer); - demux->priv->manifest_buffer = NULL; - } + demux->priv->have_manifest = FALSE; gst_segment_init (&demux->segment, GST_FORMAT_TIME); @@ -1101,7 +1105,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent, GST_MANIFEST_LOCK (demux); gst_query_parse_duration (query, &fmt, NULL); - if (fmt == GST_FORMAT_TIME && demux->priv->manifest_buffer != NULL) { + if (fmt == GST_FORMAT_TIME && demux->priv->have_manifest) { duration = demux_class->get_duration (demux); if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) { @@ -1118,7 +1122,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent, gboolean live = FALSE; GST_MANIFEST_LOCK (demux); - live = demux->priv->manifest_buffer && gst_adaptive_demux_is_live (demux); + live = demux->priv->have_manifest && gst_adaptive_demux_is_live (demux); GST_MANIFEST_UNLOCK (demux); gst_query_set_latency (query, live, 0, -1); @@ -1131,7 +1135,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent, gint64 start = 0; GST_MANIFEST_LOCK (demux); - if (demux->priv->manifest_buffer == NULL) { + if (demux->priv->have_manifest) { GST_MANIFEST_UNLOCK (demux); return FALSE; /* can't answer without manifest */ } @@ -2470,7 +2474,7 @@ gst_adaptive_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux * } static GstFlowReturn -gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux) +gst_adaptive_demux_update_manifest_default (GstAdaptiveDemux * demux) { GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux); GstFragment *download; @@ -2493,33 +2497,42 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux) buffer = gst_fragment_get_buffer (download); g_object_unref (download); - ret = klass->update_manifest (demux, buffer); - if (ret == GST_FLOW_OK) { - GstClockTime duration; - gst_buffer_unref (demux->priv->manifest_buffer); - demux->priv->manifest_buffer = buffer; + ret = klass->update_manifest_data (demux, buffer); + gst_buffer_unref (buffer); + GST_MANIFEST_UNLOCK (demux); + /* FIXME: Should the manifest uri vars be reverted to original + * values if updating fails? */ + } else { + ret = GST_FLOW_NOT_LINKED; + } - /* Send an updated duration message */ - duration = klass->get_duration (demux); + return ret; +} - GST_MANIFEST_UNLOCK (demux); - if (duration != GST_CLOCK_TIME_NONE) { - GST_DEBUG_OBJECT (demux, - "Sending duration message : %" GST_TIME_FORMAT, - GST_TIME_ARGS (duration)); - gst_element_post_message (GST_ELEMENT (demux), - gst_message_new_duration_changed (GST_OBJECT (demux))); - } else { - GST_DEBUG_OBJECT (demux, - "Duration unknown, can not send the duration message"); - } +static GstFlowReturn +gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux) +{ + GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux); + GstFlowReturn ret; + + ret = klass->update_manifest (demux); + + if (ret == GST_FLOW_OK) { + GstClockTime duration; + GST_MANIFEST_LOCK (demux); + /* Send an updated duration message */ + duration = klass->get_duration (demux); + GST_MANIFEST_UNLOCK (demux); + if (duration != GST_CLOCK_TIME_NONE) { + GST_DEBUG_OBJECT (demux, + "Sending duration message : %" GST_TIME_FORMAT, + GST_TIME_ARGS (duration)); + gst_element_post_message (GST_ELEMENT (demux), + gst_message_new_duration_changed (GST_OBJECT (demux))); } else { - GST_MANIFEST_UNLOCK (demux); - gst_buffer_unref (buffer); - /* Should the manifest uri vars be reverted to original values? */ + GST_DEBUG_OBJECT (demux, + "Duration unknown, can not send the duration message"); } - } else { - ret = GST_FLOW_NOT_LINKED; } return ret; diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h index ca47418..9303a84 100644 --- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h +++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h @@ -237,9 +237,23 @@ struct _GstAdaptiveDemuxClass * Returns: the update interval in microseconds */ gint64 (*get_manifest_update_interval) (GstAdaptiveDemux * demux); + /** * update_manifest: * @demux: #GstAdaptiveDemux + * + * During live streaming, this will be called for the subclass to update its + * manifest with the new version. By default it fetches the manifest URI + * and passes it to GstAdaptiveDemux::update_manifest_data(). + * + * Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended + * or #GST_FLOW_ERROR if an error happened + */ + GstFlowReturn (*update_manifest) (GstAdaptiveDemux * demux); + + /** + * update_manifest_data: + * @demux: #GstAdaptiveDemux * @buf: Downloaded manifest data * * During live streaming, this will be called for the subclass to update its @@ -248,7 +262,7 @@ struct _GstAdaptiveDemuxClass * Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended * or #GST_FLOW_ERROR if an error happened */ - GstFlowReturn (*update_manifest) (GstAdaptiveDemux * demux, GstBuffer * buf); + GstFlowReturn (*update_manifest_data) (GstAdaptiveDemux * demux, GstBuffer * buf); gboolean (*is_live) (GstAdaptiveDemux * demux); GstClockTime (*get_duration) (GstAdaptiveDemux * demux); -- 2.7.4