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 #define VERSION_LENGTH 256
29 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
30 GST_TYPE_ELEMENT);
32 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
33 GST_PAD_SRC,
34 GST_PAD_ALWAYS,
35 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
36 );
38 enum
39 {
40 PROP_0,
41 PROP_VERSION,
42 PROP_MAX_REORDER_FRAMES,
43 PROP_CODEC_DEBUG_INFO
44 };
46 /* helper functions */
48 static void
49 engine_close (GstDucatiVidDec * self)
50 {
51 if (self->engine) {
52 Engine_close (self->engine);
53 self->engine = NULL;
54 }
56 if (self->params) {
57 dce_free (self->params);
58 self->params = NULL;
59 }
61 if (self->dynParams) {
62 dce_free (self->dynParams);
63 self->dynParams = NULL;
64 }
66 if (self->status) {
67 dce_free (self->status);
68 self->status = NULL;
69 }
71 if (self->inBufs) {
72 dce_free (self->inBufs);
73 self->inBufs = NULL;
74 }
76 if (self->outBufs) {
77 dce_free (self->outBufs);
78 self->outBufs = NULL;
79 }
81 if (self->inArgs) {
82 dce_free (self->inArgs);
83 self->inArgs = NULL;
84 }
86 if (self->outArgs) {
87 dce_free (self->outArgs);
88 self->outArgs = NULL;
89 }
91 if (self->device) {
92 dce_deinit (self->device);
93 self->device = NULL;
94 }
95 }
97 static gboolean
98 engine_open (GstDucatiVidDec * self)
99 {
100 gboolean ret;
101 int ec;
103 if (G_UNLIKELY (self->engine)) {
104 return TRUE;
105 }
107 if (self->device == NULL) {
108 self->device = dce_init ();
109 if (self->device == NULL) {
110 GST_ERROR_OBJECT (self, "dce_init() failed");
111 return FALSE;
112 }
113 }
115 GST_DEBUG_OBJECT (self, "opening engine");
117 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
118 if (G_UNLIKELY (!self->engine)) {
119 GST_ERROR_OBJECT (self, "could not create engine");
120 return FALSE;
121 }
123 ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
124 sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
125 sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
126 sizeof (IVIDDEC3_OutArgs));
128 return ret;
129 }
131 static void
132 codec_delete (GstDucatiVidDec * self)
133 {
134 if (self->pool) {
135 gst_drm_buffer_pool_destroy (self->pool);
136 self->pool = NULL;
137 }
139 if (self->codec) {
140 GST_DEBUG ("Calling VIDDEC3_delete");
141 VIDDEC3_delete (self->codec);
142 self->codec = NULL;
143 }
145 if (self->input_bo) {
146 omap_bo_del (self->input_bo);
147 self->input_bo = NULL;
148 }
149 }
151 static gboolean
152 codec_create (GstDucatiVidDec * self)
153 {
154 gint err, n;
155 const gchar *codec_name;
156 char *version = NULL;
158 codec_delete (self);
160 if (G_UNLIKELY (!self->engine)) {
161 GST_ERROR_OBJECT (self, "no engine");
162 return FALSE;
163 }
165 /* these need to be set before VIDDEC3_create */
166 self->params->maxWidth = self->width;
167 self->params->maxHeight = self->height;
169 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
171 /* create codec: */
172 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
173 self->codec =
174 VIDDEC3_create (self->engine, (String) codec_name, self->params);
176 if (!self->codec) {
177 return FALSE;
178 }
180 GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
181 err =
182 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
183 self->status);
184 if (err) {
185 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
186 return FALSE;
187 }
189 self->first_in_buffer = TRUE;
190 self->first_out_buffer = TRUE;
192 version = dce_alloc (VERSION_LENGTH);
193 if (version) {
194 self->status->data.buf = (XDAS_Int8 *) version;
195 self->status->data.bufSize = VERSION_LENGTH;
197 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
198 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
199 self->dynParams, self->status);
201 if (err) {
202 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
203 } else
204 GST_DEBUG ("Codec version %s", self->status->data.buf);
206 self->status->data.buf = NULL;
207 self->status->data.bufSize = 0;
208 dce_free (version);
210 }
213 /* allocate input buffer and initialize inBufs: */
214 /* FIXME: needed size here has nothing to do with width * height */
215 self->input_bo = omap_bo_new (self->device,
216 self->width * self->height, OMAP_BO_WC);
217 self->input = omap_bo_map (self->input_bo);
218 self->inBufs->numBufs = 1;
219 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (self->input_bo);
221 /* Actual buffers will be set later, as they will be different for every
222 frame. We allow derived classes to add their own buffers, however, so
223 we initialize the number of outBufs here, counting the number of extra
224 buffers required, including "holes" in planes, which may not be filled
225 if not assigned. */
226 self->outBufs->numBufs = 2; /* luma and chroma planes, always */
227 for (n = 0; n < 3; n++)
228 if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
229 self->outBufs->numBufs = 2 + n + 1;
231 return TRUE;
232 }
234 static inline GstBuffer *
235 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
236 {
237 if (G_UNLIKELY (!self->pool)) {
238 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
239 self->padded_width, self->padded_height);
241 GST_DEBUG_OBJECT (self, "creating bufferpool");
242 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
243 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
244 }
245 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
246 }
248 static GstDucatiBufferPriv *
249 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
250 {
251 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
252 if (!priv) {
253 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
254 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
256 /* if it isn't a dmabuf buffer that we can import, then there
257 * is nothing we can do with it:
258 */
259 if (!dmabuf) {
260 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
261 return NULL;
262 }
264 priv = gst_ducati_buffer_priv_new ();
266 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
268 priv->uv_offset = gst_video_format_get_component_offset (format,
269 1, self->stride, self->padded_height);
270 priv->size = gst_video_format_get_size (format,
271 self->stride, self->padded_height);
273 gst_ducati_buffer_priv_set (buf, priv);
274 gst_mini_object_unref (GST_MINI_OBJECT (priv));
275 }
276 return priv;
277 }
279 static XDAS_Int32
280 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
281 gboolean force_internal)
282 {
283 GstDucatiBufferPriv *priv = NULL;
285 if (!force_internal)
286 priv = get_buffer_priv (self, *buf);
288 if (!priv) {
289 GstBuffer *orig = *buf;
291 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
292 *buf = codec_buffer_pool_get (self, NULL);
293 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
294 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
295 gst_buffer_unref (orig);
296 return codec_prepare_outbuf (self, buf, FALSE);
297 }
299 /* There are at least two buffers. Derived classes may add codec specific
300 buffers (eg, debug info) after these two if they want to. */
301 self->outBufs->descs[0].memType = XDM_MEMTYPE_BO;
302 self->outBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_handle (priv->bo);
303 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
304 self->outBufs->descs[1].memType = XDM_MEMTYPE_BO_OFFSET;
305 self->outBufs->descs[1].buf = (XDAS_Int8 *) priv->uv_offset;
306 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
308 return (XDAS_Int32) * buf;
309 }
311 static GstBuffer *
312 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
313 {
314 GstBuffer *buf = (GstBuffer *) id;
316 if (buf) {
317 g_hash_table_insert (self->passed_in_bufs, buf, buf);
319 gst_buffer_ref (buf);
320 }
321 return buf;
322 }
324 static void
325 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
326 {
327 GstBuffer *buf = (GstBuffer *) id;
329 if (buf) {
330 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
331 g_hash_table_remove (self->passed_in_bufs, buf);
332 }
333 }
335 static GstFlowReturn
336 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
337 {
338 guint64 earliest_order = G_MAXUINT64;
339 guint earliest_index = 0, i;
340 GstBuffer *buf;
342 if (self->backlog_nframes == 0)
343 return GST_FLOW_OK;
345 /* work out which frame has the earliest poc */
346 for (i = 0; i < self->backlog_nframes; i++) {
347 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
348 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
349 earliest_order = order;
350 earliest_index = i;
351 }
352 }
354 /* send it, giving away the ref */
355 buf = self->backlog_frames[earliest_index];
356 self->backlog_frames[earliest_index] =
357 self->backlog_frames[--self->backlog_nframes];
358 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
359 buf);
360 return gst_pad_push (self->srcpad, buf);
361 }
363 static void
364 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
365 {
366 /* push everything on the backlog, ignoring errors */
367 while (self->backlog_nframes > 0) {
368 gst_ducati_viddec_push_earliest (self);
369 }
370 }
372 static gint
373 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
374 GstFlowReturn * flow_ret)
375 {
376 gint err;
377 GstClockTime t;
378 GstBuffer *outbuf = NULL;
379 gint i;
380 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
381 GstFlowReturn ret = GST_FLOW_OK;
382 if (flow_ret)
383 /* never leave flow_ret uninitialized */
384 *flow_ret = GST_FLOW_OK;
386 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
387 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
389 GST_DEBUG ("Calling VIDDEC3_process");
390 t = gst_util_get_timestamp ();
391 err = VIDDEC3_process (self->codec,
392 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
393 t = gst_util_get_timestamp () - t;
394 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
395 (gint) (t / 1000000));
397 if (err) {
398 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
399 err, self->outArgs->extendedError);
400 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
401 self->error_strings);
403 GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
404 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
405 self->dynParams, self->status);
406 if (err) {
407 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
408 err, self->status->extendedError);
409 gst_ducati_log_extended_error_info (self->status->extendedError,
410 self->error_strings);
411 }
413 if (flush)
414 err = XDM_EFAIL;
415 else
416 err = klass->handle_error (self, err,
417 self->outArgs->extendedError, self->status->extendedError);
418 }
420 /* we now let the codec decide */
421 self->dynParams->newFrameFlag = XDAS_FALSE;
423 if (err == XDM_EFAIL)
424 goto skip_outbuf_processing;
426 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
427 gboolean interlaced;
429 /* Getting an extra reference for the decoder */
430 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
431 interlaced =
432 self->outArgs->decodedBufs.contentType ==
433 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
435 /* if send is FALSE, don't try to renegotiate as we could be flushing during
436 * a PAUSED->READY state change
437 */
438 if (send && interlaced != self->interlaced) {
439 GstCaps *caps;
441 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
442 "thinks interlaced=%d... trusting codec", self->interlaced,
443 interlaced);
445 self->interlaced = interlaced;
447 caps =
448 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
449 GST_INFO_OBJECT (self, "changing interlace field in caps");
450 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
451 NULL);
452 gst_drm_buffer_pool_set_caps (self->pool, caps);
453 if (!gst_pad_set_caps (self->srcpad, caps)) {
454 GST_ERROR_OBJECT (self,
455 "downstream didn't want to change interlace mode");
456 err = XDM_EFAIL;
457 }
458 gst_caps_unref (caps);
460 /* this buffer still has the old caps so we skip it */
461 send = FALSE;
462 }
464 if (G_UNLIKELY (self->send_crop_event) && send) {
465 gint crop_width, crop_height;
467 /* send region of interest to sink on first buffer: */
468 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
470 crop_width = r->bottomRight.x - r->topLeft.x;
471 crop_height = r->bottomRight.y - r->topLeft.y;
473 if (crop_width > self->input_width)
474 crop_width = self->input_width;
475 if (crop_height > self->input_height)
476 crop_height = self->input_height;
478 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
479 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
480 crop_width, crop_height);
482 gst_pad_push_event (self->srcpad,
483 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
484 crop_width, crop_height));
486 if (self->crop)
487 gst_video_crop_unref (self->crop);
489 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
490 crop_width, crop_height);
492 self->send_crop_event = FALSE;
493 }
495 if (G_UNLIKELY (self->first_out_buffer) && send) {
496 GstDRMBufferPool *pool;
497 self->first_out_buffer = FALSE;
499 /* Destroy the pool so the buffers we used so far are eventually released.
500 * The pool will be recreated if needed.
501 */
502 pool = self->pool;
503 self->pool = NULL;
504 gst_drm_buffer_pool_destroy (pool);
505 }
507 if (send) {
508 GstClockTime ts;
510 ts = GST_BUFFER_TIMESTAMP (outbuf);
512 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
513 i, outbuf, GST_TIME_ARGS (ts));
515 #ifdef USE_DTS_PTS_CODE
516 if (self->ts_may_be_pts) {
517 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
518 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
519 "enabling ts_is_pts");
520 self->ts_is_pts = TRUE;
521 }
522 }
523 #endif
525 self->last_pts = ts;
527 if (self->dts_ridx != self->dts_widx) {
528 ts = self->dts_queue[self->dts_ridx++ % NDTS];
529 }
531 if (self->ts_is_pts) {
532 /* if we have a queued DTS from demuxer, use that instead: */
533 GST_BUFFER_TIMESTAMP (outbuf) = ts;
534 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
535 i, outbuf, GST_TIME_ARGS (ts));
536 }
538 if (GST_BUFFER_CAPS (outbuf) &&
539 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
540 GST_PAD_CAPS (self->srcpad))) {
541 /* this looks a bit scary but it's really just to change the interlace=
542 * field in caps when we start as !interlaced and the codec detects
543 * otherwise */
544 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
545 "interlace mismatch");
546 outbuf = gst_buffer_make_metadata_writable (outbuf);
547 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
548 }
550 if (self->crop)
551 gst_buffer_set_video_crop (outbuf, self->crop);
553 ret = klass->push_output (self, outbuf);
554 if (flow_ret)
555 *flow_ret = ret;
556 if (ret != GST_FLOW_OK) {
557 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
558 /* just unref the remaining buffers (if any) */
559 send = FALSE;
560 }
561 } else {
562 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
563 i, outbuf);
565 gst_buffer_unref (outbuf);
566 }
567 }
569 skip_outbuf_processing:
570 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
571 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
572 }
574 return err;
575 }
577 /** call control(FLUSH), and then process() to pop out all buffers */
578 gboolean
579 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
580 {
581 gint err = FALSE;
582 int prev_num_in_bufs, prev_num_out_bufs;
584 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
586 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
588 /* note: flush is synchronized against _chain() to avoid calling
589 * the codec from multiple threads
590 */
591 GST_PAD_STREAM_LOCK (self->sinkpad);
593 #ifdef USE_DTS_PTS_CODE
594 self->dts_ridx = self->dts_widx = 0;
595 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
596 self->ts_may_be_pts = TRUE;
597 self->ts_is_pts = FALSE;
598 #endif
599 self->wait_keyframe = TRUE;
600 self->in_size = 0;
601 self->needs_flushing = FALSE;
602 self->need_out_buf = TRUE;
604 if (G_UNLIKELY (self->first_in_buffer)) {
605 goto out;
606 }
608 if (G_UNLIKELY (!self->codec)) {
609 GST_WARNING_OBJECT (self, "no codec");
610 goto out;
611 }
614 GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
615 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
616 if (err) {
617 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
618 goto out;
619 }
621 prev_num_in_bufs = self->inBufs->numBufs;
622 prev_num_out_bufs = self->outBufs->numBufs;
624 self->inBufs->descs[0].bufSize.bytes = 0;
625 self->inBufs->numBufs = 0;
626 self->inArgs->numBytes = 0;
627 self->inArgs->inputID = 0;
628 self->outBufs->numBufs = 0;
630 do {
631 err = codec_process (self, eos, TRUE, NULL);
632 } while (err != XDM_EFAIL);
634 /* We flushed the decoder, we can now remove the buffer that have never been
635 * unrefed in it */
636 g_hash_table_remove_all (self->passed_in_bufs);
638 /* reset outArgs in case we're flushing in codec_process trying to do error
639 * recovery */
640 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
641 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
643 self->dynParams->newFrameFlag = XDAS_TRUE;
645 /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
646 self->inBufs->numBufs = prev_num_in_bufs;
647 self->outBufs->numBufs = prev_num_out_bufs;
649 /* on a flush, it is normal (and not an error) for the last _process() call
650 * to return an error..
651 */
652 err = XDM_EOK;
654 out:
655 GST_PAD_STREAM_UNLOCK (self->sinkpad);
656 GST_DEBUG_OBJECT (self, "done");
658 return !err;
659 }
661 /* GstDucatiVidDec vmethod default implementations */
663 static gboolean
664 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
665 {
666 const GValue *codec_data;
667 gint w, h;
669 if (gst_structure_get_int (s, "width", &self->input_width) &&
670 gst_structure_get_int (s, "height", &self->input_height)) {
672 h = ALIGN2 (self->input_height, 4); /* round up to MB */
673 w = ALIGN2 (self->input_width, 4); /* round up to MB */
675 /* if we've already created codec, but the resolution has changed, we
676 * need to re-create the codec:
677 */
678 if (G_UNLIKELY (self->codec)) {
679 if ((h != self->height) || (w != self->width)) {
680 codec_delete (self);
681 }
682 }
684 self->width = w;
685 self->height = h;
687 codec_data = gst_structure_get_value (s, "codec_data");
689 if (codec_data) {
690 GstBuffer *buffer = gst_value_get_buffer (codec_data);
691 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
692 self->codec_data = gst_buffer_ref (buffer);
693 }
695 return TRUE;
696 }
698 return FALSE;
699 }
701 static gboolean
702 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
703 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
704 {
706 /* allocate params: */
707 self->params = dce_alloc (params_sz);
708 if (G_UNLIKELY (!self->params)) {
709 return FALSE;
710 }
711 self->params->size = params_sz;
712 self->params->maxFrameRate = 30000;
713 self->params->maxBitRate = 10000000;
715 self->params->dataEndianness = XDM_BYTE;
716 self->params->forceChromaFormat = XDM_YUV_420SP;
717 self->params->operatingMode = IVIDEO_DECODE_ONLY;
719 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
720 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
721 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
722 self->params->numInputDataUnits = 0;
723 self->params->numOutputDataUnits = 0;
725 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
726 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
727 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
728 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
730 /* allocate dynParams: */
731 self->dynParams = dce_alloc (dynparams_sz);
732 if (G_UNLIKELY (!self->dynParams)) {
733 return FALSE;
734 }
735 self->dynParams->size = dynparams_sz;
736 self->dynParams->decodeHeader = XDM_DECODE_AU;
737 self->dynParams->displayWidth = 0;
738 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
739 self->dynParams->newFrameFlag = XDAS_TRUE;
741 /* allocate status: */
742 self->status = dce_alloc (status_sz);
743 if (G_UNLIKELY (!self->status)) {
744 return FALSE;
745 }
746 memset (self->status, 0, status_sz);
747 self->status->size = status_sz;
749 /* allocate inBufs/outBufs: */
750 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
751 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
752 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
753 return FALSE;
754 }
756 /* allocate inArgs/outArgs: */
757 self->inArgs = dce_alloc (inargs_sz);
758 self->outArgs = dce_alloc (outargs_sz);
759 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
760 return FALSE;
761 }
762 self->inArgs->size = inargs_sz;
763 self->outArgs->size = outargs_sz;
765 return TRUE;
766 }
768 static GstBuffer *
769 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
770 {
771 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
772 push_input (self, GST_BUFFER_DATA (self->codec_data),
773 GST_BUFFER_SIZE (self->codec_data));
774 }
776 /* just copy entire buffer */
777 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
778 gst_buffer_unref (buf);
780 return NULL;
781 }
783 static GstFlowReturn
784 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
785 {
786 GstFlowReturn ret = GST_FLOW_OK;
788 /* if no reordering info was set, just send the buffer */
789 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
790 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
791 return gst_pad_push (self->srcpad, buf);
792 }
794 /* add the frame to the list, the array will own the ref */
795 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
796 self->backlog_frames[self->backlog_nframes++] = buf;
798 /* push till we have no more than the max needed, or error */
799 while (self->backlog_nframes > self->backlog_maxframes) {
800 ret = gst_ducati_viddec_push_earliest (self);
801 if (ret != GST_FLOW_OK)
802 break;
803 }
805 return ret;
806 }
808 static gint
809 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
810 gint extended_error, gint status_extended_error)
811 {
812 if (XDM_ISFATALERROR (extended_error))
813 ret = XDM_EFAIL;
814 else
815 ret = XDM_EOK;
817 return ret;
818 }
820 /* GstElement vmethod implementations */
822 static gboolean
823 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
824 {
825 gboolean ret = TRUE;
826 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
827 GstStructure *s;
828 GstCaps *outcaps = NULL;
829 GstStructure *out_s;
830 gint par_width, par_height;
831 gboolean par_present;
833 s = gst_caps_get_structure (caps, 0);
834 if (!klass->parse_caps (self, s)) {
835 GST_WARNING_OBJECT (self, "missing required fields");
836 ret = FALSE;
837 goto out;
838 }
840 /* update output/padded sizes */
841 klass->update_buffer_size (self);
843 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
844 self->fps_n = 0;
845 self->fps_d = 1;
846 }
847 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
848 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
849 &par_width, &par_height);
851 outcaps = gst_pad_get_allowed_caps (self->srcpad);
852 if (outcaps) {
853 outcaps = gst_caps_make_writable (outcaps);
854 gst_caps_truncate (outcaps);
855 if (gst_caps_is_empty (outcaps)) {
856 gst_caps_unref (outcaps);
857 outcaps = NULL;
858 }
859 }
861 if (!outcaps) {
862 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
863 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
864 }
866 out_s = gst_caps_get_structure (outcaps, 0);
867 gst_structure_set (out_s,
868 "width", G_TYPE_INT, self->padded_width,
869 "height", G_TYPE_INT, self->padded_height,
870 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
871 if (par_present)
872 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
873 par_width, par_height, NULL);
875 if (self->interlaced)
876 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
878 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
879 0, self->padded_width);
881 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
882 self->stride, self->padded_height);
884 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
885 self->outsize, self->stride, outcaps);
887 if (!self->first_in_buffer) {
888 /* Caps changed mid stream. We flush the codec to unlock all the potentially
889 * locked buffers. This is needed for downstream sinks that provide a
890 * buffer pool and need to destroy all the outstanding buffers before they
891 * can negotiate new caps (hello v4l2sink).
892 */
893 gst_ducati_viddec_codec_flush (self, FALSE);
894 }
896 /* (re)send a crop event when caps change */
897 self->send_crop_event = TRUE;
899 ret = gst_pad_set_caps (self->srcpad, outcaps);
901 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
903 /* default to no reordering */
904 self->backlog_maxframes = 0;
906 out:
907 if (outcaps)
908 gst_caps_unref (outcaps);
910 return ret;
911 }
913 static gboolean
914 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
915 {
916 gboolean ret = TRUE;
917 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
918 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
920 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
922 ret = klass->set_sink_caps (self, caps);
924 gst_object_unref (self);
926 return ret;
927 }
929 static GstCaps *
930 gst_ducati_viddec_src_getcaps (GstPad * pad)
931 {
932 GstCaps *caps = NULL;
934 caps = GST_PAD_CAPS (pad);
935 if (caps == NULL) {
936 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
937 } else {
938 return gst_caps_copy (caps);
939 }
940 }
942 static gboolean
943 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
944 GstQuery * query, gboolean * forward)
945 {
946 gboolean res = TRUE;
948 switch (GST_QUERY_TYPE (query)) {
949 case GST_QUERY_BUFFERS:
950 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
951 gst_query_set_buffers_count (query, self->min_buffers);
953 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
954 self->padded_width, self->padded_height);
955 gst_query_set_buffers_dimensions (query,
956 self->padded_width, self->padded_height);
957 *forward = FALSE;
958 break;
959 case GST_QUERY_LATENCY:
960 {
961 gboolean live;
962 GstClockTime min, max, latency;
964 if (self->fps_d == 0) {
965 GST_INFO_OBJECT (self, "not ready to report latency");
966 res = FALSE;
967 break;
968 }
970 gst_query_parse_latency (query, &live, &min, &max);
971 if (self->fps_n != 0)
972 latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
973 else
974 latency = 0;
976 /* Take into account the backlog frames for reordering */
977 latency *= (self->backlog_maxframes + 1);
979 if (min == GST_CLOCK_TIME_NONE)
980 min = latency;
981 else
982 min += latency;
984 if (max != GST_CLOCK_TIME_NONE)
985 max += latency;
987 GST_INFO_OBJECT (self,
988 "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
989 GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
990 gst_query_set_latency (query, live, min, max);
991 break;
992 }
993 default:
994 break;
995 }
998 return res;
999 }
1001 static gboolean
1002 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
1003 {
1004 gboolean res = TRUE, forward = TRUE;
1005 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1006 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1008 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1009 res = klass->query (self, pad, query, &forward);
1010 if (res && forward)
1011 res = gst_pad_query_default (pad, query);
1013 return res;
1014 }
1016 static gboolean
1017 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1018 {
1019 GstClockTime timestamp, qostime;
1020 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1021 gint64 diff;
1023 if (self->wait_keyframe) {
1024 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1025 GST_INFO_OBJECT (self, "skipping until the next keyframe");
1026 return FALSE;
1027 }
1029 self->wait_keyframe = FALSE;
1030 }
1032 timestamp = GST_BUFFER_TIMESTAMP (buf);
1033 if (self->segment.format != GST_FORMAT_TIME ||
1034 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1035 goto no_qos;
1037 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1038 goto no_qos;
1040 qostime = gst_segment_to_running_time (&self->segment,
1041 GST_FORMAT_TIME, timestamp);
1042 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1043 /* out of segment */
1044 goto no_qos;
1046 /* see how our next timestamp relates to the latest qos timestamp. negative
1047 * values mean we are early, positive values mean we are too late. */
1048 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1050 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1051 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1052 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1053 self->qos_proportion);
1055 if (klass->can_drop_frame (self, buf, diff)) {
1056 GST_INFO_OBJECT (self, "dropping frame");
1057 return FALSE;
1058 }
1060 no_qos:
1061 return TRUE;
1062 }
1064 static gboolean
1065 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1066 gint64 diff)
1067 {
1068 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1069 GST_BUFFER_FLAG_DELTA_UNIT);
1071 if (diff >= 0 && !is_keyframe)
1072 return TRUE;
1074 return FALSE;
1075 }
1077 GstElement *parser = NULL;
1079 static GstFlowReturn
1080 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1081 {
1082 GstElement *element = NULL;
1083 GstElement *pipe = NULL;
1084 GstPad *mypad = NULL;
1085 GstPad *peerpad = NULL;
1086 GstElement *peerelement = NULL;
1088 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1089 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1090 GstFlowReturn ret = GST_FLOW_OK;
1091 Int32 err;
1092 GstBuffer *outbuf = NULL;
1093 GstCaps *outcaps = NULL;
1094 gboolean decode;
1096 *element = gst_pad_get_parent_element (pad);
1097 pipe = GST_ELEMENT (gst_element_get_parent (element));
1098 mypad = gst_element_get_static_pad (element, "sink");
1099 peerpad = gst_pad_get_peer (mypad);
1100 peerelement = gst_pad_get_parent_element (peerpad);
1101 if (parser == NULL)
1102 {
1103 parser = gst_element_factory_make ("jpegparse", NULL);
1104 if (parser == NULL)
1105 {
1106 goto normal;
1107 }
1108 if (gst_bin_add (GST_BIN (pipe), parser) == FALSE)
1109 {
1110 gst_object_unref (parser);
1111 parser = NULL;
1112 goto normal;
1113 }
1114 gst_element_set_state (parser, GST_STATE_PAUSED);
1115 gst_element_unlink (peerelement, element);
1116 gst_element_link (parser, element);
1117 if (FALSE == gst_element_link (peerelement, parser))
1118 {
1119 gst_element_set_state (parser, GST_STATE_NULL);
1120 gst_element_unlink (parser, element);
1121 gst_element_link (peerelement, element);
1122 gst_bin_remove (GST_BIN (pipe), parser);
1123 goto normal;
1124 }
1125 gst_pad_chain (gst_element_get_static_pad (parser, "sink"), buf);
1126 return GST_FLOW_OK;
1127 }
1129 normal:
1130 if (G_UNLIKELY (!self->engine)) {
1131 GST_ERROR_OBJECT (self, "no engine");
1132 gst_buffer_unref (buf);
1133 return GST_FLOW_ERROR;
1134 }
1136 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1137 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1139 decode = gst_ducati_viddec_do_qos (self, buf);
1140 if (!decode) {
1141 gst_buffer_unref (buf);
1142 return GST_FLOW_OK;
1143 }
1145 if (!self->need_out_buf)
1146 goto have_out_buf;
1148 /* do this before creating codec to ensure reverse caps negotiation
1149 * happens first:
1150 */
1151 allocate_buffer:
1152 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1153 GST_PAD_CAPS (self->srcpad), &outbuf);
1154 if (ret != GST_FLOW_OK) {
1155 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1156 gst_flow_get_name (ret));
1157 gst_buffer_unref (buf);
1158 return ret;
1159 }
1161 outcaps = GST_BUFFER_CAPS (outbuf);
1162 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1163 GstStructure *s;
1165 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1166 GST_BUFFER_SIZE (outbuf));
1168 s = gst_caps_get_structure (outcaps, 0);
1169 gst_structure_get_int (s, "rowstride", &self->stride);
1170 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1171 self->stride, self->padded_height);
1173 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1174 self->outsize, self->stride, outcaps);
1176 gst_pad_set_caps (self->srcpad, outcaps);
1178 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1179 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1180 GST_BUFFER_SIZE (outbuf), self->outsize);
1181 gst_buffer_unref (outbuf);
1182 goto allocate_buffer;
1183 }
1184 }
1186 if (G_UNLIKELY (!self->codec)) {
1187 if (!codec_create (self)) {
1188 GST_ERROR_OBJECT (self, "could not create codec");
1189 gst_buffer_unref (buf);
1190 gst_buffer_unref (outbuf);
1191 return GST_FLOW_ERROR;
1192 }
1193 }
1195 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1196 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1198 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1199 * internal pool while self->first_out_buffer == TRUE in order to simplify
1200 * things in case we need to renegotiate */
1201 self->inArgs->inputID =
1202 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1203 if (!self->inArgs->inputID) {
1204 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1205 gst_buffer_unref (buf);
1206 return GST_FLOW_ERROR;
1207 }
1208 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1210 have_out_buf:
1211 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1213 #ifdef USE_DTS_PTS_CODE
1214 if (ts != GST_CLOCK_TIME_NONE) {
1215 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1216 /* if next buffer has earlier ts than previous, then the ts
1217 * we are getting are definitely decode order (DTS):
1218 */
1219 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1220 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1221 self->ts_may_be_pts = FALSE;
1222 }
1223 self->last_dts = ts;
1224 }
1225 #endif
1227 if (self->in_size == 0 && outbuf) {
1228 GST_DEBUG_OBJECT (self, "no input, skipping process");
1230 gst_buffer_unref (outbuf);
1231 return GST_FLOW_OK;
1232 }
1234 self->inArgs->numBytes = self->in_size;
1235 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1236 self->inBufs->descs[0].memType = XDM_MEMTYPE_BO;
1238 err = codec_process (self, TRUE, FALSE, &ret);
1239 if (err) {
1240 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1241 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1242 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1243 self->error_strings);
1245 return GST_FLOW_ERROR;
1246 }
1248 if (ret != GST_FLOW_OK) {
1249 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1250 gst_flow_get_name (ret));
1252 return ret;
1253 }
1255 self->first_in_buffer = FALSE;
1257 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1258 /* The copy could be avoided by playing with the buffer pointer,
1259 but it seems to be rare and for not many bytes */
1260 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1261 self->outArgs->bytesConsumed, self->in_size,
1262 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1263 if (self->outArgs->bytesConsumed > 0) {
1264 if (self->outArgs->bytesConsumed > self->in_size) {
1265 GST_WARNING_OBJECT (self,
1266 "Codec claims to have used more bytes than supplied");
1267 self->in_size = 0;
1268 } else {
1269 if (self->outArgs->bytesConsumed < self->in_size) {
1270 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1271 self->in_size - self->outArgs->bytesConsumed);
1272 }
1273 self->in_size -= self->outArgs->bytesConsumed;
1274 }
1275 }
1276 } else {
1277 self->in_size = 0;
1278 }
1280 if (self->outArgs->outBufsInUseFlag) {
1281 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1282 self->need_out_buf = FALSE;
1283 } else {
1284 self->need_out_buf = TRUE;
1285 }
1287 if (buf) {
1288 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1289 GST_BUFFER_SIZE (buf));
1290 ts = GST_BUFFER_TIMESTAMP (buf);
1291 goto allocate_buffer;
1292 }
1294 if (self->needs_flushing)
1295 gst_ducati_viddec_codec_flush (self, FALSE);
1297 return GST_FLOW_OK;
1298 }
1300 static gboolean
1301 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1302 {
1303 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1304 gboolean ret = TRUE;
1306 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1308 switch (GST_EVENT_TYPE (event)) {
1309 case GST_EVENT_NEWSEGMENT:
1310 {
1311 gboolean update;
1312 GstFormat fmt;
1313 gint64 start, stop, time;
1314 gdouble rate, arate;
1316 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1317 &start, &stop, &time);
1318 gst_segment_set_newsegment_full (&self->segment, update,
1319 rate, arate, fmt, start, stop, time);
1320 break;
1321 }
1322 case GST_EVENT_EOS:
1323 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1324 GST_ERROR_OBJECT (self, "could not flush on eos");
1325 ret = FALSE;
1326 }
1327 break;
1328 case GST_EVENT_FLUSH_STOP:
1329 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1330 GST_ERROR_OBJECT (self, "could not flush");
1331 gst_event_unref (event);
1332 ret = FALSE;
1333 }
1334 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1335 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1336 self->qos_proportion = 1;
1337 self->need_out_buf = TRUE;
1338 break;
1339 default:
1340 break;
1341 }
1343 if (ret)
1344 ret = gst_pad_push_event (self->srcpad, event);
1345 GST_LOG_OBJECT (self, "end");
1347 return ret;
1348 }
1350 static gboolean
1351 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1352 {
1353 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1354 gboolean ret = TRUE;
1356 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1358 switch (GST_EVENT_TYPE (event)) {
1359 case GST_EVENT_QOS:
1360 {
1361 gdouble proportion;
1362 GstClockTimeDiff diff;
1363 GstClockTime timestamp;
1365 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1367 GST_OBJECT_LOCK (self);
1368 self->qos_proportion = proportion;
1369 self->qos_earliest_time = timestamp + 2 * diff;
1370 GST_OBJECT_UNLOCK (self);
1372 GST_DEBUG_OBJECT (self,
1373 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1374 proportion, GST_TIME_ARGS (timestamp), diff);
1376 ret = gst_pad_push_event (self->sinkpad, event);
1377 break;
1378 }
1379 default:
1380 ret = gst_pad_push_event (self->sinkpad, event);
1381 break;
1382 }
1384 GST_LOG_OBJECT (self, "end");
1386 return ret;
1387 }
1389 static GstStateChangeReturn
1390 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1391 {
1392 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1393 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1394 gboolean supported;
1396 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1397 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1398 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1400 switch (transition) {
1401 case GST_STATE_CHANGE_NULL_TO_READY:
1402 if (!engine_open (self)) {
1403 GST_ERROR_OBJECT (self, "could not open");
1404 return GST_STATE_CHANGE_FAILURE;
1405 }
1406 /* try to create/destroy the codec here, it may not be supported */
1407 supported = codec_create (self);
1408 codec_delete (self);
1409 self->codec = NULL;
1410 if (!supported) {
1411 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1412 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1413 engine_close (self);
1414 return GST_STATE_CHANGE_FAILURE;
1415 }
1416 break;
1417 default:
1418 break;
1419 }
1421 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1423 if (ret == GST_STATE_CHANGE_FAILURE)
1424 goto leave;
1426 switch (transition) {
1427 case GST_STATE_CHANGE_PAUSED_TO_READY:
1428 self->interlaced = FALSE;
1429 self->send_crop_event = TRUE;
1430 gst_ducati_viddec_codec_flush (self, FALSE);
1431 break;
1432 case GST_STATE_CHANGE_READY_TO_NULL:
1433 codec_delete (self);
1434 engine_close (self);
1435 break;
1436 default:
1437 break;
1438 }
1440 leave:
1441 GST_LOG_OBJECT (self, "end");
1443 return ret;
1444 }
1446 /* GObject vmethod implementations */
1449 static void
1450 gst_ducati_viddec_get_property (GObject * obj,
1451 guint prop_id, GValue * value, GParamSpec * pspec)
1452 {
1453 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1456 switch (prop_id) {
1457 case PROP_VERSION:{
1458 int err;
1459 char *version = NULL;
1461 if (!self->engine)
1462 engine_open (self);
1464 if (!self->codec)
1465 codec_create (self);
1467 if (self->codec) {
1468 version = dce_alloc (VERSION_LENGTH);
1469 if (version) {
1470 self->status->data.buf = (XDAS_Int8 *) version;
1471 self->status->data.bufSize = VERSION_LENGTH;
1473 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1474 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1475 self->dynParams, self->status);
1477 if (err) {
1478 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1479 } else
1480 GST_DEBUG ("Codec version %s", self->status->data.buf);
1482 self->status->data.buf = NULL;
1483 self->status->data.bufSize = 0;
1484 dce_free (version);
1485 }
1486 }
1487 break;
1488 }
1489 case PROP_MAX_REORDER_FRAMES:
1490 g_value_set_int (value, self->backlog_max_maxframes);
1491 break;
1492 case PROP_CODEC_DEBUG_INFO:
1493 g_value_set_boolean (value, self->codec_debug_info);
1494 break;
1495 default:{
1496 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1497 break;
1498 }
1499 }
1500 }
1502 static void
1503 gst_ducati_viddec_set_property (GObject * obj,
1504 guint prop_id, const GValue * value, GParamSpec * pspec)
1505 {
1506 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1508 switch (prop_id) {
1509 case PROP_MAX_REORDER_FRAMES:
1510 self->backlog_max_maxframes = g_value_get_int (value);
1511 break;
1512 case PROP_CODEC_DEBUG_INFO:
1513 self->codec_debug_info = g_value_get_boolean (value);
1514 break;
1515 default:{
1516 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1517 break;
1518 }
1519 }
1520 }
1522 static void
1523 gst_ducati_viddec_finalize (GObject * obj)
1524 {
1525 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1527 codec_delete (self);
1528 engine_close (self);
1530 /* Will unref the remaining buffers if needed */
1531 g_hash_table_unref (self->passed_in_bufs);
1532 if (self->codec_data) {
1533 gst_buffer_unref (self->codec_data);
1534 self->codec_data = NULL;
1535 }
1537 G_OBJECT_CLASS (parent_class)->finalize (obj);
1538 }
1540 static void
1541 gst_ducati_viddec_base_init (gpointer gclass)
1542 {
1543 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1545 gst_element_class_add_pad_template (element_class,
1546 gst_static_pad_template_get (&src_factory));
1547 }
1549 static void
1550 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1551 {
1552 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1553 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1555 gobject_class->get_property =
1556 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1557 gobject_class->set_property =
1558 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1559 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1560 gstelement_class->change_state =
1561 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1563 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1564 klass->allocate_params =
1565 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1566 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1567 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1568 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1569 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1570 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1571 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1572 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1574 g_object_class_install_property (gobject_class, PROP_VERSION,
1575 g_param_spec_string ("version", "Version",
1576 "The codec version string", "",
1577 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1579 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1580 g_param_spec_int ("max-reorder-frames",
1581 "Maximum number of frames needed for reordering",
1582 "The maximum number of frames needed for reordering output frames. "
1583 "Only meaningful for codecs with B frames. 0 means no reordering. "
1584 "This value will be used if the correct value cannot be inferred "
1585 "from the stream. Too low a value may cause misordering, too high "
1586 "will cause extra latency.",
1587 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1588 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1590 g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1591 g_param_spec_boolean ("codec-debug-info",
1592 "Gather debug info from the codec",
1593 "Gather and log relevant debug information from the codec. "
1594 "What is gathered is typically codec specific", FALSE,
1595 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1596 }
1598 static void
1599 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1600 {
1601 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1603 gst_ducati_set_generic_error_strings (self->error_strings);
1605 self->sinkpad =
1606 gst_pad_new_from_template (gst_element_class_get_pad_template
1607 (gstelement_class, "sink"), "sink");
1608 gst_pad_set_setcaps_function (self->sinkpad,
1609 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1610 gst_pad_set_chain_function (self->sinkpad,
1611 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1612 gst_pad_set_event_function (self->sinkpad,
1613 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1615 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1616 gst_pad_set_event_function (self->srcpad,
1617 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1618 gst_pad_set_query_function (self->srcpad,
1619 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1620 gst_pad_set_getcaps_function (self->srcpad,
1621 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1623 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1624 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1626 self->input_width = 0;
1627 self->input_height = 0;
1628 /* sane defaults in case we need to create codec without caps negotiation
1629 * (for example, to get 'version' property)
1630 */
1631 self->width = 128;
1632 self->height = 128;
1633 self->fps_n = -1;
1634 self->fps_d = -1;
1636 self->first_in_buffer = TRUE;
1637 self->first_out_buffer = TRUE;
1638 self->interlaced = FALSE;
1639 self->send_crop_event = TRUE;
1641 #ifdef USE_DTS_PTS_CODE
1642 self->dts_ridx = self->dts_widx = 0;
1643 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1644 self->ts_may_be_pts = TRUE;
1645 self->ts_is_pts = FALSE;
1646 #endif
1648 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1650 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1652 self->qos_proportion = 1;
1653 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1654 self->wait_keyframe = TRUE;
1656 self->need_out_buf = TRUE;
1657 self->device = NULL;
1658 self->input_bo = NULL;
1660 self->backlog_maxframes = 0;
1661 self->backlog_nframes = 0;
1662 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1664 self->codec_debug_info = FALSE;
1666 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1667 NULL, (GDestroyNotify) gst_buffer_unref);
1668 }