From: Eunhye Choi Date: Tue, 9 Mar 2021 06:55:26 +0000 (+0900) Subject: hls: support bandwidth limit X-Git-Tag: submit/tizen/20210415.043549~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7505e8bf4c866dfabb4d0a83dc50f364d37bd723;p=platform%2Fupstream%2Fgst-plugins-bad.git hls: support bandwidth limit - add start-bandwidth, min-bandwidth properties to use when switching to alternates. Change-Id: I616847f7a6f9c71564b9a054feae1a0b38625506 --- diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c index 2e4923c30..37b3ca3d6 100644 --- a/ext/dash/gstdashdemux.c +++ b/ext/dash/gstdashdemux.c @@ -1765,7 +1765,7 @@ gst_dash_demux_stream_has_next_fragment (GstAdaptiveDemuxStream * stream) /* The goal here is to figure out, once we have pushed a keyframe downstream, * what the next ideal keyframe to download is. - * + * * This is done based on: * * the current internal position (i.e. actual_position) * * the reported downstream position (QoS feedback) @@ -2216,13 +2216,13 @@ gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream, } #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION - bitrate = (base_demux->max_bandwidth > DEFAULT_ADAPTIVE_VARIANT)? - (guint64)(base_demux->max_bandwidth):(bitrate); + if (base_demux->max_bandwidth > DEFAULT_BANDWIDTH_LIMIT) + bitrate = (guint64)base_demux->max_bandwidth; GST_DEBUG_OBJECT (stream->pad, "Trying to change to bitrate under : %" G_GUINT64_FORMAT, bitrate); /* get representation index with current max_bandwidth */ - if (GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (base_demux) || + if (GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (base_demux) || ABS (base_demux->segment.rate) <= 1.0) { new_index = gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, bitrate, @@ -3702,7 +3702,7 @@ struct Rfc5322TimeZone /* Parse an RFC5322 (section 3.3) date-time from the Date: field in the - HTTP response. + HTTP response. See https://tools.ietf.org/html/rfc5322#section-3.3 */ static GstDateTime * diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c index 8f37e9678..62f632fb0 100644 --- a/ext/hls/gsthlsdemux.c +++ b/ext/hls/gsthlsdemux.c @@ -730,16 +730,18 @@ gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf) /* select the initial variant stream */ #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION - if ((demux->connection_speed > 0) || - (demux->max_bandwidth > DEFAULT_ADAPTIVE_VARIANT) || - (demux->max_width > DEFAULT_ADAPTIVE_VARIANT) || - (demux->max_height > DEFAULT_ADAPTIVE_VARIANT)) { - variant = - gst_hls_master_playlist_get_variant_for_max_limit (hlsdemux->master, - NULL, demux->connection_speed, - demux->max_bandwidth, demux->max_width, demux->max_height); - } else { + variant = + gst_hls_master_playlist_get_variant_for_bandwitdh_limit (hlsdemux->master, + NULL, demux->connection_speed, demux->start_bandwidth, + demux->min_bandwidth, demux->max_bandwidth, demux->max_width, demux->max_height); + + if (!variant) variant = hlsdemux->master->default_variant; + + if (variant) { + GST_INFO_OBJECT (hlsdemux, "selected %s, %d, %d x %d", + variant->name, variant->bandwidth, variant->width, variant->height); + gst_hls_demux_set_current_variant (hlsdemux, variant); } #else if (demux->connection_speed == 0) { @@ -749,11 +751,11 @@ gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf) gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master, NULL, demux->connection_speed); } -#endif if (variant) { GST_INFO_OBJECT (hlsdemux, "selected %s", variant->name); gst_hls_demux_set_current_variant (hlsdemux, variant); // FIXME: inline? } +#endif /* get the selected media playlist (unless the inital list was one already) */ if (!hlsdemux->master->is_simple) { @@ -1737,9 +1739,12 @@ gst_hls_demux_change_playlist (GstHLSDemux * demux, guint max_bitrate, previous_variant = demux->current_variant; #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION new_variant = - gst_hls_master_playlist_get_variant_for_max_limit (demux->master, - demux->current_variant, max_bitrate, - adaptive_demux->max_bandwidth, adaptive_demux->max_width, adaptive_demux->max_height); + gst_hls_master_playlist_get_variant_for_bandwitdh_limit (demux->master, + demux->current_variant, max_bitrate, NULL, adaptive_demux->min_bandwidth, + adaptive_demux->max_bandwidth, adaptive_demux->max_width, adaptive_demux->max_height); + + GST_INFO_OBJECT (demux, "new_variant : %d, %d x %d", + new_variant->bandwidth, new_variant->width, new_variant->height); #else new_variant = gst_hls_master_playlist_get_variant_for_bitrate (demux->master, diff --git a/ext/hls/m3u8.c b/ext/hls/m3u8.c index d74977b07..2ce82811d 100644 --- a/ext/hls/m3u8.c +++ b/ext/hls/m3u8.c @@ -31,7 +31,8 @@ #define GST_CAT_DEFAULT hls_debug #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION -#define DEFAULT_ADAPTIVE_VARIANT -1 +#define DEFAULT_RESOLUTION_LIMIT -1 +#define DEFAULT_BANDWIDTH_LIMIT -1 #endif static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri, @@ -1005,7 +1006,7 @@ gst_m3u8_advance_fragment (GstM3U8 * m3u8, gboolean forward) } } if (m3u8->current_file) { - /* Store duration of the fragment we're using to update the position + /* Store duration of the fragment we're using to update the position * the next time we advance */ m3u8->current_file_duration = GST_M3U8_MEDIA_FILE (m3u8->current_file->data)->duration; @@ -1798,10 +1799,10 @@ get_num_of_codec(GstHLSVariantStream * variant) if (!variant || !variant->codecs) return 0; - codec_list = g_strsplit(variant->codecs, ",", MAX_NUM_OF_CODEC); + codec_list = g_strsplit (variant->codecs, ",", MAX_NUM_OF_CODEC); if (codec_list) { - cnt = g_strv_length(codec_list); - g_strfreev(codec_list); + cnt = g_strv_length (codec_list); + g_strfreev (codec_list); } return cnt; @@ -1815,52 +1816,209 @@ check_num_of_codec(GstHLSVariantStream * variant, guint req_num) if (!variant) return FALSE; - num_of_codec = get_num_of_codec(variant); + num_of_codec = get_num_of_codec (variant); if (num_of_codec > 0 && req_num > 0 && num_of_codec != req_num) { - GST_WARNING("can not support to change codec"); + GST_WARNING ("can not support to change codec"); return FALSE; } return TRUE; } +static gint +update_max_limit(gint min_limit, gint max_limit, gint start_limit, gint bitrate) +{ + if (start_limit > DEFAULT_BANDWIDTH_LIMIT && start_limit >= min_limit && + (start_limit <= max_limit || max_limit == DEFAULT_BANDWIDTH_LIMIT)) { + GST_DEBUG ("set max to start : %d ", start_limit); + return start_limit; + } + + if (bitrate > 0 && bitrate >= min_limit && + (bitrate <= max_limit || max_limit == DEFAULT_BANDWIDTH_LIMIT)) { + GST_DEBUG ("set max to bitrate : %d ", bitrate); + return bitrate; + } + + if (bitrate == 0 || bitrate < min_limit) { + GST_DEBUG ("set max to min : %d", min_limit); + return min_limit; + } + + return max_limit; +} + GstHLSVariantStream * -gst_hls_master_playlist_get_variant_for_max_limit (GstHLSMasterPlaylist * - playlist, GstHLSVariantStream * current_variant, guint bitrate, gint bandwidth, gint width, gint height) +get_average_variant(GList *variants, guint num_of_codec, gint min_limit, gint max_limit) +{ + GList *l = NULL; + GList *valid_list = NULL; + gint cnt = 0; + guint num_of_valid_variant = 0; + GstHLSVariantStream *tmp = NULL; + + for (l = g_list_first (variants); l; l = g_list_next (l)) { + if (!check_num_of_codec ((GstHLSVariantStream *)l->data, num_of_codec)) + continue; + + tmp = l->data; + + if (max_limit != DEFAULT_BANDWIDTH_LIMIT && tmp->bandwidth > max_limit) { + GST_DEBUG ("over max limit"); + break; + } + + if (min_limit != DEFAULT_BANDWIDTH_LIMIT && tmp->bandwidth < min_limit) { + GST_DEBUG ("skip to next"); + continue; + } + + num_of_valid_variant++; + valid_list = l; + } + + GST_DEBUG ("num of valid variant %d / %d", num_of_valid_variant, g_list_length (variants)); + + for (; valid_list; valid_list = g_list_previous (valid_list)) { + if (!check_num_of_codec ((GstHLSVariantStream *)valid_list->data, num_of_codec)) + continue; + + tmp = valid_list->data; + if (num_of_valid_variant/2 == cnt) { + GST_DEBUG ("get this stream %d", tmp->bandwidth); + return tmp; + } + cnt++; + } + return NULL; +} + +GstHLSVariantStream * +gst_hls_master_playlist_get_variant_for_bandwitdh_limit (GstHLSMasterPlaylist * playlist, + GstHLSVariantStream * current_variant, guint bitrate, gchar * start_bandwidth, + gint min_bandwidth, gint max_bandwidth, gint width, gint height) { GstHLSVariantStream *tmp = current_variant; GstHLSVariantStream *variant = NULL; - GList *l; - guint max_bandwidth = (bandwidth > DEFAULT_ADAPTIVE_VARIANT)?(guint)(bandwidth):(bitrate); + GstHLSVariantStream *min_variant = NULL; // lowest + GstHLSVariantStream *max_variant = NULL; // highest + GList *variants = NULL; + GList *l = NULL; + gint max_limit = DEFAULT_BANDWIDTH_LIMIT; + gint min_limit = DEFAULT_BANDWIDTH_LIMIT; + gint start_limit = DEFAULT_BANDWIDTH_LIMIT; + gint adj_max_limit = DEFAULT_BANDWIDTH_LIMIT; + guint num_of_valid_variant = 0; guint num_of_codec = 0; - num_of_codec = get_num_of_codec(current_variant); + num_of_codec = get_num_of_codec (current_variant); - GST_INFO("max limit : %u, %d, [w]%d [h]%d", bitrate, bandwidth, width, height); + GST_DEBUG ("bitrate: %u, bandwidth: %s, %d ~ %d, resolution: %d X %d", + bitrate, start_bandwidth, min_bandwidth, max_bandwidth, width, height); - /* variant lists are sorted low to high, so iterate from highest to lowest */ + /* get variant list */ if (current_variant == NULL || !current_variant->iframe) - l = g_list_last (playlist->variants); /* highest */ + variants = playlist->variants; else - l = g_list_last (playlist->iframe_variants); + variants = playlist->iframe_variants; + + if (!variants) { + GST_ERROR ("invalid playlist"); + return current_variant; + } + + /* get valid min/max variant */ + for (l = g_list_first (variants); l; l = g_list_next (l)) { + if (!check_num_of_codec ((GstHLSVariantStream *)l->data, num_of_codec)) + continue; + tmp = l->data; + num_of_valid_variant++; + + if (!min_variant) { + min_variant = tmp; + } + } + max_variant = tmp; + + GST_DEBUG("num of valid variant %d / %d", num_of_valid_variant, g_list_length (variants)); + if (num_of_valid_variant <= 1) + return tmp; + + /* get valid range limit */ + if (max_bandwidth == DEFAULT_BANDWIDTH_LIMIT || min_bandwidth <= max_bandwidth) { + if (min_variant->bandwidth <= max_bandwidth) + max_limit = adj_max_limit = max_bandwidth; + + if (max_variant->bandwidth >= min_bandwidth) + min_limit = min_bandwidth; + } + + GST_DEBUG ("range limit: %d ~ %d", min_limit, max_limit); + + if (start_bandwidth) { + if (!g_strcmp0 (start_bandwidth, "LOWEST")) { + if (min_limit == DEFAULT_BANDWIDTH_LIMIT) + return min_variant; + adj_max_limit = min_limit; + } else if (!g_strcmp0 (start_bandwidth, "HIGHEST")) { + if (max_limit == DEFAULT_BANDWIDTH_LIMIT) + return max_variant; + } else if (!g_strcmp0 (start_bandwidth, "AVERAGE")) { + variant = get_average_variant (variants, num_of_codec, min_limit, max_limit); + if (variant) + return variant; + } else { + start_limit = atoi (start_bandwidth); + /* update max limit based on the start_bandwidth or network bitrate */ + adj_max_limit = update_max_limit (min_limit, max_limit, start_limit, bitrate); + } + } else { + /* update max limit based on the network bitrate */ + adj_max_limit = update_max_limit (min_limit, max_limit, DEFAULT_BANDWIDTH_LIMIT, bitrate); + } + + if (min_limit < 0 && adj_max_limit < 0 && width < 0 && height < 0) { + GST_WARNING ("invalid condition, get default variant"); + return NULL; + } + + GST_DEBUG ("adj range limit: %d ~ %d (origin: %d)", min_limit, adj_max_limit, max_limit); - for (; l; l = g_list_previous(l)) { - if (!check_num_of_codec((GstHLSVariantStream *)l->data, num_of_codec)) + /* variant lists are sorted low to high, so iterate from highest to lowest */ + tmp = NULL; + for (l = g_list_last (variants); l; l = g_list_previous (l)) { + if (!check_num_of_codec ((GstHLSVariantStream *)l->data, num_of_codec)) continue; tmp = l->data; + GST_DEBUG ("stream info: %d, %d x %d", tmp->bandwidth, tmp->width, tmp->height); + + if (tmp->bandwidth < min_limit) { + GList *j = g_list_next(l); + if (variant) + break; + + if (j && + ((max_limit == DEFAULT_BANDWIDTH_LIMIT) || + ((GstHLSVariantStream*)j->data)->bandwidth <= max_limit)) + variant = j->data; /* get the lowest one in the valid range */ + else + variant = tmp; + break; + } - if (tmp->bandwidth > max_bandwidth) + if (adj_max_limit > DEFAULT_BANDWIDTH_LIMIT && adj_max_limit < tmp->bandwidth) continue; - if (((width > DEFAULT_ADAPTIVE_VARIANT) && (tmp->width > width)) || - ((height > DEFAULT_ADAPTIVE_VARIANT) && (tmp->height > height))) { - if (!variant) /* will be kept with the last one with the same bitrate */ + if (((width > DEFAULT_RESOLUTION_LIMIT) && (tmp->width > width)) || + ((height > DEFAULT_RESOLUTION_LIMIT) && (tmp->height > height))) { + if (adj_max_limit > DEFAULT_BANDWIDTH_LIMIT && !variant) { /* will be kept with the first one with the same bitrate */ variant = tmp; + } } else { variant = tmp; - GST_INFO("found %d, %d x %d", variant->bandwidth, variant->width, variant->height); + GST_DEBUG ("get this stream %d", variant->bandwidth); break; } } diff --git a/ext/hls/m3u8.h b/ext/hls/m3u8.h index 31d326c24..0d74f7d3b 100644 --- a/ext/hls/m3u8.h +++ b/ext/hls/m3u8.h @@ -232,10 +232,10 @@ struct _GstHLSMasterPlaylist GstHLSMasterPlaylist * gst_hls_master_playlist_new_from_data (gchar * data, const gchar * base_uri); #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION -GstHLSVariantStream * gst_hls_master_playlist_get_variant_for_max_limit (GstHLSMasterPlaylist *playlist, +GstHLSVariantStream * gst_hls_master_playlist_get_variant_for_bandwitdh_limit (GstHLSMasterPlaylist * playlist, GstHLSVariantStream * current_variant, - guint bitrate, gint bandwidth, - gint width, gint height); + guint bitrate, gchar * start_bandwidth, gint min_bandwidth, + gint max_bandwidth, gint width, gint height); #else GstHLSVariantStream * gst_hls_master_playlist_get_variant_for_bitrate (GstHLSMasterPlaylist * playlist, GstHLSVariantStream * current_variant, diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c index ebf26aa97..5634e2974 100644 --- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c +++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c @@ -159,6 +159,8 @@ enum PROP_CONNECTION_SPEED, PROP_BITRATE_LIMIT, #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION + PROP_START_BANDWIDTH, + PROP_MIN_BANDWIDTH, PROP_MAX_BANDWIDTH, PROP_MAX_WIDTH, PROP_MAX_HEIGHT, @@ -368,6 +370,13 @@ gst_adaptive_demux_set_property (GObject * object, guint prop_id, demux->bitrate_limit = g_value_get_float (value); break; #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION + case PROP_START_BANDWIDTH: + g_free(demux->start_bandwidth); + demux->start_bandwidth = g_strdup (g_value_get_string (value)); + break; + case PROP_MIN_BANDWIDTH: + demux->min_bandwidth = g_value_get_int (value); + break; case PROP_MAX_BANDWIDTH: demux->max_bandwidth = g_value_get_int (value); break; @@ -403,6 +412,15 @@ gst_adaptive_demux_get_property (GObject * object, guint prop_id, g_value_set_float (value, demux->bitrate_limit); break; #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION + case PROP_START_BANDWIDTH: + if (demux->start_bandwidth == NULL) + g_value_set_static_string (value, ""); + else + g_value_set_string (value, demux->start_bandwidth); + break; + case PROP_MIN_BANDWIDTH: + g_value_set_int (value, demux->min_bandwidth); + break; case PROP_MAX_BANDWIDTH: g_value_set_int (value, demux->max_bandwidth); break; @@ -459,25 +477,37 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION + g_object_class_install_property (gobject_class, PROP_START_BANDWIDTH, + g_param_spec_string ("start-bandwidth", "Start Bandwidth", + "Set bandwidth to use when the playback is started. (LOWEST, HIGHEST, AVERAGE or specific bandwidth value)", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_MIN_BANDWIDTH, + g_param_spec_int ("min-bandwidth", + "Min Bandwidth limit", + "Minimum limit of the available bandwidth to use when switching to alternates. (-1 = no limit)", + -1, G_MAXINT, DEFAULT_BANDWIDTH_LIMIT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAX_BANDWIDTH, g_param_spec_int ("max-bandwidth", "Max Bandwidth limit", - "Limit of the available bandwidth to use when switching to alternates. (-1 = no limit)", - -1, G_MAXINT, DEFAULT_ADAPTIVE_VARIANT, + "Maximum limit of the available bandwidth to use when switching to alternates. (-1 = no limit)", + -1, G_MAXINT, DEFAULT_BANDWIDTH_LIMIT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MAX_WIDTH, g_param_spec_int ("max-video-width", "Max video width limit", - "Limit of the available video width to use when switching to alternates. (-1 = no limit)", - -1, G_MAXINT, DEFAULT_ADAPTIVE_VARIANT, + "Maximum limit of the available video width to use when switching to alternates. (-1 = no limit)", + -1, G_MAXINT, DEFAULT_RESOLUTION_LIMIT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_MAX_HEIGHT, g_param_spec_int ("max-video-height", "Max video height limit", - "Limit of the available video height to use when switching to alternates. (-1 = no limit)", - -1, G_MAXINT, DEFAULT_ADAPTIVE_VARIANT, + "Maximum limit of the available video height to use when switching to alternates. (-1 = no limit)", + -1, G_MAXINT, DEFAULT_RESOLUTION_LIMIT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); #endif @@ -574,9 +604,11 @@ gst_adaptive_demux_init (GstAdaptiveDemux * demux, demux->bitrate_limit = DEFAULT_BITRATE_LIMIT; demux->connection_speed = DEFAULT_CONNECTION_SPEED; #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION - demux->max_bandwidth = DEFAULT_ADAPTIVE_VARIANT; - demux->max_width = DEFAULT_ADAPTIVE_VARIANT; - demux->max_height = DEFAULT_ADAPTIVE_VARIANT; + demux->start_bandwidth = NULL; + demux->min_bandwidth = DEFAULT_BANDWIDTH_LIMIT; + demux->max_bandwidth = DEFAULT_BANDWIDTH_LIMIT; + demux->max_width = DEFAULT_RESOLUTION_LIMIT; + demux->max_height = DEFAULT_RESOLUTION_LIMIT; #endif gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h index def5a7661..218b3dace 100644 --- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h +++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h @@ -94,7 +94,8 @@ G_BEGIN_DECLS #define DEFAULT_ADAPTIVE_TIMEOUT -1 #define PLAYLIST_ADAPTIVE_RETRY 3 #define PLAYLIST_ADAPTIVE_TIMEOUT 2 -#define DEFAULT_ADAPTIVE_VARIANT -1 +#define DEFAULT_BANDWIDTH_LIMIT -1 +#define DEFAULT_RESOLUTION_LIMIT -1 #endif typedef struct _GstAdaptiveDemuxStreamFragment GstAdaptiveDemuxStreamFragment; @@ -259,6 +260,8 @@ struct _GstAdaptiveDemux /* < private > */ GstAdaptiveDemuxPrivate *priv; #ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION + gchar *start_bandwidth; + gint min_bandwidth; gint max_bandwidth; gint max_width; gint max_height; diff --git a/packaging/gst-plugins-bad.spec b/packaging/gst-plugins-bad.spec index cf1b0d648..f0d544440 100644 --- a/packaging/gst-plugins-bad.spec +++ b/packaging/gst-plugins-bad.spec @@ -4,7 +4,7 @@ Name: gst-plugins-bad Version: 1.16.2 -Release: 6 +Release: 7 Summary: GStreamer Streaming-Media Framework Plug-Ins License: LGPL-2.0+ Group: Multimedia/Framework