summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Santos <thiagossantos@gmail.com>2016-10-02 16:42:26 -0300
committerThiago Santos <thiagossantos@gmail.com>2016-10-02 16:42:26 -0300
commit986de7eb01641789fcdb6d90f838887d607f44f1 (patch)
tree1d7c81b19e6f0a5be0b80264fc0602f780bdec98
parent55a0d5d7baecb4e163eddbe4afab21c399a3b0b7 (diff)
-rw-r--r--ext/dash/gstdashdemux.c48
-rw-r--r--ext/dash/gstmpdparser.c229
-rw-r--r--ext/dash/gstmpdparser.h5
-rw-r--r--gst-libs/gst/adaptivedemux/gstadaptivedemux.c20
-rw-r--r--gst/mpegtsdemux/mpegtsparse.c2
5 files changed, 290 insertions, 14 deletions
diff --git a/ext/dash/gstdashdemux.c b/ext/dash/gstdashdemux.c
index c6ded2e80..49e6ea3e3 100644
--- a/ext/dash/gstdashdemux.c
+++ b/ext/dash/gstdashdemux.c
@@ -850,11 +850,17 @@ gst_dash_demux_setup_streams (GstAdaptiveDemux * demux)
* is closest to current time */
if (gst_mpd_client_is_live (dashdemux->client)) {
GDateTime *gnow;
+ GDateTime *stream_now;
- GST_DEBUG_OBJECT (demux, "Seeking to current time of day for live stream ");
+ GST_DEBUG_OBJECT (demux, "Seeking to current time of day for live stream");
gnow = gst_date_time_to_g_date_time (now);
- gst_mpd_client_seek_to_time (dashdemux->client, gnow);
+ stream_now = gst_mpd_client_get_earliest_last_fragment (dashdemux->client);
+
+ GST_ERROR ("NOW: %s %s", g_date_time_format (gnow, "%F %T"),
+ g_date_time_format (stream_now, "%F %T"));
+
+ gst_mpd_client_seek_to_time (dashdemux->client, stream_now);
g_date_time_unref (gnow);
} else {
GST_DEBUG_OBJECT (demux, "Seeking to first segment for on-demand stream ");
@@ -1730,7 +1736,7 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
return GST_FLOW_ERROR;
}
- /* update the streams to play from the next segment */
+ /* Get to the correct segment to continue playing */
for (iter = demux->streams, streams_iter = new_client->active_streams;
iter && streams_iter;
iter = g_list_next (iter), streams_iter = g_list_next (streams_iter)) {
@@ -1747,6 +1753,37 @@ gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
return GST_FLOW_EOS;
}
+ /* Try to synchronize if the new-client first fragment ts=0 but start!=0
+ *
+ * This likely means we need to rely on the previous manifest data to
+ * properly get continuity in the ts fragments.
+ */
+ {
+ guint start_index, new_start_index;
+ GstClockTime old_timestamp, new_timestamp, timestamp;
+
+ start_index =
+ gst_mpd_client_stream_get_first_fragment_number (dashdemux->client,
+ demux_stream->active_stream, &old_timestamp);
+ new_start_index =
+ gst_mpd_client_stream_get_first_fragment_number (new_client,
+ new_stream, &new_timestamp);
+ GST_ERROR ("NEW INDEX: %u %u %" GST_TIME_FORMAT, start_index,
+ new_start_index, GST_TIME_ARGS (new_timestamp));
+ if (new_start_index != 0 && new_start_index != start_index
+ && new_timestamp == 0) {
+ timestamp =
+ gst_mpd_client_stream_get_timestamp_for_fragment
+ (dashdemux->client, demux_stream->active_stream, new_start_index);
+ GST_ERROR ("ADDING TIMESTAMP: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
+ GST_ERROR ("ADDING TIMESTAMP: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp - new_timestamp));
+ gst_mpd_client_stream_add_timestamp (new_client, new_stream,
+ timestamp - new_timestamp);
+ }
+ }
+
if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
demux_stream->index, &ts)
|| gst_mpd_client_get_last_fragment_timestamp_end (dashdemux->client,
@@ -1814,6 +1851,11 @@ gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
gst_date_time_new_from_g_date_time
(gst_adaptive_demux_get_client_now_utc (GST_ADAPTIVE_DEMUX_CAST
(dashdemux)));
+
+ GST_ERROR ("AVAILABILITY: %s",
+ gst_date_time_to_iso8601_string (segmentAvailability));
+ GST_ERROR (" NOW: %s", gst_date_time_to_iso8601_string (cur_time));
+
diff =
gst_mpd_client_calculate_time_difference (cur_time,
segmentAvailability);
diff --git a/ext/dash/gstmpdparser.c b/ext/dash/gstmpdparser.c
index e6d7283de..1d9d66549 100644
--- a/ext/dash/gstmpdparser.c
+++ b/ext/dash/gstmpdparser.c
@@ -1620,6 +1620,8 @@ gst_mpdparser_parse_mult_seg_base_type_ext (GstMultSegmentBaseType ** pointer,
mult_seg_base_type->startNumber = intval;
}
+ GST_ERROR ("STARTNUMBER: %u", (guint) mult_seg_base_type->startNumber);
+
GST_LOG ("extension of MultipleSegmentBaseType extension:");
gst_mpdparser_parse_seg_base_type_ext (&mult_seg_base_type->SegBaseType,
a_node, (parent ? parent->SegBaseType : NULL));
@@ -2261,6 +2263,8 @@ gst_mpdparser_parse_root_node (GstMPDNode ** pointer, xmlNode * a_node)
gst_mpdparser_get_xml_prop_type (a_node, "type", &new_mpd->type);
gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityStartTime",
&new_mpd->availabilityStartTime);
+ GST_ERROR ("XAVAILABILITY: %s",
+ gst_date_time_to_iso8601_string (new_mpd->availabilityStartTime));
gst_mpdparser_get_xml_prop_dateTime (a_node, "availabilityEndTime",
&new_mpd->availabilityEndTime);
gst_mpdparser_get_xml_prop_duration (a_node, "mediaPresentationDuration",
@@ -4736,12 +4740,15 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
g_return_val_if_fail (stream != NULL, 0);
+ GST_ERROR ("SEEK TO : %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
+
if (stream->segments) {
for (index = 0; index < stream->segments->len; index++) {
GstMediaSegment *segment = g_ptr_array_index (stream->segments, index);
- GST_DEBUG ("Looking at fragment sequence chunk %d / %d", index,
- stream->segments->len);
+ GST_WARNING ("Looking at fragment sequence chunk %d / %d %"
+ GST_TIME_FORMAT, index, stream->segments->len,
+ GST_TIME_ARGS (segment->start));
in_segment = FALSE;
if (segment->start <= ts) {
GstClockTime end_time;
@@ -4794,9 +4801,12 @@ gst_mpd_client_stream_seek (GstMpdClient * client, GstActiveStream * stream,
if (selectedChunk == NULL) {
stream->segment_index = stream->segments->len;
stream->segment_repeat_index = 0;
- GST_DEBUG ("Seek to after last segment");
+ GST_ERROR ("Seek to after last segment");
return FALSE;
}
+ GST_ERROR ("GOOD SEEK: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (selectedChunk->start +
+ selectedChunk->duration * repeat_index));
if (final_ts)
*final_ts = selectedChunk->start + selectedChunk->duration * repeat_index;
@@ -4895,6 +4905,43 @@ gst_mpd_client_get_availability_start_time (GstMpdClient * client)
}
gboolean
+gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client,
+ guint stream_idx, GstClockTime * ts)
+{
+ GstActiveStream *stream;
+ gint segment_idx;
+ GstMediaSegment *currentChunk;
+ GstStreamPeriod *stream_period;
+
+ 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);
+
+ if (!stream->segments) {
+ stream_period = gst_mpdparser_get_stream_period (client);
+ *ts = stream_period->start;
+ } else {
+ segment_idx = gst_mpd_client_get_segments_counts (client, stream) - 1;
+ currentChunk = g_ptr_array_index (stream->segments, segment_idx);
+
+ if (currentChunk->repeat >= 0) {
+ *ts =
+ currentChunk->start +
+ (currentChunk->duration * (currentChunk->repeat));
+ } else {
+ /* 5.3.9.6.1: negative repeat means repeat till the end of the
+ * period, or the next update of the MPD (which I think is
+ * implicit, as this will all get deleted/recreated), or the
+ * start of the next segment, if any. */
+ stream_period = gst_mpdparser_get_stream_period (client);
+ *ts = stream_period->start;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
gst_mpd_client_get_last_fragment_timestamp_end (GstMpdClient * client,
guint stream_idx, GstClockTime * ts)
{
@@ -5592,6 +5639,26 @@ gst_mpd_client_seek_to_first_segment (GstMpdClient * client)
}
}
+#if 0
+void
+gst_mpd_client_seek_to_last_segment (GstMpdClient * client)
+{
+ GList *list;
+
+ g_return_if_fail (client != NULL);
+ g_return_if_fail (client->active_streams != NULL);
+
+ for (list = g_list_first (client->active_streams); list;
+ list = g_list_next (list)) {
+ GstActiveStream *stream = (GstActiveStream *) list->data;
+ if (stream) {
+ stream->segment_index = 0;
+ stream->segment_repeat_index = 0;
+ }
+ }
+}
+#endif
+
static guint
gst_mpd_client_get_segments_counts (GstMpdClient * client,
GstActiveStream * stream)
@@ -5890,14 +5957,20 @@ gst_mpd_client_get_next_segment_availability_start_time (GstMpdClient * client,
if (segment->repeat >= 0) {
segmentEndTime = segment->start + (stream->segment_repeat_index + 1) *
segment->duration;
+ GST_ERROR ("SEGENDTIME repeat: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (segmentEndTime));
} else if (seg_idx < stream->segments->len - 1) {
const GstMediaSegment *next_segment =
g_ptr_array_index (stream->segments, seg_idx + 1);
segmentEndTime = next_segment->start;
+ GST_ERROR ("SEGENDTIME norepeat: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (segmentEndTime));
} else {
const GstStreamPeriod *stream_period;
stream_period = gst_mpdparser_get_stream_period (client);
segmentEndTime = stream_period->start + stream_period->duration;
+ GST_ERROR ("SEGENDTIME perioddur: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (segmentEndTime));
}
} else {
GstClockTime seg_duration;
@@ -5905,9 +5978,13 @@ gst_mpd_client_get_next_segment_availability_start_time (GstMpdClient * client,
if (seg_duration == 0)
return NULL;
segmentEndTime = (1 + seg_idx) * seg_duration;
+ GST_ERROR ("SEGENDTIME segidx: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (segmentEndTime));
}
availability_start_time = gst_mpd_client_get_availability_start_time (client);
+ GST_ERROR ("AVAILABILITY: %s",
+ gst_date_time_to_iso8601_string (availability_start_time));
if (availability_start_time == NULL) {
GST_WARNING_OBJECT (client, "Failed to get availability_start_time");
return NULL;
@@ -5920,6 +5997,10 @@ gst_mpd_client_get_next_segment_availability_start_time (GstMpdClient * client,
gst_date_time_unref (availability_start_time);
availability_start_time = t;
+ GST_ERROR ("PERIOD START: %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (stream_period->start));
+ GST_ERROR ("NEW AVAILABILITY: %s",
+ gst_date_time_to_iso8601_string (availability_start_time));
if (availability_start_time == NULL) {
GST_WARNING_OBJECT (client, "Failed to offset availability_start_time");
return NULL;
@@ -5928,6 +6009,8 @@ gst_mpd_client_get_next_segment_availability_start_time (GstMpdClient * client,
rv = gst_mpd_client_add_time_difference (availability_start_time,
segmentEndTime / GST_USECOND);
+ GST_ERROR ("Updated AVAILABILITY: %s",
+ gst_date_time_to_iso8601_string (availability_start_time));
gst_date_time_unref (availability_start_time);
if (rv == NULL) {
GST_WARNING_OBJECT (client, "Failed to offset availability_start_time");
@@ -5945,6 +6028,7 @@ gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
GstClockTime ts;
gboolean ret = TRUE;
GList *stream;
+ GstStreamPeriod *stream_period;
g_return_val_if_fail (gst_mpd_client_is_live (client), FALSE);
g_return_val_if_fail (client->mpd_node->availabilityStartTime != NULL, FALSE);
@@ -5952,6 +6036,9 @@ gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
start =
gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
+ GST_ERROR ("%s %s", g_date_time_format (time, "%F %T"),
+ g_date_time_format (start, "%F %T"));
+
ts_microseconds = g_date_time_difference (time, start);
g_date_time_unref (start);
@@ -5959,7 +6046,10 @@ gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
if (ts_microseconds < 0)
ts_microseconds = 0;
+ stream_period = gst_mpdparser_get_stream_period (client);
+
ts = ts_microseconds * GST_USECOND;
+ ts -= stream_period->start;
for (stream = client->active_streams; stream; stream = g_list_next (stream)) {
ret =
ret & gst_mpd_client_stream_seek (client, stream->data, TRUE, 0, ts,
@@ -5968,6 +6058,139 @@ gst_mpd_client_seek_to_time (GstMpdClient * client, GDateTime * time)
return ret;
}
+GDateTime *
+gst_mpd_client_get_earliest_last_fragment (GstMpdClient * client)
+{
+ GDateTime *start;
+ GstClockTime lowest_ts;
+ GDateTime *ret = NULL;
+ GList *stream;
+ GstStreamPeriod *stream_period;
+ gint i;
+
+ g_return_val_if_fail (gst_mpd_client_is_live (client), FALSE);
+ g_return_val_if_fail (client->mpd_node->availabilityStartTime != NULL, FALSE);
+
+ start =
+ gst_date_time_to_g_date_time (client->mpd_node->availabilityStartTime);
+
+ /* FIXME we assume live has a single period, might not always be true */
+ stream_period = gst_mpdparser_get_stream_period (client);
+
+ lowest_ts = GST_CLOCK_TIME_NONE;
+ for (i = 0, stream = client->active_streams; stream;
+ stream = g_list_next (stream), i++) {
+ GstClockTime ts;
+
+ if (gst_mpd_client_get_last_fragment_timestamp (client, i, &ts))
+ lowest_ts = lowest_ts == GST_CLOCK_TIME_NONE ? ts : MIN (ts, lowest_ts);
+ }
+
+ lowest_ts += stream_period->start;
+ ret = g_date_time_add_seconds (start, ((gdouble) lowest_ts) / GST_SECOND);
+ g_date_time_unref (start);
+
+ return ret;
+}
+
+guint
+gst_mpd_client_stream_get_first_fragment_number (GstMpdClient * client,
+ GstActiveStream * stream, GstClockTime * ts)
+{
+ guint segment_idx = 0;
+ GstClockTime _ts = GST_CLOCK_TIME_NONE;
+ GstMediaSegment *currentChunk;
+ GstStreamPeriod *stream_period;
+
+ g_return_val_if_fail (stream != NULL, 0);
+
+ if (!stream->segments) {
+ stream_period = gst_mpdparser_get_stream_period (client);
+ _ts = stream_period->start;
+ } else {
+ currentChunk = g_ptr_array_index (stream->segments, 0);
+
+ segment_idx = currentChunk->number;
+ if (currentChunk->repeat >= 0) {
+ _ts =
+ currentChunk->start +
+ (currentChunk->duration * (currentChunk->repeat));
+ } else {
+ /* 5.3.9.6.1: negative repeat means repeat till the end of the
+ * period, or the next update of the MPD (which I think is
+ * implicit, as this will all get deleted/recreated), or the
+ * start of the next segment, if any. */
+ stream_period = gst_mpdparser_get_stream_period (client);
+ _ts = stream_period->start;
+ }
+ }
+
+ if (ts)
+ *ts = _ts;
+
+ return segment_idx;
+}
+
+static gint
+gst_mpd_client_stream_get_segment_by_index (GstMpdClient * client,
+ GstActiveStream * stream, gint index, gint * repeat)
+{
+ GstMediaSegment *segment;
+ gint i;
+
+ for (i = 0; i < stream->segments->len; i++) {
+ segment = g_ptr_array_index (stream->segments, i);
+ if (segment->number <= index + segment->repeat) {
+ *repeat = index - segment->number;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+GstClockTime
+gst_mpd_client_stream_get_timestamp_for_fragment (GstMpdClient * client,
+ GstActiveStream * stream, guint index)
+{
+ GstClockTime ts = GST_CLOCK_TIME_NONE;
+ GstMediaSegment *currentChunk;
+
+ g_return_val_if_fail (stream != NULL, 0);
+
+ if (!stream->segments) {
+ GstStreamPeriod *stream_period;
+
+ stream_period = gst_mpdparser_get_stream_period (client);
+ ts = stream_period->start;
+ } else {
+ gint repeat = 0;
+ gint array_index =
+ gst_mpd_client_stream_get_segment_by_index (client, stream, index,
+ &repeat);
+
+ GST_ERROR ("ARRAY: %d %d %d", index, array_index, repeat);
+ currentChunk = g_ptr_array_index (stream->segments, array_index);
+ ts = currentChunk->start + (currentChunk->duration * (repeat));
+ }
+
+ return ts;
+}
+
+void
+gst_mpd_client_stream_add_timestamp (GstMpdClient * client,
+ GstActiveStream * stream, GstClockTimeDiff diff)
+{
+ GstMediaSegment *segment;
+ gint i;
+
+ for (i = 0; i < stream->segments->len; i++) {
+ segment = g_ptr_array_index (stream->segments, i);
+ segment->start += diff;
+ /* TODO update other time values? */
+ }
+}
+
void
gst_media_fragment_info_clear (GstMediaFragmentInfo * fragment)
{
diff --git a/ext/dash/gstmpdparser.h b/ext/dash/gstmpdparser.h
index 85b97ea2a..a27b0c181 100644
--- a/ext/dash/gstmpdparser.h
+++ b/ext/dash/gstmpdparser.h
@@ -539,6 +539,11 @@ gboolean gst_mpd_client_setup_representation (GstMpdClient *client, GstActiveStr
GstClockTime gst_mpd_client_get_next_fragment_duration (GstMpdClient * client, GstActiveStream * stream);
GstClockTime gst_mpd_client_get_media_presentation_duration (GstMpdClient *client);
GstClockTime gst_mpd_client_get_maximum_segment_duration (GstMpdClient * client);
+GDateTime * gst_mpd_client_get_earliest_last_fragment (GstMpdClient * client);
+guint gst_mpd_client_stream_get_first_fragment_number (GstMpdClient * client, GstActiveStream * stream, GstClockTime * ts);
+GstClockTime gst_mpd_client_stream_get_timestamp_for_fragment (GstMpdClient * client, GstActiveStream * stream, guint index);
+void gst_mpd_client_stream_add_timestamp (GstMpdClient * client, GstActiveStream * stream, GstClockTimeDiff ts);
+gboolean gst_mpd_client_get_last_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_last_fragment_timestamp_end (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment_timestamp (GstMpdClient * client, guint stream_idx, GstClockTime * ts);
gboolean gst_mpd_client_get_next_fragment (GstMpdClient *client, guint indexStream, GstMediaFragmentInfo * fragment);
diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
index 715893c48..33989b61d 100644
--- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
+++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
@@ -986,6 +986,8 @@ gst_adaptive_demux_expose_streams (GstAdaptiveDemux * demux,
} else {
min_pts = stream->fragment.timestamp;
}
+ min_pts +=
+ gst_adaptive_demux_stream_get_presentation_offset (demux, stream);
}
}
@@ -1059,20 +1061,24 @@ gst_adaptive_demux_expose_streams (GstAdaptiveDemux * demux,
* equivalent.
*/
+ GST_ERROR_OBJECT (stream->pad,
+ "SEGMENT: %" GST_TIME_FORMAT " %" GST_TIME_FORMAT " %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->segment.start), GST_TIME_ARGS (period_start),
+ GST_TIME_ARGS (offset));
if (demux->segment.start > period_start) {
stream->segment.start = demux->segment.start - period_start + offset;
stream->segment.position = offset;
stream->segment.time = demux->segment.time;
stream->segment.base = demux->segment.base;
} else {
- stream->segment.start = offset;
- stream->segment.position = offset;
+ stream->segment.start = MAX (demux->segment.start, offset);
+ stream->segment.position = MAX (demux->segment.start, offset);
stream->segment.time =
gst_segment_to_stream_time (&demux->segment, GST_FORMAT_TIME,
period_start);
- stream->segment.base =
- gst_segment_to_running_time (&demux->segment, GST_FORMAT_TIME,
- period_start);
+ stream->segment.base = demux->segment.base;
+// gst_segment_to_running_time (&demux->segment, GST_FORMAT_TIME,
+// period_start - demux->first_period_start);
}
stream->pending_segment = gst_event_new_segment (&stream->segment);
@@ -3211,8 +3217,8 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
gint64 wait_time =
gst_adaptive_demux_stream_get_fragment_waiting_time (demux, stream);
if (wait_time > 0) {
- GstClockTime end_time =
- gst_adaptive_demux_get_monotonic_time (demux) + wait_time;
+ GstClockTime now_time = gst_adaptive_demux_get_monotonic_time (demux);
+ GstClockTime end_time = now_time + wait_time;
GST_DEBUG_OBJECT (stream->pad, "Download waiting for %" GST_TIME_FORMAT,
GST_TIME_ARGS (wait_time));
diff --git a/gst/mpegtsdemux/mpegtsparse.c b/gst/mpegtsdemux/mpegtsparse.c
index 7bf8fc4e3..fd14633be 100644
--- a/gst/mpegtsdemux/mpegtsparse.c
+++ b/gst/mpegtsdemux/mpegtsparse.c
@@ -832,7 +832,7 @@ drain_pending_buffers (MpegTSParse2 * parse, gboolean drain_all)
pos += gst_buffer_get_size (buffer);
- GST_DEBUG_OBJECT (parse,
+ GST_ERROR_OBJECT (parse,
"InputTS %" GST_TIME_FORMAT " out %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)), GST_TIME_ARGS (out_ts));