Mangle a few files with gst-indent, for future sanity
[gstreamer-omap:gst-ducati.git] / src / gstducativc1dec.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  */
19
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  */
32
33 #ifdef HAVE_CONFIG_H
34 #  include <config.h>
35 #endif
36
37 #include "gstducativc1dec.h"
38
39
40 #define PADX  32
41 #define PADY  40
42 #define GST_BUFFER_FLAG_B_FRAME (GST_BUFFER_FLAG_LAST << 0)
43
44
45 GST_BOILERPLATE (GstDucatiVC1Dec, gst_ducati_vc1dec, GstDucatiVidDec,
46     GST_TYPE_DUCATIVIDDEC);
47
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     );
57
58 /* GstDucatiVidDec vmethod implementations */
59
60 static gboolean
61 gst_ducati_vc1dec_parse_caps (GstDucatiVidDec * vdec, GstStructure * s)
62 {
63   GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
64
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   }
84
85   return FALSE;
86 }
87
88 static void
89 gst_ducati_vc1dec_update_buffer_size (GstDucatiVidDec * self)
90 {
91   gint w = self->width;
92   gint h = self->height;
93
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 }
99
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));
108
109   if (ret) {
110     IVC1VDEC_Params *params = (IVC1VDEC_Params *) self->params;
111     self->params->maxBitRate = 45000000;
112     self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
113
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;
117
118     /* enable concealment */
119     params->ErrorConcealmentON = 1;
120
121     /* codec wants lateAcquireArg = -1 */
122     self->dynParams->lateAcquireArg = -1;
123   }
124
125   return ret;
126 }
127
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;
134
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);
138
139   if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codec_data) {
140     if (self->level == 4) {
141       /* for VC-1 Advanced Profile, strip off first byte, and
142        * send rest of codec_data unmodified;
143        */
144       push_input (vdec, GST_BUFFER_DATA (vdec->codec_data) + 1,
145           GST_BUFFER_SIZE (vdec->codec_data) - 1);
146     } else {
147       /* for VC-1 Simple and Main Profile, build the Table 265 Sequence
148        * Layer Data Structure header (refer to VC-1 spec, Annex L):
149        */
150
151       val = 0xc5ffffff;         /* we don't know the number of frames */
152       push_input (vdec, (const guint8 *) &val, 4);
153
154       /* STRUCT_C (preceded by length).. see Table 263, 264 */
155       val = 0x00000004;
156       push_input (vdec, (const guint8 *) &val, 4);
157
158       val = GST_READ_UINT32_LE (GST_BUFFER_DATA (vdec->codec_data));
159       /* FIXME: i have NO idea why asfdemux gives me something I need to patch... */
160       val |= 0x01 << 24;
161       push_input (vdec, (const guint8 *) &val, 4);
162
163       /* STRUCT_A.. see Table 260 and Annex J.2 */
164       val = vdec->height;
165       push_input (vdec, (const guint8 *) &val, 4);
166       val = vdec->width;
167       push_input (vdec, (const guint8 *) &val, 4);
168       GST_INFO_OBJECT (vdec, "seq hdr resolution: %dx%d", vdec->width,
169           vdec->height);
170
171       val = 0x0000000c;
172       push_input (vdec, (const guint8 *) &val, 4);
173
174       /* STRUCT_B.. see Table 261, 262 */
175       val = 0x00000000;         /* not sure how to populate, but codec ignores anyways */
176       push_input (vdec, (const guint8 *) &val, 4);
177       push_input (vdec, (const guint8 *) &val, 4);
178       push_input (vdec, (const guint8 *) &val, 4);
179     }
180   }
181
182   /* VC-1 Advanced profile needs start-code prepended: */
183   if (self->level == 4) {
184     static const guint8 sc[] = { 0x00, 0x00, 0x01, 0x0d };      /* start code */
185     push_input (vdec, sc, sizeof (sc));
186   }
187
188   if (params->frameLayerDataPresentFlag) {
189     val = GST_BUFFER_SIZE (buf);
190     if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
191       val |= 0x80 << 24;
192     else
193       val |= 0x00 << 24;
194     push_input (vdec, (const guint8 *) &val, 4);
195     val = GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buf) - self->first_ts);
196     push_input (vdec, (const guint8 *) &val, 4);
197   }
198
199
200   push_input (vdec, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
201   gst_buffer_unref (buf);
202
203   return NULL;
204 }
205
206 static gint
207 gst_ducati_vc1dec_handle_error (GstDucatiVidDec * self, gint ret,
208     gint extended_error, gint status_extended_error)
209 {
210   if (extended_error == 0x00409000)
211     /* the codec sets some IVC1DEC_ERR_PICHDR (corrupted picture headers) errors
212      * as fatal even though it's able to recover 
213      */
214     ret = XDM_EOK;
215   else
216     ret = parent_class->handle_error (self, ret, extended_error,
217         status_extended_error);
218
219   return ret;
220 }
221
222 static gboolean
223 gst_ducati_vc1dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
224     gint64 diff)
225 {
226   gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
227       GST_BUFFER_FLAG_B_FRAME);
228
229   if (diff >= 0 && is_bframe)
230     return TRUE;
231
232   return FALSE;
233 }
234
235 /* GstElement vmethod implementations */
236
237 static GstStateChangeReturn
238 gst_ducati_vc1dec_change_state (GstElement * element, GstStateChange transition)
239 {
240   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
241   GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (element);
242
243   GST_INFO_OBJECT (self, "begin: changing state %s -> %s",
244       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
245       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
246
247   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
248
249   if (ret == GST_STATE_CHANGE_FAILURE)
250     goto leave;
251
252   switch (transition) {
253     case GST_STATE_CHANGE_PAUSED_TO_READY:
254       self->level = -1;
255       self->first_ts = GST_CLOCK_TIME_NONE;
256       break;
257     default:
258       break;
259   }
260
261 leave:
262   GST_LOG_OBJECT (self, "end");
263
264   return ret;
265 }
266
267 /* GObject vmethod implementations */
268
269 static void
270 gst_ducati_vc1dec_base_init (gpointer gclass)
271 {
272   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
273
274   gst_element_class_set_details_simple (element_class,
275       "DucatiVC1Dec",
276       "Codec/Decoder/Video",
277       "Decodes video in WMV3/VC-1 format with ducati",
278       "Rob Clark <rob@ti.com>");
279
280   gst_element_class_add_pad_template (element_class,
281       gst_static_pad_template_get (&sink_factory));
282 }
283
284 static void
285 gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass)
286 {
287   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
288   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
289
290   gstelement_class->change_state =
291       GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_change_state);
292
293   bclass->codec_name = "ivahd_vc1vdec";
294   bclass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_parse_caps);
295   bclass->update_buffer_size =
296       GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_update_buffer_size);
297   bclass->allocate_params =
298       GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_allocate_params);
299   bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_push_input);
300   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_handle_error);
301   bclass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_can_drop_frame);
302 }
303
304 static void
305 gst_ducati_vc1dec_init (GstDucatiVC1Dec * self, GstDucatiVC1DecClass * gclass)
306 {
307   GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
308
309 #ifndef GST_DISABLE_GST_DEBUG
310   vdec->error_strings[0] = "unsupported VIDDEC3 params";
311   vdec->error_strings[1] = "unsupported dynamic VIDDEC3 params";
312   vdec->error_strings[2] = "unsupported VC1 VIDDEC3 params";
313   vdec->error_strings[3] = "bad datasync settings";
314   vdec->error_strings[4] = "no slice";
315   vdec->error_strings[5] = "corrupted slice header";
316   vdec->error_strings[6] = "corrupted MB data";
317   vdec->error_strings[7] = "unsupported VC1 feature";
318   vdec->error_strings[16] = "stream end";
319   vdec->error_strings[17] = "unsupported resolution";
320   vdec->error_strings[18] = "IVA standby";
321   vdec->error_strings[19] = "invalid mbox message";
322   vdec->error_strings[20] = "corrupted sequence header";
323   vdec->error_strings[21] = "corrupted entry point header";
324   vdec->error_strings[22] = "corrupted picture header";
325   vdec->error_strings[23] = "ref picture buffer error";
326   vdec->error_strings[24] = "no sequence header";
327   vdec->error_strings[30] = "invalid buffer descriptor";
328   vdec->error_strings[31] = "pic size change";
329 #endif
330
331   self->level = -1;
332   self->first_ts = GST_CLOCK_TIME_NONE;
333   vdec->pageMemType = XDM_MEMTYPE_RAW;
334 }