7c718626d6a789dc6f73a239827c0caa17ae8f49
1 #define USE_DTS_PTS_CODE
2 /*
3 * GStreamer
4 * Copyright (c) 2010, Texas Instruments Incorporated
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #include "gstducatividdec.h"
26 #include "gstducatibufferpriv.h"
28 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
29 GST_TYPE_ELEMENT);
31 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
32 GST_PAD_SRC,
33 GST_PAD_ALWAYS,
34 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV_STRIDED ("NV12", "[ 0, max ]"))
35 );
37 enum
38 {
39 PROP_0,
40 PROP_VERSION,
41 };
43 /* helper functions */
45 static void
46 engine_close (GstDucatiVidDec * self)
47 {
48 if (self->engine) {
49 Engine_close (self->engine);
50 self->engine = NULL;
51 }
53 if (self->params) {
54 dce_free (self->params);
55 self->params = NULL;
56 }
58 if (self->dynParams) {
59 dce_free (self->dynParams);
60 self->dynParams = NULL;
61 }
63 if (self->status) {
64 dce_free (self->status);
65 self->status = NULL;
66 }
68 if (self->inBufs) {
69 dce_free (self->inBufs);
70 self->inBufs = NULL;
71 }
73 if (self->outBufs) {
74 dce_free (self->outBufs);
75 self->outBufs = NULL;
76 }
78 if (self->inArgs) {
79 dce_free (self->inArgs);
80 self->inArgs = NULL;
81 }
83 if (self->outArgs) {
84 dce_free (self->outArgs);
85 self->outArgs = NULL;
86 }
88 if (self->device) {
89 dce_deinit (self->device);
90 self->device = NULL;
91 }
92 }
94 static gboolean
95 engine_open (GstDucatiVidDec * self)
96 {
97 gboolean ret;
98 int ec;
100 if (G_UNLIKELY (self->engine)) {
101 return TRUE;
102 }
104 if (self->device == NULL) {
105 self->device = dce_init ();
106 if (self->device == NULL) {
107 GST_ERROR_OBJECT (self, "dce_init() failed");
108 return FALSE;
109 }
110 }
112 GST_DEBUG_OBJECT (self, "opening engine");
114 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
115 if (G_UNLIKELY (!self->engine)) {
116 GST_ERROR_OBJECT (self, "could not create engine");
117 return FALSE;
118 }
120 ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
121 sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
122 sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
123 sizeof (IVIDDEC3_OutArgs));
125 return ret;
126 }
128 static void
129 codec_delete (GstDucatiVidDec * self)
130 {
131 if (self->pool) {
132 gst_drm_buffer_pool_destroy (self->pool);
133 self->pool = NULL;
134 }
136 if (self->codec) {
137 VIDDEC3_delete (self->codec);
138 self->codec = NULL;
139 }
141 if (self->input_bo) {
142 omap_bo_del (self->input_bo);
143 self->input_bo = NULL;
144 }
145 }
147 static gboolean
148 codec_create (GstDucatiVidDec * self)
149 {
150 gint err;
151 const gchar *codec_name;
153 codec_delete (self);
155 if (G_UNLIKELY (!self->engine)) {
156 GST_ERROR_OBJECT (self, "no engine");
157 return FALSE;
158 }
160 /* these need to be set before VIDDEC3_create */
161 self->params->maxWidth = self->width;
162 self->params->maxHeight = self->height;
164 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
166 /* create codec: */
167 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
168 self->codec =
169 VIDDEC3_create (self->engine, (String) codec_name, self->params);
171 if (!self->codec) {
172 return FALSE;
173 }
175 err =
176 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
177 self->status);
178 if (err) {
179 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
180 return FALSE;
181 }
183 self->first_in_buffer = TRUE;
184 self->first_out_buffer = TRUE;
186 /* allocate input buffer and initialize inBufs: */
187 /* FIXME: needed size here has nothing to do with width * height */
188 self->input_bo = omap_bo_new (self->device,
189 self->width * self->height, OMAP_BO_WC);
190 self->input = omap_bo_map (self->input_bo);
191 self->inBufs->numBufs = 1;
192 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
194 return TRUE;
195 }
197 static inline GstBuffer *
198 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
199 {
200 if (G_UNLIKELY (!self->pool)) {
201 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
202 self->padded_width, self->padded_height);
204 GST_DEBUG_OBJECT (self, "creating bufferpool");
205 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
206 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
207 }
208 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
209 }
211 static GstDucatiBufferPriv *
212 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
213 {
214 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
215 if (!priv) {
216 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
217 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
219 /* if it isn't a dmabuf buffer that we can import, then there
220 * is nothing we can do with it:
221 */
222 if (!dmabuf) {
223 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
224 return NULL;
225 }
227 priv = gst_ducati_buffer_priv_new ();
229 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
231 priv->uv_offset = gst_video_format_get_component_offset (format,
232 1, self->stride, self->padded_height);
233 priv->size = gst_video_format_get_size (format,
234 self->stride, self->padded_height);
236 gst_ducati_buffer_priv_set (buf, priv);
237 gst_mini_object_unref (GST_MINI_OBJECT (priv));
238 }
239 return priv;
240 }
242 static XDAS_Int32
243 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
244 gboolean force_internal)
245 {
246 GstDucatiBufferPriv *priv = NULL;
248 if (!force_internal)
249 priv = get_buffer_priv (self, *buf);
251 if (!priv) {
252 GstBuffer *orig = *buf;
254 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
255 *buf = codec_buffer_pool_get (self, NULL);
256 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
257 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
258 gst_buffer_unref (orig);
259 return codec_prepare_outbuf (self, buf, FALSE);
260 }
262 self->outBufs->numBufs = 2;
263 self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
264 self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
265 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
266 self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
267 self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
268 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
270 return (XDAS_Int32) * buf;
271 }
273 static GstBuffer *
274 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
275 {
276 GstBuffer *buf = (GstBuffer *) id;
278 if (buf) {
279 g_hash_table_insert (self->passed_in_bufs, buf, buf);
281 gst_buffer_ref (buf);
282 }
283 return buf;
284 }
286 static void
287 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
288 {
289 GstBuffer *buf = (GstBuffer *) id;
291 if (buf) {
292 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
293 g_hash_table_remove (self->passed_in_bufs, buf);
294 }
295 }
297 static void
298 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
299 {
300 }
302 static gint
303 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
304 GstFlowReturn * flow_ret)
305 {
306 gint err;
307 GstClockTime t;
308 GstBuffer *outbuf = NULL;
309 gint i;
310 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
311 GstFlowReturn ret = GST_FLOW_OK;
312 if (flow_ret)
313 /* never leave flow_ret uninitialized */
314 *flow_ret = GST_FLOW_OK;
316 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
317 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
319 t = gst_util_get_timestamp ();
320 err = VIDDEC3_process (self->codec,
321 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
322 GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
324 if (err) {
325 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
326 err, self->outArgs->extendedError);
327 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
329 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
330 self->dynParams, self->status);
331 if (err) {
332 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
333 err, self->status->extendedError);
334 gst_ducati_log_extended_error_info (self->status->extendedError);
335 }
337 if (flush)
338 err = XDM_EFAIL;
339 else
340 err = klass->handle_error (self, err,
341 self->outArgs->extendedError, self->status->extendedError);
342 }
344 /* we now let the codec decide */
345 self->dynParams->newFrameFlag = XDAS_FALSE;
347 if (err == XDM_EFAIL)
348 goto skip_outbuf_processing;
350 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
351 gboolean interlaced;
353 /* Getting an extra reference for the decoder */
354 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
355 interlaced =
356 self->outArgs->decodedBufs.contentType ==
357 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
359 /* if send is FALSE, don't try to renegotiate as we could be flushing during
360 * a PAUSED->READY state change
361 */
362 if (send && interlaced != self->interlaced) {
363 GstCaps *caps;
365 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
366 "thinks interlaced=%d... trusting codec", self->interlaced,
367 interlaced);
369 self->interlaced = interlaced;
371 caps =
372 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
373 GST_INFO_OBJECT (self, "changing interlace field in caps");
374 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
375 NULL);
376 gst_drm_buffer_pool_set_caps (self->pool, caps);
377 if (!gst_pad_set_caps (self->srcpad, caps)) {
378 GST_ERROR_OBJECT (self,
379 "downstream didn't want to change interlace mode");
380 err = XDM_EFAIL;
381 }
382 gst_caps_unref (caps);
384 /* this buffer still has the old caps so we skip it */
385 send = FALSE;
386 }
388 if (G_UNLIKELY (self->send_crop_event) && send) {
389 gint crop_width, crop_height;
391 /* send region of interest to sink on first buffer: */
392 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
394 crop_width = r->bottomRight.x - r->topLeft.x;
395 crop_height = r->bottomRight.y - r->topLeft.y;
397 if (crop_width > self->input_width)
398 crop_width = self->input_width;
399 if (crop_height > self->input_height)
400 crop_height = self->input_height;
402 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
403 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
404 crop_width, crop_height);
406 gst_pad_push_event (self->srcpad,
407 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
408 crop_width, crop_height));
410 if (self->crop)
411 gst_video_crop_unref (self->crop);
413 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
414 crop_width, crop_height);
416 self->send_crop_event = FALSE;
417 }
419 if (G_UNLIKELY (self->first_out_buffer) && send) {
420 GstDRMBufferPool *pool;
421 self->first_out_buffer = FALSE;
423 /* Destroy the pool so the buffers we used so far are eventually released.
424 * The pool will be recreated if needed.
425 */
426 pool = self->pool;
427 self->pool = NULL;
428 gst_drm_buffer_pool_destroy (pool);
429 }
431 if (send) {
432 GstClockTime ts;
434 ts = GST_BUFFER_TIMESTAMP (outbuf);
436 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
437 i, outbuf, GST_TIME_ARGS (ts));
439 #ifdef USE_DTS_PTS_CODE
440 if (self->ts_may_be_pts) {
441 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
442 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
443 "enabling ts_is_pts");
444 self->ts_is_pts = TRUE;
445 }
446 }
447 #endif
449 self->last_pts = ts;
451 if (self->dts_ridx != self->dts_widx) {
452 ts = self->dts_queue[self->dts_ridx++ % NDTS];
453 }
455 if (self->ts_is_pts) {
456 /* if we have a queued DTS from demuxer, use that instead: */
457 GST_BUFFER_TIMESTAMP (outbuf) = ts;
458 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
459 i, outbuf, GST_TIME_ARGS (ts));
460 }
462 if (GST_BUFFER_CAPS (outbuf) &&
463 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
464 GST_PAD_CAPS (self->srcpad))) {
465 /* this looks a bit scary but it's really just to change the interlace=
466 * field in caps when we start as !interlaced and the codec detects
467 * otherwise */
468 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
469 "interlace mismatch");
470 outbuf = gst_buffer_make_metadata_writable (outbuf);
471 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
472 }
474 if (self->crop)
475 gst_buffer_set_video_crop (outbuf, self->crop);
477 ret = klass->push_output (self, outbuf);
478 if (flow_ret)
479 *flow_ret = ret;
480 if (ret != GST_FLOW_OK) {
481 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
482 /* just unref the remaining buffers (if any) */
483 send = FALSE;
484 }
485 } else {
486 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
487 i, outbuf);
489 gst_buffer_unref (outbuf);
490 }
491 }
493 skip_outbuf_processing:
494 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
495 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
496 }
498 return err;
499 }
501 /** call control(FLUSH), and then process() to pop out all buffers */
502 gboolean
503 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
504 {
505 gint err = FALSE;
507 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
509 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
511 /* note: flush is synchronized against _chain() to avoid calling
512 * the codec from multiple threads
513 */
514 GST_PAD_STREAM_LOCK (self->sinkpad);
516 #ifdef USE_DTS_PTS_CODE
517 self->dts_ridx = self->dts_widx = 0;
518 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
519 self->ts_may_be_pts = TRUE;
520 self->ts_is_pts = FALSE;
521 #endif
522 self->wait_keyframe = TRUE;
523 self->in_size = 0;
524 self->needs_flushing = FALSE;
525 self->need_out_buf = TRUE;
527 if (G_UNLIKELY (self->first_in_buffer)) {
528 goto out;
529 }
531 if (G_UNLIKELY (!self->codec)) {
532 GST_WARNING_OBJECT (self, "no codec");
533 goto out;
534 }
536 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
537 if (err) {
538 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
539 goto out;
540 }
542 self->inBufs->descs[0].bufSize.bytes = 0;
543 self->inBufs->numBufs = 0;
544 self->inArgs->numBytes = 0;
545 self->inArgs->inputID = 0;
547 do {
548 err = codec_process (self, eos, TRUE, NULL);
549 } while (err != XDM_EFAIL);
551 /* We flushed the decoder, we can now remove the buffer that have never been
552 * unrefed in it */
553 g_hash_table_remove_all (self->passed_in_bufs);
555 /* reset outArgs in case we're flushing in codec_process trying to do error
556 * recovery */
557 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
558 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
560 self->dynParams->newFrameFlag = XDAS_TRUE;
562 /* Reset the push buffer */
563 self->inBufs->numBufs = 1;
565 /* on a flush, it is normal (and not an error) for the last _process() call
566 * to return an error..
567 */
568 err = XDM_EOK;
570 out:
571 GST_PAD_STREAM_UNLOCK (self->sinkpad);
572 GST_DEBUG_OBJECT (self, "done");
574 return !err;
575 }
577 /* GstDucatiVidDec vmethod default implementations */
579 static gboolean
580 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
581 {
582 const GValue *codec_data;
583 gint w, h;
585 if (gst_structure_get_int (s, "width", &self->input_width) &&
586 gst_structure_get_int (s, "height", &self->input_height)) {
588 h = ALIGN2 (self->input_height, 4); /* round up to MB */
589 w = ALIGN2 (self->input_width, 4); /* round up to MB */
591 /* if we've already created codec, but the resolution has changed, we
592 * need to re-create the codec:
593 */
594 if (G_UNLIKELY (self->codec)) {
595 if ((h != self->height) || (w != self->width)) {
596 codec_delete (self);
597 }
598 }
600 self->width = w;
601 self->height = h;
603 codec_data = gst_structure_get_value (s, "codec_data");
605 if (codec_data) {
606 GstBuffer *buffer = gst_value_get_buffer (codec_data);
607 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
608 self->codec_data = gst_buffer_ref (buffer);
609 }
611 return TRUE;
612 }
614 return FALSE;
615 }
617 static gboolean
618 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
619 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
620 {
622 /* allocate params: */
623 self->params = dce_alloc (params_sz);
624 if (G_UNLIKELY (!self->params)) {
625 return FALSE;
626 }
627 self->params->size = params_sz;
628 self->params->maxFrameRate = 30000;
629 self->params->maxBitRate = 10000000;
631 self->params->dataEndianness = XDM_BYTE;
632 self->params->forceChromaFormat = XDM_YUV_420SP;
633 self->params->operatingMode = IVIDEO_DECODE_ONLY;
635 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
636 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
637 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
638 self->params->numInputDataUnits = 0;
639 self->params->numOutputDataUnits = 0;
641 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
642 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
643 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
644 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
646 /* allocate dynParams: */
647 self->dynParams = dce_alloc (dynparams_sz);
648 if (G_UNLIKELY (!self->dynParams)) {
649 return FALSE;
650 }
651 self->dynParams->size = dynparams_sz;
652 self->dynParams->decodeHeader = XDM_DECODE_AU;
653 self->dynParams->displayWidth = 0;
654 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
655 self->dynParams->newFrameFlag = XDAS_TRUE;
657 /* allocate status: */
658 self->status = dce_alloc (status_sz);
659 if (G_UNLIKELY (!self->status)) {
660 return FALSE;
661 }
662 memset (self->status, 0, status_sz);
663 self->status->size = status_sz;
665 /* allocate inBufs/outBufs: */
666 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
667 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
668 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
669 return FALSE;
670 }
672 /* allocate inArgs/outArgs: */
673 self->inArgs = dce_alloc (inargs_sz);
674 self->outArgs = dce_alloc (outargs_sz);
675 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
676 return FALSE;
677 }
678 self->inArgs->size = inargs_sz;
679 self->outArgs->size = outargs_sz;
681 return TRUE;
682 }
684 static GstBuffer *
685 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
686 {
687 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
688 push_input (self, GST_BUFFER_DATA (self->codec_data),
689 GST_BUFFER_SIZE (self->codec_data));
690 }
692 /* just copy entire buffer */
693 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
694 gst_buffer_unref (buf);
696 return NULL;
697 }
699 static GstFlowReturn
700 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
701 {
702 return gst_pad_push (self->srcpad, buf);
703 }
705 static gint
706 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
707 gint extended_error, gint status_extended_error)
708 {
709 if (XDM_ISFATALERROR (extended_error))
710 ret = XDM_EFAIL;
711 else
712 ret = XDM_EOK;
714 return ret;
715 }
717 /* GstElement vmethod implementations */
719 static gboolean
720 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
721 {
722 gboolean ret = TRUE;
723 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
724 GstStructure *s;
725 GstCaps *outcaps = NULL;
726 GstStructure *out_s;
727 gint par_width, par_height;
728 gboolean par_present;
730 s = gst_caps_get_structure (caps, 0);
731 if (!klass->parse_caps (self, s)) {
732 GST_WARNING_OBJECT (self, "missing required fields");
733 ret = FALSE;
734 goto out;
735 }
737 /* update output/padded sizes */
738 klass->update_buffer_size (self);
740 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
741 self->fps_n = 0;
742 self->fps_d = 1;
743 }
744 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
745 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
746 &par_width, &par_height);
748 outcaps = gst_pad_get_allowed_caps (self->srcpad);
749 if (outcaps) {
750 outcaps = gst_caps_make_writable (outcaps);
751 gst_caps_truncate (outcaps);
752 if (gst_caps_is_empty (outcaps)) {
753 gst_caps_unref (outcaps);
754 outcaps = NULL;
755 }
756 }
758 if (!outcaps) {
759 /* note: default to non-strided for better compatibility with
760 * other gst elements that don't understand stride:
761 */
762 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
763 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
764 }
766 out_s = gst_caps_get_structure (outcaps, 0);
767 gst_structure_set (out_s,
768 "width", G_TYPE_INT, self->padded_width,
769 "height", G_TYPE_INT, self->padded_height,
770 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
771 if (par_present)
772 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
773 par_width, par_height, NULL);
775 if (self->interlaced)
776 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
778 if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
779 if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
780 self->stride = 4096;
781 gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
782 }
783 } else {
784 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
785 0, self->padded_width);
786 }
788 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
789 self->stride, self->padded_height);
791 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
792 self->outsize, self->stride, outcaps);
794 if (!self->first_in_buffer) {
795 /* Caps changed mid stream. We flush the codec to unlock all the potentially
796 * locked buffers. This is needed for downstream sinks that provide a
797 * buffer pool and need to destroy all the outstanding buffers before they
798 * can negotiate new caps (hello v4l2sink).
799 */
800 gst_ducati_viddec_codec_flush (self, FALSE);
801 }
803 /* (re)send a crop event when caps change */
804 self->send_crop_event = TRUE;
806 ret = gst_pad_set_caps (self->srcpad, outcaps);
808 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
810 out:
811 if (outcaps)
812 gst_caps_unref (outcaps);
814 return ret;
815 }
817 static gboolean
818 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
819 {
820 gboolean ret = TRUE;
821 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
822 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
824 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
826 ret = klass->set_sink_caps (self, caps);
828 gst_object_unref (self);
830 return ret;
831 }
833 static GstCaps *
834 gst_ducati_viddec_src_getcaps (GstPad * pad)
835 {
836 GstCaps *caps = NULL;
837 GstCaps *outcaps = NULL;
838 int i;
840 caps = GST_PAD_CAPS (pad);
841 if (caps == NULL) {
842 outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
843 return outcaps;
844 }
846 outcaps = gst_caps_new_empty ();
848 /* allow -rowstrided and regular yuv */
849 for (i = 0; i < gst_caps_get_size (caps); i++) {
850 GstStructure *structure;
851 GstStructure *modified_structure;
852 GValue value = { 0 };
854 structure = gst_caps_get_structure (caps, i);
855 gst_caps_append_structure (outcaps, gst_structure_copy (structure));
856 modified_structure = gst_structure_copy (structure);
858 if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
859 gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
860 g_value_init (&value, GST_TYPE_INT_RANGE);
861 gst_value_set_int_range (&value, 0, G_MAXINT);
862 gst_structure_set_value (modified_structure, "rowstride", &value);
863 gst_caps_append_structure (outcaps, modified_structure);
864 g_value_unset (&value);
865 } else {
866 gst_structure_set_name (modified_structure, "video/x-raw-yuv");
867 gst_structure_remove_field (modified_structure, "rowstride");
868 gst_caps_append_structure (outcaps, modified_structure);
869 }
870 }
871 return outcaps;
872 }
874 static gboolean
875 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
876 GstQuery * query, gboolean * forward)
877 {
878 gboolean res = TRUE;
880 switch (GST_QUERY_TYPE (query)) {
881 case GST_QUERY_BUFFERS:
882 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
883 gst_query_set_buffers_count (query, self->min_buffers);
885 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
886 self->padded_width, self->padded_height);
887 gst_query_set_buffers_dimensions (query,
888 self->padded_width, self->padded_height);
889 *forward = FALSE;
890 break;
891 default:
892 break;
893 }
896 return res;
897 }
899 static gboolean
900 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
901 {
902 gboolean res = TRUE, forward = TRUE;
903 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
904 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
906 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
907 res = klass->query (self, pad, query, &forward);
908 if (res && forward)
909 res = gst_pad_query_default (pad, query);
911 return res;
912 }
914 static gboolean
915 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
916 {
917 GstClockTime timestamp, qostime;
918 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
919 gint64 diff;
921 if (self->wait_keyframe) {
922 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
923 GST_INFO_OBJECT (self, "skipping until the next keyframe");
924 return FALSE;
925 }
927 self->wait_keyframe = FALSE;
928 }
930 timestamp = GST_BUFFER_TIMESTAMP (buf);
931 if (self->segment.format != GST_FORMAT_TIME ||
932 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
933 goto no_qos;
935 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
936 goto no_qos;
938 qostime = gst_segment_to_running_time (&self->segment,
939 GST_FORMAT_TIME, timestamp);
940 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
941 /* out of segment */
942 goto no_qos;
944 /* see how our next timestamp relates to the latest qos timestamp. negative
945 * values mean we are early, positive values mean we are too late. */
946 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
948 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
949 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
950 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
951 self->qos_proportion);
953 if (klass->can_drop_frame (self, buf, diff)) {
954 GST_INFO_OBJECT (self, "dropping frame");
955 return FALSE;
956 }
958 no_qos:
959 return TRUE;
960 }
962 static gboolean
963 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
964 gint64 diff)
965 {
966 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
967 GST_BUFFER_FLAG_DELTA_UNIT);
969 if (diff >= 0 && !is_keyframe)
970 return TRUE;
972 return FALSE;
973 }
975 static GstFlowReturn
976 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
977 {
978 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
979 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
980 GstFlowReturn ret = GST_FLOW_OK;
981 Int32 err;
982 GstBuffer *outbuf = NULL;
983 GstCaps *outcaps = NULL;
984 gboolean decode;
986 if (G_UNLIKELY (!self->engine)) {
987 GST_ERROR_OBJECT (self, "no engine");
988 gst_buffer_unref (buf);
989 return GST_FLOW_ERROR;
990 }
992 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
993 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
995 decode = gst_ducati_viddec_do_qos (self, buf);
996 if (!decode) {
997 gst_buffer_unref (buf);
998 return GST_FLOW_OK;
999 }
1001 if (!self->need_out_buf)
1002 goto have_out_buf;
1004 /* do this before creating codec to ensure reverse caps negotiation
1005 * happens first:
1006 */
1007 allocate_buffer:
1008 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1009 GST_PAD_CAPS (self->srcpad), &outbuf);
1010 if (ret != GST_FLOW_OK) {
1011 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1012 gst_flow_get_name (ret));
1013 gst_buffer_unref (buf);
1014 return ret;
1015 }
1017 outcaps = GST_BUFFER_CAPS (outbuf);
1018 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1019 GstStructure *s;
1021 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1022 GST_BUFFER_SIZE (outbuf));
1024 s = gst_caps_get_structure (outcaps, 0);
1025 gst_structure_get_int (s, "rowstride", &self->stride);
1026 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1027 self->stride, self->padded_height);
1029 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1030 self->outsize, self->stride, outcaps);
1032 gst_pad_set_caps (self->srcpad, outcaps);
1034 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1035 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1036 GST_BUFFER_SIZE (outbuf), self->outsize);
1037 gst_buffer_unref (outbuf);
1038 goto allocate_buffer;
1039 }
1040 }
1042 if (G_UNLIKELY (!self->codec)) {
1043 if (!codec_create (self)) {
1044 GST_ERROR_OBJECT (self, "could not create codec");
1045 gst_buffer_unref (buf);
1046 gst_buffer_unref (outbuf);
1047 return GST_FLOW_ERROR;
1048 }
1049 }
1051 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1052 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1054 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1055 * internal pool while self->first_out_buffer == TRUE in order to simplify
1056 * things in case we need to renegotiate */
1057 self->inArgs->inputID =
1058 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1059 if (!self->inArgs->inputID) {
1060 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1061 gst_buffer_unref (buf);
1062 return GST_FLOW_ERROR;
1063 }
1065 have_out_buf:
1066 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1068 #ifdef USE_DTS_PTS_CODE
1069 if (ts != GST_CLOCK_TIME_NONE) {
1070 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1071 /* if next buffer has earlier ts than previous, then the ts
1072 * we are getting are definitely decode order (DTS):
1073 */
1074 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1075 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1076 self->ts_may_be_pts = FALSE;
1077 }
1078 self->last_dts = ts;
1079 }
1080 #endif
1082 if (self->in_size == 0 && outbuf) {
1083 GST_DEBUG_OBJECT (self, "no input, skipping process");
1085 gst_buffer_unref (outbuf);
1086 return GST_FLOW_OK;
1087 }
1089 self->inArgs->numBytes = self->in_size;
1090 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1091 self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1093 err = codec_process (self, TRUE, FALSE, &ret);
1094 if (err) {
1095 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1096 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1097 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1099 return GST_FLOW_ERROR;
1100 }
1102 if (ret != GST_FLOW_OK) {
1103 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1104 gst_flow_get_name (ret));
1106 return ret;
1107 }
1109 self->first_in_buffer = FALSE;
1111 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1112 /* The copy could be avoided by playing with the buffer pointer,
1113 but it seems to be rare and for not many bytes */
1114 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1115 self->outArgs->bytesConsumed, self->in_size,
1116 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1117 if (self->outArgs->bytesConsumed > 0) {
1118 if (self->outArgs->bytesConsumed > self->in_size) {
1119 GST_WARNING_OBJECT (self,
1120 "Codec claims to have used more bytes than supplied");
1121 self->in_size = 0;
1122 } else {
1123 if (self->outArgs->bytesConsumed < self->in_size) {
1124 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1125 self->in_size - self->outArgs->bytesConsumed);
1126 }
1127 self->in_size -= self->outArgs->bytesConsumed;
1128 }
1129 }
1130 } else {
1131 self->in_size = 0;
1132 }
1134 if (self->outArgs->outBufsInUseFlag) {
1135 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1136 self->need_out_buf = FALSE;
1137 } else {
1138 self->need_out_buf = TRUE;
1139 }
1141 if (buf) {
1142 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1143 GST_BUFFER_SIZE (buf));
1144 ts = GST_BUFFER_TIMESTAMP (buf);
1145 goto allocate_buffer;
1146 }
1148 if (self->needs_flushing)
1149 gst_ducati_viddec_codec_flush (self, FALSE);
1151 return GST_FLOW_OK;
1152 }
1154 static gboolean
1155 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1156 {
1157 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1158 gboolean ret = TRUE;
1160 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1162 switch (GST_EVENT_TYPE (event)) {
1163 case GST_EVENT_NEWSEGMENT:
1164 {
1165 gboolean update;
1166 GstFormat fmt;
1167 gint64 start, stop, time;
1168 gdouble rate, arate;
1170 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1171 &start, &stop, &time);
1172 gst_segment_set_newsegment_full (&self->segment, update,
1173 rate, arate, fmt, start, stop, time);
1174 break;
1175 }
1176 case GST_EVENT_EOS:
1177 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1178 GST_ERROR_OBJECT (self, "could not flush on eos");
1179 ret = FALSE;
1180 }
1181 break;
1182 case GST_EVENT_FLUSH_STOP:
1183 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1184 GST_ERROR_OBJECT (self, "could not flush");
1185 gst_event_unref (event);
1186 ret = FALSE;
1187 }
1188 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1189 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1190 self->qos_proportion = 1;
1191 self->need_out_buf = TRUE;
1192 break;
1193 default:
1194 break;
1195 }
1197 if (ret)
1198 ret = gst_pad_push_event (self->srcpad, event);
1199 GST_LOG_OBJECT (self, "end");
1201 return ret;
1202 }
1204 static gboolean
1205 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1206 {
1207 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1208 gboolean ret = TRUE;
1210 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1212 switch (GST_EVENT_TYPE (event)) {
1213 case GST_EVENT_QOS:
1214 {
1215 gdouble proportion;
1216 GstClockTimeDiff diff;
1217 GstClockTime timestamp;
1219 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1221 GST_OBJECT_LOCK (self);
1222 self->qos_proportion = proportion;
1223 self->qos_earliest_time = timestamp + 2 * diff;
1224 GST_OBJECT_UNLOCK (self);
1226 GST_DEBUG_OBJECT (self,
1227 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1228 proportion, GST_TIME_ARGS (timestamp), diff);
1230 ret = gst_pad_push_event (self->sinkpad, event);
1231 break;
1232 }
1233 default:
1234 ret = gst_pad_push_event (self->sinkpad, event);
1235 break;
1236 }
1238 GST_LOG_OBJECT (self, "end");
1240 return ret;
1241 }
1243 static GstStateChangeReturn
1244 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1245 {
1246 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1247 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1248 gboolean supported;
1250 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1251 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1252 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1254 switch (transition) {
1255 case GST_STATE_CHANGE_NULL_TO_READY:
1256 if (!engine_open (self)) {
1257 GST_ERROR_OBJECT (self, "could not open");
1258 return GST_STATE_CHANGE_FAILURE;
1259 }
1260 /* try to create/destroy the codec here, it may not be supported */
1261 supported = codec_create (self);
1262 codec_delete (self);
1263 self->codec = NULL;
1264 if (!supported) {
1265 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1266 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1267 engine_close (self);
1268 return GST_STATE_CHANGE_FAILURE;
1269 }
1270 break;
1271 default:
1272 break;
1273 }
1275 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1277 if (ret == GST_STATE_CHANGE_FAILURE)
1278 goto leave;
1280 switch (transition) {
1281 case GST_STATE_CHANGE_PAUSED_TO_READY:
1282 self->interlaced = FALSE;
1283 self->send_crop_event = TRUE;
1284 gst_ducati_viddec_codec_flush (self, FALSE);
1285 break;
1286 case GST_STATE_CHANGE_READY_TO_NULL:
1287 codec_delete (self);
1288 engine_close (self);
1289 break;
1290 default:
1291 break;
1292 }
1294 leave:
1295 GST_LOG_OBJECT (self, "end");
1297 return ret;
1298 }
1300 /* GObject vmethod implementations */
1302 #define VERSION_LENGTH 256
1304 static void
1305 gst_ducati_viddec_get_property (GObject * obj,
1306 guint prop_id, GValue * value, GParamSpec * pspec)
1307 {
1308 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1311 switch (prop_id) {
1312 case PROP_VERSION:{
1313 int err;
1314 char *version = NULL;
1316 if (!self->engine)
1317 engine_open (self);
1319 if (!self->codec)
1320 codec_create (self);
1322 if (self->codec) {
1323 version = dce_alloc (VERSION_LENGTH);
1324 self->status->data.buf = (XDAS_Int8 *) version;
1325 self->status->data.bufSize = VERSION_LENGTH;
1327 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1328 self->dynParams, self->status);
1329 if (err) {
1330 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1331 }
1333 self->status->data.buf = NULL;
1334 self->status->data.bufSize = 0;
1335 }
1337 g_value_set_string (value, version);
1338 if (version)
1339 dce_free (version);
1341 break;
1342 }
1343 default:{
1344 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1345 break;
1346 }
1347 }
1348 }
1350 static void
1351 gst_ducati_viddec_finalize (GObject * obj)
1352 {
1353 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1355 codec_delete (self);
1356 engine_close (self);
1358 /* Will unref the remaining buffers if needed */
1359 g_hash_table_unref (self->passed_in_bufs);
1360 if (self->codec_data) {
1361 gst_buffer_unref (self->codec_data);
1362 self->codec_data = NULL;
1363 }
1365 G_OBJECT_CLASS (parent_class)->finalize (obj);
1366 }
1368 static void
1369 gst_ducati_viddec_base_init (gpointer gclass)
1370 {
1371 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1373 gst_element_class_add_pad_template (element_class,
1374 gst_static_pad_template_get (&src_factory));
1375 }
1377 static void
1378 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1379 {
1380 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1381 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1383 gobject_class->get_property =
1384 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1385 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1386 gstelement_class->change_state =
1387 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1389 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1390 klass->allocate_params =
1391 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1392 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1393 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1394 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1395 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1396 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1397 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1398 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1400 g_object_class_install_property (gobject_class, PROP_VERSION,
1401 g_param_spec_string ("version", "Version",
1402 "The codec version string", "",
1403 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1404 }
1406 static void
1407 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1408 {
1409 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1411 self->sinkpad =
1412 gst_pad_new_from_template (gst_element_class_get_pad_template
1413 (gstelement_class, "sink"), "sink");
1414 gst_pad_set_setcaps_function (self->sinkpad,
1415 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1416 gst_pad_set_chain_function (self->sinkpad,
1417 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1418 gst_pad_set_event_function (self->sinkpad,
1419 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1421 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1422 gst_pad_set_event_function (self->srcpad,
1423 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1424 gst_pad_set_query_function (self->srcpad,
1425 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1426 gst_pad_set_getcaps_function (self->srcpad,
1427 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1429 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1430 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1432 self->input_width = 0;
1433 self->input_height = 0;
1434 /* sane defaults in case we need to create codec without caps negotiation
1435 * (for example, to get 'version' property)
1436 */
1437 self->width = 128;
1438 self->height = 128;
1439 self->fps_n = -1;
1440 self->fps_d = -1;
1442 self->first_in_buffer = TRUE;
1443 self->first_out_buffer = TRUE;
1444 self->interlaced = FALSE;
1445 self->send_crop_event = TRUE;
1447 #ifdef USE_DTS_PTS_CODE
1448 self->dts_ridx = self->dts_widx = 0;
1449 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1450 self->ts_may_be_pts = TRUE;
1451 self->ts_is_pts = FALSE;
1452 #endif
1454 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1456 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1458 self->qos_proportion = 1;
1459 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1460 self->wait_keyframe = TRUE;
1462 self->need_out_buf = TRUE;
1463 self->device = NULL;
1464 self->input_bo = NULL;
1466 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1467 NULL, (GDestroyNotify) gst_buffer_unref);
1468 }