mssdemux: add bitrate-limit property
authorThiago Santos <thiago.sousa.santos@collabora.com>
Tue, 5 Feb 2013 03:28:19 +0000 (00:28 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 8 May 2013 00:09:48 +0000 (21:09 -0300)
It allows the plugin to use its own downloading bitrate measures
as a feedback to select the best streams bitrate for the current
network scenario

ext/smoothstreaming/gstmssdemux.c
ext/smoothstreaming/gstmssdemux.h

index c2e048f..cb98401 100644 (file)
@@ -81,6 +81,7 @@ GST_DEBUG_CATEGORY (mssdemux_debug);
 
 #define DEFAULT_CONNECTION_SPEED 0
 #define DEFAULT_MAX_QUEUE_SIZE_BUFFERS 0
+#define DEFAULT_BITRATE_LIMIT 0.8
 
 enum
 {
@@ -88,6 +89,7 @@ enum
 
   PROP_CONNECTION_SPEED,
   PROP_MAX_QUEUE_SIZE_BUFFERS,
+  PROP_BITRATE_LIMIT,
   PROP_LAST
 };
 
@@ -173,6 +175,13 @@ gst_mss_demux_class_init (GstMssDemuxClass * klass)
           "(0 = infinite)", 0, G_MAXUINT, DEFAULT_MAX_QUEUE_SIZE_BUFFERS,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_BITRATE_LIMIT,
+      g_param_spec_float ("bitrate-limit",
+          "Bitrate limit in %",
+          "Limit of the available bitrate to use when switching to alternates.",
+          0, 1, DEFAULT_BITRATE_LIMIT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_mss_demux_change_state);
 }
@@ -194,6 +203,7 @@ gst_mss_demux_init (GstMssDemux * mssdemux, GstMssDemuxClass * klass)
   gst_task_set_lock (mssdemux->stream_task, &mssdemux->stream_lock);
 
   mssdemux->data_queue_max_size = DEFAULT_MAX_QUEUE_SIZE_BUFFERS;
+  mssdemux->bitrate_limit = DEFAULT_BITRATE_LIMIT;
 }
 
 static gboolean
@@ -351,6 +361,9 @@ gst_mss_demux_set_property (GObject * object, guint prop_id,
     case PROP_MAX_QUEUE_SIZE_BUFFERS:
       mssdemux->data_queue_max_size = g_value_get_uint (value);
       break;
+    case PROP_BITRATE_LIMIT:
+      mssdemux->bitrate_limit = g_value_get_float (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -370,6 +383,9 @@ gst_mss_demux_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_MAX_QUEUE_SIZE_BUFFERS:
       g_value_set_uint (value, mssdemux->data_queue_max_size);
       break;
+    case PROP_BITRATE_LIMIT:
+      g_value_set_float (value, mssdemux->bitrate_limit);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -894,17 +910,63 @@ gst_mss_demux_reload_manifest (GstMssDemux * mssdemux)
   g_object_unref (downloader);
 }
 
+static guint64
+gst_mss_demux_get_download_bitrate (GstMssDemux * mssdemux)
+{
+  GSList *iter;
+  guint64 total = 0;
+  guint64 count = 0;
+
+  for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) {
+    GstMssDemuxStream *stream = iter->data;
+
+    total += stream->download_bitrate;
+    count++;
+  }
+
+  return total / count;
+}
+
+static gboolean
+gst_mss_demux_all_streams_have_data (GstMssDemux * mssdemux)
+{
+  GSList *iter;
+
+  for (iter = mssdemux->streams; iter; iter = g_slist_next (iter)) {
+    GstMssDemuxStream *stream = iter->data;
+
+    if (!stream->have_data)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
 static void
 gst_mss_demux_reconfigure (GstMssDemux * mssdemux)
 {
   GSList *oldpads = NULL;
   GSList *iter;
+  guint64 new_bitrate;
+
+  /* TODO lock? */
+
+  if (!gst_mss_demux_all_streams_have_data (mssdemux))
+    return;
+
+  new_bitrate = 0.8 * gst_mss_demux_get_download_bitrate (mssdemux) / 1000;
+  if (mssdemux->connection_speed) {
+    new_bitrate = MIN (mssdemux->connection_speed, new_bitrate);
+  }
+
+  GST_DEBUG_OBJECT ("Current suggested bitrate: %llu", new_bitrate);
 
   gst_mss_demux_stop_tasks (mssdemux, TRUE);
-  if (gst_mss_manifest_change_bitrate (mssdemux->manifest,
-          mssdemux->connection_speed)) {
+  if (gst_mss_manifest_change_bitrate (mssdemux->manifest, new_bitrate)) {
     GstClockTime newseg_ts = GST_CLOCK_TIME_NONE;
 
+    GST_INFO_OBJECT ("Switching to bitrate %llu", new_bitrate);
+
     GST_DEBUG_OBJECT (mssdemux, "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)) {
@@ -956,6 +1018,7 @@ gst_mss_demux_reconfigure (GstMssDemux * mssdemux)
       gst_mss_demux_expose_stream (mssdemux, stream);
 
       gst_pad_push_event (oldpad, gst_event_new_eos ());
+      stream->have_data = FALSE;
     }
 
     gst_element_no_more_pads (GST_ELEMENT (mssdemux));
@@ -1018,6 +1081,9 @@ gst_mss_demux_stream_download_fragment (GstMssDemuxStream * stream,
   GstFragment *fragment;
   GstBuffer *_buffer;
   GstFlowReturn ret = GST_FLOW_OK;
+  guint64 before_download, after_download;
+
+  before_download = g_get_real_time ();
 
   GST_DEBUG_OBJECT (mssdemux, "Getting url for stream %p", stream);
   ret = gst_mss_stream_get_fragment_url (stream->manifest_stream, &path);
@@ -1072,7 +1138,15 @@ gst_mss_demux_stream_download_fragment (GstMssDemuxStream * stream,
   if (buffer)
     *buffer = _buffer;
 
+  after_download = g_get_real_time ();
   if (_buffer) {
+    guint64 bitrate = 8 * GST_BUFFER_SIZE (_buffer) /
+        ((after_download - before_download) / 1000000ULL);
+
+    GST_DEBUG_OBJECT (mssdemux, "Measured download bitrate: %s %llu bps",
+        GST_PAD_NAME (stream->pad), bitrate);
+    stream->download_bitrate = bitrate;
+
     GST_DEBUG_OBJECT (mssdemux,
         "Storing buffer for stream %p - %s. Timestamp: %" GST_TIME_FORMAT
         " Duration: %" GST_TIME_FORMAT,
@@ -1082,6 +1156,11 @@ 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:
@@ -1109,7 +1188,6 @@ gst_mss_demux_download_loop (GstMssDemuxStream * stream)
 
   GST_LOG_OBJECT (mssdemux, "download loop start %p", stream);
 
-
   ret = gst_mss_demux_stream_download_fragment (stream, &buffer);
   switch (ret) {
     case GST_FLOW_OK:
@@ -1167,8 +1245,7 @@ gst_mss_demux_select_latest_stream (GstMssDemux * mssdemux,
       continue;
     }
 
-    if (gst_data_queue_peek (other->dataqueue, &item)) {
-    } else {
+    if (!gst_data_queue_peek (other->dataqueue, &item)) {
       /* flushing */
       return GST_FLOW_WRONG_STATE;
     }
@@ -1276,6 +1353,7 @@ gst_mss_demux_stream_loop (GstMssDemux * mssdemux)
     stream->next_timestamp =
         GST_BUFFER_TIMESTAMP (object) + GST_BUFFER_DURATION (object);
 
+    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)
index cd7f16e..ddd9a3b 100644 (file)
@@ -70,6 +70,9 @@ struct _GstMssDemuxStream {
   GStaticRecMutex download_lock;
 
   gboolean eos;
+  gboolean have_data;
+
+  guint64 download_bitrate;
 };
 
 struct _GstMssDemux {
@@ -97,6 +100,7 @@ struct _GstMssDemux {
   /* properties */
   guint64 connection_speed; /* in bps */
   guint data_queue_max_size;
+  gfloat bitrate_limit;
 };
 
 struct _GstMssDemuxClass {