Merge pull request #506 from Rafostar/adaptive

Add adaptive streaming bitrate control to Clapper API
This commit is contained in:
Rafał Dzięgiel
2024-11-16 16:15:19 +01:00
committed by GitHub
9 changed files with 500 additions and 11 deletions

View File

@@ -9,7 +9,7 @@ project('clapper', 'c',
)
glib_req = '>= 2.76.0'
gst_req = '>= 1.20.0'
gst_req = '>= 1.24.0'
gtk4_req = '>= 4.10.0'
adw_req = '>= 1.4.0'

View File

@@ -1,11 +1,11 @@
{
"app-id": "com.github.rafostar.Clapper",
"runtime": "org.gnome.Platform",
"runtime-version": "45",
"runtime-version": "47",
"sdk": "org.gnome.Sdk",
"add-extensions": {
"org.freedesktop.Platform.ffmpeg-full": {
"version": "23.08",
"version": "24.08",
"directory": "lib/ffmpeg",
"add-ld-path": ".",
"no-autodownload": false,
@@ -40,15 +40,12 @@
"flathub/lib/libass.json",
"flathub/lib/uchardet.json",
"flathub/lib/libmicrodns.json",
"flathub/gstreamer-1.0/gstreamer.json",
"testing/gstreamer_stable.json",
"testing/yt-dlp.json",
"testing/libpeas.json",
{
"name": "clapper",
"buildsystem": "meson",
"config-opts": [
"-Dc_args=\"-DHAVE_GST_PATCHES=1\""
],
"sources": [
{
"type": "dir",

View File

@@ -0,0 +1,99 @@
{
"name": "gstreamer",
"buildsystem": "meson",
"config-opts": [
"--buildtype=release",
"--wrap-mode=nodownload",
"-Dbase=enabled",
"-Dgood=enabled",
"-Dbad=enabled",
"-Dugly=enabled",
"-Dlibav=enabled",
"-Dvaapi=enabled",
"-Dsharp=disabled",
"-Drs=disabled",
"-Dpython=disabled",
"-Ddevtools=disabled",
"-Dges=disabled",
"-Drtsp_server=disabled",
"-Dgst-examples=disabled",
"-Dqt5=disabled",
"-Dtests=disabled",
"-Dexamples=disabled",
"-Dintrospection=enabled",
"-Ddoc=disabled",
"-Dgtk_doc=disabled",
"-Dgpl=enabled",
"-Dgstreamer:benchmarks=disabled",
"-Dgstreamer:gobject-cast-checks=disabled",
"-Dgstreamer:glib-asserts=disabled",
"-Dgstreamer:glib-checks=disabled",
"-Dgstreamer:extra-checks=disabled",
"-Dgst-plugins-base:gobject-cast-checks=disabled",
"-Dgst-plugins-base:glib-asserts=disabled",
"-Dgst-plugins-base:glib-checks=disabled",
"-Dgst-plugins-base:gl_api=opengl,gles2",
"-Dgst-plugins-base:gl_platform=egl,glx",
"-Dgst-plugins-good:gobject-cast-checks=disabled",
"-Dgst-plugins-good:glib-asserts=disabled",
"-Dgst-plugins-good:glib-checks=disabled",
"-Dgst-plugins-good:gtk3=disabled",
"-Dgst-plugins-bad:gobject-cast-checks=disabled",
"-Dgst-plugins-bad:glib-asserts=disabled",
"-Dgst-plugins-bad:glib-checks=disabled",
"-Dgst-plugins-bad:extra-checks=disabled",
"-Dgst-plugins-bad:vulkan=disabled",
"-Dgst-plugins-bad:webrtc=disabled",
"-Dgst-plugins-bad:wasapi=disabled",
"-Dgst-plugins-bad:wasapi2=disabled",
"-Dgst-plugins-bad:winks=disabled",
"-Dgst-plugins-bad:winscreencap=disabled",
"-Dgst-plugins-bad:assrender=enabled",
"-Dgst-plugins-bad:nvcodec=enabled",
"-Dgst-plugins-bad:v4l2codecs=enabled",
"-Dgst-plugins-bad:va=enabled",
"-Dgst-plugins-ugly:gobject-cast-checks=disabled",
"-Dgst-plugins-ugly:glib-asserts=disabled",
"-Dgst-plugins-ugly:glib-checks=disabled",
"-Dgst-plugins-ugly:mpeg2dec=enabled"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/gstreamer/gstreamer.git",
"tag": "1.24.9",
"commit": "b309f90bfde36e6d175b70bfa0c941f2829dd6a5",
"disable-submodules": true
},
{
"type": "patch",
"path": "../flathub/gstreamer-1.0/gst-libav-stop-caching-codecs.patch"
},
{
"type": "patch",
"path": "../flathub/gstreamer-1.0/gst-plugins-base-autodetect-subtitle-text-encoding.patch"
},
{
"type": "patch",
"path": "../flathub/gstreamer-1.0/gst-plugins-good-matroska-fix-attachments-detection.patch"
},
{
"type": "patch",
"path": "../flathub/gstreamer-1.0/gst-plugins-good-dashdemux2-play-last-subfragment.patch"
},
{
"type": "patch",
"path": "../flathub/gstreamer-1.0/gst-plugins-bad-dashdemux-sidx-range-download.patch"
},
{
"type": "patch",
"path": "../flathub/gstreamer-1.0/gst-plugins-bad-dashdemux-improve-initial-representation-selection.patch"
}
]
}

View File

@@ -144,6 +144,8 @@ clapper_app_apply_options_to_window (ClapperAppWindow *dest_window, GVariantDict
clapper_player_set_mute (dest_player, option_bool);
if (clapper_app_options_get ("speed", "d", options, src_player_obj, settings, &option_dbl))
clapper_player_set_speed (dest_player, PERCENTAGE_ROUND (CLAMP (option_dbl, 0.05, 2.0)));
if (clapper_app_options_get ("adaptive-start-bitrate", "i", options, src_player_obj, settings, &option_int))
clapper_player_set_adaptive_start_bitrate (dest_player, option_int);
if (clapper_app_options_get ("progression-mode", "i", options, src_queue_obj, settings, &option_int))
clapper_queue_set_progression_mode (clapper_player_get_queue (dest_player), CLAMP (option_int, 0, 4));
if (clapper_app_options_get ("subtitles-enabled", "b", NULL, src_player_obj, settings, &option_bool))
@@ -196,6 +198,8 @@ _store_settings_from_window (ClapperAppApplication *self, ClapperAppWindow *app_
g_settings_set_double (self->settings, "volume", clapper_player_get_volume (player));
g_settings_set_boolean (self->settings, "mute", clapper_player_get_mute (player));
g_settings_set_double (self->settings, "speed", clapper_player_get_speed (player));
g_settings_set_int (self->settings, "adaptive-start-bitrate",
CLAMP (clapper_player_get_adaptive_bandwidth (player) * 0.8, 0, G_MAXINT));
g_settings_set_boolean (self->settings, "subtitles-enabled", clapper_player_get_subtitles_enabled (player));
g_settings_set_int (self->settings, "progression-mode", clapper_queue_get_progression_mode (queue));
@@ -676,6 +680,7 @@ clapper_app_application_constructed (GObject *object)
{ "enqueue", 0, 0, G_OPTION_ARG_NONE, NULL, _("Add media to queue in primary application instance"), NULL },
{ "volume", 0, 0, G_OPTION_ARG_DOUBLE, NULL, _("Audio volume to set (0 - 2.0 range)"), NULL },
{ "speed", 0, 0, G_OPTION_ARG_DOUBLE, NULL, _("Playback speed to set (0.05 - 2.0 range)"), NULL },
{ "adaptive-start-bitrate", 0, 0, G_OPTION_ARG_INT, NULL, _("Initial bitrate for adaptive streaming"), NULL },
{ "progression-mode", 0, 0, G_OPTION_ARG_INT, NULL, _("Initial queue progression mode (0=none, 1=consecutive, 2=repeat-item, 3=carousel, 4=shuffle)"), NULL },
{ "fullscreen", 'f', 0, G_OPTION_ARG_NONE, NULL, _("Set window to be fullscreen"), NULL },
{ "video-filter", 0, 0, G_OPTION_ARG_STRING, NULL, _("Video filter to use (\"none\" to disable)"), NULL },

View File

@@ -151,6 +151,15 @@ _queue_current_item_changed_cb (ClapperQueue *queue,
gst_clear_object (&current_item);
}
static void
_player_adaptive_bandwidth_changed_cb (ClapperPlayer *player,
GParamSpec *pspec G_GNUC_UNUSED, gpointer *user_data G_GNUC_UNUSED)
{
/* Do not take whole bandwidth */
clapper_player_set_adaptive_start_bitrate (player,
clapper_player_get_adaptive_bandwidth (player) * 0.8);
}
static gboolean
_get_seek_method_mapping (GValue *value,
GVariant *variant, gpointer user_data G_GNUC_UNUSED)
@@ -1280,10 +1289,12 @@ clapper_app_window_constructed (GObject *object)
clapper_player_set_autoplay (player, TRUE);
/* No need to also call this here, as item is selected
/* No need to also call these here, as they only change
* after application window is contructed */
g_signal_connect (queue, "notify::current-item",
G_CALLBACK (_queue_current_item_changed_cb), self);
g_signal_connect (player, "notify::adaptive-bandwidth",
G_CALLBACK (_player_adaptive_bandwidth_changed_cb), NULL);
g_settings_bind (self->settings, "audio-offset",
player, "audio-offset", G_SETTINGS_BIND_GET);

View File

@@ -49,6 +49,10 @@
<default>1.0</default>
<summary>Stores last speed value to apply on startup</summary>
</key>
<key name="adaptive-start-bitrate" type="i">
<default>1600000</default>
<summary>Stores initial adaptive streaming bitrate to apply on startup</summary>
</key>
<key name="progression-mode" type="i">
<default>1</default>
<summary>Stores last queue progression mode used to apply on startup</summary>

View File

@@ -87,6 +87,9 @@ struct _ClapperPlayer
gboolean pending_eos; // when pausing due to EOS
gint eos; // atomic integer
/* Set adaptive props immediately */
GstElement *adaptive_demuxer;
/* Playbin2 compat */
gint n_video, n_audio, n_text;
@@ -104,6 +107,10 @@ struct _ClapperPlayer
gboolean subtitles_enabled;
gchar *download_dir;
gboolean download_enabled;
guint start_bitrate;
guint min_bitrate;
guint max_bitrate;
guint bandwidth;
gdouble audio_offset;
gdouble subtitle_offset;
};

View File

@@ -62,6 +62,7 @@
#define DEFAULT_AUDIO_ENABLED TRUE
#define DEFAULT_SUBTITLES_ENABLED TRUE
#define DEFAULT_DOWNLOAD_ENABLED FALSE
#define DEFAULT_ADAPTIVE_START_BITRATE 1600000
#define GST_CAT_DEFAULT clapper_player_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
@@ -93,6 +94,10 @@ enum
PROP_SUBTITLES_ENABLED,
PROP_DOWNLOAD_DIR,
PROP_DOWNLOAD_ENABLED,
PROP_ADAPTIVE_START_BITRATE,
PROP_ADAPTIVE_MIN_BITRATE,
PROP_ADAPTIVE_MAX_BITRATE,
PROP_ADAPTIVE_BANDWIDTH,
PROP_AUDIO_OFFSET,
PROP_SUBTITLE_OFFSET,
PROP_SUBTITLE_FONT_DESC,
@@ -712,6 +717,32 @@ clapper_player_playbin_update_current_decoders (ClapperPlayer *self)
GST_DEBUG_OBJECT (self, "Active audio decoder not found");
}
static void
_adaptive_demuxer_bandwidth_changed_cb (GstElement *adaptive_demuxer,
GParamSpec *pspec G_GNUC_UNUSED, ClapperPlayer *self)
{
guint bandwidth = 0;
gboolean changed;
g_object_get (adaptive_demuxer, "current-bandwidth", &bandwidth, NULL);
/* Skip uncalculated bandwidth from
* new adaptive demuxer instance */
if (bandwidth == 0)
return;
GST_OBJECT_LOCK (self);
if ((changed = bandwidth != self->bandwidth))
self->bandwidth = bandwidth;
GST_OBJECT_UNLOCK (self);
if (changed) {
GST_LOG_OBJECT (self, "Adaptive bandwidth: %u", bandwidth);
clapper_app_bus_post_prop_notify (self->app_bus,
GST_OBJECT_CAST (self), param_specs[PROP_ADAPTIVE_BANDWIDTH]);
}
}
void
clapper_player_reset (ClapperPlayer *self, gboolean pending_dispose)
{
@@ -727,6 +758,12 @@ clapper_player_reset (ClapperPlayer *self, gboolean pending_dispose)
gst_clear_object (&self->audio_decoder);
}
if (self->adaptive_demuxer) {
g_signal_handlers_disconnect_by_func (self->adaptive_demuxer,
_adaptive_demuxer_bandwidth_changed_cb, self);
gst_clear_object (&self->adaptive_demuxer);
}
GST_OBJECT_UNLOCK (self);
gst_clear_tag_list (&self->pending_tags);
@@ -768,13 +805,15 @@ static void
_element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self)
{
GstElementFactory *factory = gst_element_get_factory (element);
const gchar *factory_name;
if (G_UNLIKELY (factory == NULL))
return;
GST_INFO_OBJECT (self, "Element setup: %s", GST_OBJECT_NAME (factory));
factory_name = g_intern_static_string (GST_OBJECT_NAME (factory));
GST_INFO_OBJECT (self, "Element setup: %s", factory_name);
if (strcmp (GST_OBJECT_NAME (factory), "downloadbuffer") == 0) {
if (factory_name == g_intern_static_string ("downloadbuffer")) {
gchar *download_template;
/* Only set props if we have download template */
@@ -785,6 +824,37 @@ _element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self
NULL);
g_free (download_template);
}
} else if (factory_name == g_intern_static_string ("dashdemux2")
|| factory_name == g_intern_static_string ("hlsdemux2")) {
guint start_bitrate, min_bitrate, max_bitrate;
GST_OBJECT_LOCK (self);
start_bitrate = self->start_bitrate;
min_bitrate = self->min_bitrate;
max_bitrate = self->max_bitrate;
if (self->adaptive_demuxer) {
g_signal_handlers_disconnect_by_func (self->adaptive_demuxer,
_adaptive_demuxer_bandwidth_changed_cb, self);
}
gst_object_replace ((GstObject **) &self->adaptive_demuxer, GST_OBJECT_CAST (element));
if (self->adaptive_demuxer) {
g_signal_connect (self->adaptive_demuxer, "notify::current-bandwidth",
G_CALLBACK (_adaptive_demuxer_bandwidth_changed_cb), self);
}
GST_OBJECT_UNLOCK (self);
g_object_set (element,
"low-watermark-time", 3 * GST_SECOND,
"high-watermark-time", 10 * GST_SECOND,
"start-bitrate", start_bitrate,
"min-bitrate", min_bitrate,
"max-bitrate", max_bitrate,
NULL);
}
}
@@ -1668,6 +1738,193 @@ clapper_player_get_download_enabled (ClapperPlayer *self)
return enabled;
}
static void
_set_adaptive_bitrate (ClapperPlayer *self, guint *internal_ptr,
const gchar *prop_name, guint bitrate, GParamSpec *pspec)
{
GstElement *element = NULL;
gboolean changed;
if (!self->use_playbin3) {
GST_WARNING_OBJECT (self, "Setting adaptive-%s when using playbin2"
" has no effect", prop_name);
}
GST_OBJECT_LOCK (self);
if ((changed = (*internal_ptr != bitrate))) {
*internal_ptr = bitrate;
if (self->adaptive_demuxer)
element = gst_object_ref (self->adaptive_demuxer);
}
GST_OBJECT_UNLOCK (self);
if (changed) {
GST_INFO_OBJECT (self, "Set adaptive-%s: %u", prop_name, bitrate);
if (element)
g_object_set (element, prop_name, bitrate, NULL);
clapper_app_bus_post_prop_notify (self->app_bus, GST_OBJECT_CAST (self), pspec);
}
gst_clear_object (&element);
}
/**
* clapper_player_set_adaptive_start_bitrate:
* @player: a #ClapperPlayer
* @bitrate: a bitrate to set (bits/s)
*
* Set initial bitrate to select when starting adaptive
* streaming such as DASH or HLS.
*
* Since: 0.8
*/
void
clapper_player_set_adaptive_start_bitrate (ClapperPlayer *self, guint bitrate)
{
g_return_if_fail (CLAPPER_IS_PLAYER (self));
_set_adaptive_bitrate (self, &self->start_bitrate,
"start-bitrate", bitrate, param_specs[PROP_ADAPTIVE_START_BITRATE]);
}
/**
* clapper_player_get_adaptive_start_bitrate:
* @player: a #ClapperPlayer
*
* Get currently set initial bitrate (bits/s) for adaptive streaming.
*
* Returns: the start bitrate value.
*
* Since: 0.8
*/
guint
clapper_player_get_adaptive_start_bitrate (ClapperPlayer *self)
{
guint bitrate;
g_return_val_if_fail (CLAPPER_IS_PLAYER (self), 0);
GST_OBJECT_LOCK (self);
bitrate = self->start_bitrate;
GST_OBJECT_UNLOCK (self);
return bitrate;
}
/**
* clapper_player_set_adaptive_min_bitrate:
* @player: a #ClapperPlayer
* @bitrate: a bitrate to set (bits/s)
*
* Set minimal bitrate to select for adaptive streaming
* such as DASH or HLS.
*
* Since: 0.8
*/
void
clapper_player_set_adaptive_min_bitrate (ClapperPlayer *self, guint bitrate)
{
g_return_if_fail (CLAPPER_IS_PLAYER (self));
_set_adaptive_bitrate (self, &self->min_bitrate,
"min-bitrate", bitrate, param_specs[PROP_ADAPTIVE_MIN_BITRATE]);
}
/**
* clapper_player_get_adaptive_min_bitrate:
* @player: a #ClapperPlayer
*
* Get currently set minimal bitrate (bits/s) for adaptive streaming.
*
* Returns: the minimal bitrate value.
*
* Since: 0.8
*/
guint
clapper_player_get_adaptive_min_bitrate (ClapperPlayer *self)
{
guint bitrate;
g_return_val_if_fail (CLAPPER_IS_PLAYER (self), 0);
GST_OBJECT_LOCK (self);
bitrate = self->min_bitrate;
GST_OBJECT_UNLOCK (self);
return bitrate;
}
/**
* clapper_player_set_adaptive_max_bitrate:
* @player: a #ClapperPlayer
* @bitrate: a bitrate to set (bits/s)
*
* Set maximal bitrate to select for adaptive streaming
* such as DASH or HLS.
*
* Since: 0.8
*/
void
clapper_player_set_adaptive_max_bitrate (ClapperPlayer *self, guint bitrate)
{
g_return_if_fail (CLAPPER_IS_PLAYER (self));
_set_adaptive_bitrate (self, &self->max_bitrate,
"max-bitrate", bitrate, param_specs[PROP_ADAPTIVE_MAX_BITRATE]);
}
/**
* clapper_player_get_adaptive_max_bitrate:
* @player: a #ClapperPlayer
*
* Get currently set maximal bitrate (bits/s) for adaptive streaming.
*
* Returns: the maximal bitrate value.
*
* Since: 0.8
*/
guint
clapper_player_get_adaptive_max_bitrate (ClapperPlayer *self)
{
guint bitrate;
g_return_val_if_fail (CLAPPER_IS_PLAYER (self), 0);
GST_OBJECT_LOCK (self);
bitrate = self->max_bitrate;
GST_OBJECT_UNLOCK (self);
return bitrate;
}
/**
* clapper_player_get_adaptive_bandwidth:
* @player: a #ClapperPlayer
*
* Get last fragment download bandwidth (bits/s) during
* adaptive streaming.
*
* Returns: the adaptive bandwidth.
*
* Since: 0.8
*/
guint
clapper_player_get_adaptive_bandwidth (ClapperPlayer *self)
{
guint bandwidth;
g_return_val_if_fail (CLAPPER_IS_PLAYER (self), 0);
GST_OBJECT_LOCK (self);
bandwidth = self->bandwidth;
GST_OBJECT_UNLOCK (self);
return bandwidth;
}
/**
* clapper_player_set_audio_offset:
* @player: a #ClapperPlayer
@@ -1942,7 +2199,7 @@ clapper_player_thread_start (ClapperThreadedObject *threaded_object)
if (!(env = g_getenv ("CLAPPER_USE_PLAYBIN3"))) // Clapper override
env = g_getenv ("GST_CLAPPER_USE_PLAYBIN3"); // compat
self->use_playbin3 = (env && g_str_has_prefix (env, "1"));
self->use_playbin3 = (!env || g_str_has_prefix (env, "1"));
playbin_str = (self->use_playbin3) ? "playbin3" : "playbin";
if (!(self->playbin = gst_element_factory_make (playbin_str, NULL))) {
@@ -2031,6 +2288,7 @@ clapper_player_init (ClapperPlayer *self)
self->audio_enabled = DEFAULT_AUDIO_ENABLED;
self->subtitles_enabled = DEFAULT_SUBTITLES_ENABLED;
self->download_enabled = DEFAULT_DOWNLOAD_ENABLED;
self->start_bitrate = DEFAULT_ADAPTIVE_START_BITRATE;
}
static void
@@ -2164,6 +2422,18 @@ clapper_player_get_property (GObject *object, guint prop_id,
case PROP_DOWNLOAD_ENABLED:
g_value_set_boolean (value, clapper_player_get_download_enabled (self));
break;
case PROP_ADAPTIVE_START_BITRATE:
g_value_set_uint (value, clapper_player_get_adaptive_start_bitrate (self));
break;
case PROP_ADAPTIVE_MIN_BITRATE:
g_value_set_uint (value, clapper_player_get_adaptive_min_bitrate (self));
break;
case PROP_ADAPTIVE_MAX_BITRATE:
g_value_set_uint (value, clapper_player_get_adaptive_max_bitrate (self));
break;
case PROP_ADAPTIVE_BANDWIDTH:
g_value_set_uint (value, clapper_player_get_adaptive_bandwidth (self));
break;
case PROP_AUDIO_OFFSET:
g_value_set_double (value, clapper_player_get_audio_offset (self));
break;
@@ -2225,6 +2495,15 @@ clapper_player_set_property (GObject *object, guint prop_id,
case PROP_DOWNLOAD_ENABLED:
clapper_player_set_download_enabled (self, g_value_get_boolean (value));
break;
case PROP_ADAPTIVE_START_BITRATE:
clapper_player_set_adaptive_start_bitrate (self, g_value_get_uint (value));
break;
case PROP_ADAPTIVE_MIN_BITRATE:
clapper_player_set_adaptive_min_bitrate (self, g_value_get_uint (value));
break;
case PROP_ADAPTIVE_MAX_BITRATE:
clapper_player_set_adaptive_max_bitrate (self, g_value_get_uint (value));
break;
case PROP_AUDIO_OFFSET:
clapper_player_set_audio_offset (self, g_value_get_double (value));
break;
@@ -2476,6 +2755,72 @@ clapper_player_class_init (ClapperPlayerClass *klass)
NULL, NULL, DEFAULT_DOWNLOAD_ENABLED,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperPlayer:adaptive-start-bitrate:
*
* An initial bitrate (bits/s) to select during
* starting adaptive streaming such as DASH or HLS.
*
* If value is higher than lowest available bitrate in streaming
* manifest, then lowest possible bitrate will be selected.
*
* Since: 0.8
*/
param_specs[PROP_ADAPTIVE_START_BITRATE] = g_param_spec_uint ("adaptive-start-bitrate",
NULL, NULL, 0, G_MAXUINT, DEFAULT_ADAPTIVE_START_BITRATE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperPlayer:adaptive-min-bitrate:
*
* A minimal allowed bitrate (bits/s) during adaptive streaming
* such as DASH or HLS.
*
* Setting this will prevent streaming from entering lower qualities
* (even when connection speed cannot keep up). When set together with
* [property@Clapper.Player:adaptive-max-bitrate] it can be used to
* enforce some specific quality.
*
* Since: 0.8
*/
param_specs[PROP_ADAPTIVE_MIN_BITRATE] = g_param_spec_uint ("adaptive-min-bitrate",
NULL, NULL, 0, G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperPlayer:adaptive-max-bitrate:
*
* A maximal allowed bitrate (bits/s) during adaptive streaming
* such as DASH or HLS (`0` for unlimited).
*
* Setting this will prevent streaming from entering qualities with
* higher bandwidth than the one set. When set together with
* [property@Clapper.Player:adaptive-min-bitrate] it can be used to
* enforce some specific quality.
*
* Since: 0.8
*/
param_specs[PROP_ADAPTIVE_MAX_BITRATE] = g_param_spec_uint ("adaptive-max-bitrate",
NULL, NULL, 0, G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperPlayer:adaptive-bandwidth:
*
* Last fragment download bandwidth (bits/s) during adaptive streaming.
*
* This property only changes when adaptive streaming and later stays
* at the last value until streaming some adaptive content again.
*
* Apps can use this to determine and set an optimal value for
* [property@Clapper.Player:adaptive-start-bitrate].
*
* Since: 0.8
*/
param_specs[PROP_ADAPTIVE_BANDWIDTH] = g_param_spec_uint ("adaptive-bandwidth",
NULL, NULL, 0, G_MAXUINT, 0,
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* ClapperPlayer:audio-offset:
*

View File

@@ -147,6 +147,27 @@ void clapper_player_set_download_enabled (ClapperPlayer *player, gboolean enable
CLAPPER_API
gboolean clapper_player_get_download_enabled (ClapperPlayer *player);
CLAPPER_API
void clapper_player_set_adaptive_start_bitrate (ClapperPlayer *player, guint bitrate);
CLAPPER_API
guint clapper_player_get_adaptive_start_bitrate (ClapperPlayer *player);
CLAPPER_API
void clapper_player_set_adaptive_min_bitrate (ClapperPlayer *player, guint bitrate);
CLAPPER_API
guint clapper_player_get_adaptive_min_bitrate (ClapperPlayer *player);
CLAPPER_API
void clapper_player_set_adaptive_max_bitrate (ClapperPlayer *player, guint bitrate);
CLAPPER_API
guint clapper_player_get_adaptive_max_bitrate (ClapperPlayer *player);
CLAPPER_API
guint clapper_player_get_adaptive_bandwidth (ClapperPlayer *player);
CLAPPER_API
void clapper_player_set_audio_offset (ClapperPlayer *player, gdouble offset);