mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
mssdemux: add connection-speed property
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.
This commit is contained in:
parent
4b6900999a
commit
b9aec0ad0d
4 changed files with 159 additions and 2 deletions
|
@ -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
|
||||
|
|
|
@ -81,6 +81,8 @@ struct _GstMssDemux {
|
|||
guint n_videos;
|
||||
guint n_audios;
|
||||
|
||||
/* properties */
|
||||
guint64 connection_speed; /* in bps */
|
||||
};
|
||||
|
||||
struct _GstMssDemuxClass {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue