From 3226160b31aa6a3792edba9e2a24dac9fbe27b6b Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sun, 2 Sep 2012 23:32:50 -0700 Subject: [PATCH] baseparse: First attempt at handling both DTS and PTS --- libs/gst/base/gstbaseparse.c | 162 ++++++++++++++++++++++------------- 1 file changed, 101 insertions(+), 61 deletions(-) diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c index bcc8f75449..b91c47acd0 100644 --- a/libs/gst/base/gstbaseparse.c +++ b/libs/gst/base/gstbaseparse.c @@ -261,8 +261,10 @@ struct _GstBaseParsePrivate gint64 offset; gint64 sync_offset; - GstClockTime next_ts; - GstClockTime prev_ts; + GstClockTime next_pts; + GstClockTime next_dts; + GstClockTime prev_pts; + GstClockTime prev_dts; GstClockTime frame_duration; gboolean seen_keyframe; gboolean is_video; @@ -272,7 +274,8 @@ struct _GstBaseParsePrivate guint64 bytecount; guint64 data_bytecount; guint64 acc_duration; - GstClockTime first_frame_ts; + GstClockTime first_frame_pts; + GstClockTime first_frame_dts; gint64 first_frame_offset; gboolean post_min_bitrate; @@ -315,7 +318,8 @@ struct _GstBaseParsePrivate GSList *buffers_head; GSList *buffers_queued; GSList *buffers_send; - GstClockTime last_ts; + GstClockTime last_pts; + GstClockTime last_dts; gint64 last_offset; /* Pending serialized events */ @@ -712,11 +716,13 @@ gst_base_parse_reset (GstBaseParse * parse) parse->priv->framecount = 0; parse->priv->bytecount = 0; parse->priv->acc_duration = 0; - parse->priv->first_frame_ts = GST_CLOCK_TIME_NONE; + parse->priv->first_frame_pts = GST_CLOCK_TIME_NONE; + parse->priv->first_frame_dts = GST_CLOCK_TIME_NONE; parse->priv->first_frame_offset = -1; parse->priv->estimated_duration = -1; parse->priv->estimated_drift = 0; - parse->priv->next_ts = 0; + parse->priv->next_pts = 0; + parse->priv->next_dts = 0; parse->priv->syncable = TRUE; parse->priv->passthrough = FALSE; parse->priv->has_timing_info = FALSE; @@ -738,7 +744,8 @@ gst_base_parse_reset (GstBaseParse * parse) parse->priv->exact_position = TRUE; parse->priv->seen_keyframe = FALSE; - parse->priv->last_ts = GST_CLOCK_TIME_NONE; + parse->priv->last_dts = GST_CLOCK_TIME_NONE; + parse->priv->last_pts = GST_CLOCK_TIME_NONE; parse->priv->last_offset = 0; g_list_foreach (parse->priv->pending_events, (GFunc) gst_mini_object_unref, @@ -779,9 +786,13 @@ gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) { GstBuffer *buffer = frame->buffer; - if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && - GST_CLOCK_TIME_IS_VALID (parse->priv->next_ts)) { - GST_BUFFER_TIMESTAMP (buffer) = parse->priv->next_ts; + if (!GST_BUFFER_PTS_IS_VALID (buffer) && + GST_CLOCK_TIME_IS_VALID (parse->priv->next_pts)) { + GST_BUFFER_PTS (buffer) = parse->priv->next_pts; + } + if (!GST_BUFFER_DTS_IS_VALID (buffer) && + GST_CLOCK_TIME_IS_VALID (parse->priv->next_dts)) { + GST_BUFFER_DTS (buffer) = parse->priv->next_dts; } if (!GST_BUFFER_DURATION_IS_VALID (buffer) && GST_CLOCK_TIME_IS_VALID (parse->priv->frame_duration)) { @@ -941,7 +952,7 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) { const GstSegment *in_segment; GstSegment out_segment; - gint64 offset = 0, next_ts; + gint64 offset = 0, next_pts; #if 0 gdouble rate, applied_rate; @@ -984,7 +995,7 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) out_segment.stop = seek->segment.stop; out_segment.time = seek->segment.start; - next_ts = seek->start_ts; + next_pts = seek->start_ts; parse->priv->exact_position = seek->accurate; g_free (seek); } else { @@ -992,11 +1003,11 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) /* as these are only estimates, stop is kept open-ended to avoid * premature cutting */ gst_base_parse_convert (parse, GST_FORMAT_BYTES, in_segment->start, - GST_FORMAT_TIME, (gint64 *) & next_ts); + GST_FORMAT_TIME, (gint64 *) & next_pts); - out_segment.start = next_ts; + out_segment.start = next_pts; out_segment.stop = GST_CLOCK_TIME_NONE; - out_segment.time = next_ts; + out_segment.time = next_pts; parse->priv->exact_position = (in_segment->start == 0); } @@ -1019,12 +1030,12 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) event = gst_event_new_segment (&out_segment); - next_ts = 0; + next_pts = 0; } else { /* not considered BYTE seekable if it is talking to us in TIME, * whatever else it might claim */ parse->priv->upstream_seekable = FALSE; - next_ts = in_segment->start; + next_pts = in_segment->start; } memcpy (&parse->segment, &out_segment, sizeof (GstSegment)); @@ -1052,8 +1063,9 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) parse->priv->offset = offset; parse->priv->sync_offset = offset; - parse->priv->next_ts = next_ts; - parse->priv->last_ts = GST_CLOCK_TIME_NONE; + parse->priv->next_pts = next_pts; + parse->priv->last_pts = GST_CLOCK_TIME_NONE; + parse->priv->last_dts = GST_CLOCK_TIME_NONE; parse->priv->discont = TRUE; parse->priv->seen_keyframe = FALSE; break; @@ -1073,7 +1085,8 @@ gst_base_parse_sink_eventfunc (GstBaseParse * parse, GstEvent * event) gst_base_parse_clear_queues (parse); parse->priv->flushing = FALSE; parse->priv->discont = TRUE; - parse->priv->last_ts = GST_CLOCK_TIME_NONE; + parse->priv->last_pts = GST_CLOCK_TIME_NONE; + parse->priv->last_dts = GST_CLOCK_TIME_NONE; parse->priv->new_frame = TRUE; break; @@ -1777,7 +1790,7 @@ gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer, /* track skipping */ if (*skip > 0) { - GstClockTime timestamp; + GstClockTime pts, dts; GstBuffer *outbuf; GST_LOG_OBJECT (parse, "finding sync, skipping %d bytes", *skip); @@ -1785,10 +1798,12 @@ gst_base_parse_handle_buffer (GstBaseParse * parse, GstBuffer * buffer, /* reverse playback, and no frames found yet, so we are skipping * the leading part of a fragment, which may form the tail of * fragment coming later, hopefully subclass skips efficiently ... */ - timestamp = gst_adapter_prev_timestamp (parse->priv->adapter, NULL); + pts = gst_adapter_prev_pts (parse->priv->adapter, NULL); + dts = gst_adapter_prev_dts (parse->priv->adapter, NULL); outbuf = gst_adapter_take_buffer (parse->priv->adapter, *skip); outbuf = gst_buffer_make_writable (outbuf); - GST_BUFFER_TIMESTAMP (outbuf) = timestamp; + GST_BUFFER_PTS (outbuf) = pts; + GST_BUFFER_DTS (outbuf) = dts; parse->priv->buffers_head = g_slist_prepend (parse->priv->buffers_head, outbuf); outbuf = NULL; @@ -1842,13 +1857,14 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, /* check if subclass/format can provide ts. * If so, that allows and enables extra seek and duration determining options */ if (G_UNLIKELY (parse->priv->first_frame_offset < 0)) { - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && parse->priv->has_timing_info + if (GST_BUFFER_PTS_IS_VALID (buffer) && parse->priv->has_timing_info && parse->priv->pad_mode == GST_PAD_MODE_PULL) { parse->priv->first_frame_offset = offset; - parse->priv->first_frame_ts = GST_BUFFER_TIMESTAMP (buffer); + parse->priv->first_frame_pts = GST_BUFFER_PTS (buffer); + parse->priv->first_frame_dts = GST_BUFFER_DTS (buffer); GST_DEBUG_OBJECT (parse, "subclass provided ts %" GST_TIME_FORMAT " for first frame at offset %" G_GINT64_FORMAT, - GST_TIME_ARGS (parse->priv->first_frame_ts), + GST_TIME_ARGS (parse->priv->first_frame_pts), parse->priv->first_frame_offset); if (!GST_CLOCK_TIME_IS_VALID (parse->priv->duration)) { gint64 off; @@ -1868,21 +1884,28 @@ gst_base_parse_handle_and_push_frame (GstBaseParse * parse, /* again use default handler to add missing metadata; * we may have new information on frame properties */ gst_base_parse_parse_frame (parse, frame); - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) && - GST_BUFFER_DURATION_IS_VALID (buffer)) { - parse->priv->next_ts = - GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); + + parse->priv->next_pts = GST_CLOCK_TIME_NONE; + if (GST_BUFFER_DTS_IS_VALID (buffer) && GST_BUFFER_DURATION_IS_VALID (buffer)) { + parse->priv->next_dts = + GST_BUFFER_DTS (buffer) + GST_BUFFER_DURATION (buffer); + if (GST_BUFFER_PTS_IS_VALID (buffer)) { + GstClockTime next_pts = + GST_BUFFER_PTS (buffer) + GST_BUFFER_DURATION (buffer); + if (next_pts >= parse->priv->next_dts) + parse->priv->next_pts = next_pts; + } } else { /* we lost track, do not produce bogus time next time around * (probably means parser subclass has given up on parsing as well) */ GST_DEBUG_OBJECT (parse, "no next fallback timestamp"); - parse->priv->next_ts = GST_CLOCK_TIME_NONE; + parse->priv->next_dts = GST_CLOCK_TIME_NONE; } if (parse->priv->upstream_seekable && parse->priv->exact_position && - GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) + GST_BUFFER_PTS_IS_VALID (buffer)) gst_base_parse_add_index_entry (parse, offset, - GST_BUFFER_TIMESTAMP (buffer), + GST_BUFFER_PTS (buffer), !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT), FALSE); /* All OK, push queued frames if there are any */ @@ -2289,8 +2312,10 @@ gst_base_parse_start_fragment (GstBaseParse * parse) /* invalidate so no fall-back timestamping is performed; * ok if taken from subclass or upstream */ - parse->priv->next_ts = GST_CLOCK_TIME_NONE; - parse->priv->prev_ts = GST_CLOCK_TIME_NONE; + parse->priv->next_pts = GST_CLOCK_TIME_NONE; + parse->priv->prev_pts = GST_CLOCK_TIME_NONE; + parse->priv->next_dts = GST_CLOCK_TIME_NONE; + parse->priv->prev_dts = GST_CLOCK_TIME_NONE; /* prevent it hanging around stop all the time */ parse->segment.position = GST_CLOCK_TIME_NONE; /* mark next run */ @@ -2349,29 +2374,40 @@ gst_base_parse_finish_fragment (GstBaseParse * parse, gboolean prev_head) /* add metadata (if needed to queued buffers */ GST_LOG_OBJECT (parse, "last timestamp: %" GST_TIME_FORMAT, - GST_TIME_ARGS (parse->priv->last_ts)); + GST_TIME_ARGS (parse->priv->last_pts)); while (parse->priv->buffers_queued) { buf = GST_BUFFER_CAST (parse->priv->buffers_queued->data); /* no touching if upstream or parsing provided time */ - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + if (GST_BUFFER_PTS_IS_VALID (buf)) { GST_LOG_OBJECT (parse, "buffer has time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - } else if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_ts) && - GST_BUFFER_DURATION_IS_VALID (buf)) { - if (G_LIKELY (GST_BUFFER_DURATION (buf) <= parse->priv->last_ts)) - parse->priv->last_ts -= GST_BUFFER_DURATION (buf); - else - parse->priv->last_ts = 0; - GST_BUFFER_TIMESTAMP (buf) = parse->priv->last_ts; - GST_LOG_OBJECT (parse, "applied time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + GST_TIME_ARGS (GST_BUFFER_PTS (buf))); + } else if (GST_BUFFER_DURATION_IS_VALID (buf)) { + if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_pts)) { + if (G_LIKELY (GST_BUFFER_DURATION (buf) <= parse->priv->last_pts)) + parse->priv->last_pts -= GST_BUFFER_DURATION (buf); + else + parse->priv->last_pts = 0; + GST_BUFFER_PTS (buf) = parse->priv->last_pts; + GST_LOG_OBJECT (parse, "applied time %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_PTS (buf))); + } + if (GST_CLOCK_TIME_IS_VALID (parse->priv->last_dts)) { + if (G_LIKELY (GST_BUFFER_DURATION (buf) <= parse->priv->last_dts)) + parse->priv->last_dts -= GST_BUFFER_DURATION (buf); + else + parse->priv->last_dts = 0; + GST_BUFFER_DTS (buf) = parse->priv->last_dts; + GST_LOG_OBJECT (parse, "applied dts %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_DTS (buf))); + } } else { /* no idea, very bad */ GST_WARNING_OBJECT (parse, "could not determine time for buffer"); } - parse->priv->last_ts = GST_BUFFER_TIMESTAMP (buf); + parse->priv->last_pts = GST_BUFFER_PTS (buf); + parse->priv->last_dts = GST_BUFFER_DTS (buf); /* reverse order for ascending sending */ /* send downstream at keyframe not preceded by a keyframe @@ -2439,7 +2475,7 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) gint skip = -1; const guint8 *data; guint min_size, av; - GstClockTime timestamp; + GstClockTime pts, dts; parse = GST_BASE_PARSE (parent); bclass = GST_BASE_PARSE_GET_CLASS (parse); @@ -2570,10 +2606,11 @@ gst_base_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) /* move along with upstream timestamp (if any), * but interpolate in between */ - timestamp = gst_adapter_prev_timestamp (parse->priv->adapter, NULL); - if (GST_CLOCK_TIME_IS_VALID (timestamp) && - (parse->priv->prev_ts != timestamp)) { - parse->priv->prev_ts = parse->priv->next_ts = timestamp; + pts = gst_adapter_prev_pts (parse->priv->adapter, NULL); + dts = gst_adapter_prev_dts (parse->priv->adapter, NULL); + if (GST_CLOCK_TIME_IS_VALID (pts) && (parse->priv->prev_pts != pts)) { + parse->priv->prev_pts = parse->priv->next_pts = pts; + parse->priv->prev_dts = parse->priv->next_dts = dts; } /* always pass all available data */ @@ -2691,10 +2728,11 @@ gst_base_parse_handle_previous_fragment (GstBaseParse * parse) GstFlowReturn ret; GST_DEBUG_OBJECT (parse, "fragment ended; last_ts = %" GST_TIME_FORMAT - ", last_offset = %" G_GINT64_FORMAT, GST_TIME_ARGS (parse->priv->last_ts), - parse->priv->last_offset); + ", last_offset = %" G_GINT64_FORMAT, + GST_TIME_ARGS (parse->priv->last_pts), parse->priv->last_offset); - if (!parse->priv->last_offset || parse->priv->last_ts <= parse->segment.start) { + if (!parse->priv->last_offset + || parse->priv->last_pts <= parse->segment.start) { GST_DEBUG_OBJECT (parse, "past start of segment %" GST_TIME_FORMAT, GST_TIME_ARGS (parse->segment.start)); ret = GST_FLOW_EOS; @@ -2703,8 +2741,8 @@ gst_base_parse_handle_previous_fragment (GstBaseParse * parse) /* last fragment started at last_offset / last_ts; * seek back 10s capped at 1MB */ - if (parse->priv->last_ts >= 10 * GST_SECOND) - ts = parse->priv->last_ts - 10 * GST_SECOND; + if (parse->priv->last_pts >= 10 * GST_SECOND) + ts = parse->priv->last_pts - 10 * GST_SECOND; /* if we are exact now, we will be more so going backwards */ if (parse->priv->exact_position) { offset = gst_base_parse_find_offset (parse, ts, TRUE, NULL); @@ -3586,7 +3624,7 @@ gst_base_parse_locate_time (GstBaseParse * parse, GstClockTime * _time, /* need initial positions; start and end */ lpos = parse->priv->first_frame_offset; - ltime = parse->priv->first_frame_ts; + ltime = parse->priv->first_frame_pts; if (!gst_base_parse_get_duration (parse, GST_FORMAT_TIME, &htime)) { GST_DEBUG_OBJECT (parse, "Unknown time duration, cannot bisect"); return GST_FLOW_ERROR; @@ -3925,8 +3963,10 @@ gst_base_parse_handle_seek (GstBaseParse * parse, GstEvent * event) parse->priv->last_offset = seekpos; parse->priv->seen_keyframe = FALSE; parse->priv->discont = TRUE; - parse->priv->next_ts = start_ts; - parse->priv->last_ts = GST_CLOCK_TIME_NONE; + parse->priv->next_pts = start_ts; + parse->priv->next_dts = GST_CLOCK_TIME_NONE; + parse->priv->last_dts = GST_CLOCK_TIME_NONE; + parse->priv->last_pts = GST_CLOCK_TIME_NONE; parse->priv->sync_offset = seekpos; parse->priv->exact_position = accurate; }