summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hervey <bilboed@bilboed.com>2010-02-28 15:10:34 +0100
committerEdward Hervey <bilboed@bilboed.com>2010-03-01 12:52:19 +0100
commitbb2acca229c080c65e348788c454d89d45f17e20 (patch)
tree5e98458f793a1cfe7c37f52fe0af60336dbe68f6
parentc9a7e76f46d1b79a019c8eef27e1a3a240f5b45f (diff)
gstffmpegdec: Handle durations in reordered frames
The buffer durations were not being reordered along with the timestamp and offset of the buffers, resulting in buffers using the duration of the latest incoming frame instead of their original frame. Fixes #611398
-rw-r--r--ext/ffmpeg/gstffmpegdec.c76
1 files changed, 53 insertions, 23 deletions
diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c
index 80bb52d..ca35563 100644
--- a/ext/ffmpeg/gstffmpegdec.c
+++ b/ext/ffmpeg/gstffmpegdec.c
@@ -48,6 +48,7 @@ typedef struct _GstDataPassThrough GstDataPassThrough;
struct _GstDataPassThrough
{
guint64 ts;
+ guint64 duration;
guint64 offset;
};
@@ -58,6 +59,9 @@ struct _GstTSMap
/* timestamp */
guint64 ts;
+ /* duration */
+ guint64 duration;
+
/* offset */
gint64 offset;
@@ -236,7 +240,7 @@ static void gst_ts_handler_append (GstFFMpegDec * ffmpegdec,
GstBuffer * buffer);
static void gst_ts_handler_consume (GstFFMpegDec * ffmpegdec, gint size);
static guint64 gst_ts_handler_get_ts (GstFFMpegDec * ffmpegdec,
- gint64 * offset);
+ gint64 * offset, guint64 * duration);
#define GST_FFDEC_PARAMS_QDATA g_quark_from_static_string("ffdec-params")
@@ -1566,34 +1570,43 @@ flush_queued (GstFFMpegDec * ffmpegdec)
}
static gpointer
-opaque_store (GstFFMpegDec * ffmpegdec, guint64 ts, guint64 offset)
+opaque_store (GstFFMpegDec * ffmpegdec, guint64 ts, guint64 duration,
+ guint64 offset)
{
GstDataPassThrough *opaque = g_slice_new0 (GstDataPassThrough);
opaque->ts = ts;
+ opaque->duration = duration;
opaque->offset = offset;
ffmpegdec->opaque = g_list_append (ffmpegdec->opaque, (gpointer) opaque);
- GST_DEBUG_OBJECT (ffmpegdec, "Stored ts:%" GST_TIME_FORMAT ", offset:%"
- G_GUINT64_FORMAT " as opaque %p", GST_TIME_ARGS (ts), offset,
- (gpointer) opaque);
+ GST_DEBUG_OBJECT (ffmpegdec,
+ "Stored ts:%" GST_TIME_FORMAT ", duration:%" GST_TIME_FORMAT ", offset:%"
+ G_GUINT64_FORMAT " as opaque %p", GST_TIME_ARGS (ts),
+ GST_TIME_ARGS (duration), offset, (gpointer) opaque);
return opaque;
}
static gboolean
opaque_find (GstFFMpegDec * ffmpegdec, gpointer opaque_val, guint64 * _ts,
- gint64 * _offset)
+ guint64 * _duration, gint64 * _offset)
{
GstClockTime ts = GST_CLOCK_TIME_NONE;
+ GstClockTime duration = GST_CLOCK_TIME_NONE;
gint64 offset = GST_BUFFER_OFFSET_NONE;
GList *i;
+
for (i = ffmpegdec->opaque; i != NULL; i = g_list_next (i)) {
if (i->data == (gpointer) opaque_val) {
ts = ((GstDataPassThrough *) i->data)->ts;
+ duration = ((GstDataPassThrough *) i->data)->duration;
offset = ((GstDataPassThrough *) i->data)->offset;
GST_DEBUG_OBJECT (ffmpegdec,
- "Found opaque %p - ts:%" GST_TIME_FORMAT ", offset:%" G_GINT64_FORMAT,
- i->data, GST_TIME_ARGS (ts), offset);
+ "Found opaque %p - ts:%" GST_TIME_FORMAT ", duration:%"
+ GST_TIME_FORMAT ", offset:%" G_GINT64_FORMAT, i->data,
+ GST_TIME_ARGS (ts), GST_TIME_ARGS (duration), offset);
if (_ts)
*_ts = ts;
+ if (_duration)
+ *_duration = duration;
if (_offset)
*_offset = offset;
g_slice_free (GstDataPassThrough, i->data);
@@ -1673,14 +1686,15 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
"Going to store opaque values, current ts:%" GST_TIME_FORMAT ", offset: %"
G_GINT64_FORMAT, GST_TIME_ARGS (in_timestamp), in_offset);
- out_timestamp = gst_ts_handler_get_ts (ffmpegdec, &out_offset);
+ out_timestamp = gst_ts_handler_get_ts (ffmpegdec, &out_offset, &out_duration);
/* Never do this at home...
* 1) We know that ffmpegdec->context->reordered_opaque is 64-bit, and thus
* is capable of holding virtually anything including pointers
* (unless we're on 128-bit platform...)
*/
ffmpegdec->context->reordered_opaque = (gint64)
- GPOINTER_TO_SIZE (opaque_store (ffmpegdec, out_timestamp, out_offset));
+ GPOINTER_TO_SIZE (opaque_store (ffmpegdec, out_timestamp, out_duration,
+ out_offset));
/* now decode the frame */
len = avcodec_decode_video (ffmpegdec->context,
@@ -1715,10 +1729,11 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
/* recuperate the reordered timestamp */
if (!opaque_find (ffmpegdec,
(gpointer) (gulong) ffmpegdec->picture->reordered_opaque, &out_pts,
- &out_offset)) {
+ &out_duration, &out_offset)) {
GST_DEBUG_OBJECT (ffmpegdec, "Failed to find opaque %p",
(gpointer) (gulong) ffmpegdec->picture->reordered_opaque);
out_pts = -1;
+ out_duration = -1;
out_offset = GST_BUFFER_OFFSET_NONE;
} else {
GST_DEBUG_OBJECT (ffmpegdec,
@@ -1726,7 +1741,9 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
G_GINT64_FORMAT, GST_TIME_ARGS (in_timestamp), in_offset);
}
- GST_DEBUG_OBJECT (ffmpegdec, "ts-handler: pts %" G_GUINT64_FORMAT, out_pts);
+ GST_DEBUG_OBJECT (ffmpegdec,
+ "ts-handler: pts %" G_GUINT64_FORMAT " duration %" G_GUINT64_FORMAT,
+ out_pts, out_duration);
GST_DEBUG_OBJECT (ffmpegdec, "picture: pts %" G_GUINT64_FORMAT,
(guint64) ffmpegdec->picture->pts);
GST_DEBUG_OBJECT (ffmpegdec, "picture: num %d",
@@ -1857,12 +1874,15 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
/*
* Duration:
*
- * 1) Copy input duration if valid
- * 2) else use input framerate
- * 3) else use ffmpeg framerate
+ * 1) Use reordered input duration if valid
+ * 2) Else use input duration
+ * 3) else use input framerate
+ * 4) else use ffmpeg framerate
*/
- out_duration = -1;
- if (!GST_CLOCK_TIME_IS_VALID (in_duration)) {
+ if (GST_CLOCK_TIME_IS_VALID (out_duration)) {
+ /* We have a valid (reordered) duration */
+ GST_LOG_OBJECT (ffmpegdec, "We have a valid (reordered) duration");
+ } else if (!GST_CLOCK_TIME_IS_VALID (in_duration)) {
/* if we have an input framerate, use that */
if (ffmpegdec->format.video.fps_n != -1 &&
(ffmpegdec->format.video.fps_n != 1000 &&
@@ -2916,6 +2936,7 @@ gst_ts_handler_append (GstFFMpegDec * ffmpegdec, GstBuffer * buffer)
{
GstTSHandler *ts_handler = &ffmpegdec->ts_handler;
guint64 ts = GST_BUFFER_TIMESTAMP (buffer);
+ guint64 duration = GST_BUFFER_DURATION (buffer);
gint size = GST_BUFFER_SIZE (buffer);
guint64 offset = GST_BUFFER_OFFSET (buffer);
gint ind = ts_handler->buf_head;
@@ -2929,9 +2950,11 @@ gst_ts_handler_append (GstFFMpegDec * ffmpegdec, GstBuffer * buffer)
ts != -1 ? (double) ts / GST_SECOND : -1.0, size);
**/
GST_LOG_OBJECT (ffmpegdec, "store timestamp @ index [%02X] buf_count: %d"
- " ts: %" GST_TIME_FORMAT ", offset: %" G_GUINT64_FORMAT ", size: %d",
- ind, ts_handler->buf_count, GST_TIME_ARGS (ts), offset, size);
+ " ts: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT ", offset: %"
+ G_GUINT64_FORMAT ", size: %d", ind, ts_handler->buf_count,
+ GST_TIME_ARGS (ts), GST_TIME_ARGS (duration), offset, size);
ts_handler->buffers[ind].ts = ts;
+ ts_handler->buffers[ind].duration = duration;
ts_handler->buffers[ind].offset = offset;
ts_handler->buffers[ind].size = size;
ts_handler->buf_head = ind;
@@ -2989,17 +3012,24 @@ gst_ts_handler_consume (GstFFMpegDec * ffmpegdec, gint size)
/** get the timestamp from the tail of the list */
static guint64
-gst_ts_handler_get_ts (GstFFMpegDec * ffmpegdec, gint64 * _offset)
+gst_ts_handler_get_ts (GstFFMpegDec * ffmpegdec, gint64 * _offset,
+ guint64 * _duration)
{
GstTSHandler *ts_handler = &ffmpegdec->ts_handler;
guint64 ts = ts_handler->buffers[ts_handler->buf_tail].ts;
+ guint64 duration = ts_handler->buffers[ts_handler->buf_tail].duration;
gint64 offset = ts_handler->buffers[ts_handler->buf_tail].offset;
- GST_LOG_OBJECT (ffmpegdec, "Index %d yielded ts %" GST_TIME_FORMAT
- " offset %" G_GINT64_FORMAT, ts_handler->buf_tail,
- GST_TIME_ARGS (ts), offset);
+
+ GST_LOG_OBJECT (ffmpegdec, "Index %d yielded ts: %" GST_TIME_FORMAT
+ ", duration: %" GST_TIME_FORMAT ", offset: %" G_GINT64_FORMAT,
+ ts_handler->buf_tail, GST_TIME_ARGS (ts), GST_TIME_ARGS (duration),
+ offset);
if (_offset)
*_offset = offset;
+ if (_duration)
+ *_duration = duration;
ts_handler->buffers[ts_handler->buf_tail].ts = -1;
+ ts_handler->buffers[ts_handler->buf_tail].duration = -1;
ts_handler->buffers[ts_handler->buf_tail].offset = -1;
return ts;
}