]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducatividdec.c
ducatividdec: some minor trace cleanups
[glsdk/gst-plugin-ducati.git] / src / gstducatividdec.c
1 /*
2  * GStreamer
3  * Copyright (c) 2010, Texas Instruments Incorporated
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation
8  * version 2.1 of the License.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
24 #include "gstducatividdec.h"
26 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
27     GST_TYPE_ELEMENT);
29 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
30     GST_PAD_SRC,
31     GST_PAD_ALWAYS,
32     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV_STRIDED ("NV12", "[ 0, max ]"))
33     );
35 enum
36 {
37   PROP_0,
38   PROP_VERSION,
39 };
41 /* helper functions */
43 static void
44 engine_close (GstDucatiVidDec * self)
45 {
46   if (self->engine) {
47     Engine_close (self->engine);
48     self->engine = NULL;
49   }
51   if (self->params) {
52     dce_free (self->params);
53     self->params = NULL;
54   }
56   if (self->dynParams) {
57     dce_free (self->dynParams);
58     self->dynParams = NULL;
59   }
61   if (self->status) {
62     dce_free (self->status);
63     self->status = NULL;
64   }
66   if (self->inBufs) {
67     dce_free (self->inBufs);
68     self->inBufs = NULL;
69   }
71   if (self->outBufs) {
72     dce_free (self->outBufs);
73     self->outBufs = NULL;
74   }
76   if (self->inArgs) {
77     dce_free (self->inArgs);
78     self->inArgs = NULL;
79   }
81   if (self->outArgs) {
82     dce_free (self->outArgs);
83     self->outArgs = NULL;
84   }
85 }
87 static gboolean
88 engine_open (GstDucatiVidDec * self)
89 {
90   gboolean ret;
92   if (G_UNLIKELY (self->engine)) {
93     return TRUE;
94   }
96   GST_DEBUG_OBJECT (self, "opening engine");
98   self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, NULL);
99   if (G_UNLIKELY (!self->engine)) {
100     GST_ERROR_OBJECT (self, "could not create engine");
101     return FALSE;
102   }
104   ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
105       sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
106       sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
107       sizeof (IVIDDEC3_OutArgs));
109   return ret;
112 static void
113 codec_delete (GstDucatiVidDec * self)
115   if (self->pool) {
116     gst_ducati_bufferpool_destroy (self->pool);
117     self->pool = NULL;
118   }
120   if (self->codec) {
121     VIDDEC3_delete (self->codec);
122     self->codec = NULL;
123   }
125   if (self->input) {
126     MemMgr_Free (self->input);
127     self->input = NULL;
128   }
131 static gboolean
132 codec_create (GstDucatiVidDec * self)
134   gint err;
135   const gchar *codec_name;
137   codec_delete (self);
139   if (G_UNLIKELY (!self->engine)) {
140     GST_ERROR_OBJECT (self, "no engine");
141     return FALSE;
142   }
144   /* these need to be set before VIDDEC3_create */
145   self->params->maxWidth = self->width;
146   self->params->maxHeight = self->height;
148   codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
150   /* create codec: */
151   GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
152   self->codec =
153       VIDDEC3_create (self->engine, (String) codec_name, self->params);
155   if (!self->codec) {
156     return FALSE;
157   }
159   err =
160       VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
161       self->status);
162   if (err) {
163     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
164     return FALSE;
165   }
167   self->first_in_buffer = TRUE;
168   self->first_out_buffer = TRUE;
170   /* allocate input buffer and initialize inBufs: */
171   self->inBufs->numBufs = 1;
172   self->input = gst_ducati_alloc_1d (self->width * self->height);
173   self->inBufs->descs[0].buf = (XDAS_Int8 *) TilerMem_VirtToPhys (self->input);
174   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
176   return TRUE;
179 static inline GstBuffer *
180 codec_bufferpool_get (GstDucatiVidDec * self, GstBuffer * buf)
182   if (G_UNLIKELY (!self->pool)) {
183     guint size;
185     size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
186         self->padded_width, self->padded_height);
187     GST_DEBUG_OBJECT (self, "creating bufferpool");
188     self->pool = gst_ducati_bufferpool_new (GST_ELEMENT (self),
189         GST_PAD_CAPS (self->srcpad), size);
190   }
191   return GST_BUFFER (gst_ducati_bufferpool_get (self->pool, buf));
194 static XDAS_Int32
195 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf)
197   XDAS_Int16 y_type, uv_type;
198   guint8 *y_vaddr, *uv_vaddr;
199   SSPtr y_paddr, uv_paddr;
201   y_vaddr = GST_BUFFER_DATA (*buf);
202   uv_vaddr = y_vaddr + self->stride * self->padded_height;
204   y_paddr = TilerMem_VirtToPhys (y_vaddr);
205   uv_paddr = TilerMem_VirtToPhys (uv_vaddr);
207   y_type = gst_ducati_get_mem_type (y_paddr);
208   uv_type = gst_ducati_get_mem_type (uv_paddr);
209   /* FIXME: workaround for the vc1 codec expecting _RAW when it's actually
210    * _TILEDPAGE... should be removed once the codec is fixed  */
211   if (y_type == XDM_MEMTYPE_TILEDPAGE && self->pageMemType != y_type)
212     y_type = self->pageMemType;
213   if (uv_type == XDM_MEMTYPE_TILEDPAGE && self->pageMemType != uv_type)
214     uv_type = self->pageMemType;
216   if (y_type < 0 || uv_type < 0) {
217     GST_DEBUG_OBJECT (self, "non TILER buffer, fallback to bufferpool");
218     *buf = codec_bufferpool_get (self, *buf);
219     return codec_prepare_outbuf (self, buf);
220   }
222   if (!self->outBufs->numBufs) {
223     /* initialize output buffer type */
224     self->outBufs->numBufs = 2;
225     self->outBufs->descs[0].memType = y_type;
226     self->outBufs->descs[1].memType = uv_type;
227     if (y_type == XDM_MEMTYPE_RAW || y_type == XDM_MEMTYPE_TILEDPAGE) {
228       self->outBufs->descs[0].bufSize.bytes =
229           self->stride * self->padded_height;
230       self->outBufs->descs[1].bufSize.bytes =
231           self->stride * self->padded_height / 2;
232     } else {
233       self->outBufs->descs[0].bufSize.tileMem.width = self->padded_width;
234       self->outBufs->descs[0].bufSize.tileMem.height = self->padded_height;
235       /* note that UV interleaved width is same a Y: */
236       self->outBufs->descs[1].bufSize.tileMem.width = self->padded_width;
237       self->outBufs->descs[1].bufSize.tileMem.height = self->padded_height / 2;
238     }
239   } else {
240     /* verify output buffer type matches what we've already given
241      * to the codec
242      */
243     if ((self->outBufs->descs[0].memType != y_type) ||
244         (self->outBufs->descs[1].memType != uv_type)) {
245       GST_DEBUG_OBJECT (self, "buffer mismatch, fallback to bufferpool");
246       *buf = codec_bufferpool_get (self, *buf);
247       return codec_prepare_outbuf (self, buf);
248     }
249   }
251   self->outBufs->descs[0].buf = (XDAS_Int8 *) y_paddr;
252   self->outBufs->descs[1].buf = (XDAS_Int8 *) uv_paddr;
254   return (XDAS_Int32) *buf;      // XXX use lookup table
257 static GstBuffer *
258 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
260   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
261   if (buf) {
262     gst_buffer_ref (buf);
263   }
264   return buf;
267 static void
268 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
270   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
271   if (buf) {
272     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
273     gst_buffer_unref (buf);
274   }
277 static gint
278 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush)
280   gint err;
281   GstClockTime t;
282   GstBuffer *outbuf = NULL;
283   gint i;
284   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
286   memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
287   memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
289   t = gst_util_get_timestamp ();
290   err = VIDDEC3_process (self->codec,
291       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
292   GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
294   if (err) {
295     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
296         err, self->outArgs->extendedError);
298     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
299         self->dynParams, self->status);
300     if (!err) {
301       GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
302           err, self->status->extendedError);
303     }
305     if (flush)
306       err = XDM_EFAIL;
307     else
308       err = klass->handle_error (self, err,
309           self->outArgs->extendedError, self->status->extendedError);
310   }
312   for (i = 0; self->outArgs->outputID[i]; i++) {
313     if (G_UNLIKELY (self->first_out_buffer) && send) {
314       gint crop_width, crop_height;
316       /* send region of interest to sink on first buffer: */
317       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
319       crop_width = r->bottomRight.x - r->topLeft.x;
320       crop_height = r->bottomRight.y - r->topLeft.y;
322       if (crop_width > self->input_width)
323         crop_width = self->input_width;
324       if (crop_height > self->input_height)
325         crop_height = self->input_height;
327       GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
328           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
329           crop_width, crop_height);
331       gst_pad_push_event (self->srcpad,
332           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
333               crop_width, crop_height));
335       self->first_out_buffer = FALSE;
336     }
338     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
339     if (send) {
340       if (GST_IS_DUCATIBUFFER (outbuf)) {
341         outbuf = gst_ducati_buffer_get (GST_DUCATIBUFFER (outbuf));
342       }
343       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
344           i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
346       if (self->ts_is_pts) {
347         /* if we have a queued DTS from demuxer, use that instead: */
348         if (self->dts_ridx != self->dts_widx) {
349           GST_BUFFER_TIMESTAMP (outbuf) =
350               self->dts_queue[self->dts_ridx++ % NDTS];
351           GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
352               i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
353         }
354       }
356       gst_pad_push (self->srcpad, outbuf);
357     } else {
358       GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
359       gst_buffer_unref (outbuf);
360     }
361   }
363   for (i = 0; self->outArgs->freeBufID[i]; i++) {
364     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
365   }
367   return err;
370 /** call control(FLUSH), and then process() to pop out all buffers */
371 static gboolean
372 codec_flush (GstDucatiVidDec * self, gboolean eos)
374   gint err;
376   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
378   /* note: flush is synchronized against _chain() to avoid calling
379    * the codec from multiple threads
380    */
381   GST_PAD_STREAM_LOCK (self->sinkpad);
383   self->dts_ridx = self->dts_widx = 0;
385   if (G_UNLIKELY (self->first_in_buffer)) {
386     return TRUE;
387   }
389   if (G_UNLIKELY (!self->codec)) {
390     GST_WARNING_OBJECT (self, "no codec");
391     return TRUE;
392   }
394   err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
395   if (err) {
396     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
397     goto out;
398   }
400   self->inBufs->descs[0].bufSize.bytes = 0;
401   self->inArgs->numBytes = 0;
402   self->inArgs->inputID = 0;
404   do {
405     err = codec_process (self, eos, TRUE);
406   } while (err != XDM_EFAIL);
408   /* on a flush, it is normal (and not an error) for the last _process() call
409    * to return an error..
410    */
411   err = XDM_EOK;
413 out:
414   GST_PAD_STREAM_UNLOCK (self->sinkpad);
415   GST_DEBUG_OBJECT (self, "done");
417   return !err;
420 /* GstDucatiVidDec vmethod default implementations */
422 static gboolean
423 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
425   const GValue *codec_data;
426   gint w, h;
428   if (gst_structure_get_int (s, "width", &self->input_width) &&
429       gst_structure_get_int (s, "height", &self->input_height)) {
431     h = ALIGN2 (self->input_height, 4); /* round up to MB */
432     w = ALIGN2 (self->input_width, 4);  /* round up to MB */
434     /* if we've already created codec, but the resolution has changed, we
435      * need to re-create the codec:
436      */
437     if (G_UNLIKELY (self->codec)) {
438       if ((h != self->height) || (w != self->width)) {
439         codec_delete (self);
440       }
441     }
443     self->width = w;
444     self->height = h;
446     codec_data = gst_structure_get_value (s, "codec_data");
448     if (codec_data) {
449       GstBuffer *buffer = gst_value_get_buffer (codec_data);
450       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
451       self->codec_data = gst_buffer_ref (buffer);
452     }
454     return TRUE;
455   }
457   return FALSE;
460 static gboolean
461 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
462     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
465   /* allocate params: */
466   self->params = dce_alloc (params_sz);
467   if (G_UNLIKELY (!self->params)) {
468     return FALSE;
469   }
470   self->params->size = params_sz;
471   self->params->maxFrameRate = 30000;
472   self->params->maxBitRate = 10000000;
474   self->params->dataEndianness = XDM_BYTE;
475   self->params->forceChromaFormat = XDM_YUV_420SP;
476   self->params->operatingMode = IVIDEO_DECODE_ONLY;
478   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
479   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
480   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
481   self->params->numInputDataUnits = 0;
482   self->params->numOutputDataUnits = 0;
484   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
485   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
486   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
487   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
489   /* allocate dynParams: */
490   self->dynParams = dce_alloc (dynparams_sz);
491   if (G_UNLIKELY (!self->dynParams)) {
492     return FALSE;
493   }
494   self->dynParams->size = dynparams_sz;
495   self->dynParams->decodeHeader = XDM_DECODE_AU;
496   self->dynParams->displayWidth = 0;
497   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
498   self->dynParams->newFrameFlag = XDAS_TRUE;
500   /* allocate status: */
501   self->status = dce_alloc (status_sz);
502   if (G_UNLIKELY (!self->status)) {
503     return FALSE;
504   }
505   self->status->size = status_sz;
507   /* allocate inBufs/outBufs: */
508   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
509   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
510   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
511     return FALSE;
512   }
514   /* allocate inArgs/outArgs: */
515   self->inArgs = dce_alloc (inargs_sz);
516   self->outArgs = dce_alloc (outargs_sz);
517   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
518     return FALSE;
519   }
520   self->inArgs->size = inargs_sz;
521   self->outArgs->size = outargs_sz;
523   return TRUE;
526 static GstBuffer *
527 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
529   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
530     push_input (self, GST_BUFFER_DATA (self->codec_data),
531         GST_BUFFER_SIZE (self->codec_data));
532   }
534   /* just copy entire buffer */
535   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
536   gst_buffer_unref (buf);
538   return NULL;
541 static gint
542 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
543     gint extended_error, gint status_extended_error)
545   if (XDM_ISFATALERROR (extended_error))
546     ret = XDM_EFAIL;
547   else
548     ret = XDM_EOK;
550   return ret;
553 /* GstElement vmethod implementations */
555 static gboolean
556 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
558   gboolean ret = TRUE;
559   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
560   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
561   GstStructure *s;
562   GstCaps *outcaps = NULL;
563   GstStructure *out_s;
564   gboolean interlaced = FALSE;
565   gint frn = 0, frd = 1;
566   gint par_width, par_height;
567   gboolean par_present;
569   GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
571   s = gst_caps_get_structure (caps, 0);
572   if (!klass->parse_caps (self, s)) {
573     GST_WARNING_OBJECT (self, "missing required fields");
574     ret = FALSE;
575     goto out;
576   }
578   /* update output/padded sizes */
579   klass->update_buffer_size (self);
581   gst_structure_get_fraction (s, "framerate", &frn, &frd);
582   gst_structure_get_boolean (s, "interlaced", &interlaced);
583   par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
584       &par_width, &par_height);
586   outcaps = gst_pad_get_allowed_caps (self->srcpad);
587   if (outcaps) {
588     outcaps = gst_caps_make_writable (outcaps);
589     gst_caps_truncate (outcaps);
590     if (gst_caps_is_empty (outcaps)) {
591       gst_caps_unref (outcaps);
592       outcaps = NULL;
593     }
594   }
596   if (!outcaps) {
597     /* note: default to non-strided for better compatibility with
598      * other gst elements that don't understand stride:
599      */
600     outcaps = gst_caps_new_simple ("video/x-raw-yuv",
601         "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
602   }
604   out_s = gst_caps_get_structure (outcaps, 0);
605   gst_structure_set (out_s,
606       "width", G_TYPE_INT, self->padded_width,
607       "height", G_TYPE_INT, self->padded_height,
608       "framerate", GST_TYPE_FRACTION, frn, frd, NULL);
609   if (par_present)
610     gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
611         par_width, par_height, NULL);
613   if (interlaced)
614     gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
616   if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
617     if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
618       self->stride = 4096;
619       gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
620     }
621   } else {
622     self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
623         0, self->padded_width);
624   }
626   self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
627       self->stride, self->padded_height);
629   GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
630       self->outsize, self->stride, outcaps);
632   ret = gst_pad_set_caps (self->srcpad, outcaps);
634 out:
635   if (outcaps)
636     gst_caps_unref (outcaps);
637   gst_object_unref (self);
639   return ret;
642 static gboolean
643 gst_ducati_viddec_query (GstPad * pad, GstQuery * query)
645   gboolean res = TRUE, forward = TRUE;
646   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
648   GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
650   switch (GST_QUERY_TYPE (query)) {
651     case GST_QUERY_BUFFERS:
652       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
653       gst_query_set_buffers_count (query, self->min_buffers);
655       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
656           self->padded_width, self->padded_height);
657       gst_query_set_buffers_dimensions (query,
658           self->padded_width, self->padded_height);
659       forward = FALSE;
660       break;
661     default:
662       break;
663   }
665   if (forward)
666     res = gst_pad_query_default (pad, query);
668   return res;
671 static gboolean
672 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
674   GstClockTime timestamp, qostime;
675   gint64 diff;
676   gboolean is_keyframe;
678   timestamp = GST_BUFFER_TIMESTAMP (buf);
679   if (self->segment.format != GST_FORMAT_TIME ||
680       self->qos_earliest_time == GST_CLOCK_TIME_NONE)
681     goto no_qos;
683   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
684     goto no_qos;
686   qostime = gst_segment_to_running_time (&self->segment,
687       GST_FORMAT_TIME, timestamp);
688   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
689     /* out of segment */
690     goto no_qos;
692   is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
694   /* see how our next timestamp relates to the latest qos timestamp. negative
695    * values mean we are early, positive values mean we are too late. */
696   diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
698   GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
699       ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
700       GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
701       self->qos_proportion);
703   if (diff >= 0 && !is_keyframe)
704     return FALSE;
706 no_qos:
707   return TRUE;
710 static GstFlowReturn
711 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
713   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
714   GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
715   GstFlowReturn ret;
716   Int32 err;
717   GstBuffer *outbuf = NULL;
718   GstCaps *outcaps = NULL;
719   gboolean decode;
721   if (G_UNLIKELY (!self->engine)) {
722     GST_ERROR_OBJECT (self, "no engine");
723     return GST_FLOW_ERROR;
724   }
726   GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes)",
727       GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf));
729   decode = gst_ducati_viddec_do_qos (self, buf);
730   if (!decode) {
731     gst_buffer_unref (buf);
732     return GST_FLOW_OK;
733   }
735   if (!self->need_out_buf)
736     goto have_out_buf;
738   /* do this before creating codec to ensure reverse caps negotiation
739    * happens first:
740    */
741 allocate_buffer:
742   ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
743       GST_PAD_CAPS (self->srcpad), &outbuf);
744   if (ret != GST_FLOW_OK) {
745     GST_ERROR_OBJECT (self, "alloc_buffer failed %s", gst_flow_get_name (ret));
746     return ret;
747   }
749   outcaps = GST_BUFFER_CAPS (outbuf);
750   if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
751     GstStructure *s;
753     GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
754         GST_BUFFER_SIZE (outbuf));
756     s = gst_caps_get_structure (outcaps, 0);
757     gst_structure_get_int (s, "rowstride", &self->stride);
758     self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
759         self->stride, self->padded_height);
761     GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
762         self->outsize, self->stride, outcaps);
764     gst_pad_set_caps (self->srcpad, outcaps);
766     if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
767       GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
768           GST_BUFFER_SIZE (outbuf), self->outsize);
769       gst_buffer_unref (outbuf);
770       goto allocate_buffer;
771     }
772   }
774   if (G_UNLIKELY (!self->codec)) {
775     if (!codec_create (self)) {
776       GST_ERROR_OBJECT (self, "could not create codec");
777       return GST_FLOW_ERROR;
778     }
779   }
781   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
782   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
784   /* pass new output buffer as to the decoder to decode into: */
785   self->inArgs->inputID = codec_prepare_outbuf (self, &outbuf);
786   if (!self->inArgs->inputID) {
787     GST_ERROR_OBJECT (self, "could not prepare output buffer");
788     return GST_FLOW_ERROR;
789   }
791 have_out_buf:
792   self->in_size = 0;
793   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
795   if (self->ts_is_pts && (ts != GST_CLOCK_TIME_NONE)) {
796     self->duration = GST_BUFFER_DURATION (outbuf);
797     self->dts_queue[self->dts_widx++ % NDTS] = ts;
798   }
800   if (self->in_size == 0) {
801     GST_DEBUG_OBJECT (self, "no input, skipping process");
802     gst_buffer_unref (outbuf);
803     return GST_FLOW_OK;
804   }
806   self->inArgs->numBytes = self->in_size;
807   self->inBufs->descs[0].bufSize.bytes = self->in_size;
809   err = codec_process (self, TRUE, FALSE);
810   if (err) {
811     GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
812         ("process returned error: %d %08x", err, self->outArgs->extendedError));
813     return GST_FLOW_ERROR;
814   }
816   self->first_in_buffer = FALSE;
818   if (self->outArgs->outBufsInUseFlag) {
819     GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
820     self->need_out_buf = FALSE;
821   } else {
822     self->need_out_buf = TRUE;
823   }
825   if (buf) {
826     GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
827         GST_BUFFER_SIZE (buf));
828     ts = GST_BUFFER_TIMESTAMP (buf);
829     goto allocate_buffer;
830   }
832   return GST_FLOW_OK;
835 static gboolean
836 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
838   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
839   gboolean ret = TRUE;
841   GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
843   switch (GST_EVENT_TYPE (event)) {
844     case GST_EVENT_NEWSEGMENT:
845     {
846       gboolean update;
847       GstFormat fmt;
848       gint64 start, stop, time;
849       gdouble rate, arate;
851       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
852           &start, &stop, &time);
853       gst_segment_set_newsegment_full (&self->segment, update,
854           rate, arate, fmt, start, stop, time);
855       break;
856     }
857     case GST_EVENT_EOS:
858       if (!codec_flush (self, TRUE)) {
859         GST_ERROR_OBJECT (self, "could not flush on eos");
860         ret = FALSE;
861       }
862       break;
863     case GST_EVENT_FLUSH_STOP:
864       if (!codec_flush (self, FALSE)) {
865         GST_ERROR_OBJECT (self, "could not flush");
866         ret = FALSE;
867       }
868       gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
869       self->qos_earliest_time = GST_CLOCK_TIME_NONE;
870       self->qos_proportion = 1;
871       self->need_out_buf = TRUE;
872       break;
873     default:
874       break;
875   }
877   if (ret)
878     ret = gst_pad_push_event (self->srcpad, event);
879   GST_LOG_OBJECT (self, "end");
881   return ret;
884 static gboolean
885 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
887   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
888   gboolean ret = TRUE;
890   GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
892   switch (GST_EVENT_TYPE (event)) {
893     case GST_EVENT_QOS:
894     {
895       gdouble proportion;
896       GstClockTimeDiff diff;
897       GstClockTime timestamp;
899       gst_event_parse_qos (event, &proportion, &diff, &timestamp);
901       GST_OBJECT_LOCK (self);
902       self->qos_proportion = proportion;
903       self->qos_earliest_time = timestamp + 2 * diff;
904       GST_OBJECT_UNLOCK (self);
906       GST_DEBUG_OBJECT (self,
907           "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
908           proportion, GST_TIME_ARGS (timestamp), diff);
910       ret = gst_pad_push_event (self->sinkpad, event);
911       break;
912     }
913     default:
914       ret = gst_pad_push_event (self->sinkpad, event);
915       break;
916   }
918   GST_LOG_OBJECT (self, "end");
920   return ret;
923 static GstStateChangeReturn
924 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
926   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
927   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
929   GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
930       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
931       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
933   switch (transition) {
934     case GST_STATE_CHANGE_NULL_TO_READY:
935       if (!engine_open (self)) {
936         GST_ERROR_OBJECT (self, "could not open");
937         return GST_STATE_CHANGE_FAILURE;
938       }
939       break;
940     default:
941       break;
942   }
944   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
946   if (ret == GST_STATE_CHANGE_FAILURE)
947     goto leave;
949   switch (transition) {
950     case GST_STATE_CHANGE_READY_TO_NULL:
951       codec_delete (self);
952       engine_close (self);
953       break;
954     default:
955       break;
956   }
958 leave:
959   GST_LOG_OBJECT (self, "end");
961   return ret;
964 /* GObject vmethod implementations */
966 #define VERSION_LENGTH 256
968 static void
969 gst_ducati_viddec_get_property (GObject * obj,
970     guint prop_id, GValue * value, GParamSpec * pspec)
972   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
974   switch (prop_id) {
975     case PROP_VERSION:{
976       int err;
977       char *version = gst_ducati_alloc_1d (VERSION_LENGTH);
979       /* in case something fails: */
980       snprintf (version, VERSION_LENGTH, "unsupported");
982       if (!self->engine)
983         engine_open (self);
985       if (!self->codec)
986         codec_create (self);
988       if (self->codec) {
989         self->status->data.buf = (XDAS_Int8 *) TilerMem_VirtToPhys (version);
990         self->status->data.bufSize = VERSION_LENGTH;
992         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
993             self->dynParams, self->status);
994         if (err) {
995           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
996         }
998         self->status->data.buf = NULL;
999         self->status->data.bufSize = 0;
1000       }
1002       g_value_set_string (value, version);
1004       MemMgr_Free (version);
1006       break;
1007     }
1008     default:{
1009       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1010       break;
1011     }
1012   }
1015 static void
1016 gst_ducati_viddec_finalize (GObject * obj)
1018   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1020   codec_delete (self);
1021   engine_close (self);
1023   if (self->codec_data) {
1024     gst_buffer_unref (self->codec_data);
1025     self->codec_data = NULL;
1026   }
1028   G_OBJECT_CLASS (parent_class)->finalize (obj);
1031 static void
1032 gst_ducati_viddec_base_init (gpointer gclass)
1034   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1036   gst_element_class_add_pad_template (element_class,
1037       gst_static_pad_template_get (&src_factory));
1040 static void
1041 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1043   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1044   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1046   gobject_class->get_property =
1047       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1048   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1049   gstelement_class->change_state =
1050       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1052   klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1053   klass->allocate_params =
1054       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1055   klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1056   klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1058   g_object_class_install_property (gobject_class, PROP_VERSION,
1059       g_param_spec_string ("version", "Version",
1060           "The codec version string", "",
1061           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1064 static void
1065 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1067   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1069   self->sinkpad =
1070       gst_pad_new_from_template (gst_element_class_get_pad_template
1071       (gstelement_class, "sink"), "sink");
1072   gst_pad_set_setcaps_function (self->sinkpad,
1073       GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1074   gst_pad_set_chain_function (self->sinkpad,
1075       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1076   gst_pad_set_event_function (self->sinkpad,
1077       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1079   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1080   gst_pad_set_event_function (self->srcpad,
1081       GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1082   gst_pad_set_query_function (self->srcpad,
1083       GST_DEBUG_FUNCPTR (gst_ducati_viddec_query));
1085   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1086   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1088   self->input_width = 0;
1089   self->input_height = 0;
1090   /* sane defaults in case we need to create codec without caps negotiation
1091    * (for example, to get 'version' property)
1092    */
1093   self->width = 128;
1094   self->height = 128;
1096   self->first_in_buffer = TRUE;
1097   self->first_out_buffer = TRUE;
1099   self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1101   gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1103   self->qos_proportion = 1;
1104   self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1106   self->need_out_buf = TRUE;