ducatividdec: only heed bytesConsumed when not in entire frame mode
[glsdk/gst-plugin-ducati.git] / src / gstducatividdec.c
1 #define USE_DTS_PTS_CODE
2 /*
3  * GStreamer
4  * Copyright (c) 2010, Texas Instruments Incorporated
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
25 #include "gstducatividdec.h"
26 #include "gstducatibufferpriv.h"
28 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
29     GST_TYPE_ELEMENT);
31 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
32     GST_PAD_SRC,
33     GST_PAD_ALWAYS,
34     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV_STRIDED ("NV12", "[ 0, max ]"))
35     );
37 enum
38 {
39   PROP_0,
40   PROP_VERSION,
41 };
43 /* helper functions */
45 static void
46 engine_close (GstDucatiVidDec * self)
47 {
48   if (self->engine) {
49     Engine_close (self->engine);
50     self->engine = NULL;
51   }
53   if (self->params) {
54     dce_free (self->params);
55     self->params = NULL;
56   }
58   if (self->dynParams) {
59     dce_free (self->dynParams);
60     self->dynParams = NULL;
61   }
63   if (self->status) {
64     dce_free (self->status);
65     self->status = NULL;
66   }
68   if (self->inBufs) {
69     dce_free (self->inBufs);
70     self->inBufs = NULL;
71   }
73   if (self->outBufs) {
74     dce_free (self->outBufs);
75     self->outBufs = NULL;
76   }
78   if (self->inArgs) {
79     dce_free (self->inArgs);
80     self->inArgs = NULL;
81   }
83   if (self->outArgs) {
84     dce_free (self->outArgs);
85     self->outArgs = NULL;
86   }
88   if (self->device) {
89     dce_deinit (self->device);
90     self->device = NULL;
91   }
92 }
94 static gboolean
95 engine_open (GstDucatiVidDec * self)
96 {
97   gboolean ret;
98   int ec;
100   if (G_UNLIKELY (self->engine)) {
101     return TRUE;
102   }
104   if (self->device == NULL) {
105     self->device = dce_init ();
106     if (self->device == NULL) {
107       GST_ERROR_OBJECT (self, "dce_init() failed");
108       return FALSE;
109     }
110   }
112   GST_DEBUG_OBJECT (self, "opening engine");
114   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
115   if (G_UNLIKELY (!self->engine)) {
116     GST_ERROR_OBJECT (self, "could not create engine");
117     return FALSE;
118   }
120   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
121       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
122       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
123       sizeof (IVIDDEC3_OutArgs));
125   return ret;
128 static void
129 codec_delete (GstDucatiVidDec * self)
131   if (self->pool) {
132     gst_drm_buffer_pool_destroy (self->pool);
133     self->pool = NULL;
134   }
136   if (self->codec) {
137     VIDDEC3_delete (self->codec);
138     self->codec = NULL;
139   }
141   if (self->input_bo) {
142     omap_bo_del (self->input_bo);
143     self->input_bo = NULL;
144   }
147 static gboolean
148 codec_create (GstDucatiVidDec * self)
150   gint err;
151   const gchar *codec_name;
153   codec_delete (self);
155   if (G_UNLIKELY (!self->engine)) {
156     GST_ERROR_OBJECT (self, "no engine");
157     return FALSE;
158   }
160   /* these need to be set before VIDDEC3_create */
161   self->params->maxWidth = self->width;
162   self->params->maxHeight = self->height;
164   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
166   /* create codec: */
167   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
168   self->codec =
169       VIDDEC3_create (self->engine, (String) codec_name, self->params);
171   if (!self->codec) {
172     return FALSE;
173   }
175   err =
176       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
177       self->status);
178   if (err) {
179     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
180     return FALSE;
181   }
183   self->first_in_buffer = TRUE;
184   self->first_out_buffer = TRUE;
186   /* allocate input buffer and initialize inBufs: */
187   /* FIXME:  needed size here has nothing to do with width * height */
188   self->input_bo = omap_bo_new (self->device,
189       self->width * self->height, OMAP_BO_WC);
190   self->input = omap_bo_map (self->input_bo);
191   self->inBufs->numBufs = 1;
192   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
194   return TRUE;
197 static inline GstBuffer *
198 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
200   if (G_UNLIKELY (!self->pool)) {
201     guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
202         self->padded_width, self->padded_height);
204     GST_DEBUG_OBJECT (self, "creating bufferpool");
205     self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
206         dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
207   }
208   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
211 static GstDucatiBufferPriv *
212 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
214   GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
215   if (!priv) {
216     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
217     GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
219     /* if it isn't a dmabuf buffer that we can import, then there
220      * is nothing we can do with it:
221      */
222     if (!dmabuf) {
223       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
224       return NULL;
225     }
227     priv = gst_ducati_buffer_priv_new ();
229     priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
231     priv->uv_offset = gst_video_format_get_component_offset (format,
232         1, self->stride, self->padded_height);
233     priv->size = gst_video_format_get_size (format,
234         self->stride, self->padded_height);
236     gst_ducati_buffer_priv_set (buf, priv);
237     gst_mini_object_unref (GST_MINI_OBJECT (priv));
238   }
239   return priv;
242 static XDAS_Int32
243 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
244     gboolean force_internal)
246   GstDucatiBufferPriv *priv = NULL;
248   if (!force_internal)
249     priv = get_buffer_priv (self, *buf);
251   if (!priv) {
252     GstBuffer *orig = *buf;
254     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
255     *buf = codec_buffer_pool_get (self, NULL);
256     GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
257     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
258     gst_buffer_unref (orig);
259     return codec_prepare_outbuf (self, buf, FALSE);
260   }
262   self->outBufs->numBufs = 2;
263   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
264   self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
265   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
266   self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
267   self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
268   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
270   return (XDAS_Int32) * buf;    // XXX use lookup table
273 static GstBuffer *
274 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
276   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
277   if (buf) {
278     gst_buffer_ref (buf);
279   }
280   return buf;
283 static void
284 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
286   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
287   if (buf) {
288     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
289     gst_buffer_unref (buf);
290   }
293 static void
294 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
298 static gint
299 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
300     GstFlowReturn * flow_ret)
302   gint err;
303   GstClockTime t;
304   GstBuffer *outbuf = NULL;
305   gint i;
306   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
307   GstFlowReturn ret = GST_FLOW_OK;
308   if (flow_ret)
309     /* never leave flow_ret uninitialized */
310     *flow_ret = GST_FLOW_OK;
312   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
313   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
315   t = gst_util_get_timestamp ();
316   err = VIDDEC3_process (self->codec,
317       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
318   GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
320   if (err) {
321     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
322         err, self->outArgs->extendedError);
323     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
325     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
326         self->dynParams, self->status);
327     if (err) {
328       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
329           err, self->status->extendedError);
330       gst_ducati_log_extended_error_info (self->status->extendedError);
331     }
333     if (flush)
334       err = XDM_EFAIL;
335     else
336       err = klass->handle_error (self, err,
337           self->outArgs->extendedError, self->status->extendedError);
338   }
340   /* we now let the codec decide */
341   self->dynParams->newFrameFlag = XDAS_FALSE;
343   if (err == XDM_EFAIL)
344     goto skip_outbuf_processing;
346   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
347     gboolean interlaced;
349     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
351     interlaced =
352         self->outArgs->decodedBufs.contentType ==
353         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
355     /* if send is FALSE, don't try to renegotiate as we could be flushing during
356      * a PAUSED->READY state change
357      */
358     if (send && interlaced != self->interlaced) {
359       GstCaps *caps;
361       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
362           "thinks interlaced=%d... trusting codec", self->interlaced,
363           interlaced);
365       self->interlaced = interlaced;
367       caps =
368           gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
369       GST_INFO_OBJECT (self, "changing interlace field in caps");
370       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
371           NULL);
372       gst_drm_buffer_pool_set_caps (self->pool, caps);
373       if (!gst_pad_set_caps (self->srcpad, caps)) {
374         GST_ERROR_OBJECT (self,
375             "downstream didn't want to change interlace mode");
376         err = XDM_EFAIL;
377       }
378       gst_caps_unref (caps);
380       /* this buffer still has the old caps so we skip it */
381       send = FALSE;
382     }
384     if (G_UNLIKELY (self->send_crop_event) && send) {
385       gint crop_width, crop_height;
386       GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
388       /* send region of interest to sink on first buffer: */
389       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
391       crop_width = r->bottomRight.x - r->topLeft.x;
392       crop_height = r->bottomRight.y - r->topLeft.y;
394       if (crop_width > self->input_width)
395         crop_width = self->input_width;
396       if (crop_height > self->input_height)
397         crop_height = self->input_height;
399       if (self->interlaced && !strcmp (klass->codec_name, "ivahd_mpeg2vdec"))
400         crop_height = crop_height / 2;
402       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
403           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
404           crop_width, crop_height);
406       gst_pad_push_event (self->srcpad,
407           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
408               crop_width, crop_height));
410       if (self->crop)
411         gst_video_crop_unref (self->crop);
413       self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
414           crop_width, crop_height);
416       self->send_crop_event = FALSE;
417     }
419     if (G_UNLIKELY (self->first_out_buffer) && send) {
420       GstDRMBufferPool *pool;
421       self->first_out_buffer = FALSE;
423       /* Destroy the pool so the buffers we used so far are eventually released.
424        * The pool will be recreated if needed.
425        */
426       pool = self->pool;
427       self->pool = NULL;
428       gst_drm_buffer_pool_destroy (pool);
429     }
431     if (send) {
432       GstClockTime ts;
434       ts = GST_BUFFER_TIMESTAMP (outbuf);
436       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
437           i, outbuf, GST_TIME_ARGS (ts));
439 #ifdef USE_DTS_PTS_CODE
440       if (self->ts_may_be_pts) {
441         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
442           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
443               "enabling ts_is_pts");
444           self->ts_is_pts = TRUE;
445         }
446       }
447 #endif
449       self->last_pts = ts;
451       if (self->dts_ridx != self->dts_widx) {
452         ts = self->dts_queue[self->dts_ridx++ % NDTS];
453       }
455       if (self->ts_is_pts) {
456         /* if we have a queued DTS from demuxer, use that instead: */
457         GST_BUFFER_TIMESTAMP (outbuf) = ts;
458         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
459             i, outbuf, GST_TIME_ARGS (ts));
460       }
462       if (GST_BUFFER_CAPS (outbuf) &&
463           !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
464               GST_PAD_CAPS (self->srcpad))) {
465         /* this looks a bit scary but it's really just to change the interlace=
466          * field in caps when we start as !interlaced and the codec detects
467          * otherwise */
468         GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
469             "interlace mismatch");
470         outbuf = gst_buffer_make_metadata_writable (outbuf);
471         gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
472       }
474       if (self->crop)
475         gst_buffer_set_video_crop (outbuf, self->crop);
477       ret = klass->push_output (self, outbuf);
478       if (flow_ret)
479         *flow_ret = ret;
480       if (ret != GST_FLOW_OK) {
481         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
482         /* just unref the remaining buffers (if any) */
483         send = FALSE;
484       }
485     } else {
486       GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
487       gst_buffer_unref (outbuf);
488     }
489   }
491 skip_outbuf_processing:
492   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
493     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
494   }
496   return err;
499 /** call control(FLUSH), and then process() to pop out all buffers */
500 gboolean
501 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
503   gint err = FALSE;
505   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
507   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
509   /* note: flush is synchronized against _chain() to avoid calling
510    * the codec from multiple threads
511    */
512   GST_PAD_STREAM_LOCK (self->sinkpad);
514 #ifdef USE_DTS_PTS_CODE
515   self->dts_ridx = self->dts_widx = 0;
516   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
517   self->ts_may_be_pts = TRUE;
518   self->ts_is_pts = FALSE;
519 #endif
520   self->wait_keyframe = TRUE;
521   self->in_size = 0;
522   self->needs_flushing = FALSE;
523   self->need_out_buf = TRUE;
525   if (G_UNLIKELY (self->first_in_buffer)) {
526     goto out;
527   }
529   if (G_UNLIKELY (!self->codec)) {
530     GST_WARNING_OBJECT (self, "no codec");
531     goto out;
532   }
534   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
535   if (err) {
536     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
537     goto out;
538   }
540   self->inBufs->descs[0].bufSize.bytes = 0;
541   self->inArgs->numBytes = 0;
542   self->inArgs->inputID = 0;
544   do {
545     err = codec_process (self, eos, TRUE, NULL);
546   } while (err != XDM_EFAIL);
548   /* reset outArgs in case we're flushing in codec_process trying to do error
549    * recovery */
550   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
551   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
553   self->dynParams->newFrameFlag = XDAS_TRUE;
555   /* on a flush, it is normal (and not an error) for the last _process() call
556    * to return an error..
557    */
558   err = XDM_EOK;
560 out:
561   GST_PAD_STREAM_UNLOCK (self->sinkpad);
562   GST_DEBUG_OBJECT (self, "done");
564   return !err;
567 /* GstDucatiVidDec vmethod default implementations */
569 static gboolean
570 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
572   const GValue *codec_data;
573   gint w, h;
575   if (gst_structure_get_int (s, "width", &self->input_width) &&
576       gst_structure_get_int (s, "height", &self->input_height)) {
578     h = ALIGN2 (self->input_height, 4); /* round up to MB */
579     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
581     /* if we've already created codec, but the resolution has changed, we
582      * need to re-create the codec:
583      */
584     if (G_UNLIKELY (self->codec)) {
585       if ((h != self->height) || (w != self->width)) {
586         codec_delete (self);
587       }
588     }
590     self->width = w;
591     self->height = h;
593     codec_data = gst_structure_get_value (s, "codec_data");
595     if (codec_data) {
596       GstBuffer *buffer = gst_value_get_buffer (codec_data);
597       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
598       self->codec_data = gst_buffer_ref (buffer);
599     }
601     return TRUE;
602   }
604   return FALSE;
607 static gboolean
608 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
609     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
612   /* allocate params: */
613   self->params = dce_alloc (params_sz);
614   if (G_UNLIKELY (!self->params)) {
615     return FALSE;
616   }
617   self->params->size = params_sz;
618   self->params->maxFrameRate = 30000;
619   self->params->maxBitRate = 10000000;
621   self->params->dataEndianness = XDM_BYTE;
622   self->params->forceChromaFormat = XDM_YUV_420SP;
623   self->params->operatingMode = IVIDEO_DECODE_ONLY;
625   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
626   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
627   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
628   self->params->numInputDataUnits = 0;
629   self->params->numOutputDataUnits = 0;
631   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
632   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
633   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
634   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
636   /* allocate dynParams: */
637   self->dynParams = dce_alloc (dynparams_sz);
638   if (G_UNLIKELY (!self->dynParams)) {
639     return FALSE;
640   }
641   self->dynParams->size = dynparams_sz;
642   self->dynParams->decodeHeader = XDM_DECODE_AU;
643   self->dynParams->displayWidth = 0;
644   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
645   self->dynParams->newFrameFlag = XDAS_TRUE;
647   /* allocate status: */
648   self->status = dce_alloc (status_sz);
649   if (G_UNLIKELY (!self->status)) {
650     return FALSE;
651   }
652   self->status->size = status_sz;
654   /* allocate inBufs/outBufs: */
655   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
656   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
657   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
658     return FALSE;
659   }
661   /* allocate inArgs/outArgs: */
662   self->inArgs = dce_alloc (inargs_sz);
663   self->outArgs = dce_alloc (outargs_sz);
664   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
665     return FALSE;
666   }
667   self->inArgs->size = inargs_sz;
668   self->outArgs->size = outargs_sz;
670   return TRUE;
673 static GstBuffer *
674 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
676   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
677     push_input (self, GST_BUFFER_DATA (self->codec_data),
678         GST_BUFFER_SIZE (self->codec_data));
679   }
681   /* just copy entire buffer */
682   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
683   gst_buffer_unref (buf);
685   return NULL;
688 static GstFlowReturn
689 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
691   return gst_pad_push (self->srcpad, buf);
694 static gint
695 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
696     gint extended_error, gint status_extended_error)
698   if (XDM_ISFATALERROR (extended_error))
699     ret = XDM_EFAIL;
700   else
701     ret = XDM_EOK;
703   return ret;
706 /* GstElement vmethod implementations */
708 static gboolean
709 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
711   gboolean ret = TRUE;
712   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
713   GstStructure *s;
714   GstCaps *outcaps = NULL;
715   GstStructure *out_s;
716   gint par_width, par_height;
717   gboolean par_present;
719   s = gst_caps_get_structure (caps, 0);
720   if (!klass->parse_caps (self, s)) {
721     GST_WARNING_OBJECT (self, "missing required fields");
722     ret = FALSE;
723     goto out;
724   }
726   /* update output/padded sizes */
727   klass->update_buffer_size (self);
729   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
730     self->fps_n = 0;
731     self->fps_d = 1;
732   }
733   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
734   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
735       &par_width, &par_height);
737   outcaps = gst_pad_get_allowed_caps (self->srcpad);
738   if (outcaps) {
739     outcaps = gst_caps_make_writable (outcaps);
740     gst_caps_truncate (outcaps);
741     if (gst_caps_is_empty (outcaps)) {
742       gst_caps_unref (outcaps);
743       outcaps = NULL;
744     }
745   }
747   if (!outcaps) {
748     /* note: default to non-strided for better compatibility with
749      * other gst elements that don't understand stride:
750      */
751     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
752         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
753   }
755   out_s = gst_caps_get_structure (outcaps, 0);
756   gst_structure_set (out_s,
757       "width", G_TYPE_INT, self->padded_width,
758       "height", G_TYPE_INT, self->padded_height,
759       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
760   if (par_present)
761     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
762         par_width, par_height, NULL);
764   if (self->interlaced)
765     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
767   if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
768     if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
769       self->stride = 4096;
770       gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
771     }
772   } else {
773     self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
774         0, self->padded_width);
775   }
777   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
778       self->stride, self->padded_height);
780   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
781       self->outsize, self->stride, outcaps);
783   if (!self->first_in_buffer) {
784     /* Caps changed mid stream. We flush the codec to unlock all the potentially
785      * locked buffers. This is needed for downstream sinks that provide a
786      * buffer pool and need to destroy all the outstanding buffers before they
787      * can negotiate new caps (hello v4l2sink).
788      */
789     gst_ducati_viddec_codec_flush (self, FALSE);
790   }
792   /* (re)send a crop event when caps change */
793   self->send_crop_event = TRUE;
795   ret = gst_pad_set_caps (self->srcpad, outcaps);
797   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
799 out:
800   if (outcaps)
801     gst_caps_unref (outcaps);
803   return ret;
806 static gboolean
807 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
809   gboolean ret = TRUE;
810   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
811   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
813   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
815   ret = klass->set_sink_caps (self, caps);
817   gst_object_unref (self);
819   return ret;
822 static GstCaps *
823 gst_ducati_viddec_src_getcaps (GstPad * pad)
825   GstCaps *caps = NULL;
826   GstCaps *outcaps = NULL;
827   int i;
829   caps = GST_PAD_CAPS (pad);
830   if (caps == NULL) {
831     outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
832     return outcaps;
833   }
835   outcaps = gst_caps_new_empty ();
837   /* allow -rowstrided and regular yuv */
838   for (i = 0; i < gst_caps_get_size (caps); i++) {
839     GstStructure *structure;
840     GstStructure *modified_structure;
841     GValue value = { 0 };
843     structure = gst_caps_get_structure (caps, i);
844     gst_caps_append_structure (outcaps, gst_structure_copy (structure));
845     modified_structure = gst_structure_copy (structure);
847     if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
848       gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
849       g_value_init (&value, GST_TYPE_INT_RANGE);
850       gst_value_set_int_range (&value, 0, G_MAXINT);
851       gst_structure_set_value (modified_structure, "rowstride", &value);
852       gst_caps_append_structure (outcaps, modified_structure);
853       g_value_unset (&value);
854     } else {
855       gst_structure_set_name (modified_structure, "video/x-raw-yuv");
856       gst_structure_remove_field (modified_structure, "rowstride");
857       gst_caps_append_structure (outcaps, modified_structure);
858     }
859   }
860   return outcaps;
863 static gboolean
864 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
865     GstQuery * query, gboolean * forward)
867   gboolean res = TRUE;
869   switch (GST_QUERY_TYPE (query)) {
870     case GST_QUERY_BUFFERS:
871       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
872       gst_query_set_buffers_count (query, self->min_buffers);
874       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
875           self->padded_width, self->padded_height);
876       gst_query_set_buffers_dimensions (query,
877           self->padded_width, self->padded_height);
878       *forward = FALSE;
879       break;
880     default:
881       break;
882   }
885   return res;
888 static gboolean
889 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
891   gboolean res = TRUE, forward = TRUE;
892   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
893   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
895   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
896   res = klass->query (self, pad, query, &forward);
897   if (res && forward)
898     res = gst_pad_query_default (pad, query);
900   return res;
903 static gboolean
904 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
906   GstClockTime timestamp, qostime;
907   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
908   gint64 diff;
910   if (self->wait_keyframe) {
911     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
912       GST_INFO_OBJECT (self, "skipping until the next keyframe");
913       return FALSE;
914     }
916     self->wait_keyframe = FALSE;
917   }
919   timestamp = GST_BUFFER_TIMESTAMP (buf);
920   if (self->segment.format != GST_FORMAT_TIME ||
921       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
922     goto no_qos;
924   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
925     goto no_qos;
927   qostime = gst_segment_to_running_time (&self->segment,
928       GST_FORMAT_TIME, timestamp);
929   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
930     /* out of segment */
931     goto no_qos;
933   /* see how our next timestamp relates to the latest qos timestamp. negative
934    * values mean we are early, positive values mean we are too late. */
935   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
937   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
938       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
939       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
940       self->qos_proportion);
942   if (klass->can_drop_frame (self, buf, diff)) {
943     GST_INFO_OBJECT (self, "dropping frame");
944     return FALSE;
945   }
947 no_qos:
948   return TRUE;
951 static gboolean
952 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
953     gint64 diff)
955   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
956       GST_BUFFER_FLAG_DELTA_UNIT);
958   if (diff >= 0 && !is_keyframe)
959     return TRUE;
961   return FALSE;
964 static GstFlowReturn
965 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
967   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
968   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
969   GstFlowReturn ret = GST_FLOW_OK;
970   Int32 err;
971   GstBuffer *outbuf = NULL;
972   GstCaps *outcaps = NULL;
973   gboolean decode;
975   if (G_UNLIKELY (!self->engine)) {
976     GST_ERROR_OBJECT (self, "no engine");
977     gst_buffer_unref (buf);
978     return GST_FLOW_ERROR;
979   }
981   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
982       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
984   decode = gst_ducati_viddec_do_qos (self, buf);
985   if (!decode) {
986     gst_buffer_unref (buf);
987     return GST_FLOW_OK;
988   }
990   if (!self->need_out_buf)
991     goto have_out_buf;
993   /* do this before creating codec to ensure reverse caps negotiation
994    * happens first:
995    */
996 allocate_buffer:
997   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
998       GST_PAD_CAPS (self->srcpad), &outbuf);
999   if (ret != GST_FLOW_OK) {
1000     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1001         gst_flow_get_name (ret));
1002     gst_buffer_unref (buf);
1003     return ret;
1004   }
1006   outcaps = GST_BUFFER_CAPS (outbuf);
1007   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1008     GstStructure *s;
1010     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1011         GST_BUFFER_SIZE (outbuf));
1013     s = gst_caps_get_structure (outcaps, 0);
1014     gst_structure_get_int (s, "rowstride", &self->stride);
1015     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1016         self->stride, self->padded_height);
1018     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1019         self->outsize, self->stride, outcaps);
1021     gst_pad_set_caps (self->srcpad, outcaps);
1023     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1024       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1025           GST_BUFFER_SIZE (outbuf), self->outsize);
1026       gst_buffer_unref (outbuf);
1027       goto allocate_buffer;
1028     }
1029   }
1031   if (G_UNLIKELY (!self->codec)) {
1032     if (!codec_create (self)) {
1033       GST_ERROR_OBJECT (self, "could not create codec");
1034       gst_buffer_unref (buf);
1035       gst_buffer_unref (outbuf);
1036       return GST_FLOW_ERROR;
1037     }
1038   }
1040   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1041   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1043   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1044    * internal pool while self->first_out_buffer == TRUE in order to simplify
1045    * things in case we need to renegotiate */
1046   self->inArgs->inputID =
1047       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1048   if (!self->inArgs->inputID) {
1049     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1050     gst_buffer_unref (buf);
1051     return GST_FLOW_ERROR;
1052   }
1054 have_out_buf:
1055   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1057 #ifdef USE_DTS_PTS_CODE
1058   if (ts != GST_CLOCK_TIME_NONE) {
1059     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1060     /* if next buffer has earlier ts than previous, then the ts
1061      * we are getting are definitely decode order (DTS):
1062      */
1063     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1064       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1065       self->ts_may_be_pts = FALSE;
1066     }
1067     self->last_dts = ts;
1068   }
1069 #endif
1071   if (self->in_size == 0 && outbuf) {
1072     GST_DEBUG_OBJECT (self, "no input, skipping process");
1073     gst_buffer_unref (outbuf);
1074     return GST_FLOW_OK;
1075   }
1077   self->inArgs->numBytes = self->in_size;
1078   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1079   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1081   err = codec_process (self, TRUE, FALSE, &ret);
1082   if (err) {
1083     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1084         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1085     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1086     return GST_FLOW_ERROR;
1087   }
1088   if (ret != GST_FLOW_OK) {
1089     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1090         gst_flow_get_name (ret));
1091     return ret;
1092   }
1094   self->first_in_buffer = FALSE;
1096   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1097     /* The copy could be avoided by playing with the buffer pointer,
1098        but it seems to be rare and for not many bytes */
1099     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1100         self->outArgs->bytesConsumed, self->in_size,
1101         self->inArgs->numBytes,
1102         self->in_size - self->outArgs->bytesConsumed);
1103     if (self->outArgs->bytesConsumed > 0) {
1104       if (self->outArgs->bytesConsumed > self->in_size) {
1105         GST_WARNING_OBJECT (self, "Codec claims to have used more bytes than supplied");
1106         self->in_size = 0;
1107       } else {
1108         if (self->outArgs->bytesConsumed < self->in_size) {
1109           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1110               self->in_size - self->outArgs->bytesConsumed);
1111         }
1112         self->in_size -= self->outArgs->bytesConsumed;
1113       }
1114     }
1115   } else {
1116     self->in_size = 0;
1117   }
1119   if (self->outArgs->outBufsInUseFlag) {
1120     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1121     self->need_out_buf = FALSE;
1122   } else {
1123     self->need_out_buf = TRUE;
1124   }
1126   if (buf) {
1127     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1128         GST_BUFFER_SIZE (buf));
1129     ts = GST_BUFFER_TIMESTAMP (buf);
1130     goto allocate_buffer;
1131   }
1133   if (self->needs_flushing)
1134     gst_ducati_viddec_codec_flush (self, FALSE);
1136   return GST_FLOW_OK;
1139 static gboolean
1140 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1142   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1143   gboolean ret = TRUE;
1145   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1147   switch (GST_EVENT_TYPE (event)) {
1148     case GST_EVENT_NEWSEGMENT:
1149     {
1150       gboolean update;
1151       GstFormat fmt;
1152       gint64 start, stop, time;
1153       gdouble rate, arate;
1155       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1156           &start, &stop, &time);
1157       gst_segment_set_newsegment_full (&self->segment, update,
1158           rate, arate, fmt, start, stop, time);
1159       break;
1160     }
1161     case GST_EVENT_EOS:
1162       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1163         GST_ERROR_OBJECT (self, "could not flush on eos");
1164         ret = FALSE;
1165       }
1166       break;
1167     case GST_EVENT_FLUSH_STOP:
1168       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1169         GST_ERROR_OBJECT (self, "could not flush");
1170         gst_event_unref (event);
1171         ret = FALSE;
1172       }
1173       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1174       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1175       self->qos_proportion = 1;
1176       self->need_out_buf = TRUE;
1177       break;
1178     default:
1179       break;
1180   }
1182   if (ret)
1183     ret = gst_pad_push_event (self->srcpad, event);
1184   GST_LOG_OBJECT (self, "end");
1186   return ret;
1189 static gboolean
1190 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1192   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1193   gboolean ret = TRUE;
1195   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1197   switch (GST_EVENT_TYPE (event)) {
1198     case GST_EVENT_QOS:
1199     {
1200       gdouble proportion;
1201       GstClockTimeDiff diff;
1202       GstClockTime timestamp;
1204       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1206       GST_OBJECT_LOCK (self);
1207       self->qos_proportion = proportion;
1208       self->qos_earliest_time = timestamp + 2 * diff;
1209       GST_OBJECT_UNLOCK (self);
1211       GST_DEBUG_OBJECT (self,
1212           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1213           proportion, GST_TIME_ARGS (timestamp), diff);
1215       ret = gst_pad_push_event (self->sinkpad, event);
1216       break;
1217     }
1218     default:
1219       ret = gst_pad_push_event (self->sinkpad, event);
1220       break;
1221   }
1223   GST_LOG_OBJECT (self, "end");
1225   return ret;
1228 static GstStateChangeReturn
1229 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1231   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1232   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1233   gboolean supported;
1235   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1236       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1237       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1239   switch (transition) {
1240     case GST_STATE_CHANGE_NULL_TO_READY:
1241       if (!engine_open (self)) {
1242         GST_ERROR_OBJECT (self, "could not open");
1243         return GST_STATE_CHANGE_FAILURE;
1244       }
1245       /* try to create/destroy the codec here, it may not be supported */
1246       supported = codec_create (self);
1247       codec_delete (self);
1248       self->codec = NULL;
1249       if (!supported) {
1250         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1251             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1252         engine_close (self);
1253         return GST_STATE_CHANGE_FAILURE;
1254       }
1255       break;
1256     default:
1257       break;
1258   }
1260   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1262   if (ret == GST_STATE_CHANGE_FAILURE)
1263     goto leave;
1265   switch (transition) {
1266     case GST_STATE_CHANGE_PAUSED_TO_READY:
1267       self->interlaced = FALSE;
1268       self->send_crop_event = TRUE;
1269       gst_ducati_viddec_codec_flush (self, FALSE);
1270       break;
1271     case GST_STATE_CHANGE_READY_TO_NULL:
1272       codec_delete (self);
1273       engine_close (self);
1274       break;
1275     default:
1276       break;
1277   }
1279 leave:
1280   GST_LOG_OBJECT (self, "end");
1282   return ret;
1285 /* GObject vmethod implementations */
1287 #define VERSION_LENGTH 256
1289 static void
1290 gst_ducati_viddec_get_property (GObject * obj,
1291     guint prop_id, GValue * value, GParamSpec * pspec)
1293   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1296   switch (prop_id) {
1297     case PROP_VERSION:{
1298       int err;
1299       char *version = NULL;
1301       if (!self->engine)
1302         engine_open (self);
1304       if (!self->codec)
1305         codec_create (self);
1307       if (self->codec) {
1308         version = dce_alloc (VERSION_LENGTH);
1309         self->status->data.buf = (XDAS_Int8 *) version;
1310         self->status->data.bufSize = VERSION_LENGTH;
1312         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1313             self->dynParams, self->status);
1314         if (err) {
1315           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1316         }
1318         self->status->data.buf = NULL;
1319         self->status->data.bufSize = 0;
1320       }
1322       g_value_set_string (value, version);
1323       if (version)
1324         dce_free (version);
1326       break;
1327     }
1328     default:{
1329       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1330       break;
1331     }
1332   }
1335 static void
1336 gst_ducati_viddec_finalize (GObject * obj)
1338   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1340   codec_delete (self);
1341   engine_close (self);
1343   if (self->codec_data) {
1344     gst_buffer_unref (self->codec_data);
1345     self->codec_data = NULL;
1346   }
1348   G_OBJECT_CLASS (parent_class)->finalize (obj);
1351 static void
1352 gst_ducati_viddec_base_init (gpointer gclass)
1354   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1356   gst_element_class_add_pad_template (element_class,
1357       gst_static_pad_template_get (&src_factory));
1360 static void
1361 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1363   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1364   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1366   gobject_class->get_property =
1367       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1368   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1369   gstelement_class->change_state =
1370       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1372   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1373   klass->allocate_params =
1374       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1375   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1376   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1377   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1378   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1379   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1380   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1381   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1383   g_object_class_install_property (gobject_class, PROP_VERSION,
1384       g_param_spec_string ("version", "Version",
1385           "The codec version string", "",
1386           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1389 static void
1390 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1392   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1394   self->sinkpad =
1395       gst_pad_new_from_template (gst_element_class_get_pad_template
1396       (gstelement_class, "sink"), "sink");
1397   gst_pad_set_setcaps_function (self->sinkpad,
1398       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1399   gst_pad_set_chain_function (self->sinkpad,
1400       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1401   gst_pad_set_event_function (self->sinkpad,
1402       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1404   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1405   gst_pad_set_event_function (self->srcpad,
1406       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1407   gst_pad_set_query_function (self->srcpad,
1408       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1409   gst_pad_set_getcaps_function (self->srcpad,
1410       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1412   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1413   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1415   self->input_width = 0;
1416   self->input_height = 0;
1417   /* sane defaults in case we need to create codec without caps negotiation
1418    * (for example, to get 'version' property)
1419    */
1420   self->width = 128;
1421   self->height = 128;
1422   self->fps_n = -1;
1423   self->fps_d = -1;
1425   self->first_in_buffer = TRUE;
1426   self->first_out_buffer = TRUE;
1427   self->interlaced = FALSE;
1428   self->send_crop_event = TRUE;
1430 #ifdef USE_DTS_PTS_CODE
1431   self->dts_ridx = self->dts_widx = 0;
1432   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1433   self->ts_may_be_pts = TRUE;
1434   self->ts_is_pts = FALSE;
1435 #endif
1437   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1439   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1441   self->qos_proportion = 1;
1442   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1443   self->wait_keyframe = TRUE;
1445   self->need_out_buf = TRUE;
1446   self->device = NULL;
1447   self->input_bo = NULL;