]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducatimpeg4dec.c
mpeg4decode: Prevent skipping of non-VOP coded frames
[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 static void gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass);
47 static void gst_ducati_mpeg4dec_init (GstDucatiMpeg4Dec * self, gpointer klass);
48 static void gst_ducati_mpeg4dec_base_init (gpointer gclass);
49 static GstDucatiVidDecClass *parent_class = NULL;
51 GType
52 gst_ducati_mpeg4dec_get_type (void)
53 {
54   static GType ducati_mpeg4dec_type = 0;
56   if (!ducati_mpeg4dec_type) {
57     static const GTypeInfo ducati_mpeg4dec_info = {
58       sizeof (GstDucatiMpeg4DecClass),
59       (GBaseInitFunc) gst_ducati_mpeg4dec_base_init,
60       NULL,
61       (GClassInitFunc) gst_ducati_mpeg4dec_class_init,
62       NULL,
63       NULL,
64       sizeof (GstDucatiMpeg4Dec),
65       0,
66       (GInstanceInitFunc) gst_ducati_mpeg4dec_init,
67     };
69     ducati_mpeg4dec_type = g_type_register_static (GST_TYPE_DUCATIVIDDEC,
70         "GstDucatiMpeg4Dec", &ducati_mpeg4dec_info, 0);
71   }
72   return ducati_mpeg4dec_type;
73 }
75 #define MPEG4DEC_SINKCAPS_COMMON \
76     "width = (int)[ 16, 2048 ], " \
77     "height = (int)[ 16, 2048 ], " \
78     "framerate = (fraction)[ 0, max ]"
80 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
81     GST_PAD_SINK,
82     GST_PAD_ALWAYS,
83     GST_STATIC_CAPS ("video/mpeg, " "mpegversion = (int)4, " "systemstream = (boolean)false, " MPEG4DEC_SINKCAPS_COMMON ";" "video/x-divx, " "divxversion = (int)[4, 5], "      /* TODO check this */
84         MPEG4DEC_SINKCAPS_COMMON ";"
85         "video/x-xvid, "
86         MPEG4DEC_SINKCAPS_COMMON ";"
87         "video/x-3ivx, " MPEG4DEC_SINKCAPS_COMMON ";")
88     );
90 /* GstDucatiVidDec vmethod implementations */
92 static gboolean
93 gst_ducati_mpeg4dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
94     gint64 diff)
95 {
96   /* The mpeg4 video parser element (mpeg4videoparse) does not do a correct job
97      in identifying key-frames for some interlaced streams.
98      This produces undesirable artifacts when frames are dropped due to QOS.
99      This workaround asks the base class to not drop (avoid decoding) any mpeg4 
100      frames based on buffer flags.
101      TODO: Implement a parser to check if a frame is skippable or not
102    */
103   return FALSE;
106 static void
107 gst_ducati_mpeg4dec_update_buffer_size (GstDucatiVidDec * self)
109   gint w = self->width;
110   gint h = self->height;
112   /* calculate output buffer parameters: */
113   self->padded_width = ALIGN2 (w + PADX, 7);
114   self->padded_height = h + PADY;
115   self->min_buffers = 8;
118 static gboolean
119 gst_ducati_mpeg4dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
120     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
122   gboolean ret = GST_DUCATIVIDDEC_CLASS (parent_class)->allocate_params (self,
123       sizeof (IMPEG4VDEC_Params), sizeof (IMPEG4VDEC_DynamicParams),
124       sizeof (IMPEG4VDEC_Status), sizeof (IMPEG4VDEC_InArgs),
125       sizeof (IMPEG4VDEC_OutArgs));
127   if (ret) {
128     /* NB: custom params are needed as base params seem to break xvid */
129     IMPEG4VDEC_Params *params = (IMPEG4VDEC_Params *) self->params;
130     self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
131     self->dynParams->lateAcquireArg = -1;
132     params->outloopDeBlocking = FALSE;
133     params->sorensonSparkStream = FALSE;
134     params->errorConcealmentEnable = FALSE;
135   }
137   return ret;
140 #define VOS_START_CODE    0xb0  /* + visual object sequence */
141 #define VOS_END_CODE      0xb1
142 #define UD_START_CODE     0xb2  /* user data */
143 #define GVOP_START_CODE   0xb3  /* + group of VOP */
144 #define VS_ERROR_CODE     0xb4
145 #define VO_START_CODE     0xb5  /* visual object */
146 #define VOP_START_CODE    0xb6  /* + */
148 static const guint8 sc[] = { 0x00, 0x00, 0x01 };        /* start code */
150 #define SC_SZ                G_N_ELEMENTS (sc)  /* start code size */
152 static GstBitReader *
153 get_bit_reader (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
155   if (self->br) {
156     gst_bit_reader_init (self->br, data, size);
157   } else {
158     self->br = gst_bit_reader_new (data, size);
159   }
160   return self->br;
163 static void
164 decode_vol_header (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
166   GstBitReader *br = get_bit_reader (self, data, size);
167   guint32 is_oli = 0, vc_param = 0, vbv_param = 0;
168   guint32 ar_info = 0, vop_tir = 0;
170   gst_bit_reader_skip (br, 1);  /* random_accessible_vol */
171   gst_bit_reader_skip (br, 8);  /* video_object_type_indication */
173   gst_bit_reader_get_bits_uint32 (br,   /* is_object_layer_identifier */
174       &is_oli, 1);
175   if (is_oli) {
176     gst_bit_reader_skip (br, 4);        /* video_object_layer_verid */
177     gst_bit_reader_skip (br, 3);        /* video_object_layer_priority */
178   }
180   gst_bit_reader_get_bits_uint32 (br,   /* aspect_ratio_info */
181       &ar_info, 4);
182   if (ar_info == 0xf) {
183     gst_bit_reader_skip (br, 8);        /* par_width */
184     gst_bit_reader_skip (br, 8);        /* par_height */
185   }
187   gst_bit_reader_get_bits_uint32 (br,   /* vol_control_parameters */
188       &vc_param, 1);
189   if (vc_param) {
190     gst_bit_reader_skip (br, 2);        /* chroma_format */
191     gst_bit_reader_skip (br, 1);        /* low_delay */
192     gst_bit_reader_get_bits_uint32 (    /* vbv_parameters */
193         br, &vbv_param, 1);
194     if (vbv_param) {
195       gst_bit_reader_skip (br, 79);     /* don't care */
196     }
197   }
199   gst_bit_reader_skip (br, 2);  /* video_object_layer_shape */
200   gst_bit_reader_skip (br, 1);  /* marker_bit */
201   gst_bit_reader_get_bits_uint32 (br,   /* vop_time_increment_resolution */
202       &vop_tir, 16);
203   gst_bit_reader_skip (br, 1);  /* marker_bit */
205   self->time_increment_bits = (guint32) log2 ((double) (vop_tir - 1)) + 1;
207   GST_DEBUG_OBJECT (self, "vop_tir=%d, time_increment_bits=%d",
208       vop_tir, self->time_increment_bits);
210   if (self->time_increment_bits < 1)
211     self->time_increment_bits = 1;
213   /* we don't care about anything beyond here */
216 static void
217 decode_user_data (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
219   GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
220   const char *buf = (const char *) data;
221   int n, ver, build;
222   char c;
224   /* divx detection: */
225   n = sscanf (buf, "DivX%dBuild%d%c", &ver, &build, &c);
226   if (n < 2)
227     n = sscanf (buf, "DivX%db%d%c", &ver, &build, &c);
228   if (n >= 2) {
229     GST_INFO_OBJECT (self, "DivX: version %d, build %d", ver, build);
230     if ((n == 3) && (c == 'p')) {
231       GST_INFO_OBJECT (self, "detected packed B frames");
232       /* enable workarounds: */
233       vdec->ts_is_pts = TRUE;
234     }
235   }
237   /* xvid detection: */
238   n = sscanf (buf, "XviD%d", &build);
239   if (n == 1) {
240     GST_INFO_OBJECT (self, "XviD: build %d", build);
241     /* I believe we only get this in avi container, which means
242      * we also need to enable the workarounds:
243      */
244     vdec->ts_is_pts = TRUE;
245   }
248 static gboolean
249 is_vop_coded (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
251   GstBitReader *br = get_bit_reader (self, data, size);
252   guint32 b = 0;
254   gst_bit_reader_skip (br, 2);  /* vop_coding_type */
256   do {                          /* modulo_time_base */
257     gst_bit_reader_get_bits_uint32 (br, &b, 1);
258   } while (b != 0);
260   gst_bit_reader_skip (br, 1);  /* marker_bit */
261   gst_bit_reader_skip (br,      /* vop_time_increment */
262       self->time_increment_bits);
263   gst_bit_reader_skip (br, 1);  /* marker_bit */
264   gst_bit_reader_get_bits_uint32 (br,   /* vop_coded */
265       &b, 1);
267   return b;
270 static GstBuffer *
271 gst_ducati_mpeg4dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
273   GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (vdec);
274   GstBuffer *remaining = NULL;
275   gint insize = 0;
276   guint8 *in = NULL;
277   gint size = 0;
278   guint8 last_start_code = 0xff;
279   GstMapInfo info;
280   gboolean mapped;
281   mapped = gst_buffer_map (buf, &info, GST_MAP_READ);
282   if (mapped) {
283     in = info.data;
284     insize = info.size;
285   }
286   if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codecdata) {
287     push_input (vdec, vdec->codecdata, vdec->codecdatasize);
288   }
290   while (insize > (SC_SZ + 1)) {
291     gint nal_size;
292     guint8 start_code = in[SC_SZ];
293     gboolean skip = FALSE;
295     GST_DEBUG_OBJECT (self, "start_code: %02x", start_code);
297     if (size > 0) {
298       /* check if we've found a potential start of frame: */
299       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 */
300         /* if last was a VOP, or if this is first VOP, then what follows
301          * must be the next frame:
302          */
303         if (((last_start_code == 0xff) && (start_code == VOP_START_CODE)) ||
304             (last_start_code == VOP_START_CODE)) {
305           GST_DEBUG_OBJECT (self, "found end");
306           break;
307         }
308       } else if ((0x20 <= start_code) && (start_code <= 0x2f)) {
309         decode_vol_header (self, in + SC_SZ + 1, insize - SC_SZ - 1);
310       }
311     }
313     last_start_code = start_code;
315     nal_size = SC_SZ + find_start_code (sc, SC_SZ, in + SC_SZ, insize - SC_SZ);
317     if ((start_code == VOP_START_CODE) && (nal_size < 20)) {
318       /* suspiciously small nal..  check for !vop_coded and filter
319        * that out to avoid upsetting the decoder:
320        *
321        * XXX 20 is arbitrary value, but I want to avoid having
322        * to parse every VOP.. the non-coded VOP's I'm seeing
323        * are all 7 bytes but need to come up with some sane
324        * threshold
325        */
326       skip = !is_vop_coded (self, in + SC_SZ + 1, insize - SC_SZ - 1);
327       /* Since this plugin is not handling such frames and triggering
328        * a repeat frame, we should not skip pushing this to the codec.
329        * However, we need to revisit this loop at a later time and
330        * identify a better solution */
331       skip = 0;
332       if (skip)
333         GST_DEBUG_OBJECT (self, "skipping non-coded VOP");
334     } else if (start_code == UD_START_CODE) {
335       decode_user_data (self, in + SC_SZ + 1, nal_size - SC_SZ - 1);
336     }
338     if (!skip)
339       push_input (vdec, in, nal_size);
341     in += nal_size;
342     insize -= nal_size;
343     size += nal_size;
344   }
346   /* if there are remaining bytes, wrap those back as a buffer
347    * for the next go around:
348    */
349   if (insize > 0) {
350     remaining =
351         gst_buffer_copy_region (buf, GST_BUFFER_COPY_DEEP, size, insize);
353     GST_BUFFER_DURATION (remaining) = GST_BUFFER_DURATION (buf);
354     if (vdec->ts_is_pts) {
355       GST_BUFFER_PTS (remaining) = GST_CLOCK_TIME_NONE;
356     } else {
357       GST_BUFFER_PTS (remaining) = GST_BUFFER_PTS (buf) +
358           GST_BUFFER_DURATION (buf);
359     }
360   }
361   if (mapped) {
362     gst_buffer_unmap (buf, &info);
363   }
364   gst_buffer_unref (buf);
366   return remaining;
369 /* GObject vmethod implementations */
371 static void
372 gst_ducati_mpeg4dec_finalize (GObject * obj)
374   GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (obj);
375   if (self->br)
376     gst_bit_reader_free (self->br);
377   G_OBJECT_CLASS (parent_class)->finalize (obj);
380 static void
381 gst_ducati_mpeg4dec_base_init (gpointer gclass)
383   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
385   gst_element_class_set_static_metadata (element_class,
386       "DucatiMpeg4Dec",
387       "Codec/Decoder/Video",
388       "Decodes video in MPEG-4 format with ducati", "Rob Clark <rob@ti.com>");
390   gst_element_class_add_pad_template (element_class,
391       gst_static_pad_template_get (&sink_factory));
394 static void
395 gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass)
397   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
398   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
400   parent_class = g_type_class_peek_parent (klass);
401   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_finalize);
403   bclass->codec_name = "ivahd_mpeg4dec";
404   bclass->update_buffer_size =
405       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_update_buffer_size);
406   bclass->allocate_params =
407       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_allocate_params);
408   bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_push_input);
409   bclass->can_drop_frame =
410       GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_can_drop_frame);
413 static void
414 gst_ducati_mpeg4dec_init (GstDucatiMpeg4Dec * self, gpointer gclass)
416 #ifndef GST_DISABLE_GST_DEBUG
417   GstDucatiVidDec *dec = GST_DUCATIVIDDEC (self);
419   dec->error_strings[0] = "no video object sequence found";
420   dec->error_strings[1] = "incorrect video object type";
421   dec->error_strings[2] = "error in video object layer";
422   dec->error_strings[3] = "error parsing group of video";
423   dec->error_strings[4] = "error parsing video object plane";
424   dec->error_strings[5] = "error in short header parsing";
425   dec->error_strings[6] = "error in GOB parsing";
426   dec->error_strings[7] = "error in video packet parsing";
427   dec->error_strings[16] = "error in MB data parsing";
428   dec->error_strings[17] = "invalid parameter";
429   dec->error_strings[18] = "unsupported feature";
430   dec->error_strings[19] = "stream end";
431   dec->error_strings[20] = "valid header not found";
432   dec->error_strings[21] = "unsupported resolution";
433   dec->error_strings[22] = "stream buffer underflow";
434   dec->error_strings[23] = "invalid mbox message";
435   dec->error_strings[24] = "no frame to flush";
436   dec->error_strings[25] = "given vop is not codec";
437   dec->error_strings[26] = "start code not present";
438   dec->error_strings[27] = "unsupported time increment resolution";
439   dec->error_strings[28] = "resolution change";
440   dec->error_strings[29] = "unsupported H263 annex";
441   dec->error_strings[30] = "bad HDVICP2 state";
442   dec->error_strings[31] = "frame dropped";
443 #endif