Enhance handling of bufferpool allocated by peer
[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   GstQuery *query = NULL;
1273   guint min = 0;
1274   guint max = 0;
1275   guint size = 0;
1277 normal:
1278   if (G_UNLIKELY (!self->engine)) {
1279     GST_ERROR_OBJECT (self, "no engine");
1280     gst_buffer_unref (buf);
1281     return GST_FLOW_ERROR;
1282   }
1284   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1285       GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1287   decode = gst_ducati_viddec_do_qos (self, buf);
1288   if (!decode) {
1289     gst_buffer_unref (buf);
1290     return GST_FLOW_OK;
1291   }
1293   if (!self->need_out_buf)
1294     goto have_out_buf;
1296   /* do this before creating codec to ensure reverse caps negotiation
1297    * happens first:
1298    */
1299 allocate_buffer:
1300   /* For plugins like VPE that allocate buffers to peers */
1301   if (!self->queried_external_pool) {
1302     query =
1303         gst_query_new_allocation (gst_pad_get_current_caps (self->srcpad),
1304         TRUE);
1305     if (gst_pad_peer_query (self->srcpad, query)) {
1306       gst_query_parse_nth_allocation_pool (query, 0, &self->externalpool, &size,
1307           &min, &max);
1308     }
1309     gst_query_unref (query);
1310     self->queried_external_pool = TRUE;
1311   }
1313   if (self->externalpool) {
1314     GstFlowReturn ret_acq_buf =
1315         gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->externalpool),
1316         &outbuf,
1317         NULL);
1318     if (ret_acq_buf == GST_FLOW_OK) {
1319       GstMetaDmaBuf *meta = gst_buffer_get_dma_buf_meta (outbuf);
1320       if (!meta) {
1321         goto aqcuire_from_own_pool;
1322       }
1323       goto common;
1324     }
1325   } else {
1326     goto aqcuire_from_own_pool;
1327   }
1329 aqcuire_from_own_pool:
1330   if (self->externalpool) {
1331     gst_object_unref (self->externalpool);
1332     self->externalpool = NULL;
1333   }
1334   outbuf = codec_buffer_pool_get (self, NULL);
1336 common:
1337   if (ret != GST_FLOW_OK) {
1338     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1339         gst_flow_get_name (ret));
1340     gst_buffer_unref (buf);
1341     return ret;
1342   }
1344   outcaps = gst_pad_get_current_caps (self->srcpad);
1345   if (outcaps
1346       && !gst_caps_is_equal (outcaps,
1347           gst_pad_get_current_caps (self->srcpad))) {
1348     GstStructure *s;
1349     gsize bufoffset, bufmaxsize, buftotalsize;
1350     guint sz;
1351     guint8 *data = NULL;
1353     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1354         gst_buffer_get_size (outbuf));
1356     s = gst_caps_get_structure (outcaps, 0);
1357     gst_structure_get_int (s, "rowstride", &self->stride);
1358     self->outsize =
1359         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
1360         3 / 2;
1362     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1363         self->outsize, self->stride, outcaps);
1365     gst_pad_set_caps (self->srcpad, outcaps);
1367     buftotalsize = gst_buffer_get_sizes (outbuf, &bufoffset, &bufmaxsize);
1368     data = g_slice_alloc (buftotalsize);
1369     sz = gst_buffer_extract (outbuf, bufoffset, data, buftotalsize);
1371 /* TO DO for vpe
1372     if (sz != self->outsize) {
1373       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1374           sz, self->outsize);
1375       gst_buffer_unref (outbuf);
1376       goto allocate_buffer;
1377     }*/
1378   }
1380   if (G_UNLIKELY (!self->codec)) {
1381     if (!codec_create (self)) {
1382       GST_ERROR_OBJECT (self, "could not create codec");
1383       gst_buffer_unref (buf);
1384       gst_buffer_unref (outbuf);
1385       return GST_FLOW_ERROR;
1386     }
1387   }
1389   GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
1390   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1392   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1393    * internal pool while self->first_out_buffer == TRUE in order to simplify
1394    * things in case we need to renegotiate */
1395   self->inArgs->inputID =
1396       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1397   if (!self->inArgs->inputID) {
1398     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1399     gst_buffer_unref (buf);
1400     return GST_FLOW_ERROR;
1401   }
1402   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1404 have_out_buf:
1405   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1407 #ifdef USE_DTS_PTS_CODE
1408   if (ts != GST_CLOCK_TIME_NONE) {
1409     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1410     /* if next buffer has earlier ts than previous, then the ts
1411      * we are getting are definitely decode order (DTS):
1412      */
1413     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1414       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1415       self->ts_may_be_pts = FALSE;
1416     }
1417     self->last_dts = ts;
1418   }
1419 #endif
1421   if (self->in_size == 0 && outbuf) {
1422     GST_DEBUG_OBJECT (self, "no input, skipping process");
1424     gst_buffer_unref (outbuf);
1425     return GST_FLOW_OK;
1426   }
1428   self->inArgs->numBytes = self->in_size;
1429   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1430   /* XDM_MemoryType required by drm to allcoate buffer */
1431   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1433   err = codec_process (self, TRUE, FALSE, &ret);
1434   if (err) {
1435     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1436         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1437     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1438         self->error_strings);
1440     return GST_FLOW_ERROR;
1441   }
1443   if (ret != GST_FLOW_OK) {
1444     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1445         gst_flow_get_name (ret));
1447     return ret;
1448   }
1450   self->first_in_buffer = FALSE;
1452   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1453     /* The copy could be avoided by playing with the buffer pointer,
1454        but it seems to be rare and for not many bytes */
1455     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1456         self->outArgs->bytesConsumed, self->in_size,
1457         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1458     if (self->outArgs->bytesConsumed > 0) {
1459       if (self->outArgs->bytesConsumed > self->in_size) {
1460         GST_WARNING_OBJECT (self,
1461             "Codec claims to have used more bytes than supplied");
1462         self->in_size = 0;
1463       } else {
1464         if (self->outArgs->bytesConsumed < self->in_size) {
1465           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1466               self->in_size - self->outArgs->bytesConsumed);
1467         }
1468         self->in_size -= self->outArgs->bytesConsumed;
1469       }
1470     }
1471   } else {
1472     self->in_size = 0;
1473   }
1475   if (self->outArgs->outBufsInUseFlag) {
1476     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1477     self->need_out_buf = FALSE;
1478   } else {
1479     self->need_out_buf = TRUE;
1480   }
1482   if (buf) {
1483     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1484         gst_buffer_get_size (buf));
1485     ts = GST_BUFFER_PTS (buf);
1486     goto allocate_buffer;
1487   }
1489   if (self->needs_flushing)
1490     gst_ducati_viddec_codec_flush (self, FALSE);
1492   return GST_FLOW_OK;
1495 static gboolean
1496 gst_ducati_viddec_event (GstPad * pad, GstObject * parent, GstEvent * event)
1498   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1499   gboolean ret = TRUE;
1501   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1503   switch (GST_EVENT_TYPE (event)) {
1504     case GST_EVENT_CAPS:
1505     {
1506       GstCaps *caps;
1507       gst_event_parse_caps (event, &caps);
1508       return gst_ducati_viddec_sink_setcaps (pad, caps);
1509       break;
1510     }
1511     case GST_EVENT_SEGMENT:
1512     {
1514       gst_event_copy_segment (event, &self->segment);
1516       break;
1517     }
1518     case GST_EVENT_EOS:
1519       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1520         GST_ERROR_OBJECT (self, "could not flush on eos");
1521         ret = FALSE;
1522       }
1523       break;
1524     case GST_EVENT_FLUSH_STOP:
1525       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1526         GST_ERROR_OBJECT (self, "could not flush");
1527         gst_event_unref (event);
1528         ret = FALSE;
1529       }
1530       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1531       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1532       self->qos_proportion = 1;
1533       self->need_out_buf = TRUE;
1534       break;
1535     default:
1536       break;
1537   }
1539   if (ret)
1540     ret = gst_pad_push_event (self->srcpad, event);
1541   GST_LOG_OBJECT (self, "end");
1543   return ret;
1546 static gboolean
1547 gst_ducati_viddec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1549   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1550   gboolean ret = TRUE;
1552   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1554   switch (GST_EVENT_TYPE (event)) {
1555     case GST_EVENT_QOS:
1556     {
1557       gdouble proportion;
1558       GstClockTimeDiff diff;
1559       GstClockTime timestamp;
1560       GstQOSType type;
1562       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
1564       GST_OBJECT_LOCK (self);
1565       self->qos_proportion = proportion;
1566       self->qos_earliest_time = timestamp + 2 * diff;
1567       GST_OBJECT_UNLOCK (self);
1569       GST_DEBUG_OBJECT (self,
1570           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1571           proportion, GST_TIME_ARGS (timestamp), diff);
1573       ret = gst_pad_push_event (self->sinkpad, event);
1574       break;
1575     }
1576     default:
1577       ret = gst_pad_push_event (self->sinkpad, event);
1578       break;
1579   }
1581   GST_LOG_OBJECT (self, "end");
1583   return ret;
1586 static GstStateChangeReturn
1587 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1589   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1590   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1591   gboolean supported;
1593   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1594       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1595       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1597   switch (transition) {
1598     case GST_STATE_CHANGE_NULL_TO_READY:
1599       if (!engine_open (self)) {
1600         GST_ERROR_OBJECT (self, "could not open");
1601         return GST_STATE_CHANGE_FAILURE;
1602       }
1603       /* try to create/destroy the codec here, it may not be supported */
1604       supported = codec_create (self);
1605       codec_delete (self);
1606       self->codec = NULL;
1607       if (!supported) {
1608         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1609             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1610         engine_close (self);
1611         return GST_STATE_CHANGE_FAILURE;
1612       }
1613       break;
1614     default:
1615       break;
1616   }
1618   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1620   if (ret == GST_STATE_CHANGE_FAILURE)
1621     goto leave;
1623   switch (transition) {
1624     case GST_STATE_CHANGE_PAUSED_TO_READY:
1625       self->interlaced = FALSE;
1626       gst_ducati_viddec_codec_flush (self, FALSE);
1627       break;
1628     case GST_STATE_CHANGE_READY_TO_NULL:
1629       codec_delete (self);
1630       engine_close (self);
1631       break;
1632     default:
1633       break;
1634   }
1636 leave:
1637   GST_LOG_OBJECT (self, "end");
1639   return ret;
1642 /* GObject vmethod implementations */
1645 static void
1646 gst_ducati_viddec_get_property (GObject * obj,
1647     guint prop_id, GValue * value, GParamSpec * pspec)
1649   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1652   switch (prop_id) {
1653     case PROP_VERSION:{
1654       int err;
1655       char *version = NULL;
1657       if (!self->engine)
1658         engine_open (self);
1660       if (!self->codec)
1661         codec_create (self);
1663       if (self->codec) {
1664         version = dce_alloc (VERSION_LENGTH);
1665         if (version) {
1666           self->status->data.buf = (XDAS_Int8 *) version;
1667           self->status->data.bufSize = VERSION_LENGTH;
1669           GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1670           err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1671               self->dynParams, self->status);
1673           if (err) {
1674             GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1675           } else
1676             GST_DEBUG ("Codec version %s", self->status->data.buf);
1678           self->status->data.buf = NULL;
1679           self->status->data.bufSize = 0;
1680           dce_free (version);
1681         }
1682       }
1683       break;
1684     }
1685     case PROP_MAX_REORDER_FRAMES:
1686       g_value_set_int (value, self->backlog_max_maxframes);
1687       break;
1688     case PROP_CODEC_DEBUG_INFO:
1689       g_value_set_boolean (value, self->codec_debug_info);
1690       break;
1691     default:{
1692       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1693       break;
1694     }
1695   }
1698 static void
1699 gst_ducati_viddec_set_property (GObject * obj,
1700     guint prop_id, const GValue * value, GParamSpec * pspec)
1702   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1704   switch (prop_id) {
1705     case PROP_MAX_REORDER_FRAMES:
1706       self->backlog_max_maxframes = g_value_get_int (value);
1707       break;
1708     case PROP_CODEC_DEBUG_INFO:
1709       self->codec_debug_info = g_value_get_boolean (value);
1710       break;
1711     default:{
1712       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1713       break;
1714     }
1715   }
1718 static void
1719 gst_ducati_viddec_finalize (GObject * obj)
1721   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1723   codec_delete (self);
1724   engine_close (self);
1726   /* Will unref the remaining buffers if needed */
1727   g_hash_table_unref (self->dce_locked_bufs);
1728   g_hash_table_unref (self->passed_in_bufs);
1729   if (self->codec_data) {
1730     gst_buffer_unref (self->codec_data);
1731     self->codec_data = NULL;
1732   }
1733   if (self->codecdata) {
1734     g_slice_free1 (self->codecdatasize, self->codecdata);
1735     self->codecdata = NULL;
1736   }
1738   G_OBJECT_CLASS (parent_class)->finalize (obj);
1741 static void
1742 gst_ducati_viddec_base_init (gpointer gclass)
1744   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1746   gst_element_class_add_pad_template (element_class,
1747       gst_static_pad_template_get (&src_factory));
1750 static void
1751 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1753   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1754   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1755   parent_class = g_type_class_peek_parent (klass);
1757   gobject_class->get_property =
1758       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1759   gobject_class->set_property =
1760       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1761   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1762   gstelement_class->change_state =
1763       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1765   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1766   klass->allocate_params =
1767       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1768   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1769   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1770   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1771   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1772   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1773   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1774   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1776   g_object_class_install_property (gobject_class, PROP_VERSION,
1777       g_param_spec_string ("version", "Version",
1778           "The codec version string", "",
1779           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1781   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1782       g_param_spec_int ("max-reorder-frames",
1783           "Maximum number of frames needed for reordering",
1784           "The maximum number of frames needed for reordering output frames. "
1785           "Only meaningful for codecs with B frames. 0 means no reordering. "
1786           "This value will be used if the correct value cannot be inferred "
1787           "from the stream. Too low a value may cause misordering, too high "
1788           "will cause extra latency.",
1789           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1790           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1792   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1793       g_param_spec_boolean ("codec-debug-info",
1794           "Gather debug info from the codec",
1795           "Gather and log relevant debug information from the codec. "
1796           "What is gathered is typically codec specific", FALSE,
1797           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1800 static void
1801 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1803   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1805   gst_ducati_set_generic_error_strings (self->error_strings);
1807   self->sinkpad =
1808       gst_pad_new_from_template (gst_element_class_get_pad_template
1809       (gstelement_class, "sink"), "sink");
1810   gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1811   gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1813   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1814   gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1815   gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1817   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1818   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1820   self->input_width = 0;
1821   self->input_height = 0;
1822   /* sane defaults in case we need to create codec without caps negotiation
1823    * (for example, to get 'version' property)
1824    */
1825   self->width = 128;
1826   self->height = 128;
1827   self->fps_n = -1;
1828   self->fps_d = -1;
1830   self->first_in_buffer = TRUE;
1831   self->first_out_buffer = FALSE;
1832   self->interlaced = FALSE;
1834 #ifdef USE_DTS_PTS_CODE
1835   self->dts_ridx = self->dts_widx = 0;
1836   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1837   self->ts_may_be_pts = TRUE;
1838   self->ts_is_pts = FALSE;
1839 #endif
1841   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1843   self->queried_external_pool = FALSE;
1844   self->externalpool = NULL;
1846   self->codecdata = NULL;
1847   self->codecdatasize = 0;
1849   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1851   self->qos_proportion = 1;
1852   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1853   self->wait_keyframe = TRUE;
1855   self->need_out_buf = TRUE;
1856   self->device = NULL;
1857   self->input_bo = NULL;
1859   self->backlog_maxframes = 0;
1860   self->backlog_nframes = 0;
1861   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1863   self->codec_debug_info = FALSE;
1865   self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1866       NULL, (GDestroyNotify) do_dce_buf_unlock);
1867   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1868       NULL, (GDestroyNotify) gst_buffer_unref);