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;
104 }
106 static void
107 gst_ducati_mpeg4dec_update_buffer_size (GstDucatiVidDec * self)
108 {
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;
116 }
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)
121 {
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;
138 }
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)
154 {
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;
161 }
163 static void
164 decode_vol_header (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
165 {
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 */
214 }
216 static void
217 decode_user_data (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
218 {
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 }
246 }
248 static gboolean
249 is_vop_coded (GstDucatiMpeg4Dec * self, const guint8 * data, guint size)
250 {
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;
268 }
270 static GstBuffer *
271 gst_ducati_mpeg4dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
272 {
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;
367 }
369 /* GObject vmethod implementations */
371 static void
372 gst_ducati_mpeg4dec_finalize (GObject * obj)
373 {
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);
378 }
380 static void
381 gst_ducati_mpeg4dec_base_init (gpointer gclass)
382 {
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));
392 }
394 static void
395 gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass)
396 {
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);
411 }
413 static void
414 gst_ducati_mpeg4dec_init (GstDucatiMpeg4Dec * self, gpointer gclass)
415 {
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
444 }