ducatividdec: do not reorder frames when reordering info is absent
[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   /* if no reordering info was set, just send the buffer */
754   if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
755     GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
756     return gst_pad_push (self->srcpad, buf);
757   }
759   /* add the frame to the list, the array will own the ref */
760   GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
761   self->backlog_frames[self->backlog_nframes++] = buf;
763   /* push till we have no more than the max needed, or error */
764   while (self->backlog_nframes > self->backlog_maxframes) {
765     ret = gst_ducati_viddec_push_earliest (self);
766     if (ret != GST_FLOW_OK)
767       break;
768   }
770   return ret;
773 static gint
774 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
775     gint extended_error, gint status_extended_error)
777   if (XDM_ISFATALERROR (extended_error))
778     ret = XDM_EFAIL;
779   else
780     ret = XDM_EOK;
782   return ret;
785 /* GstElement vmethod implementations */
787 static gboolean
788 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
790   gboolean ret = TRUE;
791   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
792   GstStructure *s;
793   GstCaps *outcaps = NULL;
794   GstStructure *out_s;
795   gint par_width, par_height;
796   gboolean par_present;
798   s = gst_caps_get_structure (caps, 0);
799   if (!klass->parse_caps (self, s)) {
800     GST_WARNING_OBJECT (self, "missing required fields");
801     ret = FALSE;
802     goto out;
803   }
805   /* update output/padded sizes */
806   klass->update_buffer_size (self);
808   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
809     self->fps_n = 0;
810     self->fps_d = 1;
811   }
812   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
813   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
814       &par_width, &par_height);
816   outcaps = gst_pad_get_allowed_caps (self->srcpad);
817   if (outcaps) {
818     outcaps = gst_caps_make_writable (outcaps);
819     gst_caps_truncate (outcaps);
820     if (gst_caps_is_empty (outcaps)) {
821       gst_caps_unref (outcaps);
822       outcaps = NULL;
823     }
824   }
826   if (!outcaps) {
827     /* note: default to non-strided for better compatibility with
828      * other gst elements that don't understand stride:
829      */
830     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
831         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
832   }
834   out_s = gst_caps_get_structure (outcaps, 0);
835   gst_structure_set (out_s,
836       "width", G_TYPE_INT, self->padded_width,
837       "height", G_TYPE_INT, self->padded_height,
838       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
839   if (par_present)
840     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
841         par_width, par_height, NULL);
843   if (self->interlaced)
844     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
846   if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
847     if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
848       self->stride = 4096;
849       gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
850     }
851   } else {
852     self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
853         0, self->padded_width);
854   }
856   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
857       self->stride, self->padded_height);
859   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
860       self->outsize, self->stride, outcaps);
862   if (!self->first_in_buffer) {
863     /* Caps changed mid stream. We flush the codec to unlock all the potentially
864      * locked buffers. This is needed for downstream sinks that provide a
865      * buffer pool and need to destroy all the outstanding buffers before they
866      * can negotiate new caps (hello v4l2sink).
867      */
868     gst_ducati_viddec_codec_flush (self, FALSE);
869   }
871   /* (re)send a crop event when caps change */
872   self->send_crop_event = TRUE;
874   ret = gst_pad_set_caps (self->srcpad, outcaps);
876   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
878   /* default to no reordering */
879   self->backlog_maxframes = 0;
881 out:
882   if (outcaps)
883     gst_caps_unref (outcaps);
885   return ret;
888 static gboolean
889 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
891   gboolean ret = TRUE;
892   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
893   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
895   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
897   ret = klass->set_sink_caps (self, caps);
899   gst_object_unref (self);
901   return ret;
904 static GstCaps *
905 gst_ducati_viddec_src_getcaps (GstPad * pad)
907   GstCaps *caps = NULL;
908   GstCaps *outcaps = NULL;
909   int i;
911   caps = GST_PAD_CAPS (pad);
912   if (caps == NULL) {
913     outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
914     return outcaps;
915   }
917   outcaps = gst_caps_new_empty ();
919   /* allow -rowstrided and regular yuv */
920   for (i = 0; i < gst_caps_get_size (caps); i++) {
921     GstStructure *structure;
922     GstStructure *modified_structure;
923     GValue value = { 0 };
925     structure = gst_caps_get_structure (caps, i);
926     gst_caps_append_structure (outcaps, gst_structure_copy (structure));
927     modified_structure = gst_structure_copy (structure);
929     if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
930       gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
931       g_value_init (&value, GST_TYPE_INT_RANGE);
932       gst_value_set_int_range (&value, 0, G_MAXINT);
933       gst_structure_set_value (modified_structure, "rowstride", &value);
934       gst_caps_append_structure (outcaps, modified_structure);
935       g_value_unset (&value);
936     } else {
937       gst_structure_set_name (modified_structure, "video/x-raw-yuv");
938       gst_structure_remove_field (modified_structure, "rowstride");
939       gst_caps_append_structure (outcaps, modified_structure);
940     }
941   }
942   return outcaps;
945 static gboolean
946 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
947     GstQuery * query, gboolean * forward)
949   gboolean res = TRUE;
951   switch (GST_QUERY_TYPE (query)) {
952     case GST_QUERY_BUFFERS:
953       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
954       gst_query_set_buffers_count (query, self->min_buffers);
956       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
957           self->padded_width, self->padded_height);
958       gst_query_set_buffers_dimensions (query,
959           self->padded_width, self->padded_height);
960       *forward = FALSE;
961       break;
962     default:
963       break;
964   }
967   return res;
970 static gboolean
971 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
973   gboolean res = TRUE, forward = TRUE;
974   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
975   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
977   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
978   res = klass->query (self, pad, query, &forward);
979   if (res && forward)
980     res = gst_pad_query_default (pad, query);
982   return res;
985 static gboolean
986 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
988   GstClockTime timestamp, qostime;
989   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
990   gint64 diff;
992   if (self->wait_keyframe) {
993     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
994       GST_INFO_OBJECT (self, "skipping until the next keyframe");
995       return FALSE;
996     }
998     self->wait_keyframe = FALSE;
999   }
1001   timestamp = GST_BUFFER_TIMESTAMP (buf);
1002   if (self->segment.format != GST_FORMAT_TIME ||
1003       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1004     goto no_qos;
1006   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1007     goto no_qos;
1009   qostime = gst_segment_to_running_time (&self->segment,
1010       GST_FORMAT_TIME, timestamp);
1011   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1012     /* out of segment */
1013     goto no_qos;
1015   /* see how our next timestamp relates to the latest qos timestamp. negative
1016    * values mean we are early, positive values mean we are too late. */
1017   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1019   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1020       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1021       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1022       self->qos_proportion);
1024   if (klass->can_drop_frame (self, buf, diff)) {
1025     GST_INFO_OBJECT (self, "dropping frame");
1026     return FALSE;
1027   }
1029 no_qos:
1030   return TRUE;
1033 static gboolean
1034 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1035     gint64 diff)
1037   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1038       GST_BUFFER_FLAG_DELTA_UNIT);
1040   if (diff >= 0 && !is_keyframe)
1041     return TRUE;
1043   return FALSE;
1046 static GstFlowReturn
1047 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1049   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1050   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1051   GstFlowReturn ret = GST_FLOW_OK;
1052   Int32 err;
1053   GstBuffer *outbuf = NULL;
1054   GstCaps *outcaps = NULL;
1055   gboolean decode;
1057   if (G_UNLIKELY (!self->engine)) {
1058     GST_ERROR_OBJECT (self, "no engine");
1059     gst_buffer_unref (buf);
1060     return GST_FLOW_ERROR;
1061   }
1063   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1064       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1066   decode = gst_ducati_viddec_do_qos (self, buf);
1067   if (!decode) {
1068     gst_buffer_unref (buf);
1069     return GST_FLOW_OK;
1070   }
1072   if (!self->need_out_buf)
1073     goto have_out_buf;
1075   /* do this before creating codec to ensure reverse caps negotiation
1076    * happens first:
1077    */
1078 allocate_buffer:
1079   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1080       GST_PAD_CAPS (self->srcpad), &outbuf);
1081   if (ret != GST_FLOW_OK) {
1082     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1083         gst_flow_get_name (ret));
1084     gst_buffer_unref (buf);
1085     return ret;
1086   }
1088   outcaps = GST_BUFFER_CAPS (outbuf);
1089   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1090     GstStructure *s;
1092     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1093         GST_BUFFER_SIZE (outbuf));
1095     s = gst_caps_get_structure (outcaps, 0);
1096     gst_structure_get_int (s, "rowstride", &self->stride);
1097     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1098         self->stride, self->padded_height);
1100     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1101         self->outsize, self->stride, outcaps);
1103     gst_pad_set_caps (self->srcpad, outcaps);
1105     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1106       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1107           GST_BUFFER_SIZE (outbuf), self->outsize);
1108       gst_buffer_unref (outbuf);
1109       goto allocate_buffer;
1110     }
1111   }
1113   if (G_UNLIKELY (!self->codec)) {
1114     if (!codec_create (self)) {
1115       GST_ERROR_OBJECT (self, "could not create codec");
1116       gst_buffer_unref (buf);
1117       gst_buffer_unref (outbuf);
1118       return GST_FLOW_ERROR;
1119     }
1120   }
1122   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1123   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1125   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1126    * internal pool while self->first_out_buffer == TRUE in order to simplify
1127    * things in case we need to renegotiate */
1128   self->inArgs->inputID =
1129       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1130   if (!self->inArgs->inputID) {
1131     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1132     gst_buffer_unref (buf);
1133     return GST_FLOW_ERROR;
1134   }
1135   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1137 have_out_buf:
1138   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1140 #ifdef USE_DTS_PTS_CODE
1141   if (ts != GST_CLOCK_TIME_NONE) {
1142     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1143     /* if next buffer has earlier ts than previous, then the ts
1144      * we are getting are definitely decode order (DTS):
1145      */
1146     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1147       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1148       self->ts_may_be_pts = FALSE;
1149     }
1150     self->last_dts = ts;
1151   }
1152 #endif
1154   if (self->in_size == 0 && outbuf) {
1155     GST_DEBUG_OBJECT (self, "no input, skipping process");
1157     gst_buffer_unref (outbuf);
1158     return GST_FLOW_OK;
1159   }
1161   self->inArgs->numBytes = self->in_size;
1162   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1163   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1165   err = codec_process (self, TRUE, FALSE, &ret);
1166   if (err) {
1167     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1168         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1169     gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1171     return GST_FLOW_ERROR;
1172   }
1174   if (ret != GST_FLOW_OK) {
1175     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1176         gst_flow_get_name (ret));
1178     return ret;
1179   }
1181   self->first_in_buffer = FALSE;
1183   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1184     /* The copy could be avoided by playing with the buffer pointer,
1185        but it seems to be rare and for not many bytes */
1186     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1187         self->outArgs->bytesConsumed, self->in_size,
1188         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1189     if (self->outArgs->bytesConsumed > 0) {
1190       if (self->outArgs->bytesConsumed > self->in_size) {
1191         GST_WARNING_OBJECT (self,
1192             "Codec claims to have used more bytes than supplied");
1193         self->in_size = 0;
1194       } else {
1195         if (self->outArgs->bytesConsumed < self->in_size) {
1196           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1197               self->in_size - self->outArgs->bytesConsumed);
1198         }
1199         self->in_size -= self->outArgs->bytesConsumed;
1200       }
1201     }
1202   } else {
1203     self->in_size = 0;
1204   }
1206   if (self->outArgs->outBufsInUseFlag) {
1207     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1208     self->need_out_buf = FALSE;
1209   } else {
1210     self->need_out_buf = TRUE;
1211   }
1213   if (buf) {
1214     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1215         GST_BUFFER_SIZE (buf));
1216     ts = GST_BUFFER_TIMESTAMP (buf);
1217     goto allocate_buffer;
1218   }
1220   if (self->needs_flushing)
1221     gst_ducati_viddec_codec_flush (self, FALSE);
1223   return GST_FLOW_OK;
1226 static gboolean
1227 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1229   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1230   gboolean ret = TRUE;
1232   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1234   switch (GST_EVENT_TYPE (event)) {
1235     case GST_EVENT_NEWSEGMENT:
1236     {
1237       gboolean update;
1238       GstFormat fmt;
1239       gint64 start, stop, time;
1240       gdouble rate, arate;
1242       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1243           &start, &stop, &time);
1244       gst_segment_set_newsegment_full (&self->segment, update,
1245           rate, arate, fmt, start, stop, time);
1246       break;
1247     }
1248     case GST_EVENT_EOS:
1249       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1250         GST_ERROR_OBJECT (self, "could not flush on eos");
1251         ret = FALSE;
1252       }
1253       break;
1254     case GST_EVENT_FLUSH_STOP:
1255       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1256         GST_ERROR_OBJECT (self, "could not flush");
1257         gst_event_unref (event);
1258         ret = FALSE;
1259       }
1260       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1261       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1262       self->qos_proportion = 1;
1263       self->need_out_buf = TRUE;
1264       break;
1265     default:
1266       break;
1267   }
1269   if (ret)
1270     ret = gst_pad_push_event (self->srcpad, event);
1271   GST_LOG_OBJECT (self, "end");
1273   return ret;
1276 static gboolean
1277 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1279   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1280   gboolean ret = TRUE;
1282   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1284   switch (GST_EVENT_TYPE (event)) {
1285     case GST_EVENT_QOS:
1286     {
1287       gdouble proportion;
1288       GstClockTimeDiff diff;
1289       GstClockTime timestamp;
1291       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1293       GST_OBJECT_LOCK (self);
1294       self->qos_proportion = proportion;
1295       self->qos_earliest_time = timestamp + 2 * diff;
1296       GST_OBJECT_UNLOCK (self);
1298       GST_DEBUG_OBJECT (self,
1299           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1300           proportion, GST_TIME_ARGS (timestamp), diff);
1302       ret = gst_pad_push_event (self->sinkpad, event);
1303       break;
1304     }
1305     default:
1306       ret = gst_pad_push_event (self->sinkpad, event);
1307       break;
1308   }
1310   GST_LOG_OBJECT (self, "end");
1312   return ret;
1315 static GstStateChangeReturn
1316 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1318   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1319   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1320   gboolean supported;
1322   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1323       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1324       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1326   switch (transition) {
1327     case GST_STATE_CHANGE_NULL_TO_READY:
1328       if (!engine_open (self)) {
1329         GST_ERROR_OBJECT (self, "could not open");
1330         return GST_STATE_CHANGE_FAILURE;
1331       }
1332       /* try to create/destroy the codec here, it may not be supported */
1333       supported = codec_create (self);
1334       codec_delete (self);
1335       self->codec = NULL;
1336       if (!supported) {
1337         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1338             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1339         engine_close (self);
1340         return GST_STATE_CHANGE_FAILURE;
1341       }
1342       break;
1343     default:
1344       break;
1345   }
1347   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1349   if (ret == GST_STATE_CHANGE_FAILURE)
1350     goto leave;
1352   switch (transition) {
1353     case GST_STATE_CHANGE_PAUSED_TO_READY:
1354       self->interlaced = FALSE;
1355       self->send_crop_event = TRUE;
1356       gst_ducati_viddec_codec_flush (self, FALSE);
1357       break;
1358     case GST_STATE_CHANGE_READY_TO_NULL:
1359       codec_delete (self);
1360       engine_close (self);
1361       break;
1362     default:
1363       break;
1364   }
1366 leave:
1367   GST_LOG_OBJECT (self, "end");
1369   return ret;
1372 /* GObject vmethod implementations */
1374 #define VERSION_LENGTH 256
1376 static void
1377 gst_ducati_viddec_get_property (GObject * obj,
1378     guint prop_id, GValue * value, GParamSpec * pspec)
1380   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1383   switch (prop_id) {
1384     case PROP_VERSION:{
1385       int err;
1386       char *version = NULL;
1388       if (!self->engine)
1389         engine_open (self);
1391       if (!self->codec)
1392         codec_create (self);
1394       if (self->codec) {
1395         version = dce_alloc (VERSION_LENGTH);
1396         self->status->data.buf = (XDAS_Int8 *) version;
1397         self->status->data.bufSize = VERSION_LENGTH;
1399         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1400             self->dynParams, self->status);
1401         if (err) {
1402           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1403         }
1405         self->status->data.buf = NULL;
1406         self->status->data.bufSize = 0;
1407       }
1409       g_value_set_string (value, version);
1410       if (version)
1411         dce_free (version);
1413       break;
1414     }
1415     case PROP_MAX_REORDER_FRAMES:
1416       g_value_set_int (value, self->backlog_default_maxframes);
1417       break;
1418     default:{
1419       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1420       break;
1421     }
1422   }
1425 static void
1426 gst_ducati_viddec_set_property (GObject * obj,
1427     guint prop_id, const GValue * value, GParamSpec * pspec)
1429   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1431   switch (prop_id) {
1432     case PROP_MAX_REORDER_FRAMES:
1433       self->backlog_default_maxframes = g_value_get_int (value);
1434       break;
1435     default:{
1436       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1437       break;
1438     }
1439   }
1442 static void
1443 gst_ducati_viddec_finalize (GObject * obj)
1445   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1447   codec_delete (self);
1448   engine_close (self);
1450   /* Will unref the remaining buffers if needed */
1451   g_hash_table_unref (self->passed_in_bufs);
1452   if (self->codec_data) {
1453     gst_buffer_unref (self->codec_data);
1454     self->codec_data = NULL;
1455   }
1457   G_OBJECT_CLASS (parent_class)->finalize (obj);
1460 static void
1461 gst_ducati_viddec_base_init (gpointer gclass)
1463   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1465   gst_element_class_add_pad_template (element_class,
1466       gst_static_pad_template_get (&src_factory));
1469 static void
1470 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1472   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1473   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1475   gobject_class->get_property =
1476       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1477   gobject_class->set_property =
1478       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1479   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1480   gstelement_class->change_state =
1481       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1483   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1484   klass->allocate_params =
1485       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1486   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1487   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1488   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1489   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1490   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1491   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1492   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1494   g_object_class_install_property (gobject_class, PROP_VERSION,
1495       g_param_spec_string ("version", "Version",
1496           "The codec version string", "",
1497           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1499   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1500       g_param_spec_int ("max-reorder-frames",
1501           "Maximum number of frames needed for reordering",
1502           "The maximum number of frames needed for reordering output frames. "
1503           "Only meaningful for codecs with B frames. 0 means no reordering. "
1504           "This value will be used if the correct value cannot be inferred "
1505           "from the stream. Too low a value may cause misordering, too high "
1506           "will cause extra latency.",
1507           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1508           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1511 static void
1512 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1514   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1516   self->sinkpad =
1517       gst_pad_new_from_template (gst_element_class_get_pad_template
1518       (gstelement_class, "sink"), "sink");
1519   gst_pad_set_setcaps_function (self->sinkpad,
1520       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1521   gst_pad_set_chain_function (self->sinkpad,
1522       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1523   gst_pad_set_event_function (self->sinkpad,
1524       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1526   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1527   gst_pad_set_event_function (self->srcpad,
1528       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1529   gst_pad_set_query_function (self->srcpad,
1530       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1531   gst_pad_set_getcaps_function (self->srcpad,
1532       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1534   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1535   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1537   self->input_width = 0;
1538   self->input_height = 0;
1539   /* sane defaults in case we need to create codec without caps negotiation
1540    * (for example, to get 'version' property)
1541    */
1542   self->width = 128;
1543   self->height = 128;
1544   self->fps_n = -1;
1545   self->fps_d = -1;
1547   self->first_in_buffer = TRUE;
1548   self->first_out_buffer = TRUE;
1549   self->interlaced = FALSE;
1550   self->send_crop_event = TRUE;
1552 #ifdef USE_DTS_PTS_CODE
1553   self->dts_ridx = self->dts_widx = 0;
1554   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1555   self->ts_may_be_pts = TRUE;
1556   self->ts_is_pts = FALSE;
1557 #endif
1559   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1561   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1563   self->qos_proportion = 1;
1564   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1565   self->wait_keyframe = TRUE;
1567   self->need_out_buf = TRUE;
1568   self->device = NULL;
1569   self->input_bo = NULL;
1571   self->backlog_maxframes = 0;
1572   self->backlog_nframes = 0;
1573   self->backlog_default_maxframes = MAX_BACKLOG_FRAMES;
1575   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1576       NULL, (GDestroyNotify) gst_buffer_unref);