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
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;

View file

@ -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))

View file

@ -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);

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);
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,

View file

@ -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,31 +2497,11 @@ 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;
/* 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? */
}
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;
}
@ -2525,6 +2509,35 @@ gst_adaptive_demux_update_manifest (GstAdaptiveDemux * demux)
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
gst_adaptive_demux_stream_fragment_clear (GstAdaptiveDemuxStreamFragment * f)
{

View file

@ -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);