Realigned code on new Ducati header files
[glsdk/gst-plugin-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  */
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)
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;
128 static GstBuffer *
129 gst_ducati_vc1dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
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;
219 static gint
220 gst_ducati_vc1dec_handle_error (GstDucatiVidDec * self, gint ret,
221     gint extended_error, gint status_extended_error)
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;
235 static gboolean
236 gst_ducati_vc1dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
237     gint64 diff)
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;
248 /* GstElement vmethod implementations */
250 static GstStateChangeReturn
251 gst_ducati_vc1dec_change_state (GstElement * element, GstStateChange transition)
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;
280 /* GObject vmethod implementations */
282 static void
283 gst_ducati_vc1dec_base_init (gpointer gclass)
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));
297 static void
298 gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass)
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);
317 static void
318 gst_ducati_vc1dec_init (GstDucatiVC1Dec * self, GstDucatiVC1DecClass * gclass)
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;