caps = gst_dash_demux_get_input_caps (demux, active_stream);
GST_LOG_OBJECT (demux, "Creating stream %d %" GST_PTR_FORMAT, i, caps);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ caps = gst_caps_make_writable (caps);
+ gst_caps_set_simple (caps, "adaptive_stream", G_TYPE_BOOLEAN, TRUE,
+ "dash_stream", G_TYPE_BOOLEAN, TRUE, NULL);
+ GST_LOG_OBJECT (demux,
+ "*** modified caps for dash streaming = %" GST_PTR_FORMAT, caps);
+#endif
if (active_stream->cur_adapt_set) {
GstAdaptationSetNode *adp_set = active_stream->cur_adapt_set;
}
}
}
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (active_stream->mimeType == GST_STREAM_VIDEO
+ && adp_set->VariantInfo != NULL) {
+ GST_LOG_OBJECT (demux,
+ "post msg about video active stream variant info");
+
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_element (GST_OBJECT_CAST (demux),
+ gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME,
+ "video-variant-info", G_TYPE_POINTER, adp_set->VariantInfo,
+ NULL)));
+ }
+#endif
}
if (lang) {
bitrate = MIN (demux->max_bitrate, bitrate);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ bitrate = (base_demux->max_bandwidth > DEFAULT_ADAPTIVE_VARIANT)?
+ (guint64)(base_demux->max_bandwidth):(bitrate);
+ GST_DEBUG_OBJECT (stream->pad,
+ "Trying to change to bitrate under : %" G_GUINT64_FORMAT, bitrate);
+
+ /* get representation index with current max_bandwidth */
+ if ((base_demux->segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) ||
+ ABS (base_demux->segment.rate) <= 1.0) {
+ new_index =
+ gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, (gint)bitrate,
+ demux->max_video_width, demux->max_video_height);
+ } else {
+ new_index =
+ gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list,
+ (gint)(bitrate / ABS (base_demux->segment.rate)), demux->max_video_width,
+ demux->max_video_height);
+ }
+#else
/* get representation index with current max_bandwidth */
if ((base_demux->segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) ||
ABS (base_demux->segment.rate) <= 1.0) {
demux->max_video_height, demux->max_video_framerate_n,
demux->max_video_framerate_d);
}
+#endif
/* if no representation has the required bandwidth, take the lowest one */
if (new_index == -1)
/*
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 *
gst_adaptive_demux_get_client_now_utc (GST_ADAPTIVE_DEMUX_CAST (demux));
if (!value) {
GstFragment *download;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GST_DEBUG_OBJECT (demux, "Fetching current time from %s",
+ urls[clock_drift->selected_url]);
+ download = gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX_CAST
+ (demux)->downloader, urls[clock_drift->selected_url], NULL, NULL, NULL,
+ DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT, TRUE, FALSE, TRUE,
+ NULL);
+#else
gint64 range_start = 0, range_end = -1;
GST_DEBUG_OBJECT (demux, "Fetching current time from %s",
urls[clock_drift->selected_url]);
gst_uri_downloader_fetch_uri_with_range (GST_ADAPTIVE_DEMUX_CAST
(demux)->downloader, urls[clock_drift->selected_url], NULL, TRUE, TRUE,
TRUE, range_start, range_end, NULL);
+#endif
if (download) {
if (method == GST_MPD_UTCTIMING_TYPE_HTTP_HEAD && download->headers) {
value = gst_dash_demux_parse_http_head (clock_drift, download);
#include "gstdash_debug.h"
#define GST_CAT_DEFAULT gst_dash_demux_debug
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define DEFAULT_ADAPTIVE_VARIANT -1
+#endif
/* Property parsing */
static gboolean gst_mpdparser_get_xml_prop_validated_string (xmlNode * a_node,
static void
gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
pointer, xmlNode * a_node);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static gboolean gst_mpdparser_parse_representation_node (GList ** list,
+ GList ** info, xmlNode * a_node, GstAdaptationSetNode * parent,
+ GstPeriodNode * period_node);
+#else
static gboolean gst_mpdparser_parse_representation_node (GList ** list,
xmlNode * a_node, GstAdaptationSetNode * parent,
GstPeriodNode * period_node);
+#endif
static gboolean gst_mpdparser_parse_adaptation_set_node (GList ** list,
xmlNode * a_node, GstPeriodNode * parent);
static void gst_mpdparser_parse_subset_node (GList ** list, xmlNode * a_node);
GstMPDUTCTimingType method;
};
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+struct GstVideoVariantInfo
+{
+ gint bandwidth;
+ gint width;
+ gint height;
+};
+#endif
+
static const struct GstMpdParserUtcTimingMethod
gst_mpdparser_utc_timing_methods[] = {
{"urn:mpeg:dash:utc:ntp:2014", GST_MPD_UTCTIMING_TYPE_NTP},
}
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static gboolean
+gst_mpdparser_parse_representation_node (GList ** list, GList ** info, xmlNode * a_node,
+ GstAdaptationSetNode * parent, GstPeriodNode * period_node)
+#else
static gboolean
gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node,
GstAdaptationSetNode * parent, GstPeriodNode * period_node)
+#endif
{
xmlNode *cur_node;
GstRepresentationNode *new_representation;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ struct GstVideoVariantInfo *variant_info;
+ gchar *mime = NULL;
+#endif
new_representation = g_slice_new0 (GstRepresentationNode);
gst_mpdparser_parse_representation_base_type
(&new_representation->RepresentationBase, a_node);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ mime = new_representation->RepresentationBase->mimeType;
+ if (strncmp_ext(mime, "video") == 0) {
+ variant_info = g_new0(struct GstVideoVariantInfo, 1);
+
+ GST_LOG ("video variant info %d, %d x %d", new_representation->bandwidth,
+ new_representation->RepresentationBase->width,
+ new_representation->RepresentationBase->height);
+
+ variant_info->bandwidth = new_representation->bandwidth;
+ variant_info->width = new_representation->RepresentationBase->width;
+ variant_info->height = new_representation->RepresentationBase->height;
+
+ *info = g_list_append(*info, variant_info);
+ }
+#endif
+
/* explore children nodes */
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
if (xmlStrcmp (cur_node->name, (xmlChar *) "Representation") == 0) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (!gst_mpdparser_parse_representation_node
+ (&new_adap_set->Representations, &new_adap_set->VariantInfo, cur_node, new_adap_set, parent))
+ goto error;
+#else
if (!gst_mpdparser_parse_representation_node
(&new_adap_set->Representations, cur_node, new_adap_set, parent))
goto error;
+#endif
}
}
}
return lowest ? g_list_position (Representations, lowest) : -1;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+gint
+gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
+ gint max_bandwidth, gint max_video_width, gint max_video_height)
+{
+ GList *list = NULL, *best = NULL, *min_rep = NULL;
+ GstRepresentationNode *representation;
+ gint best_bandwidth = 0, min_bandwidth = 0;
+
+ GST_DEBUG ("[b]%d [w]%d [h]%d", max_bandwidth, max_video_width, max_video_height);
+
+ if (Representations == NULL)
+ return -1;
+
+ for (list = g_list_first (Representations); list; list = g_list_next (list)) {
+ representation = (GstRepresentationNode *) list->data;
+ if (!representation)
+ continue;
+
+ if (max_video_width > DEFAULT_ADAPTIVE_VARIANT
+ && representation->RepresentationBase->width > max_video_width)
+ continue;
+
+ if (max_video_height > DEFAULT_ADAPTIVE_VARIANT
+ && representation->RepresentationBase->height > max_video_height)
+ continue;
+
+ if (representation->bandwidth <= max_bandwidth &&
+ representation->bandwidth > best_bandwidth) {
+ best = list;
+ best_bandwidth = representation->bandwidth;
+ } else {
+ if ((!min_rep) || (min_bandwidth == 0) ||
+ (min_bandwidth >= representation->bandwidth)) {
+ min_rep = list;
+ min_bandwidth = representation->bandwidth;
+ }
+ }
+ }
+
+ if (!best)
+ best = min_rep;
+
+ return best ? g_list_position (Representations, best) : -1;
+}
+#else
gint
gst_mpdparser_get_rep_idx_with_max_bandwidth (GList * Representations,
gint max_bandwidth, gint max_video_width, gint max_video_height, gint
return best ? g_list_position (Representations, best) : -1;
}
-
+#endif
static GstSegmentListNode *
gst_mpd_client_fetch_external_segment_list (GstMpdClient * client,
GstPeriodNode * Period,
gst_uri_unref (base_uri);
gst_uri_unref (uri);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download =
+ gst_uri_downloader_fetch_uri (client->downloader,
+ uri_string, client->mpd_uri, NULL, NULL, DEFAULT_ADAPTIVE_RETRY,
+ DEFAULT_ADAPTIVE_TIMEOUT, TRUE, FALSE, TRUE, &err);
+#else
download =
gst_uri_downloader_fetch_uri (client->downloader,
uri_string, client->mpd_uri, TRUE, FALSE, TRUE, &err);
+#endif
g_free (uri_string);
if (!download) {
(GDestroyNotify) gst_mpdparser_free_representation_node);
g_list_free_full (adaptation_set_node->ContentComponents,
(GDestroyNotify) gst_mpdparser_free_content_component_node);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_list_free_full (adaptation_set_node->VariantInfo,
+ (GDestroyNotify) g_free);
+#endif
if (adaptation_set_node->xlink_href)
xmlFree (adaptation_set_node->xlink_href);
g_slice_free (GstAdaptationSetNode, adaptation_set_node);
gst_uri_unref (base_uri);
gst_uri_unref (uri);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download =
+ gst_uri_downloader_fetch_uri (client->downloader,
+ uri_string, client->mpd_uri, NULL, NULL, DEFAULT_ADAPTIVE_RETRY,
+ DEFAULT_ADAPTIVE_TIMEOUT, TRUE, FALSE, TRUE, &err);
+#else
download =
gst_uri_downloader_fetch_uri (client->downloader,
uri_string, client->mpd_uri, TRUE, FALSE, TRUE, &err);
+#endif
g_free (uri_string);
if (!download) {
gst_uri_unref (base_uri);
gst_uri_unref (uri);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download =
+ gst_uri_downloader_fetch_uri (client->downloader,
+ uri_string, client->mpd_uri, NULL, NULL, DEFAULT_ADAPTIVE_RETRY,
+ DEFAULT_ADAPTIVE_TIMEOUT, TRUE, FALSE, TRUE, &err);
+#else
download =
gst_uri_downloader_fetch_uri (client->downloader,
uri_string, client->mpd_uri, TRUE, FALSE, TRUE, &err);
+#endif
g_free (uri_string);
if (!download) {
GDateTime *gdt2;
GstDateTime *rv;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_return_val_if_fail (t1 != NULL, NULL);
+ gdt = gst_date_time_to_g_date_time (t1);
+ g_return_val_if_fail (gdt != NULL, NULL);
+ gdt2 = g_date_time_add (gdt, usecs);
+ g_return_val_if_fail (gdt2 != NULL, NULL);
+#else
g_assert (t1 != NULL);
gdt = gst_date_time_to_g_date_time (t1);
g_assert (gdt != NULL);
gdt2 = g_date_time_add (gdt, usecs);
g_assert (gdt2 != NULL);
+#endif
g_date_time_unref (gdt);
rv = gst_date_time_new_from_g_date_time (gdt2);
#define GST_MPD_CLIENT_LOCK(c) g_mutex_lock (&c->lock);
#define GST_MPD_CLIENT_UNLOCK(c) g_mutex_unlock (&c->lock);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define DEFAULT_ADAPTIVE_RETRY -1
+#define DEFAULT_ADAPTIVE_TIMEOUT -1
+#endif
+
#define GST_MPD_DURATION_NONE ((guint64)-1)
typedef enum
GList *Representations;
/* list of ContentComponent nodes */
GList *ContentComponents;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ /* stream variant information */
+ GList *VariantInfo;
+#endif
gchar *xlink_href;
GstXLinkActuate actuate;
gboolean gst_mpd_client_has_previous_period (GstMpdClient * client);
/* Representation selection */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint max_bandwidth, gint max_video_width, gint max_video_height);
+#else
gint gst_mpdparser_get_rep_idx_with_max_bandwidth (GList *Representations, gint max_bandwidth, gint max_video_width, gint max_video_height, gint max_video_framerate_n, gint max_video_framerate_d);
+#endif
gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations);
/* URL management */
if (hlsdemux->current_variant == variant || variant == NULL)
return;
+ GST_INFO_OBJECT (hlsdemux, "%s variant %d, %d x %d", variant->name,
+ variant->bandwidth, variant->width, variant->height);
if (hlsdemux->current_variant != NULL) {
gint i;
}
/* 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 = hlsdemux->master->default_variant;
+ }
+#else
if (demux->connection_speed == 0) {
variant = hlsdemux->master->default_variant;
} else {
gst_hls_master_playlist_get_variant_for_bitrate (hlsdemux->master,
NULL, demux->connection_speed);
}
-
- if (variant) {
- GST_INFO_OBJECT (hlsdemux, "selected %s", variant->name);
- gst_hls_demux_set_current_variant (hlsdemux, variant); // FIXME: inline?
- }
+#endif
+ if (variant)
+ gst_hls_demux_set_current_variant (hlsdemux, variant);
/* get the selected media playlist (unless the inital list was one already) */
if (!hlsdemux->master->is_simple) {
}
GST_INFO_OBJECT (demux, "Fetching key %s", key_url);
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ key_fragment =
+ gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX (demux)->downloader,
+ key_url, referer, GST_ADAPTIVE_DEMUX (demux)->user_agent,
+ GST_ADAPTIVE_DEMUX (demux)->cookies, DEFAULT_ADAPTIVE_RETRY,
+ DEFAULT_ADAPTIVE_TIMEOUT, FALSE, FALSE, allow_cache, &err);
+#else
key_fragment =
gst_uri_downloader_fetch_uri (GST_ADAPTIVE_DEMUX (demux)->downloader,
key_url, referer, FALSE, FALSE, allow_cache, &err);
+#endif
if (key_fragment == NULL) {
GST_WARNING_OBJECT (demux, "Failed to download key to decrypt data: %s",
gchar *uri = media->uri;
main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
download =
gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
+ adaptive_demux->user_agent, adaptive_demux->cookies, DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT,
TRUE, TRUE, TRUE, err);
-
+#else
+ download =
+ gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
+ TRUE, TRUE, TRUE, err);
+#endif
if (download == NULL)
return FALSE;
retry:
uri = gst_m3u8_get_uri (demux->current_variant->m3u8);
main_uri = gst_adaptive_demux_get_manifest_ref_uri (adaptive_demux);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download =
+ gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
+ adaptive_demux->user_agent, adaptive_demux->cookies, DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT,
+ TRUE, TRUE, TRUE, err);
+#else
download =
gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
TRUE, TRUE, TRUE, err);
+#endif
if (download == NULL) {
gchar *base_uri;
GST_INFO_OBJECT (demux,
"Updating playlist %s failed, attempt to refresh variant playlist %s",
uri, main_uri);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download =
+ gst_uri_downloader_fetch_uri (adaptive_demux->downloader, main_uri, NULL,
+ adaptive_demux->user_agent, adaptive_demux->cookies, DEFAULT_ADAPTIVE_RETRY, DEFAULT_ADAPTIVE_TIMEOUT,
+ TRUE, TRUE, TRUE, err);
+#else
download =
gst_uri_downloader_fetch_uri (adaptive_demux->downloader,
main_uri, NULL, TRUE, TRUE, TRUE, err);
+#endif
if (download == NULL) {
g_free (uri);
return FALSE;
GST_M3U8_CLIENT_UNLOCK (demux->client);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GST_DEBUG_OBJECT (demux, "post variant info message");
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_element (GST_OBJECT_CAST (demux),
+ gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME,
+ "video-variant-info", G_TYPE_POINTER,
+ demux->master->variant_info, NULL)));
+#endif
+
return TRUE;
}
stream = adaptive_demux->streams->data;
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);
+#else
new_variant =
gst_hls_master_playlist_get_variant_for_bitrate (demux->master,
demux->current_variant, max_bitrate);
-
+#endif
GST_M3U8_CLIENT_LOCK (demux->client);
retry_failover_protection:
#include "m3u8.h"
#define GST_CAT_DEFAULT hls_debug
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define DEFAULT_ADAPTIVE_VARIANT -1
+#endif
static GstM3U8MediaFile *gst_m3u8_media_file_new (gchar * uri,
gchar * title, GstClockTime duration, guint sequence);
}
}
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;
(GDestroyNotify) gst_hls_variant_stream_unref);
g_list_free_full (playlist->iframe_variants,
(GDestroyNotify) gst_hls_variant_stream_unref);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_list_free_full (playlist->variant_info, g_free);
+#endif
if (playlist->default_variant)
gst_hls_variant_stream_unref (playlist->default_variant);
g_free (playlist->last_data);
g_list_length (playlist->variants),
g_list_length (playlist->iframe_variants));
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GList *v = (playlist->iframe_variants)?(playlist->iframe_variants):(playlist->variants);
+
+ /* update variant stream info */
+ for (; v != NULL; v = v->next) {
+ GstHLSVariantStream *data = v->data;
+ GstM3U8VideoVariantInfo *var_info = g_new0 (GstM3U8VideoVariantInfo, 1);
+
+ GST_LOG ("variant info %d, %d x %d", data->bandwidth, data->width,
+ data->height);
+ var_info->bandwidth = data->bandwidth;
+ var_info->width = data->width;
+ var_info->height = data->height;
+
+ playlist->variant_info = g_list_append (playlist->variant_info, var_info);
+ }
+#endif
return playlist;
}
return match->data;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+GstHLSVariantStream *
+gst_hls_master_playlist_get_variant_for_max_limit (GstHLSMasterPlaylist *
+ playlist, GstHLSVariantStream * current_variant, guint bitrate, gint bandwidth, gint width, gint height)
+{
+ GstHLSVariantStream *tmp = current_variant;
+ GstHLSVariantStream *variant = NULL;
+ GList *l;
+ guint max_bandwidth = (bandwidth > DEFAULT_ADAPTIVE_VARIANT)?(guint)(bandwidth):(bitrate);
+
+ GST_INFO("max limit : %u, %d, [w]%d [h]%d", bitrate, bandwidth, width, height);
+
+ /* variant lists are sorted low to high, so iterate from highest to lowest */
+ if (current_variant == NULL || !current_variant->iframe)
+ l = g_list_last (playlist->variants); /* highest */
+ else
+ l = g_list_last (playlist->iframe_variants);
+
+ for (; l; l = g_list_previous(l)) {
+ tmp = l->data;
+
+ if (tmp->bandwidth > max_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 */
+ variant = tmp;
+ } else {
+ variant = tmp;
+ GST_INFO("found %d, %d x %d", variant->bandwidth, variant->width, variant->height);
+ break;
+ }
+ }
+
+ return (variant)?(variant):(tmp);
+}
+
+#else
GstHLSVariantStream *
gst_hls_master_playlist_get_variant_for_bitrate (GstHLSMasterPlaylist *
playlist, GstHLSVariantStream * current_variant, guint bitrate)
/* variant lists are sorted low to high, so iterate from highest to lowest */
if (current_variant == NULL || !current_variant->iframe)
- l = g_list_last (playlist->variants);
+ l = g_list_last (playlist->variants); /* highest */
else
l = g_list_last (playlist->iframe_variants);
return variant;
}
+#endif
GstHLSVariantStream *
gst_hls_master_playlist_get_matching_variant (GstHLSMasterPlaylist * playlist,
GList *media[GST_HLS_N_MEDIA_TYPES];
};
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+typedef struct
+{
+ gint bandwidth;
+ gint width;
+ gint height;
+} GstM3U8VideoVariantInfo;
+#endif
+
GstHLSVariantStream * gst_hls_variant_stream_ref (GstHLSVariantStream * stream);
void gst_hls_variant_stream_unref (GstHLSVariantStream * stream);
/* Available variant streams, sorted by bitrate (low -> high) */
GList *variants;
GList *iframe_variants;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GList *variant_info; /* stream variant info */
+#endif
GstHLSVariantStream *default_variant; /* first in the list */
gint version; /* EXT-X-VERSION */
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 * current_variant,
+ guint bitrate, gint bandwidth,
+ gint width, gint height);
+#else
GstHLSVariantStream * gst_hls_master_playlist_get_variant_for_bitrate (GstHLSMasterPlaylist * playlist,
GstHLSVariantStream * current_variant,
guint bitrate);
+#endif
GstHLSVariantStream * gst_hls_master_playlist_get_matching_variant (GstHLSMasterPlaylist * playlist,
GstHLSVariantStream * current_variant);
/* Properties */
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;
+#endif
gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
}
return result;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static gboolean
+gst_adaptive_demux_check_http_header (GQuark field_id, const GValue * value,
+ gpointer data)
+{
+ GstAdaptiveDemux *demux = GST_ADAPTIVE_DEMUX_CAST (data);
+
+ if (value
+ && g_ascii_strcasecmp (g_quark_to_string (field_id), "User-Agent") == 0) {
+ if (demux->user_agent)
+ g_free (demux->user_agent);
+ demux->user_agent = g_value_dup_string (value);
+ GST_INFO_OBJECT (demux, "User-Agent : %s",
+ (demux->user_agent) ? (demux->user_agent) : NULL);
+ }
+
+ if (value
+ && g_ascii_strcasecmp (g_quark_to_string (field_id), "Set-Cookie") == 0) {
+ guint i = 0;
+ gchar **cookies =
+ (gchar **) g_malloc0 ((gst_value_array_get_size (value) +
+ 1) * sizeof (gchar *));
+
+ for (i = 0; i < gst_value_array_get_size (value); i++) {
+ GST_INFO_OBJECT (demux, "Cookie : %s",
+ g_value_get_string (gst_value_array_get_value (value, i)));
+ cookies[i] = g_value_dup_string (gst_value_array_get_value (value, i));
+ }
+ cookies[i] = NULL;
+ if (demux->cookies)
+ g_strfreev (demux->cookies);
+ demux->cookies = g_strdupv (cookies);
+ g_strfreev (cookies);
+ }
+ return TRUE;
+}
+#endif
+
static gboolean
gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent,
GstEvent * event)
/* Swallow newsegments, we'll push our own */
gst_event_unref (event);
return TRUE;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY:{
+ const GstStructure *structure;
+ GstStructure *req_headers = NULL;
+ GstStructure *res_headers = NULL;
+
+ structure = gst_event_get_structure (event);
+ if (gst_structure_has_name (structure, "http-headers")) {
+ if (gst_structure_has_field (structure, "request-headers")) {
+ gst_structure_get (structure, "request-headers", GST_TYPE_STRUCTURE,
+ &req_headers, NULL);
+ gst_structure_foreach (req_headers,
+ gst_adaptive_demux_check_http_header, demux);
+ gst_structure_free (req_headers);
+ }
+ if (gst_structure_has_field (structure, "response-headers")) {
+ gst_structure_get (structure, "response-headers", GST_TYPE_STRUCTURE,
+ &res_headers, NULL);
+ gst_structure_foreach (res_headers,
+ gst_adaptive_demux_check_http_header, demux);
+ gst_structure_free (res_headers);
+ }
+ }
+ break;
+ }
+#endif
+
default:
break;
}
g_free (demux->manifest_base_uri);
demux->manifest_uri = NULL;
demux->manifest_base_uri = NULL;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (demux->user_agent)
+ g_free (demux->user_agent);
+ if (demux->cookies)
+ g_strfreev (demux->cookies);
+ demux->user_agent = NULL;
+ demux->cookies = NULL;
+#endif
gst_adapter_clear (demux->priv->input_adapter);
demux->priv->have_manifest = FALSE;
GST_MANIFEST_UNLOCK (demux);
break;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ case GST_QUERY_CUSTOM:{
+ /* Let decoder(which can not support DRC automatically) know the current streaming mode */
+
+ const GstStructure *s;
+ s = gst_query_get_structure (query);
+
+ if (gst_structure_has_name (s, "GstAdaptiveStreaming")) {
+ GValue value = { 0, };
+ GST_DEBUG_OBJECT (demux, "custom query to check adaptive streaming");
+
+ g_value_init (&value, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&value, TRUE);
+ gst_structure_set_value ((GstStructure *) s, "adaptive-streaming",
+ &value);
+
+ g_value_set_boolean (&value, gst_adaptive_demux_is_live (demux));
+ gst_structure_set_value ((GstStructure *) s, "is-live", &value);
+
+ ret = TRUE;
+ } else {
+ GST_DEBUG_OBJECT (demux, "Unsupported query");
+ ret = FALSE;
+ }
+ break;
+ }
+#endif
default:
/* Don't forward queries upstream because of the special nature of this
* "demuxer", which relies on the upstream element only to be fed
GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
if (G_UNLIKELY (stream->pending_caps)) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_caps_make_writable (stream->pending_caps);
+ if (gst_adaptive_demux_is_live (demux)) {
+ gst_caps_set_simple (stream->pending_caps, "is_live", G_TYPE_BOOLEAN,
+ TRUE, NULL);
+ } else {
+ gst_caps_set_simple (stream->pending_caps, "is_live", G_TYPE_BOOLEAN,
+ FALSE, NULL);
+ }
+#endif
pending_caps = gst_event_new_caps (stream->pending_caps);
gst_caps_unref (stream->pending_caps);
stream->pending_caps = NULL;
g_object_set (uri_handler, "compress", FALSE, NULL);
if (g_object_class_find_property (gobject_class, "keep-alive"))
g_object_set (uri_handler, "keep-alive", TRUE, NULL);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (g_object_class_find_property (gobject_class, "user-agent")
+ && (demux->user_agent))
+ g_object_set (stream->src, "user-agent", demux->user_agent, NULL);
+ if (g_object_class_find_property (gobject_class, "cookies")
+ && (demux->cookies))
+ g_object_set (stream->src, "cookies", demux->cookies, NULL);
+ #endif
if (g_object_class_find_property (gobject_class, "extra-headers")) {
if (referer || refresh || !allow_cache) {
GstStructure *extra_headers = gst_structure_new_empty ("headers");
GstFlowReturn ret;
GError *error = NULL;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download = gst_uri_downloader_fetch_uri (demux->downloader,
+ demux->manifest_uri, NULL, demux->user_agent, demux->cookies,
+ PLAYLIST_ADAPTIVE_RETRY, PLAYLIST_ADAPTIVE_TIMEOUT, TRUE, TRUE, TRUE,
+ NULL);
+#else
download = gst_uri_downloader_fetch_uri (demux->downloader,
demux->manifest_uri, NULL, TRUE, TRUE, TRUE, &error);
+#endif
if (download) {
g_free (demux->manifest_uri);
g_free (demux->manifest_base_uri);
#define GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT GST_FLOW_CUSTOM_SUCCESS_1
#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define DEFAULT_ADAPTIVE_RETRY -1
+#define DEFAULT_ADAPTIVE_TIMEOUT -1
+#define PLAYLIST_ADAPTIVE_RETRY 3
+#define PLAYLIST_ADAPTIVE_TIMEOUT 2
#define DEFAULT_ADAPTIVE_VARIANT -1
#endif
gchar *manifest_uri;
gchar *manifest_base_uri;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gchar *user_agent;
+ gchar **cookies;
+#endif
/* Properties */
gfloat bitrate_limit; /* limit of the available bitrate to use */
downloader->priv->urisrc = NULL;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static gboolean
+gst_uri_downloader_set_uri (GstUriDownloader * downloader, const gchar * uri,
+ const gchar * referer, gchar* user_agent, gchar** cookies, gint max_retry , gint timeout , gboolean compress, gboolean refresh,
+ gboolean allow_cache)
+#else
static gboolean
gst_uri_downloader_set_uri (GstUriDownloader * downloader, const gchar * uri,
const gchar * referer, gboolean compress,
gboolean refresh, gboolean allow_cache)
+#endif
{
GstPad *pad;
GObjectClass *gobject_class;
g_object_set (downloader->priv->urisrc, "compress", compress, NULL);
if (g_object_class_find_property (gobject_class, "keep-alive"))
g_object_set (downloader->priv->urisrc, "keep-alive", TRUE, NULL);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (user_agent && g_object_class_find_property (gobject_class, "user-agent"))
+ g_object_set (downloader->priv->urisrc, "user-agent", user_agent, NULL);
+ if (cookies && g_object_class_find_property (gobject_class, "cookies"))
+ g_object_set (downloader->priv->urisrc, "cookies", cookies, NULL);
+
+ if ((max_retry != -1)&&(g_object_class_find_property (gobject_class, "retries")))
+ g_object_set (downloader->priv->urisrc, "retries", max_retry, NULL);
+ if ((timeout != -1)&&(g_object_class_find_property (gobject_class, "timeout")))
+ g_object_set (downloader->priv->urisrc, "timeout", timeout, NULL);
+#endif
if (g_object_class_find_property (gobject_class, "extra-headers")) {
if (referer || refresh || !allow_cache) {
GstStructure *extra_headers = gst_structure_new_empty ("headers");
}
return FALSE;
}
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+GstFragment *
+gst_uri_downloader_fetch_uri (GstUriDownloader * downloader,
+ const gchar * uri, const gchar * referer, gchar* user_agent, gchar** cookies, gint max_retry , gint timeout , gboolean compress,
+ gboolean refresh, gboolean allow_cache, GError ** err)
+{
+ return gst_uri_downloader_fetch_uri_with_range (downloader, uri,
+ referer, user_agent, cookies, max_retry, timeout, compress, refresh, allow_cache, 0, -1, err);
+}
+#else
GstFragment *
gst_uri_downloader_fetch_uri (GstUriDownloader * downloader,
const gchar * uri, const gchar * referer, gboolean compress,
return gst_uri_downloader_fetch_uri_with_range (downloader, uri,
referer, compress, refresh, allow_cache, 0, -1, err);
}
-
+#endif
/**
* gst_uri_downloader_fetch_uri_with_range:
* @downloader: the #GstUriDownloader
*
* Returns the downloaded #GstFragment
*/
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+GstFragment *
+gst_uri_downloader_fetch_uri_with_range (GstUriDownloader *
+ downloader, const gchar * uri, const gchar * referer, gchar* user_agent, gchar** cookies, gint max_retry , gint timeout , gboolean compress,
+ gboolean refresh, gboolean allow_cache,
+ gint64 range_start, gint64 range_end, GError ** err)
+#else
GstFragment *
gst_uri_downloader_fetch_uri_with_range (GstUriDownloader *
downloader, const gchar * uri, const gchar * referer, gboolean compress,
gboolean refresh, gboolean allow_cache,
gint64 range_start, gint64 range_end, GError ** err)
+#endif
{
GstStateChangeReturn ret;
GstFragment *download = NULL;
GST_DEBUG_OBJECT (downloader, "Cancelled, aborting fetch");
goto quit;
}
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (!gst_uri_downloader_set_uri (downloader, uri, referer, user_agent, cookies, max_retry, timeout ,compress, refresh,
+ allow_cache)) {
+ GST_WARNING_OBJECT (downloader, "Failed to set URI");
+ goto quit;
+ }
+#else
if (!gst_uri_downloader_set_uri (downloader, uri, referer, compress, refresh,
allow_cache)) {
GST_WARNING_OBJECT (downloader, "Failed to set URI");
goto quit;
}
-
+#endif
gst_bus_set_flushing (downloader->priv->bus, FALSE);
if (downloader->priv->download)
g_object_unref (downloader->priv->download);
GstUriDownloader * gst_uri_downloader_new (void);
void gst_uri_downloader_set_parent (GstUriDownloader * downloader, GstElement * parent);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+GstFragment * gst_uri_downloader_fetch_uri (GstUriDownloader * downloader, const gchar * uri, const gchar * referer, gchar* user_agent, gchar** cookies, gint max_retry , gint timeout , gboolean compress, gboolean refresh, gboolean allow_cache, GError ** err);
+GstFragment * gst_uri_downloader_fetch_uri_with_range (GstUriDownloader * downloader, const gchar * uri, const gchar * referer, gchar* user_agent, gchar** cookies, gint max_retry , gint timeout , gboolean compress, gboolean refresh, gboolean allow_cache, gint64 range_start, gint64 range_end, GError ** err);
+#else
GstFragment * gst_uri_downloader_fetch_uri (GstUriDownloader * downloader, const gchar * uri, const gchar * referer, gboolean compress, gboolean refresh, gboolean allow_cache, GError ** err);
GstFragment * gst_uri_downloader_fetch_uri_with_range (GstUriDownloader * downloader, const gchar * uri, const gchar * referer, gboolean compress, gboolean refresh, gboolean allow_cache, gint64 range_start, gint64 range_end, GError ** err);
+#endif
void gst_uri_downloader_reset (GstUriDownloader *downloader);
void gst_uri_downloader_cancel (GstUriDownloader *downloader);
void gst_uri_downloader_free (GstUriDownloader *downloader);