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"
25 #include "gstducatibufferpriv.h"
27 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
28 GST_TYPE_ELEMENT);
30 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
31 GST_PAD_SRC,
32 GST_PAD_ALWAYS,
33 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV_STRIDED ("NV12", "[ 0, max ]"))
34 );
36 enum
37 {
38 PROP_0,
39 PROP_VERSION,
40 };
42 /* helper functions */
44 static void
45 engine_close (GstDucatiVidDec * self)
46 {
47 if (self->engine) {
48 Engine_close (self->engine);
49 self->engine = NULL;
50 }
52 if (self->params) {
53 dce_free (self->params);
54 self->params = NULL;
55 }
57 if (self->dynParams) {
58 dce_free (self->dynParams);
59 self->dynParams = NULL;
60 }
62 if (self->status) {
63 dce_free (self->status);
64 self->status = NULL;
65 }
67 if (self->inBufs) {
68 dce_free (self->inBufs);
69 self->inBufs = NULL;
70 }
72 if (self->outBufs) {
73 dce_free (self->outBufs);
74 self->outBufs = NULL;
75 }
77 if (self->inArgs) {
78 dce_free (self->inArgs);
79 self->inArgs = NULL;
80 }
82 if (self->outArgs) {
83 dce_free (self->outArgs);
84 self->outArgs = NULL;
85 }
87 if (self->device) {
88 dce_deinit (self->device);
89 self->device = NULL;
90 }
91 }
93 static gboolean
94 engine_open (GstDucatiVidDec * self)
95 {
96 gboolean ret;
97 int ec;
99 if (G_UNLIKELY (self->engine)) {
100 return TRUE;
101 }
103 if (self->device == NULL) {
104 self->device = dce_init ();
105 if (self->device == NULL) {
106 GST_ERROR_OBJECT (self, "dce_init() failed");
107 return FALSE;
108 }
109 }
111 GST_DEBUG_OBJECT (self, "opening engine");
113 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
114 if (G_UNLIKELY (!self->engine)) {
115 GST_ERROR_OBJECT (self, "could not create engine");
116 return FALSE;
117 }
119 ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
120 sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
121 sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
122 sizeof (IVIDDEC3_OutArgs));
124 return ret;
125 }
127 static void
128 codec_delete (GstDucatiVidDec * self)
129 {
130 if (self->pool) {
131 gst_drm_buffer_pool_destroy (self->pool);
132 self->pool = NULL;
133 }
135 if (self->codec) {
136 VIDDEC3_delete (self->codec);
137 self->codec = NULL;
138 }
140 if (self->input_bo) {
141 omap_bo_del (self->input_bo);
142 self->input_bo = NULL;
143 }
144 }
146 static gboolean
147 codec_create (GstDucatiVidDec * self)
148 {
149 gint err;
150 const gchar *codec_name;
152 codec_delete (self);
154 if (G_UNLIKELY (!self->engine)) {
155 GST_ERROR_OBJECT (self, "no engine");
156 return FALSE;
157 }
159 /* these need to be set before VIDDEC3_create */
160 self->params->maxWidth = self->width;
161 self->params->maxHeight = self->height;
163 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
165 /* create codec: */
166 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
167 self->codec =
168 VIDDEC3_create (self->engine, (String) codec_name, self->params);
170 if (!self->codec) {
171 return FALSE;
172 }
174 err =
175 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
176 self->status);
177 if (err) {
178 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
179 return FALSE;
180 }
182 self->first_in_buffer = TRUE;
183 self->first_out_buffer = TRUE;
185 /* allocate input buffer and initialize inBufs: */
186 /* FIXME: needed size here has nothing to do with width * height */
187 self->input_bo = omap_bo_new (self->device,
188 self->width * self->height, OMAP_BO_WC);
189 self->input = omap_bo_map (self->input_bo);
190 self->inBufs->numBufs = 1;
191 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
193 return TRUE;
194 }
196 static inline GstBuffer *
197 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
198 {
199 if (G_UNLIKELY (!self->pool)) {
200 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
201 self->padded_width, self->padded_height);
203 GST_DEBUG_OBJECT (self, "creating bufferpool");
204 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
205 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
206 }
207 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
208 }
210 static GstDucatiBufferPriv *
211 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
212 {
213 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
214 if (!priv) {
215 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
216 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
218 /* if it isn't a dmabuf buffer that we can import, then there
219 * is nothing we can do with it:
220 */
221 if (!dmabuf) {
222 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
223 return NULL;
224 }
226 priv = gst_ducati_buffer_priv_new ();
228 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
230 priv->uv_offset = gst_video_format_get_component_offset (format,
231 1, self->stride, self->padded_height);
232 priv->size = gst_video_format_get_size (format,
233 self->stride, self->padded_height);
235 gst_ducati_buffer_priv_set (buf, priv);
236 gst_mini_object_unref (GST_MINI_OBJECT (priv));
237 }
238 return priv;
239 }
241 static XDAS_Int32
242 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
243 gboolean force_internal)
244 {
245 GstDucatiBufferPriv *priv = NULL;
247 if (!force_internal)
248 priv = get_buffer_priv (self, *buf);
250 if (!priv) {
251 GstBuffer *orig = *buf;
253 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
254 *buf = codec_buffer_pool_get (self, NULL);
255 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
256 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
257 gst_buffer_unref (orig);
258 return codec_prepare_outbuf (self, buf, FALSE);
259 }
261 self->outBufs->numBufs = 2;
262 self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
263 self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
264 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
265 self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
266 self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
267 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
269 return (XDAS_Int32) * buf; // XXX use lookup table
270 }
272 static GstBuffer *
273 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
274 {
275 GstBuffer *buf = (GstBuffer *) id; // XXX use lookup table
276 if (buf) {
277 gst_buffer_ref (buf);
278 }
279 return buf;
280 }
282 static void
283 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
284 {
285 GstBuffer *buf = (GstBuffer *) id; // XXX use lookup table
286 if (buf) {
287 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
288 gst_buffer_unref (buf);
289 }
290 }
292 static gint
293 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
294 GstFlowReturn * flow_ret)
295 {
296 gint err;
297 GstClockTime t;
298 GstBuffer *outbuf = NULL;
299 gint i;
300 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
301 GstFlowReturn ret = GST_FLOW_OK;
302 if (flow_ret)
303 /* never leave flow_ret uninitialized */
304 *flow_ret = GST_FLOW_OK;
306 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
307 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
309 t = gst_util_get_timestamp ();
310 err = VIDDEC3_process (self->codec,
311 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
312 GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
314 if (err) {
315 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
316 err, self->outArgs->extendedError);
317 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
319 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
320 self->dynParams, self->status);
321 if (err) {
322 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
323 err, self->status->extendedError);
324 gst_ducati_log_extended_error_info (self->status->extendedError);
325 }
327 if (flush)
328 err = XDM_EFAIL;
329 else
330 err = klass->handle_error (self, err,
331 self->outArgs->extendedError, self->status->extendedError);
332 }
334 /* we now let the codec decide */
335 self->dynParams->newFrameFlag = XDAS_FALSE;
337 if (err == XDM_EFAIL || self->outArgs->outBufsInUseFlag)
338 goto skip_outbuf_processing;
340 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
341 gboolean interlaced;
343 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
345 interlaced =
346 self->outArgs->decodedBufs.contentType ==
347 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
349 /* if send is FALSE, don't try to renegotiate as we could be flushing during
350 * a PAUSED->READY state change
351 */
352 if (send && interlaced != self->interlaced) {
353 GstCaps *caps;
355 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
356 "thinks interlaced=%d... trusting codec", self->interlaced,
357 interlaced);
359 self->interlaced = interlaced;
361 caps =
362 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
363 GST_INFO_OBJECT (self, "changing interlace field in caps");
364 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
365 NULL);
366 gst_drm_buffer_pool_set_caps (self->pool, caps);
367 if (!gst_pad_set_caps (self->srcpad, caps)) {
368 GST_ERROR_OBJECT (self,
369 "downstream didn't want to change interlace mode");
370 err = XDM_EFAIL;
371 }
372 gst_caps_unref (caps);
374 /* this buffer still has the old caps so we skip it */
375 send = FALSE;
376 }
378 if (G_UNLIKELY (self->send_crop_event) && send) {
379 gint crop_width, crop_height;
380 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
382 /* send region of interest to sink on first buffer: */
383 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
385 crop_width = r->bottomRight.x - r->topLeft.x;
386 crop_height = r->bottomRight.y - r->topLeft.y;
388 if (crop_width > self->input_width)
389 crop_width = self->input_width;
390 if (crop_height > self->input_height)
391 crop_height = self->input_height;
393 if (self->interlaced && !strcmp (klass->codec_name, "ivahd_mpeg2vdec"))
394 crop_height = crop_height / 2;
396 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
397 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
398 crop_width, crop_height);
400 gst_pad_push_event (self->srcpad,
401 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
402 crop_width, crop_height));
404 if (self->crop)
405 gst_video_crop_unref (self->crop);
407 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
408 crop_width, crop_height);
410 self->send_crop_event = FALSE;
411 }
413 if (G_UNLIKELY (self->first_out_buffer) && send && !self->outArgs->outBufsInUseFlag) {
414 GstDRMBufferPool *pool;
415 self->first_out_buffer = FALSE;
417 /* Destroy the pool so the buffers we used so far are eventually released.
418 * The pool will be recreated if needed.
419 */
420 pool = self->pool;
421 self->pool = NULL;
422 gst_drm_buffer_pool_destroy (pool);
423 }
425 if (send && !self->outArgs->outBufsInUseFlag) {
426 GstClockTime ts;
428 ts = GST_BUFFER_TIMESTAMP (outbuf);
430 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
431 i, outbuf, GST_TIME_ARGS (ts));
433 if (self->ts_may_be_pts) {
434 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
435 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
436 "enabling ts_is_pts");
437 self->ts_is_pts = TRUE;
438 }
439 }
441 self->last_pts = ts;
443 if (self->dts_ridx != self->dts_widx) {
444 ts = self->dts_queue[self->dts_ridx++ % NDTS];
445 }
447 if (self->ts_is_pts) {
448 /* if we have a queued DTS from demuxer, use that instead: */
449 GST_BUFFER_TIMESTAMP (outbuf) = ts;
450 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
451 i, outbuf, GST_TIME_ARGS (ts));
452 }
454 if (GST_BUFFER_CAPS (outbuf) &&
455 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
456 GST_PAD_CAPS (self->srcpad))) {
457 /* this looks a bit scary but it's really just to change the interlace=
458 * field in caps when we start as !interlaced and the codec detects
459 * otherwise */
460 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
461 "interlace mismatch");
462 outbuf = gst_buffer_make_metadata_writable (outbuf);
463 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
464 }
466 if (self->crop)
467 gst_buffer_set_video_crop (outbuf, self->crop);
469 ret = gst_pad_push (self->srcpad, outbuf);
470 if (flow_ret)
471 *flow_ret = ret;
472 if (ret != GST_FLOW_OK) {
473 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
474 /* just unref the remaining buffers (if any) */
475 send = FALSE;
476 }
477 } else {
478 GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
479 gst_buffer_unref (outbuf);
480 }
481 }
483 skip_outbuf_processing:
484 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
485 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
486 }
488 return err;
489 }
491 /** call control(FLUSH), and then process() to pop out all buffers */
492 gboolean
493 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
494 {
495 gint err = FALSE;
497 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
499 /* note: flush is synchronized against _chain() to avoid calling
500 * the codec from multiple threads
501 */
502 GST_PAD_STREAM_LOCK (self->sinkpad);
504 self->dts_ridx = self->dts_widx = 0;
505 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
506 self->ts_may_be_pts = TRUE;
507 self->ts_is_pts = FALSE;
508 self->wait_keyframe = TRUE;
509 self->in_size = 0;
510 self->needs_flushing = FALSE;
511 self->need_out_buf = TRUE;
513 if (G_UNLIKELY (self->first_in_buffer)) {
514 goto out;
515 }
517 if (G_UNLIKELY (!self->codec)) {
518 GST_WARNING_OBJECT (self, "no codec");
519 goto out;
520 }
522 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
523 if (err) {
524 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
525 goto out;
526 }
528 self->inBufs->descs[0].bufSize.bytes = 0;
529 self->inArgs->numBytes = 0;
530 self->inArgs->inputID = 0;
532 do {
533 err = codec_process (self, eos, TRUE, NULL);
534 } while (err != XDM_EFAIL);
536 /* reset outArgs in case we're flushing in codec_process trying to do error
537 * recovery */
538 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
539 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
541 self->dynParams->newFrameFlag = XDAS_TRUE;
543 /* on a flush, it is normal (and not an error) for the last _process() call
544 * to return an error..
545 */
546 err = XDM_EOK;
548 out:
549 GST_PAD_STREAM_UNLOCK (self->sinkpad);
550 GST_DEBUG_OBJECT (self, "done");
552 return !err;
553 }
555 /* GstDucatiVidDec vmethod default implementations */
557 static gboolean
558 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
559 {
560 const GValue *codec_data;
561 gint w, h;
563 if (gst_structure_get_int (s, "width", &self->input_width) &&
564 gst_structure_get_int (s, "height", &self->input_height)) {
566 h = ALIGN2 (self->input_height, 4); /* round up to MB */
567 w = ALIGN2 (self->input_width, 4); /* round up to MB */
569 /* if we've already created codec, but the resolution has changed, we
570 * need to re-create the codec:
571 */
572 if (G_UNLIKELY (self->codec)) {
573 if ((h != self->height) || (w != self->width)) {
574 codec_delete (self);
575 }
576 }
578 self->width = w;
579 self->height = h;
581 codec_data = gst_structure_get_value (s, "codec_data");
583 if (codec_data) {
584 GstBuffer *buffer = gst_value_get_buffer (codec_data);
585 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
586 self->codec_data = gst_buffer_ref (buffer);
587 }
589 return TRUE;
590 }
592 return FALSE;
593 }
595 static gboolean
596 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
597 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
598 {
600 /* allocate params: */
601 self->params = dce_alloc (params_sz);
602 if (G_UNLIKELY (!self->params)) {
603 return FALSE;
604 }
605 self->params->size = params_sz;
606 self->params->maxFrameRate = 30000;
607 self->params->maxBitRate = 10000000;
609 self->params->dataEndianness = XDM_BYTE;
610 self->params->forceChromaFormat = XDM_YUV_420SP;
611 self->params->operatingMode = IVIDEO_DECODE_ONLY;
613 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
614 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
615 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
616 self->params->numInputDataUnits = 0;
617 self->params->numOutputDataUnits = 0;
619 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
620 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
621 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
622 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
624 /* allocate dynParams: */
625 self->dynParams = dce_alloc (dynparams_sz);
626 if (G_UNLIKELY (!self->dynParams)) {
627 return FALSE;
628 }
629 self->dynParams->size = dynparams_sz;
630 self->dynParams->decodeHeader = XDM_DECODE_AU;
631 self->dynParams->displayWidth = 0;
632 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
633 self->dynParams->newFrameFlag = XDAS_TRUE;
635 /* allocate status: */
636 self->status = dce_alloc (status_sz);
637 if (G_UNLIKELY (!self->status)) {
638 return FALSE;
639 }
640 self->status->size = status_sz;
642 /* allocate inBufs/outBufs: */
643 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
644 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
645 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
646 return FALSE;
647 }
649 /* allocate inArgs/outArgs: */
650 self->inArgs = dce_alloc (inargs_sz);
651 self->outArgs = dce_alloc (outargs_sz);
652 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
653 return FALSE;
654 }
655 self->inArgs->size = inargs_sz;
656 self->outArgs->size = outargs_sz;
658 return TRUE;
659 }
661 static GstBuffer *
662 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
663 {
664 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
665 push_input (self, GST_BUFFER_DATA (self->codec_data),
666 GST_BUFFER_SIZE (self->codec_data));
667 }
669 /* just copy entire buffer */
670 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
671 gst_buffer_unref (buf);
673 return NULL;
674 }
676 static gint
677 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
678 gint extended_error, gint status_extended_error)
679 {
680 if (XDM_ISFATALERROR (extended_error))
681 ret = XDM_EFAIL;
682 else
683 ret = XDM_EOK;
685 return ret;
686 }
688 /* GstElement vmethod implementations */
690 static gboolean
691 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
692 {
693 gboolean ret = TRUE;
694 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
695 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
696 GstStructure *s;
697 GstCaps *outcaps = NULL;
698 GstStructure *out_s;
699 gint par_width, par_height;
700 gboolean par_present;
702 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
704 s = gst_caps_get_structure (caps, 0);
705 if (!klass->parse_caps (self, s)) {
706 GST_WARNING_OBJECT (self, "missing required fields");
707 ret = FALSE;
708 goto out;
709 }
711 /* update output/padded sizes */
712 klass->update_buffer_size (self);
714 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
715 self->fps_n = 0;
716 self->fps_d = 1;
717 }
718 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
719 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
720 &par_width, &par_height);
722 outcaps = gst_pad_get_allowed_caps (self->srcpad);
723 if (outcaps) {
724 outcaps = gst_caps_make_writable (outcaps);
725 gst_caps_truncate (outcaps);
726 if (gst_caps_is_empty (outcaps)) {
727 gst_caps_unref (outcaps);
728 outcaps = NULL;
729 }
730 }
732 if (!outcaps) {
733 /* note: default to non-strided for better compatibility with
734 * other gst elements that don't understand stride:
735 */
736 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
737 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
738 }
740 out_s = gst_caps_get_structure (outcaps, 0);
741 gst_structure_set (out_s,
742 "width", G_TYPE_INT, self->padded_width,
743 "height", G_TYPE_INT, self->padded_height,
744 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
745 if (par_present)
746 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
747 par_width, par_height, NULL);
749 if (self->interlaced)
750 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
752 if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
753 if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
754 self->stride = 4096;
755 gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
756 }
757 } else {
758 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
759 0, self->padded_width);
760 }
762 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
763 self->stride, self->padded_height);
765 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
766 self->outsize, self->stride, outcaps);
768 if (!self->first_in_buffer) {
769 /* Caps changed mid stream. We flush the codec to unlock all the potentially
770 * locked buffers. This is needed for downstream sinks that provide a
771 * buffer pool and need to destroy all the outstanding buffers before they
772 * can negotiate new caps (hello v4l2sink).
773 */
774 gst_ducati_viddec_codec_flush (self, FALSE);
775 }
777 /* (re)send a crop event when caps change */
778 self->send_crop_event = TRUE;
780 ret = gst_pad_set_caps (self->srcpad, outcaps);
782 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
784 out:
785 if (outcaps)
786 gst_caps_unref (outcaps);
787 gst_object_unref (self);
789 return ret;
790 }
792 static GstCaps *
793 gst_ducati_viddec_src_getcaps (GstPad * pad)
794 {
795 GstCaps *caps = NULL;
796 GstCaps *outcaps = NULL;
797 int i;
799 caps = GST_PAD_CAPS (pad);
800 if (caps == NULL) {
801 outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
802 return outcaps;
803 }
805 outcaps = gst_caps_new_empty ();
807 /* allow -rowstrided and regular yuv */
808 for (i = 0; i < gst_caps_get_size (caps); i++) {
809 GstStructure *structure;
810 GstStructure *modified_structure;
811 GValue value = { 0 };
813 structure = gst_caps_get_structure (caps, i);
814 gst_caps_append_structure (outcaps, gst_structure_copy (structure));
815 modified_structure = gst_structure_copy (structure);
817 if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
818 gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
819 g_value_init (&value, GST_TYPE_INT_RANGE);
820 gst_value_set_int_range (&value, 0, G_MAXINT);
821 gst_structure_set_value (modified_structure, "rowstride", &value);
822 gst_caps_append_structure (outcaps, modified_structure);
823 g_value_unset (&value);
824 } else {
825 gst_structure_set_name (modified_structure, "video/x-raw-yuv");
826 gst_structure_remove_field (modified_structure, "rowstride");
827 gst_caps_append_structure (outcaps, modified_structure);
828 }
829 }
830 return outcaps;
831 }
833 static gboolean
834 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
835 GstQuery * query, gboolean * forward)
836 {
837 gboolean res = TRUE;
839 switch (GST_QUERY_TYPE (query)) {
840 case GST_QUERY_BUFFERS:
841 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
842 gst_query_set_buffers_count (query, self->min_buffers);
844 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
845 self->padded_width, self->padded_height);
846 gst_query_set_buffers_dimensions (query,
847 self->padded_width, self->padded_height);
848 *forward = FALSE;
849 break;
850 default:
851 break;
852 }
855 return res;
856 }
858 static gboolean
859 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
860 {
861 gboolean res = TRUE, forward = TRUE;
862 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
863 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
865 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
866 res = klass->query (self, pad, query, &forward);
867 if (res && forward)
868 res = gst_pad_query_default (pad, query);
870 return res;
871 }
873 static gboolean
874 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
875 {
876 GstClockTime timestamp, qostime;
877 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
878 gint64 diff;
880 if (self->wait_keyframe) {
881 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
882 GST_INFO_OBJECT (self, "skipping until the next keyframe");
883 return FALSE;
884 }
886 self->wait_keyframe = FALSE;
887 }
889 timestamp = GST_BUFFER_TIMESTAMP (buf);
890 if (self->segment.format != GST_FORMAT_TIME ||
891 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
892 goto no_qos;
894 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
895 goto no_qos;
897 qostime = gst_segment_to_running_time (&self->segment,
898 GST_FORMAT_TIME, timestamp);
899 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
900 /* out of segment */
901 goto no_qos;
903 /* see how our next timestamp relates to the latest qos timestamp. negative
904 * values mean we are early, positive values mean we are too late. */
905 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
907 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
908 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
909 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
910 self->qos_proportion);
912 if (klass->drop_frame (self, buf, diff)) {
913 GST_INFO_OBJECT (self, "dropping frame");
914 return FALSE;
915 }
917 no_qos:
918 return TRUE;
919 }
921 static gboolean
922 gst_ducati_viddec_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
923 gint64 diff)
924 {
925 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
926 GST_BUFFER_FLAG_DELTA_UNIT);
928 if (diff >= 0 && !is_keyframe)
929 return TRUE;
931 return FALSE;
932 }
934 static GstFlowReturn
935 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
936 {
937 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
938 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
939 GstFlowReturn ret = GST_FLOW_OK;
940 Int32 err;
941 GstBuffer *outbuf = NULL;
942 GstCaps *outcaps = NULL;
943 gboolean decode;
945 if (G_UNLIKELY (!self->engine)) {
946 GST_ERROR_OBJECT (self, "no engine");
947 gst_buffer_unref (buf);
948 return GST_FLOW_ERROR;
949 }
951 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
952 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
954 decode = gst_ducati_viddec_do_qos (self, buf);
955 if (!decode) {
956 gst_buffer_unref (buf);
957 return GST_FLOW_OK;
958 }
960 if (!self->need_out_buf)
961 goto have_out_buf;
963 /* do this before creating codec to ensure reverse caps negotiation
964 * happens first:
965 */
966 allocate_buffer:
967 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
968 GST_PAD_CAPS (self->srcpad), &outbuf);
969 if (ret != GST_FLOW_OK) {
970 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
971 gst_flow_get_name (ret));
972 gst_buffer_unref (buf);
973 return ret;
974 }
976 outcaps = GST_BUFFER_CAPS (outbuf);
977 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
978 GstStructure *s;
980 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
981 GST_BUFFER_SIZE (outbuf));
983 s = gst_caps_get_structure (outcaps, 0);
984 gst_structure_get_int (s, "rowstride", &self->stride);
985 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
986 self->stride, self->padded_height);
988 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
989 self->outsize, self->stride, outcaps);
991 gst_pad_set_caps (self->srcpad, outcaps);
993 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
994 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
995 GST_BUFFER_SIZE (outbuf), self->outsize);
996 gst_buffer_unref (outbuf);
997 goto allocate_buffer;
998 }
999 }
1001 if (G_UNLIKELY (!self->codec)) {
1002 if (!codec_create (self)) {
1003 GST_ERROR_OBJECT (self, "could not create codec");
1004 gst_buffer_unref (buf);
1005 gst_buffer_unref (outbuf);
1006 return GST_FLOW_ERROR;
1007 }
1008 }
1010 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1011 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1013 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1014 * internal pool while self->first_out_buffer == TRUE in order to simplify
1015 * things in case we need to renegotiate */
1016 self->inArgs->inputID =
1017 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1018 if (!self->inArgs->inputID) {
1019 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1020 gst_buffer_unref (buf);
1021 return GST_FLOW_ERROR;
1022 }
1024 have_out_buf:
1025 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1027 if (ts != GST_CLOCK_TIME_NONE) {
1028 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1029 /* if next buffer has earlier ts than previous, then the ts
1030 * we are getting are definitely decode order (DTS):
1031 */
1032 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1033 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1034 self->ts_may_be_pts = FALSE;
1035 }
1036 self->last_dts = ts;
1037 }
1039 if (self->in_size == 0 && outbuf) {
1040 GST_DEBUG_OBJECT (self, "no input, skipping process");
1041 gst_buffer_unref (outbuf);
1042 return GST_FLOW_OK;
1043 }
1045 self->inArgs->numBytes = self->in_size;
1046 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1047 self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1049 err = codec_process (self, TRUE, FALSE, &ret);
1050 if (err) {
1051 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1052 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1053 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1054 return GST_FLOW_ERROR;
1055 }
1056 if (ret != GST_FLOW_OK) {
1057 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1058 gst_flow_get_name (ret));
1059 return ret;
1060 }
1062 self->first_in_buffer = FALSE;
1064 /* The copy could be avoided by playing with the buffer pointer,
1065 but it seems to be rare and for not many bytes */
1066 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1067 self->outArgs->bytesConsumed, self->in_size,
1068 self->inArgs->numBytes,
1069 self->in_size - self->outArgs->bytesConsumed);
1070 if (self->outArgs->bytesConsumed > 0) {
1071 if (self->outArgs->bytesConsumed > self->in_size) {
1072 GST_WARNING_OBJECT (self, "Codec claims to have used more bytes than supplied");
1073 self->in_size = 0;
1074 } else {
1075 if (self->outArgs->bytesConsumed < self->in_size) {
1076 GST_DEBUG_OBJECT (self, "First 16 were:");
1077 gst_util_dump_mem (self->input, 16);
1078 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1079 self->in_size - self->outArgs->bytesConsumed);
1080 }
1081 self->in_size -= self->outArgs->bytesConsumed;
1082 }
1083 }
1085 if (self->outArgs->outBufsInUseFlag) {
1086 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1087 self->need_out_buf = FALSE;
1088 } else {
1089 self->need_out_buf = TRUE;
1090 }
1092 if (buf) {
1093 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1094 GST_BUFFER_SIZE (buf));
1095 ts = GST_BUFFER_TIMESTAMP (buf);
1096 goto allocate_buffer;
1097 }
1099 if (self->needs_flushing)
1100 gst_ducati_viddec_codec_flush (self, FALSE);
1102 return GST_FLOW_OK;
1103 }
1105 static gboolean
1106 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1107 {
1108 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1109 gboolean ret = TRUE;
1111 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1113 switch (GST_EVENT_TYPE (event)) {
1114 case GST_EVENT_NEWSEGMENT:
1115 {
1116 gboolean update;
1117 GstFormat fmt;
1118 gint64 start, stop, time;
1119 gdouble rate, arate;
1121 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1122 &start, &stop, &time);
1123 gst_segment_set_newsegment_full (&self->segment, update,
1124 rate, arate, fmt, start, stop, time);
1125 break;
1126 }
1127 case GST_EVENT_EOS:
1128 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1129 GST_ERROR_OBJECT (self, "could not flush on eos");
1130 ret = FALSE;
1131 }
1132 break;
1133 case GST_EVENT_FLUSH_STOP:
1134 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1135 GST_ERROR_OBJECT (self, "could not flush");
1136 gst_event_unref (event);
1137 ret = FALSE;
1138 }
1139 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1140 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1141 self->qos_proportion = 1;
1142 self->need_out_buf = TRUE;
1143 break;
1144 default:
1145 break;
1146 }
1148 if (ret)
1149 ret = gst_pad_push_event (self->srcpad, event);
1150 GST_LOG_OBJECT (self, "end");
1152 return ret;
1153 }
1155 static gboolean
1156 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1157 {
1158 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1159 gboolean ret = TRUE;
1161 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1163 switch (GST_EVENT_TYPE (event)) {
1164 case GST_EVENT_QOS:
1165 {
1166 gdouble proportion;
1167 GstClockTimeDiff diff;
1168 GstClockTime timestamp;
1170 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1172 GST_OBJECT_LOCK (self);
1173 self->qos_proportion = proportion;
1174 self->qos_earliest_time = timestamp + 2 * diff;
1175 GST_OBJECT_UNLOCK (self);
1177 GST_DEBUG_OBJECT (self,
1178 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1179 proportion, GST_TIME_ARGS (timestamp), diff);
1181 ret = gst_pad_push_event (self->sinkpad, event);
1182 break;
1183 }
1184 default:
1185 ret = gst_pad_push_event (self->sinkpad, event);
1186 break;
1187 }
1189 GST_LOG_OBJECT (self, "end");
1191 return ret;
1192 }
1194 static GstStateChangeReturn
1195 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1196 {
1197 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1198 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1199 gboolean supported;
1201 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1202 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1203 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1205 switch (transition) {
1206 case GST_STATE_CHANGE_NULL_TO_READY:
1207 if (!engine_open (self)) {
1208 GST_ERROR_OBJECT (self, "could not open");
1209 return GST_STATE_CHANGE_FAILURE;
1210 }
1211 /* try to create/destroy the codec here, it may not be supported */
1212 supported = codec_create (self);
1213 codec_delete (self);
1214 self->codec = NULL;
1215 if (!supported) {
1216 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1217 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1218 engine_close (self);
1219 return GST_STATE_CHANGE_FAILURE;
1220 }
1221 break;
1222 default:
1223 break;
1224 }
1226 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1228 if (ret == GST_STATE_CHANGE_FAILURE)
1229 goto leave;
1231 switch (transition) {
1232 case GST_STATE_CHANGE_PAUSED_TO_READY:
1233 self->interlaced = FALSE;
1234 self->send_crop_event = TRUE;
1235 gst_ducati_viddec_codec_flush (self, FALSE);
1236 break;
1237 case GST_STATE_CHANGE_READY_TO_NULL:
1238 codec_delete (self);
1239 engine_close (self);
1240 break;
1241 default:
1242 break;
1243 }
1245 leave:
1246 GST_LOG_OBJECT (self, "end");
1248 return ret;
1249 }
1251 /* GObject vmethod implementations */
1253 #define VERSION_LENGTH 256
1255 static void
1256 gst_ducati_viddec_get_property (GObject * obj,
1257 guint prop_id, GValue * value, GParamSpec * pspec)
1258 {
1259 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1262 switch (prop_id) {
1263 case PROP_VERSION:{
1264 int err;
1265 char *version = NULL;
1267 if (!self->engine)
1268 engine_open (self);
1270 if (!self->codec)
1271 codec_create (self);
1273 if (self->codec) {
1274 version = dce_alloc (VERSION_LENGTH);
1275 self->status->data.buf = (XDAS_Int8 *) version;
1276 self->status->data.bufSize = VERSION_LENGTH;
1278 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1279 self->dynParams, self->status);
1280 if (err) {
1281 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1282 }
1284 self->status->data.buf = NULL;
1285 self->status->data.bufSize = 0;
1286 }
1288 g_value_set_string (value, version);
1289 if (version)
1290 dce_free (version);
1292 break;
1293 }
1294 default:{
1295 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1296 break;
1297 }
1298 }
1299 }
1301 static void
1302 gst_ducati_viddec_finalize (GObject * obj)
1303 {
1304 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1306 codec_delete (self);
1307 engine_close (self);
1309 if (self->codec_data) {
1310 gst_buffer_unref (self->codec_data);
1311 self->codec_data = NULL;
1312 }
1314 G_OBJECT_CLASS (parent_class)->finalize (obj);
1315 }
1317 static void
1318 gst_ducati_viddec_base_init (gpointer gclass)
1319 {
1320 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1322 gst_element_class_add_pad_template (element_class,
1323 gst_static_pad_template_get (&src_factory));
1324 }
1326 static void
1327 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1328 {
1329 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1330 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1332 gobject_class->get_property =
1333 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1334 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1335 gstelement_class->change_state =
1336 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1338 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1339 klass->allocate_params =
1340 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1341 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1342 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1343 klass->drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_drop_frame);
1344 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1346 g_object_class_install_property (gobject_class, PROP_VERSION,
1347 g_param_spec_string ("version", "Version",
1348 "The codec version string", "",
1349 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1350 }
1352 static void
1353 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1354 {
1355 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1357 self->sinkpad =
1358 gst_pad_new_from_template (gst_element_class_get_pad_template
1359 (gstelement_class, "sink"), "sink");
1360 gst_pad_set_setcaps_function (self->sinkpad,
1361 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1362 gst_pad_set_chain_function (self->sinkpad,
1363 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1364 gst_pad_set_event_function (self->sinkpad,
1365 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1367 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1368 gst_pad_set_event_function (self->srcpad,
1369 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1370 gst_pad_set_query_function (self->srcpad,
1371 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1372 gst_pad_set_getcaps_function (self->srcpad,
1373 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1375 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1376 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1378 self->input_width = 0;
1379 self->input_height = 0;
1380 /* sane defaults in case we need to create codec without caps negotiation
1381 * (for example, to get 'version' property)
1382 */
1383 self->width = 128;
1384 self->height = 128;
1385 self->fps_n = -1;
1386 self->fps_d = -1;
1388 self->first_in_buffer = TRUE;
1389 self->first_out_buffer = TRUE;
1390 self->interlaced = FALSE;
1391 self->send_crop_event = TRUE;
1393 self->dts_ridx = self->dts_widx = 0;
1394 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1395 self->ts_may_be_pts = TRUE;
1396 self->ts_is_pts = FALSE;
1398 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1400 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1402 self->qos_proportion = 1;
1403 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1404 self->wait_keyframe = TRUE;
1406 self->need_out_buf = TRUE;
1407 self->device = NULL;
1408 self->input_bo = NULL;
1409 }