diff --git a/meson.build b/meson.build index 377fe254..1d5298f3 100644 --- a/meson.build +++ b/meson.build @@ -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' diff --git a/pkgs/flatpak/com.github.rafostar.Clapper.json b/pkgs/flatpak/com.github.rafostar.Clapper.json index 44d7611a..d18c46c5 100644 --- a/pkgs/flatpak/com.github.rafostar.Clapper.json +++ b/pkgs/flatpak/com.github.rafostar.Clapper.json @@ -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", diff --git a/pkgs/flatpak/testing/gstreamer_stable.json b/pkgs/flatpak/testing/gstreamer_stable.json new file mode 100644 index 00000000..a9140864 --- /dev/null +++ b/pkgs/flatpak/testing/gstreamer_stable.json @@ -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" + } + ] +} diff --git a/src/bin/clapper-app/clapper-app-application.c b/src/bin/clapper-app/clapper-app-application.c index 1232255a..703d8dec 100644 --- a/src/bin/clapper-app/clapper-app-application.c +++ b/src/bin/clapper-app/clapper-app-application.c @@ -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 }, diff --git a/src/bin/clapper-app/clapper-app-window.c b/src/bin/clapper-app/clapper-app-window.c index c7d0dbdb..9157b1a2 100644 --- a/src/bin/clapper-app/clapper-app-window.c +++ b/src/bin/clapper-app/clapper-app-window.c @@ -151,6 +151,15 @@ _queue_current_item_changed_cb (ClapperQueue *queue, gst_clear_object (¤t_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); diff --git a/src/bin/clapper-app/data/glib-2.0/schemas/com.github.rafostar.Clapper.gschema.xml b/src/bin/clapper-app/data/glib-2.0/schemas/com.github.rafostar.Clapper.gschema.xml index a73d1d55..9429f861 100644 --- a/src/bin/clapper-app/data/glib-2.0/schemas/com.github.rafostar.Clapper.gschema.xml +++ b/src/bin/clapper-app/data/glib-2.0/schemas/com.github.rafostar.Clapper.gschema.xml @@ -49,6 +49,10 @@ 1.0 Stores last speed value to apply on startup + + 1600000 + Stores initial adaptive streaming bitrate to apply on startup + 1 Stores last queue progression mode used to apply on startup diff --git a/src/lib/clapper/clapper-player-private.h b/src/lib/clapper/clapper-player-private.h index b29f64dc..43116cd2 100644 --- a/src/lib/clapper/clapper-player-private.h +++ b/src/lib/clapper/clapper-player-private.h @@ -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; }; diff --git a/src/lib/clapper/clapper-player.c b/src/lib/clapper/clapper-player.c index dc15c258..52f4e22c 100644 --- a/src/lib/clapper/clapper-player.c +++ b/src/lib/clapper/clapper-player.c @@ -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: * diff --git a/src/lib/clapper/clapper-player.h b/src/lib/clapper/clapper-player.h index 1c14c453..c47b1a78 100644 --- a/src/lib/clapper/clapper-player.h +++ b/src/lib/clapper/clapper-player.h @@ -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);