]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugin-ducati.git/blob - src/gstducatividdec.c
viddec: fix typo
[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 ("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 = VIDDEC3_create (self->engine, (char *)codec_name, self->params);
154   if (!self->codec) {
155     return FALSE;
156   }
158   err = VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams, self->status);
159   if (err) {
160     GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
161     return FALSE;
162   }
164   self->first_in_buffer = TRUE;
165   self->first_out_buffer = TRUE;
167   /* allocate input buffer and initialize inBufs: */
168   self->inBufs->numBufs = 1;
169   self->input = gst_ducati_alloc_1d (self->width * self->height);
170   self->inBufs->descs[0].buf = (XDAS_Int8 *) TilerMem_VirtToPhys (self->input);
171   self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
173   return TRUE;
176 static inline GstBuffer *
177 codec_bufferpool_get (GstDucatiVidDec * self, GstBuffer * buf)
179   if (G_UNLIKELY (!self->pool)) {
180     GST_DEBUG_OBJECT (self, "creating bufferpool");
181     self->pool = gst_ducati_bufferpool_new (GST_ELEMENT (self),
182         GST_PAD_CAPS (self->srcpad));
183   }
184   return GST_BUFFER (gst_ducati_bufferpool_get (self->pool, buf));
187 static XDAS_Int32
188 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer * buf)
190   XDAS_Int16 y_type, uv_type;
191   guint8 *y_vaddr, *uv_vaddr;
192   SSPtr y_paddr, uv_paddr;
194   y_vaddr = GST_BUFFER_DATA (buf);
195   uv_vaddr = y_vaddr + self->stride * self->padded_height;
197   y_paddr = TilerMem_VirtToPhys (y_vaddr);
198   uv_paddr = TilerMem_VirtToPhys (uv_vaddr);
200   y_type = gst_ducati_get_mem_type (y_paddr);
201   uv_type = gst_ducati_get_mem_type (uv_paddr);
203   if ((y_type < 0) || (uv_type < 0)) {
204     GST_DEBUG_OBJECT (self, "non TILER buffer, fallback to bufferpool");
205     return codec_prepare_outbuf (self, codec_bufferpool_get (self, buf));
206   }
208   if (!self->outBufs->numBufs) {
209     /* initialize output buffer type */
210     self->outBufs->numBufs = 2;
211     self->outBufs->descs[0].memType = y_type;
212     self->outBufs->descs[0].bufSize.tileMem.width = self->padded_width;
213     self->outBufs->descs[0].bufSize.tileMem.height = self->padded_height;
214     self->outBufs->descs[1].memType = uv_type;
215     /* note that UV interleaved width is same a Y: */
216     self->outBufs->descs[1].bufSize.tileMem.width = self->padded_width;
217     self->outBufs->descs[1].bufSize.tileMem.height = self->padded_height / 2;
218   } else {
219     /* verify output buffer type matches what we've already given
220      * to the codec
221      */
222     if ((self->outBufs->descs[0].memType != y_type) ||
223         (self->outBufs->descs[1].memType != uv_type)) {
224       GST_DEBUG_OBJECT (self, "buffer mismatch, fallback to bufferpool");
225       return codec_prepare_outbuf (self, codec_bufferpool_get (self, buf));
226     }
227   }
229   self->outBufs->descs[0].buf = (XDAS_Int8 *) y_paddr;
230   self->outBufs->descs[1].buf = (XDAS_Int8 *) uv_paddr;
232   return (XDAS_Int32) buf;      // XXX use lookup table
235 static GstBuffer *
236 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
238   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
239   if (buf) {
240     gst_buffer_ref (buf);
241   }
242   return buf;
245 static void
246 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
248   GstBuffer *buf = (GstBuffer *) id;    // XXX use lookup table
249   if (buf) {
250     GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
251     gst_buffer_unref (buf);
252   }
255 static gint
256 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush)
258   gint err;
259   GstClockTime t;
260   GstBuffer *outbuf = NULL;
261   gint i;
263   self->outArgs->outputID[0] = 0;
264   self->outArgs->freeBufID[0] = 0;
266   t = gst_util_get_timestamp ();
267   err = VIDDEC3_process (self->codec,
268       self->inBufs, self->outBufs, self->inArgs, self->outArgs);
269   GST_INFO_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
271   if (err) {
272     GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
273         err, self->outArgs->extendedError);
275     err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
276         self->dynParams, self->status);
278     GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
279         err, self->status->extendedError);
281     if (XDM_ISFATALERROR (self->outArgs->extendedError) || flush) {
282       /* we are processing for display and it is a non-fatal error, so lets
283        * try to recover.. otherwise return the error
284        */
285       err = XDM_EFAIL;
286     }
287   }
289   for (i = 0; self->outArgs->outputID[i]; i++) {
290     if (G_UNLIKELY (self->first_out_buffer) && send) {
291       /* send region of interest to sink on first buffer: */
292       XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
294       GST_DEBUG_OBJECT (self, "setting crop to %d, %d, %d, %d",
295           r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y);
297       gst_pad_push_event (self->srcpad,
298           gst_event_new_crop (r->topLeft.y, r->topLeft.x,
299               r->bottomRight.x - r->topLeft.x,
300               r->bottomRight.y - r->topLeft.y));
302       self->first_out_buffer = FALSE;
303     }
305     outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
306     if (send) {
307       if (GST_IS_DUCATIBUFFER (outbuf)) {
308         outbuf = gst_ducati_buffer_get (GST_DUCATIBUFFER (outbuf));
309       }
310       GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
311           i, outbuf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
312       gst_pad_push (self->srcpad, outbuf);
313     } else {
314       GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
315       gst_buffer_unref (outbuf);
316     }
317   }
319   for (i = 0; self->outArgs->freeBufID[i]; i++) {
320     codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
321   }
323   return err;
326 /** call control(FLUSH), and then process() to pop out all buffers */
327 static gboolean
328 codec_flush (GstDucatiVidDec * self, gboolean eos)
330   gint err;
332   GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
334   /* note: flush is synchronized against _chain() to avoid calling
335    * the codec from multiple threads
336    */
337   GST_PAD_STREAM_LOCK (self->sinkpad);
339   if (G_UNLIKELY (self->first_in_buffer)) {
340     return TRUE;
341   }
343   if (G_UNLIKELY (!self->codec)) {
344     GST_WARNING_OBJECT (self, "no codec");
345     return TRUE;
346   }
348   err = VIDDEC3_control (self->codec, XDM_FLUSH,
349       self->dynParams, self->status);
350   if (err) {
351     GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
352     goto out;
353   }
355   self->inBufs->descs[0].bufSize.bytes = 0;
356   self->inArgs->numBytes = 0;
357   self->inArgs->inputID = 0;
359   do {
360     err = codec_process (self, eos, TRUE);
361   } while (err != XDM_EFAIL);
363   /* on a flush, it is normal (and not an error) for the last _process() call
364    * to return an error..
365    */
366   err = XDM_EOK;
368 out:
369   GST_PAD_STREAM_UNLOCK (self->sinkpad);
370   GST_DEBUG_OBJECT (self, "done");
372   return !err;
375 /* GstDucatiVidDec vmethod default implementations */
377 static gboolean
378 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
380   const GValue *codec_data;
381   gint w, h;
383   if (gst_structure_get_int (s, "width", &w) &&
384       gst_structure_get_int (s, "height", &h)) {
386     h = ALIGN2 (h, 4);                 /* round up to MB */
387     w = ALIGN2 (w, 4);                 /* round up to MB */
389     /* if we've already created codec, but the resolution has changed, we
390      * need to re-create the codec:
391      */
392     if (G_UNLIKELY (self->codec)) {
393       if ((h != self->height) || (w != self->width)) {
394         codec_delete (self);
395       }
396     }
398     self->width  = w;
399     self->height = h;
401     const GValue *codec_data = gst_structure_get_value (s, "codec_data");
403     if (codec_data) {
404       GstBuffer *buffer = gst_value_get_buffer (codec_data);
405       GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
406       self->codec_data = gst_buffer_ref (buffer);
407     }
409     return TRUE;
410   }
412   return FALSE;
415 static gboolean
416 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
417     gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
420   /* allocate params: */
421   self->params = dce_alloc (params_sz);
422   if (G_UNLIKELY (!self->params)) {
423     return FALSE;
424   }
425   self->params->size = params_sz;
426   self->params->maxFrameRate = 30000;
427   self->params->maxBitRate = 10000000;
429   self->params->dataEndianness = XDM_BYTE;
430   self->params->forceChromaFormat = XDM_YUV_420SP;
431   self->params->operatingMode = IVIDEO_DECODE_ONLY;
433   self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
434   self->params->inputDataMode = IVIDEO_ENTIREFRAME;
435   self->params->outputDataMode = IVIDEO_ENTIREFRAME;
436   self->params->numInputDataUnits = 0;
437   self->params->numOutputDataUnits = 0;
439   self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
440   self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
441   self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
442   self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
444   /* allocate dynParams: */
445   self->dynParams = dce_alloc (dynparams_sz);
446   if (G_UNLIKELY (!self->dynParams)) {
447     return FALSE;
448   }
449   self->dynParams->size = dynparams_sz;
450   self->dynParams->decodeHeader = XDM_DECODE_AU;
451   self->dynParams->displayWidth = 0;
452   self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
453   self->dynParams->newFrameFlag = XDAS_TRUE;
455   /* allocate status: */
456   self->status = dce_alloc (status_sz);
457   if (G_UNLIKELY (!self->status)) {
458     return FALSE;
459   }
460   self->status->size = status_sz;
462   /* allocate inBufs/outBufs: */
463   self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
464   self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
465   if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
466     return FALSE;
467   }
469   /* allocate inArgs/outArgs: */
470   self->inArgs = dce_alloc (inargs_sz);
471   self->outArgs = dce_alloc (outargs_sz);
472   if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
473     return FALSE;
474   }
475   self->inArgs->size = inargs_sz;
476   self->outArgs->size = outargs_sz;
479 static GstBuffer *
480 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
482   if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
483     push_input (self, GST_BUFFER_DATA (self->codec_data),
484         GST_BUFFER_SIZE (self->codec_data));
485   }
487   /* just copy entire buffer */
488   push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
489   gst_buffer_unref (buf);
491   return NULL;
494 /* GstElement vmethod implementations */
496 static gboolean
497 gst_ducati_viddec_set_caps (GstPad * pad, GstCaps * caps)
499   gboolean ret = TRUE;
500   GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
501   GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
502   GstStructure *s;
504   g_return_val_if_fail (caps, FALSE);
505   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
507   s = gst_caps_get_structure (caps, 0);
509   if (pad == self->sinkpad) {
510     gint frn = 0, frd = 1;
511     GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
513     if (klass->parse_caps (self, s)) {
514       GstCaps *outcaps;
515       gboolean interlaced = FALSE;
517       gst_structure_get_fraction (s, "framerate", &frn, &frd);
519       self->stride = 4096;      /* TODO: don't hardcode */
521       gst_structure_get_boolean (s, "interlaced", &interlaced);
523       /* update output/padded sizes:
524        */
525       klass->update_buffer_size (self);
527       self->outsize =
528           GST_ROUND_UP_2 (self->stride * self->padded_height * 3) / 2;
530       outcaps = gst_caps_new_simple ("video/x-raw-yuv-strided",
531           "rowstride", G_TYPE_INT, self->stride,
532           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N','V','1','2'),
533           "width", G_TYPE_INT, self->padded_width,
534           "height", G_TYPE_INT, self->padded_height,
535           "framerate", GST_TYPE_FRACTION, frn, frd,
536           NULL);
538       if (interlaced) {
539         gst_caps_set_simple (outcaps, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
540       }
542       GST_DEBUG_OBJECT (self, "outcaps: %" GST_PTR_FORMAT, outcaps);
544       ret = gst_pad_set_caps (self->srcpad, outcaps);
545       gst_caps_unref (outcaps);
547       if (!ret) {
548         GST_WARNING_OBJECT (self, "failed to set caps");
549         return FALSE;
550       }
551     } else {
552       GST_WARNING_OBJECT (self, "missing required fields");
553       return FALSE;
554     }
555   } else {
556     GST_INFO_OBJECT (self, "setcaps (src): %" GST_PTR_FORMAT, caps);
557     // XXX check to make sure caps are ok.. keep track if we
558     // XXX need to handle unstrided buffers..
559     GST_WARNING_OBJECT (self, "TODO");
560   }
562   gst_object_unref (self);
564   return gst_pad_set_caps (pad, caps);
567 static gboolean
568 gst_ducati_viddec_query (GstPad * pad, GstQuery * query)
570   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
572   switch (GST_QUERY_TYPE (query)) {
573     case GST_QUERY_BUFFERS:
574       GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
575       gst_query_set_buffers_count (query, self->min_buffers);
577       GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
578           self->padded_width, self->padded_height);
579       gst_query_set_buffers_dimensions (query,
580           self->padded_width, self->padded_height);
581       return TRUE;
582     default:
583       return FALSE;
584   }
587 static GstFlowReturn
588 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
590   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
591   GstFlowReturn ret;
592   Int32 err;
593   GstBuffer *outbuf = NULL;
595   if (G_UNLIKELY (!self->engine)) {
596     GST_ERROR_OBJECT (self, "no engine");
597     return GST_FLOW_ERROR;
598   }
600   /* do this before creating codec to ensure reverse caps negotiation
601    * happens first:
602    */
603   ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad, 0, self->outsize,
604       GST_PAD_CAPS (self->srcpad), &outbuf);
606   if (ret != GST_FLOW_OK) {
607     outbuf = codec_bufferpool_get (self, NULL);
608     ret = GST_FLOW_OK;
609   }
611   if (G_UNLIKELY (!self->codec)) {
612     if (!codec_create (self)) {
613       GST_ERROR_OBJECT (self, "could not create codec");
614       return GST_FLOW_ERROR;
615     }
616   }
618   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
619   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
621   /* pass new output buffer as to the decoder to decode into: */
622   self->inArgs->inputID = codec_prepare_outbuf (self, outbuf);
623   if (!self->inArgs->inputID) {
624     GST_ERROR_OBJECT (self, "could not prepare output buffer");
625     return GST_FLOW_ERROR;
626   }
628   self->in_size = 0;
629   buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
631   if (self->in_size == 0) {
632     GST_DEBUG_OBJECT (self, "no input, skipping process");
633     gst_buffer_unref (outbuf);
634     return GST_FLOW_OK;
635   }
637   self->inArgs->numBytes = self->in_size;
638   self->inBufs->descs[0].bufSize.bytes = self->in_size;
640   if (buf) {
641     // XXX
642     GST_WARNING_OBJECT (self, "TODO.. can't push more than one.. need loop");
643     gst_buffer_unref (buf);
644     buf = NULL;
645   }
647   err = codec_process (self, TRUE, FALSE);
648   if (err) {
649     GST_ERROR_OBJECT (self, "process returned error: %d %08x",
650         err, self->outArgs->extendedError);
651     return GST_FLOW_ERROR;
652   }
654   self->first_in_buffer = FALSE;
656   if (self->outArgs->outBufsInUseFlag) {
657     GST_WARNING_OBJECT (self, "TODO... outBufsInUseFlag");      // XXX
658   }
660   return GST_FLOW_OK;
663 static gboolean
664 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
666   GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
667   gboolean ret = TRUE;
668   gboolean eos = FALSE;
670   GST_INFO_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
672   switch (GST_EVENT_TYPE (event)) {
673     case GST_EVENT_EOS:
674       eos = TRUE;
675       /* fall-through */
676     case GST_EVENT_FLUSH_STOP:
677       if (!codec_flush (self, eos)) {
678         GST_ERROR_OBJECT (self, "could not flush");
679         return FALSE;
680       }
681       /* fall-through */
682     default:
683       ret = gst_pad_push_event (self->srcpad, event);
684       break;
685   }
687   GST_LOG_OBJECT (self, "end");
689   return ret;
692 static GstStateChangeReturn
693 gst_ducati_viddec_change_state (GstElement * element,
694     GstStateChange transition)
696   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
697   GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
699   GST_INFO_OBJECT (self, "begin: changing state %s -> %s",
700       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
701       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
703   switch (transition) {
704     case GST_STATE_CHANGE_NULL_TO_READY:
705       if (!engine_open (self)) {
706         GST_ERROR_OBJECT (self, "could not open");
707         return GST_STATE_CHANGE_FAILURE;
708       }
709       break;
710     default:
711       break;
712   }
714   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
716   if (ret == GST_STATE_CHANGE_FAILURE)
717     goto leave;
719   switch (transition) {
720     case GST_STATE_CHANGE_READY_TO_NULL:
721       codec_delete (self);
722       engine_close (self);
723       break;
724     default:
725       break;
726   }
728 leave:
729   GST_LOG_OBJECT (self, "end");
731   return ret;
734 /* GObject vmethod implementations */
736 #define VERSION_LENGTH 256
738 static void
739 gst_ducati_viddec_get_property (GObject * obj,
740     guint prop_id, GValue * value, GParamSpec * pspec)
742   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
744   switch (prop_id) {
745     case PROP_VERSION: {
746       int err;
747       char *version = gst_ducati_alloc_1d (VERSION_LENGTH);
749       /* in case something fails: */
750       snprintf (version, VERSION_LENGTH, "unsupported");
752       if (! self->engine)
753         engine_open (self);
755       if (! self->codec)
756         codec_create (self);
758       if (self->codec) {
759         self->status->data.buf = (XDAS_Int8 *) TilerMem_VirtToPhys (version);
760         self->status->data.bufSize = VERSION_LENGTH;
762         err = VIDDEC3_control (self->codec, XDM_GETVERSION,
763             self->dynParams, self->status);
764         if (err) {
765           GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
766         }
768         self->status->data.buf = NULL;
769         self->status->data.bufSize = 0;
770       }
772       g_value_set_string (value, version);
774       MemMgr_Free (version);
776       break;
777     }
778     default: {
779       G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
780       break;
781     }
782   }
785 static void
786 gst_ducati_viddec_finalize (GObject * obj)
788   GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
790   codec_delete (self);
791   engine_close (self);
793   if (self->codec_data) {
794       gst_buffer_unref (self->codec_data);
795       self->codec_data = NULL;
796   }
798   G_OBJECT_CLASS (parent_class)->finalize (obj);
801 static void
802 gst_ducati_viddec_base_init (gpointer gclass)
804   GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
806   gst_element_class_add_pad_template (element_class,
807       gst_static_pad_template_get (&src_factory));
810 static void
811 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
813   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
814   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
816   gobject_class->get_property =
817       GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
818   gobject_class->finalize =
819       GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
820   gstelement_class->change_state =
821       GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
823   klass->parse_caps =
824       GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
825   klass->allocate_params =
826       GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
827   klass->push_input =
828       GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
830   g_object_class_install_property (gobject_class, PROP_VERSION,
831       g_param_spec_string ("version", "Version",
832           "The codec version string", "",
833           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
836 static void
837 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
839   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
841   self->sinkpad = gst_pad_new_from_template (
842       gst_element_class_get_pad_template (gstelement_class, "sink"), "sink");
843   gst_pad_set_setcaps_function (self->sinkpad,
844       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_caps));
845   gst_pad_set_chain_function (self->sinkpad,
846       GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
847   gst_pad_set_event_function (self->sinkpad,
848       GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
850   self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
851   gst_pad_set_setcaps_function (self->srcpad,
852       GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_caps));
853   gst_pad_set_query_function (self->srcpad,
854           GST_DEBUG_FUNCPTR (gst_ducati_viddec_query));
856   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
857   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
859   /* sane defaults in case we need to create codec without caps negotiation
860    * (for example, to get 'version' property)
861    */
862   self->width = 128;
863   self->height = 128;