ab3147dd4fb54cea58833c8dfefad6c4adf38278
[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;
273 static GstBuffer *
274 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
276   GstBuffer *buf = (GstBuffer *) id;
278   if (buf) {
279     g_hash_table_insert (self->passed_in_bufs, buf, buf);
281     gst_buffer_ref (buf);
282   }
283   return buf;
286 static void
287 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
289   GstBuffer *buf = (GstBuffer *) id;
291   if (buf) {
292     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
293     g_hash_table_remove (self->passed_in_bufs, buf);
294   }
297 static GstFlowReturn
298 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
300   guint64 earliest_order = G_MAXUINT64;
301   guint earliest_index = 0, i;
302   GstBuffer *buf;
304   if (self->backlog_nframes == 0)
305     return GST_FLOW_OK;
307   /* work out which frame has the earliest poc */
308   for (i = 0; i < self->backlog_nframes; i++) {
309     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
310     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
311       earliest_order = order;
312       earliest_index = i;
313     }
314   }
316   /* send it, giving away the ref */
317   buf = self->backlog_frames[earliest_index];
318   self->backlog_frames[earliest_index] =
319       self->backlog_frames[--self->backlog_nframes];
320   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
321       buf);
322   return gst_pad_push (self->srcpad, buf);
325 static void
326 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
328   /* push everything on the backlog, ignoring errors */
329   while (self->backlog_nframes > 0) {
330     gst_ducati_viddec_push_earliest (self);
331   }
334 static gint
335 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
336     GstFlowReturn * flow_ret)
338   gint err;
339   GstClockTime t;
340   GstBuffer *outbuf = NULL;
341   gint i;
342   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
343   GstFlowReturn ret = GST_FLOW_OK;
344   if (flow_ret)
345     /* never leave flow_ret uninitialized */
346     *flow_ret = GST_FLOW_OK;
348   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
349   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
351   t = gst_util_get_timestamp ();
352   err = VIDDEC3_process (self->codec,
353       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
354   GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
356   if (err) {
357     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
358         err, self->outArgs->extendedError);
359     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
361     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
362         self->dynParams, self->status);
363     if (err) {
364       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
365           err, self->status->extendedError);
366       gst_ducati_log_extended_error_info (self->status->extendedError);
367     }
369     if (flush)
370       err = XDM_EFAIL;
371     else
372       err = klass->handle_error (self, err,
373           self->outArgs->extendedError, self->status->extendedError);
374   }
376   /* we now let the codec decide */
377   self->dynParams->newFrameFlag = XDAS_FALSE;
379   if (err == XDM_EFAIL)
380     goto skip_outbuf_processing;
382   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
383     gboolean interlaced;
385     /* Getting an extra reference for the decoder */
386     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
387     interlaced =
388         self->outArgs->decodedBufs.contentType ==
389         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
391     /* if send is FALSE, don't try to renegotiate as we could be flushing during
392      * a PAUSED->READY state change
393      */
394     if (send && interlaced != self->interlaced) {
395       GstCaps *caps;
397       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
398           "thinks interlaced=%d... trusting codec", self->interlaced,
399           interlaced);
401       self->interlaced = interlaced;
403       caps =
404           gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
405       GST_INFO_OBJECT (self, "changing interlace field in caps");
406       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
407           NULL);
408       gst_drm_buffer_pool_set_caps (self->pool, caps);
409       if (!gst_pad_set_caps (self->srcpad, caps)) {
410         GST_ERROR_OBJECT (self,
411             "downstream didn't want to change interlace mode");
412         err = XDM_EFAIL;
413       }
414       gst_caps_unref (caps);
416       /* this buffer still has the old caps so we skip it */
417       send = FALSE;
418     }
420     if (G_UNLIKELY (self->send_crop_event) && send) {
421       gint crop_width, crop_height;
423       /* send region of interest to sink on first buffer: */
424       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
426       crop_width = r->bottomRight.x - r->topLeft.x;
427       crop_height = r->bottomRight.y - r->topLeft.y;
429       if (crop_width > self->input_width)
430         crop_width = self->input_width;
431       if (crop_height > self->input_height)
432         crop_height = self->input_height;
434       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
435           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
436           crop_width, crop_height);
438       gst_pad_push_event (self->srcpad,
439           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
440               crop_width, crop_height));
442       if (self->crop)
443         gst_video_crop_unref (self->crop);
445       self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
446           crop_width, crop_height);
448       self->send_crop_event = FALSE;
449     }
451     if (G_UNLIKELY (self->first_out_buffer) && send) {
452       GstDRMBufferPool *pool;
453       self->first_out_buffer = FALSE;
455       /* Destroy the pool so the buffers we used so far are eventually released.
456        * The pool will be recreated if needed.
457        */
458       pool = self->pool;
459       self->pool = NULL;
460       gst_drm_buffer_pool_destroy (pool);
461     }
463     if (send) {
464       GstClockTime ts;
466       ts = GST_BUFFER_TIMESTAMP (outbuf);
468       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
469           i, outbuf, GST_TIME_ARGS (ts));
471 #ifdef USE_DTS_PTS_CODE
472       if (self->ts_may_be_pts) {
473         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
474           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
475               "enabling ts_is_pts");
476           self->ts_is_pts = TRUE;
477         }
478       }
479 #endif
481       self->last_pts = ts;
483       if (self->dts_ridx != self->dts_widx) {
484         ts = self->dts_queue[self->dts_ridx++ % NDTS];
485       }
487       if (self->ts_is_pts) {
488         /* if we have a queued DTS from demuxer, use that instead: */
489         GST_BUFFER_TIMESTAMP (outbuf) = ts;
490         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
491             i, outbuf, GST_TIME_ARGS (ts));
492       }
494       if (GST_BUFFER_CAPS (outbuf) &&
495           !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
496               GST_PAD_CAPS (self->srcpad))) {
497         /* this looks a bit scary but it's really just to change the interlace=
498          * field in caps when we start as !interlaced and the codec detects
499          * otherwise */
500         GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
501             "interlace mismatch");
502         outbuf = gst_buffer_make_metadata_writable (outbuf);
503         gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
504       }
506       if (self->crop)
507         gst_buffer_set_video_crop (outbuf, self->crop);
509       ret = klass->push_output (self, outbuf);
510       if (flow_ret)
511         *flow_ret = ret;
512       if (ret != GST_FLOW_OK) {
513         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
514         /* just unref the remaining buffers (if any) */
515         send = FALSE;
516       }
517     } else {
518       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
519           i, outbuf);
521       gst_buffer_unref (outbuf);
522     }
523   }
525 skip_outbuf_processing:
526   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
527     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
528   }
530   return err;
533 /** call control(FLUSH), and then process() to pop out all buffers */
534 gboolean
535 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
537   gint err = FALSE;
539   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
541   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
543   /* note: flush is synchronized against _chain() to avoid calling
544    * the codec from multiple threads
545    */
546   GST_PAD_STREAM_LOCK (self->sinkpad);
548 #ifdef USE_DTS_PTS_CODE
549   self->dts_ridx = self->dts_widx = 0;
550   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
551   self->ts_may_be_pts = TRUE;
552   self->ts_is_pts = FALSE;
553 #endif
554   self->wait_keyframe = TRUE;
555   self->in_size = 0;
556   self->needs_flushing = FALSE;
557   self->need_out_buf = TRUE;
559   if (G_UNLIKELY (self->first_in_buffer)) {
560     goto out;
561   }
563   if (G_UNLIKELY (!self->codec)) {
564     GST_WARNING_OBJECT (self, "no codec");
565     goto out;
566   }
568   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
569   if (err) {
570     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
571     goto out;
572   }
574   self->inBufs->descs[0].bufSize.bytes = 0;
575   self->inBufs->numBufs = 0;
576   self->inArgs->numBytes = 0;
577   self->inArgs->inputID = 0;
578   self->outBufs->numBufs = 0;
580   do {
581     err = codec_process (self, eos, TRUE, NULL);
582   } while (err != XDM_EFAIL);
584   /* We flushed the decoder, we can now remove the buffer that have never been
585    * unrefed in it */
586   g_hash_table_remove_all (self->passed_in_bufs);
588   /* reset outArgs in case we're flushing in codec_process trying to do error
589    * recovery */
590   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
591   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
593   self->dynParams->newFrameFlag = XDAS_TRUE;
595   /* Reset the push buffer and YUV buffers */
596   self->inBufs->numBufs = 1;
597   self->outBufs->numBufs = 2;
599   /* on a flush, it is normal (and not an error) for the last _process() call
600    * to return an error..
601    */
602   err = XDM_EOK;
604 out:
605   GST_PAD_STREAM_UNLOCK (self->sinkpad);
606   GST_DEBUG_OBJECT (self, "done");
608   return !err;
611 /* GstDucatiVidDec vmethod default implementations */
613 static gboolean
614 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
616   const GValue *codec_data;
617   gint w, h;
619   if (gst_structure_get_int (s, "width", &self->input_width) &&
620       gst_structure_get_int (s, "height", &self->input_height)) {
622     h = ALIGN2 (self->input_height, 4); /* round up to MB */
623     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
625     /* if we've already created codec, but the resolution has changed, we
626      * need to re-create the codec:
627      */
628     if (G_UNLIKELY (self->codec)) {
629       if ((h != self->height) || (w != self->width)) {
630         codec_delete (self);
631       }
632     }
634     self->width = w;
635     self->height = h;
637     codec_data = gst_structure_get_value (s, "codec_data");
639     if (codec_data) {
640       GstBuffer *buffer = gst_value_get_buffer (codec_data);
641       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
642       self->codec_data = gst_buffer_ref (buffer);
643     }
645     return TRUE;
646   }
648   return FALSE;
651 static gboolean
652 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
653     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
656   /* allocate params: */
657   self->params = dce_alloc (params_sz);
658   if (G_UNLIKELY (!self->params)) {
659     return FALSE;
660   }
661   self->params->size = params_sz;
662   self->params->maxFrameRate = 30000;
663   self->params->maxBitRate = 10000000;
665   self->params->dataEndianness = XDM_BYTE;
666   self->params->forceChromaFormat = XDM_YUV_420SP;
667   self->params->operatingMode = IVIDEO_DECODE_ONLY;
669   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
670   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
671   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
672   self->params->numInputDataUnits = 0;
673   self->params->numOutputDataUnits = 0;
675   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
676   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
677   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
678   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
680   /* allocate dynParams: */
681   self->dynParams = dce_alloc (dynparams_sz);
682   if (G_UNLIKELY (!self->dynParams)) {
683     return FALSE;
684   }
685   self->dynParams->size = dynparams_sz;
686   self->dynParams->decodeHeader = XDM_DECODE_AU;
687   self->dynParams->displayWidth = 0;
688   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
689   self->dynParams->newFrameFlag = XDAS_TRUE;
691   /* allocate status: */
692   self->status = dce_alloc (status_sz);
693   if (G_UNLIKELY (!self->status)) {
694     return FALSE;
695   }
696   memset (self->status, 0, status_sz);
697   self->status->size = status_sz;
699   /* allocate inBufs/outBufs: */
700   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
701   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
702   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
703     return FALSE;
704   }
706   /* allocate inArgs/outArgs: */
707   self->inArgs = dce_alloc (inargs_sz);
708   self->outArgs = dce_alloc (outargs_sz);
709   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
710     return FALSE;
711   }
712   self->inArgs->size = inargs_sz;
713   self->outArgs->size = outargs_sz;
715   return TRUE;
718 static GstBuffer *
719 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
721   /* If we're about to push a keyframe, then we can flush all the frames
722      we currently have queued. For formats such as H264, this is actually
723      necessary as picture order count is local to each IDR + set of non
724      IDR frames, so will restart at 0 when next IDR frames comes in. For
725      other formats, it is not necessary, but avoids buffering frames that
726      do not need to be. */
727   if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
728     GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
729         self->backlog_nframes);
730     while (self->backlog_nframes > 0) {
731       gst_ducati_viddec_push_earliest (self);
732     }
733   }
735   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
736     push_input (self, GST_BUFFER_DATA (self->codec_data),
737         GST_BUFFER_SIZE (self->codec_data));
738   }
740   /* just copy entire buffer */
741   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
742   gst_buffer_unref (buf);
744   return NULL;
747 static GstFlowReturn
748 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
750   GstFlowReturn ret = GST_FLOW_OK;
752   /* add the frame to the list, the array will own the ref */
753   GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
754   self->backlog_frames[self->backlog_nframes++] = buf;
756   /* push till we have no more than the max needed, or error */
757   while (self->backlog_nframes > self->backlog_maxframes) {
758     ret = gst_ducati_viddec_push_earliest (self);
759     if (ret != GST_FLOW_OK)
760       break;
761   }
763   return ret;
766 static gint
767 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
768     gint extended_error, gint status_extended_error)
770   if (XDM_ISFATALERROR (extended_error))
771     ret = XDM_EFAIL;
772   else
773     ret = XDM_EOK;
775   return ret;
778 /* GstElement vmethod implementations */
780 static gboolean
781 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
783   gboolean ret = TRUE;
784   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
785   GstStructure *s;
786   GstCaps *outcaps = NULL;
787   GstStructure *out_s;
788   gint par_width, par_height;
789   gboolean par_present;
791   s = gst_caps_get_structure (caps, 0);
792   if (!klass->parse_caps (self, s)) {
793     GST_WARNING_OBJECT (self, "missing required fields");
794     ret = FALSE;
795     goto out;
796   }
798   /* update output/padded sizes */
799   klass->update_buffer_size (self);
801   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
802     self->fps_n = 0;
803     self->fps_d = 1;
804   }
805   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
806   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
807       &par_width, &par_height);
809   outcaps = gst_pad_get_allowed_caps (self->srcpad);
810   if (outcaps) {
811     outcaps = gst_caps_make_writable (outcaps);
812     gst_caps_truncate (outcaps);
813     if (gst_caps_is_empty (outcaps)) {
814       gst_caps_unref (outcaps);
815       outcaps = NULL;
816     }
817   }
819   if (!outcaps) {
820     /* note: default to non-strided for better compatibility with
821      * other gst elements that don't understand stride:
822      */
823     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
824         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
825   }
827   out_s = gst_caps_get_structure (outcaps, 0);
828   gst_structure_set (out_s,
829       "width", G_TYPE_INT, self->padded_width,
830       "height", G_TYPE_INT, self->padded_height,
831       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
832   if (par_present)
833     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
834         par_width, par_height, NULL);
836   if (self->interlaced)
837     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
839   if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
840     if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
841       self->stride = 4096;
842       gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
843     }
844   } else {
845     self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
846         0, self->padded_width);
847   }
849   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
850       self->stride, self->padded_height);
852   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
853       self->outsize, self->stride, outcaps);
855   if (!self->first_in_buffer) {
856     /* Caps changed mid stream. We flush the codec to unlock all the potentially
857      * locked buffers. This is needed for downstream sinks that provide a
858      * buffer pool and need to destroy all the outstanding buffers before they
859      * can negotiate new caps (hello v4l2sink).
860      */
861     gst_ducati_viddec_codec_flush (self, FALSE);
862   }
864   /* (re)send a crop event when caps change */
865   self->send_crop_event = TRUE;
867   ret = gst_pad_set_caps (self->srcpad, outcaps);
869   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
871   /* default to no reordering */
872   self->backlog_maxframes = 0;
874 out:
875   if (outcaps)
876     gst_caps_unref (outcaps);
878   return ret;
881 static gboolean
882 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
884   gboolean ret = TRUE;
885   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
886   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
888   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
890   ret = klass->set_sink_caps (self, caps);
892   gst_object_unref (self);
894   return ret;
897 static GstCaps *
898 gst_ducati_viddec_src_getcaps (GstPad * pad)
900   GstCaps *caps = NULL;
901   GstCaps *outcaps = NULL;
902   int i;
904   caps = GST_PAD_CAPS (pad);
905   if (caps == NULL) {
906     outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
907     return outcaps;
908   }
910   outcaps = gst_caps_new_empty ();
912   /* allow -rowstrided and regular yuv */
913   for (i = 0; i < gst_caps_get_size (caps); i++) {
914     GstStructure *structure;
915     GstStructure *modified_structure;
916     GValue value = { 0 };
918     structure = gst_caps_get_structure (caps, i);
919     gst_caps_append_structure (outcaps, gst_structure_copy (structure));
920     modified_structure = gst_structure_copy (structure);
922     if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
923       gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
924       g_value_init (&value, GST_TYPE_INT_RANGE);
925       gst_value_set_int_range (&value, 0, G_MAXINT);
926       gst_structure_set_value (modified_structure, "rowstride", &value);
927       gst_caps_append_structure (outcaps, modified_structure);
928       g_value_unset (&value);
929     } else {
930       gst_structure_set_name (modified_structure, "video/x-raw-yuv");
931       gst_structure_remove_field (modified_structure, "rowstride");
932       gst_caps_append_structure (outcaps, modified_structure);
933     }
934   }
935   return outcaps;
938 static gboolean
939 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
940     GstQuery * query, gboolean * forward)
942   gboolean res = TRUE;
944   switch (GST_QUERY_TYPE (query)) {
945     case GST_QUERY_BUFFERS:
946       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
947       gst_query_set_buffers_count (query, self->min_buffers);
949       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
950           self->padded_width, self->padded_height);
951       gst_query_set_buffers_dimensions (query,
952           self->padded_width, self->padded_height);
953       *forward = FALSE;
954       break;
955     default:
956       break;
957   }
960   return res;
963 static gboolean
964 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
966   gboolean res = TRUE, forward = TRUE;
967   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
968   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
970   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
971   res = klass->query (self, pad, query, &forward);
972   if (res && forward)
973     res = gst_pad_query_default (pad, query);
975   return res;
978 static gboolean
979 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
981   GstClockTime timestamp, qostime;
982   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
983   gint64 diff;
985   if (self->wait_keyframe) {
986     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
987       GST_INFO_OBJECT (self, "skipping until the next keyframe");
988       return FALSE;
989     }
991     self->wait_keyframe = FALSE;
992   }
994   timestamp = GST_BUFFER_TIMESTAMP (buf);
995   if (self->segment.format != GST_FORMAT_TIME ||
996       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
997     goto no_qos;
999   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1000     goto no_qos;
1002   qostime = gst_segment_to_running_time (&self->segment,
1003       GST_FORMAT_TIME, timestamp);
1004   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1005     /* out of segment */
1006     goto no_qos;
1008   /* see how our next timestamp relates to the latest qos timestamp. negative
1009    * values mean we are early, positive values mean we are too late. */
1010   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1012   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1013       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1014       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1015       self->qos_proportion);
1017   if (klass->can_drop_frame (self, buf, diff)) {
1018     GST_INFO_OBJECT (self, "dropping frame");
1019     return FALSE;
1020   }
1022 no_qos:
1023   return TRUE;
1026 static gboolean
1027 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1028     gint64 diff)
1030   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1031       GST_BUFFER_FLAG_DELTA_UNIT);
1033   if (diff >= 0 && !is_keyframe)
1034     return TRUE;
1036   return FALSE;
1039 static GstFlowReturn
1040 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1042   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1043   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1044   GstFlowReturn ret = GST_FLOW_OK;
1045   Int32 err;
1046   GstBuffer *outbuf = NULL;
1047   GstCaps *outcaps = NULL;
1048   gboolean decode;
1050   if (G_UNLIKELY (!self->engine)) {
1051     GST_ERROR_OBJECT (self, "no engine");
1052     gst_buffer_unref (buf);
1053     return GST_FLOW_ERROR;
1054   }
1056   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1057       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1059   decode = gst_ducati_viddec_do_qos (self, buf);
1060   if (!decode) {
1061     gst_buffer_unref (buf);
1062     return GST_FLOW_OK;
1063   }
1065   if (!self->need_out_buf)
1066     goto have_out_buf;
1068   /* do this before creating codec to ensure reverse caps negotiation
1069    * happens first:
1070    */
1071 allocate_buffer:
1072   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1073       GST_PAD_CAPS (self->srcpad), &outbuf);
1074   if (ret != GST_FLOW_OK) {
1075     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1076         gst_flow_get_name (ret));
1077     gst_buffer_unref (buf);
1078     return ret;
1079   }
1081   outcaps = GST_BUFFER_CAPS (outbuf);
1082   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1083     GstStructure *s;
1085     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1086         GST_BUFFER_SIZE (outbuf));
1088     s = gst_caps_get_structure (outcaps, 0);
1089     gst_structure_get_int (s, "rowstride", &self->stride);
1090     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1091         self->stride, self->padded_height);
1093     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1094         self->outsize, self->stride, outcaps);
1096     gst_pad_set_caps (self->srcpad, outcaps);
1098     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1099       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1100           GST_BUFFER_SIZE (outbuf), self->outsize);
1101       gst_buffer_unref (outbuf);
1102       goto allocate_buffer;
1103     }
1104   }
1106   if (G_UNLIKELY (!self->codec)) {
1107     if (!codec_create (self)) {
1108       GST_ERROR_OBJECT (self, "could not create codec");
1109       gst_buffer_unref (buf);
1110       gst_buffer_unref (outbuf);
1111       return GST_FLOW_ERROR;
1112     }
1113   }
1115   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1116   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1118   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1119    * internal pool while self->first_out_buffer == TRUE in order to simplify
1120    * things in case we need to renegotiate */
1121   self->inArgs->inputID =
1122       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1123   if (!self->inArgs->inputID) {
1124     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1125     gst_buffer_unref (buf);
1126     return GST_FLOW_ERROR;
1127   }
1128   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1130 have_out_buf:
1131   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1133 #ifdef USE_DTS_PTS_CODE
1134   if (ts != GST_CLOCK_TIME_NONE) {
1135     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1136     /* if next buffer has earlier ts than previous, then the ts
1137      * we are getting are definitely decode order (DTS):
1138      */
1139     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1140       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1141       self->ts_may_be_pts = FALSE;
1142     }
1143     self->last_dts = ts;
1144   }
1145 #endif
1147   if (self->in_size == 0 && outbuf) {
1148     GST_DEBUG_OBJECT (self, "no input, skipping process");
1150     gst_buffer_unref (outbuf);
1151     return GST_FLOW_OK;
1152   }
1154   self->inArgs->numBytes = self->in_size;
1155   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1156   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1158   err = codec_process (self, TRUE, FALSE, &ret);
1159   if (err) {
1160     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1161         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1162     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1164     return GST_FLOW_ERROR;
1165   }
1167   if (ret != GST_FLOW_OK) {
1168     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1169         gst_flow_get_name (ret));
1171     return ret;
1172   }
1174   self->first_in_buffer = FALSE;
1176   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1177     /* The copy could be avoided by playing with the buffer pointer,
1178        but it seems to be rare and for not many bytes */
1179     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1180         self->outArgs->bytesConsumed, self->in_size,
1181         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1182     if (self->outArgs->bytesConsumed > 0) {
1183       if (self->outArgs->bytesConsumed > self->in_size) {
1184         GST_WARNING_OBJECT (self,
1185             "Codec claims to have used more bytes than supplied");
1186         self->in_size = 0;
1187       } else {
1188         if (self->outArgs->bytesConsumed < self->in_size) {
1189           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1190               self->in_size - self->outArgs->bytesConsumed);
1191         }
1192         self->in_size -= self->outArgs->bytesConsumed;
1193       }
1194     }
1195   } else {
1196     self->in_size = 0;
1197   }
1199   if (self->outArgs->outBufsInUseFlag) {
1200     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1201     self->need_out_buf = FALSE;
1202   } else {
1203     self->need_out_buf = TRUE;
1204   }
1206   if (buf) {
1207     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1208         GST_BUFFER_SIZE (buf));
1209     ts = GST_BUFFER_TIMESTAMP (buf);
1210     goto allocate_buffer;
1211   }
1213   if (self->needs_flushing)
1214     gst_ducati_viddec_codec_flush (self, FALSE);
1216   return GST_FLOW_OK;
1219 static gboolean
1220 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1222   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1223   gboolean ret = TRUE;
1225   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1227   switch (GST_EVENT_TYPE (event)) {
1228     case GST_EVENT_NEWSEGMENT:
1229     {
1230       gboolean update;
1231       GstFormat fmt;
1232       gint64 start, stop, time;
1233       gdouble rate, arate;
1235       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1236           &start, &stop, &time);
1237       gst_segment_set_newsegment_full (&self->segment, update,
1238           rate, arate, fmt, start, stop, time);
1239       break;
1240     }
1241     case GST_EVENT_EOS:
1242       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1243         GST_ERROR_OBJECT (self, "could not flush on eos");
1244         ret = FALSE;
1245       }
1246       break;
1247     case GST_EVENT_FLUSH_STOP:
1248       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1249         GST_ERROR_OBJECT (self, "could not flush");
1250         gst_event_unref (event);
1251         ret = FALSE;
1252       }
1253       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1254       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1255       self->qos_proportion = 1;
1256       self->need_out_buf = TRUE;
1257       break;
1258     default:
1259       break;
1260   }
1262   if (ret)
1263     ret = gst_pad_push_event (self->srcpad, event);
1264   GST_LOG_OBJECT (self, "end");
1266   return ret;
1269 static gboolean
1270 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1272   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1273   gboolean ret = TRUE;
1275   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1277   switch (GST_EVENT_TYPE (event)) {
1278     case GST_EVENT_QOS:
1279     {
1280       gdouble proportion;
1281       GstClockTimeDiff diff;
1282       GstClockTime timestamp;
1284       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1286       GST_OBJECT_LOCK (self);
1287       self->qos_proportion = proportion;
1288       self->qos_earliest_time = timestamp + 2 * diff;
1289       GST_OBJECT_UNLOCK (self);
1291       GST_DEBUG_OBJECT (self,
1292           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1293           proportion, GST_TIME_ARGS (timestamp), diff);
1295       ret = gst_pad_push_event (self->sinkpad, event);
1296       break;
1297     }
1298     default:
1299       ret = gst_pad_push_event (self->sinkpad, event);
1300       break;
1301   }
1303   GST_LOG_OBJECT (self, "end");
1305   return ret;
1308 static GstStateChangeReturn
1309 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1311   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1312   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1313   gboolean supported;
1315   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1316       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1317       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1319   switch (transition) {
1320     case GST_STATE_CHANGE_NULL_TO_READY:
1321       if (!engine_open (self)) {
1322         GST_ERROR_OBJECT (self, "could not open");
1323         return GST_STATE_CHANGE_FAILURE;
1324       }
1325       /* try to create/destroy the codec here, it may not be supported */
1326       supported = codec_create (self);
1327       codec_delete (self);
1328       self->codec = NULL;
1329       if (!supported) {
1330         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1331             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1332         engine_close (self);
1333         return GST_STATE_CHANGE_FAILURE;
1334       }
1335       break;
1336     default:
1337       break;
1338   }
1340   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1342   if (ret == GST_STATE_CHANGE_FAILURE)
1343     goto leave;
1345   switch (transition) {
1346     case GST_STATE_CHANGE_PAUSED_TO_READY:
1347       self->interlaced = FALSE;
1348       self->send_crop_event = TRUE;
1349       gst_ducati_viddec_codec_flush (self, FALSE);
1350       break;
1351     case GST_STATE_CHANGE_READY_TO_NULL:
1352       codec_delete (self);
1353       engine_close (self);
1354       break;
1355     default:
1356       break;
1357   }
1359 leave:
1360   GST_LOG_OBJECT (self, "end");
1362   return ret;
1365 /* GObject vmethod implementations */
1367 #define VERSION_LENGTH 256
1369 static void
1370 gst_ducati_viddec_get_property (GObject * obj,
1371     guint prop_id, GValue * value, GParamSpec * pspec)
1373   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1376   switch (prop_id) {
1377     case PROP_VERSION:{
1378       int err;
1379       char *version = NULL;
1381       if (!self->engine)
1382         engine_open (self);
1384       if (!self->codec)
1385         codec_create (self);
1387       if (self->codec) {
1388         version = dce_alloc (VERSION_LENGTH);
1389         self->status->data.buf = (XDAS_Int8 *) version;
1390         self->status->data.bufSize = VERSION_LENGTH;
1392         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1393             self->dynParams, self->status);
1394         if (err) {
1395           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1396         }
1398         self->status->data.buf = NULL;
1399         self->status->data.bufSize = 0;
1400       }
1402       g_value_set_string (value, version);
1403       if (version)
1404         dce_free (version);
1406       break;
1407     }
1408     default:{
1409       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1410       break;
1411     }
1412   }
1415 static void
1416 gst_ducati_viddec_finalize (GObject * obj)
1418   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1420   codec_delete (self);
1421   engine_close (self);
1423   /* Will unref the remaining buffers if needed */
1424   g_hash_table_unref (self->passed_in_bufs);
1425   if (self->codec_data) {
1426     gst_buffer_unref (self->codec_data);
1427     self->codec_data = NULL;
1428   }
1430   G_OBJECT_CLASS (parent_class)->finalize (obj);
1433 static void
1434 gst_ducati_viddec_base_init (gpointer gclass)
1436   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1438   gst_element_class_add_pad_template (element_class,
1439       gst_static_pad_template_get (&src_factory));
1442 static void
1443 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1445   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1446   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1448   gobject_class->get_property =
1449       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1450   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1451   gstelement_class->change_state =
1452       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1454   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1455   klass->allocate_params =
1456       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1457   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1458   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1459   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1460   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1461   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1462   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1463   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1465   g_object_class_install_property (gobject_class, PROP_VERSION,
1466       g_param_spec_string ("version", "Version",
1467           "The codec version string", "",
1468           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1471 static void
1472 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1474   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1476   self->sinkpad =
1477       gst_pad_new_from_template (gst_element_class_get_pad_template
1478       (gstelement_class, "sink"), "sink");
1479   gst_pad_set_setcaps_function (self->sinkpad,
1480       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1481   gst_pad_set_chain_function (self->sinkpad,
1482       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1483   gst_pad_set_event_function (self->sinkpad,
1484       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1486   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1487   gst_pad_set_event_function (self->srcpad,
1488       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1489   gst_pad_set_query_function (self->srcpad,
1490       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1491   gst_pad_set_getcaps_function (self->srcpad,
1492       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1494   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1495   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1497   self->input_width = 0;
1498   self->input_height = 0;
1499   /* sane defaults in case we need to create codec without caps negotiation
1500    * (for example, to get 'version' property)
1501    */
1502   self->width = 128;
1503   self->height = 128;
1504   self->fps_n = -1;
1505   self->fps_d = -1;
1507   self->first_in_buffer = TRUE;
1508   self->first_out_buffer = TRUE;
1509   self->interlaced = FALSE;
1510   self->send_crop_event = TRUE;
1512 #ifdef USE_DTS_PTS_CODE
1513   self->dts_ridx = self->dts_widx = 0;
1514   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1515   self->ts_may_be_pts = TRUE;
1516   self->ts_is_pts = FALSE;
1517 #endif
1519   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1521   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1523   self->qos_proportion = 1;
1524   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1525   self->wait_keyframe = TRUE;
1527   self->need_out_buf = TRUE;
1528   self->device = NULL;
1529   self->input_bo = NULL;
1531   self->backlog_maxframes = 0;
1532   self->backlog_nframes = 0;
1534   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1535       NULL, (GDestroyNotify) gst_buffer_unref);