ducati: rework debug bit logging for extensibility
[gstreamer-omap:gst-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  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include "gstducatividdec.h"
26 #include "gstducatibufferpriv.h"
27
28 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
29     GST_TYPE_ELEMENT);
30
31 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
32     GST_PAD_SRC,
33     GST_PAD_ALWAYS,
34     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
35     );
36
37 enum
38 {
39   PROP_0,
40   PROP_VERSION,
41   PROP_MAX_REORDER_FRAMES,
42   PROP_CODEC_DEBUG_INFO
43 };
44
45 /* helper functions */
46
47 static void
48 engine_close (GstDucatiVidDec * self)
49 {
50   if (self->engine) {
51     Engine_close (self->engine);
52     self->engine = NULL;
53   }
54
55   if (self->params) {
56     dce_free (self->params);
57     self->params = NULL;
58   }
59
60   if (self->dynParams) {
61     dce_free (self->dynParams);
62     self->dynParams = NULL;
63   }
64
65   if (self->status) {
66     dce_free (self->status);
67     self->status = NULL;
68   }
69
70   if (self->inBufs) {
71     dce_free (self->inBufs);
72     self->inBufs = NULL;
73   }
74
75   if (self->outBufs) {
76     dce_free (self->outBufs);
77     self->outBufs = NULL;
78   }
79
80   if (self->inArgs) {
81     dce_free (self->inArgs);
82     self->inArgs = NULL;
83   }
84
85   if (self->outArgs) {
86     dce_free (self->outArgs);
87     self->outArgs = NULL;
88   }
89
90   if (self->device) {
91     dce_deinit (self->device);
92     self->device = NULL;
93   }
94 }
95
96 static gboolean
97 engine_open (GstDucatiVidDec * self)
98 {
99   gboolean ret;
100   int ec;
101
102   if (G_UNLIKELY (self->engine)) {
103     return TRUE;
104   }
105
106   if (self->device == NULL) {
107     self->device = dce_init ();
108     if (self->device == NULL) {
109       GST_ERROR_OBJECT (self, "dce_init() failed");
110       return FALSE;
111     }
112   }
113
114   GST_DEBUG_OBJECT (self, "opening engine");
115
116   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
117   if (G_UNLIKELY (!self->engine)) {
118     GST_ERROR_OBJECT (self, "could not create engine");
119     return FALSE;
120   }
121
122   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
123       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
124       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
125       sizeof (IVIDDEC3_OutArgs));
126
127   return ret;
128 }
129
130 static void
131 codec_delete (GstDucatiVidDec * self)
132 {
133   if (self->pool) {
134     gst_drm_buffer_pool_destroy (self->pool);
135     self->pool = NULL;
136   }
137
138   if (self->codec) {
139     VIDDEC3_delete (self->codec);
140     self->codec = NULL;
141   }
142
143   if (self->input_bo) {
144     omap_bo_del (self->input_bo);
145     self->input_bo = NULL;
146   }
147 }
148
149 static gboolean
150 codec_create (GstDucatiVidDec * self)
151 {
152   gint err, n;
153   const gchar *codec_name;
154
155   codec_delete (self);
156
157   if (G_UNLIKELY (!self->engine)) {
158     GST_ERROR_OBJECT (self, "no engine");
159     return FALSE;
160   }
161
162   /* these need to be set before VIDDEC3_create */
163   self->params->maxWidth = self->width;
164   self->params->maxHeight = self->height;
165
166   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
167
168   /* create codec: */
169   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
170   self->codec =
171       VIDDEC3_create (self->engine, (String) codec_name, self->params);
172
173   if (!self->codec) {
174     return FALSE;
175   }
176
177   err =
178       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
179       self->status);
180   if (err) {
181     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
182     return FALSE;
183   }
184
185   self->first_in_buffer = TRUE;
186   self->first_out_buffer = TRUE;
187
188   /* allocate input buffer and initialize inBufs: */
189   /* FIXME:  needed size here has nothing to do with width * height */
190   self->input_bo = omap_bo_new (self->device,
191       self->width * self->height, OMAP_BO_WC);
192   self->input = omap_bo_map (self->input_bo);
193   self->inBufs->numBufs = 1;
194   self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
195
196   /* Actual buffers will be set later, as they will be different for every
197      frame. We allow derived classes to add their own buffers, however, so
198      we initialize the number of outBufs here, counting the number of extra
199      buffers required, including "holes" in planes, which may not be filled
200      if not assigned. */
201   self->outBufs->numBufs = 2;   /* luma and chroma planes, always */
202   for (n = 0; n < 3; n++)
203     if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
204       self->outBufs->numBufs = 2 + n + 1;
205
206   return TRUE;
207 }
208
209 static inline GstBuffer *
210 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
211 {
212   if (G_UNLIKELY (!self->pool)) {
213     guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
214         self->padded_width, self->padded_height);
215
216     GST_DEBUG_OBJECT (self, "creating bufferpool");
217     self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
218         dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
219   }
220   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
221 }
222
223 static GstDucatiBufferPriv *
224 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
225 {
226   GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
227   if (!priv) {
228     GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
229     GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
230
231     /* if it isn't a dmabuf buffer that we can import, then there
232      * is nothing we can do with it:
233      */
234     if (!dmabuf) {
235       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
236       return NULL;
237     }
238
239     priv = gst_ducati_buffer_priv_new ();
240
241     priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
242
243     priv->uv_offset = gst_video_format_get_component_offset (format,
244         1, self->stride, self->padded_height);
245     priv->size = gst_video_format_get_size (format,
246         self->stride, self->padded_height);
247
248     gst_ducati_buffer_priv_set (buf, priv);
249     gst_mini_object_unref (GST_MINI_OBJECT (priv));
250   }
251   return priv;
252 }
253
254 static XDAS_Int32
255 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
256     gboolean force_internal)
257 {
258   GstDucatiBufferPriv *priv = NULL;
259
260   if (!force_internal)
261     priv = get_buffer_priv (self, *buf);
262
263   if (!priv) {
264     GstBuffer *orig = *buf;
265
266     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
267     *buf = codec_buffer_pool_get (self, NULL);
268     GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
269     GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
270     gst_buffer_unref (orig);
271     return codec_prepare_outbuf (self, buf, FALSE);
272   }
273
274   /* There are at least two buffers. Derived classes may add codec specific
275      buffers (eg, debug info) after these two if they want to. */
276   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
277   self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
278   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
279   self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
280   self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
281   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
282
283   return (XDAS_Int32) * buf;
284 }
285
286 static GstBuffer *
287 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
288 {
289   GstBuffer *buf = (GstBuffer *) id;
290
291   if (buf) {
292     g_hash_table_insert (self->passed_in_bufs, buf, buf);
293
294     gst_buffer_ref (buf);
295   }
296   return buf;
297 }
298
299 static void
300 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
301 {
302   GstBuffer *buf = (GstBuffer *) id;
303
304   if (buf) {
305     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
306     g_hash_table_remove (self->passed_in_bufs, buf);
307   }
308 }
309
310 static GstFlowReturn
311 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
312 {
313   guint64 earliest_order = G_MAXUINT64;
314   guint earliest_index = 0, i;
315   GstBuffer *buf;
316
317   if (self->backlog_nframes == 0)
318     return GST_FLOW_OK;
319
320   /* work out which frame has the earliest poc */
321   for (i = 0; i < self->backlog_nframes; i++) {
322     guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
323     if (earliest_order == G_MAXUINT64 || order < earliest_order) {
324       earliest_order = order;
325       earliest_index = i;
326     }
327   }
328
329   /* send it, giving away the ref */
330   buf = self->backlog_frames[earliest_index];
331   self->backlog_frames[earliest_index] =
332       self->backlog_frames[--self->backlog_nframes];
333   GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
334       buf);
335   return gst_pad_push (self->srcpad, buf);
336 }
337
338 static void
339 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
340 {
341   /* push everything on the backlog, ignoring errors */
342   while (self->backlog_nframes > 0) {
343     gst_ducati_viddec_push_earliest (self);
344   }
345 }
346
347 static gint
348 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
349     GstFlowReturn * flow_ret)
350 {
351   gint err;
352   GstClockTime t;
353   GstBuffer *outbuf = NULL;
354   gint i;
355   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
356   GstFlowReturn ret = GST_FLOW_OK;
357   if (flow_ret)
358     /* never leave flow_ret uninitialized */
359     *flow_ret = GST_FLOW_OK;
360
361   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
362   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
363
364   GST_DEBUG ("Calling VIDDEC3_process");
365   t = gst_util_get_timestamp ();
366   err = VIDDEC3_process (self->codec,
367       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
368   t = gst_util_get_timestamp () - t;
369   GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
370       (gint) (t / 1000000));
371
372   if (err) {
373     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
374         err, self->outArgs->extendedError);
375     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
376         self->error_strings);
377
378     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
379         self->dynParams, self->status);
380     if (err) {
381       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
382           err, self->status->extendedError);
383       gst_ducati_log_extended_error_info (self->status->extendedError,
384           self->error_strings);
385     }
386
387     if (flush)
388       err = XDM_EFAIL;
389     else
390       err = klass->handle_error (self, err,
391           self->outArgs->extendedError, self->status->extendedError);
392   }
393
394   /* we now let the codec decide */
395   self->dynParams->newFrameFlag = XDAS_FALSE;
396
397   if (err == XDM_EFAIL)
398     goto skip_outbuf_processing;
399
400   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
401     gboolean interlaced;
402
403     /* Getting an extra reference for the decoder */
404     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
405     interlaced =
406         self->outArgs->decodedBufs.contentType ==
407         IVIDEO_PROGRESSIVE ? FALSE : TRUE;
408
409     /* if send is FALSE, don't try to renegotiate as we could be flushing during
410      * a PAUSED->READY state change
411      */
412     if (send && interlaced != self->interlaced) {
413       GstCaps *caps;
414
415       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
416           "thinks interlaced=%d... trusting codec", self->interlaced,
417           interlaced);
418
419       self->interlaced = interlaced;
420
421       caps =
422           gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
423       GST_INFO_OBJECT (self, "changing interlace field in caps");
424       gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
425           NULL);
426       gst_drm_buffer_pool_set_caps (self->pool, caps);
427       if (!gst_pad_set_caps (self->srcpad, caps)) {
428         GST_ERROR_OBJECT (self,
429             "downstream didn't want to change interlace mode");
430         err = XDM_EFAIL;
431       }
432       gst_caps_unref (caps);
433
434       /* this buffer still has the old caps so we skip it */
435       send = FALSE;
436     }
437
438     if (G_UNLIKELY (self->send_crop_event) && send) {
439       gint crop_width, crop_height;
440
441       /* send region of interest to sink on first buffer: */
442       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
443
444       crop_width = r->bottomRight.x - r->topLeft.x;
445       crop_height = r->bottomRight.y - r->topLeft.y;
446
447       if (crop_width > self->input_width)
448         crop_width = self->input_width;
449       if (crop_height > self->input_height)
450         crop_height = self->input_height;
451
452       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
453           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
454           crop_width, crop_height);
455
456       gst_pad_push_event (self->srcpad,
457           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
458               crop_width, crop_height));
459
460       if (self->crop)
461         gst_video_crop_unref (self->crop);
462
463       self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
464           crop_width, crop_height);
465
466       self->send_crop_event = FALSE;
467     }
468
469     if (G_UNLIKELY (self->first_out_buffer) && send) {
470       GstDRMBufferPool *pool;
471       self->first_out_buffer = FALSE;
472
473       /* Destroy the pool so the buffers we used so far are eventually released.
474        * The pool will be recreated if needed.
475        */
476       pool = self->pool;
477       self->pool = NULL;
478       gst_drm_buffer_pool_destroy (pool);
479     }
480
481     if (send) {
482       GstClockTime ts;
483
484       ts = GST_BUFFER_TIMESTAMP (outbuf);
485
486       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
487           i, outbuf, GST_TIME_ARGS (ts));
488
489 #ifdef USE_DTS_PTS_CODE
490       if (self->ts_may_be_pts) {
491         if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
492           GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
493               "enabling ts_is_pts");
494           self->ts_is_pts = TRUE;
495         }
496       }
497 #endif
498
499       self->last_pts = ts;
500
501       if (self->dts_ridx != self->dts_widx) {
502         ts = self->dts_queue[self->dts_ridx++ % NDTS];
503       }
504
505       if (self->ts_is_pts) {
506         /* if we have a queued DTS from demuxer, use that instead: */
507         GST_BUFFER_TIMESTAMP (outbuf) = ts;
508         GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
509             i, outbuf, GST_TIME_ARGS (ts));
510       }
511
512       if (GST_BUFFER_CAPS (outbuf) &&
513           !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
514               GST_PAD_CAPS (self->srcpad))) {
515         /* this looks a bit scary but it's really just to change the interlace=
516          * field in caps when we start as !interlaced and the codec detects
517          * otherwise */
518         GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
519             "interlace mismatch");
520         outbuf = gst_buffer_make_metadata_writable (outbuf);
521         gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
522       }
523
524       if (self->crop)
525         gst_buffer_set_video_crop (outbuf, self->crop);
526
527       ret = klass->push_output (self, outbuf);
528       if (flow_ret)
529         *flow_ret = ret;
530       if (ret != GST_FLOW_OK) {
531         GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
532         /* just unref the remaining buffers (if any) */
533         send = FALSE;
534       }
535     } else {
536       GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
537           i, outbuf);
538
539       gst_buffer_unref (outbuf);
540     }
541   }
542
543 skip_outbuf_processing:
544   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
545     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
546   }
547
548   return err;
549 }
550
551 /** call control(FLUSH), and then process() to pop out all buffers */
552 gboolean
553 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
554 {
555   gint err = FALSE;
556   int prev_num_in_bufs, prev_num_out_bufs;
557
558   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
559
560   GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
561
562   /* note: flush is synchronized against _chain() to avoid calling
563    * the codec from multiple threads
564    */
565   GST_PAD_STREAM_LOCK (self->sinkpad);
566
567 #ifdef USE_DTS_PTS_CODE
568   self->dts_ridx = self->dts_widx = 0;
569   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
570   self->ts_may_be_pts = TRUE;
571   self->ts_is_pts = FALSE;
572 #endif
573   self->wait_keyframe = TRUE;
574   self->in_size = 0;
575   self->needs_flushing = FALSE;
576   self->need_out_buf = TRUE;
577
578   if (G_UNLIKELY (self->first_in_buffer)) {
579     goto out;
580   }
581
582   if (G_UNLIKELY (!self->codec)) {
583     GST_WARNING_OBJECT (self, "no codec");
584     goto out;
585   }
586
587   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
588   if (err) {
589     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
590     goto out;
591   }
592
593   prev_num_in_bufs = self->inBufs->numBufs;
594   prev_num_out_bufs = self->outBufs->numBufs;
595
596   self->inBufs->descs[0].bufSize.bytes = 0;
597   self->inBufs->numBufs = 0;
598   self->inArgs->numBytes = 0;
599   self->inArgs->inputID = 0;
600   self->outBufs->numBufs = 0;
601
602   do {
603     err = codec_process (self, eos, TRUE, NULL);
604   } while (err != XDM_EFAIL);
605
606   /* We flushed the decoder, we can now remove the buffer that have never been
607    * unrefed in it */
608   g_hash_table_remove_all (self->passed_in_bufs);
609
610   /* reset outArgs in case we're flushing in codec_process trying to do error
611    * recovery */
612   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
613   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
614
615   self->dynParams->newFrameFlag = XDAS_TRUE;
616
617   /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
618   self->inBufs->numBufs = prev_num_in_bufs;
619   self->outBufs->numBufs = prev_num_out_bufs;
620
621   /* on a flush, it is normal (and not an error) for the last _process() call
622    * to return an error..
623    */
624   err = XDM_EOK;
625
626 out:
627   GST_PAD_STREAM_UNLOCK (self->sinkpad);
628   GST_DEBUG_OBJECT (self, "done");
629
630   return !err;
631 }
632
633 /* GstDucatiVidDec vmethod default implementations */
634
635 static gboolean
636 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
637 {
638   const GValue *codec_data;
639   gint w, h;
640
641   if (gst_structure_get_int (s, "width", &self->input_width) &&
642       gst_structure_get_int (s, "height", &self->input_height)) {
643
644     h = ALIGN2 (self->input_height, 4); /* round up to MB */
645     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
646
647     /* if we've already created codec, but the resolution has changed, we
648      * need to re-create the codec:
649      */
650     if (G_UNLIKELY (self->codec)) {
651       if ((h != self->height) || (w != self->width)) {
652         codec_delete (self);
653       }
654     }
655
656     self->width = w;
657     self->height = h;
658
659     codec_data = gst_structure_get_value (s, "codec_data");
660
661     if (codec_data) {
662       GstBuffer *buffer = gst_value_get_buffer (codec_data);
663       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
664       self->codec_data = gst_buffer_ref (buffer);
665     }
666
667     return TRUE;
668   }
669
670   return FALSE;
671 }
672
673 static gboolean
674 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
675     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
676 {
677
678   /* allocate params: */
679   self->params = dce_alloc (params_sz);
680   if (G_UNLIKELY (!self->params)) {
681     return FALSE;
682   }
683   self->params->size = params_sz;
684   self->params->maxFrameRate = 30000;
685   self->params->maxBitRate = 10000000;
686
687   self->params->dataEndianness = XDM_BYTE;
688   self->params->forceChromaFormat = XDM_YUV_420SP;
689   self->params->operatingMode = IVIDEO_DECODE_ONLY;
690
691   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
692   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
693   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
694   self->params->numInputDataUnits = 0;
695   self->params->numOutputDataUnits = 0;
696
697   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
698   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
699   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
700   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
701
702   /* allocate dynParams: */
703   self->dynParams = dce_alloc (dynparams_sz);
704   if (G_UNLIKELY (!self->dynParams)) {
705     return FALSE;
706   }
707   self->dynParams->size = dynparams_sz;
708   self->dynParams->decodeHeader = XDM_DECODE_AU;
709   self->dynParams->displayWidth = 0;
710   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
711   self->dynParams->newFrameFlag = XDAS_TRUE;
712
713   /* allocate status: */
714   self->status = dce_alloc (status_sz);
715   if (G_UNLIKELY (!self->status)) {
716     return FALSE;
717   }
718   memset (self->status, 0, status_sz);
719   self->status->size = status_sz;
720
721   /* allocate inBufs/outBufs: */
722   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
723   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
724   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
725     return FALSE;
726   }
727
728   /* allocate inArgs/outArgs: */
729   self->inArgs = dce_alloc (inargs_sz);
730   self->outArgs = dce_alloc (outargs_sz);
731   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
732     return FALSE;
733   }
734   self->inArgs->size = inargs_sz;
735   self->outArgs->size = outargs_sz;
736
737   return TRUE;
738 }
739
740 static GstBuffer *
741 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
742 {
743   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
744     push_input (self, GST_BUFFER_DATA (self->codec_data),
745         GST_BUFFER_SIZE (self->codec_data));
746   }
747
748   /* just copy entire buffer */
749   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
750   gst_buffer_unref (buf);
751
752   return NULL;
753 }
754
755 static GstFlowReturn
756 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
757 {
758   GstFlowReturn ret = GST_FLOW_OK;
759
760   /* if no reordering info was set, just send the buffer */
761   if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
762     GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
763     return gst_pad_push (self->srcpad, buf);
764   }
765
766   /* add the frame to the list, the array will own the ref */
767   GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
768   self->backlog_frames[self->backlog_nframes++] = buf;
769
770   /* push till we have no more than the max needed, or error */
771   while (self->backlog_nframes > self->backlog_maxframes) {
772     ret = gst_ducati_viddec_push_earliest (self);
773     if (ret != GST_FLOW_OK)
774       break;
775   }
776
777   return ret;
778 }
779
780 static gint
781 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
782     gint extended_error, gint status_extended_error)
783 {
784   if (XDM_ISFATALERROR (extended_error))
785     ret = XDM_EFAIL;
786   else
787     ret = XDM_EOK;
788
789   return ret;
790 }
791
792 /* GstElement vmethod implementations */
793
794 static gboolean
795 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
796 {
797   gboolean ret = TRUE;
798   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
799   GstStructure *s;
800   GstCaps *outcaps = NULL;
801   GstStructure *out_s;
802   gint par_width, par_height;
803   gboolean par_present;
804
805   s = gst_caps_get_structure (caps, 0);
806   if (!klass->parse_caps (self, s)) {
807     GST_WARNING_OBJECT (self, "missing required fields");
808     ret = FALSE;
809     goto out;
810   }
811
812   /* update output/padded sizes */
813   klass->update_buffer_size (self);
814
815   if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
816     self->fps_n = 0;
817     self->fps_d = 1;
818   }
819   gst_structure_get_boolean (s, "interlaced", &self->interlaced);
820   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
821       &par_width, &par_height);
822
823   outcaps = gst_pad_get_allowed_caps (self->srcpad);
824   if (outcaps) {
825     outcaps = gst_caps_make_writable (outcaps);
826     gst_caps_truncate (outcaps);
827     if (gst_caps_is_empty (outcaps)) {
828       gst_caps_unref (outcaps);
829       outcaps = NULL;
830     }
831   }
832
833   if (!outcaps) {
834     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
835         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
836   }
837
838   out_s = gst_caps_get_structure (outcaps, 0);
839   gst_structure_set (out_s,
840       "width", G_TYPE_INT, self->padded_width,
841       "height", G_TYPE_INT, self->padded_height,
842       "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
843   if (par_present)
844     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
845         par_width, par_height, NULL);
846
847   if (self->interlaced)
848     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
849
850   self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
851       0, self->padded_width);
852
853   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
854       self->stride, self->padded_height);
855
856   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
857       self->outsize, self->stride, outcaps);
858
859   if (!self->first_in_buffer) {
860     /* Caps changed mid stream. We flush the codec to unlock all the potentially
861      * locked buffers. This is needed for downstream sinks that provide a
862      * buffer pool and need to destroy all the outstanding buffers before they
863      * can negotiate new caps (hello v4l2sink).
864      */
865     gst_ducati_viddec_codec_flush (self, FALSE);
866   }
867
868   /* (re)send a crop event when caps change */
869   self->send_crop_event = TRUE;
870
871   ret = gst_pad_set_caps (self->srcpad, outcaps);
872
873   GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
874
875   /* default to no reordering */
876   self->backlog_maxframes = 0;
877
878 out:
879   if (outcaps)
880     gst_caps_unref (outcaps);
881
882   return ret;
883 }
884
885 static gboolean
886 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
887 {
888   gboolean ret = TRUE;
889   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
890   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
891
892   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
893
894   ret = klass->set_sink_caps (self, caps);
895
896   gst_object_unref (self);
897
898   return ret;
899 }
900
901 static GstCaps *
902 gst_ducati_viddec_src_getcaps (GstPad * pad)
903 {
904   GstCaps *caps = NULL;
905
906   caps = GST_PAD_CAPS (pad);
907   if (caps == NULL) {
908     return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
909   } else {
910     return gst_caps_copy (caps);
911   }
912 }
913
914 static gboolean
915 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
916     GstQuery * query, gboolean * forward)
917 {
918   gboolean res = TRUE;
919
920   switch (GST_QUERY_TYPE (query)) {
921     case GST_QUERY_BUFFERS:
922       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
923       gst_query_set_buffers_count (query, self->min_buffers);
924
925       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
926           self->padded_width, self->padded_height);
927       gst_query_set_buffers_dimensions (query,
928           self->padded_width, self->padded_height);
929       *forward = FALSE;
930       break;
931     default:
932       break;
933   }
934
935
936   return res;
937 }
938
939 static gboolean
940 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
941 {
942   gboolean res = TRUE, forward = TRUE;
943   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
944   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
945
946   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
947   res = klass->query (self, pad, query, &forward);
948   if (res && forward)
949     res = gst_pad_query_default (pad, query);
950
951   return res;
952 }
953
954 static gboolean
955 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
956 {
957   GstClockTime timestamp, qostime;
958   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
959   gint64 diff;
960
961   if (self->wait_keyframe) {
962     if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
963       GST_INFO_OBJECT (self, "skipping until the next keyframe");
964       return FALSE;
965     }
966
967     self->wait_keyframe = FALSE;
968   }
969
970   timestamp = GST_BUFFER_TIMESTAMP (buf);
971   if (self->segment.format != GST_FORMAT_TIME ||
972       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
973     goto no_qos;
974
975   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
976     goto no_qos;
977
978   qostime = gst_segment_to_running_time (&self->segment,
979       GST_FORMAT_TIME, timestamp);
980   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
981     /* out of segment */
982     goto no_qos;
983
984   /* see how our next timestamp relates to the latest qos timestamp. negative
985    * values mean we are early, positive values mean we are too late. */
986   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
987
988   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
989       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
990       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
991       self->qos_proportion);
992
993   if (klass->can_drop_frame (self, buf, diff)) {
994     GST_INFO_OBJECT (self, "dropping frame");
995     return FALSE;
996   }
997
998 no_qos:
999   return TRUE;
1000 }
1001
1002 static gboolean
1003 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1004     gint64 diff)
1005 {
1006   gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1007       GST_BUFFER_FLAG_DELTA_UNIT);
1008
1009   if (diff >= 0 && !is_keyframe)
1010     return TRUE;
1011
1012   return FALSE;
1013 }
1014
1015 static GstFlowReturn
1016 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1017 {
1018   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1019   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1020   GstFlowReturn ret = GST_FLOW_OK;
1021   Int32 err;
1022   GstBuffer *outbuf = NULL;
1023   GstCaps *outcaps = NULL;
1024   gboolean decode;
1025
1026   if (G_UNLIKELY (!self->engine)) {
1027     GST_ERROR_OBJECT (self, "no engine");
1028     gst_buffer_unref (buf);
1029     return GST_FLOW_ERROR;
1030   }
1031
1032   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1033       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1034
1035   decode = gst_ducati_viddec_do_qos (self, buf);
1036   if (!decode) {
1037     gst_buffer_unref (buf);
1038     return GST_FLOW_OK;
1039   }
1040
1041   if (!self->need_out_buf)
1042     goto have_out_buf;
1043
1044   /* do this before creating codec to ensure reverse caps negotiation
1045    * happens first:
1046    */
1047 allocate_buffer:
1048   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1049       GST_PAD_CAPS (self->srcpad), &outbuf);
1050   if (ret != GST_FLOW_OK) {
1051     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1052         gst_flow_get_name (ret));
1053     gst_buffer_unref (buf);
1054     return ret;
1055   }
1056
1057   outcaps = GST_BUFFER_CAPS (outbuf);
1058   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1059     GstStructure *s;
1060
1061     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1062         GST_BUFFER_SIZE (outbuf));
1063
1064     s = gst_caps_get_structure (outcaps, 0);
1065     gst_structure_get_int (s, "rowstride", &self->stride);
1066     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1067         self->stride, self->padded_height);
1068
1069     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1070         self->outsize, self->stride, outcaps);
1071
1072     gst_pad_set_caps (self->srcpad, outcaps);
1073
1074     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1075       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1076           GST_BUFFER_SIZE (outbuf), self->outsize);
1077       gst_buffer_unref (outbuf);
1078       goto allocate_buffer;
1079     }
1080   }
1081
1082   if (G_UNLIKELY (!self->codec)) {
1083     if (!codec_create (self)) {
1084       GST_ERROR_OBJECT (self, "could not create codec");
1085       gst_buffer_unref (buf);
1086       gst_buffer_unref (outbuf);
1087       return GST_FLOW_ERROR;
1088     }
1089   }
1090
1091   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1092   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1093
1094   /* Pass new output buffer to the decoder to decode into. Use buffers from the
1095    * internal pool while self->first_out_buffer == TRUE in order to simplify
1096    * things in case we need to renegotiate */
1097   self->inArgs->inputID =
1098       codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1099   if (!self->inArgs->inputID) {
1100     GST_ERROR_OBJECT (self, "could not prepare output buffer");
1101     gst_buffer_unref (buf);
1102     return GST_FLOW_ERROR;
1103   }
1104   GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1105
1106 have_out_buf:
1107   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1108
1109 #ifdef USE_DTS_PTS_CODE
1110   if (ts != GST_CLOCK_TIME_NONE) {
1111     self->dts_queue[self->dts_widx++ % NDTS] = ts;
1112     /* if next buffer has earlier ts than previous, then the ts
1113      * we are getting are definitely decode order (DTS):
1114      */
1115     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1116       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1117       self->ts_may_be_pts = FALSE;
1118     }
1119     self->last_dts = ts;
1120   }
1121 #endif
1122
1123   if (self->in_size == 0 && outbuf) {
1124     GST_DEBUG_OBJECT (self, "no input, skipping process");
1125
1126     gst_buffer_unref (outbuf);
1127     return GST_FLOW_OK;
1128   }
1129
1130   self->inArgs->numBytes = self->in_size;
1131   self->inBufs->descs[0].bufSize.bytes = self->in_size;
1132   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1133
1134   err = codec_process (self, TRUE, FALSE, &ret);
1135   if (err) {
1136     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1137         ("process returned error: %d %08x", err, self->outArgs->extendedError));
1138     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1139         self->error_strings);
1140
1141     return GST_FLOW_ERROR;
1142   }
1143
1144   if (ret != GST_FLOW_OK) {
1145     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1146         gst_flow_get_name (ret));
1147
1148     return ret;
1149   }
1150
1151   self->first_in_buffer = FALSE;
1152
1153   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1154     /* The copy could be avoided by playing with the buffer pointer,
1155        but it seems to be rare and for not many bytes */
1156     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1157         self->outArgs->bytesConsumed, self->in_size,
1158         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1159     if (self->outArgs->bytesConsumed > 0) {
1160       if (self->outArgs->bytesConsumed > self->in_size) {
1161         GST_WARNING_OBJECT (self,
1162             "Codec claims to have used more bytes than supplied");
1163         self->in_size = 0;
1164       } else {
1165         if (self->outArgs->bytesConsumed < self->in_size) {
1166           memmove (self->input, self->input + self->outArgs->bytesConsumed,
1167               self->in_size - self->outArgs->bytesConsumed);
1168         }
1169         self->in_size -= self->outArgs->bytesConsumed;
1170       }
1171     }
1172   } else {
1173     self->in_size = 0;
1174   }
1175
1176   if (self->outArgs->outBufsInUseFlag) {
1177     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1178     self->need_out_buf = FALSE;
1179   } else {
1180     self->need_out_buf = TRUE;
1181   }
1182
1183   if (buf) {
1184     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1185         GST_BUFFER_SIZE (buf));
1186     ts = GST_BUFFER_TIMESTAMP (buf);
1187     goto allocate_buffer;
1188   }
1189
1190   if (self->needs_flushing)
1191     gst_ducati_viddec_codec_flush (self, FALSE);
1192
1193   return GST_FLOW_OK;
1194 }
1195
1196 static gboolean
1197 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1198 {
1199   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1200   gboolean ret = TRUE;
1201
1202   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1203
1204   switch (GST_EVENT_TYPE (event)) {
1205     case GST_EVENT_NEWSEGMENT:
1206     {
1207       gboolean update;
1208       GstFormat fmt;
1209       gint64 start, stop, time;
1210       gdouble rate, arate;
1211
1212       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1213           &start, &stop, &time);
1214       gst_segment_set_newsegment_full (&self->segment, update,
1215           rate, arate, fmt, start, stop, time);
1216       break;
1217     }
1218     case GST_EVENT_EOS:
1219       if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1220         GST_ERROR_OBJECT (self, "could not flush on eos");
1221         ret = FALSE;
1222       }
1223       break;
1224     case GST_EVENT_FLUSH_STOP:
1225       if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1226         GST_ERROR_OBJECT (self, "could not flush");
1227         gst_event_unref (event);
1228         ret = FALSE;
1229       }
1230       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1231       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1232       self->qos_proportion = 1;
1233       self->need_out_buf = TRUE;
1234       break;
1235     default:
1236       break;
1237   }
1238
1239   if (ret)
1240     ret = gst_pad_push_event (self->srcpad, event);
1241   GST_LOG_OBJECT (self, "end");
1242
1243   return ret;
1244 }
1245
1246 static gboolean
1247 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1248 {
1249   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1250   gboolean ret = TRUE;
1251
1252   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1253
1254   switch (GST_EVENT_TYPE (event)) {
1255     case GST_EVENT_QOS:
1256     {
1257       gdouble proportion;
1258       GstClockTimeDiff diff;
1259       GstClockTime timestamp;
1260
1261       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
1262
1263       GST_OBJECT_LOCK (self);
1264       self->qos_proportion = proportion;
1265       self->qos_earliest_time = timestamp + 2 * diff;
1266       GST_OBJECT_UNLOCK (self);
1267
1268       GST_DEBUG_OBJECT (self,
1269           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1270           proportion, GST_TIME_ARGS (timestamp), diff);
1271
1272       ret = gst_pad_push_event (self->sinkpad, event);
1273       break;
1274     }
1275     default:
1276       ret = gst_pad_push_event (self->sinkpad, event);
1277       break;
1278   }
1279
1280   GST_LOG_OBJECT (self, "end");
1281
1282   return ret;
1283 }
1284
1285 static GstStateChangeReturn
1286 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1287 {
1288   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1289   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1290   gboolean supported;
1291
1292   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1293       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1294       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1295
1296   switch (transition) {
1297     case GST_STATE_CHANGE_NULL_TO_READY:
1298       if (!engine_open (self)) {
1299         GST_ERROR_OBJECT (self, "could not open");
1300         return GST_STATE_CHANGE_FAILURE;
1301       }
1302       /* try to create/destroy the codec here, it may not be supported */
1303       supported = codec_create (self);
1304       codec_delete (self);
1305       self->codec = NULL;
1306       if (!supported) {
1307         GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1308             GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1309         engine_close (self);
1310         return GST_STATE_CHANGE_FAILURE;
1311       }
1312       break;
1313     default:
1314       break;
1315   }
1316
1317   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1318
1319   if (ret == GST_STATE_CHANGE_FAILURE)
1320     goto leave;
1321
1322   switch (transition) {
1323     case GST_STATE_CHANGE_PAUSED_TO_READY:
1324       self->interlaced = FALSE;
1325       self->send_crop_event = TRUE;
1326       gst_ducati_viddec_codec_flush (self, FALSE);
1327       break;
1328     case GST_STATE_CHANGE_READY_TO_NULL:
1329       codec_delete (self);
1330       engine_close (self);
1331       break;
1332     default:
1333       break;
1334   }
1335
1336 leave:
1337   GST_LOG_OBJECT (self, "end");
1338
1339   return ret;
1340 }
1341
1342 /* GObject vmethod implementations */
1343
1344 #define VERSION_LENGTH 256
1345
1346 static void
1347 gst_ducati_viddec_get_property (GObject * obj,
1348     guint prop_id, GValue * value, GParamSpec * pspec)
1349 {
1350   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1351
1352
1353   switch (prop_id) {
1354     case PROP_VERSION:{
1355       int err;
1356       char *version = NULL;
1357
1358       if (!self->engine)
1359         engine_open (self);
1360
1361       if (!self->codec)
1362         codec_create (self);
1363
1364       if (self->codec) {
1365         version = dce_alloc (VERSION_LENGTH);
1366         self->status->data.buf = (XDAS_Int8 *) version;
1367         self->status->data.bufSize = VERSION_LENGTH;
1368
1369         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1370             self->dynParams, self->status);
1371         if (err) {
1372           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1373         }
1374
1375         self->status->data.buf = NULL;
1376         self->status->data.bufSize = 0;
1377       }
1378
1379       g_value_set_string (value, version);
1380       if (version)
1381         dce_free (version);
1382
1383       break;
1384     }
1385     case PROP_MAX_REORDER_FRAMES:
1386       g_value_set_int (value, self->backlog_max_maxframes);
1387       break;
1388     case PROP_CODEC_DEBUG_INFO:
1389       g_value_set_boolean (value, self->codec_debug_info);
1390       break;
1391     default:{
1392       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1393       break;
1394     }
1395   }
1396 }
1397
1398 static void
1399 gst_ducati_viddec_set_property (GObject * obj,
1400     guint prop_id, const GValue * value, GParamSpec * pspec)
1401 {
1402   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1403
1404   switch (prop_id) {
1405     case PROP_MAX_REORDER_FRAMES:
1406       self->backlog_max_maxframes = g_value_get_int (value);
1407       break;
1408     case PROP_CODEC_DEBUG_INFO:
1409       self->codec_debug_info = g_value_get_boolean (value);
1410       break;
1411     default:{
1412       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1413       break;
1414     }
1415   }
1416 }
1417
1418 static void
1419 gst_ducati_viddec_finalize (GObject * obj)
1420 {
1421   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1422
1423   codec_delete (self);
1424   engine_close (self);
1425
1426   /* Will unref the remaining buffers if needed */
1427   g_hash_table_unref (self->passed_in_bufs);
1428   if (self->codec_data) {
1429     gst_buffer_unref (self->codec_data);
1430     self->codec_data = NULL;
1431   }
1432
1433   G_OBJECT_CLASS (parent_class)->finalize (obj);
1434 }
1435
1436 static void
1437 gst_ducati_viddec_base_init (gpointer gclass)
1438 {
1439   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1440
1441   gst_element_class_add_pad_template (element_class,
1442       gst_static_pad_template_get (&src_factory));
1443 }
1444
1445 static void
1446 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1447 {
1448   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1449   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1450
1451   gobject_class->get_property =
1452       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1453   gobject_class->set_property =
1454       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1455   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1456   gstelement_class->change_state =
1457       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1458
1459   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1460   klass->allocate_params =
1461       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1462   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1463   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1464   klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1465   klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1466   klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1467   klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1468   klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1469
1470   g_object_class_install_property (gobject_class, PROP_VERSION,
1471       g_param_spec_string ("version", "Version",
1472           "The codec version string", "",
1473           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1474
1475   g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1476       g_param_spec_int ("max-reorder-frames",
1477           "Maximum number of frames needed for reordering",
1478           "The maximum number of frames needed for reordering output frames. "
1479           "Only meaningful for codecs with B frames. 0 means no reordering. "
1480           "This value will be used if the correct value cannot be inferred "
1481           "from the stream. Too low a value may cause misordering, too high "
1482           "will cause extra latency.",
1483           0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1484           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1485
1486   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1487       g_param_spec_boolean ("codec-debug-info",
1488           "Gather debug info from the codec",
1489           "Gather and log relevant debug information from the codec. "
1490           "What is gathered is typically codec specific", FALSE,
1491           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1492 }
1493
1494 static void
1495 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1496 {
1497   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1498
1499   gst_ducati_set_generic_error_strings (self->error_strings);
1500
1501   self->sinkpad =
1502       gst_pad_new_from_template (gst_element_class_get_pad_template
1503       (gstelement_class, "sink"), "sink");
1504   gst_pad_set_setcaps_function (self->sinkpad,
1505       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1506   gst_pad_set_chain_function (self->sinkpad,
1507       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1508   gst_pad_set_event_function (self->sinkpad,
1509       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1510
1511   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1512   gst_pad_set_event_function (self->srcpad,
1513       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1514   gst_pad_set_query_function (self->srcpad,
1515       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1516   gst_pad_set_getcaps_function (self->srcpad,
1517       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1518
1519   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1520   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1521
1522   self->input_width = 0;
1523   self->input_height = 0;
1524   /* sane defaults in case we need to create codec without caps negotiation
1525    * (for example, to get 'version' property)
1526    */
1527   self->width = 128;
1528   self->height = 128;
1529   self->fps_n = -1;
1530   self->fps_d = -1;
1531
1532   self->first_in_buffer = TRUE;
1533   self->first_out_buffer = TRUE;
1534   self->interlaced = FALSE;
1535   self->send_crop_event = TRUE;
1536
1537 #ifdef USE_DTS_PTS_CODE
1538   self->dts_ridx = self->dts_widx = 0;
1539   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1540   self->ts_may_be_pts = TRUE;
1541   self->ts_is_pts = FALSE;
1542 #endif
1543
1544   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1545
1546   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1547
1548   self->qos_proportion = 1;
1549   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1550   self->wait_keyframe = TRUE;
1551
1552   self->need_out_buf = TRUE;
1553   self->device = NULL;
1554   self->input_bo = NULL;
1555
1556   self->backlog_maxframes = 0;
1557   self->backlog_nframes = 0;
1558   self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1559
1560   self->codec_debug_info = FALSE;
1561
1562   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1563       NULL, (GDestroyNotify) gst_buffer_unref);
1564 }