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->params) {
52 dce_free (self->params);
53 self->params = NULL;
54 }
56 if (self->dynParams) {
57 dce_free (self->dynParams);
58 self->dynParams = NULL;
59 }
61 if (self->status) {
62 dce_free (self->status);
63 self->status = NULL;
64 }
66 if (self->inBufs) {
67 dce_free (self->inBufs);
68 self->inBufs = NULL;
69 }
71 if (self->outBufs) {
72 dce_free (self->outBufs);
73 self->outBufs = NULL;
74 }
76 if (self->inArgs) {
77 dce_free (self->inArgs);
78 self->inArgs = NULL;
79 }
81 if (self->outArgs) {
82 dce_free (self->outArgs);
83 self->outArgs = NULL;
84 }
86 if (self->engine) {
87 Engine_close (self->engine);
88 self->engine = 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 = FALSE;
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 /* IPC requires dmabuf fd in place of bo handle */
220 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
222 /* Actual buffers will be set later, as they will be different for every
223 frame. We allow derived classes to add their own buffers, however, so
224 we initialize the number of outBufs here, counting the number of extra
225 buffers required, including "holes" in planes, which may not be filled
226 if not assigned. */
227 self->outBufs->numBufs = 2; /* luma and chroma planes, always */
228 for (n = 0; n < 3; n++)
229 if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
230 self->outBufs->numBufs = 2 + n + 1;
232 return TRUE;
233 }
235 static inline GstBuffer *
236 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
237 {
238 if (G_UNLIKELY (!self->pool)) {
239 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
240 self->padded_width, self->padded_height);
242 GST_DEBUG_OBJECT (self, "creating bufferpool");
243 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
244 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
245 }
246 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
247 }
249 static GstDucatiBufferPriv *
250 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
251 {
252 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
253 if (!priv) {
254 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
255 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
257 /* if it isn't a dmabuf buffer that we can import, then there
258 * is nothing we can do with it:
259 */
260 if (!dmabuf) {
261 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
262 return NULL;
263 }
265 priv = gst_ducati_buffer_priv_new ();
267 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
269 priv->uv_offset = gst_video_format_get_component_offset (format,
270 1, self->stride, self->padded_height);
271 priv->size = gst_video_format_get_size (format,
272 self->stride, self->padded_height);
274 gst_ducati_buffer_priv_set (buf, priv);
275 gst_mini_object_unref (GST_MINI_OBJECT (priv));
276 }
277 return priv;
278 }
280 static XDAS_Int32
281 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
282 gboolean force_internal)
283 {
284 GstDucatiBufferPriv *priv = NULL;
285 GstDmaBuf *dmabuf = NULL;
287 if (!force_internal)
288 priv = get_buffer_priv (self, *buf);
290 if (!priv) {
291 GstBuffer *orig = *buf;
293 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
294 *buf = codec_buffer_pool_get (self, NULL);
295 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
296 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
297 gst_buffer_unref (orig);
298 return codec_prepare_outbuf (self, buf, FALSE);
299 }
301 /* There are at least two buffers. Derived classes may add codec specific
302 buffers (eg, debug info) after these two if they want to. */
303 dmabuf = gst_buffer_get_dma_buf (*buf);
304 /* XDM_MemoryType required by drm to allcoate buffer */
305 self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
306 /* IPC requires dmabuf fd in place of bo handle */
307 self->outBufs->descs[0].buf = (XDAS_Int8 *) gst_dma_buf_get_fd (dmabuf);
308 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
309 self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
310 /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
311 ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
312 should point to a single buffer fd and need to update the
313 descs[0].bufSize.bytes with the size of luminance(Y) data
314 and descs[1].bufSize.bytes with crominance(UV) */
315 self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
316 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
318 return (XDAS_Int32) * buf;
319 }
321 static GstBuffer *
322 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
323 {
324 GstBuffer *buf = (GstBuffer *) id;
326 if (buf) {
327 g_hash_table_insert (self->passed_in_bufs, buf, buf);
329 gst_buffer_ref (buf);
330 }
331 return buf;
332 }
334 static void
335 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
336 {
337 GstBuffer *buf = (GstBuffer *) id;
338 SizeT fd;
340 if (buf) {
341 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
342 /* Get dmabuf fd of the buffer to unlock */
343 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf(buf));
344 /* Must unlock the buffer before free */
345 dce_buf_unlock(1,&fd);
346 g_hash_table_remove (self->passed_in_bufs, buf);
347 }
348 }
350 static GstFlowReturn
351 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
352 {
353 guint64 earliest_order = G_MAXUINT64;
354 guint earliest_index = 0, i;
355 GstBuffer *buf;
357 if (self->backlog_nframes == 0)
358 return GST_FLOW_OK;
360 /* work out which frame has the earliest poc */
361 for (i = 0; i < self->backlog_nframes; i++) {
362 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
363 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
364 earliest_order = order;
365 earliest_index = i;
366 }
367 }
369 /* send it, giving away the ref */
370 buf = self->backlog_frames[earliest_index];
371 self->backlog_frames[earliest_index] =
372 self->backlog_frames[--self->backlog_nframes];
373 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
374 buf);
375 return gst_pad_push (self->srcpad, buf);
376 }
378 static void
379 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
380 {
381 /* push everything on the backlog, ignoring errors */
382 while (self->backlog_nframes > 0) {
383 gst_ducati_viddec_push_earliest (self);
384 }
385 }
387 static gint
388 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
389 GstFlowReturn * flow_ret)
390 {
391 gint err;
392 GstClockTime t;
393 GstBuffer *outbuf = NULL;
394 gint i;
395 SizeT fd;
396 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
397 GstFlowReturn ret = GST_FLOW_OK;
398 if (flow_ret)
399 /* never leave flow_ret uninitialized */
400 *flow_ret = GST_FLOW_OK;
402 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
403 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
405 if (self->inArgs->inputID != 0) {
406 /* Get dmabuf fd of the buffer to lock it*/
407 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf((GstBuffer *) self->inArgs->inputID));
408 /* Must lock all the buffer passed to ducati */
409 dce_buf_lock(1,&fd);
410 }
412 GST_DEBUG ("Calling VIDDEC3_process");
413 t = gst_util_get_timestamp ();
414 err = VIDDEC3_process (self->codec,
415 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
416 t = gst_util_get_timestamp () - t;
417 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
418 (gint) (t / 1000000));
420 if (err) {
421 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
422 err, self->outArgs->extendedError);
423 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
424 self->error_strings);
426 GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
427 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
428 self->dynParams, self->status);
429 if (err) {
430 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
431 err, self->status->extendedError);
432 gst_ducati_log_extended_error_info (self->status->extendedError,
433 self->error_strings);
434 }
436 if (flush)
437 err = XDM_EFAIL;
438 else
439 err = klass->handle_error (self, err,
440 self->outArgs->extendedError, self->status->extendedError);
441 }
443 /* we now let the codec decide */
444 self->dynParams->newFrameFlag = XDAS_FALSE;
446 if (err == XDM_EFAIL)
447 goto skip_outbuf_processing;
449 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
450 gboolean interlaced;
452 interlaced =
453 self->outArgs->displayBufs.bufDesc[0].contentType ==
454 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
456 if (interlaced) {
457 GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
458 if (!buf || !gst_buffer_is_metadata_writable (buf)) {
459 GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
460 } else {
461 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_TFF);
462 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_RFF);
463 if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
464 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_TFF);
465 if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
466 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_RFF);
467 }
468 }
470 /* Getting an extra reference for the decoder */
471 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
473 /* if send is FALSE, don't try to renegotiate as we could be flushing during
474 * a PAUSED->READY state change
475 */
476 if (send && interlaced != self->interlaced) {
477 GstCaps *caps;
479 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
480 "thinks interlaced=%d... trusting codec", self->interlaced,
481 interlaced);
483 self->interlaced = interlaced;
485 caps =
486 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
487 GST_INFO_OBJECT (self, "changing interlace field in caps");
488 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
489 NULL);
490 if (self->pool) gst_drm_buffer_pool_set_caps (self->pool, caps);
491 if (!gst_pad_set_caps (self->srcpad, caps)) {
492 GST_ERROR_OBJECT (self,
493 "downstream didn't want to change interlace mode");
494 err = XDM_EFAIL;
495 }
496 gst_caps_unref (caps);
498 /* this buffer still has the old caps so we skip it */
499 send = FALSE;
500 }
502 if (G_UNLIKELY (self->send_crop_event) && send) {
503 gint crop_width, crop_height;
505 /* send region of interest to sink on first buffer: */
506 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
508 crop_width = r->bottomRight.x - r->topLeft.x;
509 crop_height = r->bottomRight.y - r->topLeft.y;
511 if (crop_width > self->input_width)
512 crop_width = self->input_width;
513 if (crop_height > self->input_height)
514 crop_height = self->input_height;
516 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
517 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
518 crop_width, crop_height);
520 gst_pad_push_event (self->srcpad,
521 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
522 crop_width, crop_height));
524 if (self->crop)
525 gst_video_crop_unref (self->crop);
527 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
528 crop_width, crop_height);
530 self->send_crop_event = FALSE;
531 }
533 if (G_UNLIKELY (self->first_out_buffer) && send) {
534 GstDRMBufferPool *pool;
535 self->first_out_buffer = FALSE;
537 /* Destroy the pool so the buffers we used so far are eventually released.
538 * The pool will be recreated if needed.
539 */
540 pool = self->pool;
541 self->pool = NULL;
542 if (pool) gst_drm_buffer_pool_destroy (pool);
543 }
545 if (send) {
546 GstClockTime ts;
548 ts = GST_BUFFER_TIMESTAMP (outbuf);
550 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
551 i, outbuf, GST_TIME_ARGS (ts));
553 #ifdef USE_DTS_PTS_CODE
554 if (self->ts_may_be_pts) {
555 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
556 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
557 "enabling ts_is_pts");
558 self->ts_is_pts = TRUE;
559 }
560 }
561 #endif
563 self->last_pts = ts;
565 if (self->dts_ridx != self->dts_widx) {
566 ts = self->dts_queue[self->dts_ridx++ % NDTS];
567 }
569 if (self->ts_is_pts) {
570 /* if we have a queued DTS from demuxer, use that instead: */
571 GST_BUFFER_TIMESTAMP (outbuf) = ts;
572 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
573 i, outbuf, GST_TIME_ARGS (ts));
574 }
576 if (GST_BUFFER_CAPS (outbuf) &&
577 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
578 GST_PAD_CAPS (self->srcpad))) {
579 /* this looks a bit scary but it's really just to change the interlace=
580 * field in caps when we start as !interlaced and the codec detects
581 * otherwise */
582 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
583 "interlace mismatch");
584 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
585 }
587 if (self->crop)
588 gst_buffer_set_video_crop (outbuf, self->crop);
590 ret = klass->push_output (self, outbuf);
591 if (flow_ret)
592 *flow_ret = ret;
593 if (ret != GST_FLOW_OK) {
594 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
595 /* just unref the remaining buffers (if any) */
596 send = FALSE;
597 }
598 } else {
599 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
600 i, outbuf);
602 gst_buffer_unref (outbuf);
603 }
604 }
606 skip_outbuf_processing:
607 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
608 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
609 }
611 return err;
612 }
614 /** call control(FLUSH), and then process() to pop out all buffers */
615 gboolean
616 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
617 {
618 gint err = FALSE;
619 int prev_num_in_bufs, prev_num_out_bufs;
621 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
623 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
625 /* note: flush is synchronized against _chain() to avoid calling
626 * the codec from multiple threads
627 */
628 GST_PAD_STREAM_LOCK (self->sinkpad);
630 #ifdef USE_DTS_PTS_CODE
631 self->dts_ridx = self->dts_widx = 0;
632 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
633 self->ts_may_be_pts = TRUE;
634 self->ts_is_pts = FALSE;
635 #endif
636 self->wait_keyframe = TRUE;
637 self->in_size = 0;
638 self->needs_flushing = FALSE;
639 self->need_out_buf = TRUE;
641 if (G_UNLIKELY (self->first_in_buffer)) {
642 goto out;
643 }
645 if (G_UNLIKELY (!self->codec)) {
646 GST_WARNING_OBJECT (self, "no codec");
647 goto out;
648 }
651 GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
652 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
653 if (err) {
654 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
655 goto out;
656 }
658 prev_num_in_bufs = self->inBufs->numBufs;
659 prev_num_out_bufs = self->outBufs->numBufs;
661 self->inBufs->descs[0].bufSize.bytes = 0;
662 self->inBufs->numBufs = 0;
663 self->inArgs->numBytes = 0;
664 self->inArgs->inputID = 0;
665 self->outBufs->numBufs = 0;
667 do {
668 err = codec_process (self, eos, TRUE, NULL);
669 } while (err != XDM_EFAIL);
671 /* We flushed the decoder, we can now remove the buffer that have never been
672 * unrefed in it */
673 g_hash_table_remove_all (self->passed_in_bufs);
675 /* reset outArgs in case we're flushing in codec_process trying to do error
676 * recovery */
677 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
678 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
680 self->dynParams->newFrameFlag = XDAS_TRUE;
682 /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
683 self->inBufs->numBufs = prev_num_in_bufs;
684 self->outBufs->numBufs = prev_num_out_bufs;
686 /* on a flush, it is normal (and not an error) for the last _process() call
687 * to return an error..
688 */
689 err = XDM_EOK;
691 out:
692 GST_PAD_STREAM_UNLOCK (self->sinkpad);
693 GST_DEBUG_OBJECT (self, "done");
695 return !err;
696 }
698 /* GstDucatiVidDec vmethod default implementations */
700 static gboolean
701 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
702 {
703 const GValue *codec_data;
704 gint w, h;
706 if (gst_structure_get_int (s, "width", &self->input_width) &&
707 gst_structure_get_int (s, "height", &self->input_height)) {
709 h = ALIGN2 (self->input_height, 4); /* round up to MB */
710 w = ALIGN2 (self->input_width, 4); /* round up to MB */
712 /* if we've already created codec, but the resolution has changed, we
713 * need to re-create the codec:
714 */
715 if (G_UNLIKELY (self->codec)) {
716 if ((h != self->height) || (w != self->width)) {
717 codec_delete (self);
718 }
719 }
721 self->width = w;
722 self->height = h;
724 codec_data = gst_structure_get_value (s, "codec_data");
726 if (codec_data) {
727 GstBuffer *buffer = gst_value_get_buffer (codec_data);
728 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
729 self->codec_data = gst_buffer_ref (buffer);
730 }
732 return TRUE;
733 }
735 return FALSE;
736 }
738 static gboolean
739 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
740 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
741 {
743 /* allocate params: */
744 self->params = dce_alloc (params_sz);
745 if (G_UNLIKELY (!self->params)) {
746 return FALSE;
747 }
748 self->params->size = params_sz;
749 self->params->maxFrameRate = 30000;
750 self->params->maxBitRate = 10000000;
752 self->params->dataEndianness = XDM_BYTE;
753 self->params->forceChromaFormat = XDM_YUV_420SP;
754 self->params->operatingMode = IVIDEO_DECODE_ONLY;
756 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
757 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
758 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
759 self->params->numInputDataUnits = 0;
760 self->params->numOutputDataUnits = 0;
762 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
763 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
764 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
765 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
767 /* allocate dynParams: */
768 self->dynParams = dce_alloc (dynparams_sz);
769 if (G_UNLIKELY (!self->dynParams)) {
770 return FALSE;
771 }
772 self->dynParams->size = dynparams_sz;
773 self->dynParams->decodeHeader = XDM_DECODE_AU;
774 self->dynParams->displayWidth = 0;
775 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
776 self->dynParams->newFrameFlag = XDAS_TRUE;
778 /* allocate status: */
779 self->status = dce_alloc (status_sz);
780 if (G_UNLIKELY (!self->status)) {
781 return FALSE;
782 }
783 memset (self->status, 0, status_sz);
784 self->status->size = status_sz;
786 /* allocate inBufs/outBufs: */
787 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
788 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
789 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
790 return FALSE;
791 }
793 /* allocate inArgs/outArgs: */
794 self->inArgs = dce_alloc (inargs_sz);
795 self->outArgs = dce_alloc (outargs_sz);
796 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
797 return FALSE;
798 }
799 self->inArgs->size = inargs_sz;
800 self->outArgs->size = outargs_sz;
802 return TRUE;
803 }
805 static GstBuffer *
806 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
807 {
808 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
809 push_input (self, GST_BUFFER_DATA (self->codec_data),
810 GST_BUFFER_SIZE (self->codec_data));
811 }
813 /* just copy entire buffer */
814 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
815 gst_buffer_unref (buf);
817 return NULL;
818 }
820 static GstFlowReturn
821 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
822 {
823 GstFlowReturn ret = GST_FLOW_OK;
825 /* if no reordering info was set, just send the buffer */
826 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
827 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
828 return gst_pad_push (self->srcpad, buf);
829 }
831 /* add the frame to the list, the array will own the ref */
832 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
833 self->backlog_frames[self->backlog_nframes++] = buf;
835 /* push till we have no more than the max needed, or error */
836 while (self->backlog_nframes > self->backlog_maxframes) {
837 ret = gst_ducati_viddec_push_earliest (self);
838 if (ret != GST_FLOW_OK)
839 break;
840 }
842 return ret;
843 }
845 static gint
846 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
847 gint extended_error, gint status_extended_error)
848 {
849 if (XDM_ISFATALERROR (extended_error))
850 ret = XDM_EFAIL;
851 else
852 ret = XDM_EOK;
854 return ret;
855 }
857 /* GstElement vmethod implementations */
859 static gboolean
860 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
861 {
862 gboolean ret = TRUE;
863 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
864 GstStructure *s;
865 GstCaps *outcaps = NULL;
866 GstStructure *out_s;
867 gint par_width, par_height;
868 gboolean par_present;
870 s = gst_caps_get_structure (caps, 0);
871 if (!klass->parse_caps (self, s)) {
872 GST_WARNING_OBJECT (self, "missing required fields");
873 ret = FALSE;
874 goto out;
875 }
877 /* update output/padded sizes */
878 klass->update_buffer_size (self);
880 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
881 self->fps_n = 0;
882 self->fps_d = 1;
883 }
884 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
885 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
886 &par_width, &par_height);
888 outcaps = gst_pad_get_allowed_caps (self->srcpad);
889 if (outcaps) {
890 outcaps = gst_caps_make_writable (outcaps);
891 gst_caps_truncate (outcaps);
892 if (gst_caps_is_empty (outcaps)) {
893 gst_caps_unref (outcaps);
894 outcaps = NULL;
895 }
896 }
898 if (!outcaps) {
899 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
900 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
901 }
903 out_s = gst_caps_get_structure (outcaps, 0);
904 gst_structure_set (out_s,
905 "width", G_TYPE_INT, self->padded_width,
906 "height", G_TYPE_INT, self->padded_height,
907 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
908 if (par_present)
909 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
910 par_width, par_height, NULL);
912 if (self->interlaced)
913 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
915 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
916 0, self->padded_width);
918 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
919 self->stride, self->padded_height);
921 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
922 self->outsize, self->stride, outcaps);
924 if (!self->first_in_buffer) {
925 /* Caps changed mid stream. We flush the codec to unlock all the potentially
926 * locked buffers. This is needed for downstream sinks that provide a
927 * buffer pool and need to destroy all the outstanding buffers before they
928 * can negotiate new caps (hello v4l2sink).
929 */
930 gst_ducati_viddec_codec_flush (self, FALSE);
931 }
933 /* (re)send a crop event when caps change */
934 self->send_crop_event = TRUE;
936 ret = gst_pad_set_caps (self->srcpad, outcaps);
938 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
940 /* default to no reordering */
941 self->backlog_maxframes = 0;
943 out:
944 if (outcaps)
945 gst_caps_unref (outcaps);
947 return ret;
948 }
950 static gboolean
951 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
952 {
953 gboolean ret = TRUE;
954 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
955 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
957 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
959 ret = klass->set_sink_caps (self, caps);
961 gst_object_unref (self);
963 return ret;
964 }
966 static GstCaps *
967 gst_ducati_viddec_src_getcaps (GstPad * pad)
968 {
969 GstCaps *caps = NULL;
971 caps = GST_PAD_CAPS (pad);
972 if (caps == NULL) {
973 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
974 } else {
975 return gst_caps_copy (caps);
976 }
977 }
979 static gboolean
980 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
981 GstQuery * query, gboolean * forward)
982 {
983 gboolean res = TRUE;
985 switch (GST_QUERY_TYPE (query)) {
986 case GST_QUERY_BUFFERS:
987 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
988 gst_query_set_buffers_count (query, self->min_buffers);
990 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
991 self->padded_width, self->padded_height);
992 gst_query_set_buffers_dimensions (query,
993 self->padded_width, self->padded_height);
994 *forward = FALSE;
995 break;
996 case GST_QUERY_LATENCY:
997 {
998 gboolean live;
999 GstClockTime min, max, latency;
1001 if (self->fps_d == 0) {
1002 GST_INFO_OBJECT (self, "not ready to report latency");
1003 res = FALSE;
1004 break;
1005 }
1007 gst_query_parse_latency (query, &live, &min, &max);
1008 if (self->fps_n != 0)
1009 latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1010 else
1011 latency = 0;
1013 /* Take into account the backlog frames for reordering */
1014 latency *= (self->backlog_maxframes + 1);
1016 if (min == GST_CLOCK_TIME_NONE)
1017 min = latency;
1018 else
1019 min += latency;
1021 if (max != GST_CLOCK_TIME_NONE)
1022 max += latency;
1024 GST_INFO_OBJECT (self,
1025 "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1026 GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1027 gst_query_set_latency (query, live, min, max);
1028 break;
1029 }
1030 default:
1031 break;
1032 }
1035 return res;
1036 }
1038 static gboolean
1039 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
1040 {
1041 gboolean res = TRUE, forward = TRUE;
1042 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1043 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1045 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1046 res = klass->query (self, pad, query, &forward);
1047 if (res && forward)
1048 res = gst_pad_query_default (pad, query);
1050 return res;
1051 }
1053 static gboolean
1054 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1055 {
1056 GstClockTime timestamp, qostime;
1057 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1058 gint64 diff;
1060 if (self->wait_keyframe) {
1061 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1062 GST_INFO_OBJECT (self, "skipping until the next keyframe");
1063 return FALSE;
1064 }
1066 self->wait_keyframe = FALSE;
1067 }
1069 timestamp = GST_BUFFER_TIMESTAMP (buf);
1070 if (self->segment.format != GST_FORMAT_TIME ||
1071 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1072 goto no_qos;
1074 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1075 goto no_qos;
1077 qostime = gst_segment_to_running_time (&self->segment,
1078 GST_FORMAT_TIME, timestamp);
1079 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1080 /* out of segment */
1081 goto no_qos;
1083 /* see how our next timestamp relates to the latest qos timestamp. negative
1084 * values mean we are early, positive values mean we are too late. */
1085 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1087 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1088 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1089 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1090 self->qos_proportion);
1092 if (klass->can_drop_frame (self, buf, diff)) {
1093 GST_INFO_OBJECT (self, "dropping frame");
1094 return FALSE;
1095 }
1097 no_qos:
1098 return TRUE;
1099 }
1101 static gboolean
1102 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1103 gint64 diff)
1104 {
1105 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1106 GST_BUFFER_FLAG_DELTA_UNIT);
1108 if (diff >= 0 && !is_keyframe)
1109 return TRUE;
1111 return FALSE;
1112 }
1114 GstElement *parser = NULL;
1116 static GstFlowReturn
1117 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1118 {
1119 GstElement *element = NULL;
1120 GstElement *pipe = NULL;
1121 GstPad *mypad = NULL;
1122 GstPad *peerpad = NULL;
1123 GstElement *peerelement = NULL;
1124 SizeT fd;
1126 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1127 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1128 GstFlowReturn ret = GST_FLOW_OK;
1129 Int32 err;
1130 GstBuffer *outbuf = NULL;
1131 GstCaps *outcaps = NULL;
1132 gboolean decode;
1134 element = gst_pad_get_parent_element (pad);
1135 pipe = GST_ELEMENT (gst_element_get_parent (element));
1136 mypad = gst_element_get_static_pad (element, "sink");
1137 peerpad = gst_pad_get_peer (mypad);
1138 peerelement = gst_pad_get_parent_element (peerpad);
1139 if (parser == NULL)
1140 {
1141 parser = gst_element_factory_make ("jpegparse", NULL);
1142 if (parser == NULL)
1143 {
1144 goto normal;
1145 }
1146 if (gst_bin_add (GST_BIN (pipe), parser) == FALSE)
1147 {
1148 gst_object_unref (parser);
1149 parser = NULL;
1150 goto normal;
1151 }
1152 gst_element_set_state (parser, GST_STATE_PAUSED);
1153 gst_element_unlink (peerelement, element);
1154 gst_element_link (parser, element);
1155 if (FALSE == gst_element_link (peerelement, parser))
1156 {
1157 gst_element_set_state (parser, GST_STATE_NULL);
1158 gst_element_unlink (parser, element);
1159 gst_element_link (peerelement, element);
1160 gst_bin_remove (GST_BIN (pipe), parser);
1161 goto normal;
1162 }
1163 gst_pad_chain (gst_element_get_static_pad (parser, "sink"), buf);
1164 return GST_FLOW_OK;
1165 }
1167 normal:
1168 if (G_UNLIKELY (!self->engine)) {
1169 GST_ERROR_OBJECT (self, "no engine");
1170 gst_buffer_unref (buf);
1171 return GST_FLOW_ERROR;
1172 }
1174 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1175 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1177 decode = gst_ducati_viddec_do_qos (self, buf);
1178 if (!decode) {
1179 gst_buffer_unref (buf);
1180 return GST_FLOW_OK;
1181 }
1183 if (!self->need_out_buf)
1184 goto have_out_buf;
1186 /* do this before creating codec to ensure reverse caps negotiation
1187 * happens first:
1188 */
1189 allocate_buffer:
1190 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1191 GST_PAD_CAPS (self->srcpad), &outbuf);
1192 if (ret != GST_FLOW_OK) {
1193 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1194 gst_flow_get_name (ret));
1195 gst_buffer_unref (buf);
1196 return ret;
1197 }
1199 outcaps = GST_BUFFER_CAPS (outbuf);
1200 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1201 GstStructure *s;
1203 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1204 GST_BUFFER_SIZE (outbuf));
1206 s = gst_caps_get_structure (outcaps, 0);
1207 gst_structure_get_int (s, "rowstride", &self->stride);
1208 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1209 self->stride, self->padded_height);
1211 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1212 self->outsize, self->stride, outcaps);
1214 gst_pad_set_caps (self->srcpad, outcaps);
1216 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1217 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1218 GST_BUFFER_SIZE (outbuf), self->outsize);
1219 gst_buffer_unref (outbuf);
1220 goto allocate_buffer;
1221 }
1222 }
1224 if (G_UNLIKELY (!self->codec)) {
1225 if (!codec_create (self)) {
1226 GST_ERROR_OBJECT (self, "could not create codec");
1227 gst_buffer_unref (buf);
1228 gst_buffer_unref (outbuf);
1229 return GST_FLOW_ERROR;
1230 }
1231 }
1233 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1234 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1236 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1237 * internal pool while self->first_out_buffer == TRUE in order to simplify
1238 * things in case we need to renegotiate */
1239 self->inArgs->inputID =
1240 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1241 if (!self->inArgs->inputID) {
1242 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1243 gst_buffer_unref (buf);
1244 return GST_FLOW_ERROR;
1245 }
1246 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1248 have_out_buf:
1249 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1251 #ifdef USE_DTS_PTS_CODE
1252 if (ts != GST_CLOCK_TIME_NONE) {
1253 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1254 /* if next buffer has earlier ts than previous, then the ts
1255 * we are getting are definitely decode order (DTS):
1256 */
1257 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1258 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1259 self->ts_may_be_pts = FALSE;
1260 }
1261 self->last_dts = ts;
1262 }
1263 #endif
1265 if (self->in_size == 0 && outbuf) {
1266 GST_DEBUG_OBJECT (self, "no input, skipping process");
1268 gst_buffer_unref (outbuf);
1269 return GST_FLOW_OK;
1270 }
1272 self->inArgs->numBytes = self->in_size;
1273 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1274 /* XDM_MemoryType required by drm to allcoate buffer */
1275 self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1277 err = codec_process (self, TRUE, FALSE, &ret);
1278 if (err) {
1279 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1280 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1281 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1282 self->error_strings);
1284 return GST_FLOW_ERROR;
1285 }
1287 if (ret != GST_FLOW_OK) {
1288 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1289 gst_flow_get_name (ret));
1291 return ret;
1292 }
1294 self->first_in_buffer = FALSE;
1296 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1297 /* The copy could be avoided by playing with the buffer pointer,
1298 but it seems to be rare and for not many bytes */
1299 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1300 self->outArgs->bytesConsumed, self->in_size,
1301 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1302 if (self->outArgs->bytesConsumed > 0) {
1303 if (self->outArgs->bytesConsumed > self->in_size) {
1304 GST_WARNING_OBJECT (self,
1305 "Codec claims to have used more bytes than supplied");
1306 self->in_size = 0;
1307 } else {
1308 if (self->outArgs->bytesConsumed < self->in_size) {
1309 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1310 self->in_size - self->outArgs->bytesConsumed);
1311 }
1312 self->in_size -= self->outArgs->bytesConsumed;
1313 }
1314 }
1315 } else {
1316 self->in_size = 0;
1317 }
1319 if (self->outArgs->outBufsInUseFlag) {
1320 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1321 self->need_out_buf = FALSE;
1322 } else {
1323 self->need_out_buf = TRUE;
1324 }
1326 if (buf) {
1327 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1328 GST_BUFFER_SIZE (buf));
1329 ts = GST_BUFFER_TIMESTAMP (buf);
1330 goto allocate_buffer;
1331 }
1333 if (self->needs_flushing)
1334 gst_ducati_viddec_codec_flush (self, FALSE);
1336 return GST_FLOW_OK;
1337 }
1339 static gboolean
1340 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1341 {
1342 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1343 gboolean ret = TRUE;
1345 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1347 switch (GST_EVENT_TYPE (event)) {
1348 case GST_EVENT_NEWSEGMENT:
1349 {
1350 gboolean update;
1351 GstFormat fmt;
1352 gint64 start, stop, time;
1353 gdouble rate, arate;
1355 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1356 &start, &stop, &time);
1357 gst_segment_set_newsegment_full (&self->segment, update,
1358 rate, arate, fmt, start, stop, time);
1359 break;
1360 }
1361 case GST_EVENT_EOS:
1362 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1363 GST_ERROR_OBJECT (self, "could not flush on eos");
1364 ret = FALSE;
1365 }
1366 break;
1367 case GST_EVENT_FLUSH_STOP:
1368 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1369 GST_ERROR_OBJECT (self, "could not flush");
1370 gst_event_unref (event);
1371 ret = FALSE;
1372 }
1373 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1374 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1375 self->qos_proportion = 1;
1376 self->need_out_buf = TRUE;
1377 break;
1378 default:
1379 break;
1380 }
1382 if (ret)
1383 ret = gst_pad_push_event (self->srcpad, event);
1384 GST_LOG_OBJECT (self, "end");
1386 return ret;
1387 }
1389 static gboolean
1390 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1391 {
1392 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1393 gboolean ret = TRUE;
1395 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1397 switch (GST_EVENT_TYPE (event)) {
1398 case GST_EVENT_QOS:
1399 {
1400 gdouble proportion;
1401 GstClockTimeDiff diff;
1402 GstClockTime timestamp;
1404 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1406 GST_OBJECT_LOCK (self);
1407 self->qos_proportion = proportion;
1408 self->qos_earliest_time = timestamp + 2 * diff;
1409 GST_OBJECT_UNLOCK (self);
1411 GST_DEBUG_OBJECT (self,
1412 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1413 proportion, GST_TIME_ARGS (timestamp), diff);
1415 ret = gst_pad_push_event (self->sinkpad, event);
1416 break;
1417 }
1418 default:
1419 ret = gst_pad_push_event (self->sinkpad, event);
1420 break;
1421 }
1423 GST_LOG_OBJECT (self, "end");
1425 return ret;
1426 }
1428 static GstStateChangeReturn
1429 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1430 {
1431 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1432 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1433 gboolean supported;
1435 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1436 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1437 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1439 switch (transition) {
1440 case GST_STATE_CHANGE_NULL_TO_READY:
1441 if (!engine_open (self)) {
1442 GST_ERROR_OBJECT (self, "could not open");
1443 return GST_STATE_CHANGE_FAILURE;
1444 }
1445 /* try to create/destroy the codec here, it may not be supported */
1446 supported = codec_create (self);
1447 codec_delete (self);
1448 self->codec = NULL;
1449 if (!supported) {
1450 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1451 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1452 engine_close (self);
1453 return GST_STATE_CHANGE_FAILURE;
1454 }
1455 break;
1456 default:
1457 break;
1458 }
1460 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1462 if (ret == GST_STATE_CHANGE_FAILURE)
1463 goto leave;
1465 switch (transition) {
1466 case GST_STATE_CHANGE_PAUSED_TO_READY:
1467 self->interlaced = FALSE;
1468 self->send_crop_event = TRUE;
1469 gst_ducati_viddec_codec_flush (self, FALSE);
1470 break;
1471 case GST_STATE_CHANGE_READY_TO_NULL:
1472 codec_delete (self);
1473 engine_close (self);
1474 break;
1475 default:
1476 break;
1477 }
1479 leave:
1480 GST_LOG_OBJECT (self, "end");
1482 return ret;
1483 }
1485 /* GObject vmethod implementations */
1488 static void
1489 gst_ducati_viddec_get_property (GObject * obj,
1490 guint prop_id, GValue * value, GParamSpec * pspec)
1491 {
1492 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1495 switch (prop_id) {
1496 case PROP_VERSION:{
1497 int err;
1498 char *version = NULL;
1500 if (!self->engine)
1501 engine_open (self);
1503 if (!self->codec)
1504 codec_create (self);
1506 if (self->codec) {
1507 version = dce_alloc (VERSION_LENGTH);
1508 if (version) {
1509 self->status->data.buf = (XDAS_Int8 *) version;
1510 self->status->data.bufSize = VERSION_LENGTH;
1512 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1513 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1514 self->dynParams, self->status);
1516 if (err) {
1517 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1518 } else
1519 GST_DEBUG ("Codec version %s", self->status->data.buf);
1521 self->status->data.buf = NULL;
1522 self->status->data.bufSize = 0;
1523 dce_free (version);
1524 }
1525 }
1526 break;
1527 }
1528 case PROP_MAX_REORDER_FRAMES:
1529 g_value_set_int (value, self->backlog_max_maxframes);
1530 break;
1531 case PROP_CODEC_DEBUG_INFO:
1532 g_value_set_boolean (value, self->codec_debug_info);
1533 break;
1534 default:{
1535 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1536 break;
1537 }
1538 }
1539 }
1541 static void
1542 gst_ducati_viddec_set_property (GObject * obj,
1543 guint prop_id, const GValue * value, GParamSpec * pspec)
1544 {
1545 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1547 switch (prop_id) {
1548 case PROP_MAX_REORDER_FRAMES:
1549 self->backlog_max_maxframes = g_value_get_int (value);
1550 break;
1551 case PROP_CODEC_DEBUG_INFO:
1552 self->codec_debug_info = g_value_get_boolean (value);
1553 break;
1554 default:{
1555 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1556 break;
1557 }
1558 }
1559 }
1561 static void
1562 gst_ducati_viddec_finalize (GObject * obj)
1563 {
1564 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1566 codec_delete (self);
1567 engine_close (self);
1569 /* Will unref the remaining buffers if needed */
1570 g_hash_table_unref (self->passed_in_bufs);
1571 if (self->codec_data) {
1572 gst_buffer_unref (self->codec_data);
1573 self->codec_data = NULL;
1574 }
1576 G_OBJECT_CLASS (parent_class)->finalize (obj);
1577 }
1579 static void
1580 gst_ducati_viddec_base_init (gpointer gclass)
1581 {
1582 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1584 gst_element_class_add_pad_template (element_class,
1585 gst_static_pad_template_get (&src_factory));
1586 }
1588 static void
1589 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1590 {
1591 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1592 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1594 gobject_class->get_property =
1595 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1596 gobject_class->set_property =
1597 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1598 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1599 gstelement_class->change_state =
1600 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1602 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1603 klass->allocate_params =
1604 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1605 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1606 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1607 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1608 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1609 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1610 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1611 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1613 g_object_class_install_property (gobject_class, PROP_VERSION,
1614 g_param_spec_string ("version", "Version",
1615 "The codec version string", "",
1616 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1618 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1619 g_param_spec_int ("max-reorder-frames",
1620 "Maximum number of frames needed for reordering",
1621 "The maximum number of frames needed for reordering output frames. "
1622 "Only meaningful for codecs with B frames. 0 means no reordering. "
1623 "This value will be used if the correct value cannot be inferred "
1624 "from the stream. Too low a value may cause misordering, too high "
1625 "will cause extra latency.",
1626 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1627 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1629 g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1630 g_param_spec_boolean ("codec-debug-info",
1631 "Gather debug info from the codec",
1632 "Gather and log relevant debug information from the codec. "
1633 "What is gathered is typically codec specific", FALSE,
1634 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1635 }
1637 static void
1638 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1639 {
1640 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1642 gst_ducati_set_generic_error_strings (self->error_strings);
1644 self->sinkpad =
1645 gst_pad_new_from_template (gst_element_class_get_pad_template
1646 (gstelement_class, "sink"), "sink");
1647 gst_pad_set_setcaps_function (self->sinkpad,
1648 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1649 gst_pad_set_chain_function (self->sinkpad,
1650 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1651 gst_pad_set_event_function (self->sinkpad,
1652 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1654 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1655 gst_pad_set_event_function (self->srcpad,
1656 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1657 gst_pad_set_query_function (self->srcpad,
1658 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1659 gst_pad_set_getcaps_function (self->srcpad,
1660 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1662 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1663 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1665 self->input_width = 0;
1666 self->input_height = 0;
1667 /* sane defaults in case we need to create codec without caps negotiation
1668 * (for example, to get 'version' property)
1669 */
1670 self->width = 128;
1671 self->height = 128;
1672 self->fps_n = -1;
1673 self->fps_d = -1;
1675 self->first_in_buffer = TRUE;
1676 self->first_out_buffer = FALSE;
1677 self->interlaced = FALSE;
1678 self->send_crop_event = TRUE;
1680 #ifdef USE_DTS_PTS_CODE
1681 self->dts_ridx = self->dts_widx = 0;
1682 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1683 self->ts_may_be_pts = TRUE;
1684 self->ts_is_pts = FALSE;
1685 #endif
1687 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1689 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1691 self->qos_proportion = 1;
1692 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1693 self->wait_keyframe = TRUE;
1695 self->need_out_buf = TRUE;
1696 self->device = NULL;
1697 self->input_bo = NULL;
1699 self->backlog_maxframes = 0;
1700 self->backlog_nframes = 0;
1701 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1703 self->codec_debug_info = FALSE;
1705 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1706 NULL, (GDestroyNotify) gst_buffer_unref);
1707 }