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 PROP_MAX_REORDER_FRAMES,
42 };
44 /* helper functions */
46 static void
47 engine_close (GstDucatiVidDec * self)
48 {
49 if (self->engine) {
50 Engine_close (self->engine);
51 self->engine = NULL;
52 }
54 if (self->params) {
55 dce_free (self->params);
56 self->params = NULL;
57 }
59 if (self->dynParams) {
60 dce_free (self->dynParams);
61 self->dynParams = NULL;
62 }
64 if (self->status) {
65 dce_free (self->status);
66 self->status = NULL;
67 }
69 if (self->inBufs) {
70 dce_free (self->inBufs);
71 self->inBufs = NULL;
72 }
74 if (self->outBufs) {
75 dce_free (self->outBufs);
76 self->outBufs = NULL;
77 }
79 if (self->inArgs) {
80 dce_free (self->inArgs);
81 self->inArgs = NULL;
82 }
84 if (self->outArgs) {
85 dce_free (self->outArgs);
86 self->outArgs = NULL;
87 }
89 if (self->device) {
90 dce_deinit (self->device);
91 self->device = NULL;
92 }
93 }
95 static gboolean
96 engine_open (GstDucatiVidDec * self)
97 {
98 gboolean ret;
99 int ec;
101 if (G_UNLIKELY (self->engine)) {
102 return TRUE;
103 }
105 if (self->device == NULL) {
106 self->device = dce_init ();
107 if (self->device == NULL) {
108 GST_ERROR_OBJECT (self, "dce_init() failed");
109 return FALSE;
110 }
111 }
113 GST_DEBUG_OBJECT (self, "opening engine");
115 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
116 if (G_UNLIKELY (!self->engine)) {
117 GST_ERROR_OBJECT (self, "could not create engine");
118 return FALSE;
119 }
121 ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
122 sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
123 sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
124 sizeof (IVIDDEC3_OutArgs));
126 return ret;
127 }
129 static void
130 codec_delete (GstDucatiVidDec * self)
131 {
132 if (self->pool) {
133 gst_drm_buffer_pool_destroy (self->pool);
134 self->pool = NULL;
135 }
137 if (self->codec) {
138 VIDDEC3_delete (self->codec);
139 self->codec = NULL;
140 }
142 if (self->input_bo) {
143 omap_bo_del (self->input_bo);
144 self->input_bo = NULL;
145 }
146 }
148 static gboolean
149 codec_create (GstDucatiVidDec * self)
150 {
151 gint err;
152 const gchar *codec_name;
154 codec_delete (self);
156 if (G_UNLIKELY (!self->engine)) {
157 GST_ERROR_OBJECT (self, "no engine");
158 return FALSE;
159 }
161 /* these need to be set before VIDDEC3_create */
162 self->params->maxWidth = self->width;
163 self->params->maxHeight = self->height;
165 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
167 /* create codec: */
168 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
169 self->codec =
170 VIDDEC3_create (self->engine, (String) codec_name, self->params);
172 if (!self->codec) {
173 return FALSE;
174 }
176 err =
177 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
178 self->status);
179 if (err) {
180 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
181 return FALSE;
182 }
184 self->first_in_buffer = TRUE;
185 self->first_out_buffer = TRUE;
187 /* allocate input buffer and initialize inBufs: */
188 /* FIXME: needed size here has nothing to do with width * height */
189 self->input_bo = omap_bo_new (self->device,
190 self->width * self->height, OMAP_BO_WC);
191 self->input = omap_bo_map (self->input_bo);
192 self->inBufs->numBufs = 1;
193 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
195 return TRUE;
196 }
198 static inline GstBuffer *
199 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
200 {
201 if (G_UNLIKELY (!self->pool)) {
202 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
203 self->padded_width, self->padded_height);
205 GST_DEBUG_OBJECT (self, "creating bufferpool");
206 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
207 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
208 }
209 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
210 }
212 static GstDucatiBufferPriv *
213 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
214 {
215 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
216 if (!priv) {
217 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
218 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
220 /* if it isn't a dmabuf buffer that we can import, then there
221 * is nothing we can do with it:
222 */
223 if (!dmabuf) {
224 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
225 return NULL;
226 }
228 priv = gst_ducati_buffer_priv_new ();
230 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
232 priv->uv_offset = gst_video_format_get_component_offset (format,
233 1, self->stride, self->padded_height);
234 priv->size = gst_video_format_get_size (format,
235 self->stride, self->padded_height);
237 gst_ducati_buffer_priv_set (buf, priv);
238 gst_mini_object_unref (GST_MINI_OBJECT (priv));
239 }
240 return priv;
241 }
243 static XDAS_Int32
244 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
245 gboolean force_internal)
246 {
247 GstDucatiBufferPriv *priv = NULL;
249 if (!force_internal)
250 priv = get_buffer_priv (self, *buf);
252 if (!priv) {
253 GstBuffer *orig = *buf;
255 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
256 *buf = codec_buffer_pool_get (self, NULL);
257 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
258 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
259 gst_buffer_unref (orig);
260 return codec_prepare_outbuf (self, buf, FALSE);
261 }
263 self->outBufs->numBufs = 2;
264 self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
265 self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
266 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
267 self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
268 self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
269 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
271 return (XDAS_Int32) * buf;
272 }
274 static GstBuffer *
275 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
276 {
277 GstBuffer *buf = (GstBuffer *) id;
279 if (buf) {
280 g_hash_table_insert (self->passed_in_bufs, buf, buf);
282 gst_buffer_ref (buf);
283 }
284 return buf;
285 }
287 static void
288 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
289 {
290 GstBuffer *buf = (GstBuffer *) id;
292 if (buf) {
293 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
294 g_hash_table_remove (self->passed_in_bufs, buf);
295 }
296 }
298 static GstFlowReturn
299 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
300 {
301 guint64 earliest_order = G_MAXUINT64;
302 guint earliest_index = 0, i;
303 GstBuffer *buf;
305 if (self->backlog_nframes == 0)
306 return GST_FLOW_OK;
308 /* work out which frame has the earliest poc */
309 for (i = 0; i < self->backlog_nframes; i++) {
310 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
311 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
312 earliest_order = order;
313 earliest_index = i;
314 }
315 }
317 /* send it, giving away the ref */
318 buf = self->backlog_frames[earliest_index];
319 self->backlog_frames[earliest_index] =
320 self->backlog_frames[--self->backlog_nframes];
321 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
322 buf);
323 return gst_pad_push (self->srcpad, buf);
324 }
326 static void
327 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
328 {
329 /* push everything on the backlog, ignoring errors */
330 while (self->backlog_nframes > 0) {
331 gst_ducati_viddec_push_earliest (self);
332 }
333 }
335 static gint
336 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
337 GstFlowReturn * flow_ret)
338 {
339 gint err;
340 GstClockTime t;
341 GstBuffer *outbuf = NULL;
342 gint i;
343 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
344 GstFlowReturn ret = GST_FLOW_OK;
345 if (flow_ret)
346 /* never leave flow_ret uninitialized */
347 *flow_ret = GST_FLOW_OK;
349 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
350 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
352 GST_DEBUG ("Calling VIDENC2_process");
353 t = gst_util_get_timestamp ();
354 err = VIDDEC3_process (self->codec,
355 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
356 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
357 (gint) (t / 1000000));
359 if (err) {
360 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
361 err, self->outArgs->extendedError);
362 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
364 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
365 self->dynParams, self->status);
366 if (err) {
367 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
368 err, self->status->extendedError);
369 gst_ducati_log_extended_error_info (self->status->extendedError);
370 }
372 if (flush)
373 err = XDM_EFAIL;
374 else
375 err = klass->handle_error (self, err,
376 self->outArgs->extendedError, self->status->extendedError);
377 }
379 /* we now let the codec decide */
380 self->dynParams->newFrameFlag = XDAS_FALSE;
382 if (err == XDM_EFAIL)
383 goto skip_outbuf_processing;
385 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
386 gboolean interlaced;
388 /* Getting an extra reference for the decoder */
389 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
390 interlaced =
391 self->outArgs->decodedBufs.contentType ==
392 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
394 /* if send is FALSE, don't try to renegotiate as we could be flushing during
395 * a PAUSED->READY state change
396 */
397 if (send && interlaced != self->interlaced) {
398 GstCaps *caps;
400 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
401 "thinks interlaced=%d... trusting codec", self->interlaced,
402 interlaced);
404 self->interlaced = interlaced;
406 caps =
407 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
408 GST_INFO_OBJECT (self, "changing interlace field in caps");
409 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
410 NULL);
411 gst_drm_buffer_pool_set_caps (self->pool, caps);
412 if (!gst_pad_set_caps (self->srcpad, caps)) {
413 GST_ERROR_OBJECT (self,
414 "downstream didn't want to change interlace mode");
415 err = XDM_EFAIL;
416 }
417 gst_caps_unref (caps);
419 /* this buffer still has the old caps so we skip it */
420 send = FALSE;
421 }
423 if (G_UNLIKELY (self->send_crop_event) && send) {
424 gint crop_width, crop_height;
426 /* send region of interest to sink on first buffer: */
427 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
429 crop_width = r->bottomRight.x - r->topLeft.x;
430 crop_height = r->bottomRight.y - r->topLeft.y;
432 if (crop_width > self->input_width)
433 crop_width = self->input_width;
434 if (crop_height > self->input_height)
435 crop_height = self->input_height;
437 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
438 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
439 crop_width, crop_height);
441 gst_pad_push_event (self->srcpad,
442 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
443 crop_width, crop_height));
445 if (self->crop)
446 gst_video_crop_unref (self->crop);
448 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
449 crop_width, crop_height);
451 self->send_crop_event = FALSE;
452 }
454 if (G_UNLIKELY (self->first_out_buffer) && send) {
455 GstDRMBufferPool *pool;
456 self->first_out_buffer = FALSE;
458 /* Destroy the pool so the buffers we used so far are eventually released.
459 * The pool will be recreated if needed.
460 */
461 pool = self->pool;
462 self->pool = NULL;
463 gst_drm_buffer_pool_destroy (pool);
464 }
466 if (send) {
467 GstClockTime ts;
469 ts = GST_BUFFER_TIMESTAMP (outbuf);
471 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
472 i, outbuf, GST_TIME_ARGS (ts));
474 #ifdef USE_DTS_PTS_CODE
475 if (self->ts_may_be_pts) {
476 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
477 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
478 "enabling ts_is_pts");
479 self->ts_is_pts = TRUE;
480 }
481 }
482 #endif
484 self->last_pts = ts;
486 if (self->dts_ridx != self->dts_widx) {
487 ts = self->dts_queue[self->dts_ridx++ % NDTS];
488 }
490 if (self->ts_is_pts) {
491 /* if we have a queued DTS from demuxer, use that instead: */
492 GST_BUFFER_TIMESTAMP (outbuf) = ts;
493 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
494 i, outbuf, GST_TIME_ARGS (ts));
495 }
497 if (GST_BUFFER_CAPS (outbuf) &&
498 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
499 GST_PAD_CAPS (self->srcpad))) {
500 /* this looks a bit scary but it's really just to change the interlace=
501 * field in caps when we start as !interlaced and the codec detects
502 * otherwise */
503 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
504 "interlace mismatch");
505 outbuf = gst_buffer_make_metadata_writable (outbuf);
506 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
507 }
509 if (self->crop)
510 gst_buffer_set_video_crop (outbuf, self->crop);
512 ret = klass->push_output (self, outbuf);
513 if (flow_ret)
514 *flow_ret = ret;
515 if (ret != GST_FLOW_OK) {
516 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
517 /* just unref the remaining buffers (if any) */
518 send = FALSE;
519 }
520 } else {
521 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
522 i, outbuf);
524 gst_buffer_unref (outbuf);
525 }
526 }
528 skip_outbuf_processing:
529 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
530 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
531 }
533 return err;
534 }
536 /** call control(FLUSH), and then process() to pop out all buffers */
537 gboolean
538 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
539 {
540 gint err = FALSE;
542 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
544 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
546 /* note: flush is synchronized against _chain() to avoid calling
547 * the codec from multiple threads
548 */
549 GST_PAD_STREAM_LOCK (self->sinkpad);
551 #ifdef USE_DTS_PTS_CODE
552 self->dts_ridx = self->dts_widx = 0;
553 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
554 self->ts_may_be_pts = TRUE;
555 self->ts_is_pts = FALSE;
556 #endif
557 self->wait_keyframe = TRUE;
558 self->in_size = 0;
559 self->needs_flushing = FALSE;
560 self->need_out_buf = TRUE;
562 if (G_UNLIKELY (self->first_in_buffer)) {
563 goto out;
564 }
566 if (G_UNLIKELY (!self->codec)) {
567 GST_WARNING_OBJECT (self, "no codec");
568 goto out;
569 }
571 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
572 if (err) {
573 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
574 goto out;
575 }
577 self->inBufs->descs[0].bufSize.bytes = 0;
578 self->inBufs->numBufs = 0;
579 self->inArgs->numBytes = 0;
580 self->inArgs->inputID = 0;
581 self->outBufs->numBufs = 0;
583 do {
584 err = codec_process (self, eos, TRUE, NULL);
585 } while (err != XDM_EFAIL);
587 /* We flushed the decoder, we can now remove the buffer that have never been
588 * unrefed in it */
589 g_hash_table_remove_all (self->passed_in_bufs);
591 /* reset outArgs in case we're flushing in codec_process trying to do error
592 * recovery */
593 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
594 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
596 self->dynParams->newFrameFlag = XDAS_TRUE;
598 /* Reset the push buffer and YUV buffers */
599 self->inBufs->numBufs = 1;
600 self->outBufs->numBufs = 2;
602 /* on a flush, it is normal (and not an error) for the last _process() call
603 * to return an error..
604 */
605 err = XDM_EOK;
607 out:
608 GST_PAD_STREAM_UNLOCK (self->sinkpad);
609 GST_DEBUG_OBJECT (self, "done");
611 return !err;
612 }
614 /* GstDucatiVidDec vmethod default implementations */
616 static gboolean
617 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
618 {
619 const GValue *codec_data;
620 gint w, h;
622 if (gst_structure_get_int (s, "width", &self->input_width) &&
623 gst_structure_get_int (s, "height", &self->input_height)) {
625 h = ALIGN2 (self->input_height, 4); /* round up to MB */
626 w = ALIGN2 (self->input_width, 4); /* round up to MB */
628 /* if we've already created codec, but the resolution has changed, we
629 * need to re-create the codec:
630 */
631 if (G_UNLIKELY (self->codec)) {
632 if ((h != self->height) || (w != self->width)) {
633 codec_delete (self);
634 }
635 }
637 self->width = w;
638 self->height = h;
640 codec_data = gst_structure_get_value (s, "codec_data");
642 if (codec_data) {
643 GstBuffer *buffer = gst_value_get_buffer (codec_data);
644 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
645 self->codec_data = gst_buffer_ref (buffer);
646 }
648 return TRUE;
649 }
651 return FALSE;
652 }
654 static gboolean
655 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
656 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
657 {
659 /* allocate params: */
660 self->params = dce_alloc (params_sz);
661 if (G_UNLIKELY (!self->params)) {
662 return FALSE;
663 }
664 self->params->size = params_sz;
665 self->params->maxFrameRate = 30000;
666 self->params->maxBitRate = 10000000;
668 self->params->dataEndianness = XDM_BYTE;
669 self->params->forceChromaFormat = XDM_YUV_420SP;
670 self->params->operatingMode = IVIDEO_DECODE_ONLY;
672 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
673 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
674 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
675 self->params->numInputDataUnits = 0;
676 self->params->numOutputDataUnits = 0;
678 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
679 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
680 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
681 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
683 /* allocate dynParams: */
684 self->dynParams = dce_alloc (dynparams_sz);
685 if (G_UNLIKELY (!self->dynParams)) {
686 return FALSE;
687 }
688 self->dynParams->size = dynparams_sz;
689 self->dynParams->decodeHeader = XDM_DECODE_AU;
690 self->dynParams->displayWidth = 0;
691 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
692 self->dynParams->newFrameFlag = XDAS_TRUE;
694 /* allocate status: */
695 self->status = dce_alloc (status_sz);
696 if (G_UNLIKELY (!self->status)) {
697 return FALSE;
698 }
699 memset (self->status, 0, status_sz);
700 self->status->size = status_sz;
702 /* allocate inBufs/outBufs: */
703 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
704 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
705 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
706 return FALSE;
707 }
709 /* allocate inArgs/outArgs: */
710 self->inArgs = dce_alloc (inargs_sz);
711 self->outArgs = dce_alloc (outargs_sz);
712 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
713 return FALSE;
714 }
715 self->inArgs->size = inargs_sz;
716 self->outArgs->size = outargs_sz;
718 return TRUE;
719 }
721 static GstBuffer *
722 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
723 {
724 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
725 push_input (self, GST_BUFFER_DATA (self->codec_data),
726 GST_BUFFER_SIZE (self->codec_data));
727 }
729 /* just copy entire buffer */
730 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
731 gst_buffer_unref (buf);
733 return NULL;
734 }
736 static GstFlowReturn
737 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
738 {
739 GstFlowReturn ret = GST_FLOW_OK;
741 /* if no reordering info was set, just send the buffer */
742 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
743 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
744 return gst_pad_push (self->srcpad, buf);
745 }
747 /* add the frame to the list, the array will own the ref */
748 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
749 self->backlog_frames[self->backlog_nframes++] = buf;
751 /* push till we have no more than the max needed, or error */
752 while (self->backlog_nframes > self->backlog_maxframes) {
753 ret = gst_ducati_viddec_push_earliest (self);
754 if (ret != GST_FLOW_OK)
755 break;
756 }
758 return ret;
759 }
761 static gint
762 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
763 gint extended_error, gint status_extended_error)
764 {
765 if (XDM_ISFATALERROR (extended_error))
766 ret = XDM_EFAIL;
767 else
768 ret = XDM_EOK;
770 return ret;
771 }
773 /* GstElement vmethod implementations */
775 static gboolean
776 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
777 {
778 gboolean ret = TRUE;
779 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
780 GstStructure *s;
781 GstCaps *outcaps = NULL;
782 GstStructure *out_s;
783 gint par_width, par_height;
784 gboolean par_present;
786 s = gst_caps_get_structure (caps, 0);
787 if (!klass->parse_caps (self, s)) {
788 GST_WARNING_OBJECT (self, "missing required fields");
789 ret = FALSE;
790 goto out;
791 }
793 /* update output/padded sizes */
794 klass->update_buffer_size (self);
796 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
797 self->fps_n = 0;
798 self->fps_d = 1;
799 }
800 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
801 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
802 &par_width, &par_height);
804 outcaps = gst_pad_get_allowed_caps (self->srcpad);
805 if (outcaps) {
806 outcaps = gst_caps_make_writable (outcaps);
807 gst_caps_truncate (outcaps);
808 if (gst_caps_is_empty (outcaps)) {
809 gst_caps_unref (outcaps);
810 outcaps = NULL;
811 }
812 }
814 if (!outcaps) {
815 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
816 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
817 }
819 out_s = gst_caps_get_structure (outcaps, 0);
820 gst_structure_set (out_s,
821 "width", G_TYPE_INT, self->padded_width,
822 "height", G_TYPE_INT, self->padded_height,
823 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
824 if (par_present)
825 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
826 par_width, par_height, NULL);
828 if (self->interlaced)
829 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
831 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
832 0, self->padded_width);
834 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
835 self->stride, self->padded_height);
837 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
838 self->outsize, self->stride, outcaps);
840 if (!self->first_in_buffer) {
841 /* Caps changed mid stream. We flush the codec to unlock all the potentially
842 * locked buffers. This is needed for downstream sinks that provide a
843 * buffer pool and need to destroy all the outstanding buffers before they
844 * can negotiate new caps (hello v4l2sink).
845 */
846 gst_ducati_viddec_codec_flush (self, FALSE);
847 }
849 /* (re)send a crop event when caps change */
850 self->send_crop_event = TRUE;
852 ret = gst_pad_set_caps (self->srcpad, outcaps);
854 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
856 /* default to no reordering */
857 self->backlog_maxframes = 0;
859 out:
860 if (outcaps)
861 gst_caps_unref (outcaps);
863 return ret;
864 }
866 static gboolean
867 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
868 {
869 gboolean ret = TRUE;
870 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
871 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
873 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
875 ret = klass->set_sink_caps (self, caps);
877 gst_object_unref (self);
879 return ret;
880 }
882 static GstCaps *
883 gst_ducati_viddec_src_getcaps (GstPad * pad)
884 {
885 GstCaps *caps = NULL;
887 caps = GST_PAD_CAPS (pad);
888 if (caps == NULL) {
889 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
890 } else {
891 return gst_caps_copy (caps);
892 }
893 }
895 static gboolean
896 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
897 GstQuery * query, gboolean * forward)
898 {
899 gboolean res = TRUE;
901 switch (GST_QUERY_TYPE (query)) {
902 case GST_QUERY_BUFFERS:
903 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
904 gst_query_set_buffers_count (query, self->min_buffers);
906 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
907 self->padded_width, self->padded_height);
908 gst_query_set_buffers_dimensions (query,
909 self->padded_width, self->padded_height);
910 *forward = FALSE;
911 break;
912 default:
913 break;
914 }
917 return res;
918 }
920 static gboolean
921 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
922 {
923 gboolean res = TRUE, forward = TRUE;
924 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
925 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
927 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
928 res = klass->query (self, pad, query, &forward);
929 if (res && forward)
930 res = gst_pad_query_default (pad, query);
932 return res;
933 }
935 static gboolean
936 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
937 {
938 GstClockTime timestamp, qostime;
939 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
940 gint64 diff;
942 if (self->wait_keyframe) {
943 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
944 GST_INFO_OBJECT (self, "skipping until the next keyframe");
945 return FALSE;
946 }
948 self->wait_keyframe = FALSE;
949 }
951 timestamp = GST_BUFFER_TIMESTAMP (buf);
952 if (self->segment.format != GST_FORMAT_TIME ||
953 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
954 goto no_qos;
956 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
957 goto no_qos;
959 qostime = gst_segment_to_running_time (&self->segment,
960 GST_FORMAT_TIME, timestamp);
961 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
962 /* out of segment */
963 goto no_qos;
965 /* see how our next timestamp relates to the latest qos timestamp. negative
966 * values mean we are early, positive values mean we are too late. */
967 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
969 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
970 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
971 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
972 self->qos_proportion);
974 if (klass->can_drop_frame (self, buf, diff)) {
975 GST_INFO_OBJECT (self, "dropping frame");
976 return FALSE;
977 }
979 no_qos:
980 return TRUE;
981 }
983 static gboolean
984 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
985 gint64 diff)
986 {
987 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
988 GST_BUFFER_FLAG_DELTA_UNIT);
990 if (diff >= 0 && !is_keyframe)
991 return TRUE;
993 return FALSE;
994 }
996 static GstFlowReturn
997 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
998 {
999 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1000 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1001 GstFlowReturn ret = GST_FLOW_OK;
1002 Int32 err;
1003 GstBuffer *outbuf = NULL;
1004 GstCaps *outcaps = NULL;
1005 gboolean decode;
1007 if (G_UNLIKELY (!self->engine)) {
1008 GST_ERROR_OBJECT (self, "no engine");
1009 gst_buffer_unref (buf);
1010 return GST_FLOW_ERROR;
1011 }
1013 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1014 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1016 decode = gst_ducati_viddec_do_qos (self, buf);
1017 if (!decode) {
1018 gst_buffer_unref (buf);
1019 return GST_FLOW_OK;
1020 }
1022 if (!self->need_out_buf)
1023 goto have_out_buf;
1025 /* do this before creating codec to ensure reverse caps negotiation
1026 * happens first:
1027 */
1028 allocate_buffer:
1029 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1030 GST_PAD_CAPS (self->srcpad), &outbuf);
1031 if (ret != GST_FLOW_OK) {
1032 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1033 gst_flow_get_name (ret));
1034 gst_buffer_unref (buf);
1035 return ret;
1036 }
1038 outcaps = GST_BUFFER_CAPS (outbuf);
1039 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1040 GstStructure *s;
1042 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1043 GST_BUFFER_SIZE (outbuf));
1045 s = gst_caps_get_structure (outcaps, 0);
1046 gst_structure_get_int (s, "rowstride", &self->stride);
1047 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1048 self->stride, self->padded_height);
1050 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1051 self->outsize, self->stride, outcaps);
1053 gst_pad_set_caps (self->srcpad, outcaps);
1055 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1056 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1057 GST_BUFFER_SIZE (outbuf), self->outsize);
1058 gst_buffer_unref (outbuf);
1059 goto allocate_buffer;
1060 }
1061 }
1063 if (G_UNLIKELY (!self->codec)) {
1064 if (!codec_create (self)) {
1065 GST_ERROR_OBJECT (self, "could not create codec");
1066 gst_buffer_unref (buf);
1067 gst_buffer_unref (outbuf);
1068 return GST_FLOW_ERROR;
1069 }
1070 }
1072 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1073 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1075 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1076 * internal pool while self->first_out_buffer == TRUE in order to simplify
1077 * things in case we need to renegotiate */
1078 self->inArgs->inputID =
1079 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1080 if (!self->inArgs->inputID) {
1081 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1082 gst_buffer_unref (buf);
1083 return GST_FLOW_ERROR;
1084 }
1085 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1087 have_out_buf:
1088 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1090 #ifdef USE_DTS_PTS_CODE
1091 if (ts != GST_CLOCK_TIME_NONE) {
1092 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1093 /* if next buffer has earlier ts than previous, then the ts
1094 * we are getting are definitely decode order (DTS):
1095 */
1096 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1097 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1098 self->ts_may_be_pts = FALSE;
1099 }
1100 self->last_dts = ts;
1101 }
1102 #endif
1104 if (self->in_size == 0 && outbuf) {
1105 GST_DEBUG_OBJECT (self, "no input, skipping process");
1107 gst_buffer_unref (outbuf);
1108 return GST_FLOW_OK;
1109 }
1111 self->inArgs->numBytes = self->in_size;
1112 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1113 self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1115 err = codec_process (self, TRUE, FALSE, &ret);
1116 if (err) {
1117 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1118 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1119 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1121 return GST_FLOW_ERROR;
1122 }
1124 if (ret != GST_FLOW_OK) {
1125 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1126 gst_flow_get_name (ret));
1128 return ret;
1129 }
1131 self->first_in_buffer = FALSE;
1133 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1134 /* The copy could be avoided by playing with the buffer pointer,
1135 but it seems to be rare and for not many bytes */
1136 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1137 self->outArgs->bytesConsumed, self->in_size,
1138 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1139 if (self->outArgs->bytesConsumed > 0) {
1140 if (self->outArgs->bytesConsumed > self->in_size) {
1141 GST_WARNING_OBJECT (self,
1142 "Codec claims to have used more bytes than supplied");
1143 self->in_size = 0;
1144 } else {
1145 if (self->outArgs->bytesConsumed < self->in_size) {
1146 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1147 self->in_size - self->outArgs->bytesConsumed);
1148 }
1149 self->in_size -= self->outArgs->bytesConsumed;
1150 }
1151 }
1152 } else {
1153 self->in_size = 0;
1154 }
1156 if (self->outArgs->outBufsInUseFlag) {
1157 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1158 self->need_out_buf = FALSE;
1159 } else {
1160 self->need_out_buf = TRUE;
1161 }
1163 if (buf) {
1164 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1165 GST_BUFFER_SIZE (buf));
1166 ts = GST_BUFFER_TIMESTAMP (buf);
1167 goto allocate_buffer;
1168 }
1170 if (self->needs_flushing)
1171 gst_ducati_viddec_codec_flush (self, FALSE);
1173 return GST_FLOW_OK;
1174 }
1176 static gboolean
1177 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1178 {
1179 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1180 gboolean ret = TRUE;
1182 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1184 switch (GST_EVENT_TYPE (event)) {
1185 case GST_EVENT_NEWSEGMENT:
1186 {
1187 gboolean update;
1188 GstFormat fmt;
1189 gint64 start, stop, time;
1190 gdouble rate, arate;
1192 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1193 &start, &stop, &time);
1194 gst_segment_set_newsegment_full (&self->segment, update,
1195 rate, arate, fmt, start, stop, time);
1196 break;
1197 }
1198 case GST_EVENT_EOS:
1199 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1200 GST_ERROR_OBJECT (self, "could not flush on eos");
1201 ret = FALSE;
1202 }
1203 break;
1204 case GST_EVENT_FLUSH_STOP:
1205 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1206 GST_ERROR_OBJECT (self, "could not flush");
1207 gst_event_unref (event);
1208 ret = FALSE;
1209 }
1210 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1211 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1212 self->qos_proportion = 1;
1213 self->need_out_buf = TRUE;
1214 break;
1215 default:
1216 break;
1217 }
1219 if (ret)
1220 ret = gst_pad_push_event (self->srcpad, event);
1221 GST_LOG_OBJECT (self, "end");
1223 return ret;
1224 }
1226 static gboolean
1227 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1228 {
1229 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1230 gboolean ret = TRUE;
1232 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1234 switch (GST_EVENT_TYPE (event)) {
1235 case GST_EVENT_QOS:
1236 {
1237 gdouble proportion;
1238 GstClockTimeDiff diff;
1239 GstClockTime timestamp;
1241 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1243 GST_OBJECT_LOCK (self);
1244 self->qos_proportion = proportion;
1245 self->qos_earliest_time = timestamp + 2 * diff;
1246 GST_OBJECT_UNLOCK (self);
1248 GST_DEBUG_OBJECT (self,
1249 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1250 proportion, GST_TIME_ARGS (timestamp), diff);
1252 ret = gst_pad_push_event (self->sinkpad, event);
1253 break;
1254 }
1255 default:
1256 ret = gst_pad_push_event (self->sinkpad, event);
1257 break;
1258 }
1260 GST_LOG_OBJECT (self, "end");
1262 return ret;
1263 }
1265 static GstStateChangeReturn
1266 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1267 {
1268 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1269 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1270 gboolean supported;
1272 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1273 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1274 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1276 switch (transition) {
1277 case GST_STATE_CHANGE_NULL_TO_READY:
1278 if (!engine_open (self)) {
1279 GST_ERROR_OBJECT (self, "could not open");
1280 return GST_STATE_CHANGE_FAILURE;
1281 }
1282 /* try to create/destroy the codec here, it may not be supported */
1283 supported = codec_create (self);
1284 codec_delete (self);
1285 self->codec = NULL;
1286 if (!supported) {
1287 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1288 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1289 engine_close (self);
1290 return GST_STATE_CHANGE_FAILURE;
1291 }
1292 break;
1293 default:
1294 break;
1295 }
1297 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1299 if (ret == GST_STATE_CHANGE_FAILURE)
1300 goto leave;
1302 switch (transition) {
1303 case GST_STATE_CHANGE_PAUSED_TO_READY:
1304 self->interlaced = FALSE;
1305 self->send_crop_event = TRUE;
1306 gst_ducati_viddec_codec_flush (self, FALSE);
1307 break;
1308 case GST_STATE_CHANGE_READY_TO_NULL:
1309 codec_delete (self);
1310 engine_close (self);
1311 break;
1312 default:
1313 break;
1314 }
1316 leave:
1317 GST_LOG_OBJECT (self, "end");
1319 return ret;
1320 }
1322 /* GObject vmethod implementations */
1324 #define VERSION_LENGTH 256
1326 static void
1327 gst_ducati_viddec_get_property (GObject * obj,
1328 guint prop_id, GValue * value, GParamSpec * pspec)
1329 {
1330 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1333 switch (prop_id) {
1334 case PROP_VERSION:{
1335 int err;
1336 char *version = NULL;
1338 if (!self->engine)
1339 engine_open (self);
1341 if (!self->codec)
1342 codec_create (self);
1344 if (self->codec) {
1345 version = dce_alloc (VERSION_LENGTH);
1346 self->status->data.buf = (XDAS_Int8 *) version;
1347 self->status->data.bufSize = VERSION_LENGTH;
1349 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1350 self->dynParams, self->status);
1351 if (err) {
1352 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1353 }
1355 self->status->data.buf = NULL;
1356 self->status->data.bufSize = 0;
1357 }
1359 g_value_set_string (value, version);
1360 if (version)
1361 dce_free (version);
1363 break;
1364 }
1365 case PROP_MAX_REORDER_FRAMES:
1366 g_value_set_int (value, self->backlog_max_maxframes);
1367 break;
1368 default:{
1369 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1370 break;
1371 }
1372 }
1373 }
1375 static void
1376 gst_ducati_viddec_set_property (GObject * obj,
1377 guint prop_id, const GValue * value, GParamSpec * pspec)
1378 {
1379 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1381 switch (prop_id) {
1382 case PROP_MAX_REORDER_FRAMES:
1383 self->backlog_max_maxframes = g_value_get_int (value);
1384 break;
1385 default:{
1386 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1387 break;
1388 }
1389 }
1390 }
1392 static void
1393 gst_ducati_viddec_finalize (GObject * obj)
1394 {
1395 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1397 codec_delete (self);
1398 engine_close (self);
1400 /* Will unref the remaining buffers if needed */
1401 g_hash_table_unref (self->passed_in_bufs);
1402 if (self->codec_data) {
1403 gst_buffer_unref (self->codec_data);
1404 self->codec_data = NULL;
1405 }
1407 G_OBJECT_CLASS (parent_class)->finalize (obj);
1408 }
1410 static void
1411 gst_ducati_viddec_base_init (gpointer gclass)
1412 {
1413 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1415 gst_element_class_add_pad_template (element_class,
1416 gst_static_pad_template_get (&src_factory));
1417 }
1419 static void
1420 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1421 {
1422 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1423 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1425 gobject_class->get_property =
1426 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1427 gobject_class->set_property =
1428 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1429 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1430 gstelement_class->change_state =
1431 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1433 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1434 klass->allocate_params =
1435 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1436 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1437 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1438 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1439 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1440 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1441 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1442 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1444 g_object_class_install_property (gobject_class, PROP_VERSION,
1445 g_param_spec_string ("version", "Version",
1446 "The codec version string", "",
1447 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1449 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1450 g_param_spec_int ("max-reorder-frames",
1451 "Maximum number of frames needed for reordering",
1452 "The maximum number of frames needed for reordering output frames. "
1453 "Only meaningful for codecs with B frames. 0 means no reordering. "
1454 "This value will be used if the correct value cannot be inferred "
1455 "from the stream. Too low a value may cause misordering, too high "
1456 "will cause extra latency.",
1457 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1458 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1459 }
1461 static void
1462 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1463 {
1464 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1466 self->sinkpad =
1467 gst_pad_new_from_template (gst_element_class_get_pad_template
1468 (gstelement_class, "sink"), "sink");
1469 gst_pad_set_setcaps_function (self->sinkpad,
1470 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1471 gst_pad_set_chain_function (self->sinkpad,
1472 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1473 gst_pad_set_event_function (self->sinkpad,
1474 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1476 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1477 gst_pad_set_event_function (self->srcpad,
1478 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1479 gst_pad_set_query_function (self->srcpad,
1480 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1481 gst_pad_set_getcaps_function (self->srcpad,
1482 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1484 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1485 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1487 self->input_width = 0;
1488 self->input_height = 0;
1489 /* sane defaults in case we need to create codec without caps negotiation
1490 * (for example, to get 'version' property)
1491 */
1492 self->width = 128;
1493 self->height = 128;
1494 self->fps_n = -1;
1495 self->fps_d = -1;
1497 self->first_in_buffer = TRUE;
1498 self->first_out_buffer = TRUE;
1499 self->interlaced = FALSE;
1500 self->send_crop_event = TRUE;
1502 #ifdef USE_DTS_PTS_CODE
1503 self->dts_ridx = self->dts_widx = 0;
1504 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1505 self->ts_may_be_pts = TRUE;
1506 self->ts_is_pts = FALSE;
1507 #endif
1509 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1511 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1513 self->qos_proportion = 1;
1514 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1515 self->wait_keyframe = TRUE;
1517 self->need_out_buf = TRUE;
1518 self->device = NULL;
1519 self->input_bo = NULL;
1521 self->backlog_maxframes = 0;
1522 self->backlog_nframes = 0;
1523 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1525 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1526 NULL, (GDestroyNotify) gst_buffer_unref);
1527 }