Port DucatiVidDec to the Gstreamer 1.0 API
[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 "gstducatimeta.h"
26 #include "gstducatividdec.h"
27
28 #include <sys/drm/gstdrmmeta.h>
29 #include <sys/dma/gstdmabufmeta.h>
30
31 #define gst_ducati_viddec_parent_class parent_class
32 G_DEFINE_TYPE (GstDucatiVidDec, gst_ducati_viddec, GST_TYPE_VIDEO_DECODER);
33
34 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
35     GST_PAD_SRC,
36     GST_PAD_ALWAYS,
37     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("NV12"))
38     );
39
40 enum
41 {
42   PROP_0,
43   PROP_VERSION,
44   PROP_CODEC_DEBUG_INFO
45 };
46
47 /***********************************
48  *                                 *
49  *         helper functions        *
50  *                                 *
51  ***********************************/
52 static void
53 engine_close (GstDucatiVidDec * self)
54 {
55   if (self->engine) {
56     Engine_close (self->engine);
57     self->engine = NULL;
58   }
59
60   if (self->params) {
61     dce_free (self->params);
62     self->params = NULL;
63   }
64
65   if (self->dynParams) {
66     dce_free (self->dynParams);
67     self->dynParams = NULL;
68   }
69
70   if (self->status) {
71     dce_free (self->status);
72     self->status = NULL;
73   }
74
75   if (self->inBufs) {
76     dce_free (self->inBufs);
77     self->inBufs = NULL;
78   }
79
80   if (self->outBufs) {
81     dce_free (self->outBufs);
82     self->outBufs = NULL;
83   }
84
85   if (self->inArgs) {
86     dce_free (self->inArgs);
87     self->inArgs = NULL;
88   }
89
90   if (self->outArgs) {
91     dce_free (self->outArgs);
92     self->outArgs = NULL;
93   }
94
95   if (self->device) {
96     dce_deinit (self->device);
97     self->device = NULL;
98   }
99 }
100
101 static gboolean
102 engine_open (GstDucatiVidDec * self)
103 {
104   int ec;
105   gboolean ret;
106
107   if (G_UNLIKELY (self->engine)) {
108     return TRUE;
109   }
110
111   if (self->device == NULL) {
112     self->device = dce_init ();
113     if (self->device == NULL) {
114       GST_ERROR_OBJECT (self, "dce_init() failed");
115       return FALSE;
116     }
117   }
118
119   GST_DEBUG_OBJECT (self, "opening engine");
120
121   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
122   if (G_UNLIKELY (!self->engine)) {
123     GST_ERROR_OBJECT (self, "could not create engine");
124     return FALSE;
125   }
126
127   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
128       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
129       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
130       sizeof (IVIDDEC3_OutArgs));
131
132   return ret;
133 }
134
135 static void
136 codec_delete (GstDucatiVidDec * self)
137 {
138   GST_DEBUG_OBJECT (self, "Deleting codec");
139
140   /* FIXME: Do we need to protect the pool here? */
141   if (self->pool) {
142     gst_object_unref (self->pool);
143     self->pool = NULL;
144   }
145
146   if (self->codec) {
147     VIDDEC3_delete (self->codec);
148     self->codec = NULL;
149   }
150
151   if (self->input_bo) {
152     omap_bo_del (self->input_bo);
153     self->input_bo = NULL;
154   }
155 }
156
157 static gboolean
158 codec_create (GstDucatiVidDec * self)
159 {
160   gint err, n;
161   const gchar *codec_name;
162
163   codec_delete (self);
164
165   if (G_UNLIKELY (!self->engine))
166     goto no_engine;
167
168   /* these need to be set before VIDDEC3_create */
169   self->params->maxWidth = self->width;
170   self->params->maxHeight = self->height;
171
172   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
173
174   /* create codec: */
175   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
176   self->codec = VIDDEC3_create (self->engine, (String) codec_name,
177       self->params);
178
179   if (!self->codec)
180     goto no_codec;
181
182   if (VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
183           self->status))
184     goto setparams_fail;
185
186   self->first_in_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   /* Error cases */
208 no_engine:
209   {
210     GST_ERROR_OBJECT (self, "no engine");
211     return FALSE;
212   }
213
214 no_codec:
215   {
216     GST_ERROR_OBJECT (self, "Failed to create codec %s", codec_name);
217     return FALSE;
218   }
219
220 setparams_fail:
221   {
222     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
223     return FALSE;
224   }
225 }
226
227 static inline GstBuffer *
228 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
229 {
230   if (G_UNLIKELY (!self->pool)) {
231     guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
232         self->padded_width, self->padded_height);
233
234     GST_DEBUG_OBJECT (self, "creating bufferpool");
235     self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
236         dce_get_fd (), GST_PAD_CAPS (GST_VIDEO_DECODER_SRC_PAD (self)), size);
237   }
238   return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
239 }
240
241 static GstDucatiBufferPriv *
242 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
243 {
244   GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
245   if (!priv) {
246     GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
247
248     /* if it isn't a dmabuf buffer that we can import, then there
249      * is nothing we can do with it:
250      */
251     if (!dmabuf) {
252       GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
253       return NULL;
254     }
255
256     priv = gst_ducati_buffer_priv_new ();
257     priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
258     priv->uv_offset = self->output_state->info.offset[1];
259     priv->size = self->output_state->info.size;
260
261     gst_ducati_buffer_priv_set (buf, priv);
262     gst_mini_object_unref (GST_MINI_OBJECT (priv));
263   }
264   return priv;
265 }
266
267 static XDAS_Int32
268 codec_prepare_outbuf (GstDucatiVidDec * self, GstVideoCodecFrame * frame,
269     gboolean force_internal)
270 {
271   GstDucatiBufferPriv *priv = NULL;
272   GstBuffer *orig, *outbuf;
273
274   orig = outbuf = frame->output_buffer;
275
276   if (!force_internal)
277     priv = get_buffer_priv (self, outbuf);
278
279   if (!priv) {
280
281     GST_DEBUG_OBJECT (self, "internal bufferpool forced");
282     outbuf = codec_buffer_pool_get (self, NULL);
283     GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (orig);
284     GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (orig);
285
286     gst_buffer_unref (orig);
287     frame->output_buffer = outbuf;
288
289     return codec_prepare_outbuf (self, frame, FALSE);
290   }
291
292   /* There are at least two buffers. Derived classes may add codec specific
293      buffers (eg, debug info) after these two if they want to. */
294   self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
295   self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
296   self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
297   self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
298   self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
299   self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
300
301   return (XDAS_Int32) frame;
302 }
303
304 static inline GstVideoCodecFrame *
305 codec_add_frame (GstDucatiVidDec * self, XDAS_Int32 id)
306 {
307   GstVideoCodecFrame *frame = (GstVideoCodecFrame *) id;
308
309   if (frame)
310     g_hash_table_insert (self->passed_in_bufs, frame,
311         gst_video_codec_frame_ref (frame));
312
313   return frame;
314 }
315
316 static void
317 codec_unlock_frame (GstDucatiVidDec * self, XDAS_Int32 id)
318 {
319   GstBuffer *buf = (GstBuffer *) id;
320
321   if (buf) {
322     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
323     g_hash_table_remove (self->passed_in_bufs, buf);
324   }
325 }
326
327 static GstFlowReturn
328 alloc_output_buffer (GstDucatiVidDec * self, GstVideoCodecFrame * frame)
329 {
330   GstCaps *outcaps;
331   GstFlowReturn ret;
332   GstBuffer *outbuf;
333
334   ret = gst_video_decoder_alloc_output_frame (GST_VIDEO_DECODER (self), frame);
335   if (ret != GST_FLOW_OK) {
336     GST_DEBUG_OBJECT (self, "gst_video_decoder_alloc_output_frame failed: %s",
337         gst_flow_get_name (ret));
338
339     return ret;
340   }
341
342   outbuf = frame->output_buffer;
343   outcaps = GST_BUFFER_CAPS (outbuf);
344   if (outcaps && gst_caps_is_equal (outcaps,
345           GST_PAD_CAPS (GST_VIDEO_DECODER_SRC_PAD (self))))
346     return ret;
347
348   /* FIXME: Reimplement with GStreamer 1.0
349    * Let reverse negotiation happen */
350   GST_FIXME_OBJECT (self, "Upstrean negotiation not implemented");
351
352   return GST_FLOW_ERROR;
353 }
354
355 /* Prepares the output_buffer of @frame */
356 static GstFlowReturn
357 prepare_output_buffer (GstDucatiVidDec * self, GstVideoCodecFrame * frame)
358 {
359   GstFlowReturn ret;
360   GstBuffer *inbuf, *outbuf;
361
362   if ((ret = alloc_output_buffer (self, frame)) != GST_FLOW_OK) {
363
364     GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
365         gst_flow_get_name (ret));
366
367     return ret;
368   }
369
370   if (G_UNLIKELY (!self->codec)) {
371     if (!codec_create (self)) {
372       GST_ERROR_OBJECT (self, "could not create codec");
373
374       return GST_FLOW_ERROR;
375     }
376   }
377
378   outbuf = frame->output_buffer;
379   inbuf = frame->input_buffer;
380   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
381   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
382
383   /* Pass frame to the decoder so it decodes into the output buffer.
384    * Use buffers from the internal pool while
385    * self->first_out_buffer == TRUE in order to simplify things in case
386    * we need to renegotiate */
387   self->inArgs->inputID = codec_prepare_outbuf (self, frame,
388       self->first_out_buffer);
389
390   if (!self->inArgs->inputID) {
391     GST_ERROR_OBJECT (self, "could not prepare output buffer");
392     return GST_FLOW_ERROR;
393   }
394
395   return GST_FLOW_OK;
396 }
397
398 static inline void
399 send_crop_event (GstDucatiVidDec * self)
400 {
401   gint crop_width, crop_height;
402
403   /* send region of interest to sink on first buffer: */
404   XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
405
406   crop_width = r->bottomRight.x - r->topLeft.x;
407   crop_height = r->bottomRight.y - r->topLeft.y;
408
409   if (crop_width > self->input_state->info.width)
410     crop_width = self->input_state->info.width;
411   if (crop_height > self->input_state->info.height)
412     crop_height = self->input_state->info.height;
413
414   GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
415       r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
416       crop_width, crop_height);
417
418   gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
419       gst_event_new_crop (r->topLeft.y, r->topLeft.x, crop_width, crop_height));
420
421   if (self->crop)
422     gst_video_crop_unref (self->crop);
423
424   self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
425       crop_width, crop_height);
426
427   self->send_crop_event = FALSE;
428 }
429
430 static gint
431 codec_process (GstDucatiVidDec * self, gboolean send,
432     gboolean flush, GstFlowReturn * flow_ret)
433 {
434   gint i;
435   gint err;
436   GstClockTime t;
437   GstBuffer *outbuf;
438   GstVideoCodecFrame *frame;
439
440   GstFlowReturn ret = GST_FLOW_OK;
441
442   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
443
444   if (flow_ret)
445     /* never leave flow_ret uninitialized */
446     *flow_ret = GST_FLOW_OK;
447
448   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
449   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
450
451   GST_DEBUG ("Calling VIDDEC3_process");
452   t = gst_util_get_timestamp ();
453   err = VIDDEC3_process (self->codec, self->inBufs, self->outBufs,
454       self->inArgs, self->outArgs);
455   GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
456       (gint) (t / 1000000));
457
458
459   if (err) {
460     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
461         err, self->outArgs->extendedError);
462     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
463         self->error_strings);
464
465     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
466         self->dynParams, self->status);
467     if (err) {
468       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
469           err, self->status->extendedError);
470       gst_ducati_log_extended_error_info (self->status->extendedError,
471           self->error_strings);
472     }
473
474     if (flush)
475       err = XDM_EFAIL;
476     else
477       err = klass->handle_error (self, err,
478           self->outArgs->extendedError, self->status->extendedError);
479   }
480
481   /* we now let the codec decide */
482   self->dynParams->newFrameFlag = XDAS_FALSE;
483
484   if (err == XDM_EFAIL)
485     goto skip_outbuf_processing;
486
487   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
488     GstClockTime ts;
489     GstVideoInterlaceMode interlaced;
490
491     /* Getting an extra reference for the decoder */
492     frame = codec_add_frame (self, self->outArgs->outputID[i]);
493     if (send == FALSE) {
494       /* if send is FALSE:
495        *  + Don't try to renegotiate as we could be flushing during a
496        *    PAUSED->READY state change
497        *  + Do not try to push the frame downstream
498        *  + Declare the frames as dropped
499        */
500
501       GST_DEBUG_OBJECT (self, "frame not pushed, dropping 'chain' ref: %d %p",
502           i, frame);
503
504       ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
505       continue;
506     }
507
508     if (self->outArgs->decodedBufs.contentType == IVIDEO_PROGRESSIVE)
509       interlaced = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
510     else
511       interlaced = GST_VIDEO_INTERLACE_MODE_INTERLEAVED;
512
513     if (interlaced != self->output_state->info.interlace_mode) {
514       GstVideoCodecState *new_state;
515
516       GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
517           "thinks interlaced=%d... trusting codec... and droping frame",
518           self->output_state->info.interlace_mode, interlaced);
519
520       self->output_state->info.interlace_mode = interlaced;
521       new_state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
522           GST_VIDEO_FORMAT_NV12, self->padded_width, self->padded_height,
523           self->output_state);
524       gst_video_codec_state_unref (self->output_state);
525       self->output_state = new_state;
526
527       /* this buffer still has the old caps so we drop it */
528       ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
529       /* and the following ones */
530       send = FALSE;
531
532       continue;
533     }
534
535     if (G_UNLIKELY (self->send_crop_event))
536       send_crop_event (self);
537
538     if (G_UNLIKELY (self->first_out_buffer)) {
539       GstDRMBufferPool *pool;
540       self->first_out_buffer = FALSE;
541
542       /* Destroy the pool so the buffers we used so far are eventually released.
543        * The pool will be recreated if needed.
544        */
545       pool = self->pool;
546       self->pool = NULL;
547       gst_drm_buffer_pool_destroy (pool);
548     }
549
550
551     outbuf = frame->output_buffer;
552     ts = GST_BUFFER_TIMESTAMP (outbuf);
553     GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
554         i, outbuf, GST_TIME_ARGS (ts));
555
556 #ifdef USE_DTS_PTS_CODE
557     if (self->ts_may_be_pts) {
558       if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
559         GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
560             "enabling ts_is_pts");
561         self->ts_is_pts = TRUE;
562       }
563     }
564 #endif
565
566     self->last_pts = ts;
567
568     if (self->dts_ridx != self->dts_widx) {
569       ts = self->dts_queue[self->dts_ridx++ % NDTS];
570     }
571
572     if (self->ts_is_pts) {
573       /* if we have a queued DTS from demuxer, use that instead: */
574       GST_BUFFER_TIMESTAMP (outbuf) = ts;
575       GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
576           i, outbuf, GST_TIME_ARGS (ts));
577     }
578     if (self->crop)
579       gst_buffer_set_video_crop (outbuf, self->crop);
580
581     GST_DEBUG_OBJECT (self, "Done with frame %p", self->inArgs->inputID);
582     ret = gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
583     if (flow_ret)
584       *flow_ret = ret;
585     if (ret != GST_FLOW_OK) {
586       GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
587       /* just unref the remaining buffers (if any) */
588       send = FALSE;
589     }
590   }
591
592 skip_outbuf_processing:
593   for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++)
594     codec_unlock_frame (self, self->outArgs->freeBufID[i]);
595
596   return err;
597 }
598
599 /** call control(FLUSH), and then process() to pop out all buffers */
600 static gboolean
601 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean hard,
602     gboolean eos)
603 {
604   gint err = FALSE;
605   int prev_num_in_bufs, prev_num_out_bufs;
606
607   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
608
609   /* FIXME GstVideoDecoder: Here we should discont */
610   /* note: flush is synchronized against _chain() to avoid calling
611    * the codec from multiple threads
612    */
613   GST_PAD_STREAM_LOCK (GST_VIDEO_DECODER_SRC_PAD (self));
614
615 #ifdef USE_DTS_PTS_CODE
616   self->dts_ridx = self->dts_widx = 0;
617   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
618   self->ts_may_be_pts = TRUE;
619   self->ts_is_pts = FALSE;
620 #endif
621   self->wait_keyframe = TRUE;
622   self->in_size = 0;
623   self->needs_flushing = FALSE;
624   self->need_out_buf = TRUE;
625
626   if (G_UNLIKELY (self->first_in_buffer)) {
627     goto out;
628   }
629
630   if (G_UNLIKELY (!self->codec)) {
631     GST_WARNING_OBJECT (self, "no codec");
632     goto out;
633   }
634
635   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
636   if (err) {
637     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
638     goto out;
639   }
640
641   prev_num_in_bufs = self->inBufs->numBufs;
642   prev_num_out_bufs = self->outBufs->numBufs;
643
644   self->inBufs->descs[0].bufSize.bytes = 0;
645   self->inBufs->numBufs = 0;
646   self->inArgs->numBytes = 0;
647   self->inArgs->inputID = 0;
648   self->outBufs->numBufs = 0;
649
650   do {
651     err = codec_process (self, eos, TRUE, NULL);
652   } while (err != XDM_EFAIL);
653
654   /* We flushed the decoder, we can now remove the buffer that have never been
655    * unrefed in it */
656   g_hash_table_remove_all (self->passed_in_bufs);
657
658   /* reset outArgs in case we're flushing in codec_process trying to do error
659    * recovery */
660   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
661   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
662
663   self->dynParams->newFrameFlag = XDAS_TRUE;
664
665   /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
666   self->inBufs->numBufs = prev_num_in_bufs;
667   self->outBufs->numBufs = prev_num_out_bufs;
668
669   /* on a flush, it is normal (and not an error) for the last _process() call
670    * to return an error..
671    */
672   err = XDM_EOK;
673
674 out:
675   GST_PAD_STREAM_UNLOCK (GST_VIDEO_DECODER_SRC_PAD (self));
676   GST_DEBUG_OBJECT (self, "done");
677
678   return !err;
679 }
680
681 /* GstDucatiVidDec vmethod default implementations */
682
683 static gboolean
684 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
685     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
686 {
687
688   /* allocate params: */
689   self->params = dce_alloc (params_sz);
690   if (G_UNLIKELY (!self->params)) {
691     return FALSE;
692   }
693   self->params->size = params_sz;
694   self->params->maxFrameRate = 30000;
695   self->params->maxBitRate = 10000000;
696
697   self->params->dataEndianness = XDM_BYTE;
698   self->params->forceChromaFormat = XDM_YUV_420SP;
699   self->params->operatingMode = IVIDEO_DECODE_ONLY;
700
701   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
702   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
703   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
704   self->params->numInputDataUnits = 0;
705   self->params->numOutputDataUnits = 0;
706
707   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
708   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
709   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
710   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
711
712   /* Let the decoder reorder frame */
713   self->params->displayDelay = IVIDDEC3_DISPLAY_DELAY_AUTO;
714
715   /* allocate dynParams: */
716   self->dynParams = dce_alloc (dynparams_sz);
717   if (G_UNLIKELY (!self->dynParams)) {
718     return FALSE;
719   }
720   self->dynParams->size = dynparams_sz;
721   self->dynParams->decodeHeader = XDM_DECODE_AU;
722   self->dynParams->displayWidth = 0;
723   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
724   self->dynParams->newFrameFlag = XDAS_TRUE;
725
726   /* allocate status: */
727   self->status = dce_alloc (status_sz);
728   if (G_UNLIKELY (!self->status)) {
729     return FALSE;
730   }
731   memset (self->status, 0, status_sz);
732   self->status->size = status_sz;
733
734   /* allocate inBufs/outBufs: */
735   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
736   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
737   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
738     return FALSE;
739   }
740
741   /* allocate inArgs/outArgs: */
742   self->inArgs = dce_alloc (inargs_sz);
743   self->outArgs = dce_alloc (outargs_sz);
744   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
745     return FALSE;
746   }
747   self->inArgs->size = inargs_sz;
748   self->outArgs->size = outargs_sz;
749
750   return TRUE;
751 }
752
753 static GstFlowReturn
754 gst_ducati_viddec_push_input (GstDucatiVidDec * self,
755     GstVideoCodecFrame * frame)
756 {
757   GstBuffer *buf = frame->input_buffer;
758
759   if (G_UNLIKELY (self->first_in_buffer) && self->input_state->codec_data)
760     push_input (self, GST_BUFFER_DATA (self->input_state->codec_data),
761         GST_BUFFER_SIZE (self->input_state->codec_data));
762
763   /* just copy entire buffer */
764   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
765
766   return GST_FLOW_OK;
767 }
768
769 static gint
770 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
771     gint extended_error, gint status_extended_error)
772 {
773   if (XDM_ISFATALERROR (extended_error))
774     ret = XDM_EFAIL;
775   else
776     ret = XDM_EOK;
777
778   return ret;
779 }
780
781 /**
782  * perform qos calculations before decoding the next frame.
783  *
784  * Returns: %TRUE if the frame should be decoded, %FALSE if the frame can be
785  * dropped entirely.
786  */
787 static gboolean
788 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstVideoCodecFrame * frame)
789 {
790   GstClockTimeDiff diff;
791
792   if (self->wait_keyframe) {
793     if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
794       GST_INFO_OBJECT (self, "skipping until the next keyframe");
795       return FALSE;
796     }
797
798     self->wait_keyframe = FALSE;
799   }
800
801   diff = gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (self),
802       frame);
803
804   /* if we don't have timing info, then we don't do QoS */
805   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (diff)))
806     return TRUE;
807
808   if (diff < 0 && !GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
809     GST_INFO_OBJECT (self, "dropping frame, diff %i", diff);
810
811     return FALSE;
812   }
813
814   return TRUE;
815 }
816
817 /* GstVideoDecoder vmethods implementation */
818 static gboolean
819 ducati_dec_open (GstVideoDecoder * decoder)
820 {
821   GstDucatiVidDec *self = GST_DUCATIVIDDEC (decoder);
822   gboolean supported;
823
824   if (!engine_open (self)) {
825     GST_ERROR_OBJECT (self, "could not open");
826     return FALSE;
827   }
828   /* try to create/destroy the codec here, it may not be supported */
829   supported = codec_create (self);
830   codec_delete (self);
831   self->codec = NULL;
832   if (!supported) {
833     GST_ERROR_OBJECT (self, "Failed to create codec %s, not supported",
834         GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
835     engine_close (self);
836     return FALSE;
837   }
838
839   return TRUE;
840 }
841
842 static gboolean
843 ducati_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state)
844 {
845   gint w, h;
846   GstDucatiVidDec *self = GST_DUCATIVIDDEC (decoder);
847   GstVideoCodecState *cstate = self->input_state ? self->input_state : state;
848
849
850   h = ALIGN2 (cstate->info.height, 4);  /* round up to MB */
851   w = ALIGN2 (cstate->info.width, 4);   /* round up to MB */
852
853   /* if we've already created codec, but the resolution has changed, we
854    * need to re-create the codec: */
855   if (G_UNLIKELY (self->codec)) {
856     if ((h != self->height) || (w != self->width)) {
857       codec_delete (self);
858     }
859   }
860
861   self->width = w;
862   self->height = h;
863
864   /* (re)send a crop event when caps change */
865   self->send_crop_event = TRUE;
866
867   /* And keep a ref to the input state */
868   if (self->input_state)
869     gst_video_codec_state_unref (self->input_state);
870
871   self->input_state = gst_video_codec_state_ref (state);
872
873   /* Now set the ouptut state */
874   GST_DUCATIVIDDEC_GET_CLASS (self)->update_buffer_size (self);
875   self->output_state =
876       gst_video_decoder_set_output_state (decoder, GST_VIDEO_FORMAT_NV12,
877       self->padded_width, self->padded_height, state);
878
879   return TRUE;
880 }
881
882 static GstFlowReturn
883 ducati_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame)
884 {
885   Int32 err;
886
887   GstFlowReturn ret = GST_FLOW_OK;
888
889   GstBuffer *buf = frame->input_buffer;
890   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
891   GstDucatiVidDec *self = GST_DUCATIVIDDEC (decoder);
892
893   if (G_UNLIKELY (!self->engine)) {
894     GST_ERROR_OBJECT (self, "no engine");
895
896     return gst_video_decoder_drop_frame (decoder, frame);
897   }
898
899   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
900       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
901
902   if (!gst_ducati_viddec_do_qos (self, frame))
903     return gst_video_decoder_drop_frame (decoder, frame);
904
905   if (self->need_out_buf) {
906     ret = prepare_output_buffer (self, frame);
907
908     if (ret != GST_FLOW_OK) {
909       GST_WARNING_OBJECT (self, "Could not prepare output buffer: %s",
910           gst_flow_get_name (ret));
911       return ret;
912     }
913   }
914
915   /* Now push buffer into the decoder */
916   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, frame);
917   if (ret != GST_FLOW_OK) {
918     GST_WARNING_OBJECT (self, "Could not push input buffer buffer: %s",
919         gst_flow_get_name (ret));
920     return ret;
921   }
922 #ifdef USE_DTS_PTS_CODE
923   if (ts != GST_CLOCK_TIME_NONE) {
924     self->dts_queue[self->dts_widx++ % NDTS] = ts;
925     /* if next buffer has earlier ts than previous, then the ts
926      * we are getting are definitely decode order (DTS):
927      */
928     if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
929       GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
930       self->ts_may_be_pts = FALSE;
931     }
932     self->last_dts = ts;
933   }
934 #endif
935
936   if (self->in_size == 0 && frame->output_buffer) {
937     GST_DEBUG_OBJECT (self, "no input, skipping process");
938
939     return gst_video_decoder_drop_frame (decoder, frame);
940   }
941
942   self->inArgs->numBytes = self->in_size;
943   self->inBufs->descs[0].bufSize.bytes = self->in_size;
944   self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
945
946   err = codec_process (self, TRUE, FALSE, &ret);
947   if (err) {
948     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
949         ("process returned error: %d %08x", err, self->outArgs->extendedError));
950     gst_ducati_log_extended_error_info (self->outArgs->extendedError,
951         self->error_strings);
952
953     return GST_FLOW_ERROR;
954   }
955
956   if (ret != GST_FLOW_OK) {
957     GST_WARNING_OBJECT (self, "push from codec_process failed %s",
958         gst_flow_get_name (ret));
959
960     /* codec_proccess failed, skip current data */
961     self->in_size = 0;
962     return ret;
963   }
964
965   self->first_in_buffer = FALSE;
966
967   if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
968     /* FIXME GstVideoDecoder Do we still need to support other modes ?? */
969
970     /* The copy could be avoided by playing with the buffer pointer,
971        but it seems to be rare and for not many bytes */
972     GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
973         self->outArgs->bytesConsumed, self->in_size,
974         self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
975     if (self->outArgs->bytesConsumed > 0) {
976       if (self->outArgs->bytesConsumed > self->in_size) {
977         GST_WARNING_OBJECT (self,
978             "Codec claims to have used more bytes than supplied");
979         self->in_size = 0;
980       } else {
981         if (self->outArgs->bytesConsumed < self->in_size) {
982           memmove (self->input, self->input + self->outArgs->bytesConsumed,
983               self->in_size - self->outArgs->bytesConsumed);
984         }
985         self->in_size -= self->outArgs->bytesConsumed;
986       }
987     }
988   } else {
989     self->in_size = 0;
990   }
991
992   if (self->outArgs->outBufsInUseFlag) {
993     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
994     self->need_out_buf = FALSE;
995   } else {
996     self->need_out_buf = TRUE;
997   }
998
999   /* FIXME GstVideoDecoder: What should be done Here?
1000      if (self->needs_flushing)
1001      gst_video_decoder_reset (self, FALSE, FALSE);
1002    */
1003
1004   return GST_FLOW_OK;
1005 }
1006
1007 static gboolean
1008 ducati_dec_reset (GstVideoDecoder * decoder, gboolean hard)
1009 {
1010   GstDucatiVidDec *self = GST_DUCATIVIDDEC (decoder);
1011
1012   /* FIXME GstVideoDecoder what should be done about *hard* ? */
1013   return gst_ducati_viddec_codec_flush (self, hard, FALSE);
1014 }
1015
1016 static GstFlowReturn
1017 ducati_dec_finish (GstVideoDecoder * decoder)
1018 {
1019   return gst_ducati_viddec_codec_flush (GST_DUCATIVIDDEC (decoder), FALSE,
1020       TRUE);
1021 }
1022
1023 static gboolean
1024 ducati_dec_stop (GstVideoDecoder * decoder)
1025 {
1026   GstDucatiVidDec *self = GST_DUCATIVIDDEC (decoder);
1027
1028   self->interlaced = FALSE;
1029   self->send_crop_event = TRUE;
1030
1031   /* VideoDecoder calls self->reset(hard) here */
1032
1033   return TRUE;
1034 }
1035
1036 static gboolean
1037 ducati_dec_close (GstVideoDecoder * decoder)
1038 {
1039   GstDucatiVidDec *self = GST_DUCATIVIDDEC (decoder);
1040
1041   codec_delete (self);
1042   engine_close (self);
1043
1044   return TRUE;
1045 }
1046
1047 /* GObject vmethod implementations */
1048
1049 #define VERSION_LENGTH 256
1050
1051 static void
1052 gst_ducati_viddec_get_property (GObject * obj,
1053     guint prop_id, GValue * value, GParamSpec * pspec)
1054 {
1055   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1056
1057
1058   switch (prop_id) {
1059     case PROP_VERSION:{
1060       int err;
1061       char *version = NULL;
1062
1063       if (!self->engine)
1064         engine_open (self);
1065
1066       if (!self->codec)
1067         codec_create (self);
1068
1069       if (self->codec) {
1070         version = dce_alloc (VERSION_LENGTH);
1071         self->status->data.buf = (XDAS_Int8 *) version;
1072         self->status->data.bufSize = VERSION_LENGTH;
1073
1074         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1075             self->dynParams, self->status);
1076         if (err) {
1077           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1078         }
1079
1080         self->status->data.buf = NULL;
1081         self->status->data.bufSize = 0;
1082       }
1083
1084       g_value_set_string (value, version);
1085       if (version)
1086         dce_free (version);
1087
1088       break;
1089     }
1090     case PROP_CODEC_DEBUG_INFO:
1091       g_value_set_boolean (value, self->codec_debug_info);
1092       break;
1093     default:{
1094       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1095       break;
1096     }
1097   }
1098 }
1099
1100 static void
1101 gst_ducati_viddec_set_property (GObject * obj,
1102     guint prop_id, const GValue * value, GParamSpec * pspec)
1103 {
1104   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1105
1106   switch (prop_id) {
1107     case PROP_CODEC_DEBUG_INFO:
1108       self->codec_debug_info = g_value_get_boolean (value);
1109       break;
1110     default:{
1111       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1112       break;
1113     }
1114   }
1115 }
1116
1117 static void
1118 gst_ducati_viddec_finalize (GObject * obj)
1119 {
1120   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1121
1122   codec_delete (self);
1123   engine_close (self);
1124
1125   /* Will unref the remaining buffers if needed */
1126   g_hash_table_unref (self->passed_in_bufs);
1127   if (self->input_state) {
1128     gst_video_codec_state_unref (self->input_state);
1129     self->input_state = NULL;
1130   }
1131
1132   G_OBJECT_CLASS (parent_class)->finalize (obj);
1133 }
1134
1135 static void
1136 gst_ducati_viddec_base_init (gpointer gclass)
1137 {
1138   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1139
1140   gst_element_class_add_pad_template (element_class,
1141       gst_static_pad_template_get (&src_factory));
1142 }
1143
1144 static void
1145 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1146 {
1147   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1148   /*GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); */
1149   GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
1150
1151   gobject_class->get_property =
1152       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1153   gobject_class->set_property =
1154       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1155   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1156   /* FIXME GstVideoDecoder: Handled by baseclass?
1157    * gstelement_class->change_state =
1158    *  GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state); */
1159
1160   video_decoder_class->open = GST_DEBUG_FUNCPTR (ducati_dec_open);
1161   video_decoder_class->set_format = GST_DEBUG_FUNCPTR (ducati_dec_set_format);
1162   video_decoder_class->handle_frame =
1163       GST_DEBUG_FUNCPTR (ducati_dec_handle_frame);
1164   video_decoder_class->reset = GST_DEBUG_FUNCPTR (ducati_dec_reset);
1165   video_decoder_class->finish = GST_DEBUG_FUNCPTR (ducati_dec_finish);
1166   video_decoder_class->stop = GST_DEBUG_FUNCPTR (ducati_dec_stop);
1167   video_decoder_class->close = GST_DEBUG_FUNCPTR (ducati_dec_close);
1168
1169   klass->allocate_params =
1170       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1171   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1172   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1173
1174   g_object_class_install_property (gobject_class, PROP_VERSION,
1175       g_param_spec_string ("version", "Version",
1176           "The codec version string", "",
1177           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1178   g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1179       g_param_spec_boolean ("codec-debug-info",
1180           "Gather debug info from the codec",
1181           "Gather and log relevant debug information from the codec. "
1182           "What is gathered is typically codec specific", FALSE,
1183           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1184 }
1185
1186 static void
1187 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1188 {
1189   /* sane defaults in case we need to  create codec without caps negotiation
1190    * (for example, to get 'version' property)
1191    */
1192   self->width = 128;
1193   self->height = 128;
1194
1195   self->first_in_buffer = TRUE;
1196   self->first_out_buffer = TRUE;
1197   self->send_crop_event = TRUE;
1198
1199 #ifdef USE_DTS_PTS_CODE
1200   self->dts_ridx = self->dts_widx = 0;
1201   self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1202   self->ts_may_be_pts = TRUE;
1203   self->ts_is_pts = FALSE;
1204 #endif
1205
1206   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1207
1208   self->wait_keyframe = TRUE;
1209   self->need_out_buf = TRUE;
1210   self->device = NULL;
1211   self->input_bo = NULL;
1212
1213   self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1214       NULL, (GDestroyNotify) gst_video_codec_frame_unref);
1215 }