diff --git a/ext/smoothstreaming/gstmssdemux.c b/ext/smoothstreaming/gstmssdemux.c index 22bfdc7aca..cb6cde3e23 100644 --- a/ext/smoothstreaming/gstmssdemux.c +++ b/ext/smoothstreaming/gstmssdemux.c @@ -42,6 +42,16 @@ 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 diff --git a/ext/smoothstreaming/gstmssdemux.h b/ext/smoothstreaming/gstmssdemux.h index 9dee169e88..54d87f9f94 100644 --- a/ext/smoothstreaming/gstmssdemux.h +++ b/ext/smoothstreaming/gstmssdemux.h @@ -81,6 +81,8 @@ struct _GstMssDemux { guint n_videos; guint n_audios; + /* properties */ + guint64 connection_speed; /* in bps */ }; struct _GstMssDemuxClass { diff --git a/ext/smoothstreaming/gstmssmanifest.c b/ext/smoothstreaming/gstmssmanifest.c index 71fd576a26..0659164564 100644 --- a/ext/smoothstreaming/gstmssmanifest.c +++ b/ext/smoothstreaming/gstmssmanifest.c @@ -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; +} diff --git a/ext/smoothstreaming/gstmssmanifest.h b/ext/smoothstreaming/gstmssmanifest.h index 6abb4e9fac..796130a746 100644 --- a/ext/smoothstreaming/gstmssmanifest.h +++ b/ext/smoothstreaming/gstmssmanifest.h @@ -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);