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-ducativc1dec
22 *
23 * FIXME:Describe ducativc1dec here.
24 *
25 * <refsect2>
26 * <title>Example launch line</title>
27 * |[
28 * gst-launch -v -m fakesrc ! ducativc1dec ! fakesink silent=TRUE
29 * ]|
30 * </refsect2>
31 */
33 #ifdef HAVE_CONFIG_H
34 # include <config.h>
35 #endif
37 #include "gstducativc1dec.h"
40 #define PADX 32
41 #define PADY 40
42 #define GST_BUFFER_FLAG_B_FRAME (GST_BUFFER_FLAG_LAST << 0)
45 GST_BOILERPLATE (GstDucatiVC1Dec, gst_ducati_vc1dec, GstDucatiVidDec,
46 GST_TYPE_DUCATIVIDDEC);
48 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
49 GST_PAD_SINK,
50 GST_PAD_ALWAYS,
51 GST_STATIC_CAPS ("video/x-wmv, "
52 "wmvversion = (int) 3, "
53 "format = (fourcc){ WVC1, WMV3 }, "
54 "width = (int)[ 16, 2048 ], "
55 "height = (int)[ 16, 2048 ], " "framerate = (fraction)[ 0, max ];")
56 );
58 /* GstDucatiVidDec vmethod implementations */
60 static gboolean
61 gst_ducati_vc1dec_parse_caps (GstDucatiVidDec * vdec, GstStructure * s)
62 {
63 GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
65 if (parent_class->parse_caps (vdec, s)) {
66 guint32 format;
67 gboolean ret = gst_structure_get_fourcc (s, "format", &format);
68 if (ret) {
69 switch (format) {
70 case GST_MAKE_FOURCC ('W', 'V', 'C', '1'):
71 self->level = 4;
72 break;
73 case GST_MAKE_FOURCC ('W', 'M', 'V', '3'):
74 self->level = 3;
75 break;
76 default:
77 ret = FALSE;
78 break;
79 }
80 }
81 GST_INFO_OBJECT (vdec, "level %d", self->level);
82 return ret;
83 }
85 return FALSE;
86 }
88 static void
89 gst_ducati_vc1dec_update_buffer_size (GstDucatiVidDec * self)
90 {
91 gint w = self->width;
92 gint h = self->height;
94 /* calculate output buffer parameters: */
95 self->padded_width = ALIGN2 (w + (2 * PADX), 7);
96 self->padded_height = (ALIGN2 (h / 2, 4) * 2) + 2 * PADY;
97 self->min_buffers = 8;
98 }
100 static gboolean
101 gst_ducati_vc1dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
102 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
103 {
104 gboolean ret = parent_class->allocate_params (self,
105 sizeof (IVC1VDEC_Params), sizeof (IVC1VDEC_DynamicParams),
106 sizeof (IVC1VDEC_Status), sizeof (IVC1VDEC_InArgs),
107 sizeof (IVC1VDEC_OutArgs));
109 if (ret) {
110 IVC1VDEC_Params *params = (IVC1VDEC_Params *) self->params;
111 self->params->maxBitRate = 45000000;
112 self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
114 /* this indicates whether buffers are prefixed with the frame layer struct
115 * or not. See Table 266: Frame Layer Data Structure from the spec */
116 params->frameLayerDataPresentFlag = FALSE;
118 /* enable concealment */
119 params->ErrorConcealmentON = 1;
121 /* codec wants lateAcquireArg = -1 */
122 self->dynParams->lateAcquireArg = -1;
123 }
125 return ret;
126 }
128 static GstBuffer *
129 gst_ducati_vc1dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
130 {
131 GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
132 IVC1VDEC_Params *params = (IVC1VDEC_Params *) vdec->params;
133 guint32 val;
135 /* need a base ts for frame layer timestamps */
136 if (self->first_ts == GST_CLOCK_TIME_NONE)
137 self->first_ts = GST_BUFFER_TIMESTAMP (buf);
139 if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
140 if (GST_BUFFER_SIZE (vdec->codec_data) > 0) {
141 unsigned char *header = GST_BUFFER_DATA (vdec->codec_data);
143 /* There is at least one VC1 stream that claims it is simple profile,
144 but goes on to have frames that use some feature that is unavailable
145 in simple profile(intensity compensation). Since ducati supports
146 both, we frob the header to claim all simple profile videos are
147 main profile. This is a lie, but it should not cause any trouble
148 (I'm sure all liars must say that). */
149 if (!(header[0] & 192))
150 header[0] |= 64;
151 }
153 if (self->level == 4) {
154 /* for VC-1 Advanced Profile, strip off first byte, and
155 * send rest of codec_data unmodified;
156 */
157 push_input (vdec, GST_BUFFER_DATA (vdec->codec_data) + 1,
158 GST_BUFFER_SIZE (vdec->codec_data) - 1);
159 } else {
160 /* for VC-1 Simple and Main Profile, build the Table 265 Sequence
161 * Layer Data Structure header (refer to VC-1 spec, Annex L):
162 */
164 val = 0xc5ffffff; /* we don't know the number of frames */
165 push_input (vdec, (const guint8 *) &val, 4);
167 /* STRUCT_C (preceded by length).. see Table 263, 264 */
168 val = 0x00000004;
169 push_input (vdec, (const guint8 *) &val, 4);
171 val = GST_READ_UINT32_LE (GST_BUFFER_DATA (vdec->codec_data));
172 /* FIXME: i have NO idea why asfdemux gives me something I need to patch... */
173 val |= 0x01 << 24;
174 push_input (vdec, (const guint8 *) &val, 4);
176 /* STRUCT_A.. see Table 260 and Annex J.2 */
177 val = vdec->height;
178 push_input (vdec, (const guint8 *) &val, 4);
179 val = vdec->width;
180 push_input (vdec, (const guint8 *) &val, 4);
181 GST_INFO_OBJECT (vdec, "seq hdr resolution: %dx%d", vdec->width,
182 vdec->height);
184 val = 0x0000000c;
185 push_input (vdec, (const guint8 *) &val, 4);
187 /* STRUCT_B.. see Table 261, 262 */
188 val = 0x00000000; /* not sure how to populate, but codec ignores anyways */
189 push_input (vdec, (const guint8 *) &val, 4);
190 push_input (vdec, (const guint8 *) &val, 4);
191 push_input (vdec, (const guint8 *) &val, 4);
192 }
193 }
195 /* VC-1 Advanced profile needs start-code prepended: */
196 if (self->level == 4) {
197 static const guint8 sc[] = { 0x00, 0x00, 0x01, 0x0d }; /* start code */
198 push_input (vdec, sc, sizeof (sc));
199 }
201 if (params->frameLayerDataPresentFlag) {
202 val = GST_BUFFER_SIZE (buf);
203 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
204 val |= 0x80 << 24;
205 else
206 val |= 0x00 << 24;
207 push_input (vdec, (const guint8 *) &val, 4);
208 val = GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buf) - self->first_ts);
209 push_input (vdec, (const guint8 *) &val, 4);
210 }
213 push_input (vdec, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
214 gst_buffer_unref (buf);
216 return NULL;
217 }
219 static gint
220 gst_ducati_vc1dec_handle_error (GstDucatiVidDec * self, gint ret,
221 gint extended_error, gint status_extended_error)
222 {
223 if (extended_error == 0x00409000)
224 /* the codec sets some IVC1DEC_ERR_PICHDR (corrupted picture headers) errors
225 * as fatal even though it's able to recover
226 */
227 ret = XDM_EOK;
228 else
229 ret = parent_class->handle_error (self, ret, extended_error,
230 status_extended_error);
232 return ret;
233 }
235 static gboolean
236 gst_ducati_vc1dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
237 gint64 diff)
238 {
239 gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
240 GST_BUFFER_FLAG_B_FRAME);
242 if (diff >= 0 && is_bframe)
243 return TRUE;
245 return FALSE;
246 }
248 /* GstElement vmethod implementations */
250 static GstStateChangeReturn
251 gst_ducati_vc1dec_change_state (GstElement * element, GstStateChange transition)
252 {
253 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
254 GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (element);
256 GST_INFO_OBJECT (self, "begin: changing state %s -> %s",
257 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
258 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
260 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
262 if (ret == GST_STATE_CHANGE_FAILURE)
263 goto leave;
265 switch (transition) {
266 case GST_STATE_CHANGE_PAUSED_TO_READY:
267 self->level = -1;
268 self->first_ts = GST_CLOCK_TIME_NONE;
269 break;
270 default:
271 break;
272 }
274 leave:
275 GST_LOG_OBJECT (self, "end");
277 return ret;
278 }
280 /* GObject vmethod implementations */
282 static void
283 gst_ducati_vc1dec_base_init (gpointer gclass)
284 {
285 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
287 gst_element_class_set_details_simple (element_class,
288 "DucatiVC1Dec",
289 "Codec/Decoder/Video",
290 "Decodes video in WMV3/VC-1 format with ducati",
291 "Rob Clark <rob@ti.com>");
293 gst_element_class_add_pad_template (element_class,
294 gst_static_pad_template_get (&sink_factory));
295 }
297 static void
298 gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass)
299 {
300 GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
301 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
303 gstelement_class->change_state =
304 GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_change_state);
306 bclass->codec_name = "ivahd_vc1vdec";
307 bclass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_parse_caps);
308 bclass->update_buffer_size =
309 GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_update_buffer_size);
310 bclass->allocate_params =
311 GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_allocate_params);
312 bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_push_input);
313 bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_handle_error);
314 bclass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_can_drop_frame);
315 }
317 static void
318 gst_ducati_vc1dec_init (GstDucatiVC1Dec * self, GstDucatiVC1DecClass * gclass)
319 {
320 GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
322 #ifndef GST_DISABLE_GST_DEBUG
323 vdec->error_strings[0] = "unsupported VIDDEC3 params";
324 vdec->error_strings[1] = "unsupported dynamic VIDDEC3 params";
325 vdec->error_strings[2] = "unsupported VC1 VIDDEC3 params";
326 vdec->error_strings[3] = "bad datasync settings";
327 vdec->error_strings[4] = "no slice";
328 vdec->error_strings[5] = "corrupted slice header";
329 vdec->error_strings[6] = "corrupted MB data";
330 vdec->error_strings[7] = "unsupported VC1 feature";
331 vdec->error_strings[16] = "stream end";
332 vdec->error_strings[17] = "unsupported resolution";
333 vdec->error_strings[18] = "IVA standby";
334 vdec->error_strings[19] = "invalid mbox message";
335 vdec->error_strings[20] = "corrupted sequence header";
336 vdec->error_strings[21] = "corrupted entry point header";
337 vdec->error_strings[22] = "corrupted picture header";
338 vdec->error_strings[23] = "ref picture buffer error";
339 vdec->error_strings[24] = "no sequence header";
340 vdec->error_strings[30] = "invalid buffer descriptor";
341 vdec->error_strings[31] = "pic size change";
342 #endif
344 self->level = -1;
345 self->first_ts = GST_CLOCK_TIME_NONE;
346 vdec->pageMemType = XDM_MEMTYPE_RAW;
347 }