mpeg2dec: Fix negotiation issue with playbin
[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 (4, 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) {
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   if (self->wait_keyframe) {
1308     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1309       GST_INFO_OBJECT (self, "skipping until the next keyframe");
1310       return FALSE;
1311     }
1313     self->wait_keyframe = FALSE;
1314   }
1316   timestamp = GST_BUFFER_PTS (buf);
1317   if (self->segment.format != GST_FORMAT_TIME ||
1318       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
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     /* out of segment */
1328     goto no_qos;
1330   /* see how our next timestamp relates to the latest qos timestamp. negative
1331    * values mean we are early, positive values mean we are too late. */
1332   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1334   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1335       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1336       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1337       self->qos_proportion);
1339   if (klass->can_drop_frame (self, buf, diff)) {
1340     GST_INFO_OBJECT (self, "dropping frame");
1341     return FALSE;
1342   }
1344 no_qos:
1345   return TRUE;
1348 static gboolean
1349 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1350     gint64 diff)
1352   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1353       GST_BUFFER_FLAG_DELTA_UNIT);
1355   if (diff >= 0 && !is_keyframe)
1356     return TRUE;
1358   return FALSE;
1361 static GstFlowReturn
1362 gst_ducati_viddec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1364   SizeT fd;
1366   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1367   GstClockTime ts = GST_BUFFER_PTS (buf);
1368   GstFlowReturn ret = GST_FLOW_OK;
1369   Int32 err;
1370   GstBuffer *outbuf = NULL;
1371   GstCaps *outcaps = NULL;
1372   gboolean decode;
1374   GstQuery *query = NULL;
1375   guint min = 0;
1376   guint max = 0;
1377   guint size = 0;
1379 normal:
1380   if (G_UNLIKELY (!self->engine)) {
1381     GST_ERROR_OBJECT (self, "no engine");
1382     gst_buffer_unref (buf);
1383     return GST_FLOW_ERROR;
1384   }
1386   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1387       GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1389   decode = gst_ducati_viddec_do_qos (self, buf);
1390   if (!decode) {
1391     gst_buffer_unref (buf);
1392     return GST_FLOW_OK;
1393   }
1395   if (!self->need_out_buf)
1396     goto have_out_buf;
1398   /* do this before creating codec to ensure reverse caps negotiation
1399    * happens first:
1400    */
1402 allocate_buffer:
1403   outbuf = codec_buffer_pool_get (self, NULL);
1405   if (outbuf == NULL) {
1406     GST_WARNING_OBJECT (self, "alloc_buffer failed");
1407     gst_buffer_unref (buf);
1408     return GST_FLOW_ERROR;
1409   }
1411   if (G_UNLIKELY (!self->codec)) {
1412     if (!codec_create (self)) {
1413       GST_ERROR_OBJECT (self, "could not create codec");
1414       gst_buffer_unref (buf);
1415       gst_buffer_unref (outbuf);
1416       return GST_FLOW_ERROR;
1417     }
1418   }
1420   GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
1421   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1423   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1424    * internal pool while self->first_out_buffer == TRUE in order to simplify
1425    * things in case we need to renegotiate */
1426   self->inArgs->inputID =
1427       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1428   if (!self->inArgs->inputID) {
1429     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1430     gst_buffer_unref (buf);
1431     return GST_FLOW_ERROR;
1432   }
1433   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1435 have_out_buf:
1436   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1438 #ifdef USE_DTS_PTS_CODE
1439   if (ts != GST_CLOCK_TIME_NONE) {
1440     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1441     /* if next buffer has earlier ts than previous, then the ts
1442      * we are getting are definitely decode order (DTS):
1443      */
1444     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1445       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1446       self->ts_may_be_pts = FALSE;
1447     }
1448     self->last_dts = ts;
1449   }
1450 #endif
1452   if (self->in_size == 0 && outbuf) {
1453     GST_DEBUG_OBJECT (self, "no input, skipping process");
1455     gst_buffer_unref (outbuf);
1456     return GST_FLOW_OK;
1457   }
1459   self->inArgs->numBytes = self->in_size;
1460   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1461   /* XDM_MemoryType required by drm to allcoate buffer */
1462   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1464   err = codec_process (self, TRUE, FALSE, &ret);
1465   if (err) {
1466     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1467         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1468     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1469         self->error_strings);
1471     return GST_FLOW_ERROR;
1472   }
1474   if (ret != GST_FLOW_OK) {
1475     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1476         gst_flow_get_name (ret));
1478     return ret;
1479   }
1481   self->first_in_buffer = FALSE;
1483   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1484     /* The copy could be avoided by playing with the buffer pointer,
1485        but it seems to be rare and for not many bytes */
1486     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1487         self->outArgs->bytesConsumed, self->in_size,
1488         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1489     if (self->outArgs->bytesConsumed > 0) {
1490       if (self->outArgs->bytesConsumed > self->in_size) {
1491         GST_WARNING_OBJECT (self,
1492             "Codec claims to have used more bytes than supplied");
1493         self->in_size = 0;
1494       } else {
1495         if (self->outArgs->bytesConsumed < self->in_size) {
1496           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1497               self->in_size - self->outArgs->bytesConsumed);
1498         }
1499         self->in_size -= self->outArgs->bytesConsumed;
1500       }
1501     }
1502   } else {
1503     self->in_size = 0;
1504   }
1506   if (self->outArgs->outBufsInUseFlag) {
1507     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1508     self->need_out_buf = FALSE;
1509   } else {
1510     self->need_out_buf = TRUE;
1511   }
1513   if (buf) {
1514     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1515         gst_buffer_get_size (buf));
1516     ts = GST_BUFFER_PTS (buf);
1517     goto allocate_buffer;
1518   }
1520   if (self->needs_flushing)
1521     gst_ducati_viddec_codec_flush (self, FALSE);
1523   return GST_FLOW_OK;
1526 static gboolean
1527 gst_ducati_viddec_event (GstPad * pad, GstObject * parent, GstEvent * event)
1529   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1530   gboolean ret = TRUE;
1532   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1534   switch (GST_EVENT_TYPE (event)) {
1535     case GST_EVENT_CAPS:
1536     {
1537       GstCaps *caps;
1538       gst_event_parse_caps (event, &caps);
1539       gst_event_unref (event);
1540       return gst_ducati_viddec_sink_setcaps (pad, caps);
1541       break;
1542     }
1543     case GST_EVENT_SEGMENT:
1544     {
1546       gst_event_copy_segment (event, &self->segment);
1548       break;
1549     }
1550     case GST_EVENT_EOS:
1551       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1552         GST_ERROR_OBJECT (self, "could not flush on eos");
1553         gst_event_unref (event);
1554         ret = FALSE;
1555       }
1556       break;
1557     case GST_EVENT_FLUSH_STOP:
1558       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1559         GST_ERROR_OBJECT (self, "could not flush");
1560         gst_event_unref (event);
1561         ret = FALSE;
1562       }
1563       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1564       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1565       self->qos_proportion = 1;
1566       self->need_out_buf = TRUE;
1567       break;
1568     default:
1569       break;
1570   }
1572   if (ret)
1573     ret = gst_pad_push_event (self->srcpad, event);
1574   GST_LOG_OBJECT (self, "end");
1576   return ret;
1579 static gboolean
1580 gst_ducati_viddec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1582   GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1583   gboolean ret = TRUE;
1585   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1587   switch (GST_EVENT_TYPE (event)) {
1588     case GST_EVENT_QOS:
1589     {
1590       gdouble proportion;
1591       GstClockTimeDiff diff;
1592       GstClockTime timestamp;
1593       GstQOSType type;
1595       gst_event_parse_qos (event, &type, &proportion, &diff, &timestamp);
1597       GST_OBJECT_LOCK (self);
1598       self->qos_proportion = proportion;
1599       self->qos_earliest_time = timestamp + 2 * diff;
1600       GST_OBJECT_UNLOCK (self);
1602       GST_DEBUG_OBJECT (self,
1603           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1604           proportion, GST_TIME_ARGS (timestamp), diff);
1606       ret = gst_pad_push_event (self->sinkpad, event);
1607       break;
1608     }
1609     default:
1610       ret = gst_pad_push_event (self->sinkpad, event);
1611       break;
1612   }
1614   GST_LOG_OBJECT (self, "end");
1616   return ret;
1619 static GstStateChangeReturn
1620 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1622   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1623   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1624   gboolean supported;
1626   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1627       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1628       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1630   switch (transition) {
1631     case GST_STATE_CHANGE_NULL_TO_READY:
1632       if (!engine_open (self)) {
1633         GST_ERROR_OBJECT (self, "could not open");
1634         return GST_STATE_CHANGE_FAILURE;
1635       }
1636       /* try to create/destroy the codec here, it may not be supported */
1637       supported = codec_create (self);
1638       codec_delete (self);
1639       self->codec = NULL;
1640       if (!supported) {
1641         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1642             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1643         engine_close (self);
1644         return GST_STATE_CHANGE_FAILURE;
1645       }
1646       break;
1647     default:
1648       break;
1649   }
1651   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1653   if (ret == GST_STATE_CHANGE_FAILURE)
1654     goto leave;
1656   switch (transition) {
1657     case GST_STATE_CHANGE_PAUSED_TO_READY:
1658       self->interlaced = FALSE;
1659       gst_ducati_viddec_codec_flush (self, FALSE);
1660       break;
1661     case GST_STATE_CHANGE_READY_TO_NULL:
1662       codec_delete (self);
1663       engine_close (self);
1664       break;
1665     default:
1666       break;
1667   }
1669 leave:
1670   GST_LOG_OBJECT (self, "end");
1672   return ret;
1675 /* GObject vmethod implementations */
1678 static void
1679 gst_ducati_viddec_get_property (GObject * obj,
1680     guint prop_id, GValue * value, GParamSpec * pspec)
1682   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1685   switch (prop_id) {
1686     case PROP_VERSION:{
1687       int err;
1688       char *version = NULL;
1690       if (!self->engine)
1691         engine_open (self);
1693       if (!self->codec)
1694         codec_create (self);
1696       if (self->codec) {
1697         version = dce_alloc (VERSION_LENGTH);
1698         if (version) {
1699           self->status->data.buf = (XDAS_Int8 *) version;
1700           self->status->data.bufSize = VERSION_LENGTH;
1702           GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1703           err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1704               self->dynParams, self->status);
1706           if (err) {
1707             GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1708           } else
1709             GST_DEBUG ("Codec version %s", self->status->data.buf);
1711           self->status->data.buf = NULL;
1712           self->status->data.bufSize = 0;
1713           dce_free (version);
1714         }
1715       }
1716       break;
1717     }
1718     case PROP_MAX_REORDER_FRAMES:
1719       g_value_set_int (value, self->backlog_max_maxframes);
1720       break;
1721     case PROP_CODEC_DEBUG_INFO:
1722       g_value_set_boolean (value, self->codec_debug_info);
1723       break;
1724     default:{
1725       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1726       break;
1727     }
1728   }
1731 static void
1732 gst_ducati_viddec_set_property (GObject * obj,
1733     guint prop_id, const GValue * value, GParamSpec * pspec)
1735   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1737   switch (prop_id) {
1738     case PROP_MAX_REORDER_FRAMES:
1739       self->backlog_max_maxframes = g_value_get_int (value);
1740       break;
1741     case PROP_CODEC_DEBUG_INFO:
1742       self->codec_debug_info = g_value_get_boolean (value);
1743       break;
1744     default:{
1745       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1746       break;
1747     }
1748   }
1751 static void
1752 gst_ducati_viddec_finalize (GObject * obj)
1754   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1756   codec_delete (self);
1758   if (self->sinkcaps)
1759     gst_caps_unref (self->sinkcaps);
1761   if (self->pool) {
1762     gst_object_unref (self->pool);
1763     self->pool = NULL;
1764   }
1766   engine_close (self);
1768   /* Will unref the remaining buffers if needed */
1769   g_hash_table_unref (self->dce_locked_bufs);
1770   g_hash_table_unref (self->passed_in_bufs);
1772   if (self->codecdata) {
1773     g_slice_free1 (self->codecdatasize, self->codecdata);
1774     self->codecdata = NULL;
1775   }
1777   G_OBJECT_CLASS (parent_class)->finalize (obj);
1780 static void
1781 gst_ducati_viddec_base_init (gpointer gclass)
1783   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1785   gst_element_class_add_pad_template (element_class,
1786       gst_static_pad_template_get (&src_factory));
1789 static void
1790 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1792   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1793   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1794   parent_class = g_type_class_peek_parent (klass);
1796   gobject_class->get_property =
1797       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1798   gobject_class->set_property =
1799       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1800   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1801   gstelement_class->change_state =
1802       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1804   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1805   klass->allocate_params =
1806       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1807   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1808   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1809   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1810   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1811   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1812   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1813   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1815   g_object_class_install_property (gobject_class, PROP_VERSION,
1816       g_param_spec_string ("version", "Version",
1817           "The codec version string", "",
1818           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1820   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1821       g_param_spec_int ("max-reorder-frames",
1822           "Maximum number of frames needed for reordering",
1823           "The maximum number of frames needed for reordering output frames. "
1824           "Only meaningful for codecs with B frames. 0 means no reordering. "
1825           "This value will be used if the correct value cannot be inferred "
1826           "from the stream. Too low a value may cause misordering, too high "
1827           "will cause extra latency.",
1828           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1829           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1831   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1832       g_param_spec_boolean ("codec-debug-info",
1833           "Gather debug info from the codec",
1834           "Gather and log relevant debug information from the codec. "
1835           "What is gathered is typically codec specific", FALSE,
1836           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1839 static void
1840 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1842   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1844   gst_ducati_set_generic_error_strings (self->error_strings);
1846   self->sinkpad =
1847       gst_pad_new_from_template (gst_element_class_get_pad_template
1848       (gstelement_class, "sink"), "sink");
1849   gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1850   gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1852   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1853   gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1854   gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1856   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1857   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1859   self->input_width = 0;
1860   self->input_height = 0;
1861   /* sane defaults in case we need to create codec without caps negotiation
1862    * (for example, to get 'version' property)
1863    */
1864   self->width = 128;
1865   self->height = 128;
1866   self->fps_n = -1;
1867   self->fps_d = -1;
1869   self->first_in_buffer = TRUE;
1870   self->first_out_buffer = FALSE;
1871   self->interlaced = FALSE;
1873 #ifdef USE_DTS_PTS_CODE
1874   self->dts_ridx = self->dts_widx = 0;
1875   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1876   self->ts_may_be_pts = TRUE;
1877   self->ts_is_pts = FALSE;
1878 #endif
1880   self->codec_create_params_changed = FALSE;
1882   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1884   self->codecdata = NULL;
1885   self->codecdatasize = 0;
1887   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1889   self->qos_proportion = 1;
1890   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1891   self->wait_keyframe = TRUE;
1893   self->need_out_buf = TRUE;
1894   self->device = NULL;
1895   self->input_bo = NULL;
1897   self->sinkcaps = NULL;
1899   self->backlog_maxframes = 0;
1900   self->backlog_nframes = 0;
1901   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1903   self->codec_debug_info = FALSE;
1905   self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1906       NULL, (GDestroyNotify) do_dce_buf_unlock);
1907   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1908       NULL, (GDestroyNotify) gst_buffer_unref);