cee2515d2958b05be74b0c4161faaa6a09b4fa86
[glsdk/gst-plugin-ducati.git] / src / gstducatimpeg4dec.c
1 /*
2  * GStreamer
3  * Copyright (c) 2010, Texas Instruments Incorporated
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation
8  * version 2.1 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
20 /**
21  * SECTION:element-ducatimpeg4dec
22  *
23  * FIXME:Describe ducatimpeg4dec here.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v -m fakesrc ! ducatimpeg4dec ! fakesink silent=TRUE
29  * ]|
30  * </refsect2>
31  */
33 #ifdef HAVE_CONFIG_H
34 #  include <config.h>
35 #endif
37 #include "gstducatimpeg4dec.h"
39 #include <math.h>
42 #define PADX  32
43 #define PADY  32
46 GST_BOILERPLATE (GstDucatiMpeg4Dec, gst_ducati_mpeg4dec, GstDucatiVidDec,
47     GST_TYPE_DUCATIVIDDEC);
49 #define MPEG4DEC_SINKCAPS_COMMON \
50     "width = (int)[ 16, 2048 ], " \
51     "height = (int)[ 16, 2048 ], " \
52     "framerate = (fraction)[ 0, max ]"
54 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
55     GST_PAD_SINK,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS (
58         "video/mpeg, "
59           "mpegversion = (int)4, "
60           "systemstream = (boolean)false, "
61           MPEG4DEC_SINKCAPS_COMMON ";"
62         "video/x-divx, "
63           "divxversion = (int)[4, 5], "  /* TODO check this */
64           MPEG4DEC_SINKCAPS_COMMON ";"
65         "video/x-xvid, "
66           MPEG4DEC_SINKCAPS_COMMON ";"
67         "video/x-3ivx, "
68           MPEG4DEC_SINKCAPS_COMMON ";"
69         )
70     );
72 /* GstDucatiVidDec vmethod implementations */
74 static void
75 gst_ducati_mpeg4dec_update_buffer_size (GstDucatiVidDec * self)
76 {
77   gint w = self->width;
78   gint h = self->height;
80   /* calculate output buffer parameters: */
81   self->padded_width = ALIGN2 (w + PADX, 7);
82   self->padded_height = h + PADY;
83   self->min_buffers = 8;
84 }
86 static gboolean
87 gst_ducati_mpeg4dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
88     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
89 {
90   gboolean ret = parent_class->allocate_params (self,
91       sizeof (IMPEG4VDEC_Params), sizeof (IMPEG4VDEC_DynamicParams),
92       sizeof (IMPEG4VDEC_Status), sizeof (IMPEG4VDEC_InArgs),
93       sizeof (IMPEG4VDEC_OutArgs));
95   if (ret) {
96     /* NB: custom params are needed as base params seem to break xvid */
97     IMPEG4VDEC_Params *params = (IMPEG4VDEC_Params *) self->params;
98     self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
99     self->dynParams->lateAcquireArg = -1;
100     params->outloopDeBlocking = FALSE;
101     params->sorensonSparkStream = FALSE;
102     params->ErrorConcealmentON = FALSE;
103   }
105   return ret;
108 #define VOS_START_CODE    0xb0    /* + visual object sequence */
109 #define VOS_END_CODE      0xb1
110 #define UD_START_CODE     0xb2    /* user data */
111 #define GVOP_START_CODE   0xb3    /* + group of VOP */
112 #define VS_ERROR_CODE     0xb4
113 #define VO_START_CODE     0xb5    /* visual object */
114 #define VOP_START_CODE    0xb6    /* + */
116 static const guint8 sc[] = {0x00, 0x00, 0x01};  /* start code */
117 #define SC_SZ                G_N_ELEMENTS (sc)  /* start code size */
119 static GstBitReader *
120 get_bit_reader (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
122   if (self->br) {
123     gst_bit_reader_init (self->br, data, size);
124   } else {
125     self->br = gst_bit_reader_new (data, size);
126   }
127   return self->br;
130 static void
131 decode_vol_header (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
133   GstBitReader *br = get_bit_reader (self, data, size);
134   guint32 is_oli = 0, vc_param = 0, vbv_param = 0;
135   guint32 ar_info = 0, vop_tir = 0;
137   gst_bit_reader_skip (br, 1);         /* random_accessible_vol */
138   gst_bit_reader_skip (br, 8);         /* video_object_type_indication */
140   gst_bit_reader_get_bits_uint32 (br,  /* is_object_layer_identifier */
141       &is_oli, 1);
142   if (is_oli) {
143     gst_bit_reader_skip (br, 4);       /* video_object_layer_verid */
144     gst_bit_reader_skip (br, 3);       /* video_object_layer_priority */
145   }
147   gst_bit_reader_get_bits_uint32 (br,  /* aspect_ratio_info */
148       &ar_info, 4);
149   if (ar_info == 0xf) {
150     gst_bit_reader_skip (br, 8);       /* par_width */
151     gst_bit_reader_skip (br, 8);       /* par_height */
152   }
154   gst_bit_reader_get_bits_uint32 (br,  /* vol_control_parameters */
155       &vc_param, 1);
156   if (vc_param) {
157     gst_bit_reader_skip (br, 2);       /* chroma_format */
158     gst_bit_reader_skip (br, 1);       /* low_delay */
159     gst_bit_reader_get_bits_uint32 (   /* vbv_parameters */
160         br, &vbv_param, 1);
161     if (vbv_param) {
162       gst_bit_reader_skip (br, 79);    /* don't care */
163     }
164   }
166   gst_bit_reader_skip (br, 2);         /* video_object_layer_shape */
167   gst_bit_reader_skip (br, 1);         /* marker_bit */
168   gst_bit_reader_get_bits_uint32 (br,  /* vop_time_increment_resolution */
169       &vop_tir, 16);
170   gst_bit_reader_skip (br, 1);         /* marker_bit */
172   self->time_increment_bits = (guint32)log2((double)(vop_tir - 1)) + 1;
174   GST_DEBUG_OBJECT (self, "vop_tir=%d, time_increment_bits=%d",
175       vop_tir, self->time_increment_bits);
177   if (self->time_increment_bits < 1)
178     self->time_increment_bits = 1;
180   /* we don't care about anything beyond here */
183 static void
184 decode_user_data (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
186   GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
187   const char *buf = (const char *)data;
188   int n, ver, build;
189   char c;
191   /* divx detection: */
192   n = sscanf(buf, "DivX%dBuild%d%c", &ver, &build, &c);
193   if (n < 2)
194     n = sscanf(buf, "DivX%db%d%c", &ver, &build, &c);
195   if (n >= 2) {
196     GST_INFO_OBJECT (self, "DivX: version %d, build %d", ver, build);
197     if ((n == 3) && (c == 'p')) {
198       GST_INFO_OBJECT (self, "detected packed B frames");
199       /* enable workarounds: */
200       vdec->ts_is_pts = TRUE;
201     }
202   }
204   /* xvid detection: */
205   n = sscanf(buf, "XviD%d", &build);
206   if (n == 1) {
207     GST_INFO_OBJECT (self, "XviD: build %d", build);
208     /* I believe we only get this in avi container, which means
209      * we also need to enable the workarounds:
210      */
211     vdec->ts_is_pts = TRUE;
212   }
215 static gboolean
216 is_vop_coded (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
218   GstBitReader *br =
219       get_bit_reader (self, data, size);
220   guint32 b = 0;
222   gst_bit_reader_skip (br, 2);         /* vop_coding_type */
224   do {                                 /* modulo_time_base */
225     gst_bit_reader_get_bits_uint32 (br, &b, 1);
226   } while (b != 0);
228   gst_bit_reader_skip (br, 1);         /* marker_bit */
229   gst_bit_reader_skip (br,             /* vop_time_increment */
230       self->time_increment_bits);
231   gst_bit_reader_skip (br, 1);         /* marker_bit */
232   gst_bit_reader_get_bits_uint32 (br,  /* vop_coded */
233       &b, 1);
235   return b;
238 static GstBuffer *
239 gst_ducati_mpeg4dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
241   GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (vdec);
242   GstBuffer *remaining = NULL;
243   gint insize = GST_BUFFER_SIZE (buf);
244   const guint8 *in  = GST_BUFFER_DATA (buf);
245   gint size = 0;
246   guint8 last_start_code = 0xff;
248   if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
249     push_input (vdec, GST_BUFFER_DATA (vdec->codec_data),
250         GST_BUFFER_SIZE (vdec->codec_data));
251   }
253   while (insize > (SC_SZ + 1)) {
254     gint nal_size;
255     guint8 start_code = in[SC_SZ];
256     gboolean skip = FALSE;
258     GST_DEBUG_OBJECT (self, "start_code: %02x", start_code);
260     if (size > 0) {
261       /* check if we've found a potential start of frame: */
262       if ((start_code == VOS_START_CODE) ||
263           (start_code == GVOP_START_CODE) ||
264           (start_code == VOP_START_CODE) ||
265           (start_code <= 0x1f)) { /* 00->0f is video_object_start_code */
266         /* if last was a VOP, or if this is first VOP, then what follows
267          * must be the next frame:
268          */
269         if (((last_start_code == 0xff) && (start_code == VOP_START_CODE)) ||
270             (last_start_code == VOP_START_CODE)) {
271           GST_DEBUG_OBJECT (self, "found end");
272           break;
273         }
274       } else if ((0x20 <= start_code) && (start_code <= 0x2f)) {
275         decode_vol_header (self, in + SC_SZ + 1, insize - SC_SZ - 1);
276       }
277     }
279     last_start_code = start_code;
281     nal_size = SC_SZ +
282         find_start_code (sc, SC_SZ, in + SC_SZ, insize - SC_SZ);
284     if ((start_code == VOP_START_CODE) && (nal_size < 20)) {
285       /* suspiciously small nal..  check for !vop_coded and filter
286        * that out to avoid upsetting the decoder:
287        *
288        * XXX 20 is arbitrary value, but I want to avoid having
289        * to parse every VOP.. the non-coded VOP's I'm seeing
290        * are all 7 bytes but need to come up with some sane
291        * threshold
292        */
293       skip = ! is_vop_coded (self, in + SC_SZ + 1, insize - SC_SZ - 1);
294       if (skip)
295         GST_DEBUG_OBJECT (self, "skipping non-coded VOP");
296     } else if (start_code == UD_START_CODE){
297       decode_user_data (self, in + SC_SZ + 1, nal_size - SC_SZ - 1);
298     }
300     if (!skip)
301       push_input (vdec, in, nal_size);
303     in += nal_size;
304     insize -= nal_size;
305     size += nal_size;
306   }
308   /* if there are remaining bytes, wrap those back as a buffer
309    * for the next go around:
310    */
311   if (insize > 0) {
312     remaining = gst_buffer_create_sub (buf, size, insize);
314     GST_BUFFER_DURATION (remaining) = GST_BUFFER_DURATION (buf);
315     if (vdec->ts_is_pts) {
316       GST_BUFFER_TIMESTAMP (remaining) = GST_CLOCK_TIME_NONE;
317     } else {
318       GST_BUFFER_TIMESTAMP (remaining) = GST_BUFFER_TIMESTAMP (buf) +
319           GST_BUFFER_DURATION (buf);
320     }
321   }
323   gst_buffer_unref (buf);
325   return remaining;
328 /* GObject vmethod implementations */
330 static void
331 gst_ducati_mpeg4dec_finalize (GObject * obj)
333   GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (obj);
334   if (self->br)
335     gst_bit_reader_free (self->br);
336   G_OBJECT_CLASS (parent_class)->finalize (obj);
339 static void
340 gst_ducati_mpeg4dec_base_init (gpointer gclass)
342   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
344   gst_element_class_set_details_simple (element_class,
345       "DucatiMpeg4Dec",
346       "Codec/Decoder/Video",
347       "Decodes video in MPEG-4 format with ducati",
348       "Rob Clark <rob@ti.com>");
350   gst_element_class_add_pad_template (element_class,
351       gst_static_pad_template_get (&sink_factory));
354 static void
355 gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass)
357   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
358   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
360   gobject_class->finalize =
361       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_finalize);
363   bclass->codec_name = "ivahd_mpeg4dec";
364   bclass->update_buffer_size =
365       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_update_buffer_size);
366   bclass->allocate_params =
367       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_allocate_params);
368   bclass->push_input =
369       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_push_input);
372 static void
373 gst_ducati_mpeg4dec_init (GstDucatiMpeg4Dec * self,
374     GstDucatiMpeg4DecClass * gclass)