diff options
author | Руслан Ижбулатов <lrn1986@gmail.com> | 2009-07-18 18:53:22 +0400 |
---|---|---|
committer | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2009-07-29 14:19:20 +0200 |
commit | a5f94859171b962106842703d8967d0b04df9efd (patch) | |
tree | c75ff4f0f430d9cfe86db526e394c598aa7d66c7 | |
parent | 6c0205c31673b04900415d3331b470dc668fd370 (diff) |
Codec frame delay fix and trailing zero-length frame fix
Takes codec frame delay into account (roughly the same way it does for timestamps for reordered frames) to produce frames with correct offsets.
A special hack to allow trailing frame with timestamp=segment.stop to be displayed.
Fixes bug #578278.
-rw-r--r-- | ext/ffmpeg/gstffmpegdec.c | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index 2498b1f..6eb0903 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -110,6 +110,16 @@ struct _GstFFMpegDec gboolean ts_is_dts; gboolean has_b_frames; + /* Incremented by 1 each time ffmpeg consumes an encoded frame but does not + * give a decoded frame back. Gradually reduced to 0 while draining. + */ + gint64 delay_offset; + + /* Last valid offset received from upstream. Used with delay_offset to + * calculate offsets while draining. + */ + gint64 last_offset; + /* parsing */ AVCodecParserContext *pctx; GstBuffer *pcache; @@ -405,6 +415,8 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec) ffmpegdec->do_padding = DEFAULT_DO_PADDING; ffmpegdec->debug_mv = DEFAULT_DEBUG_MV; ffmpegdec->crop = DEFAULT_CROP; + ffmpegdec->delay_offset = 0; + ffmpegdec->last_offset = GST_BUFFER_OFFSET_NONE; gst_ts_handler_init (ffmpegdec); @@ -1371,9 +1383,17 @@ clip_video_buffer (GstFFMpegDec * dec, GstBuffer * buf, GstClockTime in_ts, res = gst_segment_clip (&dec->segment, GST_FORMAT_TIME, in_ts, stop, &cstart, &cstop); - if (G_UNLIKELY (!res)) + if (G_UNLIKELY (!res && in_ts != dec->segment.stop)) goto beach; + /* Special case: last buffer has zero duration */ + if (G_UNLIKELY (in_ts == dec->segment.stop)) + { + res = TRUE; + cstart = in_ts - 1; + stop = cstop = in_ts; + } + /* we're pretty sure the duration of this buffer is not till the end of this * segment (which _clip will assume when the stop is -1) */ if (stop == GST_CLOCK_TIME_NONE) @@ -1511,7 +1531,7 @@ flush_queued (GstFFMpegDec * ffmpegdec) GstBuffer *buf = GST_BUFFER_CAST (ffmpegdec->queued->data); GST_LOG_OBJECT (ffmpegdec, "pushing buffer %p, offset %" - G_GINT64_FORMAT ", timestamp %" + G_GUINT64_FORMAT ", timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, buf, GST_BUFFER_OFFSET (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), @@ -1599,6 +1619,9 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, gst_ts_handler_consume (ffmpegdec, len); + if (len < 0 || have_data <= 0) + ffmpegdec->delay_offset++; + /* restore previous state */ if (!decode) ffmpegdec->context->hurry_up = hurry_up; @@ -1725,13 +1748,25 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec, * Offset: * * 1) Use input offset if valid + * 2) Use value converted from timestamp if valid */ - if (in_offset == GST_BUFFER_OFFSET_NONE) { + if (in_offset != GST_BUFFER_OFFSET_NONE) { + GST_LOG_OBJECT (ffmpegdec, "using in_offset %" G_GINT64_FORMAT, in_offset - + ffmpegdec->delay_offset); + out_offset = in_offset - ffmpegdec->delay_offset; + ffmpegdec->last_offset = in_offset; + } else if (ffmpegdec->last_offset != GST_BUFFER_OFFSET_NONE) { + GST_LOG_OBJECT (ffmpegdec, "using last_offset %" G_GINT64_FORMAT, ffmpegdec->last_offset - + ffmpegdec->delay_offset); + out_offset = ffmpegdec->last_offset - ffmpegdec->delay_offset; + } else if (out_timestamp >= 0) { + GstFormat out_fmt = GST_FORMAT_DEFAULT; + GST_LOG_OBJECT (ffmpegdec, "Using offset converted from timestamp"); + gst_pad_query_peer_convert (ffmpegdec->sinkpad, + GST_FORMAT_TIME, out_timestamp, &out_fmt, &out_offset); + } else { GST_LOG_OBJECT (ffmpegdec, "no valid offset found"); out_offset = GST_BUFFER_OFFSET_NONE; - } else { - GST_LOG_OBJECT (ffmpegdec, "using in_offset %" G_GINT64_FORMAT, in_offset); - out_offset = in_offset; } GST_BUFFER_OFFSET (*outbuf) = out_offset; @@ -2133,6 +2168,9 @@ gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) do { GstFlowReturn ret; + if (ffmpegdec->delay_offset > 0) + ffmpegdec->delay_offset--; + len = gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data, GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, -1, &ret); if (len < 0 || have_data == 0) @@ -2143,6 +2181,8 @@ gst_ffmpegdec_drain (GstFFMpegDec * ffmpegdec) /* if we have some queued frames for reverse playback, flush them now */ flush_queued (ffmpegdec); } + ffmpegdec->delay_offset = 0; + ffmpegdec->last_offset = GST_BUFFER_OFFSET_NONE; } static void |