mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-30 07:42:23 +02:00
Merge pull request #506 from Rafostar/adaptive
Add adaptive streaming bitrate control to Clapper API
This commit is contained in:
@@ -9,7 +9,7 @@ project('clapper', 'c',
|
|||||||
)
|
)
|
||||||
|
|
||||||
glib_req = '>= 2.76.0'
|
glib_req = '>= 2.76.0'
|
||||||
gst_req = '>= 1.20.0'
|
gst_req = '>= 1.24.0'
|
||||||
gtk4_req = '>= 4.10.0'
|
gtk4_req = '>= 4.10.0'
|
||||||
adw_req = '>= 1.4.0'
|
adw_req = '>= 1.4.0'
|
||||||
|
|
||||||
|
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"app-id": "com.github.rafostar.Clapper",
|
"app-id": "com.github.rafostar.Clapper",
|
||||||
"runtime": "org.gnome.Platform",
|
"runtime": "org.gnome.Platform",
|
||||||
"runtime-version": "45",
|
"runtime-version": "47",
|
||||||
"sdk": "org.gnome.Sdk",
|
"sdk": "org.gnome.Sdk",
|
||||||
"add-extensions": {
|
"add-extensions": {
|
||||||
"org.freedesktop.Platform.ffmpeg-full": {
|
"org.freedesktop.Platform.ffmpeg-full": {
|
||||||
"version": "23.08",
|
"version": "24.08",
|
||||||
"directory": "lib/ffmpeg",
|
"directory": "lib/ffmpeg",
|
||||||
"add-ld-path": ".",
|
"add-ld-path": ".",
|
||||||
"no-autodownload": false,
|
"no-autodownload": false,
|
||||||
@@ -40,15 +40,12 @@
|
|||||||
"flathub/lib/libass.json",
|
"flathub/lib/libass.json",
|
||||||
"flathub/lib/uchardet.json",
|
"flathub/lib/uchardet.json",
|
||||||
"flathub/lib/libmicrodns.json",
|
"flathub/lib/libmicrodns.json",
|
||||||
"flathub/gstreamer-1.0/gstreamer.json",
|
"testing/gstreamer_stable.json",
|
||||||
"testing/yt-dlp.json",
|
"testing/yt-dlp.json",
|
||||||
"testing/libpeas.json",
|
"testing/libpeas.json",
|
||||||
{
|
{
|
||||||
"name": "clapper",
|
"name": "clapper",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [
|
|
||||||
"-Dc_args=\"-DHAVE_GST_PATCHES=1\""
|
|
||||||
],
|
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "dir",
|
"type": "dir",
|
||||||
|
99
pkgs/flatpak/testing/gstreamer_stable.json
Normal file
99
pkgs/flatpak/testing/gstreamer_stable.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -144,6 +144,8 @@ clapper_app_apply_options_to_window (ClapperAppWindow *dest_window, GVariantDict
|
|||||||
clapper_player_set_mute (dest_player, option_bool);
|
clapper_player_set_mute (dest_player, option_bool);
|
||||||
if (clapper_app_options_get ("speed", "d", options, src_player_obj, settings, &option_dbl))
|
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)));
|
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))
|
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));
|
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))
|
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_double (self->settings, "volume", clapper_player_get_volume (player));
|
||||||
g_settings_set_boolean (self->settings, "mute", clapper_player_get_mute (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_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_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));
|
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 },
|
{ "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 },
|
{ "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 },
|
{ "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 },
|
{ "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 },
|
{ "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 },
|
{ "video-filter", 0, 0, G_OPTION_ARG_STRING, NULL, _("Video filter to use (\"none\" to disable)"), NULL },
|
||||||
|
@@ -151,6 +151,15 @@ _queue_current_item_changed_cb (ClapperQueue *queue,
|
|||||||
gst_clear_object (¤t_item);
|
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
|
static gboolean
|
||||||
_get_seek_method_mapping (GValue *value,
|
_get_seek_method_mapping (GValue *value,
|
||||||
GVariant *variant, gpointer user_data G_GNUC_UNUSED)
|
GVariant *variant, gpointer user_data G_GNUC_UNUSED)
|
||||||
@@ -1280,10 +1289,12 @@ clapper_app_window_constructed (GObject *object)
|
|||||||
|
|
||||||
clapper_player_set_autoplay (player, TRUE);
|
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 */
|
* after application window is contructed */
|
||||||
g_signal_connect (queue, "notify::current-item",
|
g_signal_connect (queue, "notify::current-item",
|
||||||
G_CALLBACK (_queue_current_item_changed_cb), self);
|
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",
|
g_settings_bind (self->settings, "audio-offset",
|
||||||
player, "audio-offset", G_SETTINGS_BIND_GET);
|
player, "audio-offset", G_SETTINGS_BIND_GET);
|
||||||
|
@@ -49,6 +49,10 @@
|
|||||||
<default>1.0</default>
|
<default>1.0</default>
|
||||||
<summary>Stores last speed value to apply on startup</summary>
|
<summary>Stores last speed value to apply on startup</summary>
|
||||||
</key>
|
</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">
|
<key name="progression-mode" type="i">
|
||||||
<default>1</default>
|
<default>1</default>
|
||||||
<summary>Stores last queue progression mode used to apply on startup</summary>
|
<summary>Stores last queue progression mode used to apply on startup</summary>
|
||||||
|
@@ -87,6 +87,9 @@ struct _ClapperPlayer
|
|||||||
gboolean pending_eos; // when pausing due to EOS
|
gboolean pending_eos; // when pausing due to EOS
|
||||||
gint eos; // atomic integer
|
gint eos; // atomic integer
|
||||||
|
|
||||||
|
/* Set adaptive props immediately */
|
||||||
|
GstElement *adaptive_demuxer;
|
||||||
|
|
||||||
/* Playbin2 compat */
|
/* Playbin2 compat */
|
||||||
gint n_video, n_audio, n_text;
|
gint n_video, n_audio, n_text;
|
||||||
|
|
||||||
@@ -104,6 +107,10 @@ struct _ClapperPlayer
|
|||||||
gboolean subtitles_enabled;
|
gboolean subtitles_enabled;
|
||||||
gchar *download_dir;
|
gchar *download_dir;
|
||||||
gboolean download_enabled;
|
gboolean download_enabled;
|
||||||
|
guint start_bitrate;
|
||||||
|
guint min_bitrate;
|
||||||
|
guint max_bitrate;
|
||||||
|
guint bandwidth;
|
||||||
gdouble audio_offset;
|
gdouble audio_offset;
|
||||||
gdouble subtitle_offset;
|
gdouble subtitle_offset;
|
||||||
};
|
};
|
||||||
|
@@ -62,6 +62,7 @@
|
|||||||
#define DEFAULT_AUDIO_ENABLED TRUE
|
#define DEFAULT_AUDIO_ENABLED TRUE
|
||||||
#define DEFAULT_SUBTITLES_ENABLED TRUE
|
#define DEFAULT_SUBTITLES_ENABLED TRUE
|
||||||
#define DEFAULT_DOWNLOAD_ENABLED FALSE
|
#define DEFAULT_DOWNLOAD_ENABLED FALSE
|
||||||
|
#define DEFAULT_ADAPTIVE_START_BITRATE 1600000
|
||||||
|
|
||||||
#define GST_CAT_DEFAULT clapper_player_debug
|
#define GST_CAT_DEFAULT clapper_player_debug
|
||||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||||
@@ -93,6 +94,10 @@ enum
|
|||||||
PROP_SUBTITLES_ENABLED,
|
PROP_SUBTITLES_ENABLED,
|
||||||
PROP_DOWNLOAD_DIR,
|
PROP_DOWNLOAD_DIR,
|
||||||
PROP_DOWNLOAD_ENABLED,
|
PROP_DOWNLOAD_ENABLED,
|
||||||
|
PROP_ADAPTIVE_START_BITRATE,
|
||||||
|
PROP_ADAPTIVE_MIN_BITRATE,
|
||||||
|
PROP_ADAPTIVE_MAX_BITRATE,
|
||||||
|
PROP_ADAPTIVE_BANDWIDTH,
|
||||||
PROP_AUDIO_OFFSET,
|
PROP_AUDIO_OFFSET,
|
||||||
PROP_SUBTITLE_OFFSET,
|
PROP_SUBTITLE_OFFSET,
|
||||||
PROP_SUBTITLE_FONT_DESC,
|
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");
|
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
|
void
|
||||||
clapper_player_reset (ClapperPlayer *self, gboolean pending_dispose)
|
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);
|
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_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
gst_clear_tag_list (&self->pending_tags);
|
gst_clear_tag_list (&self->pending_tags);
|
||||||
@@ -768,13 +805,15 @@ static void
|
|||||||
_element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self)
|
_element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self)
|
||||||
{
|
{
|
||||||
GstElementFactory *factory = gst_element_get_factory (element);
|
GstElementFactory *factory = gst_element_get_factory (element);
|
||||||
|
const gchar *factory_name;
|
||||||
|
|
||||||
if (G_UNLIKELY (factory == NULL))
|
if (G_UNLIKELY (factory == NULL))
|
||||||
return;
|
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;
|
gchar *download_template;
|
||||||
|
|
||||||
/* Only set props if we have download template */
|
/* Only set props if we have download template */
|
||||||
@@ -785,6 +824,37 @@ _element_setup_cb (GstElement *playbin, GstElement *element, ClapperPlayer *self
|
|||||||
NULL);
|
NULL);
|
||||||
g_free (download_template);
|
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;
|
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:
|
* clapper_player_set_audio_offset:
|
||||||
* @player: a #ClapperPlayer
|
* @player: a #ClapperPlayer
|
||||||
@@ -1942,7 +2199,7 @@ clapper_player_thread_start (ClapperThreadedObject *threaded_object)
|
|||||||
if (!(env = g_getenv ("CLAPPER_USE_PLAYBIN3"))) // Clapper override
|
if (!(env = g_getenv ("CLAPPER_USE_PLAYBIN3"))) // Clapper override
|
||||||
env = g_getenv ("GST_CLAPPER_USE_PLAYBIN3"); // compat
|
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";
|
playbin_str = (self->use_playbin3) ? "playbin3" : "playbin";
|
||||||
|
|
||||||
if (!(self->playbin = gst_element_factory_make (playbin_str, NULL))) {
|
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->audio_enabled = DEFAULT_AUDIO_ENABLED;
|
||||||
self->subtitles_enabled = DEFAULT_SUBTITLES_ENABLED;
|
self->subtitles_enabled = DEFAULT_SUBTITLES_ENABLED;
|
||||||
self->download_enabled = DEFAULT_DOWNLOAD_ENABLED;
|
self->download_enabled = DEFAULT_DOWNLOAD_ENABLED;
|
||||||
|
self->start_bitrate = DEFAULT_ADAPTIVE_START_BITRATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2164,6 +2422,18 @@ clapper_player_get_property (GObject *object, guint prop_id,
|
|||||||
case PROP_DOWNLOAD_ENABLED:
|
case PROP_DOWNLOAD_ENABLED:
|
||||||
g_value_set_boolean (value, clapper_player_get_download_enabled (self));
|
g_value_set_boolean (value, clapper_player_get_download_enabled (self));
|
||||||
break;
|
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:
|
case PROP_AUDIO_OFFSET:
|
||||||
g_value_set_double (value, clapper_player_get_audio_offset (self));
|
g_value_set_double (value, clapper_player_get_audio_offset (self));
|
||||||
break;
|
break;
|
||||||
@@ -2225,6 +2495,15 @@ clapper_player_set_property (GObject *object, guint prop_id,
|
|||||||
case PROP_DOWNLOAD_ENABLED:
|
case PROP_DOWNLOAD_ENABLED:
|
||||||
clapper_player_set_download_enabled (self, g_value_get_boolean (value));
|
clapper_player_set_download_enabled (self, g_value_get_boolean (value));
|
||||||
break;
|
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:
|
case PROP_AUDIO_OFFSET:
|
||||||
clapper_player_set_audio_offset (self, g_value_get_double (value));
|
clapper_player_set_audio_offset (self, g_value_get_double (value));
|
||||||
break;
|
break;
|
||||||
@@ -2476,6 +2755,72 @@ clapper_player_class_init (ClapperPlayerClass *klass)
|
|||||||
NULL, NULL, DEFAULT_DOWNLOAD_ENABLED,
|
NULL, NULL, DEFAULT_DOWNLOAD_ENABLED,
|
||||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
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:
|
* ClapperPlayer:audio-offset:
|
||||||
*
|
*
|
||||||
|
@@ -147,6 +147,27 @@ void clapper_player_set_download_enabled (ClapperPlayer *player, gboolean enable
|
|||||||
CLAPPER_API
|
CLAPPER_API
|
||||||
gboolean clapper_player_get_download_enabled (ClapperPlayer *player);
|
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
|
CLAPPER_API
|
||||||
void clapper_player_set_audio_offset (ClapperPlayer *player, gdouble offset);
|
void clapper_player_set_audio_offset (ClapperPlayer *player, gdouble offset);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user