From 1d28c574cf8971e08dbe650db1e5616af5fd6eb3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 8 Feb 2013 01:51:30 -0200 Subject: [PATCH] mssdemux: switch bitrates without switching pads --- ext/smoothstreaming/gstdownloadrate.c | 5 +- ext/smoothstreaming/gstmssdemux.c | 181 +++++++++----------------- ext/smoothstreaming/gstmssdemux.h | 2 + 3 files changed, 65 insertions(+), 123 deletions(-) diff --git a/ext/smoothstreaming/gstdownloadrate.c b/ext/smoothstreaming/gstdownloadrate.c index c7c676a99f..57e26f29da 100644 --- a/ext/smoothstreaming/gstdownloadrate.c +++ b/ext/smoothstreaming/gstdownloadrate.c @@ -102,7 +102,10 @@ gst_download_rate_get_current_rate (GstDownloadRate * rate) { guint ret; g_static_mutex_lock (&rate->mutex); - ret = rate->total / g_queue_get_length (&rate->queue); + if (g_queue_get_length (&rate->queue)) + ret = rate->total / g_queue_get_length (&rate->queue); + else + ret = G_MAXUINT; g_static_mutex_unlock (&rate->mutex); return ret; diff --git a/ext/smoothstreaming/gstmssdemux.c b/ext/smoothstreaming/gstmssdemux.c index 30aec642d7..8eaf2fba23 100644 --- a/ext/smoothstreaming/gstmssdemux.c +++ b/ext/smoothstreaming/gstmssdemux.c @@ -286,6 +286,7 @@ gst_mss_demux_stream_free (GstMssDemuxStream * stream) gst_object_unref (stream->pad); stream->pad = NULL; } + gst_caps_unref (stream->caps); g_free (stream); } @@ -789,6 +790,15 @@ gst_mss_demux_create_streams (GstMssDemux * mssdemux) GST_OBJECT_UNLOCK (mssdemux); } +static GstCaps * +create_mss_caps (GstMssDemuxStream * stream, GstCaps * caps) +{ + return gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, + "mss-fragmented", "timescale", G_TYPE_UINT64, + gst_mss_stream_get_timescale (stream->manifest_stream), "media-caps", + GST_TYPE_CAPS, caps, NULL); +} + static gboolean gst_mss_demux_expose_stream (GstMssDemux * mssdemux, GstMssDemuxStream * stream) { @@ -799,13 +809,10 @@ gst_mss_demux_expose_stream (GstMssDemux * mssdemux, GstMssDemuxStream * stream) media_caps = gst_mss_stream_get_caps (stream->manifest_stream); if (media_caps) { - caps = gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, - "mss-fragmented", "timescale", G_TYPE_UINT64, - gst_mss_stream_get_timescale (stream->manifest_stream), "media-caps", - GST_TYPE_CAPS, media_caps, NULL); + caps = create_mss_caps (stream, media_caps); gst_caps_unref (media_caps); gst_pad_set_caps (pad, caps); - gst_caps_unref (caps); + stream->caps = caps; gst_pad_set_active (pad, TRUE); GST_INFO_OBJECT (mssdemux, "Adding srcpad %s:%s with caps %" GST_PTR_FORMAT, @@ -952,120 +959,58 @@ gst_mss_demux_all_streams_have_data (GstMssDemux * mssdemux) return TRUE; } +static void +gst_mss_demux_reconfigure_stream (GstMssDemuxStream * stream) +{ + GstMssDemux *mssdemux = stream->parent; + guint64 new_bitrate; + + new_bitrate = + mssdemux->bitrate_limit * + gst_download_rate_get_current_rate (&stream->download_rate); + if (mssdemux->connection_speed) { + new_bitrate = MIN (mssdemux->connection_speed, new_bitrate); + } + + GST_DEBUG_OBJECT (mssdemux, "Current stream %s download bitrate %llu", + GST_PAD_NAME (stream->pad), new_bitrate); + + if (gst_mss_stream_select_bitrate (stream->manifest_stream, new_bitrate)) { + GstCaps *caps; + caps = gst_mss_stream_get_caps (stream->manifest_stream); + + if (stream->caps) + gst_caps_unref (stream->caps); + stream->caps = create_mss_caps (stream, caps); + gst_caps_unref (caps); + + GST_DEBUG_OBJECT (mssdemux, + "Stream %s changed bitrate to %llu caps: %" GST_PTR_FORMAT, + GST_PAD_NAME (stream->pad), + gst_mss_stream_get_current_bitrate (stream->manifest_stream), caps); + } +} + static void gst_mss_demux_reconfigure (GstMssDemux * mssdemux) { - GSList *oldpads = NULL; GSList *iter; - guint64 new_bitrate; - gboolean changed = FALSE; /* TODO lock? */ if (!gst_mss_demux_all_streams_have_data (mssdemux)) return; - gst_mss_demux_stop_tasks (mssdemux, TRUE); + //gst_mss_demux_stop_tasks (mssdemux, TRUE); for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) { GstMssDemuxStream *stream; stream = iter->data; - new_bitrate = - mssdemux->bitrate_limit * - gst_download_rate_get_current_rate (&stream->download_rate); - if (mssdemux->connection_speed) { - new_bitrate = MIN (mssdemux->connection_speed, new_bitrate); - } - - GST_DEBUG_OBJECT (mssdemux, "Current stream %s download bitrate %llu", - GST_PAD_NAME (stream->pad), new_bitrate); - - if (gst_mss_stream_select_bitrate (stream->manifest_stream, new_bitrate)) { - changed = TRUE; - GST_INFO_OBJECT (mssdemux, "Stream %s changed bitrate to %llu", - GST_PAD_NAME (stream->pad), - gst_mss_stream_get_current_bitrate (stream->manifest_stream)); - } + gst_mss_demux_reconfigure_stream (stream); } - if (changed) { - GstClockTime newseg_ts = GST_CLOCK_TIME_NONE; - - GST_DEBUG_OBJECT (mssdemux, - "Bitrates have changed, creating new pad group"); - /* if we changed the bitrate, we need to add new pads */ - for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) { - GstMssDemuxStream *stream = iter->data; - GstPad *oldpad = stream->pad; - GstClockTime ts = GST_CLOCK_TIME_NONE; - - if (oldpad) - oldpads = g_slist_prepend (oldpads, oldpad); - - /* since we are flushing the queue, get the next un-pushed timestamp to seek - * and avoid gaps */ - gst_data_queue_set_flushing (stream->dataqueue, FALSE); - if (!gst_data_queue_is_empty (stream->dataqueue)) { - GstDataQueueItem *item = NULL; - - while (!gst_data_queue_is_empty (stream->dataqueue) - && !GST_CLOCK_TIME_IS_VALID (ts)) { - gst_data_queue_pop (stream->dataqueue, &item); - - if (!item) { - g_assert_not_reached (); - break; - } - - if (GST_IS_BUFFER (item->object)) { - GstBuffer *buffer = GST_BUFFER_CAST (item->object); - - ts = GST_BUFFER_TIMESTAMP (buffer); - } - item->destroy (item); - } - - } - if (!GST_CLOCK_TIME_IS_VALID (ts)) { - ts = gst_mss_stream_get_fragment_gst_timestamp - (stream->manifest_stream); - } - - if (ts < newseg_ts) - newseg_ts = ts; - - GST_DEBUG_OBJECT (mssdemux, - "Seeking stream %p %s to ts %" GST_TIME_FORMAT, stream, - GST_PAD_NAME (stream->pad), GST_TIME_ARGS (ts)); - gst_mss_stream_seek (stream->manifest_stream, ts); - gst_data_queue_flush (stream->dataqueue); - - stream->pad = _create_pad (mssdemux, stream->manifest_stream); - gst_mss_demux_expose_stream (mssdemux, stream); - - stream->have_data = FALSE; - } - - gst_element_no_more_pads (GST_ELEMENT (mssdemux)); - - for (iter = oldpads; iter; iter = g_slist_next (iter)) { - GstPad *oldpad = iter->data; - - gst_pad_push_event (oldpad, gst_event_new_eos ()); - gst_pad_set_active (oldpad, FALSE); - gst_element_remove_pad (GST_ELEMENT (mssdemux), oldpad); - gst_object_unref (oldpad); - } - for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) { - GstMssDemuxStream *stream = iter->data; - - stream->pending_newsegment = - gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, newseg_ts, -1, - newseg_ts); - } - } - gst_mss_demux_restart_tasks (mssdemux); + //gst_mss_demux_restart_tasks (mssdemux); } static void @@ -1154,7 +1099,7 @@ gst_mss_demux_stream_download_fragment (GstMssDemuxStream * stream, _buffer = gst_fragment_get_buffer (fragment); _buffer = gst_buffer_make_metadata_writable (_buffer); - gst_buffer_set_caps (_buffer, GST_PAD_CAPS (stream->pad)); + gst_buffer_set_caps (_buffer, stream->caps); GST_BUFFER_TIMESTAMP (_buffer) = gst_mss_stream_get_fragment_gst_timestamp (stream->manifest_stream); GST_BUFFER_DURATION (_buffer) = @@ -1184,11 +1129,6 @@ gst_mss_demux_stream_download_fragment (GstMssDemuxStream * stream, gst_mss_demux_stream_store_object (stream, GST_MINI_OBJECT_CAST (_buffer)); } - - GST_OBJECT_LOCK (mssdemux); - mssdemux->update_bitrates = TRUE; - GST_OBJECT_UNLOCK (mssdemux); - return ret; no_url_error: @@ -1216,6 +1156,14 @@ gst_mss_demux_download_loop (GstMssDemuxStream * stream) GST_LOG_OBJECT (mssdemux, "download loop start %p", stream); + GST_OBJECT_LOCK (mssdemux); + + GST_DEBUG_OBJECT (mssdemux, + "Starting streams reconfiguration due to bitrate changes"); + gst_mss_demux_reconfigure_stream (stream); + GST_DEBUG_OBJECT (mssdemux, "Finished streams reconfiguration"); + GST_OBJECT_UNLOCK (mssdemux); + ret = gst_mss_demux_stream_download_fragment (stream, &buffer); switch (ret) { case GST_FLOW_OK: @@ -1312,18 +1260,6 @@ gst_mss_demux_stream_loop (GstMssDemux * mssdemux) GST_LOG_OBJECT (mssdemux, "Starting stream loop"); - GST_OBJECT_LOCK (mssdemux); - if (mssdemux->update_bitrates) { - mssdemux->update_bitrates = FALSE; - GST_OBJECT_UNLOCK (mssdemux); - - GST_DEBUG_OBJECT (mssdemux, - "Starting streams reconfiguration due to bitrate changes"); - gst_mss_demux_reconfigure (mssdemux); - GST_DEBUG_OBJECT (mssdemux, "Finished streams reconfiguration"); - } else { - GST_OBJECT_UNLOCK (mssdemux); - } ret = gst_mss_demux_select_latest_stream (mssdemux, &stream); @@ -1369,7 +1305,7 @@ gst_mss_demux_stream_loop (GstMssDemux * mssdemux) if (G_LIKELY (GST_IS_BUFFER (object))) { if (GST_BUFFER_TIMESTAMP (object) != stream->next_timestamp) { - GST_ERROR_OBJECT (mssdemux, "Marking buffer %p as discont buffer:%" + GST_DEBUG_OBJECT (mssdemux, "Marking buffer %p as discont buffer:%" GST_TIME_FORMAT " != expected:%" GST_TIME_FORMAT, object, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (object)), GST_TIME_ARGS (stream->next_timestamp)); @@ -1390,8 +1326,9 @@ gst_mss_demux_stream_loop (GstMssDemux * mssdemux) stream->have_data = TRUE; ret = gst_pad_push (stream->pad, GST_BUFFER_CAST (object)); } else if (GST_IS_EVENT (object)) { - if (GST_EVENT_TYPE (object) == GST_EVENT_EOS) + if (GST_EVENT_TYPE (object) == GST_EVENT_EOS) { stream->eos = TRUE; + } GST_DEBUG_OBJECT (mssdemux, "Pushing event %p on pad %s", object, GST_PAD_NAME (stream->pad)); gst_pad_push_event (stream->pad, GST_EVENT_CAST (object)); diff --git a/ext/smoothstreaming/gstmssdemux.h b/ext/smoothstreaming/gstmssdemux.h index 5e4f18502c..0b8eec8045 100644 --- a/ext/smoothstreaming/gstmssdemux.h +++ b/ext/smoothstreaming/gstmssdemux.h @@ -55,6 +55,8 @@ typedef struct _GstMssDemuxClass GstMssDemuxClass; struct _GstMssDemuxStream { GstPad *pad; + GstCaps *caps; + GstMssDemux *parent; GstMssStream *manifest_stream;