mssdemux: add connection-speed property
authorThiago Santos <thiago.sousa.santos@collabora.com>
Tue, 8 Jan 2013 21:01:17 +0000 (18:01 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 8 May 2013 00:05:11 +0000 (21:05 -0300)
This speed limits the maximum bitrate of streams. Currently it
is only read when starting the pipeline, but it should be used
for switching bitrates during playback to adapt to network
changes.

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

index 22bfdc7..cb6cde3 100644 (file)
 
 GST_DEBUG_CATEGORY (mssdemux_debug);
 
+#define DEFAULT_CONNECTION_SPEED 0
+
+enum
+{
+  PROP_0,
+
+  PROP_CONNECTION_SPEED,
+  PROP_LAST
+};
+
 static GstStaticPadTemplate gst_mss_demux_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
@@ -64,8 +74,12 @@ GST_STATIC_PAD_TEMPLATE ("audio_%02u",
 GST_BOILERPLATE (GstMssDemux, gst_mss_demux, GstMssDemux, GST_TYPE_ELEMENT);
 
 static void gst_mss_demux_dispose (GObject * object);
-static GstStateChangeReturn
-gst_mss_demux_change_state (GstElement * element, GstStateChange transition);
+static void gst_mss_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_mss_demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+static GstStateChangeReturn gst_mss_demux_change_state (GstElement * element,
+    GstStateChange transition);
 static GstFlowReturn gst_mss_demux_chain (GstPad * pad, GstBuffer * buffer);
 static GstFlowReturn gst_mss_demux_event (GstPad * pad, GstEvent * event);
 
@@ -106,6 +120,14 @@ gst_mss_demux_class_init (GstMssDemuxClass * klass)
   parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->dispose = gst_mss_demux_dispose;
+  gobject_class->set_property = gst_mss_demux_set_property;
+  gobject_class->get_property = gst_mss_demux_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_CONNECTION_SPEED,
+      g_param_spec_uint64 ("connection-speed", "Connection Speed",
+          "Network connection speed in kbps (0 = unknown)",
+          0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_mss_demux_change_state);
@@ -216,6 +238,38 @@ gst_mss_demux_dispose (GObject * object)
   G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
+static void
+gst_mss_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstMssDemux *mssdemux = GST_MSS_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_CONNECTION_SPEED:
+      mssdemux->connection_speed = g_value_get_uint (value) * 1000;
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_mss_demux_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstMssDemux *mssdemux = GST_MSS_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_CONNECTION_SPEED:
+      g_value_set_uint (value, mssdemux->connection_speed / 1000);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
 static GstStateChangeReturn
 gst_mss_demux_change_state (GstElement * element, GstStateChange transition)
 {
@@ -532,6 +586,10 @@ gst_mss_demux_create_streams (GstMssDemux * mssdemux)
     gst_mss_stream_set_active (manifeststream, TRUE);
     mssdemux->streams = g_slist_append (mssdemux->streams, stream);
   }
+
+  /* select initial bitrates */
+  gst_mss_manifest_change_bitrate (mssdemux->manifest,
+      mssdemux->connection_speed);
 }
 
 static gboolean
index 9dee169..54d87f9 100644 (file)
@@ -81,6 +81,8 @@ struct _GstMssDemux {
   guint n_videos;
   guint n_audios;
 
+  /* properties */
+  guint64 connection_speed; /* in bps */
 };
 
 struct _GstMssDemuxClass {
index 71fd576..0659164 100644 (file)
@@ -754,3 +754,98 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
 
   return TRUE;
 }
+
+guint64
+gst_mss_manifest_get_current_bitrate (GstMssManifest * manifest)
+{
+  guint64 bitrate = 0;
+  GSList *iter;
+
+  for (iter = gst_mss_manifest_get_streams (manifest); iter;
+      iter = g_slist_next (iter)) {
+    GstMssStream *stream = iter->data;
+    if (stream->active && stream->current_quality) {
+      GstMssStreamQuality *q = stream->current_quality->data;
+
+      bitrate += q->bitrate;
+    }
+  }
+
+  return bitrate;
+}
+
+static gboolean
+gst_mss_stream_select_bitrate (GstMssStream * stream, guint64 bitrate)
+{
+  GList *iter = stream->current_quality;
+  GList *next;
+  GstMssStreamQuality *q = iter->data;
+
+  while (q->bitrate > bitrate) {
+    next = g_list_previous (iter);
+    if (next) {
+      iter = next;
+      q = iter->data;
+    } else {
+      break;
+    }
+  }
+
+  while (q->bitrate < bitrate) {
+    GstMssStreamQuality *next_q;
+    next = g_list_next (iter);
+    if (next) {
+      next_q = next->data;
+      if (next_q->bitrate < bitrate) {
+        iter = next;
+        q = iter->data;
+      } else {
+        break;
+      }
+    } else {
+      break;
+    }
+  }
+
+  if (iter == stream->current_quality)
+    return FALSE;
+  stream->current_quality = iter;
+  return TRUE;
+}
+
+/**
+ * gst_mss_manifest_change_bitrate:
+ * @manifest: the manifest
+ * @bitrate: the maximum bitrate to use (bps)
+ *
+ * Iterates over the active streams and changes their bitrates to the maximum
+ * value so that the bitrates of all streams are not larger than
+ * @bitrate.
+ *
+ * Return: %TRUE if any stream changed its bitrate
+ */
+gboolean
+gst_mss_manifest_change_bitrate (GstMssManifest * manifest, guint64 bitrate)
+{
+  gboolean ret = FALSE;
+  GSList *iter;
+
+  /* TODO This algorithm currently sets the same bitrate for all streams,
+   * it should actually use the sum of all streams bitrates to compare to
+   * the target value */
+
+  if (bitrate == 0) {
+    /* use maximum */
+    bitrate = G_MAXUINT64;
+  }
+
+  for (iter = gst_mss_manifest_get_streams (manifest); iter;
+      iter = g_slist_next (iter)) {
+    GstMssStream *stream = iter->data;
+    if (stream->active) {
+      ret = ret | gst_mss_stream_select_bitrate (stream, bitrate);
+    }
+  }
+
+  return ret;
+}
index 6abb4e9..796130a 100644 (file)
@@ -45,6 +45,8 @@ guint64 gst_mss_manifest_get_timescale (GstMssManifest * manifest);
 guint64 gst_mss_manifest_get_duration (GstMssManifest * manifest);
 GstClockTime gst_mss_manifest_get_gst_duration (GstMssManifest * manifest);
 gboolean gst_mss_manifest_seek (GstMssManifest * manifest, guint64 time);
+gboolean gst_mss_manifest_change_bitrate (GstMssManifest *manifest, guint64 bitrate);
+guint64 gst_mss_manifest_get_current_bitrate (GstMssManifest * manifest);
 
 GstMssStreamType gst_mss_stream_get_type (GstMssStream *stream);
 GstCaps * gst_mss_stream_get_caps (GstMssStream * stream);