]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducatividdec.c
Add max-ref-frames to decoder output caps
[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   GstBuffer *ret_buf;
279   if (G_UNLIKELY (!self->pool)) {
280     guint size =
281         GST_ROUND_UP_4 (self->padded_width) *
282         GST_ROUND_UP_2 (self->padded_height) * 3 / 2;
284     GST_DEBUG_OBJECT (self, "creating bufferpool");
285     GST_DEBUG_OBJECT (self, "%s\n",
286         gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
287     self->pool =
288         gst_drm_buffer_pool_new (GST_ELEMENT (self), dce_get_fd (),
289         gst_pad_get_current_caps (self->srcpad), size);
290   }
291   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
294 static GstMetaDucatiBufferPriv *
295 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
297   GstMetaDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
298   if (!priv) {
299     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
300     struct omap_bo *bo;
301     gint uv_offset, size;
303     GstMetaDmaBuf *dmabuf = gst_buffer_get_dma_buf_meta (buf);
305     /* if it isn't a dmabuf buffer that we can import, then there
306      * is nothing we can do with it:
307      */
308     if (!dmabuf) {
309       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
310       return NULL;
311     }
313     bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_meta_get_fd (dmabuf));
315     uv_offset =
316         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height);
317     size =
318         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
319         3 / 2;
321     priv = gst_ducati_buffer_priv_set (buf, bo, uv_offset, size);
322   }
323   return priv;
326 static XDAS_Int32
327 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
328     gboolean force_internal)
330   GstMetaDucatiBufferPriv *priv = NULL;
331   GstMetaDmaBuf *dmabuf = NULL;
333   if (!force_internal)
334     priv = get_buffer_priv (self, *buf);
336   if (!priv) {
337     GstBuffer *orig = *buf;
339     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
340     *buf = codec_buffer_pool_get (self, NULL);
341     GST_BUFFER_PTS (*buf) = GST_BUFFER_PTS (orig);
342     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
343     gst_buffer_unref (orig);
344     return codec_prepare_outbuf (self, buf, FALSE);
345   }
347   /* There are at least two buffers. Derived classes may add codec specific
348      buffers (eg, debug info) after these two if they want to. */
349   dmabuf = gst_buffer_get_dma_buf_meta (*buf);
350   /* XDM_MemoryType required by drm to allcoate buffer */
351   self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
352   /* IPC requires dmabuf fd in place of bo handle */
353   self->outBufs->descs[0].buf = (XDAS_Int8 *) gst_dma_buf_meta_get_fd (dmabuf);
354   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
355   self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
356   /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
357      ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
358      should point to a single buffer fd and need to update the
359      descs[0].bufSize.bytes with the size of luminance(Y) data
360      and descs[1].bufSize.bytes with crominance(UV) */
361   self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
362   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
364   return (XDAS_Int32) * buf;
367 static GstBuffer *
368 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
370   GstBuffer *buf = (GstBuffer *) id;
372   if (buf) {
373     g_hash_table_insert (self->passed_in_bufs, buf, buf);
375     gst_buffer_ref (buf);
376   }
377   return buf;
380 static void
381 do_dce_buf_unlock (GstBuffer * buf)
383   SizeT fd;
384   /* Get dmabuf fd of the buffer to unlock */
385   fd = gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta (buf));
387   dce_buf_unlock (1, &fd);
390 static void
391 dce_buf_free_all (GstBuffer * buf, gpointer key, GstDucatiVidDec * self)
393   if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
394     /* Buffer was not found in the hash table, remove it anyway */
395     gst_buffer_unref (buf);
396   }
399 static void
400 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
402   GstBuffer *buf = (GstBuffer *) id;
404   if (buf) {
405     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
406     /* Must unlock the buffer before free */
407     g_hash_table_remove (self->dce_locked_bufs, buf);
408     if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
409       /* Buffer was not found in the hash table, remove it anyway */
410       gst_buffer_unref (buf);
411     }
412   }
415 /* Called when playing in reverse */
416 static GstFlowReturn
417 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
419   GstBuffer *buf;
421   if (self->backlog_nframes == 0)
422     return GST_FLOW_OK;
424   /* send it, giving away the ref */
425   buf = self->backlog_frames[--self->backlog_nframes];
426   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
427       buf);
428   return gst_pad_push (self->srcpad, buf);
431 static GstFlowReturn
432 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
434   guint64 earliest_order = G_MAXUINT64;
435   guint earliest_index = 0, i;
436   GstBuffer *buf;
438   if (self->backlog_nframes == 0)
439     return GST_FLOW_OK;
441   /* work out which frame has the earliest poc */
442   for (i = 0; i < self->backlog_nframes; i++) {
443     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
444     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
445       earliest_order = order;
446       earliest_index = i;
447     }
448   }
450   /* send it, giving away the ref */
451   buf = self->backlog_frames[earliest_index];
452   self->backlog_frames[earliest_index] =
453       self->backlog_frames[--self->backlog_nframes];
454   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
455       buf);
456   return gst_pad_push (self->srcpad, buf);
459 static void
460 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
462   if (self->segment.format == GST_FORMAT_TIME &&
463       self->segment.rate < (gdouble) 0.0) {
464     /* negative rate */
465     /* push everything on the backlog, ignoring errors */
466     while (self->backlog_nframes > 0) {
467       gst_ducati_viddec_push_latest (self);
468     }
469   } else {
470     /* push everything on the backlog, ignoring errors */
471     while (self->backlog_nframes > 0) {
472       gst_ducati_viddec_push_earliest (self);
473     }
474   }
477 static gint
478 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
479     GstFlowReturn * flow_ret)
481   gint err, getstatus_err;
482   GstClockTime t;
483   GstBuffer *outbuf = NULL;
484   gint i;
485   SizeT fd;
486   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
487   GstFlowReturn ret = GST_FLOW_OK;
488   if (flow_ret)
489     /* never leave flow_ret uninitialized */
490     *flow_ret = GST_FLOW_OK;
492   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
493   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
495   if (self->inArgs->inputID != 0) {
496     /* Check if this inputID was already sent to the codec */
497     if (g_hash_table_contains (self->dce_locked_bufs,
498             (gpointer) self->inArgs->inputID)) {
499       GstMetaDucatiBufferPriv *priv =
500           gst_ducati_buffer_priv_get ((GstBuffer *) self->inArgs->inputID);
502       GST_DEBUG_OBJECT (self, "Resending (inputID: %08x)",
503           self->inArgs->inputID);
504       /* Input ID needs to be resent to the codec for cases like H.264 field coded pictures.
505          The decoder indicates this by setting outArgs->outBufsInUseFlag */
506       self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
507       self->outBufs->descs[0].buf = (XDAS_Int8 *)
508           gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta ((GstBuffer *)
509               self->inArgs->inputID));
510       self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
511       self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
512       self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
513       self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
514     } else {
515       /* Get dmabuf fd of the buffer to lock it */
516       fd = gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta ((GstBuffer *)
517               self->inArgs->inputID));
518       /* Must lock all the buffer passed to ducati */
519       GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x, fd: %d)",
520           self->inArgs->inputID, fd);
521       dce_buf_lock (1, &fd);
522       g_hash_table_insert (self->dce_locked_bufs,
523           (gpointer) self->inArgs->inputID, (gpointer) self->inArgs->inputID);
524     }
525   }
526   t = gst_util_get_timestamp ();
527   err = VIDDEC3_process (self->codec,
528       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
529   t = gst_util_get_timestamp () - t;
530   GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
531       (gint) (t / 1000000));
533   if (err) {
534     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
535         err, self->outArgs->extendedError);
536     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
537         self->error_strings);
538   }
540   if (err || self->first_in_buffer) {
541     GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
542     getstatus_err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
543         self->dynParams, self->status);
544     if (getstatus_err) {
545       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
546           getstatus_err, self->status->extendedError);
547       gst_ducati_log_extended_error_info (self->status->extendedError,
548           self->error_strings);
549     }
551     if (!getstatus_err && self->first_in_buffer) {
552       if (send && self->status->maxNumDisplayBufs != 0) {
553         GstCaps *caps;
554         GST_WARNING_OBJECT (self, "changing max-ref-frames in caps to %d",
555             self->status->maxNumDisplayBufs);
557         caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
559         gst_caps_set_simple (caps, "max-ref-frames", G_TYPE_INT,
560             self->status->maxNumDisplayBufs, NULL);
561         if (self->pool)
562           gst_drm_buffer_pool_set_caps (self->pool, caps);
563         if (!gst_pad_set_caps (self->srcpad, caps)) {
564           GST_ERROR_OBJECT (self, "downstream didn't accept new caps");
565           err = XDM_EFAIL;
566         }
567         gst_caps_unref (caps);
568       }
569     }
570   }
572   if (err) {
573     if (flush)
574       err = XDM_EFAIL;
575     else
576       err = klass->handle_error (self, err,
577           self->outArgs->extendedError, self->status->extendedError);
578   }
580   /* we now let the codec decide */
581   self->dynParams->newFrameFlag = XDAS_FALSE;
583   if (err == XDM_EFAIL)
584     goto skip_outbuf_processing;
586   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
587     gboolean interlaced;
589     GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
590         i, self->outArgs->outputID[i]);
591     interlaced =
592         self->outArgs->displayBufs.bufDesc[0].contentType ==
593         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
595     if (interlaced) {
596       GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
597       if (!buf || !gst_buffer_is_writable (buf)) {
598         GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
599       } else {
600         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
601         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
602         if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
603           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
604         if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
605           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
606       }
607     }
609     /* Getting an extra reference for the decoder */
610     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
612     /* if send is FALSE, don't try to renegotiate as we could be flushing during
613      * a PAUSED->READY state change
614      */
615     if (send && interlaced != self->interlaced) {
616       GstCaps *caps;
618       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
619           "thinks interlaced=%d... trusting codec", self->interlaced,
620           interlaced);
622       self->interlaced = interlaced;
624       caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
625       GST_INFO_OBJECT (self, "changing interlace field in caps");
626       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
627           NULL);
628       if (self->pool)
629         gst_drm_buffer_pool_set_caps (self->pool, caps);
630       if (!gst_pad_set_caps (self->srcpad, caps)) {
631         GST_ERROR_OBJECT (self,
632             "downstream didn't want to change interlace mode");
633         err = XDM_EFAIL;
634       }
635       gst_caps_unref (caps);
636     }
638     if (send) {
639       GstVideoCropMeta *crop = gst_buffer_get_video_crop_meta (outbuf);
640       if (crop) {
641         gint crop_width, crop_height;
642         /* send region of interest to sink on first buffer: */
643         XDM_Rect *r =
644             &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
646         crop_width = r->bottomRight.x - r->topLeft.x;
647         crop_height = r->bottomRight.y - r->topLeft.y;
649         if (crop_width > self->input_width)
650           crop_width = self->input_width;
651         if (crop_height > self->input_height)
652           crop_height = self->input_height;
654         GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
655             r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
656             crop_width, crop_height);
658         crop->x = r->topLeft.x;
659         crop->y = r->topLeft.y;
660         crop->width = crop_width;
661         crop->height = crop_height;
662       } else {
663         GST_INFO_OBJECT (self, "Crop metadata not present in buffer");
664       }
665     }
667     if (G_UNLIKELY (self->first_out_buffer) && send) {
668       GstDRMBufferPool *pool;
669       self->first_out_buffer = FALSE;
671       /* Destroy the pool so the buffers we used so far are eventually released.
672        * The pool will be recreated if needed.
673        */
674       pool = self->pool;
675       self->pool = NULL;
676       if (pool)
677         gst_drm_buffer_pool_destroy (pool);
678     }
680     if (send) {
681       GstClockTime ts;
683       ts = GST_BUFFER_PTS (outbuf);
685       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
686           i, outbuf, GST_TIME_ARGS (ts));
688 #ifdef USE_DTS_PTS_CODE
689       if (self->ts_may_be_pts) {
690         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
691           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
692               "enabling ts_is_pts");
693           self->ts_is_pts = TRUE;
694         }
695       }
696 #endif
698       self->last_pts = ts;
700       if (self->dts_ridx != self->dts_widx) {
701         ts = self->dts_queue[self->dts_ridx++ % NDTS];
702       }
704       if (self->ts_is_pts) {
705         /* if we have a queued DTS from demuxer, use that instead: */
706         GST_BUFFER_PTS (outbuf) = ts;
707         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
708             i, outbuf, GST_TIME_ARGS (ts));
709       }
711       ret = klass->push_output (self, outbuf);
712       if (flow_ret)
713         *flow_ret = ret;
714       if (ret != GST_FLOW_OK) {
715         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
716         /* just unref the remaining buffers (if any) */
717         send = FALSE;
718       }
719     } else {
720       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
721           i, outbuf);
723       gst_buffer_unref (outbuf);
724     }
725   }
727 skip_outbuf_processing:
728   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
729     GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
730         i, self->outArgs->freeBufID[i]);
731     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
732   }
734   return err;
737 /** call control(FLUSH), and then process() to pop out all buffers */
738 gboolean
739 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
741   gint err = FALSE;
742   int prev_num_in_bufs, prev_num_out_bufs;
744   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
746   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
748   /* note: flush is synchronized against _chain() to avoid calling
749    * the codec from multiple threads
750    */
751   GST_PAD_STREAM_LOCK (self->sinkpad);
753 #ifdef USE_DTS_PTS_CODE
754   self->dts_ridx = self->dts_widx = 0;
755   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
756   self->ts_may_be_pts = TRUE;
757   self->ts_is_pts = FALSE;
758 #endif
759   self->wait_keyframe = TRUE;
760   self->in_size = 0;
761   self->needs_flushing = FALSE;
762   self->need_out_buf = TRUE;
764   if (G_UNLIKELY (self->first_in_buffer)) {
765     goto out;
766   }
768   if (G_UNLIKELY (!self->codec)) {
769     GST_WARNING_OBJECT (self, "no codec");
770     goto out;
771   }
774   GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
775   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
776   if (err) {
777     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
778     goto out;
779   }
781   prev_num_in_bufs = self->inBufs->numBufs;
782   prev_num_out_bufs = self->outBufs->numBufs;
784   self->inBufs->descs[0].bufSize.bytes = 0;
785   self->inBufs->numBufs = 0;
786   self->inArgs->numBytes = 0;
787   self->inArgs->inputID = 0;
788   self->outBufs->numBufs = 0;
790   do {
791     err = codec_process (self, eos, TRUE, NULL);
792   } while (err != XDM_EFAIL);
794   /* We flushed the decoder, we can now remove the buffer that have never been
795    * unrefed in it */
796   g_hash_table_foreach (self->dce_locked_bufs, (GHFunc) dce_buf_free_all, self);
797   g_hash_table_remove_all (self->dce_locked_bufs);
798   g_hash_table_remove_all (self->passed_in_bufs);
800   /* reset outArgs in case we're flushing in codec_process trying to do error
801    * recovery */
802   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
803   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
805   self->dynParams->newFrameFlag = XDAS_TRUE;
807   /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
808   self->inBufs->numBufs = prev_num_in_bufs;
809   self->outBufs->numBufs = prev_num_out_bufs;
811   /* on a flush, it is normal (and not an error) for the last _process() call
812    * to return an error..
813    */
814   err = XDM_EOK;
816 out:
817   GST_PAD_STREAM_UNLOCK (self->sinkpad);
818   GST_DEBUG_OBJECT (self, "done");
820   return !err;
823 /* GstDucatiVidDec vmethod default implementations */
825 static gboolean
826 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
828   const GValue *codec_data;
829   gint w, h;
831   if (gst_structure_get_int (s, "width", &self->input_width) &&
832       gst_structure_get_int (s, "height", &self->input_height)) {
834     h = ALIGN2 (self->input_height, 4); /* round up to MB */
835     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
837     /* if we've already created codec, but the resolution has changed, we
838      * need to re-create the codec:
839      */
840     if (G_UNLIKELY ((self->codec) && ((h != self->height) || (w != self->width)
841                 || self->codec_create_params_changed))) {
842       GST_DEBUG_OBJECT (self, "%dx%d => %dx%d, %d", self->width,
843           self->height, w, h, self->codec_create_params_changed);
844       codec_delete (self);
845     }
847     self->codec_create_params_changed = FALSE;
848     self->width = w;
849     self->height = h;
851     codec_data = gst_structure_get_value (s, "codec_data");
853     if (codec_data) {
854       int i;
855       GstMapInfo info;
856       gboolean mapped;
857       GstBuffer *buffer = gst_value_get_buffer (codec_data);
859       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
861       mapped = gst_buffer_map (buffer, &info, GST_MAP_READ);
862       GST_DEBUG_OBJECT (self, "codec_data dump, size = %d ", info.size);
863       for (i = 0; i < info.size; i++) {
864         GST_DEBUG_OBJECT (self, "%02x ", info.data[i]);
865       }
866       if (info.size) {
867         self->codecdata = g_slice_alloc (info.size);
868         if (self->codecdata) {
869           memcpy (self->codecdata, info.data, info.size);
870         } else {
871           GST_DEBUG_OBJECT (self, "g_slice_alloc failed");
872         }
873         self->codecdatasize = info.size;
874       }
875       if (mapped) {
876         gst_buffer_unmap (buffer, &info);
877       }
878     }
880     return TRUE;
881   }
883   return FALSE;
886 static gboolean
887 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
888     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
891   /* allocate params: */
892   self->params = dce_alloc (params_sz);
893   if (G_UNLIKELY (!self->params)) {
894     return FALSE;
895   }
896   self->params->size = params_sz;
897   self->params->maxFrameRate = 30000;
898   self->params->maxBitRate = 10000000;
900   self->params->dataEndianness = XDM_BYTE;
901   self->params->forceChromaFormat = XDM_YUV_420SP;
902   self->params->operatingMode = IVIDEO_DECODE_ONLY;
904   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
905   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
906   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
907   self->params->numInputDataUnits = 0;
908   self->params->numOutputDataUnits = 0;
910   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
911   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
912   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
913   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
915   /* allocate dynParams: */
916   self->dynParams = dce_alloc (dynparams_sz);
917   if (G_UNLIKELY (!self->dynParams)) {
918     return FALSE;
919   }
920   self->dynParams->size = dynparams_sz;
921   self->dynParams->decodeHeader = XDM_DECODE_AU;
922   self->dynParams->displayWidth = 0;
923   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
924   self->dynParams->newFrameFlag = XDAS_TRUE;
926   /* allocate status: */
927   self->status = dce_alloc (status_sz);
928   if (G_UNLIKELY (!self->status)) {
929     return FALSE;
930   }
931   memset (self->status, 0, status_sz);
932   self->status->size = status_sz;
934   /* allocate inBufs/outBufs: */
935   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
936   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
937   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
938     return FALSE;
939   }
941   /* allocate inArgs/outArgs: */
942   self->inArgs = dce_alloc (inargs_sz);
943   self->outArgs = dce_alloc (outargs_sz);
944   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
945     return FALSE;
946   }
947   self->inArgs->size = inargs_sz;
948   self->outArgs->size = outargs_sz;
950   return TRUE;
953 static GstBuffer *
954 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
956   GstMapInfo info;
957   gboolean mapped;
958   if (G_UNLIKELY (self->first_in_buffer) && self->codecdata) {
959     push_input (self, self->codecdata, self->codecdatasize);
960   }
961   /* just copy entire buffer */
963   mapped = gst_buffer_map (buf, &info, GST_MAP_READ);
964   if (mapped) {
965     push_input (self, info.data, info.size);
966     gst_buffer_unmap (buf, &info);
967   }
968   gst_buffer_unref (buf);
970   return NULL;
973 static GstFlowReturn
974 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
976   GstFlowReturn ret = GST_FLOW_OK;
978   if (self->segment.format == GST_FORMAT_TIME &&
979       self->segment.rate < (gdouble) 0.0) {
980     /* negative rate: reverse playback */
982     if (self->backlog_nframes > 0 &&
983         (GST_BUFFER_PTS (self->backlog_frames[0]) > GST_BUFFER_PTS (buf))) {
984       /* push out all backlog frames, since we have a buffer that is
985          earlier than any other in the list */
986       while (self->backlog_nframes > 0) {
987         ret = gst_ducati_viddec_push_latest (self);
988         if (ret != GST_FLOW_OK)
989           break;
990       }
991     }
992     /* add the frame to the list, the array will own the ref */
993     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
994         buf);
995     if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
996       self->backlog_frames[self->backlog_nframes++] = buf;
997     } else {
998       /* No space in the re-order buffer, drop the frame */
999       GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
1000       gst_buffer_unref (buf);
1001     }
1003   } else {
1004     /* if no reordering info was set, just send the buffer */
1005     if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
1006       GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
1007       return gst_pad_push (self->srcpad, buf);
1008     }
1010     /* add the frame to the list, the array will own the ref */
1011     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
1012         buf);
1013     self->backlog_frames[self->backlog_nframes++] = buf;
1015     /* push till we have no more than the max needed, or error */
1016     while (self->backlog_nframes > self->backlog_maxframes) {
1017       ret = gst_ducati_viddec_push_earliest (self);
1018       if (ret != GST_FLOW_OK)
1019         break;
1020     }
1021   }
1022   return ret;
1025 static gint
1026 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
1027     gint extended_error, gint status_extended_error)
1029   if (XDM_ISFATALERROR (extended_error))
1030     ret = XDM_EFAIL;
1031   else
1032     ret = XDM_EOK;
1034   return ret;
1037 /* GstElement vmethod implementations */
1039 static gboolean
1040 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
1042   gboolean ret = TRUE;
1043   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1044   GstStructure *s;
1045   GstCaps *outcaps = NULL;
1046   GstStructure *out_s;
1047   gint par_width, par_height;
1048   gboolean par_present;
1050   GST_INFO_OBJECT (self, "set_caps (sink): %" GST_PTR_FORMAT, caps);
1052   s = gst_caps_get_structure (caps, 0);
1053   if (!klass->parse_caps (self, s)) {
1054     GST_WARNING_OBJECT (self, "missing required fields");
1055     ret = FALSE;
1056     goto out;
1057   }
1059   /* update output/padded sizes */
1060   klass->update_buffer_size (self);
1062   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
1063     self->fps_n = 0;
1064     self->fps_d = 1;
1065   }
1066   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
1067   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
1068       &par_width, &par_height);
1070   outcaps = gst_pad_get_allowed_caps (self->srcpad);
1071   GST_DEBUG_OBJECT (self, "%s",
1072       gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
1073   if (outcaps) {
1074     outcaps = gst_caps_make_writable (outcaps);
1075     outcaps = gst_caps_truncate (outcaps);
1076     if (gst_caps_is_empty (outcaps)) {
1077       gst_caps_unref (outcaps);
1078       outcaps = NULL;
1079     }
1080   }
1082   if (!outcaps) {
1083     outcaps = gst_caps_new_simple ("video/x-raw",
1084         "format", G_TYPE_STRING, "NV12", NULL);
1085   }
1087   out_s = gst_caps_get_structure (outcaps, 0);
1088   gst_structure_set (out_s,
1089       "width", G_TYPE_INT, self->padded_width,
1090       "height", G_TYPE_INT, self->padded_height,
1091       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
1092   if (par_present)
1093     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1094         par_width, par_height, NULL);
1096   if (self->interlaced)
1097     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
1099   self->stride = GST_ROUND_UP_4 (self->padded_width);
1101   self->outsize =
1102       GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) * 3 /
1103       2;
1105   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1106       self->outsize, self->stride, outcaps);
1108   if (!self->first_in_buffer) {
1109     /* Caps changed mid stream. We flush the codec to unlock all the potentially
1110      * locked buffers. This is needed for downstream sinks that provide a
1111      * buffer pool and need to destroy all the outstanding buffers before they
1112      * can negotiate new caps (hello v4l2sink).
1113      */
1114     gst_ducati_viddec_codec_flush (self, FALSE);
1115   }
1118   ret = gst_pad_set_caps (self->srcpad, outcaps);
1120   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
1122   /* default to no reordering */
1123   self->backlog_maxframes = 0;
1125 out:
1126   if (outcaps)
1127     gst_caps_unref (outcaps);
1129   return ret;
1132 static gboolean
1133 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1135   gboolean ret = TRUE;
1136   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1137   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1139   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1141   ret = klass->set_sink_caps (self, caps);
1143   gst_object_unref (self);
1145   return ret;
1148 static GstCaps *
1149 gst_ducati_viddec_src_getcaps (GstPad * pad)
1151   GstCaps *caps = NULL;
1153   caps = gst_pad_get_current_caps (pad);
1154   if (caps == NULL) {
1155     GstCaps *fil = gst_pad_get_pad_template_caps (pad);
1156     GST_DEBUG ("filter caps = %s \n", gst_caps_to_string (fil));
1157     return gst_caps_copy (fil);
1158   } else {
1159     return gst_caps_copy (caps);
1160   }
1163 static gboolean
1164 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1165     GstQuery * query, gboolean * forward)
1167   gboolean res = TRUE;
1169   switch (GST_QUERY_TYPE (query)) {
1170     case GST_QUERY_CAPS:
1171     {
1172       GstCaps *filter;
1173       filter = gst_ducati_viddec_src_getcaps (pad);
1174       gst_query_parse_caps (query, &filter);
1175       break;
1176     }
1177     case GST_QUERY_LATENCY:
1178     {
1179       gboolean live;
1180       GstClockTime min, max, latency;
1182       if (self->fps_d == 0) {
1183         GST_INFO_OBJECT (self, "not ready to report latency");
1184         res = FALSE;
1185         break;
1186       }
1188       gst_query_parse_latency (query, &live, &min, &max);
1189       if (self->fps_n != 0)
1190         latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1191       else
1192         latency = 0;
1194       /* Take into account the backlog frames for reordering */
1195       latency *= (self->backlog_maxframes + 1);
1197       if (min == GST_CLOCK_TIME_NONE)
1198         min = latency;
1199       else
1200         min += latency;
1202       if (max != GST_CLOCK_TIME_NONE)
1203         max += latency;
1205       GST_INFO_OBJECT (self,
1206           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1207           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1208       gst_query_set_latency (query, live, min, max);
1209       break;
1210     }
1211     default:
1212       break;
1213   }
1216   return res;
1219 static gboolean
1220 gst_ducati_viddec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1222   gboolean res = TRUE, forward = TRUE;
1223   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1224   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1226   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1227   res = klass->query (self, pad, query, &forward);
1228   if (res && forward)
1229     res = gst_pad_query_default (pad, parent, query);
1231   return res;
1234 static gboolean
1235 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1237   GstClockTime timestamp, qostime;
1238   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1239   gint64 diff;
1241   if (self->wait_keyframe) {
1242     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1243       GST_INFO_OBJECT (self, "skipping until the next keyframe");
1244       return FALSE;
1245     }
1247     self->wait_keyframe = FALSE;
1248   }
1250   timestamp = GST_BUFFER_PTS (buf);
1251   if (self->segment.format != GST_FORMAT_TIME ||
1252       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1253     goto no_qos;
1255   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1256     goto no_qos;
1258   qostime = gst_segment_to_running_time (&self->segment,
1259       GST_FORMAT_TIME, timestamp);
1260   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1261     /* out of segment */
1262     goto no_qos;
1264   /* see how our next timestamp relates to the latest qos timestamp. negative
1265    * values mean we are early, positive values mean we are too late. */
1266   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1268   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1269       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1270       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1271       self->qos_proportion);
1273   if (klass->can_drop_frame (self, buf, diff)) {
1274     GST_INFO_OBJECT (self, "dropping frame");
1275     return FALSE;
1276   }
1278 no_qos:
1279   return TRUE;
1282 static gboolean
1283 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1284     gint64 diff)
1286   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1287       GST_BUFFER_FLAG_DELTA_UNIT);
1289   if (diff >= 0 && !is_keyframe)
1290     return TRUE;
1292   return FALSE;
1295 static GstFlowReturn
1296 gst_ducati_viddec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1298   SizeT fd;
1300   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1301   GstClockTime ts = GST_BUFFER_PTS (buf);
1302   GstFlowReturn ret = GST_FLOW_OK;
1303   Int32 err;
1304   GstBuffer *outbuf = NULL;
1305   GstCaps *outcaps = NULL;
1306   gboolean decode;
1308   GstQuery *query = NULL;
1309   guint min = 0;
1310   guint max = 0;
1311   guint size = 0;
1313 normal:
1314   if (G_UNLIKELY (!self->engine)) {
1315     GST_ERROR_OBJECT (self, "no engine");
1316     gst_buffer_unref (buf);
1317     return GST_FLOW_ERROR;
1318   }
1320   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1321       GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1323   decode = gst_ducati_viddec_do_qos (self, buf);
1324   if (!decode) {
1325     gst_buffer_unref (buf);
1326     return GST_FLOW_OK;
1327   }
1329   if (!self->need_out_buf)
1330     goto have_out_buf;
1332   /* do this before creating codec to ensure reverse caps negotiation
1333    * happens first:
1334    */
1335 allocate_buffer:
1336   /* For plugins like VPE that allocate buffers to peers */
1337   if (!self->queried_external_pool) {
1338     query =
1339         gst_query_new_allocation (gst_pad_get_current_caps (self->srcpad),
1340         TRUE);
1341     if (gst_pad_peer_query (self->srcpad, query)) {
1342       gst_query_parse_nth_allocation_pool (query, 0, &self->externalpool, &size,
1343           &min, &max);
1344     }
1345     gst_query_unref (query);
1346     self->queried_external_pool = TRUE;
1347   }
1349   if (self->externalpool) {
1350     GstFlowReturn ret_acq_buf =
1351         gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->externalpool),
1352         &outbuf,
1353         NULL);
1354     if (ret_acq_buf == GST_FLOW_OK) {
1355       GstMetaDmaBuf *meta = gst_buffer_get_dma_buf_meta (outbuf);
1356       if (meta) {
1357         goto common;
1358       } else {
1359         gst_buffer_unref (outbuf);
1360       }
1361     }
1362     GST_WARNING_OBJECT (self, "acquire buffer from externalpool failed %s",
1363         gst_flow_get_name (ret_acq_buf));
1364   }
1366 aqcuire_from_own_pool:
1367   if (self->externalpool) {
1368     gst_object_unref (self->externalpool);
1369     self->externalpool = NULL;
1370   }
1371   outbuf = codec_buffer_pool_get (self, NULL);
1373 common:
1374   if (outbuf == NULL) {
1375     GST_WARNING_OBJECT (self, "alloc_buffer failed");
1376     gst_buffer_unref (buf);
1377     return GST_FLOW_ERROR;
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);
1725   if (self->externalpool) {
1726     gst_object_unref (self->externalpool);
1727     self->externalpool = NULL;
1728   }
1730   engine_close (self);
1732   /* Will unref the remaining buffers if needed */
1733   g_hash_table_unref (self->dce_locked_bufs);
1734   g_hash_table_unref (self->passed_in_bufs);
1736   if (self->codecdata) {
1737     g_slice_free1 (self->codecdatasize, self->codecdata);
1738     self->codecdata = NULL;
1739   }
1741   G_OBJECT_CLASS (parent_class)->finalize (obj);
1744 static void
1745 gst_ducati_viddec_base_init (gpointer gclass)
1747   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1749   gst_element_class_add_pad_template (element_class,
1750       gst_static_pad_template_get (&src_factory));
1753 static void
1754 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1756   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1757   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1758   parent_class = g_type_class_peek_parent (klass);
1760   gobject_class->get_property =
1761       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1762   gobject_class->set_property =
1763       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1764   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1765   gstelement_class->change_state =
1766       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1768   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1769   klass->allocate_params =
1770       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1771   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1772   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1773   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1774   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1775   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1776   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1777   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1779   g_object_class_install_property (gobject_class, PROP_VERSION,
1780       g_param_spec_string ("version", "Version",
1781           "The codec version string", "",
1782           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1784   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1785       g_param_spec_int ("max-reorder-frames",
1786           "Maximum number of frames needed for reordering",
1787           "The maximum number of frames needed for reordering output frames. "
1788           "Only meaningful for codecs with B frames. 0 means no reordering. "
1789           "This value will be used if the correct value cannot be inferred "
1790           "from the stream. Too low a value may cause misordering, too high "
1791           "will cause extra latency.",
1792           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1793           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1795   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1796       g_param_spec_boolean ("codec-debug-info",
1797           "Gather debug info from the codec",
1798           "Gather and log relevant debug information from the codec. "
1799           "What is gathered is typically codec specific", FALSE,
1800           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1803 static void
1804 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1806   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1808   gst_ducati_set_generic_error_strings (self->error_strings);
1810   self->sinkpad =
1811       gst_pad_new_from_template (gst_element_class_get_pad_template
1812       (gstelement_class, "sink"), "sink");
1813   gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1814   gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1816   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1817   gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1818   gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1820   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1821   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1823   self->input_width = 0;
1824   self->input_height = 0;
1825   /* sane defaults in case we need to create codec without caps negotiation
1826    * (for example, to get 'version' property)
1827    */
1828   self->width = 128;
1829   self->height = 128;
1830   self->fps_n = -1;
1831   self->fps_d = -1;
1833   self->first_in_buffer = TRUE;
1834   self->first_out_buffer = FALSE;
1835   self->interlaced = FALSE;
1837 #ifdef USE_DTS_PTS_CODE
1838   self->dts_ridx = self->dts_widx = 0;
1839   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1840   self->ts_may_be_pts = TRUE;
1841   self->ts_is_pts = FALSE;
1842 #endif
1844   self->codec_create_params_changed = FALSE;
1846   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1848   self->queried_external_pool = FALSE;
1849   self->externalpool = NULL;
1851   self->codecdata = NULL;
1852   self->codecdatasize = 0;
1854   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1856   self->qos_proportion = 1;
1857   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1858   self->wait_keyframe = TRUE;
1860   self->need_out_buf = TRUE;
1861   self->device = NULL;
1862   self->input_bo = NULL;
1864   self->backlog_maxframes = 0;
1865   self->backlog_nframes = 0;
1866   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1868   self->codec_debug_info = FALSE;
1870   self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1871       NULL, (GDestroyNotify) do_dce_buf_unlock);
1872   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1873       NULL, (GDestroyNotify) gst_buffer_unref);