viddec: Drop frames if out of segment
[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     omap_bo_del (self->input_bo);
170     close ((int) self->inBufs->descs[0].buf);
171     self->input_bo = NULL;
172     self->input = NULL;
173   }
176 static gboolean
177 codec_create (GstDucatiVidDec * self)
179   gint err, n;
180   const gchar *codec_name;
181   char *version = NULL;
183   codec_delete (self);
185   if (G_UNLIKELY (!self->engine)) {
186     GST_ERROR_OBJECT (self, "no engine");
187     return FALSE;
188   }
190   /* these need to be set before VIDDEC3_create */
191   self->params->maxWidth = self->width;
192   self->params->maxHeight = self->height;
194   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
196   /* create codec: */
197   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
198   self->codec =
199       VIDDEC3_create (self->engine, (String) codec_name, self->params);
201   if (!self->codec) {
202     return FALSE;
203   }
205   GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
206   err =
207       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
208       self->status);
209   if (err) {
210     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
211     return FALSE;
212   }
214   self->first_in_buffer = TRUE;
215   self->first_out_buffer = FALSE;
217   version = dce_alloc (VERSION_LENGTH);
218   if (version) {
219     self->status->data.buf = (XDAS_Int8 *) version;
220     self->status->data.bufSize = VERSION_LENGTH;
222     GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
223     err = VIDDEC3_control (self->codec, XDM_GETVERSION,
224         self->dynParams, self->status);
226     if (err) {
227       GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
228     } else
229       GST_DEBUG ("Codec version %s", self->status->data.buf);
231     self->status->data.buf = NULL;
232     self->status->data.bufSize = 0;
233     dce_free (version);
235   }
238   /* allocate input buffer and initialize inBufs: */
239   /* FIXME:  needed size here has nothing to do with width * height */
240   self->input_bo = omap_bo_new (self->device,
241       self->width * self->height, OMAP_BO_WC);
242   self->input = omap_bo_map (self->input_bo);
243   self->inBufs->numBufs = 1;
244   /* IPC requires dmabuf fd in place of bo handle */
245   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
247   /* Actual buffers will be set later, as they will be different for every
248      frame. We allow derived classes to add their own buffers, however, so
249      we initialize the number of outBufs here, counting the number of extra
250      buffers required, including "holes" in planes, which may not be filled
251      if not assigned. */
252   self->outBufs->numBufs = 2;   /* luma and chroma planes, always */
253   for (n = 0; n < 3; n++)
254     if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
255       self->outBufs->numBufs = 2 + n + 1;
257   return TRUE;
260 static inline GstBuffer *
261 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
263   GstBuffer *ret_buf;
264   GstCaps *caps = gst_pad_get_current_caps (self->srcpad);
265   GstStructure *conf;
266   GstVideoInfo info;
267   if (!gst_video_info_from_caps (&info, caps)) {
268     GST_WARNING_OBJECT (self, "No valid pad caps");
269   }
270   if (G_UNLIKELY (!self->pool)) {
271     GstAllocator *allocator;
272     int num_buffers = 0;
273     guint size =
274         GST_ROUND_UP_4 (self->padded_width) *
275         GST_ROUND_UP_2 (self->padded_height) * 3 / 2;
277     if (self->status->maxNumDisplayBufs)
278       num_buffers = MAX (6, self->status->maxNumDisplayBufs);
280     GST_DEBUG_OBJECT (self, "creating bufferpool");
281     GST_DEBUG_OBJECT (self, "%s\n",
282         gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
284     allocator = gst_drm_allocator_get ();
286     if (!allocator) {
287       GST_DEBUG_OBJECT (self,
288           "Did not get a DRM allocator. Proceeding with default allocator");
289     }
290     self->pool = gst_buffer_pool_new ();
291     conf = gst_buffer_pool_get_config (GST_BUFFER_POOL (self->pool));
292     gst_buffer_pool_config_set_params (conf, caps, size, num_buffers,
293         num_buffers);
294     gst_buffer_pool_config_set_allocator (conf, allocator, NULL);
295     gst_buffer_pool_set_config (GST_BUFFER_POOL (self->pool), conf);
296     gst_buffer_pool_set_active (GST_BUFFER_POOL (self->pool), TRUE);
297   }
298   gst_buffer_pool_acquire_buffer (self->pool, &ret_buf, NULL);
299   gst_buffer_add_video_crop_meta (ret_buf);
300   /* Crop meta will be checked and consumed by codec_process */
302   return ret_buf;
305 static GstMetaDucatiBufferPriv *
306 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
308   GstMetaDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
309   if (!priv) {
310     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
311     struct omap_bo *bo;
312     gint uv_offset, size;
313     GstMemory *mem = gst_buffer_peek_memory (buf, 0);
314     int fd = gst_fd_memory_get_fd (mem);
316     /* if it isn't a dmabuf buffer that we can import, then there
317      * is nothing we can do with it:
318      */
319     if (fd < 0) {
320       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
321       return NULL;
322     }
324     bo = omap_bo_from_dmabuf (self->device, fd);
325     uv_offset =
326         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height);
327     size =
328         GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
329         3 / 2;
330     priv = gst_ducati_buffer_priv_set (buf, bo, uv_offset, size);
331   }
332   return priv;
335 static XDAS_Int32
336 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
337     gboolean force_internal)
339   GstMetaDucatiBufferPriv *priv = NULL;
340   int fd = -1;
342   if (!force_internal)
343     priv = get_buffer_priv (self, *buf);
345   if (!priv) {
346     GstBuffer *orig = *buf;
348     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
349     *buf = codec_buffer_pool_get (self, NULL);
350     GST_BUFFER_PTS (*buf) = GST_BUFFER_PTS (orig);
351     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
352     gst_buffer_unref (orig);
353     return codec_prepare_outbuf (self, buf, FALSE);
354   }
356   /* There are at least two buffers. Derived classes may add codec specific
357      buffers (eg, debug info) after these two if they want to. */
358   GstMemory *mem = gst_buffer_peek_memory (*buf, 0);
359   fd = gst_fd_memory_get_fd (mem);
361   if (fd < 0) {
362     GST_DEBUG_OBJECT (self, "Invalid fd");
363     return 0;
364   }
366   /* XDM_MemoryType required by drm to allcoate buffer */
367   self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
368   /* IPC requires dmabuf fd in place of bo handle */
369   self->outBufs->descs[0].buf = (XDAS_Int8 *) fd;
370   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
371   self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
372   /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
373      ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
374      should point to a single buffer fd and need to update the
375      descs[0].bufSize.bytes with the size of luminance(Y) data
376      and descs[1].bufSize.bytes with crominance(UV) */
377   self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
378   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
380   return (XDAS_Int32) * buf;
383 static GstBuffer *
384 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
386   GstBuffer *buf = (GstBuffer *) id;
388   if (buf) {
389     g_hash_table_insert (self->passed_in_bufs, buf, buf);
391     gst_buffer_ref (buf);
392   }
393   return buf;
396 static void
397 do_dce_buf_unlock (GstBuffer * buf)
399   SizeT fd;
400   /* Get dmabuf fd of the buffer to unlock */
401   GstMemory *mem = gst_buffer_peek_memory (buf, 0);
402   fd = gst_fd_memory_get_fd (mem);
404   if (fd < 0) {
405     GST_DEBUG ("Invalid Fd to unlock");
406     return;
407   }
408   dce_buf_unlock (1, &fd);
411 static void
412 dce_buf_free_all (GstBuffer * buf, gpointer key, GstDucatiVidDec * self)
414   if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
415     /* Buffer was not found in the hash table, remove it anyway */
416     gst_buffer_unref (buf);
417   }
420 static void
421 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
423   GstBuffer *buf = (GstBuffer *) id;
425   if (buf) {
426     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
427     /* Must unlock the buffer before free */
428     g_hash_table_remove (self->dce_locked_bufs, buf);
429     if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
430       /* Buffer was not found in the hash table, remove it anyway */
431       gst_buffer_unref (buf);
432     }
433   }
436 /* Called when playing in reverse */
437 static GstFlowReturn
438 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
440   GstBuffer *buf;
442   if (self->backlog_nframes == 0)
443     return GST_FLOW_OK;
445   /* send it, giving away the ref */
446   buf = self->backlog_frames[--self->backlog_nframes];
447   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
448       buf);
449   return gst_pad_push (self->srcpad, buf);
452 static GstFlowReturn
453 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
455   guint64 earliest_order = G_MAXUINT64;
456   guint earliest_index = 0, i;
457   GstBuffer *buf;
459   if (self->backlog_nframes == 0)
460     return GST_FLOW_OK;
462   /* work out which frame has the earliest poc */
463   for (i = 0; i < self->backlog_nframes; i++) {
464     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
465     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
466       earliest_order = order;
467       earliest_index = i;
468     }
469   }
471   /* send it, giving away the ref */
472   buf = self->backlog_frames[earliest_index];
473   self->backlog_frames[earliest_index] =
474       self->backlog_frames[--self->backlog_nframes];
475   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
476       buf);
477   return gst_pad_push (self->srcpad, buf);
480 static void
481 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
483   if (self->segment.format == GST_FORMAT_TIME &&
484       self->segment.rate < (gdouble) 0.0) {
485     /* negative rate */
486     /* push everything on the backlog, ignoring errors */
487     while (self->backlog_nframes > 0) {
488       gst_ducati_viddec_push_latest (self);
489     }
490   } else {
491     /* push everything on the backlog, ignoring errors */
492     while (self->backlog_nframes > 0) {
493       gst_ducati_viddec_push_earliest (self);
494     }
495   }
498 static gint
499 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
500     GstFlowReturn * flow_ret)
502   gint err, getstatus_err;
503   GstClockTime t;
504   GstBuffer *outbuf = NULL;
505   gint i;
506   SizeT fd;
507   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
508   GstFlowReturn ret = GST_FLOW_OK;
509   if (flow_ret)
510     /* never leave flow_ret uninitialized */
511     *flow_ret = GST_FLOW_OK;
513   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
514   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
516   if (self->inArgs->inputID != 0) {
517     /* Check if this inputID was already sent to the codec */
518     if (g_hash_table_contains (self->dce_locked_bufs,
519             (gpointer) self->inArgs->inputID)) {
520       int out_fd = -1;
521       GstMetaDucatiBufferPriv *priv =
522           gst_ducati_buffer_priv_get ((GstBuffer *) self->inArgs->inputID);
524       GST_DEBUG_OBJECT (self, "Resending (inputID: %08x)",
525           self->inArgs->inputID);
526       /* Input ID needs to be resent to the codec for cases like H.264 field coded pictures.
527          The decoder indicates this by setting outArgs->outBufsInUseFlag */
528       self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
530       GstMemory *mem =
531           gst_buffer_peek_memory ((GstBuffer *) self->inArgs->inputID, 0);
532       out_fd = gst_fd_memory_get_fd (mem);
533       if (out_fd < 0) {
534         GST_DEBUG_OBJECT (self, "Invalid fd %d", out_fd);
535         gst_buffer_unref (((GstBuffer *) self->inArgs->inputID));
536         return GST_FLOW_ERROR;
537       }
538       self->outBufs->descs[0].buf = (XDAS_Int8 *) out_fd;
539       self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
540       self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
541       self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
542       self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
543     } else {
544       /* Get dmabuf fd of the buffer to lock it */
545       GstMemory *mem =
546           gst_buffer_peek_memory ((GstBuffer *) self->inArgs->inputID, 0);
547       fd = gst_fd_memory_get_fd (mem);
548       if (fd < 0) {
549         GST_DEBUG_OBJECT (self, "Invalid fd %d", fd);
550         gst_buffer_unref (((GstBuffer *) self->inArgs->inputID));
551         return GST_FLOW_ERROR;
552       }
553       /* Must lock all the buffer passed to ducati */
554       GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x, fd: %d)",
555           self->inArgs->inputID, fd);
556       dce_buf_lock (1, &fd);
557       g_hash_table_insert (self->dce_locked_bufs,
558           (gpointer) self->inArgs->inputID, (gpointer) self->inArgs->inputID);
559     }
560   }
561   t = gst_util_get_timestamp ();
562   err = VIDDEC3_process (self->codec,
563       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
564   t = gst_util_get_timestamp () - t;
565   GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
566       (gint) (t / 1000000));
568   if (err) {
569     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
570         err, self->outArgs->extendedError);
571     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
572         self->error_strings);
573   }
575   if (err || self->first_in_buffer) {
576     GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
577     getstatus_err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
578         self->dynParams, self->status);
579     if (getstatus_err) {
580       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
581           getstatus_err, self->status->extendedError);
582       gst_ducati_log_extended_error_info (self->status->extendedError,
583           self->error_strings);
584     }
586     if (!getstatus_err && self->first_in_buffer) {
587       if (send && self->status->maxNumDisplayBufs != 0) {
588         GstCaps *caps;
589         GST_WARNING_OBJECT (self, "changing max-ref-frames in caps to %d",
590             self->status->maxNumDisplayBufs);
592         caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
594         gst_caps_set_simple (caps, "max-ref-frames", G_TYPE_INT,
595             self->status->maxNumDisplayBufs, NULL);
596         if (!gst_pad_set_caps (self->srcpad, caps)) {
597           GST_ERROR_OBJECT (self, "downstream didn't accept new caps");
598           err = XDM_EFAIL;
599         }
601         if (self->pool) {
602           gst_object_unref (self->pool);
603           self->pool = NULL;
604         }
605         gst_caps_unref (caps);
606       }
607     }
608   }
610   if (err) {
611     if (flush)
612       err = XDM_EFAIL;
613     else
614       err = klass->handle_error (self, err,
615           self->outArgs->extendedError, self->status->extendedError);
616   }
618   /* we now let the codec decide */
619   self->dynParams->newFrameFlag = XDAS_FALSE;
621   if (err == XDM_EFAIL)
622     goto skip_outbuf_processing;
624   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
625     gboolean interlaced;
627     GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
628         i, self->outArgs->outputID[i]);
629     interlaced =
630         self->outArgs->displayBufs.bufDesc[0].contentType ==
631         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
633     if (interlaced) {
634       GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
635       if (!buf || !gst_buffer_is_writable (buf)) {
636         GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
637       } else {
638         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
639         GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
640         if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
641           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
642         if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
643           GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
644       }
645     }
647     /* Getting an extra reference for the decoder */
648     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
650     /* if send is FALSE, don't try to renegotiate as we could be flushing during
651      * a PAUSED->READY state change
652      */
653     if (send && interlaced != self->interlaced) {
654       GstCaps *caps;
656       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
657           "thinks interlaced=%d... trusting codec", self->interlaced,
658           interlaced);
660       self->interlaced = interlaced;
662       caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
663       GST_INFO_OBJECT (self, "changing interlace field in caps");
664       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
665           NULL);
666       if (!gst_pad_set_caps (self->srcpad, caps)) {
667         GST_ERROR_OBJECT (self,
668             "downstream didn't want to change interlace mode");
669         err = XDM_EFAIL;
670       }
671       gst_caps_unref (caps);
672     }
674     if (send) {
675       GstVideoCropMeta *crop = gst_buffer_get_video_crop_meta (outbuf);
676       if (crop) {
677         gint crop_width, crop_height;
678         /* send region of interest to sink on first buffer: */
679         XDM_Rect *r =
680             &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
682         crop_width = r->bottomRight.x - r->topLeft.x;
683         crop_height = r->bottomRight.y - r->topLeft.y;
685         if (crop_width > self->input_width)
686           crop_width = self->input_width;
687         if (crop_height > self->input_height)
688           crop_height = self->input_height;
690         GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
691             r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
692             crop_width, crop_height);
694         crop->x = r->topLeft.x;
695         crop->y = r->topLeft.y;
696         crop->width = crop_width;
697         crop->height = crop_height;
698       } else {
699         GST_INFO_OBJECT (self, "Crop metadata not present in buffer");
700       }
701     }
703     if (G_UNLIKELY (self->first_out_buffer) && send) {
705       self->first_out_buffer = FALSE;
707       /* Destroy the pool so the buffers we used so far are eventually released.
708        * The pool will be recreated if needed.
709        */
711       if (self->pool) {
712         gst_object_unref (self->pool);
713         self->pool = NULL;
714       }
716     }
718     if (send && self->out_of_segment == FALSE ) {
719       GstClockTime ts;
721       ts = GST_BUFFER_PTS (outbuf);
723       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
724           i, outbuf, GST_TIME_ARGS (ts));
726 #ifdef USE_DTS_PTS_CODE
727       if (self->ts_may_be_pts) {
728         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
729           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
730               "enabling ts_is_pts");
731           self->ts_is_pts = TRUE;
732         }
733       }
734 #endif
736       self->last_pts = ts;
738       if (self->dts_ridx != self->dts_widx) {
739         ts = self->dts_queue[self->dts_ridx++ % NDTS];
740       }
742       if (self->ts_is_pts) {
743         /* if we have a queued DTS from demuxer, use that instead: */
744         GST_BUFFER_PTS (outbuf) = ts;
745         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
746             i, outbuf, GST_TIME_ARGS (ts));
747       }
749       ret = klass->push_output (self, outbuf);
750       if (flow_ret)
751         *flow_ret = ret;
752       if (ret != GST_FLOW_OK) {
753         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
754         /* just unref the remaining buffers (if any) */
755         send = FALSE;
756       }
757     } else {
758       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
759           i, outbuf);
761       gst_buffer_unref (outbuf);
762     }
763   }
765 skip_outbuf_processing:
766   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
767     GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
768         i, self->outArgs->freeBufID[i]);
769     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
770   }
772   /* The following condition will occur when it is 
773    * not a normal flush and remote proc has crashed */
774   if (!flush && err == XDM_EFAIL) {
775     codec_delete (self);
776     self->codec = NULL;
777     engine_close (self);
778     exit (-1);
779   }
781   return err;
784 /** call control(FLUSH), and then process() to pop out all buffers */
785 gboolean
786 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
788   gint err = FALSE;
789   int prev_num_in_bufs, prev_num_out_bufs;
791   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
793   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
795   /* note: flush is synchronized against _chain() to avoid calling
796    * the codec from multiple threads
797    */
798   GST_PAD_STREAM_LOCK (self->sinkpad);
800 #ifdef USE_DTS_PTS_CODE
801   self->dts_ridx = self->dts_widx = 0;
802   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
803   self->ts_may_be_pts = TRUE;
804   self->ts_is_pts = FALSE;
805 #endif
806   self->wait_keyframe = TRUE;
807   self->in_size = 0;
808   self->needs_flushing = FALSE;
809   self->need_out_buf = TRUE;
811   if (G_UNLIKELY (self->first_in_buffer)) {
812     goto out;
813   }
815   if (G_UNLIKELY (!self->codec)) {
816     GST_WARNING_OBJECT (self, "no codec");
817     goto out;
818   }
821   GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
822   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
823   if (err) {
824     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
825     goto out;
826   }
828   prev_num_in_bufs = self->inBufs->numBufs;
829   prev_num_out_bufs = self->outBufs->numBufs;
831   self->inBufs->descs[0].bufSize.bytes = 0;
832   self->inBufs->numBufs = 0;
833   self->inArgs->numBytes = 0;
834   self->inArgs->inputID = 0;
835   self->outBufs->numBufs = 0;
837   do {
838     err = codec_process (self, eos, TRUE, NULL);
839   } while (err != XDM_EFAIL);
841   /* We flushed the decoder, we can now remove the buffer that have never been
842    * unrefed in it */
843   g_hash_table_foreach (self->dce_locked_bufs, (GHFunc) dce_buf_free_all, self);
844   g_hash_table_remove_all (self->dce_locked_bufs);
845   g_hash_table_remove_all (self->passed_in_bufs);
847   /* reset outArgs in case we're flushing in codec_process trying to do error
848    * recovery */
849   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
850   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
852   self->dynParams->newFrameFlag = XDAS_TRUE;
854   /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
855   self->inBufs->numBufs = prev_num_in_bufs;
856   self->outBufs->numBufs = prev_num_out_bufs;
858   /* on a flush, it is normal (and not an error) for the last _process() call
859    * to return an error..
860    */
861   err = XDM_EOK;
863 out:
864   GST_PAD_STREAM_UNLOCK (self->sinkpad);
865   GST_DEBUG_OBJECT (self, "done");
867   return !err;
870 /* GstDucatiVidDec vmethod default implementations */
872 static gboolean
873 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
875   const GValue *codec_data;
876   gint w, h;
878   if (gst_structure_get_int (s, "width", &self->input_width) &&
879       gst_structure_get_int (s, "height", &self->input_height)) {
881     h = ALIGN2 (self->input_height, 4); /* round up to MB */
882     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
885   } else {
887     h = ALIGN2 (1080, 4); /* round up to MB */
888     w = ALIGN2 (1920, 4);  /* round up to MB */
889   }
891     /* if we've already created codec, but the resolution has changed, we
892      * need to re-create the codec:
893      */
894     if (G_UNLIKELY ((self->codec) && ((h != self->height) || (w != self->width)
895                 || self->codec_create_params_changed))) {
896       GST_DEBUG_OBJECT (self, "%dx%d => %dx%d, %d", self->width,
897           self->height, w, h, self->codec_create_params_changed);
898       codec_delete (self);
899     }
901     self->codec_create_params_changed = FALSE;
902     self->width = w;
903     self->height = h;
905     codec_data = gst_structure_get_value (s, "codec_data");
907     if (codec_data) {
908       int i;
909       GstMapInfo info;
910       gboolean mapped;
911       GstBuffer *buffer = gst_value_get_buffer (codec_data);
913       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
915       mapped = gst_buffer_map (buffer, &info, GST_MAP_READ);
916       GST_DEBUG_OBJECT (self, "codec_data dump, size = %d ", info.size);
917       for (i = 0; i < info.size; i++) {
918         GST_DEBUG_OBJECT (self, "%02x ", info.data[i]);
919       }
920       if (info.size) {
921         self->codecdata = g_slice_alloc (info.size);
922         if (self->codecdata) {
923           memcpy (self->codecdata, info.data, info.size);
924         } else {
925           GST_DEBUG_OBJECT (self, "g_slice_alloc failed");
926         }
927         self->codecdatasize = info.size;
928       }
929       if (mapped) {
930         gst_buffer_unmap (buffer, &info);
931       }
933     }
935   return TRUE;
938 static gboolean
939 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
940     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
943   /* allocate params: */
944   self->params = dce_alloc (params_sz);
945   if (G_UNLIKELY (!self->params)) {
946     return FALSE;
947   }
948   self->params->size = params_sz;
949   self->params->maxFrameRate = 30000;
950   self->params->maxBitRate = 10000000;
952   self->params->dataEndianness = XDM_BYTE;
953   self->params->forceChromaFormat = XDM_YUV_420SP;
954   self->params->operatingMode = IVIDEO_DECODE_ONLY;
956   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
957   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
958   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
959   self->params->numInputDataUnits = 0;
960   self->params->numOutputDataUnits = 0;
962   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
963   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
964   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
965   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
967   /* allocate dynParams: */
968   self->dynParams = dce_alloc (dynparams_sz);
969   if (G_UNLIKELY (!self->dynParams)) {
970     return FALSE;
971   }
972   self->dynParams->size = dynparams_sz;
973   self->dynParams->decodeHeader = XDM_DECODE_AU;
974   self->dynParams->displayWidth = 0;
975   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
976   self->dynParams->newFrameFlag = XDAS_TRUE;
978   /* allocate status: */
979   self->status = dce_alloc (status_sz);
980   if (G_UNLIKELY (!self->status)) {
981     return FALSE;
982   }
983   memset (self->status, 0, status_sz);
984   self->status->size = status_sz;
986   /* allocate inBufs/outBufs: */
987   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
988   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
989   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
990     return FALSE;
991   }
993   /* allocate inArgs/outArgs: */
994   self->inArgs = dce_alloc (inargs_sz);
995   self->outArgs = dce_alloc (outargs_sz);
996   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
997     return FALSE;
998   }
999   self->inArgs->size = inargs_sz;
1000   self->outArgs->size = outargs_sz;
1002   return TRUE;
1005 static GstBuffer *
1006 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
1008   GstMapInfo info;
1009   gboolean mapped;
1010   if (G_UNLIKELY (self->first_in_buffer) && self->codecdata) {
1011     push_input (self, self->codecdata, self->codecdatasize);
1012   }
1013   /* just copy entire buffer */
1015   mapped = gst_buffer_map (buf, &info, GST_MAP_READ);
1016   if (mapped) {
1017     push_input (self, info.data, info.size);
1018     gst_buffer_unmap (buf, &info);
1019   }
1020   gst_buffer_unref (buf);
1022   return NULL;
1025 static GstFlowReturn
1026 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
1028   GstFlowReturn ret = GST_FLOW_OK;
1030   if (self->segment.format == GST_FORMAT_TIME &&
1031       self->segment.rate < (gdouble) 0.0) {
1032     /* negative rate: reverse playback */
1034     if (self->backlog_nframes > 0 &&
1035         (GST_BUFFER_PTS (self->backlog_frames[0]) > GST_BUFFER_PTS (buf))) {
1036       /* push out all backlog frames, since we have a buffer that is
1037          earlier than any other in the list */
1038       while (self->backlog_nframes > 0) {
1039         ret = gst_ducati_viddec_push_latest (self);
1040         if (ret != GST_FLOW_OK)
1041           break;
1042       }
1043     }
1044     /* add the frame to the list, the array will own the ref */
1045     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
1046         buf);
1047     if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
1048       self->backlog_frames[self->backlog_nframes++] = buf;
1049     } else {
1050       /* No space in the re-order buffer, drop the frame */
1051       GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
1052       gst_buffer_unref (buf);
1053     }
1055   } else {
1056     /* if no reordering info was set, just send the buffer */
1057     if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
1058       GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
1059       return gst_pad_push (self->srcpad, buf);
1060     }
1062     /* add the frame to the list, the array will own the ref */
1063     GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
1064         buf);
1065     self->backlog_frames[self->backlog_nframes++] = buf;
1067     /* push till we have no more than the max needed, or error */
1068     while (self->backlog_nframes > self->backlog_maxframes) {
1069       ret = gst_ducati_viddec_push_earliest (self);
1070       if (ret != GST_FLOW_OK)
1071         break;
1072     }
1073   }
1074   return ret;
1077 static gint
1078 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
1079     gint extended_error, gint status_extended_error)
1081   if (XDM_ISFATALERROR (extended_error) || (ret == DCE_EXDM_UNSUPPORTED)
1082       || (ret == DCE_EIPC_CALL_FAIL) || (ret == DCE_EINVALID_INPUT))
1083     ret = XDM_EFAIL;
1084   else
1085     ret = XDM_EOK;
1087   return ret;
1090 /* GstElement vmethod implementations */
1092 static gboolean
1093 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
1095   gboolean ret = TRUE;
1096   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1097   GstStructure *s;
1098   GstCaps *outcaps = NULL;
1099   GstStructure *out_s;
1100   gint par_width, par_height;
1101   gboolean par_present;
1103   GST_INFO_OBJECT (self, "set_caps (sink): %" GST_PTR_FORMAT, caps);
1105   s = gst_caps_get_structure (caps, 0);
1106   if (!klass->parse_caps (self, s)) {
1107     GST_WARNING_OBJECT (self, "missing required fields");
1108     ret = FALSE;
1109     goto out;
1110   }
1112   /* update output/padded sizes */
1113   klass->update_buffer_size (self);
1115   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
1116     self->fps_n = 0;
1117     self->fps_d = 1;
1118   }
1119   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
1120   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
1121       &par_width, &par_height);
1123   outcaps = gst_pad_get_allowed_caps (self->srcpad);
1124   GST_DEBUG_OBJECT (self, "%s",
1125       gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
1126   if (outcaps) {
1127     outcaps = gst_caps_make_writable (outcaps);
1128     outcaps = gst_caps_truncate (outcaps);
1129     if (gst_caps_is_empty (outcaps)) {
1130       gst_caps_unref (outcaps);
1131       outcaps = NULL;
1132     }
1133   }
1135   if (!outcaps) {
1136     outcaps = gst_caps_new_simple ("video/x-raw",
1137         "format", G_TYPE_STRING, "NV12", NULL);
1138   }
1140   out_s = gst_caps_get_structure (outcaps, 0);
1141   gst_structure_set (out_s,
1142       "width", G_TYPE_INT, self->padded_width,
1143       "height", G_TYPE_INT, self->padded_height,
1144       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
1145   if (par_present)
1146     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1147         par_width, par_height, NULL);
1149   if (self->interlaced)
1150     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
1152   gst_structure_set (out_s, "drm_mem", G_TYPE_BOOLEAN, TRUE, NULL);
1154   self->stride = GST_ROUND_UP_4 (self->padded_width);
1156   self->outsize =
1157       GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) * 3 /
1158       2;
1160   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1161       self->outsize, self->stride, outcaps);
1163   if (!self->first_in_buffer) {
1164     /* Caps changed mid stream. We flush the codec to unlock all the potentially
1165      * locked buffers. This is needed for downstream sinks that provide a
1166      * buffer pool and need to destroy all the outstanding buffers before they
1167      * can negotiate new caps (hello v4l2sink).
1168      */
1169     gst_ducati_viddec_codec_flush (self, FALSE);
1170   }
1173   ret = gst_pad_set_caps (self->srcpad, outcaps);
1175   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
1177   /* default to no reordering */
1178   self->backlog_maxframes = 0;
1180   if (ret == TRUE) {
1181     if (self->sinkcaps)
1182       gst_caps_unref (self->sinkcaps);
1183     self->sinkcaps = gst_caps_copy (caps);
1184   }
1186 out:
1187   if (outcaps)
1188     gst_caps_unref (outcaps);
1190   return ret;
1193 static gboolean
1194 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1196   gboolean ret = TRUE;
1197   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1198   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1200   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1202   if (!self->sinkcaps || !gst_caps_is_strictly_equal (self->sinkcaps, caps))
1203     ret = klass->set_sink_caps (self, caps);
1204   else {
1205     ret = TRUE;
1206     gst_caps_unref (caps);
1207   }
1209   gst_object_unref (self);
1211   return ret;
1214 static GstCaps *
1215 gst_ducati_viddec_src_getcaps (GstPad * pad)
1217   GstCaps *caps = NULL;
1219   caps = gst_pad_get_current_caps (pad);
1220   if (caps == NULL) {
1221     GstCaps *fil = gst_pad_get_pad_template_caps (pad);
1222     GST_DEBUG ("filter caps = %s \n", gst_caps_to_string (fil));
1223     return fil;
1224   } else {
1225     return caps;
1226   }
1229 static gboolean
1230 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1231     GstQuery * query, gboolean * forward)
1233   gboolean res = TRUE;
1235   switch (GST_QUERY_TYPE (query)) {
1236     case GST_QUERY_CAPS:
1237     {
1238       GstCaps *filter;
1239       filter = gst_ducati_viddec_src_getcaps (pad);
1240       gst_query_set_caps_result (query, filter);
1241       break;
1242     }
1243     case GST_QUERY_LATENCY:
1244     {
1245       gboolean live;
1246       GstClockTime min, max, latency;
1248       if (self->fps_d == 0) {
1249         GST_INFO_OBJECT (self, "not ready to report latency");
1250         res = FALSE;
1251         break;
1252       }
1254       gst_query_parse_latency (query, &live, &min, &max);
1255       if (self->fps_n != 0)
1256         latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1257       else
1258         latency = 0;
1260       /* Take into account the backlog frames for reordering */
1261       latency *= (self->backlog_maxframes + 1);
1263       if (min == GST_CLOCK_TIME_NONE)
1264         min = latency;
1265       else
1266         min += latency;
1268       if (max != GST_CLOCK_TIME_NONE)
1269         max += latency;
1271       GST_INFO_OBJECT (self,
1272           "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1273           GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1274       gst_query_set_latency (query, live, min, max);
1275       break;
1276     }
1277     default:
1278       break;
1279   }
1282   return res;
1285 static gboolean
1286 gst_ducati_viddec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1288   gboolean res = TRUE, forward = TRUE;
1289   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1290   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1292   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1293   res = klass->query (self, pad, query, &forward);
1294   if (res && forward)
1295     res = gst_pad_query_default (pad, parent, query);
1297   return res;
1300 static gboolean
1301 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1303   GstClockTime timestamp, qostime;
1304   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1305   gint64 diff;
1307   self->out_of_segment = FALSE;
1308   if (self->wait_keyframe) {
1309     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1310       GST_INFO_OBJECT (self, "skipping until the next keyframe");
1311       return FALSE;
1312     }
1314     self->wait_keyframe = FALSE;
1315   }
1317   timestamp = GST_BUFFER_PTS (buf);
1318   if (self->segment.format != GST_FORMAT_TIME)
1319     goto no_qos;
1321   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1322     goto no_qos;
1324   qostime = gst_segment_to_running_time (&self->segment,
1325       GST_FORMAT_TIME, timestamp);
1326   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime))) {
1327     self->out_of_segment = TRUE;
1328     /* out of segment */
1329     GST_DEBUG_OBJECT(self, "out of segment\n");
1330     goto no_qos;
1331   }
1333   /* see how our next timestamp relates to the latest qos timestamp. negative
1334    * values mean we are early, positive values mean we are too late. */
1335   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1337   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1338       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1339       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1340       self->qos_proportion);
1342   if (klass->can_drop_frame (self, buf, diff)) {
1343     GST_INFO_OBJECT (self, "dropping frame");
1344     return FALSE;
1345   }
1347 no_qos:
1348   return TRUE;
1351 static gboolean
1352 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1353     gint64 diff)
1355   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1356       GST_BUFFER_FLAG_DELTA_UNIT);
1358   if (diff >= 0 && !is_keyframe)
1359     return TRUE;
1361   return FALSE;
1364 static GstFlowReturn
1365 gst_ducati_viddec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1367   SizeT fd;
1369   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1370   GstClockTime ts = GST_BUFFER_PTS (buf);
1371   GstFlowReturn ret = GST_FLOW_OK;
1372   Int32 err;
1373   GstBuffer *outbuf = NULL;
1374   GstCaps *outcaps = NULL;
1375   gboolean decode;
1377   GstQuery *query = NULL;
1378   guint min = 0;
1379   guint max = 0;
1380   guint size = 0;
1382 normal:
1383   if (G_UNLIKELY (!self->engine)) {
1384     GST_ERROR_OBJECT (self, "no engine");
1385     gst_buffer_unref (buf);
1386     return GST_FLOW_ERROR;
1387   }
1389   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1390       GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1392   decode = gst_ducati_viddec_do_qos (self, buf);
1393   if (!decode) {
1394     gst_buffer_unref (buf);
1395     return GST_FLOW_OK;
1396   }
1398   if (!self->need_out_buf)
1399     goto have_out_buf;
1401   /* do this before creating codec to ensure reverse caps negotiation
1402    * happens first:
1403    */
1405 allocate_buffer:
1406   outbuf = codec_buffer_pool_get (self, NULL);
1408   if (outbuf == NULL) {
1409     GST_WARNING_OBJECT (self, "alloc_buffer failed");
1410     gst_buffer_unref (buf);
1411     return GST_FLOW_ERROR;
1412   }
1414   if (G_UNLIKELY (!self->codec)) {
1415     if (!codec_create (self)) {
1416       GST_ERROR_OBJECT (self, "could not create codec");
1417       gst_buffer_unref (buf);
1418       gst_buffer_unref (outbuf);
1419       return GST_FLOW_ERROR;
1420     }
1421   }
1423   GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
1424   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1426   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1427    * internal pool while self->first_out_buffer == TRUE in order to simplify
1428    * things in case we need to renegotiate */
1429   self->inArgs->inputID =
1430       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1431   if (!self->inArgs->inputID) {
1432     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1433     gst_buffer_unref (buf);
1434     return GST_FLOW_ERROR;
1435   }
1436   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1438 have_out_buf:
1439   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1441 #ifdef USE_DTS_PTS_CODE
1442   if (ts != GST_CLOCK_TIME_NONE) {
1443     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1444     /* if next buffer has earlier ts than previous, then the ts
1445      * we are getting are definitely decode order (DTS):
1446      */
1447     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1448       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1449       self->ts_may_be_pts = FALSE;
1450     }
1451     self->last_dts = ts;
1452   }
1453 #endif
1455   if (self->in_size == 0 && outbuf) {
1456     GST_DEBUG_OBJECT (self, "no input, skipping process");
1458     gst_buffer_unref (outbuf);
1459     return GST_FLOW_OK;
1460   }
1462   self->inArgs->numBytes = self->in_size;
1463   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1464   /* XDM_MemoryType required by drm to allcoate buffer */
1465   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1467   err = codec_process (self, TRUE, FALSE, &ret);
1468   if (err) {
1469     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1470         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1471     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1472         self->error_strings);
1474     return GST_FLOW_ERROR;
1475   }
1477   if (ret != GST_FLOW_OK) {
1478     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1479         gst_flow_get_name (ret));
1481     return ret;
1482   }
1484   self->first_in_buffer = FALSE;
1486   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1487     /* The copy could be avoided by playing with the buffer pointer,
1488        but it seems to be rare and for not many bytes */
1489     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1490         self->outArgs->bytesConsumed, self->in_size,
1491         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1492     if (self->outArgs->bytesConsumed > 0) {
1493       if (self->outArgs->bytesConsumed > self->in_size) {
1494         GST_WARNING_OBJECT (self,
1495             "Codec claims to have used more bytes than supplied");
1496         self->in_size = 0;
1497       } else {
1498         if (self->outArgs->bytesConsumed < self->in_size) {
1499           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1500               self->in_size - self->outArgs->bytesConsumed);
1501         }
1502         self->in_size -= self->outArgs->bytesConsumed;
1503       }
1504     }
1505   } else {
1506     self->in_size = 0;
1507   }
1509   if (self->outArgs->outBufsInUseFlag) {
1510     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1511     self->need_out_buf = FALSE;
1512   } else {
1513     self->need_out_buf = TRUE;
1514   }
1516   if (buf) {
1517     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1518         gst_buffer_get_size (buf));
1519     ts = GST_BUFFER_PTS (buf);
1520     goto allocate_buffer;
1521   }
1523   if (self->needs_flushing)
1524     gst_ducati_viddec_codec_flush (self, FALSE);
1526   return GST_FLOW_OK;
1529 static gboolean
1530 gst_ducati_viddec_event (GstPad * pad, GstObject * parent, GstEvent * event)
1532   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1533   gboolean ret = TRUE;
1535   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1537   switch (GST_EVENT_TYPE (event)) {
1538     case GST_EVENT_CAPS:
1539     {
1540       GstCaps *caps;
1541       gst_event_parse_caps (event, &caps);
1542       gst_event_unref (event);
1543       return gst_ducati_viddec_sink_setcaps (pad, caps);
1544       break;
1545     }
1546     case GST_EVENT_SEGMENT:
1547     {
1549       gst_event_copy_segment (event, &self->segment);
1551       break;
1552     }
1553     case GST_EVENT_EOS:
1554       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1555         GST_ERROR_OBJECT (self, "could not flush on eos");
1556         gst_event_unref (event);
1557         ret = FALSE;
1558       }
1559       break;
1560     case GST_EVENT_FLUSH_STOP:
1561       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1562         GST_ERROR_OBJECT (self, "could not flush");
1563         gst_event_unref (event);
1564         ret = FALSE;
1565       }
1566       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1567       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1568       self->qos_proportion = 1;
1569       self->need_out_buf = TRUE;
1570       break;
1571     default:
1572       break;
1573   }
1575   if (ret)
1576     ret = gst_pad_push_event (self->srcpad, event);
1577   GST_LOG_OBJECT (self, "end");
1579   return ret;
1582 static gboolean
1583 gst_ducati_viddec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1585   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1586   gboolean ret = TRUE;
1588   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1590   switch (GST_EVENT_TYPE (event)) {
1591     case GST_EVENT_QOS:
1592     {
1593       gdouble proportion;
1594       GstClockTimeDiff diff;
1595       GstClockTime timestamp;
1596       GstQOSType type;
1598       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
1600       GST_OBJECT_LOCK (self);
1601       self->qos_proportion = proportion;
1602       self->qos_earliest_time = timestamp + 2 * diff;
1603       GST_OBJECT_UNLOCK (self);
1605       GST_DEBUG_OBJECT (self,
1606           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1607           proportion, GST_TIME_ARGS (timestamp), diff);
1609       ret = gst_pad_push_event (self->sinkpad, event);
1610       break;
1611     }
1612     default:
1613       ret = gst_pad_push_event (self->sinkpad, event);
1614       break;
1615   }
1617   GST_LOG_OBJECT (self, "end");
1619   return ret;
1622 static GstStateChangeReturn
1623 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1625   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1626   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1627   gboolean supported;
1629   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1630       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1631       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1633   switch (transition) {
1634     case GST_STATE_CHANGE_NULL_TO_READY:
1635       if (!engine_open (self)) {
1636         GST_ERROR_OBJECT (self, "could not open");
1637         return GST_STATE_CHANGE_FAILURE;
1638       }
1639       /* try to create/destroy the codec here, it may not be supported */
1640       supported = codec_create (self);
1641       codec_delete (self);
1642       self->codec = NULL;
1643       if (!supported) {
1644         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1645             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1646         engine_close (self);
1647         return GST_STATE_CHANGE_FAILURE;
1648       }
1649       break;
1650     default:
1651       break;
1652   }
1654   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1656   if (ret == GST_STATE_CHANGE_FAILURE)
1657     goto leave;
1659   switch (transition) {
1660     case GST_STATE_CHANGE_PAUSED_TO_READY:
1661       self->interlaced = FALSE;
1662       gst_ducati_viddec_codec_flush (self, FALSE);
1663       break;
1664     case GST_STATE_CHANGE_READY_TO_NULL:
1665       codec_delete (self);
1666       engine_close (self);
1667       break;
1668     default:
1669       break;
1670   }
1672 leave:
1673   GST_LOG_OBJECT (self, "end");
1675   return ret;
1678 /* GObject vmethod implementations */
1681 static void
1682 gst_ducati_viddec_get_property (GObject * obj,
1683     guint prop_id, GValue * value, GParamSpec * pspec)
1685   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1688   switch (prop_id) {
1689     case PROP_VERSION:{
1690       int err;
1691       char *version = NULL;
1693       if (!self->engine)
1694         engine_open (self);
1696       if (!self->codec)
1697         codec_create (self);
1699       if (self->codec) {
1700         version = dce_alloc (VERSION_LENGTH);
1701         if (version) {
1702           self->status->data.buf = (XDAS_Int8 *) version;
1703           self->status->data.bufSize = VERSION_LENGTH;
1705           GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1706           err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1707               self->dynParams, self->status);
1709           if (err) {
1710             GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1711           } else
1712             GST_DEBUG ("Codec version %s", self->status->data.buf);
1714           self->status->data.buf = NULL;
1715           self->status->data.bufSize = 0;
1716           dce_free (version);
1717         }
1718       }
1719       break;
1720     }
1721     case PROP_MAX_REORDER_FRAMES:
1722       g_value_set_int (value, self->backlog_max_maxframes);
1723       break;
1724     case PROP_CODEC_DEBUG_INFO:
1725       g_value_set_boolean (value, self->codec_debug_info);
1726       break;
1727     default:{
1728       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1729       break;
1730     }
1731   }
1734 static void
1735 gst_ducati_viddec_set_property (GObject * obj,
1736     guint prop_id, const GValue * value, GParamSpec * pspec)
1738   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1740   switch (prop_id) {
1741     case PROP_MAX_REORDER_FRAMES:
1742       self->backlog_max_maxframes = g_value_get_int (value);
1743       break;
1744     case PROP_CODEC_DEBUG_INFO:
1745       self->codec_debug_info = g_value_get_boolean (value);
1746       break;
1747     default:{
1748       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1749       break;
1750     }
1751   }
1754 static void
1755 gst_ducati_viddec_finalize (GObject * obj)
1757   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1759   codec_delete (self);
1761   if (self->sinkcaps)
1762     gst_caps_unref (self->sinkcaps);
1764   if (self->pool) {
1765     gst_object_unref (self->pool);
1766     self->pool = NULL;
1767   }
1769   engine_close (self);
1771   /* Will unref the remaining buffers if needed */
1772   g_hash_table_unref (self->dce_locked_bufs);
1773   g_hash_table_unref (self->passed_in_bufs);
1775   if (self->codecdata) {
1776     g_slice_free1 (self->codecdatasize, self->codecdata);
1777     self->codecdata = NULL;
1778   }
1780   G_OBJECT_CLASS (parent_class)->finalize (obj);
1783 static void
1784 gst_ducati_viddec_base_init (gpointer gclass)
1786   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1788   gst_element_class_add_pad_template (element_class,
1789       gst_static_pad_template_get (&src_factory));
1792 static void
1793 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1795   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1796   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1797   parent_class = g_type_class_peek_parent (klass);
1799   gobject_class->get_property =
1800       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1801   gobject_class->set_property =
1802       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1803   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1804   gstelement_class->change_state =
1805       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1807   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1808   klass->allocate_params =
1809       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1810   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1811   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1812   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1813   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1814   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1815   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1816   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1818   g_object_class_install_property (gobject_class, PROP_VERSION,
1819       g_param_spec_string ("version", "Version",
1820           "The codec version string", "",
1821           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1823   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1824       g_param_spec_int ("max-reorder-frames",
1825           "Maximum number of frames needed for reordering",
1826           "The maximum number of frames needed for reordering output frames. "
1827           "Only meaningful for codecs with B frames. 0 means no reordering. "
1828           "This value will be used if the correct value cannot be inferred "
1829           "from the stream. Too low a value may cause misordering, too high "
1830           "will cause extra latency.",
1831           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1832           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1834   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1835       g_param_spec_boolean ("codec-debug-info",
1836           "Gather debug info from the codec",
1837           "Gather and log relevant debug information from the codec. "
1838           "What is gathered is typically codec specific", FALSE,
1839           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1842 static void
1843 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1845   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1847   gst_ducati_set_generic_error_strings (self->error_strings);
1849   self->sinkpad =
1850       gst_pad_new_from_template (gst_element_class_get_pad_template
1851       (gstelement_class, "sink"), "sink");
1852   gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1853   gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1855   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1856   gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1857   gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1859   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1860   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1862   self->input_width = 0;
1863   self->input_height = 0;
1864   /* sane defaults in case we need to create codec without caps negotiation
1865    * (for example, to get 'version' property)
1866    */
1867   self->width = 128;
1868   self->height = 128;
1869   self->fps_n = -1;
1870   self->fps_d = -1;
1872   self->first_in_buffer = TRUE;
1873   self->first_out_buffer = FALSE;
1874   self->interlaced = FALSE;
1876 #ifdef USE_DTS_PTS_CODE
1877   self->dts_ridx = self->dts_widx = 0;
1878   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1879   self->ts_may_be_pts = TRUE;
1880   self->ts_is_pts = FALSE;
1881 #endif
1883   self->codec_create_params_changed = FALSE;
1885   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1887   self->codecdata = NULL;
1888   self->codecdatasize = 0;
1890   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1892   self->qos_proportion = 1;
1893   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1894   self->wait_keyframe = TRUE;
1896   self->need_out_buf = TRUE;
1897   self->device = NULL;
1898   self->input_bo = NULL;
1900   self->sinkcaps = NULL;
1902   self->backlog_maxframes = 0;
1903   self->backlog_nframes = 0;
1904   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1906   self->codec_debug_info = FALSE;
1908   self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1909       NULL, (GDestroyNotify) do_dce_buf_unlock);
1910   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1911       NULL, (GDestroyNotify) gst_buffer_unref);