adaptivedemux: Allow subclasses to override how a new manifest would be downloaded

This commit is contained in:
Sebastian Dröge 2015-04-23 17:22:11 +02:00
parent c1f98daa74
commit 0cd3938345
6 changed files with 82 additions and 48 deletions

View file

@ -214,7 +214,7 @@ static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
static gint64 static gint64
gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux); gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
static GstFlowReturn static GstFlowReturn
gst_dash_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buf); gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux, GstBuffer * buf);
static gint64 static gint64
gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream * gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
stream); stream);
@ -354,7 +354,8 @@ gst_dash_demux_class_init (GstDashDemuxClass * klass)
gstadaptivedemux_class->seek = gst_dash_demux_seek; gstadaptivedemux_class->seek = gst_dash_demux_seek;
gstadaptivedemux_class->process_manifest = gst_dash_demux_process_manifest; 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 = gstadaptivedemux_class->get_manifest_update_interval =
gst_dash_demux_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 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); GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
GstMpdClient *new_client = NULL; GstMpdClient *new_client = NULL;

View file

@ -100,8 +100,8 @@ static gint64 gst_hls_demux_get_manifest_update_interval (GstAdaptiveDemux *
demux); demux);
static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, static gboolean gst_hls_demux_process_manifest (GstAdaptiveDemux * demux,
GstBuffer * buf); GstBuffer * buf);
static GstFlowReturn gst_hls_demux_update_manifest (GstAdaptiveDemux * demux, static GstFlowReturn gst_hls_demux_update_manifest_data (GstAdaptiveDemux *
GstBuffer * buf); demux, GstBuffer * buf);
static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek); static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
static gboolean static gboolean
gst_hls_demux_start_fragment (GstAdaptiveDemux * demux, gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
@ -186,7 +186,8 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass)
adaptivedemux_class->get_manifest_update_interval = adaptivedemux_class->get_manifest_update_interval =
gst_hls_demux_get_manifest_update_interval; gst_hls_demux_get_manifest_update_interval;
adaptivedemux_class->process_manifest = gst_hls_demux_process_manifest; 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->reset = gst_hls_demux_reset;
adaptivedemux_class->seek = gst_hls_demux_seek; adaptivedemux_class->seek = gst_hls_demux_seek;
adaptivedemux_class->stream_has_next_fragment = adaptivedemux_class->stream_has_next_fragment =
@ -400,7 +401,7 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
} }
static GstFlowReturn 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); GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
if (!gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL)) if (!gst_hls_demux_update_playlist (hlsdemux, TRUE, NULL))

View file

@ -135,7 +135,8 @@ static gboolean gst_mss_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
static gint64 static gint64
gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux); gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
static GstFlowReturn static GstFlowReturn
gst_mss_demux_update_manifest (GstAdaptiveDemux * demux, GstBuffer * buffer); gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
GstBuffer * buffer);
static void static void
gst_mss_demux_class_init (GstMssDemuxClass * klass) gst_mss_demux_class_init (GstMssDemuxClass * klass)
@ -188,7 +189,8 @@ gst_mss_demux_class_init (GstMssDemuxClass * klass)
gst_mss_demux_stream_select_bitrate; gst_mss_demux_stream_select_bitrate;
gstadaptivedemux_class->stream_update_fragment_info = gstadaptivedemux_class->stream_update_fragment_info =
gst_mss_demux_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"); 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 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); GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);

View file

@ -724,7 +724,8 @@ _gst_mss_stream_audio_caps_from_qualitylevel_xml (GstMssStreamQuality * q)
gst_structure_set (structure, "rate", G_TYPE_INT, rate, NULL); gst_structure_set (structure, "rate", G_TYPE_INT, rate, NULL);
if (q->bitrate) 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) if (codec_data)
gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, codec_data, gst_structure_set (structure, "codec_data", GST_TYPE_BUFFER, codec_data,

View file

@ -106,7 +106,7 @@ enum GstAdaptiveDemuxFlowReturn
struct _GstAdaptiveDemuxPrivate struct _GstAdaptiveDemuxPrivate
{ {
GstAdapter *input_adapter; GstAdapter *input_adapter;
GstBuffer *manifest_buffer; gboolean have_manifest;
GstUriDownloader *downloader; GstUriDownloader *downloader;
@ -167,6 +167,8 @@ gst_adaptive_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream); GstAdaptiveDemuxStream * stream);
static GstFlowReturn gst_adaptive_demux_update_manifest (GstAdaptiveDemux * static GstFlowReturn gst_adaptive_demux_update_manifest (GstAdaptiveDemux *
demux); demux);
static GstFlowReturn
gst_adaptive_demux_update_manifest_default (GstAdaptiveDemux * demux);
static gboolean gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux); static gboolean gst_adaptive_demux_has_next_period (GstAdaptiveDemux * demux);
static void gst_adaptive_demux_advance_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->data_received = gst_adaptive_demux_stream_data_received_default;
klass->finish_fragment = gst_adaptive_demux_stream_finish_fragment_default; klass->finish_fragment = gst_adaptive_demux_stream_finish_fragment_default;
klass->update_manifest = gst_adaptive_demux_update_manifest_default;
} }
static void static void
@ -419,6 +422,7 @@ gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent,
gboolean query_res; gboolean query_res;
gboolean ret = TRUE; gboolean ret = TRUE;
gsize available; gsize available;
GstBuffer *manifest_buffer;
demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux); demux_class = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
available = gst_adapter_available (demux->priv->input_adapter); 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); gst_query_unref (query);
/* Let the subclass parse the manifest */ /* Let the subclass parse the manifest */
demux->priv->manifest_buffer = manifest_buffer =
gst_adapter_take_buffer (demux->priv->input_adapter, available); 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 /* 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 * source element and we have received the 404 HTML response instead of
* the manifest */ * the manifest */
GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid manifest."), GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid manifest."),
(NULL)); (NULL));
ret = FALSE; ret = FALSE;
} else {
demux->priv->have_manifest = TRUE;
} }
gst_buffer_unref (manifest_buffer);
gst_element_post_message (GST_ELEMENT_CAST (demux), gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_element (GST_OBJECT_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; demux->manifest_base_uri = NULL;
gst_adapter_clear (demux->priv->input_adapter); gst_adapter_clear (demux->priv->input_adapter);
if (demux->priv->manifest_buffer) { demux->priv->have_manifest = FALSE;
gst_buffer_unref (demux->priv->manifest_buffer);
demux->priv->manifest_buffer = NULL;
}
gst_segment_init (&demux->segment, GST_FORMAT_TIME); 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_MANIFEST_LOCK (demux);
gst_query_parse_duration (query, &fmt, NULL); 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); duration = demux_class->get_duration (demux);
if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) { 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; gboolean live = FALSE;
GST_MANIFEST_LOCK (demux); 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_MANIFEST_UNLOCK (demux);
gst_query_set_latency (query, live, 0, -1); gst_query_set_latency (query, live, 0, -1);
@ -1131,7 +1135,7 @@ gst_adaptive_demux_src_query (GstPad * pad, GstObject * parent,
gint64 start = 0; gint64 start = 0;
GST_MANIFEST_LOCK (demux); GST_MANIFEST_LOCK (demux);
if (demux->priv->manifest_buffer == NULL) { if (demux->priv->have_manifest) {
GST_MANIFEST_UNLOCK (demux); GST_MANIFEST_UNLOCK (demux);
return FALSE; /* can't answer without manifest */ return FALSE; /* can't answer without manifest */
} }
@ -2470,7 +2474,7 @@ gst_adaptive_demux_stream_get_fragment_waiting_time (GstAdaptiveDemux *
} }
static GstFlowReturn 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); GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
GstFragment *download; GstFragment *download;
@ -2493,31 +2497,11 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
buffer = gst_fragment_get_buffer (download); buffer = gst_fragment_get_buffer (download);
g_object_unref (download); g_object_unref (download);
ret = klass->update_manifest (demux, buffer); ret = klass->update_manifest_data (demux, buffer);
if (ret == GST_FLOW_OK) { gst_buffer_unref (buffer);
GstClockTime duration; GST_MANIFEST_UNLOCK (demux);
gst_buffer_unref (demux->priv->manifest_buffer); /* FIXME: Should the manifest uri vars be reverted to original
demux->priv->manifest_buffer = buffer; * values if updating fails? */
/* 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_DEBUG_OBJECT (demux,
"Duration unknown, can not send the duration message");
}
} else {
GST_MANIFEST_UNLOCK (demux);
gst_buffer_unref (buffer);
/* Should the manifest uri vars be reverted to original values? */
}
} else { } else {
ret = GST_FLOW_NOT_LINKED; ret = GST_FLOW_NOT_LINKED;
} }
@ -2525,6 +2509,35 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
return ret; return ret;
} }
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_DEBUG_OBJECT (demux,
"Duration unknown, can not send the duration message");
}
}
return ret;
}
void void
gst_adaptive_demux_stream_fragment_clear (GstAdaptiveDemuxStreamFragment * f) gst_adaptive_demux_stream_fragment_clear (GstAdaptiveDemuxStreamFragment * f)
{ {

View file

@ -237,9 +237,23 @@ struct _GstAdaptiveDemuxClass
* Returns: the update interval in microseconds * Returns: the update interval in microseconds
*/ */
gint64 (*get_manifest_update_interval) (GstAdaptiveDemux * demux); gint64 (*get_manifest_update_interval) (GstAdaptiveDemux * demux);
/** /**
* update_manifest: * update_manifest:
* @demux: #GstAdaptiveDemux * @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 * @buf: Downloaded manifest data
* *
* During live streaming, this will be called for the subclass to update its * 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 * Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended
* or #GST_FLOW_ERROR if an error happened * 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); gboolean (*is_live) (GstAdaptiveDemux * demux);
GstClockTime (*get_duration) (GstAdaptiveDemux * demux); GstClockTime (*get_duration) (GstAdaptiveDemux * demux);