]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducatimpeg4dec.c
212a4b88211796d6493eef41b04e99c88fb67ada
[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 ("video/mpeg, " "mpegversion = (int)4, " "systemstream = (boolean)false, " MPEG4DEC_SINKCAPS_COMMON ";" "video/x-divx, " "divxversion = (int)[4, 5], "      /* TODO check this */
58         MPEG4DEC_SINKCAPS_COMMON ";"
59         "video/x-xvid, "
60         MPEG4DEC_SINKCAPS_COMMON ";"
61         "video/x-3ivx, " MPEG4DEC_SINKCAPS_COMMON ";")
62     );
64 /* GstDucatiVidDec vmethod implementations */
66 static void
67 gst_ducati_mpeg4dec_update_buffer_size (GstDucatiVidDec * self)
68 {
69   gint w = self->width;
70   gint h = self->height;
72   /* calculate output buffer parameters: */
73   self->padded_width = ALIGN2 (w + PADX, 7);
74   self->padded_height = h + PADY;
75   self->min_buffers = 8;
76 }
78 static gboolean
79 gst_ducati_mpeg4dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
80     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
81 {
82   gboolean ret = parent_class->allocate_params (self,
83       sizeof (IMPEG4VDEC_Params), sizeof (IMPEG4VDEC_DynamicParams),
84       sizeof (IMPEG4VDEC_Status), sizeof (IMPEG4VDEC_InArgs),
85       sizeof (IMPEG4VDEC_OutArgs));
87   if (ret) {
88     /* NB: custom params are needed as base params seem to break xvid */
89     IMPEG4VDEC_Params *params = (IMPEG4VDEC_Params *) self->params;
90     self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
91     self->dynParams->lateAcquireArg = -1;
92     params->outloopDeBlocking = FALSE;
93     params->sorensonSparkStream = FALSE;
94     params->errorConcealmentEnable = FALSE;
95   }
97   return ret;
98 }
100 #define VOS_START_CODE    0xb0  /* + visual object sequence */
101 #define VOS_END_CODE      0xb1
102 #define UD_START_CODE     0xb2  /* user data */
103 #define GVOP_START_CODE   0xb3  /* + group of VOP */
104 #define VS_ERROR_CODE     0xb4
105 #define VO_START_CODE     0xb5  /* visual object */
106 #define VOP_START_CODE    0xb6  /* + */
108 static const guint8 sc[] = { 0x00, 0x00, 0x01 };        /* start code */
110 #define SC_SZ                G_N_ELEMENTS (sc)  /* start code size */
112 static GstBitReader *
113 get_bit_reader (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
115   if (self->br) {
116     gst_bit_reader_init (self->br, data, size);
117   } else {
118     self->br = gst_bit_reader_new (data, size);
119   }
120   return self->br;
123 static void
124 decode_vol_header (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
126   GstBitReader *br = get_bit_reader (self, data, size);
127   guint32 is_oli = 0, vc_param = 0, vbv_param = 0;
128   guint32 ar_info = 0, vop_tir = 0;
130   gst_bit_reader_skip (br, 1);  /* random_accessible_vol */
131   gst_bit_reader_skip (br, 8);  /* video_object_type_indication */
133   gst_bit_reader_get_bits_uint32 (br,   /* is_object_layer_identifier */
134       &is_oli, 1);
135   if (is_oli) {
136     gst_bit_reader_skip (br, 4);        /* video_object_layer_verid */
137     gst_bit_reader_skip (br, 3);        /* video_object_layer_priority */
138   }
140   gst_bit_reader_get_bits_uint32 (br,   /* aspect_ratio_info */
141       &ar_info, 4);
142   if (ar_info == 0xf) {
143     gst_bit_reader_skip (br, 8);        /* par_width */
144     gst_bit_reader_skip (br, 8);        /* par_height */
145   }
147   gst_bit_reader_get_bits_uint32 (br,   /* vol_control_parameters */
148       &vc_param, 1);
149   if (vc_param) {
150     gst_bit_reader_skip (br, 2);        /* chroma_format */
151     gst_bit_reader_skip (br, 1);        /* low_delay */
152     gst_bit_reader_get_bits_uint32 (    /* vbv_parameters */
153         br, &vbv_param, 1);
154     if (vbv_param) {
155       gst_bit_reader_skip (br, 79);     /* don't care */
156     }
157   }
159   gst_bit_reader_skip (br, 2);  /* video_object_layer_shape */
160   gst_bit_reader_skip (br, 1);  /* marker_bit */
161   gst_bit_reader_get_bits_uint32 (br,   /* vop_time_increment_resolution */
162       &vop_tir, 16);
163   gst_bit_reader_skip (br, 1);  /* marker_bit */
165   self->time_increment_bits = (guint32) log2 ((double) (vop_tir - 1)) + 1;
167   GST_DEBUG_OBJECT (self, "vop_tir=%d, time_increment_bits=%d",
168       vop_tir, self->time_increment_bits);
170   if (self->time_increment_bits < 1)
171     self->time_increment_bits = 1;
173   /* we don't care about anything beyond here */
176 static void
177 decode_user_data (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
179   GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
180   const char *buf = (const char *) data;
181   int n, ver, build;
182   char c;
184   /* divx detection: */
185   n = sscanf (buf, "DivX%dBuild%d%c", &ver, &build, &c);
186   if (n < 2)
187     n = sscanf (buf, "DivX%db%d%c", &ver, &build, &c);
188   if (n >= 2) {
189     GST_INFO_OBJECT (self, "DivX: version %d, build %d", ver, build);
190     if ((n == 3) && (c == 'p')) {
191       GST_INFO_OBJECT (self, "detected packed B frames");
192       /* enable workarounds: */
193       vdec->ts_is_pts = TRUE;
194     }
195   }
197   /* xvid detection: */
198   n = sscanf (buf, "XviD%d", &build);
199   if (n == 1) {
200     GST_INFO_OBJECT (self, "XviD: build %d", build);
201     /* I believe we only get this in avi container, which means
202      * we also need to enable the workarounds:
203      */
204     vdec->ts_is_pts = TRUE;
205   }
208 static gboolean
209 is_vop_coded (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
211   GstBitReader *br = get_bit_reader (self, data, size);
212   guint32 b = 0;
214   gst_bit_reader_skip (br, 2);  /* vop_coding_type */
216   do {                          /* modulo_time_base */
217     gst_bit_reader_get_bits_uint32 (br, &b, 1);
218   } while (b != 0);
220   gst_bit_reader_skip (br, 1);  /* marker_bit */
221   gst_bit_reader_skip (br,      /* vop_time_increment */
222       self->time_increment_bits);
223   gst_bit_reader_skip (br, 1);  /* marker_bit */
224   gst_bit_reader_get_bits_uint32 (br,   /* vop_coded */
225       &b, 1);
227   return b;
230 static GstBuffer *
231 gst_ducati_mpeg4dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
233   GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (vdec);
234   GstBuffer *remaining = NULL;
235   gint insize = GST_BUFFER_SIZE (buf);
236   const guint8 *in = GST_BUFFER_DATA (buf);
237   gint size = 0;
238   guint8 last_start_code = 0xff;
240   if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
241     push_input (vdec, GST_BUFFER_DATA (vdec->codec_data),
242         GST_BUFFER_SIZE (vdec->codec_data));
243   }
245   while (insize > (SC_SZ + 1)) {
246     gint nal_size;
247     guint8 start_code = in[SC_SZ];
248     gboolean skip = FALSE;
250     GST_DEBUG_OBJECT (self, "start_code: %02x", start_code);
252     if (size > 0) {
253       /* check if we've found a potential start of frame: */
254       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 */
255         /* if last was a VOP, or if this is first VOP, then what follows
256          * must be the next frame:
257          */
258         if (((last_start_code == 0xff) && (start_code == VOP_START_CODE)) ||
259             (last_start_code == VOP_START_CODE)) {
260           GST_DEBUG_OBJECT (self, "found end");
261           break;
262         }
263       } else if ((0x20 <= start_code) && (start_code <= 0x2f)) {
264         decode_vol_header (self, in + SC_SZ + 1, insize - SC_SZ - 1);
265       }
266     }
268     last_start_code = start_code;
270     nal_size = SC_SZ + find_start_code (sc, SC_SZ, in + SC_SZ, insize - SC_SZ);
272     if ((start_code == VOP_START_CODE) && (nal_size < 20)) {
273       /* suspiciously small nal..  check for !vop_coded and filter
274        * that out to avoid upsetting the decoder:
275        *
276        * XXX 20 is arbitrary value, but I want to avoid having
277        * to parse every VOP.. the non-coded VOP's I'm seeing
278        * are all 7 bytes but need to come up with some sane
279        * threshold
280        */
281       skip = !is_vop_coded (self, in + SC_SZ + 1, insize - SC_SZ - 1);
282       if (skip)
283         GST_DEBUG_OBJECT (self, "skipping non-coded VOP");
284     } else if (start_code == UD_START_CODE) {
285       decode_user_data (self, in + SC_SZ + 1, nal_size - SC_SZ - 1);
286     }
288     if (!skip)
289       push_input (vdec, in, nal_size);
291     in += nal_size;
292     insize -= nal_size;
293     size += nal_size;
294   }
296   /* if there are remaining bytes, wrap those back as a buffer
297    * for the next go around:
298    */
299   if (insize > 0) {
300     remaining = gst_buffer_create_sub (buf, size, insize);
302     GST_BUFFER_DURATION (remaining) = GST_BUFFER_DURATION (buf);
303     if (vdec->ts_is_pts) {
304       GST_BUFFER_TIMESTAMP (remaining) = GST_CLOCK_TIME_NONE;
305     } else {
306       GST_BUFFER_TIMESTAMP (remaining) = GST_BUFFER_TIMESTAMP (buf) +
307           GST_BUFFER_DURATION (buf);
308     }
309   }
311   gst_buffer_unref (buf);
313   return remaining;
316 /* GObject vmethod implementations */
318 static void
319 gst_ducati_mpeg4dec_finalize (GObject * obj)
321   GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (obj);
322   if (self->br)
323     gst_bit_reader_free (self->br);
324   G_OBJECT_CLASS (parent_class)->finalize (obj);
327 static void
328 gst_ducati_mpeg4dec_base_init (gpointer gclass)
330   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
332   gst_element_class_set_details_simple (element_class,
333       "DucatiMpeg4Dec",
334       "Codec/Decoder/Video",
335       "Decodes video in MPEG-4 format with ducati", "Rob Clark <rob@ti.com>");
337   gst_element_class_add_pad_template (element_class,
338       gst_static_pad_template_get (&sink_factory));
341 static void
342 gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass)
344   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
345   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
347   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_finalize);
349   bclass->codec_name = "ivahd_mpeg4dec";
350   bclass->update_buffer_size =
351       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_update_buffer_size);
352   bclass->allocate_params =
353       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_allocate_params);
354   bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_push_input);
357 static void
358 gst_ducati_mpeg4dec_init (GstDucatiMpeg4Dec * self,
359     GstDucatiMpeg4DecClass * gclass)
361 #ifndef GST_DISABLE_GST_DEBUG
362   GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
364   dec->error_strings[0] = "no video object sequence found";
365   dec->error_strings[1] = "incorrect video object type";
366   dec->error_strings[2] = "error in video object layer";
367   dec->error_strings[3] = "error parsing group of video";
368   dec->error_strings[4] = "error parsing video object plane";
369   dec->error_strings[5] = "error in short header parsing";
370   dec->error_strings[6] = "error in GOB parsing";
371   dec->error_strings[7] = "error in video packet parsing";
372   dec->error_strings[16] = "error in MB data parsing";
373   dec->error_strings[17] = "invalid parameter";
374   dec->error_strings[18] = "unsupported feature";
375   dec->error_strings[19] = "stream end";
376   dec->error_strings[20] = "valid header not found";
377   dec->error_strings[21] = "unsupported resolution";
378   dec->error_strings[22] = "stream buffer underflow";
379   dec->error_strings[23] = "invalid mbox message";
380   dec->error_strings[24] = "no frame to flush";
381   dec->error_strings[25] = "given vop is not codec";
382   dec->error_strings[26] = "start code not present";
383   dec->error_strings[27] = "unsupported time increment resolution";
384   dec->error_strings[28] = "resolution change";
385   dec->error_strings[29] = "unsupported H263 annex";
386   dec->error_strings[30] = "bad HDVICP2 state";
387   dec->error_strings[31] = "frame dropped";
388 #endif