]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducatividdec.c
gst-ducati: Migrate to gst 1.6.3 (V2)
[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"
27 #include <stdlib.h>
29 #define VERSION_LENGTH 256
31 static void gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass);
32 static void gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass);
33 static void gst_ducati_viddec_base_init (gpointer gclass);
34 static GstElementClass *parent_class = NULL;
36 GType
37 gst_ducati_viddec_get_type (void)
38 {
39   static GType ducati_viddec_type = 0;
41   if (!ducati_viddec_type) {
42     static const GTypeInfo ducati_viddec_info = {
43       sizeof (GstDucatiVidDecClass),
44       (GBaseInitFunc) gst_ducati_viddec_base_init,
45       NULL,
46       (GClassInitFunc) gst_ducati_viddec_class_init,
47       NULL,
48       NULL,
49       sizeof (GstDucatiVidDec),
50       0,
51       (GInstanceInitFunc) gst_ducati_viddec_init,
52     };
54     ducati_viddec_type = g_type_register_static (GST_TYPE_ELEMENT,
55         "GstDucatiVidDec", &ducati_viddec_info, 0);
56   }
57   return ducati_viddec_type;
58 }
60 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
61     GST_PAD_SRC,
62     GST_PAD_ALWAYS,
63     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("NV12"))
64     );
66 enum
67 {
68   PROP_0,
69   PROP_VERSION,
70   PROP_MAX_REORDER_FRAMES,
71   PROP_CODEC_DEBUG_INFO
72 };
74 /* helper functions */
76 static void
77 engine_close (GstDucatiVidDec * self)
78 {
79   if (self->params) {
80     dce_free (self->params);
81     self->params = NULL;
82   }
84   if (self->dynParams) {
85     dce_free (self->dynParams);
86     self->dynParams = NULL;
87   }
89   if (self->status) {
90     dce_free (self->status);
91     self->status = NULL;
92   }
94   if (self->inBufs) {
95     dce_free (self->inBufs);
96     self->inBufs = NULL;
97   }
99   if (self->outBufs) {
100     dce_free (self->outBufs);
101     self->outBufs = NULL;
102   }
104   if (self->inArgs) {
105     dce_free (self->inArgs);
106     self->inArgs = NULL;
107   }
109   if (self->outArgs) {
110     dce_free (self->outArgs);
111     self->outArgs = NULL;
112   }
114   if (self->engine) {
115     Engine_close (self->engine);
116     self->engine = NULL;
117   }
119   if (self->device) {
120     dce_deinit (self->device);
121     self->device = NULL;
122   }
125 static gboolean
126 engine_open (GstDucatiVidDec * self)
128   gboolean ret;
129   int ec;
131   if (G_UNLIKELY (self->engine)) {
132     return TRUE;
133   }
135   if (self->device == NULL) {
136     self->device = dce_init ();
137     if (self->device == NULL) {
138       GST_ERROR_OBJECT (self, "dce_init() failed");
139       return FALSE;
140     }
141   }
143   GST_DEBUG_OBJECT (self, "opening engine");
145   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
146   if (G_UNLIKELY (!self->engine)) {
147     GST_ERROR_OBJECT (self, "could not create engine");
148     return FALSE;
149   }
151   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
152       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
153       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
154       sizeof (IVIDDEC3_OutArgs));
156   return ret;
159 static void
160 codec_delete (GstDucatiVidDec * self)
162   if (self->codec) {
163     GST_DEBUG ("Calling VIDDEC3_delete");
164     VIDDEC3_delete (self->codec);
165     self->codec = NULL;
166   }
168   if (self->input_bo) {
169     close ((int) self->inBufs->descs[0].buf);
170     omap_bo_del (self->input_bo);
171     self->input_bo = NULL;
172   }
175 static gboolean
176 codec_create (GstDucatiVidDec * self)
178   gint err, n;
179   const gchar *codec_name;
180   char *version = NULL;
182   codec_delete (self);
184   if (G_UNLIKELY (!self->engine)) {
185     GST_ERROR_OBJECT (self, "no engine");
186     return FALSE;
187   }
189   /* these need to be set before VIDDEC3_create */
190   self->params->maxWidth = self->width;
191   self->params->maxHeight = self->height;
193   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
195   /* create codec: */
196   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
197   self->codec =
198       VIDDEC3_create (self->engine, (String) codec_name, self->params);
200   if (!self->codec) {
201     return FALSE;
202   }
204   GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
205   err =
206       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
207       self->status);
208   if (err) {
209     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
210     return FALSE;
211   }
213   self->first_in_buffer = TRUE;
214   self->first_out_buffer = FALSE;
216   version = dce_alloc (VERSION_LENGTH);
217   if (version) {
218     self->status->data.buf = (XDAS_Int8 *) version;
219     self->status->data.bufSize = VERSION_LENGTH;
221     GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
222     err = VIDDEC3_control (self->codec, XDM_GETVERSION,
223         self->dynParams, self->status);
225     if (err) {
226       GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
227     } else
228       GST_DEBUG ("Codec version %s", self->status->data.buf);
230     self->status->data.buf = NULL;
231     self->status->data.bufSize = 0;
232     dce_free (version);
234   }
237   /* allocate input buffer and initialize inBufs: */
238   /* FIXME:  needed size here has nothing to do with width * height */
239   self->input_bo = omap_bo_new (self->device,
240       self->width * self->height, OMAP_BO_WC);
241   self->input = omap_bo_map (self->input_bo);
242   self->inBufs->numBufs = 1;
243   /* IPC requires dmabuf fd in place of bo handle */
244   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
246   /* Actual buffers will be set later, as they will be different for every
247      frame. We allow derived classes to add their own buffers, however, so
248      we initialize the number of outBufs here, counting the number of extra
249      buffers required, including "holes" in planes, which may not be filled
250      if not assigned. */
251   self->outBufs->numBufs = 2;   /* luma and chroma planes, always */
252   for (n = 0; n < 3; n++)
253     if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
254       self->outBufs->numBufs = 2 + n + 1;
256   return TRUE;
259 static inline GstBuffer *
260 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
262   GstBuffer *ret_buf;
263   GstCaps *caps = gst_pad_get_current_caps (self->srcpad);
264   GstStructure *conf;
265   GstVideoInfo info;
266   if (!gst_video_info_from_caps (&info, caps)) {
267     GST_WARNING_OBJECT (self, "No valid pad caps");
268   }
269   if (G_UNLIKELY (!self->pool)) {
270     GstAllocator *allocator;
271     int num_buffers = 0;
272     guint size =
273         GST_ROUND_UP_4 (self->padded_width) *
274         GST_ROUND_UP_2 (self->padded_height) * 3 / 2;
276     if (self->status->maxNumDisplayBufs)
277       num_buffers = self->status->maxNumDisplayBufs + 5;
279     GST_DEBUG_OBJECT (self, "creating bufferpool");
280     GST_DEBUG_OBJECT (self, "%s\n",
281         gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
283     allocator = gst_drm_allocator_get ();
285     if (!allocator) {
286       GST_DEBUG_OBJECT (self,
287           "Did not get a DRM allocator. Proceeding with default allocator");
288     }
289     self->pool = gst_buffer_pool_new ();
290     conf = gst_buffer_pool_get_config (GST_BUFFER_POOL (self->pool));
291     gst_buffer_pool_config_set_params (conf, caps, size, num_buffers,
292         num_buffers);
293     gst_buffer_pool_config_set_allocator (conf, allocator, NULL);
294     gst_buffer_pool_set_config (GST_BUFFER_POOL (self->pool), conf);
295     gst_buffer_pool_set_active (GST_BUFFER_POOL (self->pool), TRUE);
296   }
297   gst_buffer_pool_acquire_buffer (self->pool, &ret_buf, NULL);
298   gst_buffer_add_video_crop_meta (ret_buf);
299   /* Crop meta will be checked and consumed by codec_process */
301   return ret_buf;
304 static GstMetaDucatiBufferPriv *
305 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
307   GstMetaDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
308   if (!priv) {
309     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
310     struct omap_bo *bo;
311     gint uv_offset, size;
312     GstMemory *mem = gst_buffer_peek_memory (buf, 0);
313     int fd = gst_fd_memory_get_fd (mem);
315     /* if it isn't a dmabuf buffer that we can import, then there
316      * is nothing we can do with it:
317      */
318     if (fd < 0) {
319       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
320       return NULL;
321     }
323     bo = omap_bo_from_dmabuf (self->device, fd);
324     uv_offset =
325         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height);
326     size =
327         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
328         3 / 2;
329     priv = gst_ducati_buffer_priv_set (buf, bo, uv_offset, size);
330   }
331   return priv;
334 static XDAS_Int32
335 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
336     gboolean force_internal)
338   GstMetaDucatiBufferPriv *priv = NULL;
339   int fd = -1;
341   if (!force_internal)
342     priv = get_buffer_priv (self, *buf);
344   if (!priv) {
345     GstBuffer *orig = *buf;
347     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
348     *buf = codec_buffer_pool_get (self, NULL);
349     GST_BUFFER_PTS (*buf) = GST_BUFFER_PTS (orig);
350     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
351     gst_buffer_unref (orig);
352     return codec_prepare_outbuf (self, buf, FALSE);
353   }
355   /* There are at least two buffers. Derived classes may add codec specific
356      buffers (eg, debug info) after these two if they want to. */
357   GstMemory *mem = gst_buffer_peek_memory (*buf, 0);
358   fd = gst_fd_memory_get_fd (mem);
360   if (fd < 0) {
361     GST_DEBUG_OBJECT (self, "Invalid fd");
362     return 0;
363   }
365   /* XDM_MemoryType required by drm to allcoate buffer */
366   self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
367   /* IPC requires dmabuf fd in place of bo handle */
368   self->outBufs->descs[0].buf = (XDAS_Int8 *) fd;
369   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
370   self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
371   /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
372      ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
373      should point to a single buffer fd and need to update the
374      descs[0].bufSize.bytes with the size of luminance(Y) data
375      and descs[1].bufSize.bytes with crominance(UV) */
376   self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
377   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
379   return (XDAS_Int32) * buf;
382 static GstBuffer *
383 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
385   GstBuffer *buf = (GstBuffer *) id;
387   if (buf) {
388     g_hash_table_insert (self->passed_in_bufs, buf, buf);
390     gst_buffer_ref (buf);
391   }
392   return buf;
395 static void
396 do_dce_buf_unlock (GstBuffer * buf)
398   SizeT fd;
399   /* Get dmabuf fd of the buffer to unlock */
400   GstMemory *mem = gst_buffer_peek_memory (buf, 0);
401   fd = gst_fd_memory_get_fd (mem);
403   if (fd < 0) {
404     GST_DEBUG ("Invalid Fd to unlock");
405     return;
406   }
407   dce_buf_unlock (1, &fd);
410 static void
411 dce_buf_free_all (GstBuffer * buf, gpointer key, GstDucatiVidDec * self)
413   if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
414     /* Buffer was not found in the hash table, remove it anyway */
415     gst_buffer_unref (buf);
416   }
419 static void
420 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
422   GstBuffer *buf = (GstBuffer *) id;
424   if (buf) {
425     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
426     /* Must unlock the buffer before free */
427     g_hash_table_remove (self->dce_locked_bufs, buf);
428     if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
429       /* Buffer was not found in the hash table, remove it anyway */
430       gst_buffer_unref (buf);
431     }
432   }
435 /* Called when playing in reverse */
436 static GstFlowReturn
437 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
439   GstBuffer *buf;
441   if (self->backlog_nframes == 0)
442     return GST_FLOW_OK;
444   /* send it, giving away the ref */
445   buf = self->backlog_frames[--self->backlog_nframes];
446   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
447       buf);
448   return gst_pad_push (self->srcpad, buf);
451 static GstFlowReturn
452 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
454   guint64 earliest_order = G_MAXUINT64;
455   guint earliest_index = 0, i;
456   GstBuffer *buf;
458   if (self->backlog_nframes == 0)
459     return GST_FLOW_OK;
461   /* work out which frame has the earliest poc */
462   for (i = 0; i < self->backlog_nframes; i++) {
463     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
464     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
465       earliest_order = order;
466       earliest_index = i;
467     }
468   }
470   /* send it, giving away the ref */
471   buf = self->backlog_frames[earliest_index];
472   self->backlog_frames[earliest_index] =
473       self->backlog_frames[--self->backlog_nframes];
474   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
475       buf);
476   return gst_pad_push (self->srcpad, buf);
479 static void
480 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
482   if (self->segment.format == GST_FORMAT_TIME &&
483       self->segment.rate < (gdouble) 0.0) {
484     /* negative rate */
485     /* push everything on the backlog, ignoring errors */
486     while (self->backlog_nframes > 0) {
487       gst_ducati_viddec_push_latest (self);
488     }
489   } else {
490     /* push everything on the backlog, ignoring errors */
491     while (self->backlog_nframes > 0) {
492       gst_ducati_viddec_push_earliest (self);
493     }
494   }
497 static gint
498 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
499     GstFlowReturn * flow_ret)
501   gint err, getstatus_err;
502   GstClockTime t;
503   GstBuffer *outbuf = NULL;
504   gint i;
505   SizeT fd;
506   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
507   GstFlowReturn ret = GST_FLOW_OK;
508   if (flow_ret)
509     /* never leave flow_ret uninitialized */
510     *flow_ret = GST_FLOW_OK;
512   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
513   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
515   if (self->inArgs->inputID != 0) {
516     /* Check if this inputID was already sent to the codec */
517     if (g_hash_table_contains (self->dce_locked_bufs,
518             (gpointer) self->inArgs->inputID)) {
519       int out_fd = -1;
520       GstMetaDucatiBufferPriv *priv =
521           gst_ducati_buffer_priv_get ((GstBuffer *) self->inArgs->inputID);
523       GST_DEBUG_OBJECT (self, "Resending (inputID: %08x)",
524           self->inArgs->inputID);
525       /* Input ID needs to be resent to the codec for cases like H.264 field coded pictures.
526          The decoder indicates this by setting outArgs->outBufsInUseFlag */
527       self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
529       GstMemory *mem =
530           gst_buffer_peek_memory ((GstBuffer *) self->inArgs->inputID, 0);
531       out_fd = gst_fd_memory_get_fd (mem);
532       if (out_fd < 0) {
533         GST_DEBUG_OBJECT (self, "Invalid fd %d", out_fd);
534         gst_buffer_unref (((GstBuffer *) self->inArgs->inputID));
535         return GST_FLOW_ERROR;
536       }
537       self->outBufs->descs[0].buf = (XDAS_Int8 *) out_fd;
538       self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
539       self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
540       self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
541       self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
542     } else {
543       /* Get dmabuf fd of the buffer to lock it */
544       GstMemory *mem =
545           gst_buffer_peek_memory ((GstBuffer *) self->inArgs->inputID, 0);
546       fd = gst_fd_memory_get_fd (mem);
547       if (fd < 0) {
548         GST_DEBUG_OBJECT (self, "Invalid fd %d", fd);
549         gst_buffer_unref (((GstBuffer *) self->inArgs->inputID));
550         return GST_FLOW_ERROR;
551       }
552       /* Must lock all the buffer passed to ducati */
553       GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x, fd: %d)",
554           self->inArgs->inputID, fd);
555       dce_buf_lock (1, &fd);
556       g_hash_table_insert (self->dce_locked_bufs,
557           (gpointer) self->inArgs->inputID, (gpointer) self->inArgs->inputID);
558     }
559   }
560   t = gst_util_get_timestamp ();
561   err = VIDDEC3_process (self->codec,
562       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
563   t = gst_util_get_timestamp () - t;
564   GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
565       (gint) (t / 1000000));
567   if (err) {
568     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
569         err, self->outArgs->extendedError);
570     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
571         self->error_strings);
572   }
574   if (err || self->first_in_buffer) {
575     GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
576     getstatus_err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
577         self->dynParams, self->status);
578     if (getstatus_err) {
579       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
580           getstatus_err, self->status->extendedError);
581       gst_ducati_log_extended_error_info (self->status->extendedError,
582           self->error_strings);
583     }
585     if (!getstatus_err && self->first_in_buffer) {
586       if (send && self->status->maxNumDisplayBufs != 0) {
587         GstCaps *caps;
588         GST_WARNING_OBJECT (self, "changing max-ref-frames in caps to %d",
589             self->status->maxNumDisplayBufs);
591         caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
593         gst_caps_set_simple (caps, "max-ref-frames", G_TYPE_INT,
594             self->status->maxNumDisplayBufs, NULL);
595         if (!gst_pad_set_caps (self->srcpad, caps)) {
596           GST_ERROR_OBJECT (self, "downstream didn't accept new caps");
597           err = XDM_EFAIL;
598         }
599         gst_caps_unref (caps);
600       }
601     }
602   }
604   if (err) {
605     if (flush)
606       err = XDM_EFAIL;
607     else
608       err = klass->handle_error (self, err,
609           self->outArgs->extendedError, self->status->extendedError);
610   }
612   /* we now let the codec decide */
613   self->dynParams->newFrameFlag = XDAS_FALSE;
615   if (err == XDM_EFAIL)
616     goto skip_outbuf_processing;
618   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
619     gboolean interlaced;
621     GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
622         i, self->outArgs->outputID[i]);
623     interlaced =
624         self->outArgs->displayBufs.bufDesc[0].contentType ==
625         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
627     if (interlaced) {
628       GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
629       if (!buf || !gst_buffer_is_writable (buf)) {
630         GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
631       } else {
632         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
633         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
634         if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
635           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
636         if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
637           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
638       }
639     }
641     /* Getting an extra reference for the decoder */
642     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
644     /* if send is FALSE, don't try to renegotiate as we could be flushing during
645      * a PAUSED->READY state change
646      */
647     if (send && interlaced != self->interlaced) {
648       GstCaps *caps;
650       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
651           "thinks interlaced=%d... trusting codec", self->interlaced,
652           interlaced);
654       self->interlaced = interlaced;
656       caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
657       GST_INFO_OBJECT (self, "changing interlace field in caps");
658       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
659           NULL);
660       if (!gst_pad_set_caps (self->srcpad, caps)) {
661         GST_ERROR_OBJECT (self,
662             "downstream didn't want to change interlace mode");
663         err = XDM_EFAIL;
664       }
665       gst_caps_unref (caps);
666     }
668     if (send) {
669       GstVideoCropMeta *crop = gst_buffer_get_video_crop_meta (outbuf);
670       if (crop) {
671         gint crop_width, crop_height;
672         /* send region of interest to sink on first buffer: */
673         XDM_Rect *r =
674             &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
676         crop_width = r->bottomRight.x - r->topLeft.x;
677         crop_height = r->bottomRight.y - r->topLeft.y;
679         if (crop_width > self->input_width)
680           crop_width = self->input_width;
681         if (crop_height > self->input_height)
682           crop_height = self->input_height;
684         GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
685             r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
686             crop_width, crop_height);
688         crop->x = r->topLeft.x;
689         crop->y = r->topLeft.y;
690         crop->width = crop_width;
691         crop->height = crop_height;
692       } else {
693         GST_INFO_OBJECT (self, "Crop metadata not present in buffer");
694       }
695     }
697     if (G_UNLIKELY (self->first_out_buffer) && send) {
699       self->first_out_buffer = FALSE;
701       /* Destroy the pool so the buffers we used so far are eventually released.
702        * The pool will be recreated if needed.
703        */
705       if (self->pool) {
706         gst_object_unref (self->pool);
707         self->pool = NULL;
708       }
710       if (self->externalpool) {
711         gst_object_unref (self->externalpool);
712         self->externalpool = NULL;
713       }
714     }
716     if (send) {
717       GstClockTime ts;
719       ts = GST_BUFFER_PTS (outbuf);
721       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
722           i, outbuf, GST_TIME_ARGS (ts));
724 #ifdef USE_DTS_PTS_CODE
725       if (self->ts_may_be_pts) {
726         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
727           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
728               "enabling ts_is_pts");
729           self->ts_is_pts = TRUE;
730         }
731       }
732 #endif
734       self->last_pts = ts;
736       if (self->dts_ridx != self->dts_widx) {
737         ts = self->dts_queue[self->dts_ridx++ % NDTS];
738       }
740       if (self->ts_is_pts) {
741         /* if we have a queued DTS from demuxer, use that instead: */
742         GST_BUFFER_PTS (outbuf) = ts;
743         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
744             i, outbuf, GST_TIME_ARGS (ts));
745       }
747       ret = klass->push_output (self, outbuf);
748       if (flow_ret)
749         *flow_ret = ret;
750       if (ret != GST_FLOW_OK) {
751         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
752         /* just unref the remaining buffers (if any) */
753         send = FALSE;
754       }
755     } else {
756       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
757           i, outbuf);
759       gst_buffer_unref (outbuf);
760     }
761   }
763 skip_outbuf_processing:
764   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
765     GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
766         i, self->outArgs->freeBufID[i]);
767     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
768   }
770   /* The following condition will occur when it is 
771    * not a normal flush and remote proc has crashed */
772   if (!flush && err == XDM_EFAIL) {
773     codec_delete (self);
774     self->codec = NULL;
775     engine_close (self);
776     exit (-1);
777   }
779   return err;
782 /** call control(FLUSH), and then process() to pop out all buffers */
783 gboolean
784 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
786   gint err = FALSE;
787   int prev_num_in_bufs, prev_num_out_bufs;
789   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
791   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
793   /* note: flush is synchronized against _chain() to avoid calling
794    * the codec from multiple threads
795    */
796   GST_PAD_STREAM_LOCK (self->sinkpad);
798 #ifdef USE_DTS_PTS_CODE
799   self->dts_ridx = self->dts_widx = 0;
800   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
801   self->ts_may_be_pts = TRUE;
802   self->ts_is_pts = FALSE;
803 #endif
804   self->wait_keyframe = TRUE;
805   self->in_size = 0;
806   self->needs_flushing = FALSE;
807   self->need_out_buf = TRUE;
809   if (G_UNLIKELY (self->first_in_buffer)) {
810     goto out;
811   }
813   if (G_UNLIKELY (!self->codec)) {
814     GST_WARNING_OBJECT (self, "no codec");
815     goto out;
816   }
819   GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
820   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
821   if (err) {
822     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
823     goto out;
824   }
826   prev_num_in_bufs = self->inBufs->numBufs;
827   prev_num_out_bufs = self->outBufs->numBufs;
829   self->inBufs->descs[0].bufSize.bytes = 0;
830   self->inBufs->numBufs = 0;
831   self->inArgs->numBytes = 0;
832   self->inArgs->inputID = 0;
833   self->outBufs->numBufs = 0;
835   do {
836     err = codec_process (self, eos, TRUE, NULL);
837   } while (err != XDM_EFAIL);
839   /* We flushed the decoder, we can now remove the buffer that have never been
840    * unrefed in it */
841   g_hash_table_foreach (self->dce_locked_bufs, (GHFunc) dce_buf_free_all, self);
842   g_hash_table_remove_all (self->dce_locked_bufs);
843   g_hash_table_remove_all (self->passed_in_bufs);
845   /* reset outArgs in case we're flushing in codec_process trying to do error
846    * recovery */
847   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
848   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
850   self->dynParams->newFrameFlag = XDAS_TRUE;
852   /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
853   self->inBufs->numBufs = prev_num_in_bufs;
854   self->outBufs->numBufs = prev_num_out_bufs;
856   /* on a flush, it is normal (and not an error) for the last _process() call
857    * to return an error..
858    */
859   err = XDM_EOK;
861 out:
862   GST_PAD_STREAM_UNLOCK (self->sinkpad);
863   GST_DEBUG_OBJECT (self, "done");
865   return !err;
868 /* GstDucatiVidDec vmethod default implementations */
870 static gboolean
871 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
873   const GValue *codec_data;
874   gint w, h;
876   if (gst_structure_get_int (s, "width", &self->input_width) &&
877       gst_structure_get_int (s, "height", &self->input_height)) {
879     h = ALIGN2 (self->input_height, 4); /* round up to MB */
880     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
882     /* if we've already created codec, but the resolution has changed, we
883      * need to re-create the codec:
884      */
885     if (G_UNLIKELY ((self->codec) && ((h != self->height) || (w != self->width)
886                 || self->codec_create_params_changed))) {
887       GST_DEBUG_OBJECT (self, "%dx%d => %dx%d, %d", self->width,
888           self->height, w, h, self->codec_create_params_changed);
889       codec_delete (self);
890     }
892     self->codec_create_params_changed = FALSE;
893     self->width = w;
894     self->height = h;
896     codec_data = gst_structure_get_value (s, "codec_data");
898     if (codec_data) {
899       int i;
900       GstMapInfo info;
901       gboolean mapped;
902       GstBuffer *buffer = gst_value_get_buffer (codec_data);
904       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
906       mapped = gst_buffer_map (buffer, &info, GST_MAP_READ);
907       GST_DEBUG_OBJECT (self, "codec_data dump, size = %d ", info.size);
908       for (i = 0; i < info.size; i++) {
909         GST_DEBUG_OBJECT (self, "%02x ", info.data[i]);
910       }
911       if (info.size) {
912         self->codecdata = g_slice_alloc (info.size);
913         if (self->codecdata) {
914           memcpy (self->codecdata, info.data, info.size);
915         } else {
916           GST_DEBUG_OBJECT (self, "g_slice_alloc failed");
917         }
918         self->codecdatasize = info.size;
919       }
920       if (mapped) {
921         gst_buffer_unmap (buffer, &info);
922       }
923     }
925     return TRUE;
926   }
928   return FALSE;
931 static gboolean
932 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
933     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
936   /* allocate params: */
937   self->params = dce_alloc (params_sz);
938   if (G_UNLIKELY (!self->params)) {
939     return FALSE;
940   }
941   self->params->size = params_sz;
942   self->params->maxFrameRate = 30000;
943   self->params->maxBitRate = 10000000;
945   self->params->dataEndianness = XDM_BYTE;
946   self->params->forceChromaFormat = XDM_YUV_420SP;
947   self->params->operatingMode = IVIDEO_DECODE_ONLY;
949   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
950   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
951   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
952   self->params->numInputDataUnits = 0;
953   self->params->numOutputDataUnits = 0;
955   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
956   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
957   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
958   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
960   /* allocate dynParams: */
961   self->dynParams = dce_alloc (dynparams_sz);
962   if (G_UNLIKELY (!self->dynParams)) {
963     return FALSE;
964   }
965   self->dynParams->size = dynparams_sz;
966   self->dynParams->decodeHeader = XDM_DECODE_AU;
967   self->dynParams->displayWidth = 0;
968   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
969   self->dynParams->newFrameFlag = XDAS_TRUE;
971   /* allocate status: */
972   self->status = dce_alloc (status_sz);
973   if (G_UNLIKELY (!self->status)) {
974     return FALSE;
975   }
976   memset (self->status, 0, status_sz);
977   self->status->size = status_sz;
979   /* allocate inBufs/outBufs: */
980   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
981   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
982   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
983     return FALSE;
984   }
986   /* allocate inArgs/outArgs: */
987   self->inArgs = dce_alloc (inargs_sz);
988   self->outArgs = dce_alloc (outargs_sz);
989   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
990     return FALSE;
991   }
992   self->inArgs->size = inargs_sz;
993   self->outArgs->size = outargs_sz;
995   return TRUE;
998 static GstBuffer *
999 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
1001   GstMapInfo info;
1002   gboolean mapped;
1003   if (G_UNLIKELY (self->first_in_buffer) && self->codecdata) {
1004     push_input (self, self->codecdata, self->codecdatasize);
1005   }
1006   /* just copy entire buffer */
1008   mapped = gst_buffer_map (buf, &info, GST_MAP_READ);
1009   if (mapped) {
1010     push_input (self, info.data, info.size);
1011     gst_buffer_unmap (buf, &info);
1012   }
1013   gst_buffer_unref (buf);
1015   return NULL;
1018 static GstFlowReturn
1019 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
1021   GstFlowReturn ret = GST_FLOW_OK;
1023   if (self->segment.format == GST_FORMAT_TIME &&
1024       self->segment.rate < (gdouble) 0.0) {
1025     /* negative rate: reverse playback */
1027     if (self->backlog_nframes > 0 &&
1028         (GST_BUFFER_PTS (self->backlog_frames[0]) > GST_BUFFER_PTS (buf))) {
1029       /* push out all backlog frames, since we have a buffer that is
1030          earlier than any other in the list */
1031       while (self->backlog_nframes > 0) {
1032         ret = gst_ducati_viddec_push_latest (self);
1033         if (ret != GST_FLOW_OK)
1034           break;
1035       }
1036     }
1037     /* add the frame to the list, the array will own the ref */
1038     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
1039         buf);
1040     if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
1041       self->backlog_frames[self->backlog_nframes++] = buf;
1042     } else {
1043       /* No space in the re-order buffer, drop the frame */
1044       GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
1045       gst_buffer_unref (buf);
1046     }
1048   } else {
1049     /* if no reordering info was set, just send the buffer */
1050     if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
1051       GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
1052       return gst_pad_push (self->srcpad, buf);
1053     }
1055     /* add the frame to the list, the array will own the ref */
1056     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
1057         buf);
1058     self->backlog_frames[self->backlog_nframes++] = buf;
1060     /* push till we have no more than the max needed, or error */
1061     while (self->backlog_nframes > self->backlog_maxframes) {
1062       ret = gst_ducati_viddec_push_earliest (self);
1063       if (ret != GST_FLOW_OK)
1064         break;
1065     }
1066   }
1067   return ret;
1070 static gint
1071 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
1072     gint extended_error, gint status_extended_error)
1074   if (XDM_ISFATALERROR (extended_error) || (ret == DCE_EXDM_UNSUPPORTED)
1075       || (ret == DCE_EIPC_CALL_FAIL) || (ret == DCE_EINVALID_INPUT))
1076     ret = XDM_EFAIL;
1077   else
1078     ret = XDM_EOK;
1080   return ret;
1083 /* GstElement vmethod implementations */
1085 static gboolean
1086 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
1088   gboolean ret = TRUE;
1089   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1090   GstStructure *s;
1091   GstCaps *outcaps = NULL;
1092   GstStructure *out_s;
1093   gint par_width, par_height;
1094   gboolean par_present;
1096   GST_INFO_OBJECT (self, "set_caps (sink): %" GST_PTR_FORMAT, caps);
1098   s = gst_caps_get_structure (caps, 0);
1099   if (!klass->parse_caps (self, s)) {
1100     GST_WARNING_OBJECT (self, "missing required fields");
1101     ret = FALSE;
1102     goto out;
1103   }
1105   /* update output/padded sizes */
1106   klass->update_buffer_size (self);
1108   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
1109     self->fps_n = 0;
1110     self->fps_d = 1;
1111   }
1112   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
1113   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
1114       &par_width, &par_height);
1116   outcaps = gst_pad_get_allowed_caps (self->srcpad);
1117   GST_DEBUG_OBJECT (self, "%s",
1118       gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
1119   if (outcaps) {
1120     outcaps = gst_caps_make_writable (outcaps);
1121     outcaps = gst_caps_truncate (outcaps);
1122     if (gst_caps_is_empty (outcaps)) {
1123       gst_caps_unref (outcaps);
1124       outcaps = NULL;
1125     }
1126   }
1128   if (!outcaps) {
1129     outcaps = gst_caps_new_simple ("video/x-raw",
1130         "format", G_TYPE_STRING, "NV12", NULL);
1131   }
1133   out_s = gst_caps_get_structure (outcaps, 0);
1134   gst_structure_set (out_s,
1135       "width", G_TYPE_INT, self->padded_width,
1136       "height", G_TYPE_INT, self->padded_height,
1137       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
1138   if (par_present)
1139     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1140         par_width, par_height, NULL);
1142   if (self->interlaced)
1143     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
1145   gst_structure_set (out_s, "drm_mem", G_TYPE_BOOLEAN, TRUE, NULL);
1147   self->stride = GST_ROUND_UP_4 (self->padded_width);
1149   self->outsize =
1150       GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) * 3 /
1151       2;
1153   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1154       self->outsize, self->stride, outcaps);
1156   if (!self->first_in_buffer) {
1157     /* Caps changed mid stream. We flush the codec to unlock all the potentially
1158      * locked buffers. This is needed for downstream sinks that provide a
1159      * buffer pool and need to destroy all the outstanding buffers before they
1160      * can negotiate new caps (hello v4l2sink).
1161      */
1162     gst_ducati_viddec_codec_flush (self, FALSE);
1163   }
1166   ret = gst_pad_set_caps (self->srcpad, outcaps);
1168   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
1170   /* default to no reordering */
1171   self->backlog_maxframes = 0;
1173   if (ret == TRUE) {
1174     if (self->sinkcaps)
1175       gst_caps_unref (self->sinkcaps);
1176     self->sinkcaps = gst_caps_copy (caps);
1177   }
1179 out:
1180   if (outcaps)
1181     gst_caps_unref (outcaps);
1183   return ret;
1186 static gboolean
1187 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1189   gboolean ret = TRUE;
1190   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1191   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1193   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1195   if (!self->sinkcaps || !gst_caps_is_strictly_equal (self->sinkcaps, caps))
1196     ret = klass->set_sink_caps (self, caps);
1197   else
1198     ret = TRUE;
1200   gst_object_unref (self);
1202   return ret;
1205 static GstCaps *
1206 gst_ducati_viddec_src_getcaps (GstPad * pad)
1208   GstCaps *caps = NULL;
1210   caps = gst_pad_get_current_caps (pad);
1211   if (caps == NULL) {
1212     GstCaps *fil = gst_pad_get_pad_template_caps (pad);
1213     GST_DEBUG ("filter caps = %s \n", gst_caps_to_string (fil));
1214     return gst_caps_copy (fil);
1215   } else {
1216     return gst_caps_copy (caps);
1217   }
1220 static gboolean
1221 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1222     GstQuery * query, gboolean * forward)
1224   gboolean res = TRUE;
1226   switch (GST_QUERY_TYPE (query)) {
1227     case GST_QUERY_CAPS:
1228     {
1229       GstCaps *filter;
1230       filter = gst_ducati_viddec_src_getcaps (pad);
1231       gst_query_parse_caps (query, &filter);
1232       break;
1233     }
1234     case GST_QUERY_LATENCY:
1235     {
1236       gboolean live;
1237       GstClockTime min, max, latency;
1239       if (self->fps_d == 0) {
1240         GST_INFO_OBJECT (self, "not ready to report latency");
1241         res = FALSE;
1242         break;
1243       }
1245       gst_query_parse_latency (query, &live, &min, &max);
1246       if (self->fps_n != 0)
1247         latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1248       else
1249         latency = 0;
1251       /* Take into account the backlog frames for reordering */
1252       latency *= (self->backlog_maxframes + 1);
1254       if (min == GST_CLOCK_TIME_NONE)
1255         min = latency;
1256       else
1257         min += latency;
1259       if (max != GST_CLOCK_TIME_NONE)
1260         max += latency;
1262       GST_INFO_OBJECT (self,
1263           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1264           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1265       gst_query_set_latency (query, live, min, max);
1266       break;
1267     }
1268     default:
1269       break;
1270   }
1273   return res;
1276 static gboolean
1277 gst_ducati_viddec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1279   gboolean res = TRUE, forward = TRUE;
1280   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1281   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1283   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1284   res = klass->query (self, pad, query, &forward);
1285   if (res && forward)
1286     res = gst_pad_query_default (pad, parent, query);
1288   return res;
1291 static gboolean
1292 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1294   GstClockTime timestamp, qostime;
1295   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1296   gint64 diff;
1298   if (self->wait_keyframe) {
1299     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1300       GST_INFO_OBJECT (self, "skipping until the next keyframe");
1301       return FALSE;
1302     }
1304     self->wait_keyframe = FALSE;
1305   }
1307   timestamp = GST_BUFFER_PTS (buf);
1308   if (self->segment.format != GST_FORMAT_TIME ||
1309       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1310     goto no_qos;
1312   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1313     goto no_qos;
1315   qostime = gst_segment_to_running_time (&self->segment,
1316       GST_FORMAT_TIME, timestamp);
1317   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1318     /* out of segment */
1319     goto no_qos;
1321   /* see how our next timestamp relates to the latest qos timestamp. negative
1322    * values mean we are early, positive values mean we are too late. */
1323   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1325   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1326       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1327       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1328       self->qos_proportion);
1330   if (klass->can_drop_frame (self, buf, diff)) {
1331     GST_INFO_OBJECT (self, "dropping frame");
1332     return FALSE;
1333   }
1335 no_qos:
1336   return TRUE;
1339 static gboolean
1340 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1341     gint64 diff)
1343   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1344       GST_BUFFER_FLAG_DELTA_UNIT);
1346   if (diff >= 0 && !is_keyframe)
1347     return TRUE;
1349   return FALSE;
1352 static GstFlowReturn
1353 gst_ducati_viddec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1355   SizeT fd;
1357   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1358   GstClockTime ts = GST_BUFFER_PTS (buf);
1359   GstFlowReturn ret = GST_FLOW_OK;
1360   Int32 err;
1361   GstBuffer *outbuf = NULL;
1362   GstCaps *outcaps = NULL;
1363   gboolean decode;
1365   GstQuery *query = NULL;
1366   guint min = 0;
1367   guint max = 0;
1368   guint size = 0;
1370 normal:
1371   if (G_UNLIKELY (!self->engine)) {
1372     GST_ERROR_OBJECT (self, "no engine");
1373     gst_buffer_unref (buf);
1374     return GST_FLOW_ERROR;
1375   }
1377   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1378       GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1380   decode = gst_ducati_viddec_do_qos (self, buf);
1381   if (!decode) {
1382     gst_buffer_unref (buf);
1383     return GST_FLOW_OK;
1384   }
1386   if (!self->need_out_buf)
1387     goto have_out_buf;
1389   /* do this before creating codec to ensure reverse caps negotiation
1390    * happens first:
1391    */
1392 allocate_buffer:
1393   /* For plugins like VPE that allocate buffers to peers */
1394   if (!self->queried_external_pool) {
1395     query =
1396         gst_query_new_allocation (gst_pad_get_current_caps (self->srcpad),
1397         TRUE);
1398     if (gst_pad_peer_query (self->srcpad, query)) {
1399       gst_query_parse_nth_allocation_pool (query, 0, &self->externalpool, &size,
1400           &min, &max);
1401     }
1402     gst_query_unref (query);
1403     self->queried_external_pool = TRUE;
1404   }
1406   if (self->externalpool) {
1407     gst_buffer_pool_set_active (self->externalpool, TRUE);
1408     GstFlowReturn ret_acq_buf =
1409         gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->externalpool),
1410         &outbuf,
1411         NULL);
1412     if (ret_acq_buf == GST_FLOW_OK) {
1413       gst_buffer_add_video_crop_meta (outbuf);
1414       /* Crop meta will be checked and consumed by codec_process */
1415       GstMemory *mem = gst_buffer_get_memory (outbuf, 0);
1416       gboolean mem_type = gst_is_drm_memory (mem);
1417       gst_memory_unref (mem);
1418       if (mem_type) {
1419         goto common;
1420       } else {
1421         gst_buffer_unref (outbuf);
1422       }
1423     }
1424     GST_WARNING_OBJECT (self, "acquire buffer from externalpool failed %s",
1425         gst_flow_get_name (ret_acq_buf));
1427   }
1429 aqcuire_from_own_pool:
1430   if (self->externalpool) {
1431     gst_object_unref (self->externalpool);
1432     self->externalpool = NULL;
1433   }
1434   outbuf = codec_buffer_pool_get (self, NULL);
1436 common:
1437   if (outbuf == NULL) {
1438     GST_WARNING_OBJECT (self, "alloc_buffer failed");
1439     gst_buffer_unref (buf);
1440     return GST_FLOW_ERROR;
1441   }
1443   if (G_UNLIKELY (!self->codec)) {
1444     if (!codec_create (self)) {
1445       GST_ERROR_OBJECT (self, "could not create codec");
1446       gst_buffer_unref (buf);
1447       gst_buffer_unref (outbuf);
1448       return GST_FLOW_ERROR;
1449     }
1450   }
1452   GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
1453   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1455   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1456    * internal pool while self->first_out_buffer == TRUE in order to simplify
1457    * things in case we need to renegotiate */
1458   self->inArgs->inputID =
1459       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1460   if (!self->inArgs->inputID) {
1461     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1462     gst_buffer_unref (buf);
1463     return GST_FLOW_ERROR;
1464   }
1465   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1467 have_out_buf:
1468   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1470 #ifdef USE_DTS_PTS_CODE
1471   if (ts != GST_CLOCK_TIME_NONE) {
1472     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1473     /* if next buffer has earlier ts than previous, then the ts
1474      * we are getting are definitely decode order (DTS):
1475      */
1476     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1477       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1478       self->ts_may_be_pts = FALSE;
1479     }
1480     self->last_dts = ts;
1481   }
1482 #endif
1484   if (self->in_size == 0 && outbuf) {
1485     GST_DEBUG_OBJECT (self, "no input, skipping process");
1487     gst_buffer_unref (outbuf);
1488     return GST_FLOW_OK;
1489   }
1491   self->inArgs->numBytes = self->in_size;
1492   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1493   /* XDM_MemoryType required by drm to allcoate buffer */
1494   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1496   err = codec_process (self, TRUE, FALSE, &ret);
1497   if (err) {
1498     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1499         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1500     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1501         self->error_strings);
1503     return GST_FLOW_ERROR;
1504   }
1506   if (ret != GST_FLOW_OK) {
1507     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1508         gst_flow_get_name (ret));
1510     return ret;
1511   }
1513   self->first_in_buffer = FALSE;
1515   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1516     /* The copy could be avoided by playing with the buffer pointer,
1517        but it seems to be rare and for not many bytes */
1518     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1519         self->outArgs->bytesConsumed, self->in_size,
1520         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1521     if (self->outArgs->bytesConsumed > 0) {
1522       if (self->outArgs->bytesConsumed > self->in_size) {
1523         GST_WARNING_OBJECT (self,
1524             "Codec claims to have used more bytes than supplied");
1525         self->in_size = 0;
1526       } else {
1527         if (self->outArgs->bytesConsumed < self->in_size) {
1528           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1529               self->in_size - self->outArgs->bytesConsumed);
1530         }
1531         self->in_size -= self->outArgs->bytesConsumed;
1532       }
1533     }
1534   } else {
1535     self->in_size = 0;
1536   }
1538   if (self->outArgs->outBufsInUseFlag) {
1539     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1540     self->need_out_buf = FALSE;
1541   } else {
1542     self->need_out_buf = TRUE;
1543   }
1545   if (buf) {
1546     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1547         gst_buffer_get_size (buf));
1548     ts = GST_BUFFER_PTS (buf);
1549     goto allocate_buffer;
1550   }
1552   if (self->needs_flushing)
1553     gst_ducati_viddec_codec_flush (self, FALSE);
1555   return GST_FLOW_OK;
1558 static gboolean
1559 gst_ducati_viddec_event (GstPad * pad, GstObject * parent, GstEvent * event)
1561   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1562   gboolean ret = TRUE;
1564   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1566   switch (GST_EVENT_TYPE (event)) {
1567     case GST_EVENT_CAPS:
1568     {
1569       GstCaps *caps;
1570       gst_event_parse_caps (event, &caps);
1571       return gst_ducati_viddec_sink_setcaps (pad, caps);
1572       break;
1573     }
1574     case GST_EVENT_SEGMENT:
1575     {
1577       gst_event_copy_segment (event, &self->segment);
1579       break;
1580     }
1581     case GST_EVENT_EOS:
1582       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1583         GST_ERROR_OBJECT (self, "could not flush on eos");
1584         ret = FALSE;
1585       }
1586       break;
1587     case GST_EVENT_FLUSH_STOP:
1588       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1589         GST_ERROR_OBJECT (self, "could not flush");
1590         gst_event_unref (event);
1591         ret = FALSE;
1592       }
1593       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1594       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1595       self->qos_proportion = 1;
1596       self->need_out_buf = TRUE;
1597       break;
1598     default:
1599       break;
1600   }
1602   if (ret)
1603     ret = gst_pad_push_event (self->srcpad, event);
1604   GST_LOG_OBJECT (self, "end");
1606   return ret;
1609 static gboolean
1610 gst_ducati_viddec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1612   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1613   gboolean ret = TRUE;
1615   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1617   switch (GST_EVENT_TYPE (event)) {
1618     case GST_EVENT_QOS:
1619     {
1620       gdouble proportion;
1621       GstClockTimeDiff diff;
1622       GstClockTime timestamp;
1623       GstQOSType type;
1625       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
1627       GST_OBJECT_LOCK (self);
1628       self->qos_proportion = proportion;
1629       self->qos_earliest_time = timestamp + 2 * diff;
1630       GST_OBJECT_UNLOCK (self);
1632       GST_DEBUG_OBJECT (self,
1633           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1634           proportion, GST_TIME_ARGS (timestamp), diff);
1636       ret = gst_pad_push_event (self->sinkpad, event);
1637       break;
1638     }
1639     default:
1640       ret = gst_pad_push_event (self->sinkpad, event);
1641       break;
1642   }
1644   GST_LOG_OBJECT (self, "end");
1646   return ret;
1649 static GstStateChangeReturn
1650 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1652   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1653   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1654   gboolean supported;
1656   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1657       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1658       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1660   switch (transition) {
1661     case GST_STATE_CHANGE_NULL_TO_READY:
1662       if (!engine_open (self)) {
1663         GST_ERROR_OBJECT (self, "could not open");
1664         return GST_STATE_CHANGE_FAILURE;
1665       }
1666       /* try to create/destroy the codec here, it may not be supported */
1667       supported = codec_create (self);
1668       codec_delete (self);
1669       self->codec = NULL;
1670       if (!supported) {
1671         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1672             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1673         engine_close (self);
1674         return GST_STATE_CHANGE_FAILURE;
1675       }
1676       break;
1677     default:
1678       break;
1679   }
1681   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1683   if (ret == GST_STATE_CHANGE_FAILURE)
1684     goto leave;
1686   switch (transition) {
1687     case GST_STATE_CHANGE_PAUSED_TO_READY:
1688       self->interlaced = FALSE;
1689       gst_ducati_viddec_codec_flush (self, FALSE);
1690       break;
1691     case GST_STATE_CHANGE_READY_TO_NULL:
1692       codec_delete (self);
1693       engine_close (self);
1694       break;
1695     default:
1696       break;
1697   }
1699 leave:
1700   GST_LOG_OBJECT (self, "end");
1702   return ret;
1705 /* GObject vmethod implementations */
1708 static void
1709 gst_ducati_viddec_get_property (GObject * obj,
1710     guint prop_id, GValue * value, GParamSpec * pspec)
1712   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1715   switch (prop_id) {
1716     case PROP_VERSION:{
1717       int err;
1718       char *version = NULL;
1720       if (!self->engine)
1721         engine_open (self);
1723       if (!self->codec)
1724         codec_create (self);
1726       if (self->codec) {
1727         version = dce_alloc (VERSION_LENGTH);
1728         if (version) {
1729           self->status->data.buf = (XDAS_Int8 *) version;
1730           self->status->data.bufSize = VERSION_LENGTH;
1732           GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1733           err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1734               self->dynParams, self->status);
1736           if (err) {
1737             GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1738           } else
1739             GST_DEBUG ("Codec version %s", self->status->data.buf);
1741           self->status->data.buf = NULL;
1742           self->status->data.bufSize = 0;
1743           dce_free (version);
1744         }
1745       }
1746       break;
1747     }
1748     case PROP_MAX_REORDER_FRAMES:
1749       g_value_set_int (value, self->backlog_max_maxframes);
1750       break;
1751     case PROP_CODEC_DEBUG_INFO:
1752       g_value_set_boolean (value, self->codec_debug_info);
1753       break;
1754     default:{
1755       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1756       break;
1757     }
1758   }
1761 static void
1762 gst_ducati_viddec_set_property (GObject * obj,
1763     guint prop_id, const GValue * value, GParamSpec * pspec)
1765   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1767   switch (prop_id) {
1768     case PROP_MAX_REORDER_FRAMES:
1769       self->backlog_max_maxframes = g_value_get_int (value);
1770       break;
1771     case PROP_CODEC_DEBUG_INFO:
1772       self->codec_debug_info = g_value_get_boolean (value);
1773       break;
1774     default:{
1775       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1776       break;
1777     }
1778   }
1781 static void
1782 gst_ducati_viddec_finalize (GObject * obj)
1784   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1786   codec_delete (self);
1788   if (self->sinkcaps)
1789     gst_caps_unref (self->sinkcaps);
1791   if (self->externalpool) {
1792     gst_object_unref (self->externalpool);
1793     self->externalpool = NULL;
1794   }
1796   if (self->pool) {
1797     gst_object_unref (self->pool);
1798     self->pool = NULL;
1799   }
1801   engine_close (self);
1803   /* Will unref the remaining buffers if needed */
1804   g_hash_table_unref (self->dce_locked_bufs);
1805   g_hash_table_unref (self->passed_in_bufs);
1807   if (self->codecdata) {
1808     g_slice_free1 (self->codecdatasize, self->codecdata);
1809     self->codecdata = NULL;
1810   }
1812   G_OBJECT_CLASS (parent_class)->finalize (obj);
1815 static void
1816 gst_ducati_viddec_base_init (gpointer gclass)
1818   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1820   gst_element_class_add_pad_template (element_class,
1821       gst_static_pad_template_get (&src_factory));
1824 static void
1825 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1827   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1828   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1829   parent_class = g_type_class_peek_parent (klass);
1831   gobject_class->get_property =
1832       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1833   gobject_class->set_property =
1834       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1835   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1836   gstelement_class->change_state =
1837       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1839   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1840   klass->allocate_params =
1841       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1842   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1843   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1844   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1845   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1846   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1847   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1848   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1850   g_object_class_install_property (gobject_class, PROP_VERSION,
1851       g_param_spec_string ("version", "Version",
1852           "The codec version string", "",
1853           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1855   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1856       g_param_spec_int ("max-reorder-frames",
1857           "Maximum number of frames needed for reordering",
1858           "The maximum number of frames needed for reordering output frames. "
1859           "Only meaningful for codecs with B frames. 0 means no reordering. "
1860           "This value will be used if the correct value cannot be inferred "
1861           "from the stream. Too low a value may cause misordering, too high "
1862           "will cause extra latency.",
1863           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1864           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1866   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1867       g_param_spec_boolean ("codec-debug-info",
1868           "Gather debug info from the codec",
1869           "Gather and log relevant debug information from the codec. "
1870           "What is gathered is typically codec specific", FALSE,
1871           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1874 static void
1875 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1877   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1879   gst_ducati_set_generic_error_strings (self->error_strings);
1881   self->sinkpad =
1882       gst_pad_new_from_template (gst_element_class_get_pad_template
1883       (gstelement_class, "sink"), "sink");
1884   gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1885   gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1887   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1888   gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1889   gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1891   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1892   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1894   self->input_width = 0;
1895   self->input_height = 0;
1896   /* sane defaults in case we need to create codec without caps negotiation
1897    * (for example, to get 'version' property)
1898    */
1899   self->width = 128;
1900   self->height = 128;
1901   self->fps_n = -1;
1902   self->fps_d = -1;
1904   self->first_in_buffer = TRUE;
1905   self->first_out_buffer = FALSE;
1906   self->interlaced = FALSE;
1908 #ifdef USE_DTS_PTS_CODE
1909   self->dts_ridx = self->dts_widx = 0;
1910   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1911   self->ts_may_be_pts = TRUE;
1912   self->ts_is_pts = FALSE;
1913 #endif
1915   self->codec_create_params_changed = FALSE;
1917   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1919   self->queried_external_pool = FALSE;
1920   self->externalpool = NULL;
1922   self->codecdata = NULL;
1923   self->codecdatasize = 0;
1925   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1927   self->qos_proportion = 1;
1928   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1929   self->wait_keyframe = TRUE;
1931   self->need_out_buf = TRUE;
1932   self->device = NULL;
1933   self->input_bo = NULL;
1935   self->sinkcaps = NULL;
1937   self->backlog_maxframes = 0;
1938   self->backlog_nframes = 0;
1939   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1941   self->codec_debug_info = FALSE;
1943   self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1944       NULL, (GDestroyNotify) do_dce_buf_unlock);
1945   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1946       NULL, (GDestroyNotify) gst_buffer_unref);