videodecoder: improve PTS and DTS handling

Also keep track of the DTS and use it to set PTS on keyframes.
Set DTS on outgoing buffers.
This commit is contained in:
Wim Taymans 2012-06-27 13:48:58 +02:00
parent b27c649a48
commit 9f591a0bd1

View file

@ -1427,7 +1427,8 @@ typedef struct _Timestamp Timestamp;
struct _Timestamp
{
guint64 offset;
GstClockTime timestamp;
GstClockTime pts;
GstClockTime dts;
GstClockTime duration;
};
@ -1440,11 +1441,14 @@ gst_video_decoder_add_timestamp (GstVideoDecoder * decoder, GstBuffer * buffer)
ts = g_malloc (sizeof (Timestamp));
GST_LOG_OBJECT (decoder,
"adding timestamp %" GST_TIME_FORMAT " (offset:%" G_GUINT64_FORMAT ")",
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), priv->input_offset);
"adding PTS %" GST_TIME_FORMAT " DTS %" GST_TIME_FORMAT
" (offset:%" G_GUINT64_FORMAT ")",
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)),
GST_TIME_ARGS (GST_BUFFER_DTS (buffer)), priv->input_offset);
ts->offset = priv->input_offset;
ts->timestamp = GST_BUFFER_TIMESTAMP (buffer);
ts->pts = GST_BUFFER_PTS (buffer);
ts->dts = GST_BUFFER_DTS (buffer);
ts->duration = GST_BUFFER_DURATION (buffer);
priv->timestamps = g_list_append (priv->timestamps, ts);
@ -1452,7 +1456,8 @@ gst_video_decoder_add_timestamp (GstVideoDecoder * decoder, GstBuffer * buffer)
static void
gst_video_decoder_get_timestamp_at_offset (GstVideoDecoder *
decoder, guint64 offset, GstClockTime * timestamp, GstClockTime * duration)
decoder, guint64 offset, GstClockTime * pts, GstClockTime * dts,
GstClockTime * duration)
{
#ifndef GST_DISABLE_GST_DEBUG
guint64 got_offset = 0;
@ -1460,7 +1465,8 @@ gst_video_decoder_get_timestamp_at_offset (GstVideoDecoder *
Timestamp *ts;
GList *g;
*timestamp = GST_CLOCK_TIME_NONE;
*pts = GST_CLOCK_TIME_NONE;
*dts = GST_CLOCK_TIME_NONE;
*duration = GST_CLOCK_TIME_NONE;
g = decoder->priv->timestamps;
@ -1470,7 +1476,8 @@ gst_video_decoder_get_timestamp_at_offset (GstVideoDecoder *
#ifndef GST_DISABLE_GST_DEBUG
got_offset = ts->offset;
#endif
*timestamp = ts->timestamp;
*pts = ts->pts;
*dts = ts->dts;
*duration = ts->duration;
g_free (ts);
g = g->next;
@ -1481,9 +1488,9 @@ gst_video_decoder_get_timestamp_at_offset (GstVideoDecoder *
}
GST_LOG_OBJECT (decoder,
"got timestamp %" GST_TIME_FORMAT " @ offs %" G_GUINT64_FORMAT
" (wanted offset:%" G_GUINT64_FORMAT ")", GST_TIME_ARGS (*timestamp),
got_offset, offset);
"got PTS %" GST_TIME_FORMAT " DTS %" GST_TIME_FORMAT " @ offs %"
G_GUINT64_FORMAT " (wanted offset:%" G_GUINT64_FORMAT ")",
GST_TIME_ARGS (*pts), GST_TIME_ARGS (*dts), got_offset, offset);
}
static void
@ -1590,7 +1597,7 @@ gst_video_decoder_chain_forward (GstVideoDecoder * decoder,
if (priv->current_frame == NULL)
priv->current_frame = gst_video_decoder_new_frame (decoder);
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
if (GST_BUFFER_PTS_IS_VALID (buf)) {
gst_video_decoder_add_timestamp (decoder, buf);
}
priv->input_offset += gst_buffer_get_size (buf);
@ -1647,8 +1654,10 @@ gst_video_decoder_flush_decode (GstVideoDecoder * dec)
GstVideoCodecFrame *frame = (GstVideoCodecFrame *) (walk->data);
GstBuffer *buf = frame->input_buffer;
GST_DEBUG_OBJECT (dec, "decoding frame %p buffer %p, ts %" GST_TIME_FORMAT,
frame, buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
GST_DEBUG_OBJECT (dec, "decoding frame %p buffer %p, PTS %" GST_TIME_FORMAT
", DTS %" GST_TIME_FORMAT, frame, buf,
GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DTS (buf)));
next = walk->next;
@ -1695,8 +1704,9 @@ gst_video_decoder_flush_parse (GstVideoDecoder * dec, gboolean at_eos)
GstBuffer *buf = GST_BUFFER_CAST (walk->data);
GList *next = walk->next;
GST_DEBUG_OBJECT (dec, "parsing buffer %p, ts %" GST_TIME_FORMAT,
buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
GST_DEBUG_OBJECT (dec, "parsing buffer %p, PTS %" GST_TIME_FORMAT
", DTS %" GST_TIME_FORMAT, buf, GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DTS (buf)));
/* parse buffer, resulting frames prepended to parse_gather queue */
gst_buffer_ref (buf);
@ -1730,8 +1740,10 @@ gst_video_decoder_flush_parse (GstVideoDecoder * dec, gboolean at_eos)
/* if we copied a keyframe, flush and decode the decode queue */
if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
GST_DEBUG_OBJECT (dec, "found keyframe %p with PTS %" GST_TIME_FORMAT,
frame, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (frame->input_buffer)));
GST_DEBUG_OBJECT (dec, "found keyframe %p with PTS %" GST_TIME_FORMAT
", DTS %" GST_TIME_FORMAT, frame,
GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)),
GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)));
res = gst_video_decoder_flush_decode (dec);
if (res != GST_FLOW_OK)
goto done;
@ -1794,8 +1806,10 @@ gst_video_decoder_chain_reverse (GstVideoDecoder * dec, GstBuffer * buf)
if (G_LIKELY (buf)) {
GST_DEBUG_OBJECT (dec, "gathering buffer %p of size %" G_GSIZE_FORMAT ", "
"time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
gst_buffer_get_size (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
"PTS %" GST_TIME_FORMAT ", DTS %" GST_TIME_FORMAT ", dur %"
GST_TIME_FORMAT, buf, gst_buffer_get_size (buf),
GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
/* add buffer to gather queue */
@ -1814,8 +1828,10 @@ gst_video_decoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
decoder = GST_VIDEO_DECODER (parent);
GST_LOG_OBJECT (decoder,
"chain %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " size %"
G_GSIZE_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
"chain PTS %" GST_TIME_FORMAT ", DTS %" GST_TIME_FORMAT " duration %"
GST_TIME_FORMAT " size %" G_GSIZE_FORMAT,
GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), gst_buffer_get_size (buf));
GST_VIDEO_DECODER_STREAM_LOCK (decoder);
@ -1973,7 +1989,7 @@ gst_video_decoder_prepare_finish_frame (GstVideoDecoder *
#endif
GST_LOG_OBJECT (decoder,
"finish frame %p (#%d) sync:%d pts:%" GST_TIME_FORMAT " dts:%"
"finish frame %p (#%d) sync:%d PTS:%" GST_TIME_FORMAT " DTS:%"
GST_TIME_FORMAT,
frame, frame->system_frame_number,
GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame), GST_TIME_ARGS (frame->pts),
@ -2182,7 +2198,9 @@ gst_video_decoder_finish_frame (GstVideoDecoder * decoder,
GST_BUFFER_FLAG_UNSET (output_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
GST_BUFFER_TIMESTAMP (output_buffer) = frame->pts;
/* set PTS and DTS to both the PTS for decoded frames */
GST_BUFFER_PTS (output_buffer) = frame->pts;
GST_BUFFER_DTS (output_buffer) = frame->pts;
GST_BUFFER_DURATION (output_buffer) = frame->duration;
GST_BUFFER_OFFSET (output_buffer) = GST_BUFFER_OFFSET_NONE;
@ -2219,7 +2237,7 @@ gst_video_decoder_clip_and_push_buf (GstVideoDecoder * decoder, GstBuffer * buf)
GstClockTime duration;
/* Check for clipping */
start = GST_BUFFER_TIMESTAMP (buf);
start = GST_BUFFER_PTS (buf);
duration = GST_BUFFER_DURATION (buf);
stop = GST_CLOCK_TIME_NONE;
@ -2231,7 +2249,7 @@ gst_video_decoder_clip_and_push_buf (GstVideoDecoder * decoder, GstBuffer * buf)
segment = &decoder->output_segment;
if (gst_segment_clip (segment, GST_FORMAT_TIME, start, stop, &cstart, &cstop)) {
GST_BUFFER_TIMESTAMP (buf) = cstart;
GST_BUFFER_PTS (buf) = cstart;
if (stop != GST_CLOCK_TIME_NONE)
GST_BUFFER_DURATION (buf) = cstop - cstart;
@ -2240,8 +2258,8 @@ gst_video_decoder_clip_and_push_buf (GstVideoDecoder * decoder, GstBuffer * buf)
"accepting buffer inside segment: %" GST_TIME_FORMAT " %"
GST_TIME_FORMAT " seg %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
" time %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) +
GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
GST_TIME_ARGS (GST_BUFFER_PTS (buf) +
GST_BUFFER_DURATION (buf)),
GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop),
GST_TIME_ARGS (segment->time));
@ -2271,9 +2289,9 @@ gst_video_decoder_clip_and_push_buf (GstVideoDecoder * decoder, GstBuffer * buf)
}
GST_DEBUG_OBJECT (decoder, "pushing buffer %p of size %" G_GSIZE_FORMAT ", "
"time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
"PTS %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
gst_buffer_get_size (buf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
/* we got data, so note things are looking up again, reduce
@ -2353,8 +2371,7 @@ gst_video_decoder_have_frame (GstVideoDecoder * decoder)
GstVideoDecoderPrivate *priv = decoder->priv;
GstBuffer *buffer;
int n_available;
GstClockTime timestamp;
GstClockTime duration;
GstClockTime pts, dts, duration;
GstFlowReturn ret = GST_FLOW_OK;
GST_LOG_OBJECT (decoder, "have_frame");
@ -2371,14 +2388,16 @@ gst_video_decoder_have_frame (GstVideoDecoder * decoder)
priv->current_frame->input_buffer = buffer;
gst_video_decoder_get_timestamp_at_offset (decoder,
priv->frame_offset, &timestamp, &duration);
priv->frame_offset, &pts, &dts, &duration);
GST_BUFFER_TIMESTAMP (buffer) = timestamp;
GST_BUFFER_PTS (buffer) = pts;
GST_BUFFER_DTS (buffer) = dts;
GST_BUFFER_DURATION (buffer) = duration;
GST_LOG_OBJECT (decoder, "collected frame size %d, "
"ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
n_available, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
"PTS %" GST_TIME_FORMAT ", DTS %" GST_TIME_FORMAT ", dur %"
GST_TIME_FORMAT, n_available, GST_TIME_ARGS (pts), GST_TIME_ARGS (dts),
GST_TIME_ARGS (duration));
/* In reverse playback, just capture and queue frames for later processing */
if (decoder->output_segment.rate < 0.0) {
@ -2415,15 +2434,18 @@ gst_video_decoder_decode_frame (GstVideoDecoder * decoder,
frame->distance_from_sync = priv->distance_from_sync;
priv->distance_from_sync++;
frame->pts = GST_BUFFER_TIMESTAMP (frame->input_buffer);
frame->pts = GST_BUFFER_PTS (frame->input_buffer);
frame->dts = GST_BUFFER_DTS (frame->input_buffer);
frame->duration = GST_BUFFER_DURATION (frame->input_buffer);
/* For keyframes, DTS = PTS */
if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
frame->dts = frame->pts;
/* For keyframes, PTS = DTS */
if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
if (!GST_CLOCK_TIME_IS_VALID (frame->pts))
frame->pts = frame->dts;
}
GST_LOG_OBJECT (decoder, "pts %" GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
GST_LOG_OBJECT (decoder, "dts %" GST_TIME_FORMAT, GST_TIME_ARGS (frame->dts));
GST_LOG_OBJECT (decoder, "PTS %" GST_TIME_FORMAT ", DTS %" GST_TIME_FORMAT,
GST_TIME_ARGS (frame->pts), GST_TIME_ARGS (frame->dts));
GST_LOG_OBJECT (decoder, "dist %d", frame->distance_from_sync);
priv->frames = g_list_append (priv->frames, frame);
frame->deadline =