ducativideodec: add a max-reorder-frames decoder property
[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   PROP_MAX_REORDER_FRAMES,
42 };
44 /* helper functions */
46 static void
47 engine_close (GstDucatiVidDec * self)
48 {
49   if (self->engine) {
50     Engine_close (self->engine);
51     self->engine = NULL;
52   }
54   if (self->params) {
55     dce_free (self->params);
56     self->params = NULL;
57   }
59   if (self->dynParams) {
60     dce_free (self->dynParams);
61     self->dynParams = NULL;
62   }
64   if (self->status) {
65     dce_free (self->status);
66     self->status = NULL;
67   }
69   if (self->inBufs) {
70     dce_free (self->inBufs);
71     self->inBufs = NULL;
72   }
74   if (self->outBufs) {
75     dce_free (self->outBufs);
76     self->outBufs = NULL;
77   }
79   if (self->inArgs) {
80     dce_free (self->inArgs);
81     self->inArgs = NULL;
82   }
84   if (self->outArgs) {
85     dce_free (self->outArgs);
86     self->outArgs = NULL;
87   }
89   if (self->device) {
90     dce_deinit (self->device);
91     self->device = NULL;
92   }
93 }
95 static gboolean
96 engine_open (GstDucatiVidDec * self)
97 {
98   gboolean ret;
99   int ec;
101   if (G_UNLIKELY (self->engine)) {
102     return TRUE;
103   }
105   if (self->device == NULL) {
106     self->device = dce_init ();
107     if (self->device == NULL) {
108       GST_ERROR_OBJECT (self, "dce_init() failed");
109       return FALSE;
110     }
111   }
113   GST_DEBUG_OBJECT (self, "opening engine");
115   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
116   if (G_UNLIKELY (!self->engine)) {
117     GST_ERROR_OBJECT (self, "could not create engine");
118     return FALSE;
119   }
121   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
122       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
123       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
124       sizeof (IVIDDEC3_OutArgs));
126   return ret;
129 static void
130 codec_delete (GstDucatiVidDec * self)
132   if (self->pool) {
133     gst_drm_buffer_pool_destroy (self->pool);
134     self->pool = NULL;
135   }
137   if (self->codec) {
138     VIDDEC3_delete (self->codec);
139     self->codec = NULL;
140   }
142   if (self->input_bo) {
143     omap_bo_del (self->input_bo);
144     self->input_bo = NULL;
145   }
148 static gboolean
149 codec_create (GstDucatiVidDec * self)
151   gint err;
152   const gchar *codec_name;
154   codec_delete (self);
156   if (G_UNLIKELY (!self->engine)) {
157     GST_ERROR_OBJECT (self, "no engine");
158     return FALSE;
159   }
161   /* these need to be set before VIDDEC3_create */
162   self->params->maxWidth = self->width;
163   self->params->maxHeight = self->height;
165   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
167   /* create codec: */
168   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
169   self->codec =
170       VIDDEC3_create (self->engine, (String) codec_name, self->params);
172   if (!self->codec) {
173     return FALSE;
174   }
176   err =
177       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
178       self->status);
179   if (err) {
180     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
181     return FALSE;
182   }
184   self->first_in_buffer = TRUE;
185   self->first_out_buffer = TRUE;
187   /* allocate input buffer and initialize inBufs: */
188   /* FIXME:  needed size here has nothing to do with width * height */
189   self->input_bo = omap_bo_new (self->device,
190       self->width * self->height, OMAP_BO_WC);
191   self->input = omap_bo_map (self->input_bo);
192   self->inBufs->numBufs = 1;
193   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
195   return TRUE;
198 static inline GstBuffer *
199 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
201   if (G_UNLIKELY (!self->pool)) {
202     guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
203         self->padded_width, self->padded_height);
205     GST_DEBUG_OBJECT (self, "creating bufferpool");
206     self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
207         dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
208   }
209   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
212 static GstDucatiBufferPriv *
213 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
215   GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
216   if (!priv) {
217     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
218     GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
220     /* if it isn't a dmabuf buffer that we can import, then there
221      * is nothing we can do with it:
222      */
223     if (!dmabuf) {
224       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
225       return NULL;
226     }
228     priv = gst_ducati_buffer_priv_new ();
230     priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
232     priv->uv_offset = gst_video_format_get_component_offset (format,
233         1, self->stride, self->padded_height);
234     priv->size = gst_video_format_get_size (format,
235         self->stride, self->padded_height);
237     gst_ducati_buffer_priv_set (buf, priv);
238     gst_mini_object_unref (GST_MINI_OBJECT (priv));
239   }
240   return priv;
243 static XDAS_Int32
244 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
245     gboolean force_internal)
247   GstDucatiBufferPriv *priv = NULL;
249   if (!force_internal)
250     priv = get_buffer_priv (self, *buf);
252   if (!priv) {
253     GstBuffer *orig = *buf;
255     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
256     *buf = codec_buffer_pool_get (self, NULL);
257     GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
258     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
259     gst_buffer_unref (orig);
260     return codec_prepare_outbuf (self, buf, FALSE);
261   }
263   self->outBufs->numBufs = 2;
264   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
265   self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
266   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
267   self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
268   self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
269   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
271   return (XDAS_Int32) * buf;
274 static GstBuffer *
275 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
277   GstBuffer *buf = (GstBuffer *) id;
279   if (buf) {
280     g_hash_table_insert (self->passed_in_bufs, buf, buf);
282     gst_buffer_ref (buf);
283   }
284   return buf;
287 static void
288 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
290   GstBuffer *buf = (GstBuffer *) id;
292   if (buf) {
293     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
294     g_hash_table_remove (self->passed_in_bufs, buf);
295   }
298 static GstFlowReturn
299 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
301   guint64 earliest_order = G_MAXUINT64;
302   guint earliest_index = 0, i;
303   GstBuffer *buf;
305   if (self->backlog_nframes == 0)
306     return GST_FLOW_OK;
308   /* work out which frame has the earliest poc */
309   for (i = 0; i < self->backlog_nframes; i++) {
310     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
311     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
312       earliest_order = order;
313       earliest_index = i;
314     }
315   }
317   /* send it, giving away the ref */
318   buf = self->backlog_frames[earliest_index];
319   self->backlog_frames[earliest_index] =
320       self->backlog_frames[--self->backlog_nframes];
321   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
322       buf);
323   return gst_pad_push (self->srcpad, buf);
326 static void
327 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
329   /* push everything on the backlog, ignoring errors */
330   while (self->backlog_nframes > 0) {
331     gst_ducati_viddec_push_earliest (self);
332   }
335 static gint
336 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
337     GstFlowReturn * flow_ret)
339   gint err;
340   GstClockTime t;
341   GstBuffer *outbuf = NULL;
342   gint i;
343   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
344   GstFlowReturn ret = GST_FLOW_OK;
345   if (flow_ret)
346     /* never leave flow_ret uninitialized */
347     *flow_ret = GST_FLOW_OK;
349   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
350   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
352   t = gst_util_get_timestamp ();
353   err = VIDDEC3_process (self->codec,
354       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
355   GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
357   if (err) {
358     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
359         err, self->outArgs->extendedError);
360     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
362     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
363         self->dynParams, self->status);
364     if (err) {
365       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
366           err, self->status->extendedError);
367       gst_ducati_log_extended_error_info (self->status->extendedError);
368     }
370     if (flush)
371       err = XDM_EFAIL;
372     else
373       err = klass->handle_error (self, err,
374           self->outArgs->extendedError, self->status->extendedError);
375   }
377   /* we now let the codec decide */
378   self->dynParams->newFrameFlag = XDAS_FALSE;
380   if (err == XDM_EFAIL)
381     goto skip_outbuf_processing;
383   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
384     gboolean interlaced;
386     /* Getting an extra reference for the decoder */
387     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
388     interlaced =
389         self->outArgs->decodedBufs.contentType ==
390         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
392     /* if send is FALSE, don't try to renegotiate as we could be flushing during
393      * a PAUSED->READY state change
394      */
395     if (send && interlaced != self->interlaced) {
396       GstCaps *caps;
398       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
399           "thinks interlaced=%d... trusting codec", self->interlaced,
400           interlaced);
402       self->interlaced = interlaced;
404       caps =
405           gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
406       GST_INFO_OBJECT (self, "changing interlace field in caps");
407       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
408           NULL);
409       gst_drm_buffer_pool_set_caps (self->pool, caps);
410       if (!gst_pad_set_caps (self->srcpad, caps)) {
411         GST_ERROR_OBJECT (self,
412             "downstream didn't want to change interlace mode");
413         err = XDM_EFAIL;
414       }
415       gst_caps_unref (caps);
417       /* this buffer still has the old caps so we skip it */
418       send = FALSE;
419     }
421     if (G_UNLIKELY (self->send_crop_event) && send) {
422       gint crop_width, crop_height;
424       /* send region of interest to sink on first buffer: */
425       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
427       crop_width = r->bottomRight.x - r->topLeft.x;
428       crop_height = r->bottomRight.y - r->topLeft.y;
430       if (crop_width > self->input_width)
431         crop_width = self->input_width;
432       if (crop_height > self->input_height)
433         crop_height = self->input_height;
435       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
436           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
437           crop_width, crop_height);
439       gst_pad_push_event (self->srcpad,
440           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
441               crop_width, crop_height));
443       if (self->crop)
444         gst_video_crop_unref (self->crop);
446       self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
447           crop_width, crop_height);
449       self->send_crop_event = FALSE;
450     }
452     if (G_UNLIKELY (self->first_out_buffer) && send) {
453       GstDRMBufferPool *pool;
454       self->first_out_buffer = FALSE;
456       /* Destroy the pool so the buffers we used so far are eventually released.
457        * The pool will be recreated if needed.
458        */
459       pool = self->pool;
460       self->pool = NULL;
461       gst_drm_buffer_pool_destroy (pool);
462     }
464     if (send) {
465       GstClockTime ts;
467       ts = GST_BUFFER_TIMESTAMP (outbuf);
469       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
470           i, outbuf, GST_TIME_ARGS (ts));
472 #ifdef USE_DTS_PTS_CODE
473       if (self->ts_may_be_pts) {
474         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
475           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
476               "enabling ts_is_pts");
477           self->ts_is_pts = TRUE;
478         }
479       }
480 #endif
482       self->last_pts = ts;
484       if (self->dts_ridx != self->dts_widx) {
485         ts = self->dts_queue[self->dts_ridx++ % NDTS];
486       }
488       if (self->ts_is_pts) {
489         /* if we have a queued DTS from demuxer, use that instead: */
490         GST_BUFFER_TIMESTAMP (outbuf) = ts;
491         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
492             i, outbuf, GST_TIME_ARGS (ts));
493       }
495       if (GST_BUFFER_CAPS (outbuf) &&
496           !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
497               GST_PAD_CAPS (self->srcpad))) {
498         /* this looks a bit scary but it's really just to change the interlace=
499          * field in caps when we start as !interlaced and the codec detects
500          * otherwise */
501         GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
502             "interlace mismatch");
503         outbuf = gst_buffer_make_metadata_writable (outbuf);
504         gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
505       }
507       if (self->crop)
508         gst_buffer_set_video_crop (outbuf, self->crop);
510       ret = klass->push_output (self, outbuf);
511       if (flow_ret)
512         *flow_ret = ret;
513       if (ret != GST_FLOW_OK) {
514         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
515         /* just unref the remaining buffers (if any) */
516         send = FALSE;
517       }
518     } else {
519       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
520           i, outbuf);
522       gst_buffer_unref (outbuf);
523     }
524   }
526 skip_outbuf_processing:
527   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
528     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
529   }
531   return err;
534 /** call control(FLUSH), and then process() to pop out all buffers */
535 gboolean
536 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
538   gint err = FALSE;
540   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
542   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
544   /* note: flush is synchronized against _chain() to avoid calling
545    * the codec from multiple threads
546    */
547   GST_PAD_STREAM_LOCK (self->sinkpad);
549 #ifdef USE_DTS_PTS_CODE
550   self->dts_ridx = self->dts_widx = 0;
551   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
552   self->ts_may_be_pts = TRUE;
553   self->ts_is_pts = FALSE;
554 #endif
555   self->wait_keyframe = TRUE;
556   self->in_size = 0;
557   self->needs_flushing = FALSE;
558   self->need_out_buf = TRUE;
560   if (G_UNLIKELY (self->first_in_buffer)) {
561     goto out;
562   }
564   if (G_UNLIKELY (!self->codec)) {
565     GST_WARNING_OBJECT (self, "no codec");
566     goto out;
567   }
569   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
570   if (err) {
571     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
572     goto out;
573   }
575   self->inBufs->descs[0].bufSize.bytes = 0;
576   self->inBufs->numBufs = 0;
577   self->inArgs->numBytes = 0;
578   self->inArgs->inputID = 0;
579   self->outBufs->numBufs = 0;
581   do {
582     err = codec_process (self, eos, TRUE, NULL);
583   } while (err != XDM_EFAIL);
585   /* We flushed the decoder, we can now remove the buffer that have never been
586    * unrefed in it */
587   g_hash_table_remove_all (self->passed_in_bufs);
589   /* reset outArgs in case we're flushing in codec_process trying to do error
590    * recovery */
591   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
592   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
594   self->dynParams->newFrameFlag = XDAS_TRUE;
596   /* Reset the push buffer and YUV buffers */
597   self->inBufs->numBufs = 1;
598   self->outBufs->numBufs = 2;
600   /* on a flush, it is normal (and not an error) for the last _process() call
601    * to return an error..
602    */
603   err = XDM_EOK;
605 out:
606   GST_PAD_STREAM_UNLOCK (self->sinkpad);
607   GST_DEBUG_OBJECT (self, "done");
609   return !err;
612 /* GstDucatiVidDec vmethod default implementations */
614 static gboolean
615 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
617   const GValue *codec_data;
618   gint w, h;
620   if (gst_structure_get_int (s, "width", &self->input_width) &&
621       gst_structure_get_int (s, "height", &self->input_height)) {
623     h = ALIGN2 (self->input_height, 4); /* round up to MB */
624     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
626     /* if we've already created codec, but the resolution has changed, we
627      * need to re-create the codec:
628      */
629     if (G_UNLIKELY (self->codec)) {
630       if ((h != self->height) || (w != self->width)) {
631         codec_delete (self);
632       }
633     }
635     self->width = w;
636     self->height = h;
638     codec_data = gst_structure_get_value (s, "codec_data");
640     if (codec_data) {
641       GstBuffer *buffer = gst_value_get_buffer (codec_data);
642       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
643       self->codec_data = gst_buffer_ref (buffer);
644     }
646     return TRUE;
647   }
649   return FALSE;
652 static gboolean
653 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
654     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
657   /* allocate params: */
658   self->params = dce_alloc (params_sz);
659   if (G_UNLIKELY (!self->params)) {
660     return FALSE;
661   }
662   self->params->size = params_sz;
663   self->params->maxFrameRate = 30000;
664   self->params->maxBitRate = 10000000;
666   self->params->dataEndianness = XDM_BYTE;
667   self->params->forceChromaFormat = XDM_YUV_420SP;
668   self->params->operatingMode = IVIDEO_DECODE_ONLY;
670   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
671   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
672   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
673   self->params->numInputDataUnits = 0;
674   self->params->numOutputDataUnits = 0;
676   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
677   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
678   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
679   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
681   /* allocate dynParams: */
682   self->dynParams = dce_alloc (dynparams_sz);
683   if (G_UNLIKELY (!self->dynParams)) {
684     return FALSE;
685   }
686   self->dynParams->size = dynparams_sz;
687   self->dynParams->decodeHeader = XDM_DECODE_AU;
688   self->dynParams->displayWidth = 0;
689   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
690   self->dynParams->newFrameFlag = XDAS_TRUE;
692   /* allocate status: */
693   self->status = dce_alloc (status_sz);
694   if (G_UNLIKELY (!self->status)) {
695     return FALSE;
696   }
697   memset (self->status, 0, status_sz);
698   self->status->size = status_sz;
700   /* allocate inBufs/outBufs: */
701   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
702   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
703   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
704     return FALSE;
705   }
707   /* allocate inArgs/outArgs: */
708   self->inArgs = dce_alloc (inargs_sz);
709   self->outArgs = dce_alloc (outargs_sz);
710   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
711     return FALSE;
712   }
713   self->inArgs->size = inargs_sz;
714   self->outArgs->size = outargs_sz;
716   return TRUE;
719 static GstBuffer *
720 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
722   /* If we're about to push a keyframe, then we can flush all the frames
723      we currently have queued. For formats such as H264, this is actually
724      necessary as picture order count is local to each IDR + set of non
725      IDR frames, so will restart at 0 when next IDR frames comes in. For
726      other formats, it is not necessary, but avoids buffering frames that
727      do not need to be. */
728   if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
729     GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
730         self->backlog_nframes);
731     while (self->backlog_nframes > 0) {
732       gst_ducati_viddec_push_earliest (self);
733     }
734   }
736   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
737     push_input (self, GST_BUFFER_DATA (self->codec_data),
738         GST_BUFFER_SIZE (self->codec_data));
739   }
741   /* just copy entire buffer */
742   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
743   gst_buffer_unref (buf);
745   return NULL;
748 static GstFlowReturn
749 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
751   GstFlowReturn ret = GST_FLOW_OK;
753   /* add the frame to the list, the array will own the ref */
754   GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
755   self->backlog_frames[self->backlog_nframes++] = buf;
757   /* push till we have no more than the max needed, or error */
758   while (self->backlog_nframes > self->backlog_maxframes) {
759     ret = gst_ducati_viddec_push_earliest (self);
760     if (ret != GST_FLOW_OK)
761       break;
762   }
764   return ret;
767 static gint
768 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
769     gint extended_error, gint status_extended_error)
771   if (XDM_ISFATALERROR (extended_error))
772     ret = XDM_EFAIL;
773   else
774     ret = XDM_EOK;
776   return ret;
779 /* GstElement vmethod implementations */
781 static gboolean
782 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
784   gboolean ret = TRUE;
785   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
786   GstStructure *s;
787   GstCaps *outcaps = NULL;
788   GstStructure *out_s;
789   gint par_width, par_height;
790   gboolean par_present;
792   s = gst_caps_get_structure (caps, 0);
793   if (!klass->parse_caps (self, s)) {
794     GST_WARNING_OBJECT (self, "missing required fields");
795     ret = FALSE;
796     goto out;
797   }
799   /* update output/padded sizes */
800   klass->update_buffer_size (self);
802   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
803     self->fps_n = 0;
804     self->fps_d = 1;
805   }
806   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
807   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
808       &par_width, &par_height);
810   outcaps = gst_pad_get_allowed_caps (self->srcpad);
811   if (outcaps) {
812     outcaps = gst_caps_make_writable (outcaps);
813     gst_caps_truncate (outcaps);
814     if (gst_caps_is_empty (outcaps)) {
815       gst_caps_unref (outcaps);
816       outcaps = NULL;
817     }
818   }
820   if (!outcaps) {
821     /* note: default to non-strided for better compatibility with
822      * other gst elements that don't understand stride:
823      */
824     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
825         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
826   }
828   out_s = gst_caps_get_structure (outcaps, 0);
829   gst_structure_set (out_s,
830       "width", G_TYPE_INT, self->padded_width,
831       "height", G_TYPE_INT, self->padded_height,
832       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
833   if (par_present)
834     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
835         par_width, par_height, NULL);
837   if (self->interlaced)
838     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
840   if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
841     if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
842       self->stride = 4096;
843       gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
844     }
845   } else {
846     self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
847         0, self->padded_width);
848   }
850   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
851       self->stride, self->padded_height);
853   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
854       self->outsize, self->stride, outcaps);
856   if (!self->first_in_buffer) {
857     /* Caps changed mid stream. We flush the codec to unlock all the potentially
858      * locked buffers. This is needed for downstream sinks that provide a
859      * buffer pool and need to destroy all the outstanding buffers before they
860      * can negotiate new caps (hello v4l2sink).
861      */
862     gst_ducati_viddec_codec_flush (self, FALSE);
863   }
865   /* (re)send a crop event when caps change */
866   self->send_crop_event = TRUE;
868   ret = gst_pad_set_caps (self->srcpad, outcaps);
870   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
872   /* default to no reordering */
873   self->backlog_maxframes = 0;
875 out:
876   if (outcaps)
877     gst_caps_unref (outcaps);
879   return ret;
882 static gboolean
883 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
885   gboolean ret = TRUE;
886   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
887   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
889   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
891   ret = klass->set_sink_caps (self, caps);
893   gst_object_unref (self);
895   return ret;
898 static GstCaps *
899 gst_ducati_viddec_src_getcaps (GstPad * pad)
901   GstCaps *caps = NULL;
902   GstCaps *outcaps = NULL;
903   int i;
905   caps = GST_PAD_CAPS (pad);
906   if (caps == NULL) {
907     outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
908     return outcaps;
909   }
911   outcaps = gst_caps_new_empty ();
913   /* allow -rowstrided and regular yuv */
914   for (i = 0; i < gst_caps_get_size (caps); i++) {
915     GstStructure *structure;
916     GstStructure *modified_structure;
917     GValue value = { 0 };
919     structure = gst_caps_get_structure (caps, i);
920     gst_caps_append_structure (outcaps, gst_structure_copy (structure));
921     modified_structure = gst_structure_copy (structure);
923     if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
924       gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
925       g_value_init (&value, GST_TYPE_INT_RANGE);
926       gst_value_set_int_range (&value, 0, G_MAXINT);
927       gst_structure_set_value (modified_structure, "rowstride", &value);
928       gst_caps_append_structure (outcaps, modified_structure);
929       g_value_unset (&value);
930     } else {
931       gst_structure_set_name (modified_structure, "video/x-raw-yuv");
932       gst_structure_remove_field (modified_structure, "rowstride");
933       gst_caps_append_structure (outcaps, modified_structure);
934     }
935   }
936   return outcaps;
939 static gboolean
940 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
941     GstQuery * query, gboolean * forward)
943   gboolean res = TRUE;
945   switch (GST_QUERY_TYPE (query)) {
946     case GST_QUERY_BUFFERS:
947       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
948       gst_query_set_buffers_count (query, self->min_buffers);
950       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
951           self->padded_width, self->padded_height);
952       gst_query_set_buffers_dimensions (query,
953           self->padded_width, self->padded_height);
954       *forward = FALSE;
955       break;
956     default:
957       break;
958   }
961   return res;
964 static gboolean
965 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
967   gboolean res = TRUE, forward = TRUE;
968   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
969   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
971   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
972   res = klass->query (self, pad, query, &forward);
973   if (res && forward)
974     res = gst_pad_query_default (pad, query);
976   return res;
979 static gboolean
980 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
982   GstClockTime timestamp, qostime;
983   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
984   gint64 diff;
986   if (self->wait_keyframe) {
987     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
988       GST_INFO_OBJECT (self, "skipping until the next keyframe");
989       return FALSE;
990     }
992     self->wait_keyframe = FALSE;
993   }
995   timestamp = GST_BUFFER_TIMESTAMP (buf);
996   if (self->segment.format != GST_FORMAT_TIME ||
997       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
998     goto no_qos;
1000   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1001     goto no_qos;
1003   qostime = gst_segment_to_running_time (&self->segment,
1004       GST_FORMAT_TIME, timestamp);
1005   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1006     /* out of segment */
1007     goto no_qos;
1009   /* see how our next timestamp relates to the latest qos timestamp. negative
1010    * values mean we are early, positive values mean we are too late. */
1011   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1013   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1014       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1015       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1016       self->qos_proportion);
1018   if (klass->can_drop_frame (self, buf, diff)) {
1019     GST_INFO_OBJECT (self, "dropping frame");
1020     return FALSE;
1021   }
1023 no_qos:
1024   return TRUE;
1027 static gboolean
1028 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1029     gint64 diff)
1031   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1032       GST_BUFFER_FLAG_DELTA_UNIT);
1034   if (diff >= 0 && !is_keyframe)
1035     return TRUE;
1037   return FALSE;
1040 static GstFlowReturn
1041 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1043   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1044   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1045   GstFlowReturn ret = GST_FLOW_OK;
1046   Int32 err;
1047   GstBuffer *outbuf = NULL;
1048   GstCaps *outcaps = NULL;
1049   gboolean decode;
1051   if (G_UNLIKELY (!self->engine)) {
1052     GST_ERROR_OBJECT (self, "no engine");
1053     gst_buffer_unref (buf);
1054     return GST_FLOW_ERROR;
1055   }
1057   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1058       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1060   decode = gst_ducati_viddec_do_qos (self, buf);
1061   if (!decode) {
1062     gst_buffer_unref (buf);
1063     return GST_FLOW_OK;
1064   }
1066   if (!self->need_out_buf)
1067     goto have_out_buf;
1069   /* do this before creating codec to ensure reverse caps negotiation
1070    * happens first:
1071    */
1072 allocate_buffer:
1073   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1074       GST_PAD_CAPS (self->srcpad), &outbuf);
1075   if (ret != GST_FLOW_OK) {
1076     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1077         gst_flow_get_name (ret));
1078     gst_buffer_unref (buf);
1079     return ret;
1080   }
1082   outcaps = GST_BUFFER_CAPS (outbuf);
1083   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1084     GstStructure *s;
1086     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1087         GST_BUFFER_SIZE (outbuf));
1089     s = gst_caps_get_structure (outcaps, 0);
1090     gst_structure_get_int (s, "rowstride", &self->stride);
1091     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1092         self->stride, self->padded_height);
1094     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1095         self->outsize, self->stride, outcaps);
1097     gst_pad_set_caps (self->srcpad, outcaps);
1099     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1100       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1101           GST_BUFFER_SIZE (outbuf), self->outsize);
1102       gst_buffer_unref (outbuf);
1103       goto allocate_buffer;
1104     }
1105   }
1107   if (G_UNLIKELY (!self->codec)) {
1108     if (!codec_create (self)) {
1109       GST_ERROR_OBJECT (self, "could not create codec");
1110       gst_buffer_unref (buf);
1111       gst_buffer_unref (outbuf);
1112       return GST_FLOW_ERROR;
1113     }
1114   }
1116   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1117   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1119   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1120    * internal pool while self->first_out_buffer == TRUE in order to simplify
1121    * things in case we need to renegotiate */
1122   self->inArgs->inputID =
1123       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1124   if (!self->inArgs->inputID) {
1125     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1126     gst_buffer_unref (buf);
1127     return GST_FLOW_ERROR;
1128   }
1129   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1131 have_out_buf:
1132   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1134 #ifdef USE_DTS_PTS_CODE
1135   if (ts != GST_CLOCK_TIME_NONE) {
1136     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1137     /* if next buffer has earlier ts than previous, then the ts
1138      * we are getting are definitely decode order (DTS):
1139      */
1140     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1141       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1142       self->ts_may_be_pts = FALSE;
1143     }
1144     self->last_dts = ts;
1145   }
1146 #endif
1148   if (self->in_size == 0 && outbuf) {
1149     GST_DEBUG_OBJECT (self, "no input, skipping process");
1151     gst_buffer_unref (outbuf);
1152     return GST_FLOW_OK;
1153   }
1155   self->inArgs->numBytes = self->in_size;
1156   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1157   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1159   err = codec_process (self, TRUE, FALSE, &ret);
1160   if (err) {
1161     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1162         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1163     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1165     return GST_FLOW_ERROR;
1166   }
1168   if (ret != GST_FLOW_OK) {
1169     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1170         gst_flow_get_name (ret));
1172     return ret;
1173   }
1175   self->first_in_buffer = FALSE;
1177   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1178     /* The copy could be avoided by playing with the buffer pointer,
1179        but it seems to be rare and for not many bytes */
1180     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1181         self->outArgs->bytesConsumed, self->in_size,
1182         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1183     if (self->outArgs->bytesConsumed > 0) {
1184       if (self->outArgs->bytesConsumed > self->in_size) {
1185         GST_WARNING_OBJECT (self,
1186             "Codec claims to have used more bytes than supplied");
1187         self->in_size = 0;
1188       } else {
1189         if (self->outArgs->bytesConsumed < self->in_size) {
1190           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1191               self->in_size - self->outArgs->bytesConsumed);
1192         }
1193         self->in_size -= self->outArgs->bytesConsumed;
1194       }
1195     }
1196   } else {
1197     self->in_size = 0;
1198   }
1200   if (self->outArgs->outBufsInUseFlag) {
1201     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1202     self->need_out_buf = FALSE;
1203   } else {
1204     self->need_out_buf = TRUE;
1205   }
1207   if (buf) {
1208     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1209         GST_BUFFER_SIZE (buf));
1210     ts = GST_BUFFER_TIMESTAMP (buf);
1211     goto allocate_buffer;
1212   }
1214   if (self->needs_flushing)
1215     gst_ducati_viddec_codec_flush (self, FALSE);
1217   return GST_FLOW_OK;
1220 static gboolean
1221 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1223   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1224   gboolean ret = TRUE;
1226   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1228   switch (GST_EVENT_TYPE (event)) {
1229     case GST_EVENT_NEWSEGMENT:
1230     {
1231       gboolean update;
1232       GstFormat fmt;
1233       gint64 start, stop, time;
1234       gdouble rate, arate;
1236       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1237           &start, &stop, &time);
1238       gst_segment_set_newsegment_full (&self->segment, update,
1239           rate, arate, fmt, start, stop, time);
1240       break;
1241     }
1242     case GST_EVENT_EOS:
1243       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1244         GST_ERROR_OBJECT (self, "could not flush on eos");
1245         ret = FALSE;
1246       }
1247       break;
1248     case GST_EVENT_FLUSH_STOP:
1249       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1250         GST_ERROR_OBJECT (self, "could not flush");
1251         gst_event_unref (event);
1252         ret = FALSE;
1253       }
1254       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1255       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1256       self->qos_proportion = 1;
1257       self->need_out_buf = TRUE;
1258       break;
1259     default:
1260       break;
1261   }
1263   if (ret)
1264     ret = gst_pad_push_event (self->srcpad, event);
1265   GST_LOG_OBJECT (self, "end");
1267   return ret;
1270 static gboolean
1271 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1273   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1274   gboolean ret = TRUE;
1276   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1278   switch (GST_EVENT_TYPE (event)) {
1279     case GST_EVENT_QOS:
1280     {
1281       gdouble proportion;
1282       GstClockTimeDiff diff;
1283       GstClockTime timestamp;
1285       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1287       GST_OBJECT_LOCK (self);
1288       self->qos_proportion = proportion;
1289       self->qos_earliest_time = timestamp + 2 * diff;
1290       GST_OBJECT_UNLOCK (self);
1292       GST_DEBUG_OBJECT (self,
1293           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1294           proportion, GST_TIME_ARGS (timestamp), diff);
1296       ret = gst_pad_push_event (self->sinkpad, event);
1297       break;
1298     }
1299     default:
1300       ret = gst_pad_push_event (self->sinkpad, event);
1301       break;
1302   }
1304   GST_LOG_OBJECT (self, "end");
1306   return ret;
1309 static GstStateChangeReturn
1310 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1312   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1313   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1314   gboolean supported;
1316   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1317       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1318       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1320   switch (transition) {
1321     case GST_STATE_CHANGE_NULL_TO_READY:
1322       if (!engine_open (self)) {
1323         GST_ERROR_OBJECT (self, "could not open");
1324         return GST_STATE_CHANGE_FAILURE;
1325       }
1326       /* try to create/destroy the codec here, it may not be supported */
1327       supported = codec_create (self);
1328       codec_delete (self);
1329       self->codec = NULL;
1330       if (!supported) {
1331         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1332             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1333         engine_close (self);
1334         return GST_STATE_CHANGE_FAILURE;
1335       }
1336       break;
1337     default:
1338       break;
1339   }
1341   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1343   if (ret == GST_STATE_CHANGE_FAILURE)
1344     goto leave;
1346   switch (transition) {
1347     case GST_STATE_CHANGE_PAUSED_TO_READY:
1348       self->interlaced = FALSE;
1349       self->send_crop_event = TRUE;
1350       gst_ducati_viddec_codec_flush (self, FALSE);
1351       break;
1352     case GST_STATE_CHANGE_READY_TO_NULL:
1353       codec_delete (self);
1354       engine_close (self);
1355       break;
1356     default:
1357       break;
1358   }
1360 leave:
1361   GST_LOG_OBJECT (self, "end");
1363   return ret;
1366 /* GObject vmethod implementations */
1368 #define VERSION_LENGTH 256
1370 static void
1371 gst_ducati_viddec_get_property (GObject * obj,
1372     guint prop_id, GValue * value, GParamSpec * pspec)
1374   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1377   switch (prop_id) {
1378     case PROP_VERSION:{
1379       int err;
1380       char *version = NULL;
1382       if (!self->engine)
1383         engine_open (self);
1385       if (!self->codec)
1386         codec_create (self);
1388       if (self->codec) {
1389         version = dce_alloc (VERSION_LENGTH);
1390         self->status->data.buf = (XDAS_Int8 *) version;
1391         self->status->data.bufSize = VERSION_LENGTH;
1393         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1394             self->dynParams, self->status);
1395         if (err) {
1396           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1397         }
1399         self->status->data.buf = NULL;
1400         self->status->data.bufSize = 0;
1401       }
1403       g_value_set_string (value, version);
1404       if (version)
1405         dce_free (version);
1407       break;
1408     }
1409     case PROP_MAX_REORDER_FRAMES:
1410       g_value_set_int (value, self->backlog_default_maxframes);
1411       break;
1412     default:{
1413       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1414       break;
1415     }
1416   }
1419 static void
1420 gst_ducati_viddec_set_property (GObject * obj,
1421     guint prop_id, const GValue * value, GParamSpec * pspec)
1423   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1425   switch (prop_id) {
1426     case PROP_MAX_REORDER_FRAMES:
1427       self->backlog_default_maxframes = g_value_get_int (value);
1428       break;
1429     default:{
1430       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1431       break;
1432     }
1433   }
1436 static void
1437 gst_ducati_viddec_finalize (GObject * obj)
1439   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1441   codec_delete (self);
1442   engine_close (self);
1444   /* Will unref the remaining buffers if needed */
1445   g_hash_table_unref (self->passed_in_bufs);
1446   if (self->codec_data) {
1447     gst_buffer_unref (self->codec_data);
1448     self->codec_data = NULL;
1449   }
1451   G_OBJECT_CLASS (parent_class)->finalize (obj);
1454 static void
1455 gst_ducati_viddec_base_init (gpointer gclass)
1457   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1459   gst_element_class_add_pad_template (element_class,
1460       gst_static_pad_template_get (&src_factory));
1463 static void
1464 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1466   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1467   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1469   gobject_class->get_property =
1470       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1471   gobject_class->set_property =
1472       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1473   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1474   gstelement_class->change_state =
1475       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1477   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1478   klass->allocate_params =
1479       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1480   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1481   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1482   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1483   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1484   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1485   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1486   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1488   g_object_class_install_property (gobject_class, PROP_VERSION,
1489       g_param_spec_string ("version", "Version",
1490           "The codec version string", "",
1491           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1493   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1494       g_param_spec_int ("max-reorder-frames",
1495           "Maximum number of frames needed for reordering",
1496           "The maximum number of frames needed for reordering output frames. "
1497           "Only meaningful for codecs with B frames. 0 means no reordering. "
1498           "This value will be used if the correct value cannot be inferred "
1499           "from the stream. Too low a value may cause misordering, too high "
1500           "will cause extra latency.",
1501           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1502           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1505 static void
1506 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1508   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1510   self->sinkpad =
1511       gst_pad_new_from_template (gst_element_class_get_pad_template
1512       (gstelement_class, "sink"), "sink");
1513   gst_pad_set_setcaps_function (self->sinkpad,
1514       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1515   gst_pad_set_chain_function (self->sinkpad,
1516       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1517   gst_pad_set_event_function (self->sinkpad,
1518       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1520   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1521   gst_pad_set_event_function (self->srcpad,
1522       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1523   gst_pad_set_query_function (self->srcpad,
1524       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1525   gst_pad_set_getcaps_function (self->srcpad,
1526       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1528   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1529   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1531   self->input_width = 0;
1532   self->input_height = 0;
1533   /* sane defaults in case we need to create codec without caps negotiation
1534    * (for example, to get 'version' property)
1535    */
1536   self->width = 128;
1537   self->height = 128;
1538   self->fps_n = -1;
1539   self->fps_d = -1;
1541   self->first_in_buffer = TRUE;
1542   self->first_out_buffer = TRUE;
1543   self->interlaced = FALSE;
1544   self->send_crop_event = TRUE;
1546 #ifdef USE_DTS_PTS_CODE
1547   self->dts_ridx = self->dts_widx = 0;
1548   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1549   self->ts_may_be_pts = TRUE;
1550   self->ts_is_pts = FALSE;
1551 #endif
1553   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1555   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1557   self->qos_proportion = 1;
1558   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1559   self->wait_keyframe = TRUE;
1561   self->need_out_buf = TRUE;
1562   self->device = NULL;
1563   self->input_bo = NULL;
1565   self->backlog_maxframes = 0;
1566   self->backlog_nframes = 0;
1567   self->backlog_default_maxframes = MAX_BACKLOG_FRAMES;
1569   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1570       NULL, (GDestroyNotify) gst_buffer_unref);