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