4d43cd4946a97ba84ea5c8dc0e5b291f20d598dd
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 self->input_bo = omap_bo_new (self->device,
187 self->width * self->height, OMAP_BO_WC);
188 self->input = omap_bo_map (self->input_bo);
189 self->inBufs->numBufs = 1;
190 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
192 return TRUE;
193 }
195 static inline GstBuffer *
196 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
197 {
198 if (G_UNLIKELY (!self->pool)) {
199 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
200 self->padded_width, self->padded_height);
202 GST_DEBUG_OBJECT (self, "creating bufferpool");
203 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
204 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
205 }
206 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
207 }
209 static GstDucatiBufferPriv *
210 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
211 {
212 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
213 if (!priv) {
214 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
215 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
217 /* if it isn't a dmabuf buffer that we can import, then there
218 * is nothing we can do with it:
219 */
220 if (!dmabuf) {
221 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
222 return NULL;
223 }
225 priv = gst_ducati_buffer_priv_new ();
227 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
229 priv->uv_offset = gst_video_format_get_component_offset (format,
230 1, self->stride, self->padded_height);
231 priv->size = gst_video_format_get_size (format,
232 self->stride, self->padded_height);
234 gst_ducati_buffer_priv_set (buf, priv);
235 }
236 return priv;
237 }
239 static XDAS_Int32
240 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
241 gboolean force_internal)
242 {
243 GstDucatiBufferPriv *priv = NULL;
245 if (!force_internal)
246 priv = get_buffer_priv (self, *buf);
248 if (!priv) {
249 GstBuffer *orig = *buf;
251 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
252 *buf = codec_buffer_pool_get (self, NULL);
253 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
254 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
255 gst_buffer_unref (orig);
256 return codec_prepare_outbuf (self, buf, FALSE);
257 }
259 self->outBufs->numBufs = 2;
260 self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
261 self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
262 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
263 self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
264 self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
265 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
267 return (XDAS_Int32) * buf; // XXX use lookup table
268 }
270 static GstBuffer *
271 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
272 {
273 GstBuffer *buf = (GstBuffer *) id; // XXX use lookup table
274 if (buf) {
275 gst_buffer_ref (buf);
276 }
277 return buf;
278 }
280 static void
281 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
282 {
283 GstBuffer *buf = (GstBuffer *) id; // XXX use lookup table
284 if (buf) {
285 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
286 gst_buffer_unref (buf);
287 }
288 }
290 static gint
291 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
292 GstFlowReturn * flow_ret)
293 {
294 gint err;
295 GstClockTime t;
296 GstBuffer *outbuf = NULL;
297 gint i;
298 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
299 GstFlowReturn ret = GST_FLOW_OK;
300 if (flow_ret)
301 /* never leave flow_ret uninitialized */
302 *flow_ret = GST_FLOW_OK;
304 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
305 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
307 t = gst_util_get_timestamp ();
308 err = VIDDEC3_process (self->codec,
309 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
310 GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
312 if (err) {
313 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
314 err, self->outArgs->extendedError);
316 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
317 self->dynParams, self->status);
318 if (!err) {
319 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
320 err, self->status->extendedError);
321 }
323 if (flush)
324 err = XDM_EFAIL;
325 else
326 err = klass->handle_error (self, err,
327 self->outArgs->extendedError, self->status->extendedError);
328 }
330 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
331 gboolean interlaced;
333 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
335 interlaced =
336 self->outArgs->decodedBufs.contentType ==
337 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
339 /* if send is FALSE, don't try to renegotiate as we could be flushing during
340 * a PAUSED->READY state change
341 */
342 if (send && interlaced != self->interlaced) {
343 GstCaps *caps;
345 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
346 "thinks interlaced=%d... trusting codec", self->interlaced,
347 interlaced);
349 self->interlaced = interlaced;
351 caps =
352 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
353 GST_INFO_OBJECT (self, "changing interlace field in caps");
354 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
355 NULL);
356 gst_drm_buffer_pool_set_caps (self->pool, caps);
357 if (!gst_pad_set_caps (self->srcpad, caps)) {
358 GST_ERROR_OBJECT (self,
359 "downstream didn't want to change interlace mode");
360 err = XDM_EFAIL;
361 }
362 gst_caps_unref (caps);
364 /* this buffer still has the old caps so we skip it */
365 send = FALSE;
366 }
368 if (G_UNLIKELY (self->send_crop_event) && send) {
369 gint crop_width, crop_height;
370 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
372 /* send region of interest to sink on first buffer: */
373 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
375 crop_width = r->bottomRight.x - r->topLeft.x;
376 crop_height = r->bottomRight.y - r->topLeft.y;
378 if (crop_width > self->input_width)
379 crop_width = self->input_width;
380 if (crop_height > self->input_height)
381 crop_height = self->input_height;
383 if (self->interlaced && !strcmp (klass->codec_name, "ivahd_mpeg2vdec"))
384 crop_height = crop_height / 2;
386 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
387 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
388 crop_width, crop_height);
390 gst_pad_push_event (self->srcpad,
391 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
392 crop_width, crop_height));
394 if (self->crop)
395 gst_video_crop_unref (self->crop);
397 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
398 crop_width, crop_height);
400 self->send_crop_event = FALSE;
401 }
403 if (G_UNLIKELY (self->first_out_buffer) && send) {
404 GstDRMBufferPool *pool;
405 self->first_out_buffer = FALSE;
407 /* Destroy the pool so the buffers we used so far are eventually released.
408 * The pool will be recreated if needed.
409 */
410 pool = self->pool;
411 self->pool = NULL;
412 gst_drm_buffer_pool_destroy (pool);
413 }
415 if (send) {
416 GstClockTime ts;
418 ts = GST_BUFFER_TIMESTAMP (outbuf);
420 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
421 i, outbuf, GST_TIME_ARGS (ts));
423 if (self->ts_may_be_pts) {
424 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
425 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
426 "enabling ts_is_pts");
427 self->ts_is_pts = TRUE;
428 }
429 }
431 self->last_pts = ts;
433 if (self->dts_ridx != self->dts_widx) {
434 ts = self->dts_queue[self->dts_ridx++ % NDTS];
435 }
437 if (self->ts_is_pts) {
438 /* if we have a queued DTS from demuxer, use that instead: */
439 GST_BUFFER_TIMESTAMP (outbuf) = ts;
440 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
441 i, outbuf, GST_TIME_ARGS (ts));
442 }
444 if (GST_BUFFER_CAPS (outbuf) &&
445 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
446 GST_PAD_CAPS (self->srcpad))) {
447 /* this looks a bit scary but it's really just to change the interlace=
448 * field in caps when we start as !interlaced and the codec detects
449 * otherwise */
450 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
451 "interlace mismatch");
452 outbuf = gst_buffer_make_metadata_writable (outbuf);
453 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
454 }
456 if (self->crop)
457 gst_buffer_set_video_crop (outbuf, self->crop);
459 ret = gst_pad_push (self->srcpad, outbuf);
460 if (flow_ret)
461 *flow_ret = ret;
462 if (ret != GST_FLOW_OK) {
463 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
464 /* just unref the remaining buffers (if any) */
465 send = FALSE;
466 }
467 } else {
468 GST_DEBUG_OBJECT (self, "free buffer: %d %p", i, outbuf);
469 gst_buffer_unref (outbuf);
470 }
471 }
473 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
474 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
475 }
477 return err;
478 }
480 /** call control(FLUSH), and then process() to pop out all buffers */
481 gboolean
482 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
483 {
484 gint err = FALSE;
486 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
488 /* note: flush is synchronized against _chain() to avoid calling
489 * the codec from multiple threads
490 */
491 GST_PAD_STREAM_LOCK (self->sinkpad);
493 self->dts_ridx = self->dts_widx = 0;
494 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
495 self->ts_may_be_pts = TRUE;
496 self->ts_is_pts = FALSE;
497 self->wait_keyframe = TRUE;
499 if (G_UNLIKELY (self->first_in_buffer)) {
500 goto out;
501 }
503 if (G_UNLIKELY (!self->codec)) {
504 GST_WARNING_OBJECT (self, "no codec");
505 goto out;
506 }
508 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
509 if (err) {
510 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
511 goto out;
512 }
514 self->inBufs->descs[0].bufSize.bytes = 0;
515 self->inArgs->numBytes = 0;
516 self->inArgs->inputID = 0;
518 do {
519 err = codec_process (self, eos, TRUE, NULL);
520 } while (err != XDM_EFAIL);
522 /* reset outArgs in case we're flushing in codec_process trying to do error
523 * recovery */
524 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
525 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
527 /* on a flush, it is normal (and not an error) for the last _process() call
528 * to return an error..
529 */
530 err = XDM_EOK;
532 out:
533 GST_PAD_STREAM_UNLOCK (self->sinkpad);
534 GST_DEBUG_OBJECT (self, "done");
536 return !err;
537 }
539 /* GstDucatiVidDec vmethod default implementations */
541 static gboolean
542 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
543 {
544 const GValue *codec_data;
545 gint w, h;
547 if (gst_structure_get_int (s, "width", &self->input_width) &&
548 gst_structure_get_int (s, "height", &self->input_height)) {
550 h = ALIGN2 (self->input_height, 4); /* round up to MB */
551 w = ALIGN2 (self->input_width, 4); /* round up to MB */
553 /* if we've already created codec, but the resolution has changed, we
554 * need to re-create the codec:
555 */
556 if (G_UNLIKELY (self->codec)) {
557 if ((h != self->height) || (w != self->width)) {
558 codec_delete (self);
559 }
560 }
562 self->width = w;
563 self->height = h;
565 codec_data = gst_structure_get_value (s, "codec_data");
567 if (codec_data) {
568 GstBuffer *buffer = gst_value_get_buffer (codec_data);
569 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
570 self->codec_data = gst_buffer_ref (buffer);
571 }
573 return TRUE;
574 }
576 return FALSE;
577 }
579 static gboolean
580 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
581 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
582 {
584 /* allocate params: */
585 self->params = dce_alloc (params_sz);
586 if (G_UNLIKELY (!self->params)) {
587 return FALSE;
588 }
589 self->params->size = params_sz;
590 self->params->maxFrameRate = 30000;
591 self->params->maxBitRate = 10000000;
593 self->params->dataEndianness = XDM_BYTE;
594 self->params->forceChromaFormat = XDM_YUV_420SP;
595 self->params->operatingMode = IVIDEO_DECODE_ONLY;
597 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
598 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
599 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
600 self->params->numInputDataUnits = 0;
601 self->params->numOutputDataUnits = 0;
603 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
604 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
605 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
606 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
608 /* allocate dynParams: */
609 self->dynParams = dce_alloc (dynparams_sz);
610 if (G_UNLIKELY (!self->dynParams)) {
611 return FALSE;
612 }
613 self->dynParams->size = dynparams_sz;
614 self->dynParams->decodeHeader = XDM_DECODE_AU;
615 self->dynParams->displayWidth = 0;
616 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
617 self->dynParams->newFrameFlag = XDAS_TRUE;
619 /* allocate status: */
620 self->status = dce_alloc (status_sz);
621 if (G_UNLIKELY (!self->status)) {
622 return FALSE;
623 }
624 self->status->size = status_sz;
626 /* allocate inBufs/outBufs: */
627 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
628 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
629 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
630 return FALSE;
631 }
633 /* allocate inArgs/outArgs: */
634 self->inArgs = dce_alloc (inargs_sz);
635 self->outArgs = dce_alloc (outargs_sz);
636 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
637 return FALSE;
638 }
639 self->inArgs->size = inargs_sz;
640 self->outArgs->size = outargs_sz;
642 return TRUE;
643 }
645 static GstBuffer *
646 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
647 {
648 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
649 push_input (self, GST_BUFFER_DATA (self->codec_data),
650 GST_BUFFER_SIZE (self->codec_data));
651 }
653 /* just copy entire buffer */
654 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
655 gst_buffer_unref (buf);
657 return NULL;
658 }
660 static gint
661 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
662 gint extended_error, gint status_extended_error)
663 {
664 if (XDM_ISFATALERROR (extended_error))
665 ret = XDM_EFAIL;
666 else
667 ret = XDM_EOK;
669 return ret;
670 }
672 /* GstElement vmethod implementations */
674 static gboolean
675 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
676 {
677 gboolean ret = TRUE;
678 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
679 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
680 GstStructure *s;
681 GstCaps *outcaps = NULL;
682 GstStructure *out_s;
683 gint par_width, par_height;
684 gboolean par_present;
686 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
688 s = gst_caps_get_structure (caps, 0);
689 if (!klass->parse_caps (self, s)) {
690 GST_WARNING_OBJECT (self, "missing required fields");
691 ret = FALSE;
692 goto out;
693 }
695 /* update output/padded sizes */
696 klass->update_buffer_size (self);
698 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
699 self->fps_n = 0;
700 self->fps_d = 1;
701 }
702 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
703 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
704 &par_width, &par_height);
706 outcaps = gst_pad_get_allowed_caps (self->srcpad);
707 if (outcaps) {
708 outcaps = gst_caps_make_writable (outcaps);
709 gst_caps_truncate (outcaps);
710 if (gst_caps_is_empty (outcaps)) {
711 gst_caps_unref (outcaps);
712 outcaps = NULL;
713 }
714 }
716 if (!outcaps) {
717 /* note: default to non-strided for better compatibility with
718 * other gst elements that don't understand stride:
719 */
720 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
721 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
722 }
724 out_s = gst_caps_get_structure (outcaps, 0);
725 gst_structure_set (out_s,
726 "width", G_TYPE_INT, self->padded_width,
727 "height", G_TYPE_INT, self->padded_height,
728 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
729 if (par_present)
730 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
731 par_width, par_height, NULL);
733 if (self->interlaced)
734 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
736 if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
737 if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
738 self->stride = 4096;
739 gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
740 }
741 } else {
742 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
743 0, self->padded_width);
744 }
746 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
747 self->stride, self->padded_height);
749 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
750 self->outsize, self->stride, outcaps);
752 if (!self->first_in_buffer) {
753 /* Caps changed mid stream. We flush the codec to unlock all the potentially
754 * locked buffers. This is needed for downstream sinks that provide a
755 * buffer pool and need to destroy all the outstanding buffers before they
756 * can negotiate new caps (hello v4l2sink).
757 */
758 gst_ducati_viddec_codec_flush (self, FALSE);
759 }
761 /* (re)send a crop event when caps change */
762 self->send_crop_event = TRUE;
764 ret = gst_pad_set_caps (self->srcpad, outcaps);
766 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
768 out:
769 if (outcaps)
770 gst_caps_unref (outcaps);
771 gst_object_unref (self);
773 return ret;
774 }
776 static GstCaps *
777 gst_ducati_viddec_src_getcaps (GstPad * pad)
778 {
779 GstCaps *caps = NULL;
780 GstCaps *outcaps = NULL;
781 int i;
783 caps = GST_PAD_CAPS (pad);
784 if (caps == NULL) {
785 outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
786 return outcaps;
787 }
789 outcaps = gst_caps_new_empty ();
791 /* allow -rowstrided and regular yuv */
792 for (i = 0; i < gst_caps_get_size (caps); i++) {
793 GstStructure *structure;
794 GstStructure *modified_structure;
795 GValue value = { 0 };
797 structure = gst_caps_get_structure (caps, i);
798 gst_caps_append_structure (outcaps, gst_structure_copy (structure));
799 modified_structure = gst_structure_copy (structure);
801 if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
802 gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
803 g_value_init (&value, GST_TYPE_INT_RANGE);
804 gst_value_set_int_range (&value, 0, G_MAXINT);
805 gst_structure_set_value (modified_structure, "rowstride", &value);
806 gst_caps_append_structure (outcaps, modified_structure);
807 g_value_unset (&value);
808 } else {
809 gst_structure_set_name (modified_structure, "video/x-raw-yuv");
810 gst_structure_remove_field (modified_structure, "rowstride");
811 gst_caps_append_structure (outcaps, modified_structure);
812 }
813 }
814 return outcaps;
815 }
817 static gboolean
818 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
819 GstQuery * query, gboolean * forward)
820 {
821 gboolean res = TRUE;
823 switch (GST_QUERY_TYPE (query)) {
824 case GST_QUERY_BUFFERS:
825 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
826 gst_query_set_buffers_count (query, self->min_buffers);
828 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
829 self->padded_width, self->padded_height);
830 gst_query_set_buffers_dimensions (query,
831 self->padded_width, self->padded_height);
832 *forward = FALSE;
833 break;
834 default:
835 break;
836 }
839 return res;
840 }
842 static gboolean
843 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
844 {
845 gboolean res = TRUE, forward = TRUE;
846 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
847 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
849 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
850 res = klass->query (self, pad, query, &forward);
851 if (res && forward)
852 res = gst_pad_query_default (pad, query);
854 return res;
855 }
857 static gboolean
858 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
859 {
860 GstClockTime timestamp, qostime;
861 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
862 gint64 diff;
864 if (self->wait_keyframe) {
865 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
866 GST_INFO_OBJECT (self, "skipping until the next keyframe");
867 return FALSE;
868 }
870 self->wait_keyframe = FALSE;
871 }
873 timestamp = GST_BUFFER_TIMESTAMP (buf);
874 if (self->segment.format != GST_FORMAT_TIME ||
875 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
876 goto no_qos;
878 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
879 goto no_qos;
881 qostime = gst_segment_to_running_time (&self->segment,
882 GST_FORMAT_TIME, timestamp);
883 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
884 /* out of segment */
885 goto no_qos;
887 /* see how our next timestamp relates to the latest qos timestamp. negative
888 * values mean we are early, positive values mean we are too late. */
889 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
891 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
892 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
893 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
894 self->qos_proportion);
896 if (klass->drop_frame (self, buf, diff)) {
897 GST_INFO_OBJECT (self, "dropping frame");
898 return FALSE;
899 }
901 no_qos:
902 return TRUE;
903 }
905 static gboolean
906 gst_ducati_viddec_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
907 gint64 diff)
908 {
909 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
910 GST_BUFFER_FLAG_DELTA_UNIT);
912 if (diff >= 0 && !is_keyframe)
913 return TRUE;
915 return FALSE;
916 }
918 static GstFlowReturn
919 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
920 {
921 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
922 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
923 GstFlowReturn ret = GST_FLOW_OK;
924 Int32 err;
925 GstBuffer *outbuf = NULL;
926 GstCaps *outcaps = NULL;
927 gboolean decode;
929 if (G_UNLIKELY (!self->engine)) {
930 GST_ERROR_OBJECT (self, "no engine");
931 gst_buffer_unref (buf);
932 return GST_FLOW_ERROR;
933 }
935 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
936 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
938 decode = gst_ducati_viddec_do_qos (self, buf);
939 if (!decode) {
940 gst_buffer_unref (buf);
941 return GST_FLOW_OK;
942 }
944 if (!self->need_out_buf)
945 goto have_out_buf;
947 /* do this before creating codec to ensure reverse caps negotiation
948 * happens first:
949 */
950 allocate_buffer:
951 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
952 GST_PAD_CAPS (self->srcpad), &outbuf);
953 if (ret != GST_FLOW_OK) {
954 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
955 gst_flow_get_name (ret));
956 gst_buffer_unref (buf);
957 return ret;
958 }
960 outcaps = GST_BUFFER_CAPS (outbuf);
961 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
962 GstStructure *s;
964 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
965 GST_BUFFER_SIZE (outbuf));
967 s = gst_caps_get_structure (outcaps, 0);
968 gst_structure_get_int (s, "rowstride", &self->stride);
969 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
970 self->stride, self->padded_height);
972 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
973 self->outsize, self->stride, outcaps);
975 gst_pad_set_caps (self->srcpad, outcaps);
977 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
978 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
979 GST_BUFFER_SIZE (outbuf), self->outsize);
980 gst_buffer_unref (outbuf);
981 goto allocate_buffer;
982 }
983 }
985 if (G_UNLIKELY (!self->codec)) {
986 if (!codec_create (self)) {
987 GST_ERROR_OBJECT (self, "could not create codec");
988 gst_buffer_unref (buf);
989 gst_buffer_unref (outbuf);
990 return GST_FLOW_ERROR;
991 }
992 }
994 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
995 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
997 /* Pass new output buffer to the decoder to decode into. Use buffers from the
998 * internal pool while self->first_out_buffer == TRUE in order to simplify
999 * things in case we need to renegotiate */
1000 self->inArgs->inputID =
1001 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1002 if (!self->inArgs->inputID) {
1003 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1004 gst_buffer_unref (buf);
1005 return GST_FLOW_ERROR;
1006 }
1008 have_out_buf:
1009 self->in_size = 0;
1010 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1012 if (ts != GST_CLOCK_TIME_NONE) {
1013 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1014 /* if next buffer has earlier ts than previous, then the ts
1015 * we are getting are definitely decode order (DTS):
1016 */
1017 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1018 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1019 self->ts_may_be_pts = FALSE;
1020 }
1021 self->last_dts = ts;
1022 }
1024 if (self->in_size == 0 && outbuf) {
1025 GST_DEBUG_OBJECT (self, "no input, skipping process");
1026 gst_buffer_unref (outbuf);
1027 return GST_FLOW_OK;
1028 }
1030 self->inArgs->numBytes = self->in_size;
1031 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1032 self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1034 err = codec_process (self, TRUE, FALSE, &ret);
1035 if (err) {
1036 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1037 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1038 return GST_FLOW_ERROR;
1039 }
1040 if (ret != GST_FLOW_OK) {
1041 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1042 gst_flow_get_name (ret));
1043 return ret;
1044 }
1046 self->first_in_buffer = FALSE;
1048 if (self->outArgs->outBufsInUseFlag) {
1049 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1050 self->need_out_buf = FALSE;
1051 } else {
1052 self->need_out_buf = TRUE;
1053 }
1055 if (buf) {
1056 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1057 GST_BUFFER_SIZE (buf));
1058 ts = GST_BUFFER_TIMESTAMP (buf);
1059 goto allocate_buffer;
1060 }
1062 return GST_FLOW_OK;
1063 }
1065 static gboolean
1066 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1067 {
1068 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1069 gboolean ret = TRUE;
1071 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1073 switch (GST_EVENT_TYPE (event)) {
1074 case GST_EVENT_NEWSEGMENT:
1075 {
1076 gboolean update;
1077 GstFormat fmt;
1078 gint64 start, stop, time;
1079 gdouble rate, arate;
1081 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1082 &start, &stop, &time);
1083 gst_segment_set_newsegment_full (&self->segment, update,
1084 rate, arate, fmt, start, stop, time);
1085 break;
1086 }
1087 case GST_EVENT_EOS:
1088 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1089 GST_ERROR_OBJECT (self, "could not flush on eos");
1090 ret = FALSE;
1091 }
1092 break;
1093 case GST_EVENT_FLUSH_STOP:
1094 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1095 GST_ERROR_OBJECT (self, "could not flush");
1096 gst_event_unref (event);
1097 ret = FALSE;
1098 }
1099 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1100 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1101 self->qos_proportion = 1;
1102 self->need_out_buf = TRUE;
1103 break;
1104 default:
1105 break;
1106 }
1108 if (ret)
1109 ret = gst_pad_push_event (self->srcpad, event);
1110 GST_LOG_OBJECT (self, "end");
1112 return ret;
1113 }
1115 static gboolean
1116 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1117 {
1118 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1119 gboolean ret = TRUE;
1121 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1123 switch (GST_EVENT_TYPE (event)) {
1124 case GST_EVENT_QOS:
1125 {
1126 gdouble proportion;
1127 GstClockTimeDiff diff;
1128 GstClockTime timestamp;
1130 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1132 GST_OBJECT_LOCK (self);
1133 self->qos_proportion = proportion;
1134 self->qos_earliest_time = timestamp + 2 * diff;
1135 GST_OBJECT_UNLOCK (self);
1137 GST_DEBUG_OBJECT (self,
1138 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1139 proportion, GST_TIME_ARGS (timestamp), diff);
1141 ret = gst_pad_push_event (self->sinkpad, event);
1142 break;
1143 }
1144 default:
1145 ret = gst_pad_push_event (self->sinkpad, event);
1146 break;
1147 }
1149 GST_LOG_OBJECT (self, "end");
1151 return ret;
1152 }
1154 static GstStateChangeReturn
1155 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1156 {
1157 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1158 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1159 gboolean supported;
1161 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1162 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1163 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1165 switch (transition) {
1166 case GST_STATE_CHANGE_NULL_TO_READY:
1167 if (!engine_open (self)) {
1168 GST_ERROR_OBJECT (self, "could not open");
1169 return GST_STATE_CHANGE_FAILURE;
1170 }
1171 /* try to create/destroy the codec here, it may not be supported */
1172 supported = codec_create (self);
1173 codec_delete (self);
1174 self->codec = NULL;
1175 if (!supported) {
1176 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1177 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1178 engine_close (self);
1179 return GST_STATE_CHANGE_FAILURE;
1180 }
1181 break;
1182 default:
1183 break;
1184 }
1186 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1188 if (ret == GST_STATE_CHANGE_FAILURE)
1189 goto leave;
1191 switch (transition) {
1192 case GST_STATE_CHANGE_PAUSED_TO_READY:
1193 self->interlaced = FALSE;
1194 self->send_crop_event = TRUE;
1195 gst_ducati_viddec_codec_flush (self, FALSE);
1196 break;
1197 case GST_STATE_CHANGE_READY_TO_NULL:
1198 codec_delete (self);
1199 engine_close (self);
1200 break;
1201 default:
1202 break;
1203 }
1205 leave:
1206 GST_LOG_OBJECT (self, "end");
1208 return ret;
1209 }
1211 /* GObject vmethod implementations */
1213 #define VERSION_LENGTH 256
1215 static void
1216 gst_ducati_viddec_get_property (GObject * obj,
1217 guint prop_id, GValue * value, GParamSpec * pspec)
1218 {
1219 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1222 switch (prop_id) {
1223 case PROP_VERSION:{
1224 int err;
1225 char *version = NULL;
1227 if (!self->engine)
1228 engine_open (self);
1230 if (!self->codec)
1231 codec_create (self);
1233 if (self->codec) {
1234 version = dce_alloc (VERSION_LENGTH);
1235 self->status->data.buf = (XDAS_Int8 *) version;
1236 self->status->data.bufSize = VERSION_LENGTH;
1238 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1239 self->dynParams, self->status);
1240 if (err) {
1241 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1242 }
1244 self->status->data.buf = NULL;
1245 self->status->data.bufSize = 0;
1246 }
1248 g_value_set_string (value, version);
1249 if (version)
1250 dce_free (version);
1252 break;
1253 }
1254 default:{
1255 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1256 break;
1257 }
1258 }
1259 }
1261 static void
1262 gst_ducati_viddec_finalize (GObject * obj)
1263 {
1264 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1266 codec_delete (self);
1267 engine_close (self);
1269 if (self->codec_data) {
1270 gst_buffer_unref (self->codec_data);
1271 self->codec_data = NULL;
1272 }
1274 G_OBJECT_CLASS (parent_class)->finalize (obj);
1275 }
1277 static void
1278 gst_ducati_viddec_base_init (gpointer gclass)
1279 {
1280 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1282 gst_element_class_add_pad_template (element_class,
1283 gst_static_pad_template_get (&src_factory));
1284 }
1286 static void
1287 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1288 {
1289 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1290 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1292 gobject_class->get_property =
1293 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1294 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1295 gstelement_class->change_state =
1296 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1298 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1299 klass->allocate_params =
1300 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1301 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1302 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1303 klass->drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_drop_frame);
1304 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1306 g_object_class_install_property (gobject_class, PROP_VERSION,
1307 g_param_spec_string ("version", "Version",
1308 "The codec version string", "",
1309 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1310 }
1312 static void
1313 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1314 {
1315 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1317 self->sinkpad =
1318 gst_pad_new_from_template (gst_element_class_get_pad_template
1319 (gstelement_class, "sink"), "sink");
1320 gst_pad_set_setcaps_function (self->sinkpad,
1321 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1322 gst_pad_set_chain_function (self->sinkpad,
1323 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1324 gst_pad_set_event_function (self->sinkpad,
1325 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1327 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1328 gst_pad_set_event_function (self->srcpad,
1329 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1330 gst_pad_set_query_function (self->srcpad,
1331 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1332 gst_pad_set_getcaps_function (self->srcpad,
1333 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1335 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1336 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1338 self->input_width = 0;
1339 self->input_height = 0;
1340 /* sane defaults in case we need to create codec without caps negotiation
1341 * (for example, to get 'version' property)
1342 */
1343 self->width = 128;
1344 self->height = 128;
1345 self->fps_n = -1;
1346 self->fps_d = -1;
1348 self->first_in_buffer = TRUE;
1349 self->first_out_buffer = TRUE;
1350 self->interlaced = FALSE;
1351 self->send_crop_event = TRUE;
1353 self->dts_ridx = self->dts_widx = 0;
1354 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1355 self->ts_may_be_pts = TRUE;
1356 self->ts_is_pts = FALSE;
1358 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1360 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1362 self->qos_proportion = 1;
1363 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1364 self->wait_keyframe = TRUE;
1366 self->need_out_buf = TRUE;
1367 self->device = NULL;
1368 self->input_bo = NULL;
1369 }