]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducativc1dec.c
viddec: Drop frames if out of segment
[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 static void gst_ducati_vc1dec_base_init (gpointer gclass);
46 static void gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass);
47 static void gst_ducati_vc1dec_init (GstDucatiVC1Dec * self, gpointer klass);
49 static GstDucatiVidDecClass *parent_class = NULL;
51 GType
52 gst_ducati_vc1dec_get_type (void)
53 {
54   static GType ducati_vc1dec_type = 0;
56   if (!ducati_vc1dec_type) {
57     static const GTypeInfo ducati_vc1dec_info = {
58       sizeof (GstDucatiVC1DecClass),
59       (GBaseInitFunc) gst_ducati_vc1dec_base_init,
60       NULL,
61       (GClassInitFunc) gst_ducati_vc1dec_class_init,
62       NULL,
63       NULL,
64       sizeof (GstDucatiVC1Dec),
65       0,
66       (GInstanceInitFunc) gst_ducati_vc1dec_init,
67     };
69     ducati_vc1dec_type = g_type_register_static (GST_TYPE_DUCATIVIDDEC,
70         "GstDucatiVC1Dec", &ducati_vc1dec_info, 0);
71   }
72   return ducati_vc1dec_type;
73 }
75 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
76     GST_PAD_SINK,
77     GST_PAD_ALWAYS,
78     GST_STATIC_CAPS ("video/x-wmv, "
79         "wmvversion = (int) 3, "
80         "format = (string){ WVC1, WMV3 }, "
81         "width = (int)[ 16, 2048 ], "
82         "height = (int)[ 16, 2048 ], " "framerate = (fraction)[ 0, max ];")
83     );
85 /* GstDucatiVidDec vmethod implementations */
87 static gboolean
88 gst_ducati_vc1dec_parse_caps (GstDucatiVidDec * vdec, GstStructure * s)
89 {
90   GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
92   if (GST_DUCATIVIDDEC_CLASS (parent_class)->parse_caps (vdec, s)) {
93     gchar *format;
94     gboolean ret = FALSE;
95     format = gst_structure_get_string (s, "format");
96     if (format) {
97       if (strcmp (format, "WVC1") == 0) {
99         ret = TRUE;
100         self->level = 4;
101         return ret;
102       }
104       if (strcmp (format, "WMV3") == 0) {
105         ret = TRUE;
106         self->level = 3;
107         return ret;
109       }
110     }
111     GST_INFO_OBJECT (vdec, "level %d", self->level);
112   }
114   return FALSE;
117 static void
118 gst_ducati_vc1dec_update_buffer_size (GstDucatiVidDec * self)
120   gint w = self->width;
121   gint h = self->height;
123   /* calculate output buffer parameters: */
124   self->padded_width = ALIGN2 (w + (2 * PADX), 7);
125   self->padded_height = (ALIGN2 (h / 2, 4) * 2) + 4 * PADY;
126   self->min_buffers = 8;
129 static gboolean
130 gst_ducati_vc1dec_allocate_params (GstDucatiVidDec * self, gint params_sz,
131     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
133   gboolean ret = GST_DUCATIVIDDEC_CLASS (parent_class)->allocate_params (self,
134       sizeof (IVC1VDEC_Params), sizeof (IVC1VDEC_DynamicParams),
135       sizeof (IVC1VDEC_Status), sizeof (IVC1VDEC_InArgs),
136       sizeof (IVC1VDEC_OutArgs));
138   if (ret) {
139     IVC1VDEC_Params *params = (IVC1VDEC_Params *) self->params;
140     self->params->maxBitRate = 45000000;
141     self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
143     /* this indicates whether buffers are prefixed with the frame layer struct
144      * or not.  See Table 266: Frame Layer Data Structure from the spec */
145     params->frameLayerDataPresentFlag = FALSE;
147     /* enable concealment */
148     params->errorConcealmentON = 1;
150     /* codec wants lateAcquireArg = -1 */
151     self->dynParams->lateAcquireArg = -1;
152   }
154   return ret;
157 static GstBuffer *
158 gst_ducati_vc1dec_push_input (GstDucatiVidDec * vdec, GstBuffer * buf)
160   GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (vdec);
161   IVC1VDEC_Params *params = (IVC1VDEC_Params *) vdec->params;
162   guint32 val;
163   GstMapInfo info;
164   gboolean mapped;
166   /* need a base ts for frame layer timestamps */
167   if (self->first_ts == GST_CLOCK_TIME_NONE)
168     self->first_ts = GST_BUFFER_PTS (buf);
170   if (G_UNLIKELY (vdec->first_in_buffer) && vdec->codecdata) {
171     if (vdec->codecdatasize > 0) {
172       /* There is at least one VC1 stream that claims it is simple profile,
173          but goes on to have frames that use some feature that is unavailable
174          in simple profile(intensity compensation). Since ducati supports
175          both, we frob the header to claim all simple profile videos are
176          main profile. This is a lie, but it should not cause any trouble
177          (I'm sure all liars must say that). */
179       if (!(vdec->codecdata[0] & 192))
180         vdec->codecdata[0] |= 64;
181     }
183     if (self->level == 4) {
184       /* for VC-1 Advanced Profile, strip off first byte, and
185        * send rest of codec_data unmodified;
186        */
187       push_input (vdec, vdec->codecdata + 1, vdec->codecdatasize - 1);
188     } else {
189       /* for VC-1 Simple and Main Profile, build the Table 265 Sequence
190        * Layer Data Structure header (refer to VC-1 spec, Annex L):
191        */
192       val = 0xc5ffffff;         /* we don't know the number of frames */
193       push_input (vdec, (const guint8 *) &val, 4);
195       /* STRUCT_C (preceded by length).. see Table 263, 264 */
196       val = 0x00000004;
197       push_input (vdec, (const guint8 *) &val, 4);
199       val = GST_READ_UINT32_LE (vdec->codecdata);
200       /* FIXME: i have NO idea why asfdemux gives me something I need to patch... */
201       val |= 0x01 << 24;
202       push_input (vdec, (const guint8 *) &val, 4);
203       /* STRUCT_A.. see Table 260 and Annex J.2 */
204       val = vdec->height;
205       push_input (vdec, (const guint8 *) &val, 4);
206       val = vdec->width;
207       push_input (vdec, (const guint8 *) &val, 4);
208       GST_INFO_OBJECT (vdec, "seq hdr resolution: %dx%d", vdec->width,
209           vdec->height);
211       val = 0x0000000c;
212       push_input (vdec, (const guint8 *) &val, 4);
214       /* STRUCT_B.. see Table 261, 262 */
215       val = 0x00000000;         /* not sure how to populate, but codec ignores anyways */
216       push_input (vdec, (const guint8 *) &val, 4);
217       push_input (vdec, (const guint8 *) &val, 4);
218       push_input (vdec, (const guint8 *) &val, 4);
219     }
220   }
222   /* VC-1 Advanced profile needs start-code prepended: */
223   if (self->level == 4) {
224     static const guint8 sc[] = { 0x00, 0x00, 0x01, 0x0d };      /* start code */
225     push_input (vdec, sc, sizeof (sc));
226   }
228   if (params->frameLayerDataPresentFlag) {
229     val = gst_buffer_get_sizes (buf, NULL, NULL);
230     if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT))
231       val |= 0x80 << 24;
232     else
233       val |= 0x00 << 24;
234     push_input (vdec, (const guint8 *) &val, 4);
235     val = GST_TIME_AS_MSECONDS (GST_BUFFER_PTS (buf) - self->first_ts);
236     push_input (vdec, (const guint8 *) &val, 4);
237   }
239   mapped = gst_buffer_map (buf, &info, GST_MAP_READ);
240   if (mapped) {
241     push_input (vdec, info.data, info.size);
242     gst_buffer_unmap (buf, &info);
243   }
244   gst_buffer_unref (buf);
246   return NULL;
249 static gint
250 gst_ducati_vc1dec_handle_error (GstDucatiVidDec * self, gint ret,
251     gint extended_error, gint status_extended_error)
253   if (extended_error == 0x00409000)
254     /* the codec sets some IVC1DEC_ERR_PICHDR (corrupted picture headers) errors
255      * as fatal even though it's able to recover 
256      */
257     ret = XDM_EOK;
258   else
259     ret =
260         GST_DUCATIVIDDEC_CLASS (parent_class)->handle_error (self, ret,
261         extended_error, status_extended_error);
263   return ret;
266 static gboolean
267 gst_ducati_vc1dec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
268     gint64 diff)
270   gboolean is_bframe = GST_BUFFER_FLAG_IS_SET (buf,
271       GST_BUFFER_FLAG_B_FRAME);
273   if (diff >= 0 && is_bframe)
274     return TRUE;
276   return FALSE;
279 /* GstElement vmethod implementations */
281 static GstStateChangeReturn
282 gst_ducati_vc1dec_change_state (GstElement * element, GstStateChange transition)
284   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
285   GstDucatiVC1Dec *self = GST_DUCATIVC1DEC (element);
287   GST_INFO_OBJECT (self, "begin: changing state %s -> %s",
288       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
289       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
291   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
293   if (ret == GST_STATE_CHANGE_FAILURE)
294     goto leave;
296   switch (transition) {
297     case GST_STATE_CHANGE_PAUSED_TO_READY:
298       self->level = -1;
299       self->first_ts = GST_CLOCK_TIME_NONE;
300       break;
301     default:
302       break;
303   }
305 leave:
306   GST_LOG_OBJECT (self, "end");
308   return ret;
311 /* GObject vmethod implementations */
313 static void
314 gst_ducati_vc1dec_base_init (gpointer gclass)
316   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
318   gst_element_class_set_static_metadata (element_class,
319       "DucatiVC1Dec",
320       "Codec/Decoder/Video",
321       "Decodes video in WMV3/VC-1 format with ducati",
322       "Rob Clark <rob@ti.com>");
324   gst_element_class_add_pad_template (element_class,
325       gst_static_pad_template_get (&sink_factory));
328 static void
329 gst_ducati_vc1dec_class_init (GstDucatiVC1DecClass * klass)
331   GstDucatiVidDecClass *bclass = GST_DUCATIVIDDEC_CLASS (klass);
332   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
333   parent_class = g_type_class_peek_parent (klass);
335   gstelement_class->change_state =
336       GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_change_state);
338   bclass->codec_name = "ivahd_vc1vdec";
339   bclass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_parse_caps);
340   bclass->update_buffer_size =
341       GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_update_buffer_size);
342   bclass->allocate_params =
343       GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_allocate_params);
344   bclass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_push_input);
345   bclass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_handle_error);
346   bclass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_vc1dec_can_drop_frame);
349 static void
350 gst_ducati_vc1dec_init (GstDucatiVC1Dec * self, gpointer gclass)
352   GstDucatiVidDec *vdec = GST_DUCATIVIDDEC (self);
354 #ifndef GST_DISABLE_GST_DEBUG
355   vdec->error_strings[0] = "unsupported VIDDEC3 params";
356   vdec->error_strings[1] = "unsupported dynamic VIDDEC3 params";
357   vdec->error_strings[2] = "unsupported VC1 VIDDEC3 params";
358   vdec->error_strings[3] = "bad datasync settings";
359   vdec->error_strings[4] = "no slice";
360   vdec->error_strings[5] = "corrupted slice header";
361   vdec->error_strings[6] = "corrupted MB data";
362   vdec->error_strings[7] = "unsupported VC1 feature";
363   vdec->error_strings[16] = "stream end";
364   vdec->error_strings[17] = "unsupported resolution";
365   vdec->error_strings[18] = "IVA standby";
366   vdec->error_strings[19] = "invalid mbox message";
367   vdec->error_strings[20] = "corrupted sequence header";
368   vdec->error_strings[21] = "corrupted entry point header";
369   vdec->error_strings[22] = "corrupted picture header";
370   vdec->error_strings[23] = "ref picture buffer error";
371   vdec->error_strings[24] = "no sequence header";
372   vdec->error_strings[30] = "invalid buffer descriptor";
373   vdec->error_strings[31] = "pic size change";
374 #endif
376   self->level = -1;
377   self->first_ts = GST_CLOCK_TIME_NONE;
378   vdec->pageMemType = XDM_MEMTYPE_RAW;