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 IMPEG4VDEC_Params *params = (IMPEG4VDEC_Params *) self->params;
97 self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
98 self->dynParams->lateAcquireArg = -1;
99 params->outloopDeBlocking = FALSE;
100 params->sorensonSparkStream = FALSE;
101 params->ErrorConcealmentON = FALSE;
102 }
104 return ret;
105 }
107 #define VOS_START_CODE 0xb0 /* + visual object sequence */
108 #define VOS_END_CODE 0xb1
109 #define UD_START_CODE 0xb2 /* user data */
110 #define GVOP_START_CODE 0xb3 /* + group of VOP */
111 #define VS_ERROR_CODE 0xb4
112 #define VO_START_CODE 0xb5 /* visual object */
113 #define VOP_START_CODE 0xb6 /* + */
115 static const guint8 sc[] = {0x00, 0x00, 0x01}; /* start code */
116 #define SC_SZ G_N_ELEMENTS (sc) /* start code size */
118 static GstBitReader *
119 get_bit_reader (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
120 {
121 if (self->br) {
122 gst_bit_reader_init (self->br, data, size);
123 } else {
124 self->br = gst_bit_reader_new (data, size);
125 }
126 return self->br;
127 }
129 static void
130 decode_vol_header (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
131 {
132 GstBitReader *br = get_bit_reader (self, data, size);
133 guint32 is_oli = 0, vc_param = 0, vbv_param = 0;
134 guint32 ar_info = 0, vop_tir = 0;
136 gst_bit_reader_skip (br, 1); /* random_accessible_vol */
137 gst_bit_reader_skip (br, 8); /* video_object_type_indication */
139 gst_bit_reader_get_bits_uint32 (br, /* is_object_layer_identifier */
140 &is_oli, 1);
141 if (is_oli) {
142 gst_bit_reader_skip (br, 4); /* video_object_layer_verid */
143 gst_bit_reader_skip (br, 3); /* video_object_layer_priority */
144 }
146 gst_bit_reader_get_bits_uint32 (br, /* aspect_ratio_info */
147 &ar_info, 4);
148 if (ar_info == 0xf) {
149 gst_bit_reader_skip (br, 8); /* par_width */
150 gst_bit_reader_skip (br, 8); /* par_height */
151 }
153 gst_bit_reader_get_bits_uint32 (br, /* vol_control_parameters */
154 &vc_param, 1);
155 if (vc_param) {
156 gst_bit_reader_skip (br, 2); /* chroma_format */
157 gst_bit_reader_skip (br, 1); /* low_delay */
158 gst_bit_reader_get_bits_uint32 ( /* vbv_parameters */
159 br, &vbv_param, 1);
160 if (vbv_param) {
161 gst_bit_reader_skip (br, 79); /* don't care */
162 }
163 }
165 gst_bit_reader_skip (br, 2); /* video_object_layer_shape */
166 gst_bit_reader_skip (br, 1); /* marker_bit */
167 gst_bit_reader_get_bits_uint32 (br, /* vop_time_increment_resolution */
168 &vop_tir, 16);
169 gst_bit_reader_skip (br, 1); /* marker_bit */
171 self->time_increment_bits = (guint32)log2((double)(vop_tir - 1)) + 1;
173 GST_DEBUG_OBJECT (self, "vop_tir=%d, time_increment_bits=%d",
174 vop_tir, self->time_increment_bits);
176 if (self->time_increment_bits < 1)
177 self->time_increment_bits = 1;
179 /* we don't care about anything beyond here */
180 }
182 static void
183 decode_user_data (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
184 {
185 GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
186 const char *buf = (const char *)data;
187 int n, ver, build;
188 char c;
190 /* divx detection: */
191 n = sscanf(buf, "DivX%dBuild%d%c", &ver, &build, &c);
192 if (n < 2)
193 n = sscanf(buf, "DivX%db%d%c", &ver, &build, &c);
194 if (n >= 2) {
195 GST_INFO_OBJECT (self, "DivX: version %d, build %d", ver, build);
196 if ((n == 3) && (c == 'p')) {
197 GST_INFO_OBJECT (self, "detected packed B frames");
198 /* enable workarounds: */
199 vdec->ts_is_pts = TRUE;
200 }
201 }
203 /* xvid detection: */
204 n = sscanf(buf, "XviD%d", &build);
205 if (n == 1) {
206 GST_INFO_OBJECT (self, "XviD: build %d", build);
207 /* I believe we only get this in avi container, which means
208 * we also need to enable the workarounds:
209 */
210 vdec->ts_is_pts = TRUE;
211 }
212 }
214 static gboolean
215 is_vop_coded (GstDucatiMpeg4Dec *self, const guint8 * data, guint size)
216 {
217 GstBitReader *br =
218 get_bit_reader (self, data, size);
219 guint32 b = 0;
221 gst_bit_reader_skip (br, 2); /* vop_coding_type */
223 do { /* modulo_time_base */
224 gst_bit_reader_get_bits_uint32 (br, &b, 1);
225 } while (b != 0);
227 gst_bit_reader_skip (br, 1); /* marker_bit */
228 gst_bit_reader_skip (br, /* vop_time_increment */
229 self->time_increment_bits);
230 gst_bit_reader_skip (br, 1); /* marker_bit */
231 gst_bit_reader_get_bits_uint32 (br, /* vop_coded */
232 &b, 1);
234 return b;
235 }
237 static GstBuffer *
238 gst_ducati_mpeg4dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
239 {
240 GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (vdec);
241 GstBuffer *remaining = NULL;
242 gint insize = GST_BUFFER_SIZE (buf);
243 const guint8 *in = GST_BUFFER_DATA (buf);
244 gint size = 0;
245 guint8 last_start_code = 0xff;
247 if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
248 push_input (vdec, GST_BUFFER_DATA (vdec->codec_data),
249 GST_BUFFER_SIZE (vdec->codec_data));
250 }
252 while (insize > (SC_SZ + 1)) {
253 gint nal_size;
254 guint8 start_code = in[SC_SZ];
255 gboolean skip = FALSE;
257 GST_DEBUG_OBJECT (self, "start_code: %02x", start_code);
259 if (size > 0) {
260 /* check if we've found a potential start of frame: */
261 if ((start_code == VOS_START_CODE) ||
262 (start_code == GVOP_START_CODE) ||
263 (start_code == VOP_START_CODE) ||
264 (start_code <= 0x1f)) { /* 00->0f is video_object_start_code */
265 /* if last was a VOP, or if this is first VOP, then what follows
266 * must be the next frame:
267 */
268 if (((last_start_code == 0xff) && (start_code == VOP_START_CODE)) ||
269 (last_start_code == VOP_START_CODE)) {
270 GST_DEBUG_OBJECT (self, "found end");
271 break;
272 }
273 } else if ((0x20 <= start_code) && (start_code <= 0x2f)) {
274 decode_vol_header (self, in + SC_SZ + 1, insize - SC_SZ - 1);
275 }
276 }
278 last_start_code = start_code;
280 nal_size = SC_SZ +
281 find_start_code (sc, SC_SZ, in + SC_SZ, insize - SC_SZ);
283 if ((start_code == VOP_START_CODE) && (nal_size < 20)) {
284 /* suspiciously small nal.. check for !vop_coded and filter
285 * that out to avoid upsetting the decoder:
286 *
287 * XXX 20 is arbitrary value, but I want to avoid having
288 * to parse every VOP.. the non-coded VOP's I'm seeing
289 * are all 7 bytes but need to come up with some sane
290 * threshold
291 */
292 skip = ! is_vop_coded (self, in + SC_SZ + 1, insize - SC_SZ - 1);
293 if (skip)
294 GST_DEBUG_OBJECT (self, "skipping non-coded VOP");
295 } else if (start_code == UD_START_CODE){
296 decode_user_data (self, in + SC_SZ + 1, nal_size - SC_SZ - 1);
297 }
299 if (!skip)
300 push_input (vdec, in, nal_size);
302 in += nal_size;
303 insize -= nal_size;
304 size += nal_size;
305 }
307 /* if there are remaining bytes, wrap those back as a buffer
308 * for the next go around:
309 */
310 if (insize > 0) {
311 remaining = gst_buffer_create_sub (buf, size, insize);
313 GST_BUFFER_DURATION (remaining) = GST_BUFFER_DURATION (buf);
314 if (vdec->ts_is_pts) {
315 GST_BUFFER_TIMESTAMP (remaining) = GST_CLOCK_TIME_NONE;
316 } else {
317 GST_BUFFER_TIMESTAMP (remaining) = GST_BUFFER_TIMESTAMP (buf) +
318 GST_BUFFER_DURATION (buf);
319 }
320 }
322 gst_buffer_unref (buf);
324 return remaining;
325 }
327 /* GObject vmethod implementations */
329 static void
330 gst_ducati_mpeg4dec_finalize (GObject * obj)
331 {
332 GstDucatiMpeg4Dec *self = GST_DUCATIMPEG4DEC (obj);
333 if (self->br)
334 gst_bit_reader_free (self->br);
335 G_OBJECT_CLASS (parent_class)->finalize (obj);
336 }
338 static void
339 gst_ducati_mpeg4dec_base_init (gpointer gclass)
340 {
341 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
343 gst_element_class_set_details_simple (element_class,
344 "DucatiMpeg4Dec",
345 "Codec/Decoder/Video",
346 "Decodes video in MPEG-4 format with ducati",
347 "Rob Clark <rob@ti.com>");
349 gst_element_class_add_pad_template (element_class,
350 gst_static_pad_template_get (&sink_factory));
351 }
353 static void
354 gst_ducati_mpeg4dec_class_init (GstDucatiMpeg4DecClass * klass)
355 {
356 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
357 GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
359 gobject_class->finalize =
360 GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_finalize);
362 bclass->codec_name = "ivahd_mpeg4dec";
363 bclass->update_buffer_size =
364 GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_update_buffer_size);
365 bclass->allocate_params =
366 GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_allocate_params);
367 bclass->push_input =
368 GST_DEBUG_FUNCPTR (gst_ducati_mpeg4dec_push_input);
369 }
371 static void
372 gst_ducati_mpeg4dec_init (GstDucatiMpeg4Dec * self,
373 GstDucatiMpeg4DecClass * gclass)
374 {
375 }