ducatividdec: add a comment about a fishy, but OK, bit of code
[glsdk/gst-plugin-ducati.git] / src / gstducatividdec.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 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
24 #include "gstducatividdec.h"
25 #include "gstducatibufferpriv.h"
27 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
28     GST_TYPE_ELEMENT);
30 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
31     GST_PAD_SRC,
32     GST_PAD_ALWAYS,
33     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV_STRIDED ("NV12", "[ 0, max ]"))
34     );
36 enum
37 {
38   PROP_0,
39   PROP_VERSION,
40 };
42 /* helper functions */
44 static void
45 engine_close (GstDucatiVidDec * self)
46 {
47   if (self->engine) {
48     Engine_close (self->engine);
49     self->engine = NULL;
50   }
52   if (self->params) {
53     dce_free (self->params);
54     self->params = NULL;
55   }
57   if (self->dynParams) {
58     dce_free (self->dynParams);
59     self->dynParams = NULL;
60   }
62   if (self->status) {
63     dce_free (self->status);
64     self->status = NULL;
65   }
67   if (self->inBufs) {
68     dce_free (self->inBufs);
69     self->inBufs = NULL;
70   }
72   if (self->outBufs) {
73     dce_free (self->outBufs);
74     self->outBufs = NULL;
75   }
77   if (self->inArgs) {
78     dce_free (self->inArgs);
79     self->inArgs = NULL;
80   }
82   if (self->outArgs) {
83     dce_free (self->outArgs);
84     self->outArgs = NULL;
85   }
87   if (self->device) {
88     dce_deinit (self->device);
89     self->device = NULL;
90   }
91 }
93 static gboolean
94 engine_open (GstDucatiVidDec * self)
95 {
96   gboolean ret;
97   int ec;
99   if (G_UNLIKELY (self->engine)) {
100     return TRUE;
101   }
103   if (self->device == NULL) {
104     self->device = dce_init ();
105     if (self->device == NULL) {
106       GST_ERROR_OBJECT (self, "dce_init() failed");
107       return FALSE;
108     }
109   }
111   GST_DEBUG_OBJECT (self, "opening engine");
113   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
114   if (G_UNLIKELY (!self->engine)) {
115     GST_ERROR_OBJECT (self, "could not create engine");
116     return FALSE;
117   }
119   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
120       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
121       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
122       sizeof (IVIDDEC3_OutArgs));
124   return ret;
127 static void
128 codec_delete (GstDucatiVidDec * self)
130   if (self->pool) {
131     gst_drm_buffer_pool_destroy (self->pool);
132     self->pool = NULL;
133   }
135   if (self->codec) {
136     VIDDEC3_delete (self->codec);
137     self->codec = NULL;
138   }
140   if (self->input_bo) {
141     omap_bo_del (self->input_bo);
142     self->input_bo = NULL;
143   }
146 static gboolean
147 codec_create (GstDucatiVidDec * self)
149   gint err;
150   const gchar *codec_name;
152   codec_delete (self);
154   if (G_UNLIKELY (!self->engine)) {
155     GST_ERROR_OBJECT (self, "no engine");
156     return FALSE;
157   }
159   /* these need to be set before VIDDEC3_create */
160   self->params->maxWidth = self->width;
161   self->params->maxHeight = self->height;
163   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
165   /* create codec: */
166   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
167   self->codec =
168       VIDDEC3_create (self->engine, (String) codec_name, self->params);
170   if (!self->codec) {
171     return FALSE;
172   }
174   err =
175       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
176       self->status);
177   if (err) {
178     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
179     return FALSE;
180   }
182   self->first_in_buffer = TRUE;
183   self->first_out_buffer = TRUE;
185   /* allocate input buffer and initialize inBufs: */
186   /* FIXME:  needed size here has nothing to do with width * height */
187   self->input_bo = omap_bo_new (self->device,
188       self->width * self->height, OMAP_BO_WC);
189   self->input = omap_bo_map (self->input_bo);
190   self->inBufs->numBufs = 1;
191   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
193   return TRUE;
196 static inline GstBuffer *
197 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
199   if (G_UNLIKELY (!self->pool)) {
200     guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
201         self->padded_width, self->padded_height);
203     GST_DEBUG_OBJECT (self, "creating bufferpool");
204     self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
205         dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
206   }
207   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
210 static GstDucatiBufferPriv *
211 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
213   GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
214   if (!priv) {
215     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
216     GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
218     /* if it isn't a dmabuf buffer that we can import, then there
219      * is nothing we can do with it:
220      */
221     if (!dmabuf) {
222       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
223       return NULL;
224     }
226     priv = gst_ducati_buffer_priv_new ();
228     priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
230     priv->uv_offset = gst_video_format_get_component_offset (format,
231         1, self->stride, self->padded_height);
232     priv->size = gst_video_format_get_size (format,
233         self->stride, self->padded_height);
235     gst_ducati_buffer_priv_set (buf, priv);
236     gst_mini_object_unref (GST_MINI_OBJECT (priv));
237   }
238   return priv;
241 static XDAS_Int32
242 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
243     gboolean force_internal)
245   GstDucatiBufferPriv *priv = NULL;
247   if (!force_internal)
248     priv = get_buffer_priv (self, *buf);
250   if (!priv) {
251     GstBuffer *orig = *buf;
253     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
254     *buf = codec_buffer_pool_get (self, NULL);
255     GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
256     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
257     gst_buffer_unref (orig);
258     return codec_prepare_outbuf (self, buf, FALSE);
259   }
261   self->outBufs->numBufs = 2;
262   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
263   self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
264   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
265   self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
266   self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
267   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
269   return (XDAS_Int32) * buf;    // XXX use lookup table
272 static GstBuffer *
273 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
275   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
276   if (buf) {
277     gst_buffer_ref (buf);
278   }
279   return buf;
282 static void
283 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
285   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
286   if (buf) {
287     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
288     gst_buffer_unref (buf);
289   }
292 static gint
293 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
294     GstFlowReturn * flow_ret)
296   gint err;
297   GstClockTime t;
298   GstBuffer *outbuf = NULL;
299   gint i;
300   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
301   GstFlowReturn ret = GST_FLOW_OK;
302   if (flow_ret)
303     /* never leave flow_ret uninitialized */
304     *flow_ret = GST_FLOW_OK;
306   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
307   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
309   t = gst_util_get_timestamp ();
310   err = VIDDEC3_process (self->codec,
311       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
312   GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
314   if (err) {
315     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
316         err, self->outArgs->extendedError);
317     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
319     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
320         self->dynParams, self->status);
321     if (err) {
322       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
323           err, self->status->extendedError);
324       gst_ducati_log_extended_error_info (self->status->extendedError);
325     }
327     if (flush)
328       err = XDM_EFAIL;
329     else
330       err = klass->handle_error (self, err,
331           self->outArgs->extendedError, self->status->extendedError);
332   }
334   /* we now let the codec decide */
335   self->dynParams->newFrameFlag = XDAS_FALSE;
337   if (err == XDM_EFAIL || self->outArgs->outBufsInUseFlag)
338     goto skip_outbuf_processing;
340   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
341     gboolean interlaced;
343     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
345     interlaced =
346         self->outArgs->decodedBufs.contentType ==
347         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
349     /* if send is FALSE, don't try to renegotiate as we could be flushing during
350      * a PAUSED->READY state change
351      */
352     if (send && interlaced != self->interlaced) {
353       GstCaps *caps;
355       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
356           "thinks interlaced=%d... trusting codec", self->interlaced,
357           interlaced);
359       self->interlaced = interlaced;
361       caps =
362           gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
363       GST_INFO_OBJECT (self, "changing interlace field in caps");
364       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
365           NULL);
366       gst_drm_buffer_pool_set_caps (self->pool, caps);
367       if (!gst_pad_set_caps (self->srcpad, caps)) {
368         GST_ERROR_OBJECT (self,
369             "downstream didn't want to change interlace mode");
370         err = XDM_EFAIL;
371       }
372       gst_caps_unref (caps);
374       /* this buffer still has the old caps so we skip it */
375       send = FALSE;
376     }
378     if (G_UNLIKELY (self->send_crop_event) && send) {
379       gint crop_width, crop_height;
380       GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
382       /* send region of interest to sink on first buffer: */
383       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
385       crop_width = r->bottomRight.x - r->topLeft.x;
386       crop_height = r->bottomRight.y - r->topLeft.y;
388       if (crop_width > self->input_width)
389         crop_width = self->input_width;
390       if (crop_height > self->input_height)
391         crop_height = self->input_height;
393       if (self->interlaced && !strcmp (klass->codec_name, "ivahd_mpeg2vdec"))
394         crop_height = crop_height / 2;
396       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
397           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
398           crop_width, crop_height);
400       gst_pad_push_event (self->srcpad,
401           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
402               crop_width, crop_height));
404       if (self->crop)
405         gst_video_crop_unref (self->crop);
407       self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
408           crop_width, crop_height);
410       self->send_crop_event = FALSE;
411     }
413     if (G_UNLIKELY (self->first_out_buffer) && send && !self->outArgs->outBufsInUseFlag) {
414       GstDRMBufferPool *pool;
415       self->first_out_buffer = FALSE;
417       /* Destroy the pool so the buffers we used so far are eventually released.
418        * The pool will be recreated if needed.
419        */
420       pool = self->pool;
421       self->pool = NULL;
422       gst_drm_buffer_pool_destroy (pool);
423     }
425     if (send && !self->outArgs->outBufsInUseFlag) {
426       GstClockTime ts;
428       ts = GST_BUFFER_TIMESTAMP (outbuf);
430       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
431           i, outbuf, GST_TIME_ARGS (ts));
433       if (self->ts_may_be_pts) {
434         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
435           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
436               "enabling ts_is_pts");
437           self->ts_is_pts = TRUE;
438         }
439       }
441       self->last_pts = ts;
443       if (self->dts_ridx != self->dts_widx) {
444         ts = self->dts_queue[self->dts_ridx++ % NDTS];
445       }
447       if (self->ts_is_pts) {
448         /* if we have a queued DTS from demuxer, use that instead: */
449         GST_BUFFER_TIMESTAMP (outbuf) = ts;
450         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
451             i, outbuf, GST_TIME_ARGS (ts));
452       }
454       if (GST_BUFFER_CAPS (outbuf) &&
455           !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
456               GST_PAD_CAPS (self->srcpad))) {
457         /* this looks a bit scary but it's really just to change the interlace=
458          * field in caps when we start as !interlaced and the codec detects
459          * otherwise */
460         GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
461             "interlace mismatch");
462         outbuf = gst_buffer_make_metadata_writable (outbuf);
463         gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
464       }
466       if (self->crop)
467         gst_buffer_set_video_crop (outbuf, self->crop);
469       ret = gst_pad_push (self->srcpad, outbuf);
470       if (flow_ret)
471         *flow_ret = ret;
472       if (ret != GST_FLOW_OK) {
473         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
474         /* just unref the remaining buffers (if any) */
475         send = FALSE;
476       }
477     } else {
478       GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
479       gst_buffer_unref (outbuf);
480     }
481   }
483 skip_outbuf_processing:
484   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
485     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
486   }
488   return err;
491 /** call control(FLUSH), and then process() to pop out all buffers */
492 gboolean
493 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
495   gint err = FALSE;
497   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
499   /* note: flush is synchronized against _chain() to avoid calling
500    * the codec from multiple threads
501    */
502   GST_PAD_STREAM_LOCK (self->sinkpad);
504   self->dts_ridx = self->dts_widx = 0;
505   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
506   self->ts_may_be_pts = TRUE;
507   self->ts_is_pts = FALSE;
508   self->wait_keyframe = TRUE;
509   self->in_size = 0;
510   self->needs_flushing = FALSE;
511   self->need_out_buf = TRUE;
513   if (G_UNLIKELY (self->first_in_buffer)) {
514     goto out;
515   }
517   if (G_UNLIKELY (!self->codec)) {
518     GST_WARNING_OBJECT (self, "no codec");
519     goto out;
520   }
522   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
523   if (err) {
524     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
525     goto out;
526   }
528   self->inBufs->descs[0].bufSize.bytes = 0;
529   self->inArgs->numBytes = 0;
530   self->inArgs->inputID = 0;
532   do {
533     err = codec_process (self, eos, TRUE, NULL);
534   } while (err != XDM_EFAIL);
536   /* reset outArgs in case we're flushing in codec_process trying to do error
537    * recovery */
538   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
539   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
541   self->dynParams->newFrameFlag = XDAS_TRUE;
543   /* on a flush, it is normal (and not an error) for the last _process() call
544    * to return an error..
545    */
546   err = XDM_EOK;
548 out:
549   GST_PAD_STREAM_UNLOCK (self->sinkpad);
550   GST_DEBUG_OBJECT (self, "done");
552   return !err;
555 /* GstDucatiVidDec vmethod default implementations */
557 static gboolean
558 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
560   const GValue *codec_data;
561   gint w, h;
563   if (gst_structure_get_int (s, "width", &self->input_width) &&
564       gst_structure_get_int (s, "height", &self->input_height)) {
566     h = ALIGN2 (self->input_height, 4); /* round up to MB */
567     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
569     /* if we've already created codec, but the resolution has changed, we
570      * need to re-create the codec:
571      */
572     if (G_UNLIKELY (self->codec)) {
573       if ((h != self->height) || (w != self->width)) {
574         codec_delete (self);
575       }
576     }
578     self->width = w;
579     self->height = h;
581     codec_data = gst_structure_get_value (s, "codec_data");
583     if (codec_data) {
584       GstBuffer *buffer = gst_value_get_buffer (codec_data);
585       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
586       self->codec_data = gst_buffer_ref (buffer);
587     }
589     return TRUE;
590   }
592   return FALSE;
595 static gboolean
596 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
597     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
600   /* allocate params: */
601   self->params = dce_alloc (params_sz);
602   if (G_UNLIKELY (!self->params)) {
603     return FALSE;
604   }
605   self->params->size = params_sz;
606   self->params->maxFrameRate = 30000;
607   self->params->maxBitRate = 10000000;
609   self->params->dataEndianness = XDM_BYTE;
610   self->params->forceChromaFormat = XDM_YUV_420SP;
611   self->params->operatingMode = IVIDEO_DECODE_ONLY;
613   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
614   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
615   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
616   self->params->numInputDataUnits = 0;
617   self->params->numOutputDataUnits = 0;
619   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
620   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
621   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
622   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
624   /* allocate dynParams: */
625   self->dynParams = dce_alloc (dynparams_sz);
626   if (G_UNLIKELY (!self->dynParams)) {
627     return FALSE;
628   }
629   self->dynParams->size = dynparams_sz;
630   self->dynParams->decodeHeader = XDM_DECODE_AU;
631   self->dynParams->displayWidth = 0;
632   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
633   self->dynParams->newFrameFlag = XDAS_TRUE;
635   /* allocate status: */
636   self->status = dce_alloc (status_sz);
637   if (G_UNLIKELY (!self->status)) {
638     return FALSE;
639   }
640   self->status->size = status_sz;
642   /* allocate inBufs/outBufs: */
643   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
644   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
645   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
646     return FALSE;
647   }
649   /* allocate inArgs/outArgs: */
650   self->inArgs = dce_alloc (inargs_sz);
651   self->outArgs = dce_alloc (outargs_sz);
652   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
653     return FALSE;
654   }
655   self->inArgs->size = inargs_sz;
656   self->outArgs->size = outargs_sz;
658   return TRUE;
661 static GstBuffer *
662 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
664   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
665     push_input (self, GST_BUFFER_DATA (self->codec_data),
666         GST_BUFFER_SIZE (self->codec_data));
667   }
669   /* just copy entire buffer */
670   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
671   gst_buffer_unref (buf);
673   return NULL;
676 static gint
677 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
678     gint extended_error, gint status_extended_error)
680   if (XDM_ISFATALERROR (extended_error))
681     ret = XDM_EFAIL;
682   else
683     ret = XDM_EOK;
685   return ret;
688 /* GstElement vmethod implementations */
690 static gboolean
691 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
693   gboolean ret = TRUE;
694   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
695   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
696   GstStructure *s;
697   GstCaps *outcaps = NULL;
698   GstStructure *out_s;
699   gint par_width, par_height;
700   gboolean par_present;
702   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
704   s = gst_caps_get_structure (caps, 0);
705   if (!klass->parse_caps (self, s)) {
706     GST_WARNING_OBJECT (self, "missing required fields");
707     ret = FALSE;
708     goto out;
709   }
711   /* update output/padded sizes */
712   klass->update_buffer_size (self);
714   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
715     self->fps_n = 0;
716     self->fps_d = 1;
717   }
718   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
719   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
720       &par_width, &par_height);
722   outcaps = gst_pad_get_allowed_caps (self->srcpad);
723   if (outcaps) {
724     outcaps = gst_caps_make_writable (outcaps);
725     gst_caps_truncate (outcaps);
726     if (gst_caps_is_empty (outcaps)) {
727       gst_caps_unref (outcaps);
728       outcaps = NULL;
729     }
730   }
732   if (!outcaps) {
733     /* note: default to non-strided for better compatibility with
734      * other gst elements that don't understand stride:
735      */
736     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
737         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
738   }
740   out_s = gst_caps_get_structure (outcaps, 0);
741   gst_structure_set (out_s,
742       "width", G_TYPE_INT, self->padded_width,
743       "height", G_TYPE_INT, self->padded_height,
744       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
745   if (par_present)
746     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
747         par_width, par_height, NULL);
749   if (self->interlaced)
750     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
752   if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
753     if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
754       self->stride = 4096;
755       gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
756     }
757   } else {
758     self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
759         0, self->padded_width);
760   }
762   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
763       self->stride, self->padded_height);
765   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
766       self->outsize, self->stride, outcaps);
768   if (!self->first_in_buffer) {
769     /* Caps changed mid stream. We flush the codec to unlock all the potentially
770      * locked buffers. This is needed for downstream sinks that provide a
771      * buffer pool and need to destroy all the outstanding buffers before they
772      * can negotiate new caps (hello v4l2sink).
773      */
774     gst_ducati_viddec_codec_flush (self, FALSE);
775   }
777   /* (re)send a crop event when caps change */
778   self->send_crop_event = TRUE;
780   ret = gst_pad_set_caps (self->srcpad, outcaps);
782   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
784 out:
785   if (outcaps)
786     gst_caps_unref (outcaps);
787   gst_object_unref (self);
789   return ret;
792 static GstCaps *
793 gst_ducati_viddec_src_getcaps (GstPad * pad)
795   GstCaps *caps = NULL;
796   GstCaps *outcaps = NULL;
797   int i;
799   caps = GST_PAD_CAPS (pad);
800   if (caps == NULL) {
801     outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
802     return outcaps;
803   }
805   outcaps = gst_caps_new_empty ();
807   /* allow -rowstrided and regular yuv */
808   for (i = 0; i < gst_caps_get_size (caps); i++) {
809     GstStructure *structure;
810     GstStructure *modified_structure;
811     GValue value = { 0 };
813     structure = gst_caps_get_structure (caps, i);
814     gst_caps_append_structure (outcaps, gst_structure_copy (structure));
815     modified_structure = gst_structure_copy (structure);
817     if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
818       gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
819       g_value_init (&value, GST_TYPE_INT_RANGE);
820       gst_value_set_int_range (&value, 0, G_MAXINT);
821       gst_structure_set_value (modified_structure, "rowstride", &value);
822       gst_caps_append_structure (outcaps, modified_structure);
823       g_value_unset (&value);
824     } else {
825       gst_structure_set_name (modified_structure, "video/x-raw-yuv");
826       gst_structure_remove_field (modified_structure, "rowstride");
827       gst_caps_append_structure (outcaps, modified_structure);
828     }
829   }
830   return outcaps;
833 static gboolean
834 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
835     GstQuery * query, gboolean * forward)
837   gboolean res = TRUE;
839   switch (GST_QUERY_TYPE (query)) {
840     case GST_QUERY_BUFFERS:
841       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
842       gst_query_set_buffers_count (query, self->min_buffers);
844       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
845           self->padded_width, self->padded_height);
846       gst_query_set_buffers_dimensions (query,
847           self->padded_width, self->padded_height);
848       *forward = FALSE;
849       break;
850     default:
851       break;
852   }
855   return res;
858 static gboolean
859 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
861   gboolean res = TRUE, forward = TRUE;
862   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
863   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
865   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
866   res = klass->query (self, pad, query, &forward);
867   if (res && forward)
868     res = gst_pad_query_default (pad, query);
870   return res;
873 static gboolean
874 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
876   GstClockTime timestamp, qostime;
877   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
878   gint64 diff;
880   if (self->wait_keyframe) {
881     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
882       GST_INFO_OBJECT (self, "skipping until the next keyframe");
883       return FALSE;
884     }
886     self->wait_keyframe = FALSE;
887   }
889   timestamp = GST_BUFFER_TIMESTAMP (buf);
890   if (self->segment.format != GST_FORMAT_TIME ||
891       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
892     goto no_qos;
894   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
895     goto no_qos;
897   qostime = gst_segment_to_running_time (&self->segment,
898       GST_FORMAT_TIME, timestamp);
899   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
900     /* out of segment */
901     goto no_qos;
903   /* see how our next timestamp relates to the latest qos timestamp. negative
904    * values mean we are early, positive values mean we are too late. */
905   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
907   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
908       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
909       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
910       self->qos_proportion);
912   if (klass->drop_frame (self, buf, diff)) {
913     GST_INFO_OBJECT (self, "dropping frame");
914     return FALSE;
915   }
917 no_qos:
918   return TRUE;
921 static gboolean
922 gst_ducati_viddec_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
923     gint64 diff)
925   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
926       GST_BUFFER_FLAG_DELTA_UNIT);
928   if (diff >= 0 && !is_keyframe)
929     return TRUE;
931   return FALSE;
934 static GstFlowReturn
935 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
937   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
938   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
939   GstFlowReturn ret = GST_FLOW_OK;
940   Int32 err;
941   GstBuffer *outbuf = NULL;
942   GstCaps *outcaps = NULL;
943   gboolean decode;
945   if (G_UNLIKELY (!self->engine)) {
946     GST_ERROR_OBJECT (self, "no engine");
947     gst_buffer_unref (buf);
948     return GST_FLOW_ERROR;
949   }
951   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
952       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
954   decode = gst_ducati_viddec_do_qos (self, buf);
955   if (!decode) {
956     gst_buffer_unref (buf);
957     return GST_FLOW_OK;
958   }
960   if (!self->need_out_buf)
961     goto have_out_buf;
963   /* do this before creating codec to ensure reverse caps negotiation
964    * happens first:
965    */
966 allocate_buffer:
967   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
968       GST_PAD_CAPS (self->srcpad), &outbuf);
969   if (ret != GST_FLOW_OK) {
970     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
971         gst_flow_get_name (ret));
972     gst_buffer_unref (buf);
973     return ret;
974   }
976   outcaps = GST_BUFFER_CAPS (outbuf);
977   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
978     GstStructure *s;
980     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
981         GST_BUFFER_SIZE (outbuf));
983     s = gst_caps_get_structure (outcaps, 0);
984     gst_structure_get_int (s, "rowstride", &self->stride);
985     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
986         self->stride, self->padded_height);
988     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
989         self->outsize, self->stride, outcaps);
991     gst_pad_set_caps (self->srcpad, outcaps);
993     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
994       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
995           GST_BUFFER_SIZE (outbuf), self->outsize);
996       gst_buffer_unref (outbuf);
997       goto allocate_buffer;
998     }
999   }
1001   if (G_UNLIKELY (!self->codec)) {
1002     if (!codec_create (self)) {
1003       GST_ERROR_OBJECT (self, "could not create codec");
1004       gst_buffer_unref (buf);
1005       gst_buffer_unref (outbuf);
1006       return GST_FLOW_ERROR;
1007     }
1008   }
1010   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1011   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1013   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1014    * internal pool while self->first_out_buffer == TRUE in order to simplify
1015    * things in case we need to renegotiate */
1016   self->inArgs->inputID =
1017       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1018   if (!self->inArgs->inputID) {
1019     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1020     gst_buffer_unref (buf);
1021     return GST_FLOW_ERROR;
1022   }
1024 have_out_buf:
1025   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1027   if (ts != GST_CLOCK_TIME_NONE) {
1028     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1029     /* if next buffer has earlier ts than previous, then the ts
1030      * we are getting are definitely decode order (DTS):
1031      */
1032     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1033       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1034       self->ts_may_be_pts = FALSE;
1035     }
1036     self->last_dts = ts;
1037   }
1039   if (self->in_size == 0 && outbuf) {
1040     GST_DEBUG_OBJECT (self, "no input, skipping process");
1041     gst_buffer_unref (outbuf);
1042     return GST_FLOW_OK;
1043   }
1045   self->inArgs->numBytes = self->in_size;
1046   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1047   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1049   err = codec_process (self, TRUE, FALSE, &ret);
1050   if (err) {
1051     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1052         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1053     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1054     return GST_FLOW_ERROR;
1055   }
1056   if (ret != GST_FLOW_OK) {
1057     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1058         gst_flow_get_name (ret));
1059     return ret;
1060   }
1062   self->first_in_buffer = FALSE;
1064   /* The copy could be avoided by playing with the buffer pointer,
1065      but it seems to be rare and for not many bytes */
1066   GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1067       self->outArgs->bytesConsumed, self->in_size,
1068       self->inArgs->numBytes,
1069       self->in_size - self->outArgs->bytesConsumed);
1070   if (self->outArgs->bytesConsumed > 0) {
1071     if (self->outArgs->bytesConsumed > self->in_size) {
1072       GST_WARNING_OBJECT (self, "Codec claims to have used more bytes than supplied");
1073       self->in_size = 0;
1074     } else {
1075       if (self->outArgs->bytesConsumed < self->in_size) {
1076         GST_DEBUG_OBJECT (self, "First 16 were:");
1077         gst_util_dump_mem (self->input, 16);
1078         memmove (self->input, self->input + self->outArgs->bytesConsumed,
1079             self->in_size - self->outArgs->bytesConsumed);
1080       }
1081       self->in_size -= self->outArgs->bytesConsumed;
1082     }
1083   }
1085   if (self->outArgs->outBufsInUseFlag) {
1086     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1087     self->need_out_buf = FALSE;
1088   } else {
1089     self->need_out_buf = TRUE;
1090   }
1092   if (buf) {
1093     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1094         GST_BUFFER_SIZE (buf));
1095     ts = GST_BUFFER_TIMESTAMP (buf);
1096     goto allocate_buffer;
1097   }
1099   if (self->needs_flushing)
1100     gst_ducati_viddec_codec_flush (self, FALSE);
1102   return GST_FLOW_OK;
1105 static gboolean
1106 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1108   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1109   gboolean ret = TRUE;
1111   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1113   switch (GST_EVENT_TYPE (event)) {
1114     case GST_EVENT_NEWSEGMENT:
1115     {
1116       gboolean update;
1117       GstFormat fmt;
1118       gint64 start, stop, time;
1119       gdouble rate, arate;
1121       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1122           &start, &stop, &time);
1123       gst_segment_set_newsegment_full (&self->segment, update,
1124           rate, arate, fmt, start, stop, time);
1125       break;
1126     }
1127     case GST_EVENT_EOS:
1128       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1129         GST_ERROR_OBJECT (self, "could not flush on eos");
1130         ret = FALSE;
1131       }
1132       break;
1133     case GST_EVENT_FLUSH_STOP:
1134       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1135         GST_ERROR_OBJECT (self, "could not flush");
1136         gst_event_unref (event);
1137         ret = FALSE;
1138       }
1139       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1140       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1141       self->qos_proportion = 1;
1142       self->need_out_buf = TRUE;
1143       break;
1144     default:
1145       break;
1146   }
1148   if (ret)
1149     ret = gst_pad_push_event (self->srcpad, event);
1150   GST_LOG_OBJECT (self, "end");
1152   return ret;
1155 static gboolean
1156 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1158   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1159   gboolean ret = TRUE;
1161   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1163   switch (GST_EVENT_TYPE (event)) {
1164     case GST_EVENT_QOS:
1165     {
1166       gdouble proportion;
1167       GstClockTimeDiff diff;
1168       GstClockTime timestamp;
1170       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1172       GST_OBJECT_LOCK (self);
1173       self->qos_proportion = proportion;
1174       self->qos_earliest_time = timestamp + 2 * diff;
1175       GST_OBJECT_UNLOCK (self);
1177       GST_DEBUG_OBJECT (self,
1178           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1179           proportion, GST_TIME_ARGS (timestamp), diff);
1181       ret = gst_pad_push_event (self->sinkpad, event);
1182       break;
1183     }
1184     default:
1185       ret = gst_pad_push_event (self->sinkpad, event);
1186       break;
1187   }
1189   GST_LOG_OBJECT (self, "end");
1191   return ret;
1194 static GstStateChangeReturn
1195 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1197   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1198   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1199   gboolean supported;
1201   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1202       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1203       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1205   switch (transition) {
1206     case GST_STATE_CHANGE_NULL_TO_READY:
1207       if (!engine_open (self)) {
1208         GST_ERROR_OBJECT (self, "could not open");
1209         return GST_STATE_CHANGE_FAILURE;
1210       }
1211       /* try to create/destroy the codec here, it may not be supported */
1212       supported = codec_create (self);
1213       codec_delete (self);
1214       self->codec = NULL;
1215       if (!supported) {
1216         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1217             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1218         engine_close (self);
1219         return GST_STATE_CHANGE_FAILURE;
1220       }
1221       break;
1222     default:
1223       break;
1224   }
1226   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1228   if (ret == GST_STATE_CHANGE_FAILURE)
1229     goto leave;
1231   switch (transition) {
1232     case GST_STATE_CHANGE_PAUSED_TO_READY:
1233       self->interlaced = FALSE;
1234       self->send_crop_event = TRUE;
1235       gst_ducati_viddec_codec_flush (self, FALSE);
1236       break;
1237     case GST_STATE_CHANGE_READY_TO_NULL:
1238       codec_delete (self);
1239       engine_close (self);
1240       break;
1241     default:
1242       break;
1243   }
1245 leave:
1246   GST_LOG_OBJECT (self, "end");
1248   return ret;
1251 /* GObject vmethod implementations */
1253 #define VERSION_LENGTH 256
1255 static void
1256 gst_ducati_viddec_get_property (GObject * obj,
1257     guint prop_id, GValue * value, GParamSpec * pspec)
1259   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1262   switch (prop_id) {
1263     case PROP_VERSION:{
1264       int err;
1265       char *version = NULL;
1267       if (!self->engine)
1268         engine_open (self);
1270       if (!self->codec)
1271         codec_create (self);
1273       if (self->codec) {
1274         version = dce_alloc (VERSION_LENGTH);
1275         self->status->data.buf = (XDAS_Int8 *) version;
1276         self->status->data.bufSize = VERSION_LENGTH;
1278         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1279             self->dynParams, self->status);
1280         if (err) {
1281           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1282         }
1284         self->status->data.buf = NULL;
1285         self->status->data.bufSize = 0;
1286       }
1288       g_value_set_string (value, version);
1289       if (version)
1290         dce_free (version);
1292       break;
1293     }
1294     default:{
1295       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1296       break;
1297     }
1298   }
1301 static void
1302 gst_ducati_viddec_finalize (GObject * obj)
1304   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1306   codec_delete (self);
1307   engine_close (self);
1309   if (self->codec_data) {
1310     gst_buffer_unref (self->codec_data);
1311     self->codec_data = NULL;
1312   }
1314   G_OBJECT_CLASS (parent_class)->finalize (obj);
1317 static void
1318 gst_ducati_viddec_base_init (gpointer gclass)
1320   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1322   gst_element_class_add_pad_template (element_class,
1323       gst_static_pad_template_get (&src_factory));
1326 static void
1327 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1329   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1330   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1332   gobject_class->get_property =
1333       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1334   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1335   gstelement_class->change_state =
1336       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1338   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1339   klass->allocate_params =
1340       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1341   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1342   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1343   klass->drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_drop_frame);
1344   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1346   g_object_class_install_property (gobject_class, PROP_VERSION,
1347       g_param_spec_string ("version", "Version",
1348           "The codec version string", "",
1349           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1352 static void
1353 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1355   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1357   self->sinkpad =
1358       gst_pad_new_from_template (gst_element_class_get_pad_template
1359       (gstelement_class, "sink"), "sink");
1360   gst_pad_set_setcaps_function (self->sinkpad,
1361       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1362   gst_pad_set_chain_function (self->sinkpad,
1363       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1364   gst_pad_set_event_function (self->sinkpad,
1365       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1367   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1368   gst_pad_set_event_function (self->srcpad,
1369       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1370   gst_pad_set_query_function (self->srcpad,
1371       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1372   gst_pad_set_getcaps_function (self->srcpad,
1373       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1375   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1376   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1378   self->input_width = 0;
1379   self->input_height = 0;
1380   /* sane defaults in case we need to create codec without caps negotiation
1381    * (for example, to get 'version' property)
1382    */
1383   self->width = 128;
1384   self->height = 128;
1385   self->fps_n = -1;
1386   self->fps_d = -1;
1388   self->first_in_buffer = TRUE;
1389   self->first_out_buffer = TRUE;
1390   self->interlaced = FALSE;
1391   self->send_crop_event = TRUE;
1393   self->dts_ridx = self->dts_widx = 0;
1394   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1395   self->ts_may_be_pts = TRUE;
1396   self->ts_is_pts = FALSE;
1398   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1400   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1402   self->qos_proportion = 1;
1403   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1404   self->wait_keyframe = TRUE;
1406   self->need_out_buf = TRUE;
1407   self->device = NULL;
1408   self->input_bo = NULL;