summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: f578a7c)
raw | patch | inline | side by side (parent: f578a7c)
author | Rob Clark <rob@ti.com> | |
Sun, 4 Dec 2011 05:20:15 +0000 (23:20 -0600) | ||
committer | Rob Clark <rob@ti.com> | |
Sun, 11 Dec 2011 23:51:04 +0000 (17:51 -0600) |
Handle xvid streams with B-frames encoded in containers that don't
support B-frames natively (ie. PB-frames). Packed frames are split
and passed to the codec in successive _process() calls, and non-coded
frames are discarded.
support B-frames natively (ie. PB-frames). Packed frames are split
and passed to the codec in successive _process() calls, and non-coded
frames are discarded.
src/gstducatimpeg4dec.c | patch | blob | history | |
src/gstducatimpeg4dec.h | patch | blob | history | |
src/gstducatividdec.c | patch | blob | history | |
src/gstducatividdec.h | patch | blob | history |
index 124731a2554112e9c077743523176f88464b4985..98e1fe531d54f0523ba16766a21e62abfa759d2f 100644 (file)
--- a/src/gstducatimpeg4dec.c
+++ b/src/gstducatimpeg4dec.c
#include "gstducatimpeg4dec.h"
+#include <math.h>
+
#define PADX 32
#define PADY 32
if (ret) {
IMPEG4VDEC_Params *params = (IMPEG4VDEC_Params *) self->params;
- self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_1;
+ self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
self->dynParams->lateAcquireArg = -1;
params->outloopDeBlocking = TRUE;
params->sorensonSparkStream = FALSE;
return ret;
}
+#define VOS_START_CODE 0xb0 /* + visual object sequence */
+#define VOS_END_CODE 0xb1
+#define UD_START_CODE 0xb2 /* user data */
+#define GVOP_START_CODE 0xb3 /* + group of VOP */
+#define VS_ERROR_CODE 0xb4
+#define VO_START_CODE 0xb5 /* visual object */
+#define VOP_START_CODE 0xb6 /* + */
+
+static const guint8 sc[] = {0x00, 0x00, 0x01}; /* start code */
+#define SC_SZ G_N_ELEMENTS (sc) /* start code size */
+
+static GstBitReader *
+get_bit_reader (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
+{
+ if (self->br) {
+ gst_bit_reader_init (self->br, data, size);
+ } else {
+ self->br = gst_bit_reader_new (data, size);
+ }
+ return self->br;
+}
+
+static void
+decode_vol_header (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
+{
+ GstBitReader *br = get_bit_reader (self, data, size);
+ guint32 is_oli, vc_param, vbv_param=0;
+ guint32 ar_info, vop_tir;
+
+ gst_bit_reader_skip (br, 1); /* random_accessible_vol */
+ gst_bit_reader_skip (br, 8); /* video_object_type_indication */
+
+ gst_bit_reader_get_bits_uint32 (br, /* is_object_layer_identifier */
+ &is_oli, 1);
+ if (is_oli) {
+ gst_bit_reader_skip (br, 4); /* video_object_layer_verid */
+ gst_bit_reader_skip (br, 3); /* video_object_layer_priority */
+ }
+
+ gst_bit_reader_get_bits_uint32 (br, /* aspect_ratio_info */
+ &ar_info, 4);
+ if (ar_info == 0xf) {
+ gst_bit_reader_skip (br, 8); /* par_width */
+ gst_bit_reader_skip (br, 8); /* par_height */
+ }
+
+ gst_bit_reader_get_bits_uint32 (br, /* vol_control_parameters */
+ &vc_param, 1);
+ if (vc_param) {
+ gst_bit_reader_skip (br, 2); /* chroma_format */
+ gst_bit_reader_skip (br, 1); /* low_delay */
+ gst_bit_reader_get_bits_uint32 ( /* vbv_parameters */
+ br, &vbv_param, 1);
+ if (vbv_param) {
+ gst_bit_reader_skip (br, 79); /* don't care */
+ }
+ }
+
+ gst_bit_reader_skip (br, 2); /* video_object_layer_shape */
+ gst_bit_reader_skip (br, 1); /* marker_bit */
+ gst_bit_reader_get_bits_uint32 (br, /* vop_time_increment_resolution */
+ &vop_tir, 16);
+ gst_bit_reader_skip (br, 1); /* marker_bit */
+
+ self->time_increment_bits = (guint32)log2((double)(vop_tir - 1)) + 1;
+
+ GST_DEBUG_OBJECT (self, "vop_tir=%d, time_increment_bits=%d",
+ vop_tir, self->time_increment_bits);
+
+ if (self->time_increment_bits < 1)
+ self->time_increment_bits = 1;
+
+ /* we don't care about anything beyond here */
+}
+
+static gboolean
+is_vop_coded (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
+{
+ GstBitReader *br =
+ get_bit_reader (self, data, size);
+ guint32 b = 0;
+
+ gst_bit_reader_skip (br, 2); /* vop_coding_type */
+
+ do { /* modulo_time_base */
+ gst_bit_reader_get_bits_uint32 (br, &b, 1);
+ } while (b != 0);
+
+ gst_bit_reader_skip (br, 1); /* marker_bit */
+ gst_bit_reader_skip (br, /* vop_time_increment */
+ self->time_increment_bits);
+ gst_bit_reader_skip (br, 1); /* marker_bit */
+ gst_bit_reader_get_bits_uint32 (br, /* vop_coded */
+ &b, 1);
+
+ return b;
+}
+
+static GstBuffer *
+gst_ducati_mpeg4dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
+{
+ GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (vdec);
+ GstBuffer *remaining = NULL;
+ gint insize = GST_BUFFER_SIZE (buf);
+ const guint8 *in = GST_BUFFER_DATA (buf);
+ gint size = 0;
+ guint8 last_start_code = 0xff;
+
+ while (insize > (SC_SZ + 1)) {
+ gint nal_size;
+ guint8 start_code = in[SC_SZ];
+ gboolean skip = FALSE;
+
+ GST_DEBUG_OBJECT (self, "start_code: %02x", start_code);
+
+ if (size > 0) {
+ /* check if we've found a potential start of frame: */
+ if ((start_code == VOS_START_CODE) ||
+ (start_code == GVOP_START_CODE) ||
+ (start_code == VOP_START_CODE) ||
+ (start_code <= 0x1f)) { /* 00->0f is video_object_start_code */
+ /* if last was a VOP, or if this is first VOP, then what follows
+ * must be the next frame:
+ */
+ if (((last_start_code == 0xff) && (start_code == VOP_START_CODE)) ||
+ (last_start_code == VOP_START_CODE)) {
+ GST_DEBUG_OBJECT (self, "found end");
+ break;
+ }
+ } else if ((0x20 <= start_code) && (start_code <= 0x2f)) {
+ decode_vol_header (self, in + SC_SZ + 1, insize - SC_SZ - 1);
+ }
+ }
+
+ last_start_code = start_code;
+
+ nal_size = SC_SZ +
+ find_start_code (sc, SC_SZ, in + SC_SZ, insize - SC_SZ);
+
+ if ((start_code == VOP_START_CODE) && (nal_size < 20)) {
+ /* suspiciously small nal.. check for !vop_coded and filter
+ * that out to avoid upsetting the decoder:
+ *
+ * XXX 20 is arbitrary value, but I want to avoid having
+ * to parse every VOP.. the non-coded VOP's I'm seeing
+ * are all 7 bytes but need to come up with some sane
+ * threshold
+ */
+ skip = ! is_vop_coded (self, in + SC_SZ + 1, insize - SC_SZ - 1);
+ if (skip)
+ GST_DEBUG_OBJECT (self, "skipping non-coded VOP");
+ }
+
+ if (!skip)
+ push_input (vdec, in, nal_size);
+
+ in += nal_size;
+ insize -= nal_size;
+ size += nal_size;
+ }
+
+ /* if there are remaining bytes, wrap those back as a buffer
+ * for the next go around:
+ */
+ if (insize > 0) {
+ remaining = gst_buffer_create_sub (buf, size, insize);
+ }
+
+ return remaining;
+}
+
/* GObject vmethod implementations */
+static void
+gst_ducati_mpeg4dec_finalize (GObject * obj)
+{
+ GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (obj);
+ if (self->br)
+ gst_bit_reader_free (self->br);
+ G_OBJECT_CLASS (parent_class)->finalize (obj);
+}
+
static void
gst_ducati_mpeg4dec_base_init (gpointer gclass)
{
static void
gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
+
+ gobject_class->finalize =
+ GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_finalize);
+
bclass->codec_name = "ivahd_mpeg4dec";
bclass->update_buffer_size =
GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_update_buffer_size);
bclass->allocate_params =
GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_allocate_params);
+ bclass->push_input =
+ GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_push_input);
}
static void
index f039c08a64420ba55a2f4af48f5facb0b523d2b2..1a72b55ef2bdb0041d09683313f9fa4014ac609d 100644 (file)
--- a/src/gstducatimpeg4dec.h
+++ b/src/gstducatimpeg4dec.h
#include "gstducatividdec.h"
+#include <gst/base/gstbitreader.h>
#include <ti/sdo/codecs/mpeg4dec/impeg4vdec.h>
struct _GstDucatiMpeg4Dec
{
GstDucatiVidDec parent;
+ GstBitReader *br;
+ gint time_increment_bits;
};
struct _GstDucatiMpeg4DecClass
diff --git a/src/gstducatividdec.c b/src/gstducatividdec.c
index d4fe417e78e95fcc68ed091a2471bfa46521018f..a2d919f14f67920b2af724e6811b2563157db413 100644 (file)
--- a/src/gstducatividdec.c
+++ b/src/gstducatividdec.c
return GST_FLOW_ERROR;
}
+ GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes)",
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+ GST_BUFFER_SIZE (buf));
+
decode = gst_ducati_viddec_do_qos (self, buf);
if (!decode) {
gst_buffer_unref (buf);
self->inArgs->numBytes = self->in_size;
self->inBufs->descs[0].bufSize.bytes = self->in_size;
- if (buf) {
- // XXX
- GST_WARNING_OBJECT (self, "TODO.. can't push more than one.. need loop");
- gst_buffer_unref (buf);
- buf = NULL;
- }
-
err = codec_process (self, TRUE, FALSE);
if (err) {
GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
self->need_out_buf = TRUE;
}
+ if (buf) {
+ GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
+ GST_BUFFER_SIZE (buf));
+ goto allocate_buffer;
+ }
+
return GST_FLOW_OK;
}
diff --git a/src/gstducatividdec.h b/src/gstducatividdec.h
index 23a06a8a8ff4a7d056b350d9b60a34f758c60c55..7f83e90eea4145eb16f8227c53c221bd32b0c8de 100644 (file)
--- a/src/gstducatividdec.h
+++ b/src/gstducatividdec.h
/* helper methods for derived classes: */
static inline void
-push_input (GstDucatiVidDec * self, guint8 *in, gint sz)
+push_input (GstDucatiVidDec * self, const guint8 *in, gint sz)
{
GST_DEBUG_OBJECT (self, "push: %d bytes)", sz);
memcpy (self->input + self->in_size, in, sz);
self->in_size += sz;
}
+static inline int
+check_start_code (const guint8 *sc, gint scsize,
+ const guint8 *inbuf, gint insize)
+{
+ if (insize < scsize)
+ return FALSE;
+
+ while (scsize) {
+ if (*sc != *inbuf)
+ return FALSE;
+ scsize--;
+ sc++;
+ inbuf++;
+ }
+
+ return TRUE;
+}
+
+static inline int
+find_start_code (const guint8 *sc, gint scsize,
+ const guint8 *inbuf, gint insize)
+{
+ gint size = 0;
+ while (insize) {
+ if (check_start_code (sc, scsize, inbuf, insize))
+ break;
+ insize--;
+ size++;
+ inbuf++;
+ }
+ return size;
+}
+
G_END_DECLS
#endif /* __GST_DUCATIVIDDEC_H__ */