diff --git a/ChangeLog b/ChangeLog index f44d74884a..0e0b348c55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-09-04 Wim Taymans + + * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_frame), + (gst_ffmpegdec_chain): + If we have a parser and we did not consume any of the bytes of a new + buffer, make sure we submit the buffer again with its original timestamp + instead of a -1 timestamp. Fixes various h264 cases with reordered + frames. + If we have a discont and a timestamp but the first buffer after the + discont did not produce any data, make sure we set the timestamp on the + next buffer instead. Fixes initial timestamp on realaudio in many cases. + 2008-09-04 Wim Taymans * ext/ffmpeg/gstffmpegcodecmap.c: (nal_escape), (copy_config), diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index d49b09549b..8ef83da5e2 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -71,6 +71,7 @@ struct _GstFFMpegDec } format; gboolean waiting_for_key; gboolean discont; + gboolean clear_ts; guint64 next_ts; guint64 in_ts; GstClockTime last_out; @@ -1856,6 +1857,14 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, len = gst_ffmpegdec_audio_frame (ffmpegdec, data, size, in_timestamp, in_duration, &outbuf, ret); + + /* if we did not get an output buffer and we have a pending discont, don't + * clear the input timestamps, we will put them on the next buffer because + * else we might create the first buffer with a very big timestamp gap. */ + if (outbuf == NULL && ffmpegdec->discont) { + GST_DEBUG_OBJECT (ffmpegdec, "no buffer but keeping timestamp"); + ffmpegdec->clear_ts = FALSE; + } break; default: GST_ERROR_OBJECT (ffmpegdec, "Asked to decode non-audio/video frame !"); @@ -1899,7 +1908,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, /* and off we go */ *ret = gst_pad_push (ffmpegdec->srcpad, outbuf); } else { - /* reverse playback, queue frame till later */ + /* reverse playback, queue frame till later when we get a discont. */ GST_DEBUG_OBJECT (ffmpegdec, "queued frame"); ffmpegdec->queued = g_list_prepend (ffmpegdec->queued, outbuf); *ret = GST_FLOW_OK; @@ -2122,6 +2131,9 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) ffmpegdec->last_out = GST_CLOCK_TIME_NONE; ffmpegdec->next_ts = GST_CLOCK_TIME_NONE; } + /* by default we clear the input timestamp after decoding each frame so that + * interpollation can work. */ + ffmpegdec->clear_ts = TRUE; oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); @@ -2198,9 +2210,16 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) GST_LOG_OBJECT (ffmpegdec, "consuming %d bytes. ts:%" GST_TIME_FORMAT, size, GST_TIME_ARGS (ffmpegdec->pctx->pts)); - /* there is output, set pointers for next round. */ - bsize -= res; - bdata += res; + if (res) { + /* there is output, set pointers for next round. */ + bsize -= res; + bdata += res; + } + else { + /* Parser did not consume any data, make sure we don't clear the + * timestamp for the next round */ + ffmpegdec->clear_ts = FALSE; + } /* if there is no output, we must break and wait for more data. also the * timestamp in the context is not updated. */ @@ -2279,8 +2298,13 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) /* make sure we don't use the same old timestamp for the next frame and let * the interpollation take care of it. */ - in_timestamp = GST_CLOCK_TIME_NONE; - in_duration = GST_CLOCK_TIME_NONE; + if (ffmpegdec->clear_ts) { + in_timestamp = GST_CLOCK_TIME_NONE; + in_duration = GST_CLOCK_TIME_NONE; + } + else { + ffmpegdec->clear_ts = TRUE; + } GST_LOG_OBJECT (ffmpegdec, "Before (while bsize>0). bsize:%d , bdata:%p", bsize, bdata);