#define DEFAULT_BANDWIDTH_USAGE 0.8 /* 0 to 1 */
#define DEFAULT_MAX_BITRATE 24000000 /* in bit/s */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \
+ ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \
+ (r < 0 && stop_type != GST_SEEK_TYPE_NONE))
+#endif
+
/* Clock drift compensation for live streams */
#define SLOW_CLOCK_UPDATE_INTERVAL (1000000 * 30 * 60) /* 30 minutes */
#define FAST_CLOCK_UPDATE_INTERVAL (1000000 * 30) /* 30 seconds */
stream);
static void gst_dash_demux_advance_period (GstAdaptiveDemux * demux);
static gboolean gst_dash_demux_has_next_period (GstAdaptiveDemux * demux);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static gboolean
+gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream);
+static GstFlowReturn gst_dash_demux_data_received (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
+#else
static GstFlowReturn gst_dash_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
+#endif
static GstFlowReturn
gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
#define SIDX(s) (&(s)->sidx_parser.sidx)
#define SIDX_ENTRY(s,i) (&(SIDX(s)->entries[(i)]))
#define SIDX_CURRENT_ENTRY(s) SIDX_ENTRY(s, SIDX(s)->entry_index)
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define SIDX_ENTRY_COUNT(s) (SIDX(s)->entries_count)
+#endif
static void gst_dash_demux_send_content_protection_event (gpointer cp_data,
gpointer stream);
gst_dash_demux_get_presentation_offset;
gstadaptivedemux_class->get_period_start_time =
gst_dash_demux_get_period_start_time;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gstadaptivedemux_class->start_fragment = gst_dash_demux_stream_fragment_start;
+#endif
gstadaptivedemux_class->finish_fragment =
gst_dash_demux_stream_fragment_finished;
srcpad = gst_dash_demux_create_pad (demux, active_stream);
caps = gst_dash_demux_get_input_caps (demux, active_stream);
+
+#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
+
GST_LOG_OBJECT (demux, "Creating stream %d %" GST_PTR_FORMAT, i, caps);
if (active_stream->cur_adapt_set) {
}
gst_isoff_sidx_parser_init (&stream->sidx_parser);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (gst_mpd_client_has_isoff_ondemand_profile (demux->client))
+ stream->sidx_adapter = gst_adapter_new ();
+#endif
}
return TRUE;
&fragment);
stream->fragment.uri = fragment.uri;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ int entry_count = SIDX_ENTRY_COUNT(dashstream);
+ GST_DEBUG_OBJECT(stream, "dashstream sidx entries_count=%d \n", entry_count);
+ if (isombff && entry_count > 0 && dashstream->sidx_index > 0 && dashstream->sidx_index <= entry_count) {
+#else
if (isombff && dashstream->sidx_index != 0) {
+#endif
GstSidxBoxEntry *entry = SIDX_CURRENT_ENTRY (dashstream);
stream->fragment.range_start =
dashstream->sidx_base_offset + entry->offset;
stream->fragment.range_end = fragment.range_end;
}
} else {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GST_DEBUG_OBJECT(stream, "sidx entries_count=%d sidx_index=%d\n", dashstream->sidx_parser.sidx.entries_count, dashstream->sidx_index);
+#endif
stream->fragment.timestamp = fragment.timestamp;
stream->fragment.duration = fragment.duration;
stream->fragment.range_start =
}
sidx->entry_index = i;
dashstream->sidx_index = i;
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
if (i < sidx->entries_count)
dashstream->sidx_current_remaining = sidx->entries[i].size;
else
dashstream->sidx_current_remaining = 0;
+#endif
}
static GstFlowReturn
GST_DEBUG_OBJECT (stream->pad, "New sidx index: %d / %d. "
"Finished fragment: %d", sidx->entry_index, sidx->entries_count,
fragment_finished);
-
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
if (!fragment_finished) {
dashstream->sidx_current_remaining = sidx->entries[sidx->entry_index].size;
}
+#endif
return !fragment_finished;
}
dashstream->active_stream, stream->demux->segment.rate > 0.0);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static void
+gst_dash_demux_clear_pending_stream_data (GstDashDemux * dashdemux,
+ GstDashDemuxStream * dashstream)
+{
+ gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
+ gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
+ if (dashstream->sidx_adapter)
+ gst_adapter_clear (dashstream->sidx_adapter);
+}
+#endif
+
static GstFlowReturn
gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream)
{
if (gst_dash_demux_stream_advance_subfragment (stream))
return GST_FLOW_OK;
}
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_dash_demux_clear_pending_stream_data (dashdemux, dashstream);
+#endif
return gst_mpd_client_advance_segment (dashdemux->client,
dashstream->active_stream, stream->demux->segment.rate > 0.0);
}
}
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (ret) {
+ gst_dash_demux_clear_pending_stream_data (demux, dashstream);
+ if (gst_mpd_client_has_isoff_ondemand_profile (demux->client)) {
+ /* store our current position to change to the same one in a different
+ * representation if needed */
+ dashstream->sidx_index = SIDX (dashstream)->entry_index;
+ }
+ }
+ #else
if (gst_mpd_client_has_isoff_ondemand_profile (demux->client)) {
/* store our current position to change to the same one in a different
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
}
}
+#endif
end:
return ret;
&stop_type, &stop);
/* TODO check if start-type/stop-type is SET */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (!SEEK_UPDATES_PLAY_POSITION (rate, start_type, stop_type)) {
+ /* nothing to do if we don't have to update the current position */
+ return TRUE;
+ }
+#endif
+
if (demux->segment.rate > 0.0)
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ target_pos = (GstClockTime) start;
+#else
target_pos = (GstClockTime) demux->segment.start;
+#endif
else
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ target_pos = (GstClockTime) stop;
+#else
target_pos = (GstClockTime) demux->segment.stop;
-
+#endif
/* select the requested Period in the Media Presentation */
if (!gst_mpd_client_setup_media_presentation (dashdemux->client, target_pos,
-1, NULL))
GstDashDemuxStream *dashstream = iter->data;
if (flags & GST_SEEK_FLAG_FLUSH) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_dash_demux_clear_pending_stream_data (dashdemux, dashstream);
+#else
gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
+#endif
}
gst_dash_demux_stream_seek (iter->data, target_pos);
}
return newbuf;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static gboolean
+gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream)
+{
+ GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
+
+ dashstream->sidx_index_header_or_data = 0;
+ dashstream->sidx_current_offset = -1;
+
+ return TRUE;
+}
+#endif
+
static GstFlowReturn
gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
stream->fragment.duration);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static GstFlowReturn
+gst_dash_demux_data_received (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
+#else
static GstFlowReturn
gst_dash_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
+#endif
{
GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
GstFlowReturn ret = GST_FLOW_OK;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ guint index_header_or_data;
+#else
GstBuffer *buffer;
gsize available;
+#endif
if (!gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client))
- return GST_ADAPTIVE_DEMUX_CLASS (parent_class)->data_received (demux,
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ return gst_adaptive_demux_stream_push_buffer (stream, buffer);
+#else
+ return GST_ADAPTIVE_DEMUX_CLASS (parent_class)->data_received (demux,
stream);
+#endif
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (stream->downloading_index)
+ index_header_or_data = 1;
+ else if (stream->downloading_header)
+ index_header_or_data = 2;
+ else
+ index_header_or_data = 3;
+
+ if (dash_stream->sidx_index_header_or_data != index_header_or_data) {
+ /* Clear pending data */
+ if (gst_adapter_available (dash_stream->sidx_adapter) != 0)
+ GST_ERROR_OBJECT (stream->pad,
+ "Had pending SIDX data after switch between index/header/data");
+ gst_adapter_clear (dash_stream->sidx_adapter);
+ dash_stream->sidx_index_header_or_data = index_header_or_data;
+ dash_stream->sidx_current_offset = -1;
+ }
+
+ if (dash_stream->sidx_current_offset == -1)
+ dash_stream->sidx_current_offset =
+ GST_BUFFER_OFFSET_IS_VALID (buffer) ? GST_BUFFER_OFFSET (buffer) : 0;
+
+ gst_adapter_push (dash_stream->sidx_adapter, buffer);
+ buffer = NULL;
+#endif
+
if (stream->downloading_index) {
GstIsoffParserResult res;
guint consumed;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gsize available;
+ available = gst_adapter_available (dash_stream->sidx_adapter);
+ buffer = gst_adapter_take_buffer (dash_stream->sidx_adapter, available);
+#else
available = gst_adapter_available (stream->adapter);
buffer = gst_adapter_take_buffer (stream->adapter, available);
+#endif
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (buffer == NULL)
+ {
+ GST_ERROR_OBJECT (demux, "buffer data is NULL");
+ return GST_FLOW_OK;
+ }
+#endif
if (dash_stream->sidx_parser.status != GST_ISOFF_SIDX_PARSER_FINISHED) {
res =
gst_isoff_sidx_parser_add_buffer (&dash_stream->sidx_parser, buffer,
} else {
SIDX (dash_stream)->entry_index = dash_stream->sidx_index;
}
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
dash_stream->sidx_current_remaining =
SIDX_CURRENT_ENTRY (dash_stream)->size;
+#endif
} else if (consumed < available) {
GstBuffer *pending;
/* we still need to keep some data around for the next parsing round
* so just push what was already processed by the parser */
pending = _gst_buffer_split (buffer, consumed, -1);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_adapter_push (dash_stream->sidx_adapter, pending);
+#else
gst_adapter_push (stream->adapter, pending);
+#endif
}
}
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GST_BUFFER_OFFSET (buffer) = dash_stream->sidx_current_offset;
+ GST_BUFFER_OFFSET_END (buffer) =
+ GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer);
+ dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
+#endif
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
} else if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gsize available;
+ while (ret == GST_FLOW_OK
+ && ((available = gst_adapter_available (dash_stream->sidx_adapter)) > 0)) {
+#else
while (ret == GST_FLOW_OK
&& ((available = gst_adapter_available (stream->adapter)) > 0)) {
+#endif
gboolean advance = FALSE;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ guint64 sidx_end_offset =
+ dash_stream->sidx_base_offset +
+ SIDX_CURRENT_ENTRY (dash_stream)->offset +
+ SIDX_CURRENT_ENTRY (dash_stream)->size;
+ if (dash_stream->sidx_current_offset + available < sidx_end_offset){
+ buffer = gst_adapter_take_buffer (dash_stream->sidx_adapter, available);
+ } else {
+ buffer =
+ gst_adapter_take_buffer (dash_stream->sidx_adapter,
+ sidx_end_offset - dash_stream->sidx_current_offset);
+ advance = TRUE;
+ }
+#else
if (available < dash_stream->sidx_current_remaining) {
buffer = gst_adapter_take_buffer (stream->adapter, available);
dash_stream->sidx_current_remaining -= available;
dash_stream->sidx_current_remaining = 0;
advance = TRUE;
}
+#endif
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (buffer == NULL) {
+ GST_ERROR_OBJECT (demux, "buffer data is NULL");
+ return GST_FLOW_OK;
+ }
+ GST_BUFFER_OFFSET (buffer) = dash_stream->sidx_current_offset;
+ GST_BUFFER_OFFSET_END (buffer) =
+ GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer);
+ dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
+#endif
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
if (advance) {
GstFlowReturn new_ret;
}
} else {
/* this should be the main header, just push it all */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ buffer = gst_adapter_take_buffer (dash_stream->sidx_adapter,
+ gst_adapter_available (dash_stream->sidx_adapter));
+
+ GST_BUFFER_OFFSET (buffer) = dash_stream->sidx_current_offset;
+ GST_BUFFER_OFFSET_END (buffer) =
+ GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer);
+ dash_stream->sidx_current_offset = GST_BUFFER_OFFSET_END (buffer);
+
+ ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
+#else
ret =
gst_adaptive_demux_stream_push_buffer (stream,
gst_adapter_take_buffer (stream->adapter,
gst_adapter_available (stream->adapter)));
+#endif
}
return ret;
GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (dash_stream->sidx_adapter)
+ g_object_unref (dash_stream->sidx_adapter);
+#endif
}
static GstDashDemuxClockDrift *
/*
Parse an RFC822 (section 5) date-time from the Date: field in the
- HTTP response.
+ HTTP response.
See https://tools.ietf.org/html/rfc822#section-5
*/
static GstDateTime *
if (method == GST_MPD_UTCTIMING_TYPE_HTTP_HEAD) {
range_start = -1;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ 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
download =
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);
GstMediaFragmentInfo current_fragment;
/* index parsing */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GstAdapter *sidx_adapter;
+#endif
GstSidxParser sidx_parser;
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
gsize sidx_current_remaining;
+#endif
gint sidx_index;
gint64 sidx_base_offset;
GstClockTime pending_seek_ts;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ /* sidx offset tracking */
+ guint64 sidx_current_offset;
+ /* index = 1, header = 2, data = 3 */
+ guint sidx_index_header_or_data;
+#endif
};
/**
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) {
uri_string = gst_uri_to_string (uri);
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);
-
/* Don't g_date_time_unref(gdt2) because gst_date_time_new_from_g_date_time takes
* ownership of the GDateTime pointer.
*/
GST_DEBUG ("Stream index: %i", stream_idx);
stream = g_list_nth_data (client->active_streams, stream_idx);
g_return_val_if_fail (stream != NULL, 0);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_return_val_if_fail (stream->segments != NULL, 0);
+#endif
segment_idx = gst_mpd_client_get_segments_counts (client, stream) - 1;
currentChunk = g_ptr_array_index (stream->segments, segment_idx);
#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
+
typedef enum
{
GST_STREAM_UNKNOWN,
GstAdaptiveDemuxStream * stream);
static GstFlowReturn gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
+#else
static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
+#endif
static gboolean gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemuxStream *
stream);
static GstFlowReturn gst_hls_demux_advance_fragment (GstAdaptiveDemuxStream *
GstHLSDemux *demux = GST_HLS_DEMUX (obj);
gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_object_unref (demux->pending_encrypted_data);
+#endif
gst_m3u8_client_free (demux->client);
G_OBJECT_CLASS (parent_class)->dispose (obj);
gst_hls_demux_init (GstHLSDemux * demux)
{
demux->do_typefind = TRUE;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ demux->pending_encrypted_data = gst_adapter_new ();
+#endif
}
static void
return 0;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static void
+gst_hls_demux_clear_pending_data (GstHLSDemux * hlsdemux)
+{
+ gst_hls_demux_decrypt_end (hlsdemux);
+ gst_adapter_clear (hlsdemux->pending_encrypted_data);
+ gst_buffer_replace (&hlsdemux->pending_decrypted_buffer, NULL);
+ gst_buffer_replace (&hlsdemux->pending_typefind_buffer, NULL);
+ hlsdemux->current_offset = -1;
+}
+#endif
+
static gboolean
gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
{
/* properly cleanup pending decryption status */
if (flags & GST_SEEK_FLAG_FLUSH) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_hls_demux_clear_pending_data (hlsdemux);
+#else
gst_hls_demux_decrypt_end (hlsdemux);
+#endif
}
/* Use I-frame variants for trick modes */
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
/* only 1 output supported */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_hls_demux_clear_pending_data (hlsdemux);
+#endif
gst_adaptive_demux_stream_new (demux, gst_hls_demux_create_pad (hlsdemux));
hlsdemux->reset_pts = TRUE;
hlsdemux->key_fragment = NULL;
GST_INFO_OBJECT (demux, "Fetching key %s", hlsdemux->current_key);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ key_fragment =
+ gst_uri_downloader_fetch_uri (demux->downloader,
+ hlsdemux->current_key, hlsdemux->client->main ?
+ hlsdemux->client->main->uri : NULL, demux->user_agent, demux->cookies, DEFAULT_ADAPTIVE_RETRY,DEFAULT_ADAPTIVE_TIMEOUT,FALSE, FALSE,
+ hlsdemux->client->current ? hlsdemux->client->current->
+ allowcache : TRUE, &err);
+#else
key_fragment =
gst_uri_downloader_fetch_uri (demux->downloader,
hlsdemux->current_key, hlsdemux->client->main ?
hlsdemux->client->main->uri : NULL, FALSE, FALSE,
hlsdemux->client->current ? hlsdemux->client->current->
allowcache : TRUE, &err);
+#endif
if (key_fragment == NULL)
goto key_failed;
hlsdemux->key_url = g_strdup (hlsdemux->current_key);
gst_buffer_unref (key_buffer);
g_object_unref (key_fragment);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_hls_demux_clear_pending_data (hlsdemux);
+#endif
return TRUE;
guint buffer_size;
GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (hlsdemux->pending_typefind_buffer)
+ buffer = gst_buffer_append (hlsdemux->pending_typefind_buffer, buffer);
+ hlsdemux->pending_typefind_buffer = NULL;
+#endif
+
gst_buffer_map (buffer, &info, GST_MAP_READ);
buffer_size = info.size;
gst_buffer_unref (buffer);
return GST_FLOW_NOT_NEGOTIATED;
} else {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ hlsdemux->pending_typefind_buffer = buffer;
+#else
if (hlsdemux->pending_buffer)
hlsdemux->pending_buffer =
gst_buffer_append (buffer, hlsdemux->pending_buffer);
else
hlsdemux->pending_buffer = buffer;
+#endif
return GST_FLOW_OK;
}
}
#endif
hlsdemux->do_typefind = FALSE;
}
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ g_assert (hlsdemux->pending_typefind_buffer == NULL);
+ if (buffer) {
+ buffer = gst_buffer_make_writable (buffer);
+ GST_BUFFER_OFFSET (buffer) = hlsdemux->current_offset;
+ hlsdemux->current_offset += gst_buffer_get_size (buffer);
+ GST_BUFFER_OFFSET_END (buffer) = hlsdemux->current_offset;
+ return gst_adaptive_demux_stream_push_buffer (stream, buffer);
+ }
+#else
if (buffer)
return gst_adaptive_demux_stream_push_buffer (stream, buffer);
+#endif
+
return GST_FLOW_OK;
}
if (hlsdemux->current_key)
gst_hls_demux_decrypt_end (hlsdemux);
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
/* ideally this should be empty, but this eos might have been
* caused by an error on the source element */
GST_DEBUG_OBJECT (demux, "Data still on the adapter when EOS was received"
": %" G_GSIZE_FORMAT, gst_adapter_available (stream->adapter));
gst_adapter_clear (stream->adapter);
+#endif
if (stream->last_ret == GST_FLOW_OK) {
- if (hlsdemux->pending_buffer) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (hlsdemux->pending_decrypted_buffer)
+#else
+ if (hlsdemux->pending_buffer)
+#endif
+ {
if (hlsdemux->current_key) {
GstMapInfo info;
gssize unpadded_size;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ /* Handle pkcs7 unpadding here */
+ gst_buffer_map (hlsdemux->pending_decrypted_buffer, &info, GST_MAP_READ);
+ unpadded_size = info.size - info.data[info.size - 1];
+ gst_buffer_unmap (hlsdemux->pending_decrypted_buffer, &info);
+ gst_buffer_resize (hlsdemux->pending_decrypted_buffer, 0, unpadded_size);
+#else
/* Handle pkcs7 unpadding here */
gst_buffer_map (hlsdemux->pending_buffer, &info, GST_MAP_READ);
unpadded_size = info.size - info.data[info.size - 1];
gst_buffer_unmap (hlsdemux->pending_buffer, &info);
gst_buffer_resize (hlsdemux->pending_buffer, 0, unpadded_size);
+#endif
}
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ ret =
+ gst_hls_demux_handle_buffer (demux, stream, hlsdemux->pending_decrypted_buffer,
+ TRUE);
+ hlsdemux->pending_decrypted_buffer = NULL;
+#else
ret =
gst_hls_demux_handle_buffer (demux, stream, hlsdemux->pending_buffer,
TRUE);
hlsdemux->pending_buffer = NULL;
+#endif
}
- } else {
+ }
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_hls_demux_clear_pending_data (hlsdemux);
+#else
+ else {
if (hlsdemux->pending_buffer)
gst_buffer_unref (hlsdemux->pending_buffer);
hlsdemux->pending_buffer = NULL;
}
-
+#endif
+ GST_WARNING_OBJECT (hlsdemux, "gst_hls_demux_handle_buffer return : %d",ret);
if (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED)
return gst_adaptive_demux_stream_advance_fragment (demux, stream,
stream->fragment.duration);
return ret;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static GstFlowReturn
+gst_hls_demux_data_received (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
+#else
static GstFlowReturn
gst_hls_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
+#endif
{
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
gsize available;
GstBuffer *buffer = NULL;
available = gst_adapter_available (stream->adapter);
+#endif
+
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (hlsdemux->current_offset == -1)
+ hlsdemux->current_offset =
+ GST_BUFFER_OFFSET_IS_VALID (buffer) ? GST_BUFFER_OFFSET (buffer) : 0;
+#endif
/* Is it encrypted? */
if (hlsdemux->current_key) {
GError *err = NULL;
GstBuffer *tmp_buffer;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gsize size;
+ gst_adapter_push (hlsdemux->pending_encrypted_data, buffer);
+ size = gst_adapter_available (hlsdemux->pending_encrypted_data);
+#endif
/* must be a multiple of 16 */
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ size = size & (~0xF);
+#else
available = available & (~0xF);
+#endif
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (size == 0) {
+ return GST_FLOW_OK;
+ }
+#else
if (available == 0) {
return GST_FLOW_OK;
}
+#endif
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ buffer = gst_adapter_take_buffer (hlsdemux->pending_encrypted_data, size);
+#else
buffer = gst_adapter_take_buffer (stream->adapter, available);
+#endif
buffer = gst_hls_demux_decrypt_fragment (hlsdemux, buffer, &err);
if (buffer == NULL) {
GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"),
return GST_FLOW_ERROR;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ tmp_buffer = hlsdemux->pending_decrypted_buffer;
+ hlsdemux->pending_decrypted_buffer = buffer;
+ buffer = tmp_buffer;
+#else
tmp_buffer = hlsdemux->pending_buffer;
hlsdemux->pending_buffer = buffer;
buffer = tmp_buffer;
- } else {
+#endif
+ }
+ else {
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
buffer = gst_adapter_take_buffer (stream->adapter, available);
if (hlsdemux->pending_buffer) {
buffer = gst_buffer_append (hlsdemux->pending_buffer, buffer);
hlsdemux->pending_buffer = NULL;
}
+#endif
}
return gst_hls_demux_handle_buffer (demux, stream, buffer, FALSE);
demux->client = gst_m3u8_client_new ("", NULL);
demux->srcpad_counter = 0;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_hls_demux_clear_pending_data (demux);
+#else
if (demux->pending_buffer)
gst_buffer_unref (demux->pending_buffer);
demux->pending_buffer = NULL;
+#endif
if (demux->current_key) {
g_free (demux->current_key);
demux->current_key = NULL;
gboolean main_checked = FALSE, updated = FALSE;
gchar *uri, *main_uri;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+//[prasenjit.c]Sometimes for Errornous Clips , when Server changes the playlist abruptly , the URI does not remain valid anymore.
+//Adding one error check condition to handle the cases.
+ if ((!demux->client->current)||(!demux->client->main)) {
+ GST_WARNING_OBJECT (demux, "Invalid m3u8 instance in playlist .. no update possible !!!");
+ return FALSE;
+ }
+#endif
+
retry:
uri = gst_m3u8_client_get_current_uri (demux->client);
main_uri = gst_m3u8_client_get_uri (demux->client);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ download =
+ gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri, adaptive_demux->user_agent, adaptive_demux->cookies,PLAYLIST_ADAPTIVE_RETRY,PLAYLIST_ADAPTIVE_TIMEOUT,
+ TRUE, TRUE, TRUE, err);
+#else
download =
gst_uri_downloader_fetch_uri (adaptive_demux->downloader, uri, main_uri,
TRUE, TRUE, TRUE, err);
+#endif
g_free (main_uri);
if (download == NULL) {
if (!adaptive_demux->cancelled && update && !main_checked
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, PLAYLIST_ADAPTIVE_RETRY,PLAYLIST_ADAPTIVE_TIMEOUT,TRUE, TRUE, TRUE, &err2);
+#else
download =
gst_uri_downloader_fetch_uri (adaptive_demux->downloader,
main_uri, NULL, TRUE, TRUE, TRUE, &err2);
+#endif
g_free (main_uri);
g_clear_error (&err2);
if (download != NULL) {
old_bandwidth = GST_M3U8 (previous_variant->data)->bandwidth;
new_bandwidth = GST_M3U8 (current_variant->data)->bandwidth;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GST_INFO_OBJECT (demux, "Previous Stream Codec = %s , Codec_Count = %d", GST_M3U8 (previous_variant->data)->codecs,GST_M3U8 (previous_variant->data)->codec_count);
+ GST_INFO_OBJECT (demux, "Current Stream Codec = %s , Codec_Count = %d", GST_M3U8 (current_variant->data)->codecs,GST_M3U8 (current_variant->data)->codec_count);
+#endif
/* Don't do anything else if the playlist is the same */
if (new_bandwidth == old_bandwidth) {
GST_M3U8_CLIENT_UNLOCK (demux->client);
GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
" to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);
stream->discont = TRUE;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (GST_M3U8 (previous_variant->data)->codec_count > GST_M3U8 (current_variant->data)->codec_count)
+ {
+ GST_WARNING_OBJECT (demux, "Temporary patch for disabling stream switch in case New Variant has lesser streams than current variant !!");
+ goto playlist_switch_back;
+ }
+#endif
if (gst_hls_demux_update_playlist (demux, FALSE, NULL)) {
gchar *uri;
gchar *main_uri;
if (changed)
*changed = TRUE;
} else {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+playlist_switch_back:
+ GST_INFO_OBJECT (demux, "Unable to update playlist. Switching back");
+
+ GList *failover = NULL;
+#else
GList *failover = NULL;
GST_INFO_OBJECT (demux, "Unable to update playlist. Switching back");
+#endif
GST_M3U8_CLIENT_LOCK (demux->client);
failover = g_list_previous (current_variant);
#endif
gchar *current_key;
guint8 *current_iv;
- GstBuffer *pending_buffer; /* decryption scenario:
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GstAdapter *pending_encrypted_data; /* for chunking data into 16 byte multiples for decryption */
+ GstBuffer *pending_decrypted_buffer; /* last decrypted buffer for pkcs7 unpadding.
+ We only know that it is the last at EOS */
+ GstBuffer *pending_typefind_buffer; /* for collecting data until typefind succeeds */
+ guint64 current_offset; /* offset we're currently at */
+#else
+ GstBuffer *pending_buffer; /*decryption scenario:
* the last buffer can only be pushed when
* resized, so need to store and wait for
* EOS to know it is the last */
+#endif
gboolean reset_pts;
};
new_list = gst_m3u8_new ();
new_list->parent = self;
new_list->iframe = iframe;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ new_list->codec_count = 0;
+#endif
data = data + (iframe ? 26 : 18);
while (data && parse_attributes (&data, &a, &v)) {
if (g_str_equal (a, "BANDWIDTH")) {
} else if (g_str_equal (a, "CODECS")) {
g_free (new_list->codecs);
new_list->codecs = g_strdup (v);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gchar *temp_codec_str = NULL;
+ gchar *temp_codec_ptr = NULL;
+
+ temp_codec_str = g_strdup (new_list->codecs);
+ GST_DEBUG ("CODECS : %s",new_list->codecs);
+ new_list->codec_count = 1;
+ temp_codec_ptr = temp_codec_str;
+ while(temp_codec_str != NULL)
+ {
+ temp_codec_str = strchr (temp_codec_str, ',');
+ if (temp_codec_str)
+ {
+ new_list->codec_count++;
+ temp_codec_str = temp_codec_str + 1;
+ }
+ }
+ g_free(temp_codec_ptr);
+ GST_DEBUG ("CODEC COUNT : %d",new_list->codec_count);
+#endif
} else if (g_str_equal (a, "RESOLUTION")) {
if (!int_from_string (v, &v, &new_list->width))
GST_WARNING ("Error while reading RESOLUTION width");
}
if (m3u8->files && self->sequence == -1) {
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ self->current_file = g_list_first (m3u8->files);
+#endif
if (GST_M3U8_CLIENT_IS_LIVE (self)) {
/* for live streams, start GST_M3U8_LIVE_MIN_FRAGMENT_DISTANCE from
the end of the playlist. See section 6.3.3 of HLS draft */
gint pos =
g_list_length (m3u8->files) - GST_M3U8_LIVE_MIN_FRAGMENT_DISTANCE;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+/*[shweta.agg] While playing live video in hotstar, Video is starting from beginning.Setting current_file to nth fragment for live streams.
+ https://cgit.freedesktop.org/gstreamer/gst-plugins-bad/commit/ext/hls/m3u8.c?id=22456ce0328a8d06a12997979a143a0103867a49
+*/
self->current_file = g_list_nth (m3u8->files, pos >= 0 ? pos : 0);
+#else
+ self->sequence =
+ GST_M3U8_MEDIA_FILE (g_list_nth_data (m3u8->files,
+ pos >= 0 ? pos : 0))->sequence;
+#endif
} else {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
self->current_file = g_list_first (m3u8->files);
+#else
+ self->sequence = GST_M3U8_MEDIA_FILE (self->current_file->data)->sequence;
+#endif
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
self->sequence = GST_M3U8_MEDIA_FILE (self->current_file->data)->sequence;
+#endif
self->sequence_position = 0;
GST_DEBUG ("Setting first sequence at %u", (guint) self->sequence);
}
}
}
if (client->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 */
client->current_file_duration =
GST_M3U8_MEDIA_FILE (client->current_file->data)->duration;
gint bandwidth;
gint program_id;
gchar *codecs;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gint codec_count;
+#endif
gint width;
gint height;
gboolean iframe;
#define DEFAULT_LOOKBACK_FRAGMENTS 3
#define DEFAULT_CONNECTION_SPEED 0
#define DEFAULT_BITRATE_LIMIT 0.8
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+#define MAX_DASH_DOWNLOAD_ERROR_COUNT 200
+#endif
enum
{
PROP_0,
static void
gst_adaptive_demux_stream_fragment_download_finish (GstAdaptiveDemuxStream *
stream, GstFlowReturn ret, GError * err);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static GstFlowReturn
+gst_adaptive_demux_stream_data_received_default (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
+#else
static GstFlowReturn
gst_adaptive_demux_stream_data_received_default (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
+#endif
static GstFlowReturn
gst_adaptive_demux_stream_finish_fragment_default (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
demux->num_lookback_fragments = DEFAULT_LOOKBACK_FRAGMENTS;
demux->bitrate_limit = DEFAULT_BITRATE_LIMIT;
demux->connection_speed = DEFAULT_CONNECTION_SPEED;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ demux->is_dashstreaming = FALSE;
+ demux->dash_error_count = 0;
+ demux->dash_newest_segment = NULL;
+#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)
demux->manifest_base_uri = redirect_uri;
}
- GST_DEBUG_OBJECT (demux, "Fetched manifest at URI: %s (base: %s)",
+ GST_WARNING_OBJECT (demux, "Fetched manifest at URI: %s (base: %s)",
demux->manifest_uri, GST_STR_NULL (demux->manifest_base_uri));
} else {
GST_WARNING_OBJECT (demux, "Upstream URI query failed.");
/* 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;
}
demux->priv->old_streams = NULL;
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (demux->dash_newest_segment) {
+ g_free (demux->dash_newest_segment);
+ demux->dash_newest_segment = NULL;
+ }
+#endif
+
g_free (demux->manifest_uri);
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;
for (iter = demux->streams; iter; iter = g_list_next (iter)) {
stream = iter->data;
if (GST_OBJECT_CAST (stream->src) == GST_MESSAGE_SRC (msg)) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gchar *caps_str = NULL;
+ GstCaps *pad_caps = NULL;
+ pad_caps = gst_pad_get_current_caps(stream->pad);
+ if (pad_caps)
+ caps_str = gst_caps_to_string (pad_caps);
+#endif
gst_message_parse_error (msg, &err, &debug);
GST_WARNING_OBJECT (GST_ADAPTIVE_DEMUX_STREAM_PAD (stream),
err->message = new_error;
}
- /* error, but ask to retry */
- gst_adaptive_demux_stream_fragment_download_finish (stream,
- GST_FLOW_CUSTOM_ERROR, err);
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if ((caps_str) && (strstr(caps_str,"dash_stream")) && (gst_adaptive_demux_is_live (demux))) {
+ if (demux->dash_error_count < MAX_DASH_DOWNLOAD_ERROR_COUNT) {
+ if (strstr(err->message,"Not Found")) {
+ char tmp_current_fragment[100] = {0,};
+ char tmp_newest_fragment[100] = {0,};
+ char tmp_intermediate_url[1000]={0,};
+ char *s1 = NULL , *s2 = NULL;
+ int index1=0, index2=0;
+ gboolean bRet = TRUE;
+
+ if (demux->dash_newest_segment) {
+ g_free (demux->dash_newest_segment);
+ demux->dash_newest_segment = NULL;
+ }
+
+ if (stream->fragment.uri) {
+ s1 = strrchr(stream->fragment.uri, '/');
+ index1 = (int)(s1 - stream->fragment.uri);
+ index2 = (int)strlen(stream->fragment.uri);
+ s1++;
+ strncpy(tmp_current_fragment, s1, index2-index1-1);
+ tmp_current_fragment[index2-index1-1]='\0';
+ }
+
+ s1 = s2 = NULL;
+ s1 = strstr(err->message,"Dash-Newest-Segment");
+ if (s1) {
+ s1 = s1 + 20;
+ s2 = strrchr(s1,',');
+ index1 = (int)strlen(s1);
+ index2 = (int)strlen(s2);
+ strncpy(tmp_intermediate_url, s1, index1-index2);
+ tmp_intermediate_url[index1-index2] = '\0';
+
+ if (strcmp(tmp_intermediate_url,"(NULL)") != 0) {
+ s1 = s2 = NULL;
+ s1 = strrchr(tmp_intermediate_url, '/');
+ index1 = (int)(s1 - tmp_intermediate_url);
+ index2 = (int)strlen(tmp_intermediate_url);
+ s1++;
+ strncpy(tmp_newest_fragment, s1, index2-index1-1);
+ tmp_newest_fragment[index2-index1-1]='\0';
+ } else {
+ GST_WARNING_OBJECT (demux, "Dash-Newest-Segment Not Available !!\n");
+ }
+ }
+
+ if ((tmp_current_fragment)&&(tmp_newest_fragment)) {
+ if (g_ascii_strcasecmp(tmp_newest_fragment,tmp_current_fragment) <= 0) {
+ GST_DEBUG_OBJECT (demux, "newest fragment less than current fragment");
+ bRet = FALSE;
+ } else {
+ GST_DEBUG_OBJECT (demux, "newest fragment more than current fragment");
+ bRet = TRUE;
+ }
+ }
+
+ demux->dash_newest_segment = g_strdup(tmp_newest_fragment);
+ demux->dash_error_count++;
+
+ if (bRet)
+ {
+ GST_DEBUG_OBJECT (demux, "Advancing the Fragment \n");
+ GstAdaptiveDemuxClass *klass;
+ GstFlowReturn ret;
+ klass = GST_ADAPTIVE_DEMUX_GET_CLASS (stream->demux);
+ ret = klass->finish_fragment (stream->demux, stream);
+ gst_adaptive_demux_stream_fragment_download_finish (stream, ret, NULL);
+ } else {
+ GST_DEBUG_OBJECT (demux, "retry: Not advancing the fragment \n");
+ gst_adaptive_demux_stream_fragment_download_finish (stream, GST_FLOW_OK, NULL);
+ }
+ } else {
+ GST_DEBUG_OBJECT (demux, "retry");
+ gst_adaptive_demux_stream_fragment_download_finish (stream, GST_FLOW_OK, NULL);
+ }
+ } else {
+ GST_DEBUG_OBJECT (demux, "error count reached MAX .. posting Error and stopping the task");
+ gst_adaptive_demux_stream_fragment_download_finish (stream, GST_FLOW_EOS, err);
+ }
+ } else
+#endif
+ {
+ /* error, but ask to retry */
+ gst_adaptive_demux_stream_fragment_download_finish (stream,GST_FLOW_CUSTOM_ERROR, err);
+ }
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gst_caps_unref (pad_caps);
+ g_free (caps_str);
+#endif
g_error_free (err);
g_free (debug);
break;
gst_adaptive_demux_stream_new (GstAdaptiveDemux * demux, GstPad * pad)
{
GstAdaptiveDemuxStream *stream;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gchar *factory_name = NULL;
+ GstElementFactory *factory = NULL;
+#endif
stream = g_malloc0 (demux->stream_struct_size);
gst_segment_init (&stream->segment, GST_FORMAT_TIME);
g_cond_init (&stream->fragment_download_cond);
g_mutex_init (&stream->fragment_download_lock);
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ factory = gst_element_get_factory(demux);
+ factory_name = GST_OBJECT_NAME(factory);
+ GST_DEBUG_OBJECT (demux,"Plugin Factory Name: %s", factory_name);
+
+ if (!demux->is_dashstreaming && g_strrstr(factory_name, "dashdemux")){
+ demux->is_dashstreaming = TRUE;
+ g_mutex_init (&demux->UC_download_lock);
+ GST_DEBUG_OBJECT (demux,"Enabling Flag is_dashstreaming !!!");
+ }
+#endif
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
stream->adapter = gst_adapter_new ();
+#endif
demux->next_streams = g_list_append (demux->next_streams, stream);
g_cond_clear (&stream->fragment_download_cond);
g_mutex_clear (&stream->fragment_download_lock);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (demux->is_dashstreaming){
+ demux->is_dashstreaming = FALSE;
+ g_mutex_clear (&demux->UC_download_lock);
+ }
+#endif
+
g_free (stream->fragment_bitrates);
if (stream->pad) {
if (stream->pending_caps)
gst_caps_unref (stream->pending_caps);
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
g_object_unref (stream->adapter);
+#endif
g_free (stream);
}
gst_task_join (stream->download_task);
stream->download_error_count = 0;
stream->need_header = TRUE;
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
gst_adapter_clear (stream->adapter);
+#endif
}
gst_task_join (demux->priv->updates_task);
}
stream->fragment.duration);
}
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+static GstFlowReturn
+gst_adaptive_demux_stream_data_received_default (GstAdaptiveDemux * demux,
+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
+#else
static GstFlowReturn
gst_adaptive_demux_stream_data_received_default (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
+#endif
{
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
GstBuffer *buffer;
buffer = gst_adapter_take_buffer (stream->adapter,
gst_adapter_available (stream->adapter));
+#endif
return gst_adaptive_demux_stream_push_buffer (stream, buffer);
}
stream->fragment_total_time +=
g_get_monotonic_time () - stream->download_chunk_start_time;
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
gst_adapter_push (stream->adapter, buffer);
+#endif
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ demux->dash_error_count = 0;
+#endif
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ GST_DEBUG_OBJECT (stream->pad, "Received buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (buffer));
+ ret = klass->data_received (demux, stream, buffer);
+#else
GST_DEBUG_OBJECT (stream->pad, "Received buffer of size %" G_GSIZE_FORMAT
". Now %" G_GSIZE_FORMAT " on adapter", gst_buffer_get_size (buffer),
gst_adapter_available (stream->adapter));
ret = klass->data_received (demux, stream);
+#endif
stream->download_chunk_start_time = g_get_monotonic_time ();
if (ret != GST_FLOW_OK) {
+ GST_WARNING_OBJECT (stream->pad, "data_received return = %d",ret);
if (ret < GST_FLOW_EOS) {
GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL),
("stream stopped, reason %s", gst_flow_get_name (ret)));
GstAdaptiveDemuxClass *klass;
GstFlowReturn ret;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ char tmp_current_fragment[100] = {0,};
+ char *s1 = NULL ;
+ int index1=0, index2=0;
+ gboolean bRet = TRUE;
+ gchar *caps_str = NULL;
+ GstCaps *pad_caps = NULL;
+ pad_caps = gst_pad_get_current_caps(stream->pad);
+ if (pad_caps)
+ caps_str = gst_caps_to_string (pad_caps);
+
+ if ((caps_str)&&(strstr(caps_str,"dash_stream")) &&
+ (gst_adaptive_demux_is_live (stream->demux))&&(stream->demux->dash_error_count > 0)) {
+
+ GST_DEBUG_OBJECT (stream->demux, "_src_event fragment comparison for Dash stream !!!\n");
+ if (stream->fragment.uri) {
+ s1 = strrchr(stream->fragment.uri, '/');
+ index1 = (int)(s1 - stream->fragment.uri);
+ index2 = (int)strlen(stream->fragment.uri);
+ s1++;
+ strncpy(tmp_current_fragment, s1, index2-index1-1);
+ tmp_current_fragment[index2-index1-1]='\0';
+ }
+ if ((tmp_current_fragment)&&(stream->demux->dash_newest_segment)) {
+ if (g_ascii_strcasecmp(stream->demux->dash_newest_segment,tmp_current_fragment) <= 0) {
+ GST_DEBUG_OBJECT (stream->demux, "newest fragment less than current fragment");
+ bRet = FALSE;
+ } else {
+ GST_DEBUG_OBJECT (stream->demux, "newest fragment more than current fragment");
+ bRet = TRUE;
+ }
+ }
+ }
+
+ if (bRet) {
+ klass = GST_ADAPTIVE_DEMUX_GET_CLASS (stream->demux);
+ ret = klass->finish_fragment (stream->demux, stream);
+ gst_adaptive_demux_stream_fragment_download_finish (stream, ret, NULL);
+ } else {
+ GST_DEBUG_OBJECT (stream->demux, "retry: Not advancing the fragment from src_event !!");
+ gst_adaptive_demux_stream_fragment_download_finish (stream, GST_FLOW_OK, NULL);
+ }
+
+ gst_caps_unref (pad_caps);
+ g_free (caps_str);
+#else
klass = GST_ADAPTIVE_DEMUX_GET_CLASS (stream->demux);
ret = klass->finish_fragment (stream->demux, stream);
gst_adaptive_demux_stream_fragment_download_finish (stream, ret, NULL);
+#endif
break;
}
default:
g_object_set (stream->src, "compress", FALSE, NULL);
if (g_object_class_find_property (gobject_class, "keep-alive"))
g_object_set (stream->src, "keep-alive", TRUE, NULL);
+
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ if (demux->is_dashstreaming){
+ g_mutex_lock (&demux->UC_download_lock);
+ GST_DEBUG_OBJECT (demux, "DashDemux Case: Locking UC_download_lock !!!");
+ }
+ 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);
+ if (demux->is_dashstreaming){
+ g_mutex_unlock (&demux->UC_download_lock);
+ GST_DEBUG_OBJECT (demux, "DashDemux Case: Unlocking UC_download_lock !!!");
+ }
+#endif
if (g_object_class_find_property (gobject_class, "extra-headers")) {
if (referer || refresh || !allow_cache) {
GstStructure *extra_headers = gst_structure_new_empty ("headers");
gst_adaptive_demux_stream_get_fragment_waiting_time (demux, stream);
GST_MANIFEST_UNLOCK (demux);
if (wait_time > 0)
+ {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gint64 end_time = g_get_monotonic_time () + wait_time / GST_USECOND;
+ GST_DEBUG_OBJECT (stream->pad, "Download waiting for %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (wait_time));
+#endif
gst_adaptive_demux_stream_download_wait (stream, wait_time);
+ }
} else {
GST_MANIFEST_UNLOCK (demux);
}
GstFlowReturn ret = GST_FLOW_OK;
/* Wait here until we should do the next update or we're cancelled */
- GST_DEBUG_OBJECT (demux, "Wait for next playlist update");
+ GST_DEBUG_OBJECT (demux, "Wait for next playlist update : next_update=%" GST_TIME_FORMAT,GST_TIME_ARGS(demux->priv->next_update));
g_mutex_lock (&demux->priv->updates_timed_lock);
if (demux->priv->stop_updates_task) {
if (gst_adaptive_demux_is_live (demux)
|| gst_adaptive_demux_stream_has_next_fragment (demux, stream)) {
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ demux->dash_error_count = 0;
+#endif
ret = klass->stream_advance_fragment (stream);
} else {
ret = GST_FLOW_EOS;
if (gst_adaptive_demux_stream_select_bitrate (demux, stream,
gst_adaptive_demux_stream_update_current_bitrate (demux, stream))) {
stream->need_header = TRUE;
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
gst_adapter_clear (stream->adapter);
+#endif
ret = (GstFlowReturn) GST_ADAPTIVE_DEMUX_FLOW_SWITCH;
}
GstFragment *download;
GstBuffer *buffer;
GstFlowReturn ret;
-
+#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, NULL);
+#endif
if (download) {
GST_MANIFEST_LOCK (demux);
g_free (demux->manifest_uri);
g_clear_error (&err); \
} G_STMT_END
+#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
+#endif
+
typedef struct _GstAdaptiveDemuxStreamFragment GstAdaptiveDemuxStreamFragment;
typedef struct _GstAdaptiveDemuxStream GstAdaptiveDemuxStream;
typedef struct _GstAdaptiveDemux GstAdaptiveDemux;
#endif
GstSegment segment;
+#ifndef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
GstAdapter *adapter;
+#endif
GstCaps *pending_caps;
GstEvent *pending_segment;
gchar *manifest_uri;
gchar *manifest_base_uri;
-
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ gchar *user_agent;
+ gchar **cookies;
+ gboolean is_dashstreaming;
+ /* Lock for updating User Agent & Cookies */
+ GMutex UC_download_lock;
+#endif
/* Properties */
guint num_lookback_fragments;
gfloat bitrate_limit; /* limit of the available bitrate to use */
/* < private > */
GstAdaptiveDemuxPrivate *priv;
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ guint dash_error_count;
+ gchar *dash_newest_segment;
+#endif
};
/**
* also push any pending data before moving to the next fragment.
*/
GstFlowReturn (*finish_fragment) (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream);
+#ifdef TIZEN_FEATURE_ADAPTIVE_MODIFICATION
+ /**
+ * data_received:
+ * @demux: #GstAdaptiveDemux
+ * @stream: #GstAdaptiveDemuxStream
+ * @buffer: #GstBuffer
+ *
+ * Notifies the subclass that a fragment chunk was downloaded. The subclass
+ * can look at the data and modify/push data as desired.
+ *
+ * Returns: #GST_FLOW_OK if successful, #GST_FLOW_ERROR in case of error.
+ */
+ GstFlowReturn (*data_received) (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
+#else
/**
* data_received:
* @demux: #GstAdaptiveDemux
* Returns: #GST_FLOW_OK if successful, #GST_FLOW_ERROR in case of error.
*/
GstFlowReturn (*data_received) (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream);
+#endif
/**
* get_live_seek_range:
return TRUE;
}
+#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);
GType gst_uri_downloader_get_type (void);
GstUriDownloader * gst_uri_downloader_new (void);
+#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);
packetizer->refoffset = -1;
packetizer->last_in_time = GST_CLOCK_TIME_NONE;
#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ packetizer->ra_base_time = GST_CLOCK_TIME_NONE;
+ packetizer->is_random_access = FALSE;
packetizer->is_non_pcr_live_feed = FALSE;
packetizer->non_pcr_base_time = GST_CLOCK_TIME_NONE;
packetizer->last_live_pts = GST_CLOCK_TIME_NONE;
GST_TIME_ARGS (PCRTIME_TO_GSTTIME (packet->pcr)), packet->offset);
PACKETIZER_GROUP_LOCK (packetizer);
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ if (packetizer->calculate_skew
+ && GST_CLOCK_TIME_IS_VALID (packetizer->last_in_time))
+ {
+ pcrtable = get_pcr_table (packetizer, packet->pid);
+ if (((!GST_CLOCK_TIME_IS_VALID (pcrtable->base_time))||(!GST_CLOCK_TIME_IS_VALID (pcrtable->base_pcrtime)))||(packetizer->is_live_stream))
+ {
+ calculate_skew (packetizer, pcrtable, packet->pcr,packetizer->last_in_time);
+ }
+ else
+ GST_DEBUG (" **** skew calculation not done **** !!!");
+ }
+#else
if (packetizer->calculate_skew
&& GST_CLOCK_TIME_IS_VALID (packetizer->last_in_time)) {
pcrtable = get_pcr_table (packetizer, packet->pid);
calculate_skew (packetizer, pcrtable, packet->pcr,
packetizer->last_in_time);
}
+#endif
if (packetizer->calculate_offset) {
if (!pcrtable)
pcrtable = get_pcr_table (packetizer, packet->pid);
}
}
#endif
+
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+/* Random Access indicator */
+ if (afcflags & MPEGTS_AFC_RANDOM_ACCES_FLAGS) {
+ GST_DEBUG ("Random access flag enabled: 0x40");
+ packetizer->is_random_access = TRUE;
+ }
+/*
+[prasenjit.c] For Jio Beats Audio-Only HLS Contents , PCR flags are not getting set.
+As a result , when DRC switch happens , Base Offset not getting updated resulting in timestamp mismatch.
+Currently have checked for adaptation control flags and if PCR is not getting set along with other flags , Skew calculation is done based on last_in_time.
+*/
+ if ((afcflags != 0x00)&&(!(afcflags & MPEGTS_AFC_PCR_FLAG)))
+ {
+ MpegTSPCR *pcrtable = NULL;
+ pcrtable = get_pcr_table (packetizer, packet->pid);
+ GST_DEBUG ("last_in_time %" GST_TIME_FORMAT " base_pcrtime:%" GST_TIME_FORMAT
+ " base_time:%" GST_TIME_FORMAT " pcroffset:%" GST_TIME_FORMAT " skew:%" GST_TIME_FORMAT " last_pcrtime:%" GST_TIME_FORMAT ,
+ GST_TIME_ARGS (packetizer->last_in_time),
+ GST_TIME_ARGS (pcrtable->base_pcrtime),
+ GST_TIME_ARGS (pcrtable->base_time),
+ GST_TIME_ARGS (pcrtable->pcroffset),
+ GST_TIME_ARGS (pcrtable->skew),
+ GST_TIME_ARGS (pcrtable->last_pcrtime));
+
+/*
+[prasenjit.c] For Hotstar Live Streams , PCR flags comes intermittently. This code was causing skew calculation getting done for those streams , causing invalid timestamps to get passed to Decoder.
+Blocked the code for Live Streams.
+Additionally , if Skew calculation is already done via this logic , need to disable RA flag to avoid base_time double recalculation.
+*/
+ if (((!GST_CLOCK_TIME_IS_VALID (pcrtable->base_time))||(!GST_CLOCK_TIME_IS_VALID (pcrtable->base_pcrtime)))&&(!packetizer->is_live_stream))
+ {
+ GST_WARNING ("PCR Flag is not set. Need to Reset the TS Basetime properly (disabling RA flag if enabled) !!!");
+ packet->pcr = packetizer->last_in_time;
+ calculate_skew (packetizer, pcrtable, packet->pcr,packetizer->last_in_time);
+ packetizer->is_random_access = FALSE;
+ }
+ }
+ else if ((afcflags == 0x00)&&(!(afcflags & MPEGTS_AFC_PCR_FLAG))&&(packetizer->is_live_stream))
+ {
+ GST_DEBUG ("Non-PCR Live Stream Case !!");
+ packetizer->is_non_pcr_live_feed = TRUE;
+ }
+#else
#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
if ((afcflags == 0x00) && (!(afcflags & MPEGTS_AFC_PCR_FLAG)) && (packetizer->is_live_stream)) {
GST_DEBUG ("Non-PCR Live Stream Case !!");
packetizer->is_non_pcr_live_feed = TRUE;
}
#endif
+#endif
return TRUE;
}
packetizer->map_offset = 0;
packetizer->last_in_time = GST_CLOCK_TIME_NONE;
#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ packetizer->ra_base_time = GST_CLOCK_TIME_NONE;
+ packetizer->is_random_access = FALSE;
packetizer->is_live_stream = FALSE;
#endif
GST_LOG
("PID 0x%04x PUSI and pointer == 0, skipping straight to section_start parsing",
packet->pid);
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ mpegts_packetizer_clear_section (stream);
+#endif
goto section_start;
}
}
pcr->prev_in_time = time;
pcr->prev_send_diff = send_diff;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ GST_DEBUG (" gstpcrtime %" GST_TIME_FORMAT " base_pcrtime:%" GST_TIME_FORMAT
+ " base_time:%" GST_TIME_FORMAT " pcroffset:%" GST_TIME_FORMAT " out_time:%" GST_TIME_FORMAT"skew:%" GST_TIME_FORMAT " last_pcrtime:%" GST_TIME_FORMAT ,
+ GST_TIME_ARGS (gstpcrtime),
+ GST_TIME_ARGS (pcr->base_pcrtime),
+ GST_TIME_ARGS (pcr->base_time),
+ GST_TIME_ARGS (pcr->pcroffset),
+ GST_TIME_ARGS (out_time),
+ GST_TIME_ARGS (pcr->skew),
+ GST_TIME_ARGS (pcr->last_pcrtime));
+#else
GST_DEBUG ("skew %" G_GINT64_FORMAT ", out %" GST_TIME_FORMAT,
pcr->skew, GST_TIME_ARGS (out_time));
+#endif
return out_time;
}
GST_DEBUG ("Wraparound prev-cur (guess_offset:%" GST_TIME_FORMAT
") bitrate:%" G_GUINT64_FORMAT,
GST_TIME_ARGS (PCRTIME_TO_GSTTIME (guess_offset)), lastbr);
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ if(prevbr == 0) {
+ GST_ERROR ("Division by zero error, prevbr is 0");
+ continue;
+ }
+#endif
diffprev = (float) 100.0 *(ABSDIFF (prevbr, lastbr)) / (float) prevbr;
GST_DEBUG ("Difference with previous bitrate:%f", diffprev);
if (diffprev < 10.0) {
/* Use clock skew if present */
if (packetizer->calculate_skew
&& GST_CLOCK_TIME_IS_VALID (pcrtable->base_time)) {
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ res = pts + pcrtable->pcroffset;
+ GST_DEBUG ("pts %" GST_TIME_FORMAT " base_pcrtime:%" GST_TIME_FORMAT
+ " base_time:%" GST_TIME_FORMAT " pcroffset:%" GST_TIME_FORMAT " res:%" GST_TIME_FORMAT"skew:%" GST_TIME_FORMAT " last_pcrtime:%" GST_TIME_FORMAT ,
+ GST_TIME_ARGS (pts),
+ GST_TIME_ARGS (pcrtable->base_pcrtime),
+ GST_TIME_ARGS (pcrtable->base_time),
+ GST_TIME_ARGS (pcrtable->pcroffset),
+ GST_TIME_ARGS (res),
+ GST_TIME_ARGS (pcrtable->skew),
+ GST_TIME_ARGS (pcrtable->last_pcrtime));
+#else
GST_DEBUG ("pts %" GST_TIME_FORMAT " base_pcrtime:%" GST_TIME_FORMAT
" base_time:%" GST_TIME_FORMAT " pcroffset:%" GST_TIME_FORMAT,
GST_TIME_ARGS (pts),
GST_TIME_ARGS (pcrtable->base_time),
GST_TIME_ARGS (pcrtable->pcroffset));
res = pts + pcrtable->pcroffset;
+#endif
/* Don't return anything if we differ too much against last seen PCR */
/* FIXME : Ideally we want to figure out whether we have a wraparound or
* That being said, this will only happen for the small interval of time
* where PTS/DTS are wrapping just before we see the first reset/wrap PCR
*/
+ /*
+ * [prasenjit.c] For some HLS Live servers (e.g tvpstream.tvp.pl ) , we observe erronous PCR values.
+ * As a result , last_pcrtime comes faulty which causes PTS values not to be calculated at all and buffers are dropped.
+ * We are currently ignoring the check for handling the erronous server PCR case.
+ */
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ GstClockTime tmp = pcrtable->base_time + pcrtable->skew;
+ if (packetizer->is_live_stream)
+ {
+ if (G_UNLIKELY (ABSDIFF (res, pcrtable->last_pcrtime) > 15 * GST_SECOND))
+ {
+ GST_WARNING ("Live Stream : Server sending erronous PCR values : Recalculating!!");
+ }
+ if (tmp + res > pcrtable->base_pcrtime)
+ {
+ res += tmp - pcrtable->base_pcrtime;
+ }
+ else
+ res = GST_CLOCK_TIME_NONE;
+ }
+ else
+ {
+ if (G_UNLIKELY (ABSDIFF (res, pcrtable->last_pcrtime) > 15 * GST_SECOND))
+ {
+ GST_WARNING ("VOD Stream : Server sending erronous PCR values : Maintaining old ts value !!!");
+ }
+ else if (tmp + res > pcrtable->base_pcrtime)
+ {
+ res += tmp - pcrtable->base_pcrtime;
+ }
+ else
+ res = GST_CLOCK_TIME_NONE;
+ }
+#else
if (G_UNLIKELY (ABSDIFF (res, pcrtable->last_pcrtime) > 15 * GST_SECOND))
res = GST_CLOCK_TIME_NONE;
else {
else
res = GST_CLOCK_TIME_NONE;
}
+#endif
} else if (packetizer->calculate_offset && pcrtable->groups) {
gint64 refpcr = G_MAXINT64, refpcroffset;
PCROffsetGroup *group = pcrtable->current->group;
GST_DEBUG ("Using group !");
refpcr = group->first_pcr;
refpcroffset = group->pcr_offset;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ if (pts < PCRTIME_TO_GSTTIME (refpcr)) {
+ if (PCRTIME_TO_GSTTIME (refpcr) - pts > GST_SECOND)
+ pts += PCR_GST_MAX_VALUE;
+ else
+ refpcr = G_MAXINT64;
+ }
+#else
if (pts < refpcr)
refpcr -= PCR_MAX_VALUE;
+#endif
}
}
if (refpcr != G_MAXINT64)
GST_WARNING ("No groups, can't calculate timestamp");
}
#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
- else if ((packetizer->is_non_pcr_live_feed) && (GST_CLOCK_TIME_IS_VALID(pts))) {
+ else if(packetizer->is_random_access){
+ if(!GST_CLOCK_TIME_IS_VALID (packetizer->ra_base_time))
+ packetizer->ra_base_time = pts;
+ res = pts - packetizer->ra_base_time;
+ } else if ((packetizer->is_non_pcr_live_feed) && (GST_CLOCK_TIME_IS_VALID(pts))) {
/*
[prasenjit.c] For Live Youtube Channels , PCR flag does not come.
Due to this , base offset of the content pts values are not obtained , so playback does not work.
/* Last inputted timestamp */
GstClockTime last_in_time;
#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ /* Random Access flag handling*/
+ GstClockTime ra_base_time;
+ gboolean is_random_access;
gboolean is_live_stream;
gboolean is_non_pcr_live_feed;
GstClockTime non_pcr_base_time;
demux->group_id = G_MAXUINT;
demux->last_seek_offset = -1;
+
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ demux->has_video = FALSE;
+ demux->video_keyframe_found = FALSE;
+#endif
#ifdef TIZEN_FEATURE_AVOID_PAD_SWITCHING
gst_ts_demux_remove_old_streams (demux, FALSE);
#endif
GST_DEBUG_OBJECT (stream->pad, "Found keyframe at: %u",
unit.sc_offset);
frame_unit = unit;
+
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ GstTSDemux *demux = GST_TS_DEMUX(gst_pad_get_parent(stream->pad));
+ demux->video_keyframe_found = TRUE;
+#endif
}
}
demux->last_seek_offset = base->seek_offset;
demux->rate = rate;
res = GST_FLOW_OK;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ demux->video_keyframe_found = FALSE;
+#endif
+
+ GST_DEBUG("seek_offset = %"G_GUINT64_FORMAT, base->seek_offset);
gst_segment_do_seek (&demux->segment, rate, format, flags, start_type,
start, stop_type, stop, NULL);
create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
MpegTSBaseProgram * program)
{
-#ifndef TIZEN_FEATURE_AVOID_PAD_SWITCHING
GstTSDemux *demux = GST_TS_DEMUX (base);
-#endif
TSDemuxStream *stream = (TSDemuxStream *) bstream;
gchar *name = NULL;
GstCaps *caps = NULL;
gst_pad_push_event (pad, event);
g_free (stream_id);
#endif
+
+//caps modification done for both audio and video streams by adding adaptive_streaming flag.
+//This flag will be used by parser / decoder to identify whether the stream is a HLS stream or not for their processing.
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ caps = gst_caps_make_writable (caps);
+ gst_caps_set_simple (caps,"adaptive_stream", G_TYPE_BOOLEAN, TRUE, "hls_stream", G_TYPE_BOOLEAN, TRUE, NULL);
+ GST_DEBUG("*** modified caps for hls streaming = %" GST_PTR_FORMAT,
+ caps);
+#endif
+
gst_pad_set_caps (pad, caps);
if (!stream->taglist)
stream->taglist = gst_tag_list_new_empty ();
gst_pad_set_event_function (pad, gst_ts_demux_srcpad_event);
}
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ /* Push pending tags */
+ if (stream->taglist) {
+ /* post now, send event on pad later */
+ GST_DEBUG_OBJECT (stream->pad, "Posting tags %" GST_PTR_FORMAT, stream->taglist);
+ gst_element_post_message (GST_ELEMENT_CAST (demux), gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (stream->taglist)));
+ }
+#endif
+
if (name)
g_free (name);
if (template)
&& bstream->stream_type == GST_MPEGTS_STREAM_TYPE_VIDEO_H264) {
stream->scan_function =
(GstTsDemuxKeyFrameScanFunction) scan_keyframe_h264;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ demux->has_video = TRUE;
+#endif
} else {
stream->scan_function = NULL;
}
demux->segment.time = firstts;
demux->segment.rate = demux->rate;
demux->segment.base = base;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ /*Modification : when first program using firstts, but if seek,
+ gst_ts_demux_do_seek() already set the segment*/
+ if(demux->reset_segment)
+ {
+ demux->reset_segment = FALSE;
+ }
+#endif
}
} else if (demux->segment.start < firstts) {
/* Take into account the offset to the first buffer timestamp */
if (stream->needs_keyframe) {
MpegTSBase *base = (MpegTSBase *) demux;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ /*FIXME : for seek case, only when ts stream has video and also video stream had found the key_frame, then push the stream*/
+ if ((gst_ts_demux_adjust_seek_offset_for_keyframe (stream, stream->data,
+ stream->current_size) && (demux->has_video ? demux->video_keyframe_found : TRUE) ) || demux->last_seek_offset == 0)
+#else
if ((gst_ts_demux_adjust_seek_offset_for_keyframe (stream, stream->data,
- stream->current_size)) || demux->last_seek_offset == 0) {
+ stream->current_size) ) || demux->last_seek_offset == 0)
+#endif
+ {
GST_DEBUG_OBJECT (stream->pad,
"Got Keyframe, ready to go at %" GST_TIME_FORMAT,
GST_TIME_ARGS (stream->pts));
stream->seeked_dts = stream->dts;
stream->needs_keyframe = FALSE;
} else {
- base->seek_offset = demux->last_seek_offset - 200 * base->packetsize;
- if (demux->last_seek_offset < 200 * (guint64)base->packetsize)
- base->seek_offset = 0;
- demux->last_seek_offset = base->seek_offset;
- mpegts_packetizer_flush (base->packetizer, FALSE);
- base->mode = BASE_MODE_SEEKING;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ /*Modification : fix seek performance issue, when found one non-keyframe,
+ need to combine the left packets to a complete frame and check if it is Keyframe */
+ if(base->seek_offset - demux->last_seek_offset > 100 * base->packetsize)
+ {
+ base->seek_offset = demux->last_seek_offset - 100 * base->packetsize;
+#else
+ base->seek_offset = demux->last_seek_offset - 200 * base->packetsize;
+#endif
+ if (demux->last_seek_offset < 200 * base->packetsize)
+ base->seek_offset = 0;
+ demux->last_seek_offset = base->seek_offset;
+ mpegts_packetizer_flush (base->packetizer, FALSE);
+ base->mode = BASE_MODE_SEEKING;
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ }
+#endif
stream->continuity_counter = CONTINUITY_UNSET;
res = GST_FLOW_REWINDING;
g_free (stream->data);
/* Used when seeking for a keyframe to go backward in the stream */
guint64 last_seek_offset;
+
+#ifdef TIZEN_FEATURE_TSDEMUX_MODIFICATION
+ gboolean video_keyframe_found;
+ gboolean has_video;
+#endif
};
struct _GstTSDemuxClass
Name: gst-plugins-bad
Version: 1.6.1
-Release: 9
+Release: 10
Summary: GStreamer Streaming-Media Framework Plug-Ins
License: LGPL-2.0+
Group: Multimedia/Framework
%build
export V=1
NOCONFIGURE=1 ./autogen.sh
-export CFLAGS+=" -Wall -g -fPIC -DTIZEN_FEATURE_WLSINK_ENHANCEMENT -DTIZEN_FEATURE_AVOID_PAD_SWITCHING -DTIZEN_FEATURE_ADAPTIVE_MODIFICATION -DTIZEN_FEATURE_TSDEMUX_MODIFICATION -DTIZEN_FEATURE_UPSTREAM"
+export CFLAGS+=" -Wall -g -fPIC\
+ -DTIZEN_FEATURE_WLSINK_ENHANCEMENT\
+ -DTIZEN_FEATURE_AVOID_PAD_SWITCHING\
+ -DTIZEN_FEATURE_ADAPTIVE_MODIFICATION\
+ -DTIZEN_FEATURE_TSDEMUX_MODIFICATION\
+ -DTIZEN_FEATURE_UPSTREAM"
+
%configure\
--disable-static\
--disable-examples\
--disable-adpcmenc\
--disable-aiff\
--disable-asfmux\
- --disable-audiomixer\
--disable-compositor\
--disable-audiovisualizers\
--disable-bayer\
#%{_libdir}/gstreamer-%{gst_branch}/libgstvideofiltersbad.so
#%{_libdir}/gstreamer-%{gst_branch}/libgstyadif.so
#%{_libdir}/gstreamer-%{gst_branch}/libgstuvch264.so
+%{_libdir}/gstreamer-%{gst_branch}/libgstaudiomixer.so
%if %{with wayland}
%{_libdir}/libgstwayland-%{gst_branch}.so.0*