index 7c16547cdbe09a3733f58f3e489c5ff190ee1789..cee2515d2958b05be74b0c4161faaa6a09b4fa86 100644 (file)
--- a/src/gstducatimpeg4dec.c
+++ b/src/gstducatimpeg4dec.c
# include <config.h>
#endif
-#include <gst/gst.h>
-#include <gst/video/video.h>
-
#include "gstducatimpeg4dec.h"
+#include <math.h>
+
#define PADX 32
#define PADY 32
sizeof (IMPEG4VDEC_OutArgs));
if (ret) {
+ /* NB: custom params are needed as base params seem to break xvid */
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->outloopDeBlocking = FALSE;
params->sorensonSparkStream = FALSE;
params->ErrorConcealmentON = 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 = 0, vc_param = 0, vbv_param = 0;
+ guint32 ar_info = 0, vop_tir = 0;
+
+ 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 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);
+ /* I believe we only get this in avi container, which means
+ * we also need to enable the workarounds:
+ */
+ vdec->ts_is_pts = TRUE;
+ }
+}
+
+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;
+
+ if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
+ push_input (vdec, GST_BUFFER_DATA (vdec->codec_data),
+ GST_BUFFER_SIZE (vdec->codec_data));
+ }
+
+ 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");
+ } else if (start_code == UD_START_CODE){
+ decode_user_data (self, in + SC_SZ + 1, nal_size - SC_SZ - 1);
+ }
+
+ 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);
+
+ 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);
+ }
+ }
+
+ gst_buffer_unref (buf);
+
+ 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