GstContentComponentNode *cc_node = adp_set->ContentComponents->data;
lang = cc_node->lang;
}
+
+#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) {
GstActiveStream *active_stream = NULL;
GList *rep_list = NULL;
gint new_index;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GstAdaptiveDemux *adaptive_demux = GST_ADAPTIVE_DEMUX_CAST (stream->demux);
+#endif
GstDashDemux *demux = GST_DASH_DEMUX_CAST (stream->demux);
GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
gboolean ret = FALSE;
GST_DEBUG_OBJECT (stream->pad,
"Trying to change to bitrate: %" G_GUINT64_FORMAT, bitrate);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ /* get representation index with current max_bandwidth */
+ new_index = gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list,
+ (adaptive_demux->max_bandwidth > DEFAULT_ADAPTIVE_VARIANT)?(adaptive_demux->max_bandwidth):(bitrate),
+ adaptive_demux->max_width, adaptive_demux->max_height);
+#else
/* get representation index with current max_bandwidth */
new_index = gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, bitrate);
+#endif
/* if no representation has the required bandwidth, take the lowest one */
if (new_index == -1)
#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_string (xmlNode * a_node,
static void
gst_mpdparser_parse_representation_base_type (GstRepresentationBaseType **
pointer, xmlNode * a_node);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static void gst_mpdparser_parse_representation_node (GList ** list,
+ GList ** info, xmlNode * a_node, GstAdaptationSetNode * parent);
+#else
static void gst_mpdparser_parse_representation_node (GList ** list,
xmlNode * a_node, GstAdaptationSetNode * parent);
+#endif
static void 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 void
+gst_mpdparser_parse_representation_node (GList ** list, GList ** info, xmlNode * a_node,
+ GstAdaptationSetNode * parent)
+#else
static void
gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node,
GstAdaptationSetNode * parent)
+#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);
*list = g_list_append (*list, new_representation);
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
+ gst_mpdparser_parse_representation_node (&new_adap_set->Representations,
+ &new_adap_set->VariantInfo, cur_node, new_adap_set);
+#else
gst_mpdparser_parse_representation_node (&new_adap_set->Representations,
cur_node, new_adap_set);
+#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)
return best ? g_list_position (Representations, best) : -1;
}
+#endif
static GstSegmentListNode *
gst_mpd_client_fetch_external_segment_list (GstMpdClient * client,
(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);
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);
+#endif
gint gst_mpdparser_get_rep_idx_with_min_bandwidth (GList * Representations);
/* URL management */
return FALSE;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_element_post_message (GST_ELEMENT_CAST (hlsdemux),
+ gst_message_new_element (GST_OBJECT_CAST (hlsdemux),
+ gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME,
+ "video-variant-info", G_TYPE_POINTER, hlsdemux->client->main->variant_info, NULL)));
+#endif
+
/* If this playlist is a variant playlist, select the first one
* and update it */
if (gst_m3u8_client_has_variant_playlist (hlsdemux->client)) {
child = hlsdemux->client->main->current_variant->data;
GST_M3U8_CLIENT_UNLOCK (hlsdemux->client);
} else {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GList *tmp = gst_m3u8_client_get_playlist_for_max_limit (hlsdemux->client,
+ demux->connection_speed, demux->max_bandwidth, demux->max_width, demux->max_height);
+#else
GList *tmp = gst_m3u8_client_get_playlist_for_bitrate (hlsdemux->client,
demux->connection_speed);
-
+#endif
child = GST_M3U8 (tmp->data);
}
return FALSE;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ 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->client->main->variant_info, NULL)));
+#endif
+
/* If it's a live source, do not let the sequence number go beyond
* three fragments before the end of the list */
if (update == FALSE && demux->client->current &&
stream = adaptive_demux->streams->data;
previous_variant = demux->client->main->current_variant;
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ current_variant = gst_m3u8_client_get_playlist_for_max_limit (demux->client,
+ max_bitrate, adaptive_demux->max_bandwidth, adaptive_demux->max_width, adaptive_demux->max_height);
+#else
current_variant = gst_m3u8_client_get_playlist_for_bitrate (demux->client,
max_bitrate);
-
+#endif
GST_M3U8_CLIENT_LOCK (demux->client);
retry_failover_protection:
#include "m3u8.h"
#define GST_CAT_DEFAULT fragmented_debug
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define DEFAULT_ADAPTIVE_VARIANT -1
+#endif
#if !GLIB_CHECK_VERSION (2, 33, 4)
#define g_list_copy_deep gst_g_list_copy_deep
g_free (self->name);
g_free (self->codecs);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_list_free_full (self->variant_info, g_free);
+#endif
g_list_foreach (self->files, (GFunc) gst_m3u8_media_file_free, NULL);
g_list_free (self->files);
self->duration, self->sequence);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static GstM3U8VideoVariantInfo *
+gst_variant_info_copy(const GstM3U8VideoVariantInfo *self, gpointer user_data)
+{
+ GstM3U8VideoVariantInfo *var_info = NULL;
+ g_return_val_if_fail (self != NULL, NULL);
+
+ var_info = g_new0(GstM3U8VideoVariantInfo, 1);
+ if (!var_info) return NULL;
+ var_info->bandwidth = self->bandwidth;
+ var_info->width = self->width;
+ var_info->height = self->height;
+
+ return var_info;
+}
+#endif
+
static GstM3U8 *
_m3u8_copy (const GstM3U8 * self, GstM3U8 * parent)
{
dup->files =
g_list_copy_deep (self->files, (GCopyFunc) gst_m3u8_media_file_copy,
NULL);
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ dup->variant_info =
+ g_list_copy_deep(self->variant_info, (GCopyFunc) gst_variant_info_copy,
+ NULL);
+#endif
/* private */
dup->last_data = g_strdup (self->last_data);
dup->lists = g_list_copy_deep (self->lists, (GCopyFunc) _m3u8_copy, dup);
if (self->lists) {
gchar *top_variant_uri = NULL;
gboolean iframe = FALSE;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GList *l;
+#endif
if (!self->current_variant) {
top_variant_uri = GST_M3U8 (self->lists->data)->uri;
} else {
else
self->current_variant = g_list_find_custom (self->lists, top_variant_uri,
(GCompareFunc) _m3u8_compare_uri);
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ /* update variant stream info */
+ for (l = self->current_variant; l != NULL; l = l->next) {
+ GstM3U8 *data = l->data;
+ GstM3U8VideoVariantInfo *var_info = g_new0(GstM3U8VideoVariantInfo, 1);
+
+ GST_LOG ("stream 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;
+
+ self->variant_info = g_list_append(self->variant_info, var_info);
+ }
+#endif
}
/* calculate the start and end times of this media playlist. */
if (self->files) {
return ret;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+
+GList *
+gst_m3u8_client_get_playlist_for_max_limit (GstM3U8Client * client, guint bitrate, gint bandwidth, gint width, gint height)
+{
+ GList *list, *current_variant;
+// guint max_bandwidth = (bandwidth < 0)?(bitrate):((guint)bandwidth);
+ guint max_bandwidth = (bandwidth > DEFAULT_ADAPTIVE_VARIANT)?(bandwidth):(bitrate);
+
+ GST_M3U8_CLIENT_LOCK (client);
+
+ GST_WARNING("max list : %u, %d, [w]%d [h]%d", bitrate, bandwidth, width, height);
+
+ current_variant = list = g_list_first(client->main->current_variant);
+
+ for (; list; list = g_list_next (list)) {
+
+ if (height > DEFAULT_ADAPTIVE_VARIANT
+ && GST_M3U8 (list->data)->height > height)
+ continue;
+
+ if (width > DEFAULT_ADAPTIVE_VARIANT
+ && GST_M3U8 (list->data)->width > width)
+ continue;
+
+ if (GST_M3U8 (list->data)->bandwidth <= max_bandwidth)
+ current_variant = list;
+ }
+
+ GST_WARNING("selected variant %d %d %d", GST_M3U8 (current_variant->data)->bandwidth,
+ GST_M3U8 (current_variant->data)->width,
+ GST_M3U8 (current_variant->data)->height);
+
+ GST_M3U8_CLIENT_UNLOCK (client);
+
+ return current_variant;
+}
+
+#else
+
GList *
gst_m3u8_client_get_playlist_for_bitrate (GstM3U8Client * client, guint bitrate)
{
return current_variant;
}
+#endif
gchar *
uri_join (const gchar * uri1, const gchar * uri2)
value is three fragments */
#define GST_M3U8_LIVE_MIN_FRAGMENT_DISTANCE 3
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+typedef struct
+{
+ gint bandwidth;
+ gint width;
+ gint height;
+} GstM3U8VideoVariantInfo;
+#endif
+
struct _GstM3U8
{
gchar *uri; /* actually downloaded URI */
gchar *codecs;
#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
gint codec_count;
+ GList *variant_info; /* stream variant info */
#endif
gint width;
gint height;
gboolean gst_m3u8_client_has_main(GstM3U8Client * client);
gboolean gst_m3u8_client_has_variant_playlist(GstM3U8Client * client);
gboolean gst_m3u8_client_is_live(GstM3U8Client * client);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+GList * gst_m3u8_client_get_playlist_for_max_limit (GstM3U8Client * client,
+ guint bitrate, gint bandwidth, gint width, gint height);
+#else
GList * gst_m3u8_client_get_playlist_for_bitrate (GstM3U8Client * client,
guint bitrate);
+#endif
guint64 gst_m3u8_client_get_current_fragment_duration (GstM3U8Client * client);
PROP_LOOKBACK_FRAGMENTS,
PROP_CONNECTION_SPEED,
PROP_BITRATE_LIMIT,
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ PROP_MAX_BANDWIDTH,
+ PROP_MAX_WIDTH,
+ PROP_MAX_HEIGHT,
+#endif
PROP_LAST
};
case PROP_BITRATE_LIMIT:
demux->bitrate_limit = g_value_get_float (value);
break;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ case PROP_MAX_BANDWIDTH:
+ demux->max_bandwidth = g_value_get_int (value);
+ break;
+ case PROP_MAX_WIDTH:
+ demux->max_width = g_value_get_int (value);
+ break;
+ case PROP_MAX_HEIGHT:
+ demux->max_height = g_value_get_int (value);
+ break;
+#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_BITRATE_LIMIT:
g_value_set_float (value, demux->bitrate_limit);
break;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ case PROP_MAX_BANDWIDTH:
+ g_value_set_int (value, demux->max_bandwidth);
+ break;
+ case PROP_MAX_WIDTH:
+ g_value_set_int (value, demux->max_width);
+ break;
+ case PROP_MAX_HEIGHT:
+ g_value_set_int (value, demux->max_height);
+ break;
+#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
0, 1, DEFAULT_BITRATE_LIMIT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ 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,
+ 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,
+ 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,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
gstelement_class->change_state = gst_adaptive_demux_change_state;
gstbin_class->handle_message = gst_adaptive_demux_handle_message;
demux->is_dashstreaming = FALSE;
demux->dash_error_count = 0;
demux->dash_newest_segment = NULL;
+ 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);
* Since: 1.6
*/
#define GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME "adaptive-streaming-statistics"
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME "adaptive-streaming-variant"
+#endif
#define GST_MANIFEST_GET_LOCK(d) (&(GST_ADAPTIVE_DEMUX_CAST(d)->manifest_lock))
#define GST_MANIFEST_LOCK(d) (g_mutex_lock (GST_MANIFEST_GET_LOCK (d)))
#define DEFAULT_ADAPTIVE_TIMEOUT -1
#define PLAYLIST_ADAPTIVE_RETRY 3
#define PLAYLIST_ADAPTIVE_TIMEOUT 2
+#define DEFAULT_ADAPTIVE_VARIANT -1
#endif
typedef struct _GstAdaptiveDemuxStreamFragment GstAdaptiveDemuxStreamFragment;
#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
guint dash_error_count;
gchar *dash_newest_segment;
+ gint max_bandwidth;
+ gint max_width;
+ gint max_height;
#endif
};
Name: gst-plugins-bad
Version: 1.6.1
-Release: 14
+Release: 15
Summary: GStreamer Streaming-Media Framework Plug-Ins
License: LGPL-2.0+
Group: Multimedia/Framework