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,
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);
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);
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)
{
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
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;
+}