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;
110 }
112 static void
113 codec_delete (GstDucatiVidDec * self)
114 {
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 }
129 }
131 static gboolean
132 codec_create (GstDucatiVidDec * self)
133 {
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;
174 }
176 static inline GstBuffer *
177 codec_bufferpool_get (GstDucatiVidDec * self, GstBuffer * buf)
178 {
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));
185 }
187 static XDAS_Int32
188 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer * buf)
189 {
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
233 }
235 static GstBuffer *
236 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
237 {
238 GstBuffer *buf = (GstBuffer *) id; // XXX use lookup table
239 if (buf) {
240 gst_buffer_ref (buf);
241 }
242 return buf;
243 }
245 static void
246 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
247 {
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 }
253 }
255 static gint
256 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush)
257 {
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;
324 }
326 /** call control(FLUSH), and then process() to pop out all buffers */
327 static gboolean
328 codec_flush (GstDucatiVidDec * self, gboolean eos)
329 {
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;
373 }
375 /* GstDucatiVidDec vmethod default implementations */
377 static gboolean
378 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
379 {
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;
413 }
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)
418 {
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;
477 }
479 static GstBuffer *
480 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
481 {
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;
492 }
494 /* GstElement vmethod implementations */
496 static gboolean
497 gst_ducati_viddec_set_caps (GstPad * pad, GstCaps * caps)
498 {
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);
565 }
567 static gboolean
568 gst_ducati_viddec_query (GstPad * pad, GstQuery * query)
569 {
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 }
585 }
587 static GstFlowReturn
588 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
589 {
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;
661 }
663 static gboolean
664 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
665 {
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;
690 }
692 static GstStateChangeReturn
693 gst_ducati_viddec_change_state (GstElement * element,
694 GstStateChange transition)
695 {
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;
732 }
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)
741 {
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 }
783 }
785 static void
786 gst_ducati_viddec_finalize (GObject * obj)
787 {
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);
799 }
801 static void
802 gst_ducati_viddec_base_init (gpointer gclass)
803 {
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));
808 }
810 static void
811 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
812 {
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));
834 }
836 static void
837 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
838 {
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;
864 }