summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: fdd74ac)
raw | patch | inline | side by side (parent: fdd74ac)
author | Rob Clark <rob@ti.com> | |
Sun, 4 Dec 2011 06:57:12 +0000 (00:57 -0600) | ||
committer | Rob Clark <rob@ti.com> | |
Sun, 11 Dec 2011 23:51:04 +0000 (17:51 -0600) |
When packed frames are used, the timestamps we get from demuxer are
actually PTS, not DTS. Detect this and fix up the timestamps on
the outgoing buffers.
This commit implements detection of packed frames (PB-frames) in
ducatimpeg4dec, and a DTS queue in the base ducatividdec (which
could be used by other decoders). When packed frames are detected,
we assume the demuxer doesn't properly understand B-frames, and
therefore timestamps from demuxer must actually be PTS timestamps.
Because the codec is unaware of this, and re-ordering frames to
display order, if we preserve the original timestamps the video
sink ends up seeing timestamps out of order. To work around this
we pop the DTS from the demuxer out of a queue and use that
instead.
actually PTS, not DTS. Detect this and fix up the timestamps on
the outgoing buffers.
This commit implements detection of packed frames (PB-frames) in
ducatimpeg4dec, and a DTS queue in the base ducatividdec (which
could be used by other decoders). When packed frames are detected,
we assume the demuxer doesn't properly understand B-frames, and
therefore timestamps from demuxer must actually be PTS timestamps.
Because the codec is unaware of this, and re-ordering frames to
display order, if we preserve the original timestamps the video
sink ends up seeing timestamps out of order. To work around this
we pop the DTS from the demuxer out of a queue and use that
instead.
src/gstducatimpeg4dec.c | patch | blob | history | |
src/gstducatividdec.c | patch | blob | history | |
src/gstducatividdec.h | patch | blob | history |
index 98e1fe531d54f0523ba16766a21e62abfa759d2f..87a6bb1c282e325fad485871a2a7e05fbba7639d 100644 (file)
--- a/src/gstducatimpeg4dec.c
+++ b/src/gstducatimpeg4dec.c
/* we don't care about anything beyond here */
}
+static void
+decode_user_data (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
+{
+ GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
+ const char *buf = (const char *)data;
+ int n, ver, build;
+ char c;
+
+ /* divx detection: */
+ n = sscanf(buf, "DivX%dBuild%d%c", &ver, &build, &c);
+ if (n < 2)
+ n = sscanf(buf, "DivX%db%d%c", &ver, &build, &c);
+ if (n >= 2) {
+ GST_INFO_OBJECT (self, "DivX: version %d, build %d", ver, build);
+ if ((n == 3) && (c == 'p')) {
+ GST_INFO_OBJECT (self, "detected packed B frames");
+ /* enable workarounds: */
+ vdec->ts_is_pts = TRUE;
+ }
+ }
+
+ /* xvid detection: */
+ n = sscanf(buf, "XviD%d", &build);
+ if (n == 1) {
+ GST_INFO_OBJECT (self, "XviD: build %d", build);
+ // XXX do we need to enable workarounds??
+ }
+}
+
static gboolean
is_vop_coded (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
{
skip = ! is_vop_coded (self, in + SC_SZ + 1, insize - SC_SZ - 1);
if (skip)
GST_DEBUG_OBJECT (self, "skipping non-coded VOP");
+ } else if (start_code == UD_START_CODE){
+ decode_user_data (self, in + SC_SZ + 1, nal_size - SC_SZ - 1);
}
if (!skip)
*/
if (insize > 0) {
remaining = gst_buffer_create_sub (buf, size, insize);
+
+ GST_BUFFER_DURATION (remaining) = GST_BUFFER_DURATION (buf);
+ if (vdec->ts_is_pts) {
+ GST_BUFFER_TIMESTAMP (remaining) = GST_CLOCK_TIME_NONE;
+ } else {
+ GST_BUFFER_TIMESTAMP (remaining) = GST_BUFFER_TIMESTAMP (buf) +
+ GST_BUFFER_DURATION (buf);
+ }
}
return remaining;
diff --git a/src/gstducatividdec.c b/src/gstducatividdec.c
index a2d919f14f67920b2af724e6811b2563157db413..d57365ccc49c0e3b8e2ec4c41f4624f341ddeed7 100644 (file)
--- a/src/gstducatividdec.c
+++ b/src/gstducatividdec.c
}
GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+
+ if (self->ts_is_pts) {
+ /* if we have a queued DTS from demuxer, use that instead: */
+ if (self->dts_ridx != self->dts_widx) {
+ GST_BUFFER_TIMESTAMP (outbuf) =
+ self->dts_queue[self->dts_ridx++ % NDTS];
+ GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
+ i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
+ }
+ }
+
gst_pad_push (self->srcpad, outbuf);
} else {
GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
{
GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
+ GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
GstFlowReturn ret;
Int32 err;
GstBuffer *outbuf = NULL;
}
GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes)",
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
- GST_BUFFER_SIZE (buf));
+ GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf));
decode = gst_ducati_viddec_do_qos (self, buf);
if (!decode) {
self->in_size = 0;
buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
+ if (self->ts_is_pts && (ts != GST_CLOCK_TIME_NONE)) {
+ self->duration = GST_BUFFER_DURATION (outbuf);
+ self->dts_queue[self->dts_widx++ % NDTS] = ts;
+ }
+
if (self->in_size == 0) {
GST_DEBUG_OBJECT (self, "no input, skipping process");
gst_buffer_unref (outbuf);
if (buf) {
GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
GST_BUFFER_SIZE (buf));
+ ts = GST_BUFFER_TIMESTAMP (buf);
goto allocate_buffer;
}
diff --git a/src/gstducatividdec.h b/src/gstducatividdec.h
index 7f83e90eea4145eb16f8227c53c221bd32b0c8de..f6b4b6652d0f3ce77da2c951ffd9a32d68d19bb1 100644 (file)
--- a/src/gstducatividdec.h
+++ b/src/gstducatividdec.h
/* by default, codec_data from sinkpad is prepended to first buffer: */
GstBuffer *codec_data;
+ /* workaround enabled to indicate that timestamp from demuxer is PTS,
+ * not DTS (cough, cough.. avi):
+ */
+ gboolean ts_is_pts;
+
+ GstClockTime duration;
+#define NDTS 32
+ GstClockTime dts_queue[NDTS];
+ gint dts_ridx, dts_widx;
+
Engine_Handle engine;
VIDDEC3_Handle codec;
VIDDEC3_Params *params;