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 GstFlowReturn
298 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
299 {
300 guint64 earliest_order = G_MAXUINT64;
301 guint earliest_index = 0, i;
302 GstBuffer *buf;
304 if (self->backlog_nframes == 0)
305 return GST_FLOW_OK;
307 /* work out which frame has the earliest poc */
308 for (i = 0; i < self->backlog_nframes; i++) {
309 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
310 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
311 earliest_order = order;
312 earliest_index = i;
313 }
314 }
316 /* send it, giving away the ref */
317 buf = self->backlog_frames[earliest_index];
318 self->backlog_frames[earliest_index] =
319 self->backlog_frames[--self->backlog_nframes];
320 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
321 buf);
322 return gst_pad_push (self->srcpad, buf);
323 }
325 static void
326 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
327 {
328 /* push everything on the backlog, ignoring errors */
329 while (self->backlog_nframes > 0) {
330 gst_ducati_viddec_push_earliest (self);
331 }
332 }
334 static gint
335 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
336 GstFlowReturn * flow_ret)
337 {
338 gint err;
339 GstClockTime t;
340 GstBuffer *outbuf = NULL;
341 gint i;
342 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
343 GstFlowReturn ret = GST_FLOW_OK;
344 if (flow_ret)
345 /* never leave flow_ret uninitialized */
346 *flow_ret = GST_FLOW_OK;
348 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
349 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
351 t = gst_util_get_timestamp ();
352 err = VIDDEC3_process (self->codec,
353 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
354 GST_DEBUG_OBJECT (self, "%10dns", (gint) (gst_util_get_timestamp () - t));
356 if (err) {
357 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
358 err, self->outArgs->extendedError);
359 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
361 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
362 self->dynParams, self->status);
363 if (err) {
364 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
365 err, self->status->extendedError);
366 gst_ducati_log_extended_error_info (self->status->extendedError);
367 }
369 if (flush)
370 err = XDM_EFAIL;
371 else
372 err = klass->handle_error (self, err,
373 self->outArgs->extendedError, self->status->extendedError);
374 }
376 /* we now let the codec decide */
377 self->dynParams->newFrameFlag = XDAS_FALSE;
379 if (err == XDM_EFAIL)
380 goto skip_outbuf_processing;
382 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
383 gboolean interlaced;
385 /* Getting an extra reference for the decoder */
386 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
387 interlaced =
388 self->outArgs->decodedBufs.contentType ==
389 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
391 /* if send is FALSE, don't try to renegotiate as we could be flushing during
392 * a PAUSED->READY state change
393 */
394 if (send && interlaced != self->interlaced) {
395 GstCaps *caps;
397 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
398 "thinks interlaced=%d... trusting codec", self->interlaced,
399 interlaced);
401 self->interlaced = interlaced;
403 caps =
404 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
405 GST_INFO_OBJECT (self, "changing interlace field in caps");
406 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
407 NULL);
408 gst_drm_buffer_pool_set_caps (self->pool, caps);
409 if (!gst_pad_set_caps (self->srcpad, caps)) {
410 GST_ERROR_OBJECT (self,
411 "downstream didn't want to change interlace mode");
412 err = XDM_EFAIL;
413 }
414 gst_caps_unref (caps);
416 /* this buffer still has the old caps so we skip it */
417 send = FALSE;
418 }
420 if (G_UNLIKELY (self->send_crop_event) && send) {
421 gint crop_width, crop_height;
423 /* send region of interest to sink on first buffer: */
424 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
426 crop_width = r->bottomRight.x - r->topLeft.x;
427 crop_height = r->bottomRight.y - r->topLeft.y;
429 if (crop_width > self->input_width)
430 crop_width = self->input_width;
431 if (crop_height > self->input_height)
432 crop_height = self->input_height;
434 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
435 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
436 crop_width, crop_height);
438 gst_pad_push_event (self->srcpad,
439 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
440 crop_width, crop_height));
442 if (self->crop)
443 gst_video_crop_unref (self->crop);
445 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
446 crop_width, crop_height);
448 self->send_crop_event = FALSE;
449 }
451 if (G_UNLIKELY (self->first_out_buffer) && send) {
452 GstDRMBufferPool *pool;
453 self->first_out_buffer = FALSE;
455 /* Destroy the pool so the buffers we used so far are eventually released.
456 * The pool will be recreated if needed.
457 */
458 pool = self->pool;
459 self->pool = NULL;
460 gst_drm_buffer_pool_destroy (pool);
461 }
463 if (send) {
464 GstClockTime ts;
466 ts = GST_BUFFER_TIMESTAMP (outbuf);
468 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
469 i, outbuf, GST_TIME_ARGS (ts));
471 #ifdef USE_DTS_PTS_CODE
472 if (self->ts_may_be_pts) {
473 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
474 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
475 "enabling ts_is_pts");
476 self->ts_is_pts = TRUE;
477 }
478 }
479 #endif
481 self->last_pts = ts;
483 if (self->dts_ridx != self->dts_widx) {
484 ts = self->dts_queue[self->dts_ridx++ % NDTS];
485 }
487 if (self->ts_is_pts) {
488 /* if we have a queued DTS from demuxer, use that instead: */
489 GST_BUFFER_TIMESTAMP (outbuf) = ts;
490 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
491 i, outbuf, GST_TIME_ARGS (ts));
492 }
494 if (GST_BUFFER_CAPS (outbuf) &&
495 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
496 GST_PAD_CAPS (self->srcpad))) {
497 /* this looks a bit scary but it's really just to change the interlace=
498 * field in caps when we start as !interlaced and the codec detects
499 * otherwise */
500 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
501 "interlace mismatch");
502 outbuf = gst_buffer_make_metadata_writable (outbuf);
503 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
504 }
506 if (self->crop)
507 gst_buffer_set_video_crop (outbuf, self->crop);
509 ret = klass->push_output (self, outbuf);
510 if (flow_ret)
511 *flow_ret = ret;
512 if (ret != GST_FLOW_OK) {
513 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
514 /* just unref the remaining buffers (if any) */
515 send = FALSE;
516 }
517 } else {
518 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
519 i, outbuf);
521 gst_buffer_unref (outbuf);
522 }
523 }
525 skip_outbuf_processing:
526 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
527 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
528 }
530 return err;
531 }
533 /** call control(FLUSH), and then process() to pop out all buffers */
534 gboolean
535 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
536 {
537 gint err = FALSE;
539 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
541 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
543 /* note: flush is synchronized against _chain() to avoid calling
544 * the codec from multiple threads
545 */
546 GST_PAD_STREAM_LOCK (self->sinkpad);
548 #ifdef USE_DTS_PTS_CODE
549 self->dts_ridx = self->dts_widx = 0;
550 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
551 self->ts_may_be_pts = TRUE;
552 self->ts_is_pts = FALSE;
553 #endif
554 self->wait_keyframe = TRUE;
555 self->in_size = 0;
556 self->needs_flushing = FALSE;
557 self->need_out_buf = TRUE;
559 if (G_UNLIKELY (self->first_in_buffer)) {
560 goto out;
561 }
563 if (G_UNLIKELY (!self->codec)) {
564 GST_WARNING_OBJECT (self, "no codec");
565 goto out;
566 }
568 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
569 if (err) {
570 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
571 goto out;
572 }
574 self->inBufs->descs[0].bufSize.bytes = 0;
575 self->inBufs->numBufs = 0;
576 self->inArgs->numBytes = 0;
577 self->inArgs->inputID = 0;
578 self->outBufs->numBufs = 0;
580 do {
581 err = codec_process (self, eos, TRUE, NULL);
582 } while (err != XDM_EFAIL);
584 /* We flushed the decoder, we can now remove the buffer that have never been
585 * unrefed in it */
586 g_hash_table_remove_all (self->passed_in_bufs);
588 /* reset outArgs in case we're flushing in codec_process trying to do error
589 * recovery */
590 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
591 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
593 self->dynParams->newFrameFlag = XDAS_TRUE;
595 /* Reset the push buffer and YUV buffers */
596 self->inBufs->numBufs = 1;
597 self->outBufs->numBufs = 2;
599 /* on a flush, it is normal (and not an error) for the last _process() call
600 * to return an error..
601 */
602 err = XDM_EOK;
604 out:
605 GST_PAD_STREAM_UNLOCK (self->sinkpad);
606 GST_DEBUG_OBJECT (self, "done");
608 return !err;
609 }
611 /* GstDucatiVidDec vmethod default implementations */
613 static gboolean
614 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
615 {
616 const GValue *codec_data;
617 gint w, h;
619 if (gst_structure_get_int (s, "width", &self->input_width) &&
620 gst_structure_get_int (s, "height", &self->input_height)) {
622 h = ALIGN2 (self->input_height, 4); /* round up to MB */
623 w = ALIGN2 (self->input_width, 4); /* round up to MB */
625 /* if we've already created codec, but the resolution has changed, we
626 * need to re-create the codec:
627 */
628 if (G_UNLIKELY (self->codec)) {
629 if ((h != self->height) || (w != self->width)) {
630 codec_delete (self);
631 }
632 }
634 self->width = w;
635 self->height = h;
637 codec_data = gst_structure_get_value (s, "codec_data");
639 if (codec_data) {
640 GstBuffer *buffer = gst_value_get_buffer (codec_data);
641 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
642 self->codec_data = gst_buffer_ref (buffer);
643 }
645 return TRUE;
646 }
648 return FALSE;
649 }
651 static gboolean
652 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
653 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
654 {
656 /* allocate params: */
657 self->params = dce_alloc (params_sz);
658 if (G_UNLIKELY (!self->params)) {
659 return FALSE;
660 }
661 self->params->size = params_sz;
662 self->params->maxFrameRate = 30000;
663 self->params->maxBitRate = 10000000;
665 self->params->dataEndianness = XDM_BYTE;
666 self->params->forceChromaFormat = XDM_YUV_420SP;
667 self->params->operatingMode = IVIDEO_DECODE_ONLY;
669 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
670 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
671 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
672 self->params->numInputDataUnits = 0;
673 self->params->numOutputDataUnits = 0;
675 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
676 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
677 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
678 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
680 /* allocate dynParams: */
681 self->dynParams = dce_alloc (dynparams_sz);
682 if (G_UNLIKELY (!self->dynParams)) {
683 return FALSE;
684 }
685 self->dynParams->size = dynparams_sz;
686 self->dynParams->decodeHeader = XDM_DECODE_AU;
687 self->dynParams->displayWidth = 0;
688 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
689 self->dynParams->newFrameFlag = XDAS_TRUE;
691 /* allocate status: */
692 self->status = dce_alloc (status_sz);
693 if (G_UNLIKELY (!self->status)) {
694 return FALSE;
695 }
696 memset (self->status, 0, status_sz);
697 self->status->size = status_sz;
699 /* allocate inBufs/outBufs: */
700 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
701 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
702 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
703 return FALSE;
704 }
706 /* allocate inArgs/outArgs: */
707 self->inArgs = dce_alloc (inargs_sz);
708 self->outArgs = dce_alloc (outargs_sz);
709 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
710 return FALSE;
711 }
712 self->inArgs->size = inargs_sz;
713 self->outArgs->size = outargs_sz;
715 return TRUE;
716 }
718 static GstBuffer *
719 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
720 {
721 /* If we're about to push a keyframe, then we can flush all the frames
722 we currently have queued. For formats such as H264, this is actually
723 necessary as picture order count is local to each IDR + set of non
724 IDR frames, so will restart at 0 when next IDR frames comes in. For
725 other formats, it is not necessary, but avoids buffering frames that
726 do not need to be. */
727 if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
728 GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
729 self->backlog_nframes);
730 while (self->backlog_nframes > 0) {
731 gst_ducati_viddec_push_earliest (self);
732 }
733 }
735 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
736 push_input (self, GST_BUFFER_DATA (self->codec_data),
737 GST_BUFFER_SIZE (self->codec_data));
738 }
740 /* just copy entire buffer */
741 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
742 gst_buffer_unref (buf);
744 return NULL;
745 }
747 static GstFlowReturn
748 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
749 {
750 GstFlowReturn ret = GST_FLOW_OK;
752 /* add the frame to the list, the array will own the ref */
753 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
754 self->backlog_frames[self->backlog_nframes++] = buf;
756 /* push till we have no more than the max needed, or error */
757 while (self->backlog_nframes > self->backlog_maxframes) {
758 ret = gst_ducati_viddec_push_earliest (self);
759 if (ret != GST_FLOW_OK)
760 break;
761 }
763 return ret;
764 }
766 static gint
767 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
768 gint extended_error, gint status_extended_error)
769 {
770 if (XDM_ISFATALERROR (extended_error))
771 ret = XDM_EFAIL;
772 else
773 ret = XDM_EOK;
775 return ret;
776 }
778 /* GstElement vmethod implementations */
780 static gboolean
781 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
782 {
783 gboolean ret = TRUE;
784 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
785 GstStructure *s;
786 GstCaps *outcaps = NULL;
787 GstStructure *out_s;
788 gint par_width, par_height;
789 gboolean par_present;
791 s = gst_caps_get_structure (caps, 0);
792 if (!klass->parse_caps (self, s)) {
793 GST_WARNING_OBJECT (self, "missing required fields");
794 ret = FALSE;
795 goto out;
796 }
798 /* update output/padded sizes */
799 klass->update_buffer_size (self);
801 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
802 self->fps_n = 0;
803 self->fps_d = 1;
804 }
805 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
806 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
807 &par_width, &par_height);
809 outcaps = gst_pad_get_allowed_caps (self->srcpad);
810 if (outcaps) {
811 outcaps = gst_caps_make_writable (outcaps);
812 gst_caps_truncate (outcaps);
813 if (gst_caps_is_empty (outcaps)) {
814 gst_caps_unref (outcaps);
815 outcaps = NULL;
816 }
817 }
819 if (!outcaps) {
820 /* note: default to non-strided for better compatibility with
821 * other gst elements that don't understand stride:
822 */
823 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
824 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
825 }
827 out_s = gst_caps_get_structure (outcaps, 0);
828 gst_structure_set (out_s,
829 "width", G_TYPE_INT, self->padded_width,
830 "height", G_TYPE_INT, self->padded_height,
831 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
832 if (par_present)
833 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
834 par_width, par_height, NULL);
836 if (self->interlaced)
837 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
839 if (!strcmp (gst_structure_get_name (out_s), "video/x-raw-yuv-strided")) {
840 if (!gst_structure_get_int (out_s, "rowstride", &self->stride)) {
841 self->stride = 4096;
842 gst_structure_set (out_s, "rowstride", G_TYPE_INT, self->stride, NULL);
843 }
844 } else {
845 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
846 0, self->padded_width);
847 }
849 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
850 self->stride, self->padded_height);
852 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
853 self->outsize, self->stride, outcaps);
855 if (!self->first_in_buffer) {
856 /* Caps changed mid stream. We flush the codec to unlock all the potentially
857 * locked buffers. This is needed for downstream sinks that provide a
858 * buffer pool and need to destroy all the outstanding buffers before they
859 * can negotiate new caps (hello v4l2sink).
860 */
861 gst_ducati_viddec_codec_flush (self, FALSE);
862 }
864 /* (re)send a crop event when caps change */
865 self->send_crop_event = TRUE;
867 ret = gst_pad_set_caps (self->srcpad, outcaps);
869 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
871 /* default to no reordering */
872 self->backlog_maxframes = 0;
874 out:
875 if (outcaps)
876 gst_caps_unref (outcaps);
878 return ret;
879 }
881 static gboolean
882 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
883 {
884 gboolean ret = TRUE;
885 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
886 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
888 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
890 ret = klass->set_sink_caps (self, caps);
892 gst_object_unref (self);
894 return ret;
895 }
897 static GstCaps *
898 gst_ducati_viddec_src_getcaps (GstPad * pad)
899 {
900 GstCaps *caps = NULL;
901 GstCaps *outcaps = NULL;
902 int i;
904 caps = GST_PAD_CAPS (pad);
905 if (caps == NULL) {
906 outcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
907 return outcaps;
908 }
910 outcaps = gst_caps_new_empty ();
912 /* allow -rowstrided and regular yuv */
913 for (i = 0; i < gst_caps_get_size (caps); i++) {
914 GstStructure *structure;
915 GstStructure *modified_structure;
916 GValue value = { 0 };
918 structure = gst_caps_get_structure (caps, i);
919 gst_caps_append_structure (outcaps, gst_structure_copy (structure));
920 modified_structure = gst_structure_copy (structure);
922 if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
923 gst_structure_set_name (modified_structure, "video/x-raw-yuv-strided");
924 g_value_init (&value, GST_TYPE_INT_RANGE);
925 gst_value_set_int_range (&value, 0, G_MAXINT);
926 gst_structure_set_value (modified_structure, "rowstride", &value);
927 gst_caps_append_structure (outcaps, modified_structure);
928 g_value_unset (&value);
929 } else {
930 gst_structure_set_name (modified_structure, "video/x-raw-yuv");
931 gst_structure_remove_field (modified_structure, "rowstride");
932 gst_caps_append_structure (outcaps, modified_structure);
933 }
934 }
935 return outcaps;
936 }
938 static gboolean
939 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
940 GstQuery * query, gboolean * forward)
941 {
942 gboolean res = TRUE;
944 switch (GST_QUERY_TYPE (query)) {
945 case GST_QUERY_BUFFERS:
946 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
947 gst_query_set_buffers_count (query, self->min_buffers);
949 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
950 self->padded_width, self->padded_height);
951 gst_query_set_buffers_dimensions (query,
952 self->padded_width, self->padded_height);
953 *forward = FALSE;
954 break;
955 default:
956 break;
957 }
960 return res;
961 }
963 static gboolean
964 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
965 {
966 gboolean res = TRUE, forward = TRUE;
967 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
968 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
970 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
971 res = klass->query (self, pad, query, &forward);
972 if (res && forward)
973 res = gst_pad_query_default (pad, query);
975 return res;
976 }
978 static gboolean
979 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
980 {
981 GstClockTime timestamp, qostime;
982 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
983 gint64 diff;
985 if (self->wait_keyframe) {
986 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
987 GST_INFO_OBJECT (self, "skipping until the next keyframe");
988 return FALSE;
989 }
991 self->wait_keyframe = FALSE;
992 }
994 timestamp = GST_BUFFER_TIMESTAMP (buf);
995 if (self->segment.format != GST_FORMAT_TIME ||
996 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
997 goto no_qos;
999 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1000 goto no_qos;
1002 qostime = gst_segment_to_running_time (&self->segment,
1003 GST_FORMAT_TIME, timestamp);
1004 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1005 /* out of segment */
1006 goto no_qos;
1008 /* see how our next timestamp relates to the latest qos timestamp. negative
1009 * values mean we are early, positive values mean we are too late. */
1010 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1012 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1013 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1014 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1015 self->qos_proportion);
1017 if (klass->can_drop_frame (self, buf, diff)) {
1018 GST_INFO_OBJECT (self, "dropping frame");
1019 return FALSE;
1020 }
1022 no_qos:
1023 return TRUE;
1024 }
1026 static gboolean
1027 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1028 gint64 diff)
1029 {
1030 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1031 GST_BUFFER_FLAG_DELTA_UNIT);
1033 if (diff >= 0 && !is_keyframe)
1034 return TRUE;
1036 return FALSE;
1037 }
1039 static GstFlowReturn
1040 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1041 {
1042 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1043 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1044 GstFlowReturn ret = GST_FLOW_OK;
1045 Int32 err;
1046 GstBuffer *outbuf = NULL;
1047 GstCaps *outcaps = NULL;
1048 gboolean decode;
1050 if (G_UNLIKELY (!self->engine)) {
1051 GST_ERROR_OBJECT (self, "no engine");
1052 gst_buffer_unref (buf);
1053 return GST_FLOW_ERROR;
1054 }
1056 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1057 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1059 decode = gst_ducati_viddec_do_qos (self, buf);
1060 if (!decode) {
1061 gst_buffer_unref (buf);
1062 return GST_FLOW_OK;
1063 }
1065 if (!self->need_out_buf)
1066 goto have_out_buf;
1068 /* do this before creating codec to ensure reverse caps negotiation
1069 * happens first:
1070 */
1071 allocate_buffer:
1072 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1073 GST_PAD_CAPS (self->srcpad), &outbuf);
1074 if (ret != GST_FLOW_OK) {
1075 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1076 gst_flow_get_name (ret));
1077 gst_buffer_unref (buf);
1078 return ret;
1079 }
1081 outcaps = GST_BUFFER_CAPS (outbuf);
1082 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1083 GstStructure *s;
1085 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1086 GST_BUFFER_SIZE (outbuf));
1088 s = gst_caps_get_structure (outcaps, 0);
1089 gst_structure_get_int (s, "rowstride", &self->stride);
1090 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1091 self->stride, self->padded_height);
1093 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1094 self->outsize, self->stride, outcaps);
1096 gst_pad_set_caps (self->srcpad, outcaps);
1098 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1099 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1100 GST_BUFFER_SIZE (outbuf), self->outsize);
1101 gst_buffer_unref (outbuf);
1102 goto allocate_buffer;
1103 }
1104 }
1106 if (G_UNLIKELY (!self->codec)) {
1107 if (!codec_create (self)) {
1108 GST_ERROR_OBJECT (self, "could not create codec");
1109 gst_buffer_unref (buf);
1110 gst_buffer_unref (outbuf);
1111 return GST_FLOW_ERROR;
1112 }
1113 }
1115 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1116 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1118 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1119 * internal pool while self->first_out_buffer == TRUE in order to simplify
1120 * things in case we need to renegotiate */
1121 self->inArgs->inputID =
1122 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1123 if (!self->inArgs->inputID) {
1124 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1125 gst_buffer_unref (buf);
1126 return GST_FLOW_ERROR;
1127 }
1128 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1130 have_out_buf:
1131 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1133 #ifdef USE_DTS_PTS_CODE
1134 if (ts != GST_CLOCK_TIME_NONE) {
1135 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1136 /* if next buffer has earlier ts than previous, then the ts
1137 * we are getting are definitely decode order (DTS):
1138 */
1139 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1140 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1141 self->ts_may_be_pts = FALSE;
1142 }
1143 self->last_dts = ts;
1144 }
1145 #endif
1147 if (self->in_size == 0 && outbuf) {
1148 GST_DEBUG_OBJECT (self, "no input, skipping process");
1150 gst_buffer_unref (outbuf);
1151 return GST_FLOW_OK;
1152 }
1154 self->inArgs->numBytes = self->in_size;
1155 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1156 self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1158 err = codec_process (self, TRUE, FALSE, &ret);
1159 if (err) {
1160 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1161 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1162 gst_ducati_log_extended_error_info (self->outArgs->extendedError);
1164 return GST_FLOW_ERROR;
1165 }
1167 if (ret != GST_FLOW_OK) {
1168 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1169 gst_flow_get_name (ret));
1171 return ret;
1172 }
1174 self->first_in_buffer = FALSE;
1176 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1177 /* The copy could be avoided by playing with the buffer pointer,
1178 but it seems to be rare and for not many bytes */
1179 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1180 self->outArgs->bytesConsumed, self->in_size,
1181 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1182 if (self->outArgs->bytesConsumed > 0) {
1183 if (self->outArgs->bytesConsumed > self->in_size) {
1184 GST_WARNING_OBJECT (self,
1185 "Codec claims to have used more bytes than supplied");
1186 self->in_size = 0;
1187 } else {
1188 if (self->outArgs->bytesConsumed < self->in_size) {
1189 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1190 self->in_size - self->outArgs->bytesConsumed);
1191 }
1192 self->in_size -= self->outArgs->bytesConsumed;
1193 }
1194 }
1195 } else {
1196 self->in_size = 0;
1197 }
1199 if (self->outArgs->outBufsInUseFlag) {
1200 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1201 self->need_out_buf = FALSE;
1202 } else {
1203 self->need_out_buf = TRUE;
1204 }
1206 if (buf) {
1207 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1208 GST_BUFFER_SIZE (buf));
1209 ts = GST_BUFFER_TIMESTAMP (buf);
1210 goto allocate_buffer;
1211 }
1213 if (self->needs_flushing)
1214 gst_ducati_viddec_codec_flush (self, FALSE);
1216 return GST_FLOW_OK;
1217 }
1219 static gboolean
1220 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1221 {
1222 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1223 gboolean ret = TRUE;
1225 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1227 switch (GST_EVENT_TYPE (event)) {
1228 case GST_EVENT_NEWSEGMENT:
1229 {
1230 gboolean update;
1231 GstFormat fmt;
1232 gint64 start, stop, time;
1233 gdouble rate, arate;
1235 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1236 &start, &stop, &time);
1237 gst_segment_set_newsegment_full (&self->segment, update,
1238 rate, arate, fmt, start, stop, time);
1239 break;
1240 }
1241 case GST_EVENT_EOS:
1242 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1243 GST_ERROR_OBJECT (self, "could not flush on eos");
1244 ret = FALSE;
1245 }
1246 break;
1247 case GST_EVENT_FLUSH_STOP:
1248 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1249 GST_ERROR_OBJECT (self, "could not flush");
1250 gst_event_unref (event);
1251 ret = FALSE;
1252 }
1253 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1254 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1255 self->qos_proportion = 1;
1256 self->need_out_buf = TRUE;
1257 break;
1258 default:
1259 break;
1260 }
1262 if (ret)
1263 ret = gst_pad_push_event (self->srcpad, event);
1264 GST_LOG_OBJECT (self, "end");
1266 return ret;
1267 }
1269 static gboolean
1270 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1271 {
1272 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1273 gboolean ret = TRUE;
1275 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1277 switch (GST_EVENT_TYPE (event)) {
1278 case GST_EVENT_QOS:
1279 {
1280 gdouble proportion;
1281 GstClockTimeDiff diff;
1282 GstClockTime timestamp;
1284 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1286 GST_OBJECT_LOCK (self);
1287 self->qos_proportion = proportion;
1288 self->qos_earliest_time = timestamp + 2 * diff;
1289 GST_OBJECT_UNLOCK (self);
1291 GST_DEBUG_OBJECT (self,
1292 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1293 proportion, GST_TIME_ARGS (timestamp), diff);
1295 ret = gst_pad_push_event (self->sinkpad, event);
1296 break;
1297 }
1298 default:
1299 ret = gst_pad_push_event (self->sinkpad, event);
1300 break;
1301 }
1303 GST_LOG_OBJECT (self, "end");
1305 return ret;
1306 }
1308 static GstStateChangeReturn
1309 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1310 {
1311 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1312 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1313 gboolean supported;
1315 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1316 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1317 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1319 switch (transition) {
1320 case GST_STATE_CHANGE_NULL_TO_READY:
1321 if (!engine_open (self)) {
1322 GST_ERROR_OBJECT (self, "could not open");
1323 return GST_STATE_CHANGE_FAILURE;
1324 }
1325 /* try to create/destroy the codec here, it may not be supported */
1326 supported = codec_create (self);
1327 codec_delete (self);
1328 self->codec = NULL;
1329 if (!supported) {
1330 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1331 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1332 engine_close (self);
1333 return GST_STATE_CHANGE_FAILURE;
1334 }
1335 break;
1336 default:
1337 break;
1338 }
1340 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1342 if (ret == GST_STATE_CHANGE_FAILURE)
1343 goto leave;
1345 switch (transition) {
1346 case GST_STATE_CHANGE_PAUSED_TO_READY:
1347 self->interlaced = FALSE;
1348 self->send_crop_event = TRUE;
1349 gst_ducati_viddec_codec_flush (self, FALSE);
1350 break;
1351 case GST_STATE_CHANGE_READY_TO_NULL:
1352 codec_delete (self);
1353 engine_close (self);
1354 break;
1355 default:
1356 break;
1357 }
1359 leave:
1360 GST_LOG_OBJECT (self, "end");
1362 return ret;
1363 }
1365 /* GObject vmethod implementations */
1367 #define VERSION_LENGTH 256
1369 static void
1370 gst_ducati_viddec_get_property (GObject * obj,
1371 guint prop_id, GValue * value, GParamSpec * pspec)
1372 {
1373 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1376 switch (prop_id) {
1377 case PROP_VERSION:{
1378 int err;
1379 char *version = NULL;
1381 if (!self->engine)
1382 engine_open (self);
1384 if (!self->codec)
1385 codec_create (self);
1387 if (self->codec) {
1388 version = dce_alloc (VERSION_LENGTH);
1389 self->status->data.buf = (XDAS_Int8 *) version;
1390 self->status->data.bufSize = VERSION_LENGTH;
1392 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1393 self->dynParams, self->status);
1394 if (err) {
1395 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1396 }
1398 self->status->data.buf = NULL;
1399 self->status->data.bufSize = 0;
1400 }
1402 g_value_set_string (value, version);
1403 if (version)
1404 dce_free (version);
1406 break;
1407 }
1408 default:{
1409 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1410 break;
1411 }
1412 }
1413 }
1415 static void
1416 gst_ducati_viddec_finalize (GObject * obj)
1417 {
1418 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1420 codec_delete (self);
1421 engine_close (self);
1423 /* Will unref the remaining buffers if needed */
1424 g_hash_table_unref (self->passed_in_bufs);
1425 if (self->codec_data) {
1426 gst_buffer_unref (self->codec_data);
1427 self->codec_data = NULL;
1428 }
1430 G_OBJECT_CLASS (parent_class)->finalize (obj);
1431 }
1433 static void
1434 gst_ducati_viddec_base_init (gpointer gclass)
1435 {
1436 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1438 gst_element_class_add_pad_template (element_class,
1439 gst_static_pad_template_get (&src_factory));
1440 }
1442 static void
1443 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1444 {
1445 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1446 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1448 gobject_class->get_property =
1449 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1450 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1451 gstelement_class->change_state =
1452 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1454 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1455 klass->allocate_params =
1456 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1457 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1458 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1459 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1460 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1461 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1462 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1463 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1465 g_object_class_install_property (gobject_class, PROP_VERSION,
1466 g_param_spec_string ("version", "Version",
1467 "The codec version string", "",
1468 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1469 }
1471 static void
1472 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1473 {
1474 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1476 self->sinkpad =
1477 gst_pad_new_from_template (gst_element_class_get_pad_template
1478 (gstelement_class, "sink"), "sink");
1479 gst_pad_set_setcaps_function (self->sinkpad,
1480 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1481 gst_pad_set_chain_function (self->sinkpad,
1482 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1483 gst_pad_set_event_function (self->sinkpad,
1484 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1486 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1487 gst_pad_set_event_function (self->srcpad,
1488 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1489 gst_pad_set_query_function (self->srcpad,
1490 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1491 gst_pad_set_getcaps_function (self->srcpad,
1492 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1494 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1495 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1497 self->input_width = 0;
1498 self->input_height = 0;
1499 /* sane defaults in case we need to create codec without caps negotiation
1500 * (for example, to get 'version' property)
1501 */
1502 self->width = 128;
1503 self->height = 128;
1504 self->fps_n = -1;
1505 self->fps_d = -1;
1507 self->first_in_buffer = TRUE;
1508 self->first_out_buffer = TRUE;
1509 self->interlaced = FALSE;
1510 self->send_crop_event = TRUE;
1512 #ifdef USE_DTS_PTS_CODE
1513 self->dts_ridx = self->dts_widx = 0;
1514 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1515 self->ts_may_be_pts = TRUE;
1516 self->ts_is_pts = FALSE;
1517 #endif
1519 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1521 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1523 self->qos_proportion = 1;
1524 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1525 self->wait_keyframe = TRUE;
1527 self->need_out_buf = TRUE;
1528 self->device = NULL;
1529 self->input_bo = NULL;
1531 self->backlog_maxframes = 0;
1532 self->backlog_nframes = 0;
1534 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1535 NULL, (GDestroyNotify) gst_buffer_unref);
1536 }