9e8d92056f162da4b342e28a58b9ae5c86045103
[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 #define VERSION_LENGTH 256
30 static void gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass);
31 static void gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass);
32 static void gst_ducati_viddec_base_init (gpointer gclass);
33 static GstElementClass *parent_class = NULL;
34 void gst_drm_buffer_pool_set_caps (GstDRMBufferPool * self, GstCaps * caps);
37 void
38 gst_drm_buffer_pool_set_caps (GstDRMBufferPool * self, GstCaps * caps)
39 {
40   GstStructure *conf;
41   conf = gst_buffer_pool_get_config (GST_BUFFER_POOL (self));
42   gst_buffer_pool_config_set_params (conf, caps, self->size, 0, 0);
43   gst_drm_buffer_pool_set_config (GST_BUFFER_POOL (self), conf);
45 }
47 GType
48 gst_ducati_viddec_get_type (void)
49 {
50   static GType ducati_viddec_type = 0;
52   if (!ducati_viddec_type) {
53     static const GTypeInfo ducati_viddec_info = {
54       sizeof (GstDucatiVidDecClass),
55       (GBaseInitFunc) gst_ducati_viddec_base_init,
56       NULL,
57       (GClassInitFunc) gst_ducati_viddec_class_init,
58       NULL,
59       NULL,
60       sizeof (GstDucatiVidDec),
61       0,
62       (GInstanceInitFunc) gst_ducati_viddec_init,
63     };
65     ducati_viddec_type = g_type_register_static (GST_TYPE_ELEMENT,
66         "GstDucatiVidDec", &ducati_viddec_info, 0);
67   }
68   return ducati_viddec_type;
69 }
71 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
72     GST_PAD_SRC,
73     GST_PAD_ALWAYS,
74     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("NV12"))
75     );
77 enum
78 {
79   PROP_0,
80   PROP_VERSION,
81   PROP_MAX_REORDER_FRAMES,
82   PROP_CODEC_DEBUG_INFO
83 };
85 /* helper functions */
87 static void
88 engine_close (GstDucatiVidDec * self)
89 {
90   if (self->params) {
91     dce_free (self->params);
92     self->params = NULL;
93   }
95   if (self->dynParams) {
96     dce_free (self->dynParams);
97     self->dynParams = NULL;
98   }
100   if (self->status) {
101     dce_free (self->status);
102     self->status = NULL;
103   }
105   if (self->inBufs) {
106     dce_free (self->inBufs);
107     self->inBufs = NULL;
108   }
110   if (self->outBufs) {
111     dce_free (self->outBufs);
112     self->outBufs = NULL;
113   }
115   if (self->inArgs) {
116     dce_free (self->inArgs);
117     self->inArgs = NULL;
118   }
120   if (self->outArgs) {
121     dce_free (self->outArgs);
122     self->outArgs = NULL;
123   }
125   if (self->engine) {
126     Engine_close (self->engine);
127     self->engine = NULL;
128   }
130   if (self->device) {
131     dce_deinit (self->device);
132     self->device = NULL;
133   }
136 static gboolean
137 engine_open (GstDucatiVidDec * self)
139   gboolean ret;
140   int ec;
142   if (G_UNLIKELY (self->engine)) {
143     return TRUE;
144   }
146   if (self->device == NULL) {
147     self->device = dce_init ();
148     if (self->device == NULL) {
149       GST_ERROR_OBJECT (self, "dce_init() failed");
150       return FALSE;
151     }
152   }
154   GST_DEBUG_OBJECT (self, "opening engine");
156   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
157   if (G_UNLIKELY (!self->engine)) {
158     GST_ERROR_OBJECT (self, "could not create engine");
159     return FALSE;
160   }
162   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
163       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
164       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
165       sizeof (IVIDDEC3_OutArgs));
167   return ret;
170 static void
171 codec_delete (GstDucatiVidDec * self)
173   if (self->pool) {
174     gst_drm_buffer_pool_destroy (self->pool);
175     self->pool = NULL;
176   }
178   if (self->codec) {
179     GST_DEBUG ("Calling VIDDEC3_delete");
180     VIDDEC3_delete (self->codec);
181     self->codec = NULL;
182   }
184   if (self->input_bo) {
185     close ((int) self->inBufs->descs[0].buf);
186     omap_bo_del (self->input_bo);
187     self->input_bo = NULL;
188   }
191 static gboolean
192 codec_create (GstDucatiVidDec * self)
194   gint err, n;
195   const gchar *codec_name;
196   char *version = NULL;
198   codec_delete (self);
200   if (G_UNLIKELY (!self->engine)) {
201     GST_ERROR_OBJECT (self, "no engine");
202     return FALSE;
203   }
205   /* these need to be set before VIDDEC3_create */
206   self->params->maxWidth = self->width;
207   self->params->maxHeight = self->height;
209   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
211   /* create codec: */
212   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
213   self->codec =
214       VIDDEC3_create (self->engine, (String) codec_name, self->params);
216   if (!self->codec) {
217     return FALSE;
218   }
220   GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
221   err =
222       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
223       self->status);
224   if (err) {
225     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
226     return FALSE;
227   }
229   self->first_in_buffer = TRUE;
230   self->first_out_buffer = FALSE;
232   version = dce_alloc (VERSION_LENGTH);
233   if (version) {
234     self->status->data.buf = (XDAS_Int8 *) version;
235     self->status->data.bufSize = VERSION_LENGTH;
237     GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
238     err = VIDDEC3_control (self->codec, XDM_GETVERSION,
239         self->dynParams, self->status);
241     if (err) {
242       GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
243     } else
244       GST_DEBUG ("Codec version %s", self->status->data.buf);
246     self->status->data.buf = NULL;
247     self->status->data.bufSize = 0;
248     dce_free (version);
250   }
253   /* allocate input buffer and initialize inBufs: */
254   /* FIXME:  needed size here has nothing to do with width * height */
255   self->input_bo = omap_bo_new (self->device,
256       self->width * self->height, OMAP_BO_WC);
257   self->input = omap_bo_map (self->input_bo);
258   self->inBufs->numBufs = 1;
259   /* IPC requires dmabuf fd in place of bo handle */
260   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
262   /* Actual buffers will be set later, as they will be different for every
263      frame. We allow derived classes to add their own buffers, however, so
264      we initialize the number of outBufs here, counting the number of extra
265      buffers required, including "holes" in planes, which may not be filled
266      if not assigned. */
267   self->outBufs->numBufs = 2;   /* luma and chroma planes, always */
268   for (n = 0; n < 3; n++)
269     if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
270       self->outBufs->numBufs = 2 + n + 1;
272   return TRUE;
275 static inline GstBuffer *
276 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
278   if (G_UNLIKELY (!self->pool)) {
279     guint size =
280         GST_ROUND_UP_4 (self->padded_width) *
281         GST_ROUND_UP_2 (self->padded_height) * 3 / 2;
283     GST_DEBUG_OBJECT (self, "creating bufferpool");
284     GST_DEBUG_OBJECT (self, "%s\n",
285         gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
286     self->pool =
287         gst_drm_buffer_pool_new (GST_ELEMENT (self), dce_get_fd (),
288         gst_pad_get_current_caps (self->srcpad), size);
289   }
290   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
293 static GstMetaDucatiBufferPriv *
294 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
296   GstMetaDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
297   if (!priv) {
298     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
299     struct omap_bo *bo;
300     gint uv_offset, size;
302     GstMetaDmaBuf *dmabuf = gst_buffer_get_dma_buf_meta (buf);
304     /* if it isn't a dmabuf buffer that we can import, then there
305      * is nothing we can do with it:
306      */
307     if (!dmabuf) {
308       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
309       return NULL;
310     }
312     bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_meta_get_fd (dmabuf));
314     uv_offset =
315         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height);
316     size =
317         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
318         3 / 2;
320     priv = gst_ducati_buffer_priv_set (buf, bo, uv_offset, size);
321   }
322   return priv;
325 static XDAS_Int32
326 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
327     gboolean force_internal)
329   GstMetaDucatiBufferPriv *priv = NULL;
330   GstMetaDmaBuf *dmabuf = NULL;
332   if (!force_internal)
333     priv = get_buffer_priv (self, *buf);
335   if (!priv) {
336     GstBuffer *orig = *buf;
338     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
339     *buf = codec_buffer_pool_get (self, NULL);
340     GST_BUFFER_PTS (*buf) = GST_BUFFER_PTS (orig);
341     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
342     gst_buffer_unref (orig);
343     return codec_prepare_outbuf (self, buf, FALSE);
344   }
346   /* There are at least two buffers. Derived classes may add codec specific
347      buffers (eg, debug info) after these two if they want to. */
348   dmabuf = gst_buffer_get_dma_buf_meta (*buf);
349   /* XDM_MemoryType required by drm to allcoate buffer */
350   self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
351   /* IPC requires dmabuf fd in place of bo handle */
352   self->outBufs->descs[0].buf = (XDAS_Int8 *) gst_dma_buf_meta_get_fd (dmabuf);
353   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
354   self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
355   /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
356      ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
357      should point to a single buffer fd and need to update the
358      descs[0].bufSize.bytes with the size of luminance(Y) data
359      and descs[1].bufSize.bytes with crominance(UV) */
360   self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
361   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
363   return (XDAS_Int32) * buf;
366 static GstBuffer *
367 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
369   GstBuffer *buf = (GstBuffer *) id;
371   if (buf) {
372     g_hash_table_insert (self->passed_in_bufs, buf, buf);
374     gst_buffer_ref (buf);
375   }
376   return buf;
379 static void
380 do_dce_buf_unlock (GstBuffer * buf)
382   SizeT fd;
383   /* Get dmabuf fd of the buffer to unlock */
384   fd = gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta (buf));
386   dce_buf_unlock (1, &fd);
389 static void
390 dce_buf_free_all (GstBuffer * buf, gpointer key, GstDucatiVidDec * self)
392   if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
393     /* Buffer was not found in the hash table, remove it anyway */
394     gst_buffer_unref (buf);
395   }
398 static void
399 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
401   GstBuffer *buf = (GstBuffer *) id;
403   if (buf) {
404     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
405     /* Must unlock the buffer before free */
406     g_hash_table_remove (self->dce_locked_bufs, buf);
407     if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
408       /* Buffer was not found in the hash table, remove it anyway */
409       gst_buffer_unref (buf);
410     }
411   }
414 /* Called when playing in reverse */
415 static GstFlowReturn
416 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
418   GstBuffer *buf;
420   if (self->backlog_nframes == 0)
421     return GST_FLOW_OK;
423   /* send it, giving away the ref */
424   buf = self->backlog_frames[--self->backlog_nframes];
425   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
426       buf);
427   return gst_pad_push (self->srcpad, buf);
430 static GstFlowReturn
431 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
433   guint64 earliest_order = G_MAXUINT64;
434   guint earliest_index = 0, i;
435   GstBuffer *buf;
437   if (self->backlog_nframes == 0)
438     return GST_FLOW_OK;
440   /* work out which frame has the earliest poc */
441   for (i = 0; i < self->backlog_nframes; i++) {
442     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
443     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
444       earliest_order = order;
445       earliest_index = i;
446     }
447   }
449   /* send it, giving away the ref */
450   buf = self->backlog_frames[earliest_index];
451   self->backlog_frames[earliest_index] =
452       self->backlog_frames[--self->backlog_nframes];
453   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
454       buf);
455   return gst_pad_push (self->srcpad, buf);
458 static void
459 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
461   if (self->segment.format == GST_FORMAT_TIME &&
462       self->segment.rate < (gdouble) 0.0) {
463     /* negative rate */
464     /* push everything on the backlog, ignoring errors */
465     while (self->backlog_nframes > 0) {
466       gst_ducati_viddec_push_latest (self);
467     }
468   } else {
469     /* push everything on the backlog, ignoring errors */
470     while (self->backlog_nframes > 0) {
471       gst_ducati_viddec_push_earliest (self);
472     }
473   }
476 static gint
477 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
478     GstFlowReturn * flow_ret)
480   gint err;
481   GstClockTime t;
482   GstBuffer *outbuf = NULL;
483   gint i;
484   SizeT fd;
485   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
486   GstFlowReturn ret = GST_FLOW_OK;
487   if (flow_ret)
488     /* never leave flow_ret uninitialized */
489     *flow_ret = GST_FLOW_OK;
491   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
492   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
494   if (self->inArgs->inputID != 0) {
495     /* Check if this inputID was already sent to the codec */
496     if (g_hash_table_contains (self->dce_locked_bufs,
497             (gpointer) self->inArgs->inputID)) {
498       GstMetaDucatiBufferPriv *priv =
499           gst_ducati_buffer_priv_get ((GstBuffer *) self->inArgs->inputID);
501       GST_DEBUG_OBJECT (self, "Resending (inputID: %08x)",
502           self->inArgs->inputID);
503       /* Input ID needs to be resent to the codec for cases like H.264 field coded pictures.
504          The decoder indicates this by setting outArgs->outBufsInUseFlag */
505       self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
506       self->outBufs->descs[0].buf = (XDAS_Int8 *)
507           gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta ((GstBuffer *)
508               self->inArgs->inputID));
509       self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
510       self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
511       self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
512       self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
513     } else {
514       /* Get dmabuf fd of the buffer to lock it */
515       fd = gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta ((GstBuffer *)
516               self->inArgs->inputID));
517       /* Must lock all the buffer passed to ducati */
518       GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x, fd: %d)",
519           self->inArgs->inputID, fd);
520       dce_buf_lock (1, &fd);
521       g_hash_table_insert (self->dce_locked_bufs,
522           (gpointer) self->inArgs->inputID, (gpointer) self->inArgs->inputID);
523     }
524   }
525   t = gst_util_get_timestamp ();
526   err = VIDDEC3_process (self->codec,
527       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
528   t = gst_util_get_timestamp () - t;
529   GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
530       (gint) (t / 1000000));
532   if (err) {
533     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
534         err, self->outArgs->extendedError);
535     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
536         self->error_strings);
538     GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
539     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
540         self->dynParams, self->status);
541     if (err) {
542       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
543           err, self->status->extendedError);
544       gst_ducati_log_extended_error_info (self->status->extendedError,
545           self->error_strings);
546     }
548     if (flush)
549       err = XDM_EFAIL;
550     else
551       err = klass->handle_error (self, err,
552           self->outArgs->extendedError, self->status->extendedError);
553   }
555   /* we now let the codec decide */
556   self->dynParams->newFrameFlag = XDAS_FALSE;
558   if (err == XDM_EFAIL)
559     goto skip_outbuf_processing;
561   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
562     gboolean interlaced;
564     GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
565         i, self->outArgs->outputID[i]);
566     interlaced =
567         self->outArgs->displayBufs.bufDesc[0].contentType ==
568         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
570     if (interlaced) {
571       GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
572       if (!buf || !gst_buffer_is_writable (buf)) {
573         GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
574       } else {
575         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
576         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
577         if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
578           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
579         if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
580           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
581       }
582     }
584     /* Getting an extra reference for the decoder */
585     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
587     /* if send is FALSE, don't try to renegotiate as we could be flushing during
588      * a PAUSED->READY state change
589      */
590     if (send && interlaced != self->interlaced) {
591       GstCaps *caps;
593       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
594           "thinks interlaced=%d... trusting codec", self->interlaced,
595           interlaced);
597       self->interlaced = interlaced;
599       caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
600       GST_INFO_OBJECT (self, "changing interlace field in caps");
601       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
602           NULL);
603       if (self->pool)
604         gst_drm_buffer_pool_set_caps (self->pool, caps);
605       if (!gst_pad_set_caps (self->srcpad, caps)) {
606         GST_ERROR_OBJECT (self,
607             "downstream didn't want to change interlace mode");
608         err = XDM_EFAIL;
609       }
610       gst_caps_unref (caps);
612       /* this buffer still has the old caps so we skip it */
613       send = FALSE;
614     }
616     if (send) {
617       gint crop_width, crop_height;
619       GstVideoCropMeta *crop = gst_buffer_get_video_crop_meta (outbuf);
620       /* send region of interest to sink on first buffer: */
621       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
623       crop_width = r->bottomRight.x - r->topLeft.x;
624       crop_height = r->bottomRight.y - r->topLeft.y;
626       if (crop_width > self->input_width)
627         crop_width = self->input_width;
628       if (crop_height > self->input_height)
629         crop_height = self->input_height;
631       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
632           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
633           crop_width, crop_height);
635       crop->x = r->topLeft.x;
636       crop->y = r->topLeft.y;
637       crop->width = crop_width;
638       crop->height = crop_height;
639     }
641     if (G_UNLIKELY (self->first_out_buffer) && send) {
642       GstDRMBufferPool *pool;
643       self->first_out_buffer = FALSE;
645       /* Destroy the pool so the buffers we used so far are eventually released.
646        * The pool will be recreated if needed.
647        */
648       pool = self->pool;
649       self->pool = NULL;
650       if (pool)
651         gst_drm_buffer_pool_destroy (pool);
652     }
654     if (send) {
655       GstClockTime ts;
657       ts = GST_BUFFER_PTS (outbuf);
659       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
660           i, outbuf, GST_TIME_ARGS (ts));
662 #ifdef USE_DTS_PTS_CODE
663       if (self->ts_may_be_pts) {
664         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
665           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
666               "enabling ts_is_pts");
667           self->ts_is_pts = TRUE;
668         }
669       }
670 #endif
672       self->last_pts = ts;
674       if (self->dts_ridx != self->dts_widx) {
675         ts = self->dts_queue[self->dts_ridx++ % NDTS];
676       }
678       if (self->ts_is_pts) {
679         /* if we have a queued DTS from demuxer, use that instead: */
680         GST_BUFFER_PTS (outbuf) = ts;
681         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
682             i, outbuf, GST_TIME_ARGS (ts));
683       }
685       ret = klass->push_output (self, outbuf);
686       if (flow_ret)
687         *flow_ret = ret;
688       if (ret != GST_FLOW_OK) {
689         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
690         /* just unref the remaining buffers (if any) */
691         send = FALSE;
692       }
693     } else {
694       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
695           i, outbuf);
697       gst_buffer_unref (outbuf);
698     }
699   }
701 skip_outbuf_processing:
702   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
703     GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
704         i, self->outArgs->freeBufID[i]);
705     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
706   }
708   return err;
711 /** call control(FLUSH), and then process() to pop out all buffers */
712 gboolean
713 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
715   gint err = FALSE;
716   int prev_num_in_bufs, prev_num_out_bufs;
718   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
720   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
722   /* note: flush is synchronized against _chain() to avoid calling
723    * the codec from multiple threads
724    */
725   GST_PAD_STREAM_LOCK (self->sinkpad);
727 #ifdef USE_DTS_PTS_CODE
728   self->dts_ridx = self->dts_widx = 0;
729   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
730   self->ts_may_be_pts = TRUE;
731   self->ts_is_pts = FALSE;
732 #endif
733   self->wait_keyframe = TRUE;
734   self->in_size = 0;
735   self->needs_flushing = FALSE;
736   self->need_out_buf = TRUE;
738   if (G_UNLIKELY (self->first_in_buffer)) {
739     goto out;
740   }
742   if (G_UNLIKELY (!self->codec)) {
743     GST_WARNING_OBJECT (self, "no codec");
744     goto out;
745   }
748   GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
749   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
750   if (err) {
751     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
752     goto out;
753   }
755   prev_num_in_bufs = self->inBufs->numBufs;
756   prev_num_out_bufs = self->outBufs->numBufs;
758   self->inBufs->descs[0].bufSize.bytes = 0;
759   self->inBufs->numBufs = 0;
760   self->inArgs->numBytes = 0;
761   self->inArgs->inputID = 0;
762   self->outBufs->numBufs = 0;
764   do {
765     err = codec_process (self, eos, TRUE, NULL);
766   } while (err != XDM_EFAIL);
768   /* We flushed the decoder, we can now remove the buffer that have never been
769    * unrefed in it */
770   g_hash_table_foreach (self->dce_locked_bufs, (GHFunc) dce_buf_free_all, self);
771   g_hash_table_remove_all (self->dce_locked_bufs);
772   g_hash_table_remove_all (self->passed_in_bufs);
774   /* reset outArgs in case we're flushing in codec_process trying to do error
775    * recovery */
776   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
777   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
779   self->dynParams->newFrameFlag = XDAS_TRUE;
781   /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
782   self->inBufs->numBufs = prev_num_in_bufs;
783   self->outBufs->numBufs = prev_num_out_bufs;
785   /* on a flush, it is normal (and not an error) for the last _process() call
786    * to return an error..
787    */
788   err = XDM_EOK;
790 out:
791   GST_PAD_STREAM_UNLOCK (self->sinkpad);
792   GST_DEBUG_OBJECT (self, "done");
794   return !err;
797 /* GstDucatiVidDec vmethod default implementations */
799 static gboolean
800 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
802   const GValue *codec_data;
803   gint w, h;
805   if (gst_structure_get_int (s, "width", &self->input_width) &&
806       gst_structure_get_int (s, "height", &self->input_height)) {
808     h = ALIGN2 (self->input_height, 4); /* round up to MB */
809     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
811     /* if we've already created codec, but the resolution has changed, we
812      * need to re-create the codec:
813      */
814     if (G_UNLIKELY (self->codec)) {
815       if ((h != self->height) || (w != self->width)) {
816         codec_delete (self);
817       }
818     }
820     self->width = w;
821     self->height = h;
823     codec_data = gst_structure_get_value (s, "codec_data");
825     if (codec_data) {
826       int i;
827       GstMapInfo info;
828       GstBuffer *buffer = gst_value_get_buffer (codec_data);
830       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
832       gst_buffer_map (buffer, &info, GST_MAP_READ);
833       GST_DEBUG_OBJECT (self, "codec_data dump, size = %d ", info.size);
834       for (i = 0; i < info.size; i++) {
835         GST_DEBUG_OBJECT (self, "%02x ", info.data[i]);
836       }
837       self->codecdata = g_slice_alloc (info.size);
838       memcpy (self->codecdata, info.data, info.size);
839       self->codecdatasize = info.size;
840       gst_buffer_unmap (buffer, &info);
841       self->codec_data = gst_buffer_ref (buffer);
842     }
844     return TRUE;
845   }
847   return FALSE;
850 static gboolean
851 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
852     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
855   /* allocate params: */
856   self->params = dce_alloc (params_sz);
857   if (G_UNLIKELY (!self->params)) {
858     return FALSE;
859   }
860   self->params->size = params_sz;
861   self->params->maxFrameRate = 30000;
862   self->params->maxBitRate = 10000000;
864   self->params->dataEndianness = XDM_BYTE;
865   self->params->forceChromaFormat = XDM_YUV_420SP;
866   self->params->operatingMode = IVIDEO_DECODE_ONLY;
868   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
869   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
870   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
871   self->params->numInputDataUnits = 0;
872   self->params->numOutputDataUnits = 0;
874   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
875   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
876   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
877   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
879   /* allocate dynParams: */
880   self->dynParams = dce_alloc (dynparams_sz);
881   if (G_UNLIKELY (!self->dynParams)) {
882     return FALSE;
883   }
884   self->dynParams->size = dynparams_sz;
885   self->dynParams->decodeHeader = XDM_DECODE_AU;
886   self->dynParams->displayWidth = 0;
887   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
888   self->dynParams->newFrameFlag = XDAS_TRUE;
890   /* allocate status: */
891   self->status = dce_alloc (status_sz);
892   if (G_UNLIKELY (!self->status)) {
893     return FALSE;
894   }
895   memset (self->status, 0, status_sz);
896   self->status->size = status_sz;
898   /* allocate inBufs/outBufs: */
899   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
900   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
901   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
902     return FALSE;
903   }
905   /* allocate inArgs/outArgs: */
906   self->inArgs = dce_alloc (inargs_sz);
907   self->outArgs = dce_alloc (outargs_sz);
908   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
909     return FALSE;
910   }
911   self->inArgs->size = inargs_sz;
912   self->outArgs->size = outargs_sz;
914   return TRUE;
917 static GstBuffer *
918 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
920   gsize bufoffset, bufmaxsize, buftotalsize;
921   guint sz;
922   guint8 *data = NULL;
923   if (G_UNLIKELY (self->first_in_buffer) && self->codecdata) {
924     push_input (self, self->codecdata, self->codecdatasize);
925   }
927   /* just copy entire buffer */
928   buftotalsize = gst_buffer_get_sizes (buf, &bufoffset, &bufmaxsize);
929   data = g_slice_alloc (buftotalsize);
930   sz = gst_buffer_extract (buf, bufoffset, data, buftotalsize);
931   push_input (self, data, sz);
932   gst_buffer_unref (buf);
934   return NULL;
937 static GstFlowReturn
938 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
940   GstFlowReturn ret = GST_FLOW_OK;
942   if (self->segment.format == GST_FORMAT_TIME &&
943       self->segment.rate < (gdouble) 0.0) {
944     /* negative rate: reverse playback */
946     if (self->backlog_nframes > 0 &&
947         (GST_BUFFER_PTS (self->backlog_frames[0]) > GST_BUFFER_PTS (buf))) {
948       /* push out all backlog frames, since we have a buffer that is
949          earlier than any other in the list */
950       while (self->backlog_nframes > 0) {
951         ret = gst_ducati_viddec_push_latest (self);
952         if (ret != GST_FLOW_OK)
953           break;
954       }
955     }
956     /* add the frame to the list, the array will own the ref */
957     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
958         buf);
959     if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
960       self->backlog_frames[self->backlog_nframes++] = buf;
961     } else {
962       /* No space in the re-order buffer, drop the frame */
963       GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
964       gst_buffer_unref (buf);
965     }
967   } else {
968     /* if no reordering info was set, just send the buffer */
969     if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
970       GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
971       return gst_pad_push (self->srcpad, buf);
972     }
974     /* add the frame to the list, the array will own the ref */
975     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
976         buf);
977     self->backlog_frames[self->backlog_nframes++] = buf;
979     /* push till we have no more than the max needed, or error */
980     while (self->backlog_nframes > self->backlog_maxframes) {
981       ret = gst_ducati_viddec_push_earliest (self);
982       if (ret != GST_FLOW_OK)
983         break;
984     }
985   }
986   return ret;
989 static gint
990 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
991     gint extended_error, gint status_extended_error)
993   if (XDM_ISFATALERROR (extended_error))
994     ret = XDM_EFAIL;
995   else
996     ret = XDM_EOK;
998   return ret;
1001 /* GstElement vmethod implementations */
1003 static gboolean
1004 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
1006   gboolean ret = TRUE;
1007   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1008   GstStructure *s;
1009   GstCaps *outcaps = NULL;
1010   GstStructure *out_s;
1011   gint par_width, par_height;
1012   gboolean par_present;
1014   GST_INFO_OBJECT (self, "set_caps (sink): %" GST_PTR_FORMAT, caps);
1016   s = gst_caps_get_structure (caps, 0);
1017   if (!klass->parse_caps (self, s)) {
1018     GST_WARNING_OBJECT (self, "missing required fields");
1019     ret = FALSE;
1020     goto out;
1021   }
1023   /* update output/padded sizes */
1024   klass->update_buffer_size (self);
1026   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
1027     self->fps_n = 0;
1028     self->fps_d = 1;
1029   }
1030   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
1031   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
1032       &par_width, &par_height);
1034   outcaps = gst_pad_get_allowed_caps (self->srcpad);
1035   GST_DEBUG_OBJECT (self, "%s",
1036       gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
1037   if (outcaps) {
1038     outcaps = gst_caps_make_writable (outcaps);
1039     outcaps = gst_caps_truncate (outcaps);
1040     if (gst_caps_is_empty (outcaps)) {
1041       gst_caps_unref (outcaps);
1042       outcaps = NULL;
1043     }
1044   }
1046   if (!outcaps) {
1047     outcaps = gst_caps_new_simple ("video/x-raw",
1048         "format", G_TYPE_STRING, "NV12", NULL);
1049   }
1051   out_s = gst_caps_get_structure (outcaps, 0);
1052   gst_structure_set (out_s,
1053       "width", G_TYPE_INT, self->padded_width,
1054       "height", G_TYPE_INT, self->padded_height,
1055       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
1056   if (par_present)
1057     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1058         par_width, par_height, NULL);
1060   if (self->interlaced)
1061     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
1063   self->stride = GST_ROUND_UP_4 (self->padded_width);
1065   self->outsize =
1066       GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) * 3 /
1067       2;
1069   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1070       self->outsize, self->stride, outcaps);
1072   if (!self->first_in_buffer) {
1073     /* Caps changed mid stream. We flush the codec to unlock all the potentially
1074      * locked buffers. This is needed for downstream sinks that provide a
1075      * buffer pool and need to destroy all the outstanding buffers before they
1076      * can negotiate new caps (hello v4l2sink).
1077      */
1078     gst_ducati_viddec_codec_flush (self, FALSE);
1079   }
1082   ret = gst_pad_set_caps (self->srcpad, outcaps);
1084   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
1086   /* default to no reordering */
1087   self->backlog_maxframes = 0;
1089 out:
1090   if (outcaps)
1091     gst_caps_unref (outcaps);
1093   return ret;
1096 static gboolean
1097 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1099   gboolean ret = TRUE;
1100   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1101   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1103   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1105   ret = klass->set_sink_caps (self, caps);
1107   gst_object_unref (self);
1109   return ret;
1112 static GstCaps *
1113 gst_ducati_viddec_src_getcaps (GstPad * pad)
1115   GstCaps *caps = NULL;
1117   caps = gst_pad_get_current_caps (pad);
1118   if (caps == NULL) {
1119     GstCaps *fil = gst_pad_get_pad_template_caps (pad);
1120     GST_DEBUG ("filter caps = %s \n", gst_caps_to_string (fil));
1121     return gst_caps_copy (fil);
1122   } else {
1123     return gst_caps_copy (caps);
1124   }
1127 static gboolean
1128 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1129     GstQuery * query, gboolean * forward)
1131   gboolean res = TRUE;
1133   switch (GST_QUERY_TYPE (query)) {
1134     case GST_QUERY_CAPS:
1135     {
1136       GstCaps *filter;
1137       filter = gst_ducati_viddec_src_getcaps (pad);
1138       gst_query_parse_caps (query, &filter);
1139       break;
1140     }
1141     case GST_QUERY_LATENCY:
1142     {
1143       gboolean live;
1144       GstClockTime min, max, latency;
1146       if (self->fps_d == 0) {
1147         GST_INFO_OBJECT (self, "not ready to report latency");
1148         res = FALSE;
1149         break;
1150       }
1152       gst_query_parse_latency (query, &live, &min, &max);
1153       if (self->fps_n != 0)
1154         latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1155       else
1156         latency = 0;
1158       /* Take into account the backlog frames for reordering */
1159       latency *= (self->backlog_maxframes + 1);
1161       if (min == GST_CLOCK_TIME_NONE)
1162         min = latency;
1163       else
1164         min += latency;
1166       if (max != GST_CLOCK_TIME_NONE)
1167         max += latency;
1169       GST_INFO_OBJECT (self,
1170           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1171           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1172       gst_query_set_latency (query, live, min, max);
1173       break;
1174     }
1175     default:
1176       break;
1177   }
1180   return res;
1183 static gboolean
1184 gst_ducati_viddec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1186   gboolean res = TRUE, forward = TRUE;
1187   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1188   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1190   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1191   res = klass->query (self, pad, query, &forward);
1192   if (res && forward)
1193     res = gst_pad_query_default (pad, parent, query);
1195   return res;
1198 static gboolean
1199 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1201   GstClockTime timestamp, qostime;
1202   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1203   gint64 diff;
1205   if (self->wait_keyframe) {
1206     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1207       GST_INFO_OBJECT (self, "skipping until the next keyframe");
1208       return FALSE;
1209     }
1211     self->wait_keyframe = FALSE;
1212   }
1214   timestamp = GST_BUFFER_PTS (buf);
1215   if (self->segment.format != GST_FORMAT_TIME ||
1216       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1217     goto no_qos;
1219   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1220     goto no_qos;
1222   qostime = gst_segment_to_running_time (&self->segment,
1223       GST_FORMAT_TIME, timestamp);
1224   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1225     /* out of segment */
1226     goto no_qos;
1228   /* see how our next timestamp relates to the latest qos timestamp. negative
1229    * values mean we are early, positive values mean we are too late. */
1230   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1232   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1233       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1234       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1235       self->qos_proportion);
1237   if (klass->can_drop_frame (self, buf, diff)) {
1238     GST_INFO_OBJECT (self, "dropping frame");
1239     return FALSE;
1240   }
1242 no_qos:
1243   return TRUE;
1246 static gboolean
1247 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1248     gint64 diff)
1250   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1251       GST_BUFFER_FLAG_DELTA_UNIT);
1253   if (diff >= 0 && !is_keyframe)
1254     return TRUE;
1256   return FALSE;
1259 static GstFlowReturn
1260 gst_ducati_viddec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1262   SizeT fd;
1264   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1265   GstClockTime ts = GST_BUFFER_PTS (buf);
1266   GstFlowReturn ret = GST_FLOW_OK;
1267   Int32 err;
1268   GstBuffer *outbuf = NULL;
1269   GstCaps *outcaps = NULL;
1270   gboolean decode;
1272   GstBufferPool *externalpool = NULL;
1273   GstQuery *query = NULL;
1274   guint min = 0;
1275   guint max = 0;
1276   guint size = 0;
1278 normal:
1279   if (G_UNLIKELY (!self->engine)) {
1280     GST_ERROR_OBJECT (self, "no engine");
1281     gst_buffer_unref (buf);
1282     return GST_FLOW_ERROR;
1283   }
1285   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1286       GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1288   decode = gst_ducati_viddec_do_qos (self, buf);
1289   if (!decode) {
1290     gst_buffer_unref (buf);
1291     return GST_FLOW_OK;
1292   }
1294   if (!self->need_out_buf)
1295     goto have_out_buf;
1297   /* do this before creating codec to ensure reverse caps negotiation
1298    * happens first:
1299    */
1300 allocate_buffer:
1301   /* For plugins like VPE that allocate buffers to peers */
1303   query =
1304       gst_query_new_allocation (gst_pad_get_current_caps (self->srcpad), TRUE);
1305   if (gst_pad_peer_query (self->srcpad, query)) {
1306     gst_query_parse_nth_allocation_pool (query, 0, &externalpool, &size, &min,
1307         &max);
1308   }
1309   gst_query_unref (query);
1311   if (externalpool) {
1312     ret =
1313         gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (externalpool), &outbuf,
1314         NULL);
1315     if (ret == GST_FLOW_OK) {
1316       GstMetaDmaBuf *meta = gst_buffer_get_dma_buf_meta (outbuf);
1317       if (!meta) {
1318         outbuf = codec_buffer_pool_get (self, NULL);
1319       }
1320     }
1321   } else {
1322     outbuf = codec_buffer_pool_get (self, NULL);
1323   }
1325   if (ret != GST_FLOW_OK) {
1326     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1327         gst_flow_get_name (ret));
1328     gst_buffer_unref (buf);
1329     return ret;
1330   }
1332   outcaps = gst_pad_get_current_caps (self->srcpad);
1333   if (outcaps
1334       && !gst_caps_is_equal (outcaps,
1335           gst_pad_get_current_caps (self->srcpad))) {
1336     GstStructure *s;
1337     gsize bufoffset, bufmaxsize, buftotalsize;
1338     guint sz;
1339     guint8 *data = NULL;
1341     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1342         gst_buffer_get_size (outbuf));
1344     s = gst_caps_get_structure (outcaps, 0);
1345     gst_structure_get_int (s, "rowstride", &self->stride);
1346     self->outsize =
1347         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
1348         3 / 2;
1350     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1351         self->outsize, self->stride, outcaps);
1353     gst_pad_set_caps (self->srcpad, outcaps);
1355     buftotalsize = gst_buffer_get_sizes (outbuf, &bufoffset, &bufmaxsize);
1356     data = g_slice_alloc (buftotalsize);
1357     sz = gst_buffer_extract (outbuf, bufoffset, data, buftotalsize);
1359 /* TO DO for vpe
1360     if (sz != self->outsize) {
1361       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1362           sz, self->outsize);
1363       gst_buffer_unref (outbuf);
1364       goto allocate_buffer;
1365     }*/
1366   }
1368   if (G_UNLIKELY (!self->codec)) {
1369     if (!codec_create (self)) {
1370       GST_ERROR_OBJECT (self, "could not create codec");
1371       gst_buffer_unref (buf);
1372       gst_buffer_unref (outbuf);
1373       return GST_FLOW_ERROR;
1374     }
1375   }
1377   GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
1378   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1380   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1381    * internal pool while self->first_out_buffer == TRUE in order to simplify
1382    * things in case we need to renegotiate */
1383   self->inArgs->inputID =
1384       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1385   if (!self->inArgs->inputID) {
1386     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1387     gst_buffer_unref (buf);
1388     return GST_FLOW_ERROR;
1389   }
1390   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1392 have_out_buf:
1393   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1395 #ifdef USE_DTS_PTS_CODE
1396   if (ts != GST_CLOCK_TIME_NONE) {
1397     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1398     /* if next buffer has earlier ts than previous, then the ts
1399      * we are getting are definitely decode order (DTS):
1400      */
1401     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1402       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1403       self->ts_may_be_pts = FALSE;
1404     }
1405     self->last_dts = ts;
1406   }
1407 #endif
1409   if (self->in_size == 0 && outbuf) {
1410     GST_DEBUG_OBJECT (self, "no input, skipping process");
1412     gst_buffer_unref (outbuf);
1413     return GST_FLOW_OK;
1414   }
1416   self->inArgs->numBytes = self->in_size;
1417   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1418   /* XDM_MemoryType required by drm to allcoate buffer */
1419   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1421   err = codec_process (self, TRUE, FALSE, &ret);
1422   if (err) {
1423     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1424         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1425     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1426         self->error_strings);
1428     return GST_FLOW_ERROR;
1429   }
1431   if (ret != GST_FLOW_OK) {
1432     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1433         gst_flow_get_name (ret));
1435     return ret;
1436   }
1438   self->first_in_buffer = FALSE;
1440   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1441     /* The copy could be avoided by playing with the buffer pointer,
1442        but it seems to be rare and for not many bytes */
1443     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1444         self->outArgs->bytesConsumed, self->in_size,
1445         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1446     if (self->outArgs->bytesConsumed > 0) {
1447       if (self->outArgs->bytesConsumed > self->in_size) {
1448         GST_WARNING_OBJECT (self,
1449             "Codec claims to have used more bytes than supplied");
1450         self->in_size = 0;
1451       } else {
1452         if (self->outArgs->bytesConsumed < self->in_size) {
1453           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1454               self->in_size - self->outArgs->bytesConsumed);
1455         }
1456         self->in_size -= self->outArgs->bytesConsumed;
1457       }
1458     }
1459   } else {
1460     self->in_size = 0;
1461   }
1463   if (self->outArgs->outBufsInUseFlag) {
1464     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1465     self->need_out_buf = FALSE;
1466   } else {
1467     self->need_out_buf = TRUE;
1468   }
1470   if (buf) {
1471     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1472         gst_buffer_get_size (buf));
1473     ts = GST_BUFFER_PTS (buf);
1474     goto allocate_buffer;
1475   }
1477   if (self->needs_flushing)
1478     gst_ducati_viddec_codec_flush (self, FALSE);
1480   return GST_FLOW_OK;
1483 static gboolean
1484 gst_ducati_viddec_event (GstPad * pad, GstObject * parent, GstEvent * event)
1486   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1487   gboolean ret = TRUE;
1489   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1491   switch (GST_EVENT_TYPE (event)) {
1492     case GST_EVENT_CAPS:
1493     {
1494       GstCaps *caps;
1495       gst_event_parse_caps (event, &caps);
1496       return gst_ducati_viddec_sink_setcaps (pad, caps);
1497       break;
1498     }
1499     case GST_EVENT_SEGMENT:
1500     {
1502       gst_event_copy_segment (event, &self->segment);
1504       break;
1505     }
1506     case GST_EVENT_EOS:
1507       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1508         GST_ERROR_OBJECT (self, "could not flush on eos");
1509         ret = FALSE;
1510       }
1511       break;
1512     case GST_EVENT_FLUSH_STOP:
1513       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1514         GST_ERROR_OBJECT (self, "could not flush");
1515         gst_event_unref (event);
1516         ret = FALSE;
1517       }
1518       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1519       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1520       self->qos_proportion = 1;
1521       self->need_out_buf = TRUE;
1522       break;
1523     default:
1524       break;
1525   }
1527   if (ret)
1528     ret = gst_pad_push_event (self->srcpad, event);
1529   GST_LOG_OBJECT (self, "end");
1531   return ret;
1534 static gboolean
1535 gst_ducati_viddec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1537   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1538   gboolean ret = TRUE;
1540   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1542   switch (GST_EVENT_TYPE (event)) {
1543     case GST_EVENT_QOS:
1544     {
1545       gdouble proportion;
1546       GstClockTimeDiff diff;
1547       GstClockTime timestamp;
1548       GstQOSType type;
1550       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
1552       GST_OBJECT_LOCK (self);
1553       self->qos_proportion = proportion;
1554       self->qos_earliest_time = timestamp + 2 * diff;
1555       GST_OBJECT_UNLOCK (self);
1557       GST_DEBUG_OBJECT (self,
1558           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1559           proportion, GST_TIME_ARGS (timestamp), diff);
1561       ret = gst_pad_push_event (self->sinkpad, event);
1562       break;
1563     }
1564     default:
1565       ret = gst_pad_push_event (self->sinkpad, event);
1566       break;
1567   }
1569   GST_LOG_OBJECT (self, "end");
1571   return ret;
1574 static GstStateChangeReturn
1575 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1577   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1578   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1579   gboolean supported;
1581   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1582       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1583       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1585   switch (transition) {
1586     case GST_STATE_CHANGE_NULL_TO_READY:
1587       if (!engine_open (self)) {
1588         GST_ERROR_OBJECT (self, "could not open");
1589         return GST_STATE_CHANGE_FAILURE;
1590       }
1591       /* try to create/destroy the codec here, it may not be supported */
1592       supported = codec_create (self);
1593       codec_delete (self);
1594       self->codec = NULL;
1595       if (!supported) {
1596         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1597             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1598         engine_close (self);
1599         return GST_STATE_CHANGE_FAILURE;
1600       }
1601       break;
1602     default:
1603       break;
1604   }
1606   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1608   if (ret == GST_STATE_CHANGE_FAILURE)
1609     goto leave;
1611   switch (transition) {
1612     case GST_STATE_CHANGE_PAUSED_TO_READY:
1613       self->interlaced = FALSE;
1614       gst_ducati_viddec_codec_flush (self, FALSE);
1615       break;
1616     case GST_STATE_CHANGE_READY_TO_NULL:
1617       codec_delete (self);
1618       engine_close (self);
1619       break;
1620     default:
1621       break;
1622   }
1624 leave:
1625   GST_LOG_OBJECT (self, "end");
1627   return ret;
1630 /* GObject vmethod implementations */
1633 static void
1634 gst_ducati_viddec_get_property (GObject * obj,
1635     guint prop_id, GValue * value, GParamSpec * pspec)
1637   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1640   switch (prop_id) {
1641     case PROP_VERSION:{
1642       int err;
1643       char *version = NULL;
1645       if (!self->engine)
1646         engine_open (self);
1648       if (!self->codec)
1649         codec_create (self);
1651       if (self->codec) {
1652         version = dce_alloc (VERSION_LENGTH);
1653         if (version) {
1654           self->status->data.buf = (XDAS_Int8 *) version;
1655           self->status->data.bufSize = VERSION_LENGTH;
1657           GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1658           err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1659               self->dynParams, self->status);
1661           if (err) {
1662             GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1663           } else
1664             GST_DEBUG ("Codec version %s", self->status->data.buf);
1666           self->status->data.buf = NULL;
1667           self->status->data.bufSize = 0;
1668           dce_free (version);
1669         }
1670       }
1671       break;
1672     }
1673     case PROP_MAX_REORDER_FRAMES:
1674       g_value_set_int (value, self->backlog_max_maxframes);
1675       break;
1676     case PROP_CODEC_DEBUG_INFO:
1677       g_value_set_boolean (value, self->codec_debug_info);
1678       break;
1679     default:{
1680       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1681       break;
1682     }
1683   }
1686 static void
1687 gst_ducati_viddec_set_property (GObject * obj,
1688     guint prop_id, const GValue * value, GParamSpec * pspec)
1690   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1692   switch (prop_id) {
1693     case PROP_MAX_REORDER_FRAMES:
1694       self->backlog_max_maxframes = g_value_get_int (value);
1695       break;
1696     case PROP_CODEC_DEBUG_INFO:
1697       self->codec_debug_info = g_value_get_boolean (value);
1698       break;
1699     default:{
1700       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1701       break;
1702     }
1703   }
1706 static void
1707 gst_ducati_viddec_finalize (GObject * obj)
1709   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1711   codec_delete (self);
1712   engine_close (self);
1714   /* Will unref the remaining buffers if needed */
1715   g_hash_table_unref (self->dce_locked_bufs);
1716   g_hash_table_unref (self->passed_in_bufs);
1717   if (self->codec_data) {
1718     gst_buffer_unref (self->codec_data);
1719     self->codec_data = NULL;
1720   }
1721   if (self->codecdata) {
1722     g_slice_free1 (self->codecdatasize, self->codecdata);
1723     self->codecdata = NULL;
1724   }
1726   G_OBJECT_CLASS (parent_class)->finalize (obj);
1729 static void
1730 gst_ducati_viddec_base_init (gpointer gclass)
1732   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1734   gst_element_class_add_pad_template (element_class,
1735       gst_static_pad_template_get (&src_factory));
1738 static void
1739 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1741   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1742   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1743   parent_class = g_type_class_peek_parent (klass);
1745   gobject_class->get_property =
1746       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1747   gobject_class->set_property =
1748       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1749   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1750   gstelement_class->change_state =
1751       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1753   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1754   klass->allocate_params =
1755       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1756   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1757   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1758   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1759   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1760   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1761   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1762   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1764   g_object_class_install_property (gobject_class, PROP_VERSION,
1765       g_param_spec_string ("version", "Version",
1766           "The codec version string", "",
1767           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1769   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1770       g_param_spec_int ("max-reorder-frames",
1771           "Maximum number of frames needed for reordering",
1772           "The maximum number of frames needed for reordering output frames. "
1773           "Only meaningful for codecs with B frames. 0 means no reordering. "
1774           "This value will be used if the correct value cannot be inferred "
1775           "from the stream. Too low a value may cause misordering, too high "
1776           "will cause extra latency.",
1777           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1778           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1780   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1781       g_param_spec_boolean ("codec-debug-info",
1782           "Gather debug info from the codec",
1783           "Gather and log relevant debug information from the codec. "
1784           "What is gathered is typically codec specific", FALSE,
1785           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1788 static void
1789 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1791   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1793   gst_ducati_set_generic_error_strings (self->error_strings);
1795   self->sinkpad =
1796       gst_pad_new_from_template (gst_element_class_get_pad_template
1797       (gstelement_class, "sink"), "sink");
1798   gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1799   gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1801   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1802   gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1803   gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1805   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1806   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1808   self->input_width = 0;
1809   self->input_height = 0;
1810   /* sane defaults in case we need to create codec without caps negotiation
1811    * (for example, to get 'version' property)
1812    */
1813   self->width = 128;
1814   self->height = 128;
1815   self->fps_n = -1;
1816   self->fps_d = -1;
1818   self->first_in_buffer = TRUE;
1819   self->first_out_buffer = FALSE;
1820   self->interlaced = FALSE;
1822 #ifdef USE_DTS_PTS_CODE
1823   self->dts_ridx = self->dts_widx = 0;
1824   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1825   self->ts_may_be_pts = TRUE;
1826   self->ts_is_pts = FALSE;
1827 #endif
1829   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1831   self->codecdata = NULL;
1832   self->codecdatasize = 0;
1834   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1836   self->qos_proportion = 1;
1837   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1838   self->wait_keyframe = TRUE;
1840   self->need_out_buf = TRUE;
1841   self->device = NULL;
1842   self->input_bo = NULL;
1844   self->backlog_maxframes = 0;
1845   self->backlog_nframes = 0;
1846   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1848   self->codec_debug_info = FALSE;
1850   self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1851       NULL, (GDestroyNotify) do_dce_buf_unlock);
1852   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1853       NULL, (GDestroyNotify) gst_buffer_unref);