diff options
author | Thiago Santos <thiagossantos@gmail.com> | 2016-10-02 16:42:26 -0300 |
---|---|---|
committer | Thiago Santos <thiagossantos@gmail.com> | 2016-10-02 16:42:26 -0300 |
commit | 986de7eb01641789fcdb6d90f838887d607f44f1 (patch) | |
tree | 1d7c81b19e6f0a5be0b80264fc0602f780bdec98 | |
parent | 55a0d5d7baecb4e163eddbe4afab21c399a3b0b7 (diff) |
wipdash-youtube
-rw-r--r-- | ext/dash/gstdashdemux.c | 48 | ||||
-rw-r--r-- | ext/dash/gstmpdparser.c | 229 | ||||
-rw-r--r-- | ext/dash/gstmpdparser.h | 5 | ||||
-rw-r--r-- | gst-libs/gst/adaptivedemux/gstadaptivedemux.c | 20 | ||||
-rw-r--r-- | gst/mpegtsdemux/mpegtsparse.c | 2 |
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)); |