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 22bfdc7aca7acf5f93c00f9176de10b3f6f2ec3c..cb6cde3e23418a46a1f27b9d881a23197cf86677 100644 (file)
 
 GST_DEBUG_CATEGORY (mssdemux_debug);
 
 
 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,
 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);
 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);
 
 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;
   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);
 
   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);
 }
 
   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)
 {
 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);
   }
     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
 }
 
 static gboolean
index 9dee169e880c0b988b971b7e54d01350905297af..54d87f9f94a238d29bd20dad2b994878cfc35595 100644 (file)
@@ -81,6 +81,8 @@ struct _GstMssDemux {
   guint n_videos;
   guint n_audios;
 
   guint n_videos;
   guint n_audios;
 
+  /* properties */
+  guint64 connection_speed; /* in bps */
 };
 
 struct _GstMssDemuxClass {
 };
 
 struct _GstMssDemuxClass {
index 71fd576a26cec984fdbc5d8d6ddd013ea7ed5416..0659164564f74a6928e07586a2d9a9610b5e806d 100644 (file)
@@ -754,3 +754,98 @@ gst_mss_stream_seek (GstMssStream * stream, guint64 time)
 
   return TRUE;
 }
 
   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 6abb4e9facb453dd33e447f1703ff8a2537f2053..796130a74658a22e78b710bb8b09d780af6cd4c8 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);
 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);
 
 GstMssStreamType gst_mss_stream_get_type (GstMssStream *stream);
 GstCaps * gst_mss_stream_get_caps (GstMssStream * stream);