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 close((int)self->inBufs->descs[0].buf);
147 omap_bo_del (self->input_bo);
148 self->input_bo = NULL;
149 }
150 }
152 static gboolean
153 codec_create (GstDucatiVidDec * self)
154 {
155 gint err, n;
156 const gchar *codec_name;
157 char *version = NULL;
159 codec_delete (self);
161 if (G_UNLIKELY (!self->engine)) {
162 GST_ERROR_OBJECT (self, "no engine");
163 return FALSE;
164 }
166 /* these need to be set before VIDDEC3_create */
167 self->params->maxWidth = self->width;
168 self->params->maxHeight = self->height;
170 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
172 /* create codec: */
173 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
174 self->codec =
175 VIDDEC3_create (self->engine, (String) codec_name, self->params);
177 if (!self->codec) {
178 return FALSE;
179 }
181 GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
182 err =
183 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
184 self->status);
185 if (err) {
186 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
187 return FALSE;
188 }
190 self->first_in_buffer = TRUE;
191 self->first_out_buffer = FALSE;
193 version = dce_alloc (VERSION_LENGTH);
194 if (version) {
195 self->status->data.buf = (XDAS_Int8 *) version;
196 self->status->data.bufSize = VERSION_LENGTH;
198 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
199 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
200 self->dynParams, self->status);
202 if (err) {
203 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
204 } else
205 GST_DEBUG ("Codec version %s", self->status->data.buf);
207 self->status->data.buf = NULL;
208 self->status->data.bufSize = 0;
209 dce_free (version);
211 }
214 /* allocate input buffer and initialize inBufs: */
215 /* FIXME: needed size here has nothing to do with width * height */
216 self->input_bo = omap_bo_new (self->device,
217 self->width * self->height, OMAP_BO_WC);
218 self->input = omap_bo_map (self->input_bo);
219 self->inBufs->numBufs = 1;
220 /* IPC requires dmabuf fd in place of bo handle */
221 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
223 /* Actual buffers will be set later, as they will be different for every
224 frame. We allow derived classes to add their own buffers, however, so
225 we initialize the number of outBufs here, counting the number of extra
226 buffers required, including "holes" in planes, which may not be filled
227 if not assigned. */
228 self->outBufs->numBufs = 2; /* luma and chroma planes, always */
229 for (n = 0; n < 3; n++)
230 if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
231 self->outBufs->numBufs = 2 + n + 1;
233 return TRUE;
234 }
236 static inline GstBuffer *
237 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
238 {
239 if (G_UNLIKELY (!self->pool)) {
240 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
241 self->padded_width, self->padded_height);
243 GST_DEBUG_OBJECT (self, "creating bufferpool");
244 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
245 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
246 }
247 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
248 }
250 static GstDucatiBufferPriv *
251 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
252 {
253 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
254 if (!priv) {
255 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
256 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
258 /* if it isn't a dmabuf buffer that we can import, then there
259 * is nothing we can do with it:
260 */
261 if (!dmabuf) {
262 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
263 return NULL;
264 }
266 priv = gst_ducati_buffer_priv_new ();
268 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
270 priv->uv_offset = gst_video_format_get_component_offset (format,
271 1, self->stride, self->padded_height);
272 priv->size = gst_video_format_get_size (format,
273 self->stride, self->padded_height);
275 gst_ducati_buffer_priv_set (buf, priv);
276 gst_mini_object_unref (GST_MINI_OBJECT (priv));
277 }
278 return priv;
279 }
281 static XDAS_Int32
282 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
283 gboolean force_internal)
284 {
285 GstDucatiBufferPriv *priv = NULL;
286 GstDmaBuf *dmabuf = NULL;
288 if (!force_internal)
289 priv = get_buffer_priv (self, *buf);
291 if (!priv) {
292 GstBuffer *orig = *buf;
294 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
295 *buf = codec_buffer_pool_get (self, NULL);
296 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
297 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
298 gst_buffer_unref (orig);
299 return codec_prepare_outbuf (self, buf, FALSE);
300 }
302 /* There are at least two buffers. Derived classes may add codec specific
303 buffers (eg, debug info) after these two if they want to. */
304 dmabuf = gst_buffer_get_dma_buf (*buf);
305 /* XDM_MemoryType required by drm to allcoate buffer */
306 self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
307 /* IPC requires dmabuf fd in place of bo handle */
308 self->outBufs->descs[0].buf = (XDAS_Int8 *) gst_dma_buf_get_fd (dmabuf);
309 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
310 self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
311 /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
312 ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
313 should point to a single buffer fd and need to update the
314 descs[0].bufSize.bytes with the size of luminance(Y) data
315 and descs[1].bufSize.bytes with crominance(UV) */
316 self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
317 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
319 return (XDAS_Int32) * buf;
320 }
322 static GstBuffer *
323 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
324 {
325 GstBuffer *buf = (GstBuffer *) id;
327 if (buf) {
328 g_hash_table_insert (self->passed_in_bufs, buf, buf);
330 gst_buffer_ref (buf);
331 }
332 return buf;
333 }
335 static void
336 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
337 {
338 GstBuffer *buf = (GstBuffer *) id;
339 SizeT fd;
341 if (buf) {
342 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
343 /* Get dmabuf fd of the buffer to unlock */
344 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf(buf));
345 /* Must unlock the buffer before free */
346 dce_buf_unlock(1,&fd);
347 g_hash_table_remove (self->passed_in_bufs, buf);
348 }
349 }
351 /* Called when playing in reverse */
352 static GstFlowReturn
353 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
354 {
355 GstBuffer *buf;
357 if (self->backlog_nframes == 0)
358 return GST_FLOW_OK;
360 /* send it, giving away the ref */
361 buf = self->backlog_frames[--self->backlog_nframes];
362 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
363 buf);
364 return gst_pad_push (self->srcpad, buf);
365 }
367 static GstFlowReturn
368 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
369 {
370 guint64 earliest_order = G_MAXUINT64;
371 guint earliest_index = 0, i;
372 GstBuffer *buf;
374 if (self->backlog_nframes == 0)
375 return GST_FLOW_OK;
377 /* work out which frame has the earliest poc */
378 for (i = 0; i < self->backlog_nframes; i++) {
379 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
380 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
381 earliest_order = order;
382 earliest_index = i;
383 }
384 }
386 /* send it, giving away the ref */
387 buf = self->backlog_frames[earliest_index];
388 self->backlog_frames[earliest_index] =
389 self->backlog_frames[--self->backlog_nframes];
390 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
391 buf);
392 return gst_pad_push (self->srcpad, buf);
393 }
395 static void
396 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
397 {
398 if (self->segment.format == GST_FORMAT_TIME &&
399 self->segment.rate < (gdouble) 0.0) {
400 /* negative rate */
401 /* push everything on the backlog, ignoring errors */
402 while (self->backlog_nframes > 0) {
403 gst_ducati_viddec_push_latest (self);
404 }
405 } else {
406 /* push everything on the backlog, ignoring errors */
407 while (self->backlog_nframes > 0) {
408 gst_ducati_viddec_push_earliest (self);
409 }
410 }
411 }
413 static gint
414 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
415 GstFlowReturn * flow_ret)
416 {
417 gint err;
418 GstClockTime t;
419 GstBuffer *outbuf = NULL;
420 gint i;
421 SizeT fd;
422 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
423 GstFlowReturn ret = GST_FLOW_OK;
424 if (flow_ret)
425 /* never leave flow_ret uninitialized */
426 *flow_ret = GST_FLOW_OK;
428 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
429 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
431 if (self->inArgs->inputID != 0) {
432 /* Get dmabuf fd of the buffer to lock it*/
433 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf((GstBuffer *) self->inArgs->inputID));
434 /* Must lock all the buffer passed to ducati */
435 GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x", self->inArgs->inputID);
436 dce_buf_lock(1,&fd);
437 }
439 GST_DEBUG_OBJECT (self, "Calling VIDDEC3_process, inputID: %08x", self->inArgs->inputID);
440 t = gst_util_get_timestamp ();
441 err = VIDDEC3_process (self->codec,
442 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
443 t = gst_util_get_timestamp () - t;
444 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
445 (gint) (t / 1000000));
447 if (err) {
448 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
449 err, self->outArgs->extendedError);
450 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
451 self->error_strings);
453 GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
454 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
455 self->dynParams, self->status);
456 if (err) {
457 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
458 err, self->status->extendedError);
459 gst_ducati_log_extended_error_info (self->status->extendedError,
460 self->error_strings);
461 }
463 if (flush)
464 err = XDM_EFAIL;
465 else
466 err = klass->handle_error (self, err,
467 self->outArgs->extendedError, self->status->extendedError);
468 }
470 /* we now let the codec decide */
471 self->dynParams->newFrameFlag = XDAS_FALSE;
473 if (err == XDM_EFAIL)
474 goto skip_outbuf_processing;
476 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
477 gboolean interlaced;
479 GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
480 i, self->outArgs->outputID[i]);
481 interlaced =
482 self->outArgs->displayBufs.bufDesc[0].contentType ==
483 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
485 if (interlaced) {
486 GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
487 if (!buf || !gst_buffer_is_metadata_writable (buf)) {
488 GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
489 } else {
490 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_TFF);
491 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_RFF);
492 if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
493 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_TFF);
494 if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
495 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_RFF);
496 }
497 }
499 /* Getting an extra reference for the decoder */
500 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
502 /* if send is FALSE, don't try to renegotiate as we could be flushing during
503 * a PAUSED->READY state change
504 */
505 if (send && interlaced != self->interlaced) {
506 GstCaps *caps;
508 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
509 "thinks interlaced=%d... trusting codec", self->interlaced,
510 interlaced);
512 self->interlaced = interlaced;
514 caps =
515 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
516 GST_INFO_OBJECT (self, "changing interlace field in caps");
517 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
518 NULL);
519 if (self->pool) gst_drm_buffer_pool_set_caps (self->pool, caps);
520 if (!gst_pad_set_caps (self->srcpad, caps)) {
521 GST_ERROR_OBJECT (self,
522 "downstream didn't want to change interlace mode");
523 err = XDM_EFAIL;
524 }
525 gst_caps_unref (caps);
527 /* this buffer still has the old caps so we skip it */
528 send = FALSE;
529 }
531 if (G_UNLIKELY (self->send_crop_event) && send) {
532 gint crop_width, crop_height;
534 /* send region of interest to sink on first buffer: */
535 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
537 crop_width = r->bottomRight.x - r->topLeft.x;
538 crop_height = r->bottomRight.y - r->topLeft.y;
540 if (crop_width > self->input_width)
541 crop_width = self->input_width;
542 if (crop_height > self->input_height)
543 crop_height = self->input_height;
545 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
546 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
547 crop_width, crop_height);
549 gst_pad_push_event (self->srcpad,
550 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
551 crop_width, crop_height));
553 if (self->crop)
554 gst_video_crop_unref (self->crop);
556 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
557 crop_width, crop_height);
559 self->send_crop_event = FALSE;
560 }
562 if (G_UNLIKELY (self->first_out_buffer) && send) {
563 GstDRMBufferPool *pool;
564 self->first_out_buffer = FALSE;
566 /* Destroy the pool so the buffers we used so far are eventually released.
567 * The pool will be recreated if needed.
568 */
569 pool = self->pool;
570 self->pool = NULL;
571 if (pool) gst_drm_buffer_pool_destroy (pool);
572 }
574 if (send) {
575 GstClockTime ts;
577 ts = GST_BUFFER_TIMESTAMP (outbuf);
579 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
580 i, outbuf, GST_TIME_ARGS (ts));
582 #ifdef USE_DTS_PTS_CODE
583 if (self->ts_may_be_pts) {
584 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
585 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
586 "enabling ts_is_pts");
587 self->ts_is_pts = TRUE;
588 }
589 }
590 #endif
592 self->last_pts = ts;
594 if (self->dts_ridx != self->dts_widx) {
595 ts = self->dts_queue[self->dts_ridx++ % NDTS];
596 }
598 if (self->ts_is_pts) {
599 /* if we have a queued DTS from demuxer, use that instead: */
600 GST_BUFFER_TIMESTAMP (outbuf) = ts;
601 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
602 i, outbuf, GST_TIME_ARGS (ts));
603 }
605 if (GST_BUFFER_CAPS (outbuf) &&
606 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
607 GST_PAD_CAPS (self->srcpad))) {
608 /* this looks a bit scary but it's really just to change the interlace=
609 * field in caps when we start as !interlaced and the codec detects
610 * otherwise */
611 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
612 "interlace mismatch");
613 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
614 }
616 if (self->crop)
617 gst_buffer_set_video_crop (outbuf, self->crop);
619 ret = klass->push_output (self, outbuf);
620 if (flow_ret)
621 *flow_ret = ret;
622 if (ret != GST_FLOW_OK) {
623 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
624 /* just unref the remaining buffers (if any) */
625 send = FALSE;
626 }
627 } else {
628 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
629 i, outbuf);
631 gst_buffer_unref (outbuf);
632 }
633 }
635 skip_outbuf_processing:
636 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
637 GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
638 i, self->outArgs->freeBufID[i]);
639 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
640 }
642 return err;
643 }
645 /** call control(FLUSH), and then process() to pop out all buffers */
646 gboolean
647 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
648 {
649 gint err = FALSE;
650 int prev_num_in_bufs, prev_num_out_bufs;
652 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
654 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
656 /* note: flush is synchronized against _chain() to avoid calling
657 * the codec from multiple threads
658 */
659 GST_PAD_STREAM_LOCK (self->sinkpad);
661 #ifdef USE_DTS_PTS_CODE
662 self->dts_ridx = self->dts_widx = 0;
663 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
664 self->ts_may_be_pts = TRUE;
665 self->ts_is_pts = FALSE;
666 #endif
667 self->wait_keyframe = TRUE;
668 self->in_size = 0;
669 self->needs_flushing = FALSE;
670 self->need_out_buf = TRUE;
672 if (G_UNLIKELY (self->first_in_buffer)) {
673 goto out;
674 }
676 if (G_UNLIKELY (!self->codec)) {
677 GST_WARNING_OBJECT (self, "no codec");
678 goto out;
679 }
682 GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
683 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
684 if (err) {
685 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
686 goto out;
687 }
689 prev_num_in_bufs = self->inBufs->numBufs;
690 prev_num_out_bufs = self->outBufs->numBufs;
692 self->inBufs->descs[0].bufSize.bytes = 0;
693 self->inBufs->numBufs = 0;
694 self->inArgs->numBytes = 0;
695 self->inArgs->inputID = 0;
696 self->outBufs->numBufs = 0;
698 do {
699 err = codec_process (self, eos, TRUE, NULL);
700 } while (err != XDM_EFAIL);
702 /* We flushed the decoder, we can now remove the buffer that have never been
703 * unrefed in it */
704 g_hash_table_remove_all (self->passed_in_bufs);
706 /* reset outArgs in case we're flushing in codec_process trying to do error
707 * recovery */
708 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
709 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
711 self->dynParams->newFrameFlag = XDAS_TRUE;
713 /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
714 self->inBufs->numBufs = prev_num_in_bufs;
715 self->outBufs->numBufs = prev_num_out_bufs;
717 /* on a flush, it is normal (and not an error) for the last _process() call
718 * to return an error..
719 */
720 err = XDM_EOK;
722 out:
723 GST_PAD_STREAM_UNLOCK (self->sinkpad);
724 GST_DEBUG_OBJECT (self, "done");
726 return !err;
727 }
729 /* GstDucatiVidDec vmethod default implementations */
731 static gboolean
732 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
733 {
734 const GValue *codec_data;
735 gint w, h;
737 if (gst_structure_get_int (s, "width", &self->input_width) &&
738 gst_structure_get_int (s, "height", &self->input_height)) {
740 h = ALIGN2 (self->input_height, 4); /* round up to MB */
741 w = ALIGN2 (self->input_width, 4); /* round up to MB */
743 /* if we've already created codec, but the resolution has changed, we
744 * need to re-create the codec:
745 */
746 if (G_UNLIKELY (self->codec)) {
747 if ((h != self->height) || (w != self->width)) {
748 codec_delete (self);
749 }
750 }
752 self->width = w;
753 self->height = h;
755 codec_data = gst_structure_get_value (s, "codec_data");
757 if (codec_data) {
758 GstBuffer *buffer = gst_value_get_buffer (codec_data);
759 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
760 self->codec_data = gst_buffer_ref (buffer);
761 }
763 return TRUE;
764 }
766 return FALSE;
767 }
769 static gboolean
770 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
771 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
772 {
774 /* allocate params: */
775 self->params = dce_alloc (params_sz);
776 if (G_UNLIKELY (!self->params)) {
777 return FALSE;
778 }
779 self->params->size = params_sz;
780 self->params->maxFrameRate = 30000;
781 self->params->maxBitRate = 10000000;
783 self->params->dataEndianness = XDM_BYTE;
784 self->params->forceChromaFormat = XDM_YUV_420SP;
785 self->params->operatingMode = IVIDEO_DECODE_ONLY;
787 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
788 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
789 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
790 self->params->numInputDataUnits = 0;
791 self->params->numOutputDataUnits = 0;
793 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
794 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
795 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
796 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
798 /* allocate dynParams: */
799 self->dynParams = dce_alloc (dynparams_sz);
800 if (G_UNLIKELY (!self->dynParams)) {
801 return FALSE;
802 }
803 self->dynParams->size = dynparams_sz;
804 self->dynParams->decodeHeader = XDM_DECODE_AU;
805 self->dynParams->displayWidth = 0;
806 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
807 self->dynParams->newFrameFlag = XDAS_TRUE;
809 /* allocate status: */
810 self->status = dce_alloc (status_sz);
811 if (G_UNLIKELY (!self->status)) {
812 return FALSE;
813 }
814 memset (self->status, 0, status_sz);
815 self->status->size = status_sz;
817 /* allocate inBufs/outBufs: */
818 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
819 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
820 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
821 return FALSE;
822 }
824 /* allocate inArgs/outArgs: */
825 self->inArgs = dce_alloc (inargs_sz);
826 self->outArgs = dce_alloc (outargs_sz);
827 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
828 return FALSE;
829 }
830 self->inArgs->size = inargs_sz;
831 self->outArgs->size = outargs_sz;
833 return TRUE;
834 }
836 static GstBuffer *
837 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
838 {
839 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
840 push_input (self, GST_BUFFER_DATA (self->codec_data),
841 GST_BUFFER_SIZE (self->codec_data));
842 }
844 /* just copy entire buffer */
845 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
846 gst_buffer_unref (buf);
848 return NULL;
849 }
851 static GstFlowReturn
852 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
853 {
854 GstFlowReturn ret = GST_FLOW_OK;
856 if (self->segment.format == GST_FORMAT_TIME &&
857 self->segment.rate < (gdouble) 0.0) {
858 /* negative rate: reverse playback */
860 if (self->backlog_nframes > 0 &&
861 (GST_BUFFER_TIMESTAMP (self->backlog_frames[0]) >
862 GST_BUFFER_TIMESTAMP (buf))) {
863 /* push out all backlog frames, since we have a buffer that is
864 earlier than any other in the list */
865 while (self->backlog_nframes > 0) {
866 ret = gst_ducati_viddec_push_latest (self);
867 if (ret != GST_FLOW_OK)
868 break;
869 }
870 }
871 /* add the frame to the list, the array will own the ref */
872 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
873 buf);
874 if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
875 self->backlog_frames[self->backlog_nframes++] = buf;
876 } else {
877 /* No space in the re-order buffer, drop the frame */
878 GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
879 gst_buffer_unref (buf);
880 }
882 } else {
883 /* if no reordering info was set, just send the buffer */
884 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
885 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
886 return gst_pad_push (self->srcpad, buf);
887 }
889 /* add the frame to the list, the array will own the ref */
890 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
891 buf);
892 self->backlog_frames[self->backlog_nframes++] = buf;
894 /* push till we have no more than the max needed, or error */
895 while (self->backlog_nframes > self->backlog_maxframes) {
896 ret = gst_ducati_viddec_push_earliest (self);
897 if (ret != GST_FLOW_OK)
898 break;
899 }
900 }
901 return ret;
902 }
904 static gint
905 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
906 gint extended_error, gint status_extended_error)
907 {
908 if (XDM_ISFATALERROR (extended_error))
909 ret = XDM_EFAIL;
910 else
911 ret = XDM_EOK;
913 return ret;
914 }
916 /* GstElement vmethod implementations */
918 static gboolean
919 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
920 {
921 gboolean ret = TRUE;
922 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
923 GstStructure *s;
924 GstCaps *outcaps = NULL;
925 GstStructure *out_s;
926 gint par_width, par_height;
927 gboolean par_present;
929 s = gst_caps_get_structure (caps, 0);
930 if (!klass->parse_caps (self, s)) {
931 GST_WARNING_OBJECT (self, "missing required fields");
932 ret = FALSE;
933 goto out;
934 }
936 /* update output/padded sizes */
937 klass->update_buffer_size (self);
939 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
940 self->fps_n = 0;
941 self->fps_d = 1;
942 }
943 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
944 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
945 &par_width, &par_height);
947 outcaps = gst_pad_get_allowed_caps (self->srcpad);
948 if (outcaps) {
949 outcaps = gst_caps_make_writable (outcaps);
950 gst_caps_truncate (outcaps);
951 if (gst_caps_is_empty (outcaps)) {
952 gst_caps_unref (outcaps);
953 outcaps = NULL;
954 }
955 }
957 if (!outcaps) {
958 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
959 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
960 }
962 out_s = gst_caps_get_structure (outcaps, 0);
963 gst_structure_set (out_s,
964 "width", G_TYPE_INT, self->padded_width,
965 "height", G_TYPE_INT, self->padded_height,
966 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
967 if (par_present)
968 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
969 par_width, par_height, NULL);
971 if (self->interlaced)
972 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
974 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
975 0, self->padded_width);
977 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
978 self->stride, self->padded_height);
980 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
981 self->outsize, self->stride, outcaps);
983 if (!self->first_in_buffer) {
984 /* Caps changed mid stream. We flush the codec to unlock all the potentially
985 * locked buffers. This is needed for downstream sinks that provide a
986 * buffer pool and need to destroy all the outstanding buffers before they
987 * can negotiate new caps (hello v4l2sink).
988 */
989 gst_ducati_viddec_codec_flush (self, FALSE);
990 }
992 /* (re)send a crop event when caps change */
993 self->send_crop_event = TRUE;
995 ret = gst_pad_set_caps (self->srcpad, outcaps);
997 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
999 /* default to no reordering */
1000 self->backlog_maxframes = 0;
1002 out:
1003 if (outcaps)
1004 gst_caps_unref (outcaps);
1006 return ret;
1007 }
1009 static gboolean
1010 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1011 {
1012 gboolean ret = TRUE;
1013 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1014 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1016 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1018 ret = klass->set_sink_caps (self, caps);
1020 gst_object_unref (self);
1022 return ret;
1023 }
1025 static GstCaps *
1026 gst_ducati_viddec_src_getcaps (GstPad * pad)
1027 {
1028 GstCaps *caps = NULL;
1030 caps = GST_PAD_CAPS (pad);
1031 if (caps == NULL) {
1032 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
1033 } else {
1034 return gst_caps_copy (caps);
1035 }
1036 }
1038 static gboolean
1039 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1040 GstQuery * query, gboolean * forward)
1041 {
1042 gboolean res = TRUE;
1044 switch (GST_QUERY_TYPE (query)) {
1045 case GST_QUERY_BUFFERS:
1046 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
1047 gst_query_set_buffers_count (query, self->min_buffers);
1049 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
1050 self->padded_width, self->padded_height);
1051 gst_query_set_buffers_dimensions (query,
1052 self->padded_width, self->padded_height);
1053 *forward = FALSE;
1054 break;
1055 case GST_QUERY_LATENCY:
1056 {
1057 gboolean live;
1058 GstClockTime min, max, latency;
1060 if (self->fps_d == 0) {
1061 GST_INFO_OBJECT (self, "not ready to report latency");
1062 res = FALSE;
1063 break;
1064 }
1066 gst_query_parse_latency (query, &live, &min, &max);
1067 if (self->fps_n != 0)
1068 latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1069 else
1070 latency = 0;
1072 /* Take into account the backlog frames for reordering */
1073 latency *= (self->backlog_maxframes + 1);
1075 if (min == GST_CLOCK_TIME_NONE)
1076 min = latency;
1077 else
1078 min += latency;
1080 if (max != GST_CLOCK_TIME_NONE)
1081 max += latency;
1083 GST_INFO_OBJECT (self,
1084 "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1085 GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1086 gst_query_set_latency (query, live, min, max);
1087 break;
1088 }
1089 default:
1090 break;
1091 }
1094 return res;
1095 }
1097 static gboolean
1098 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
1099 {
1100 gboolean res = TRUE, forward = TRUE;
1101 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1102 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1104 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1105 res = klass->query (self, pad, query, &forward);
1106 if (res && forward)
1107 res = gst_pad_query_default (pad, query);
1109 return res;
1110 }
1112 static gboolean
1113 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1114 {
1115 GstClockTime timestamp, qostime;
1116 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1117 gint64 diff;
1119 if (self->wait_keyframe) {
1120 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1121 GST_INFO_OBJECT (self, "skipping until the next keyframe");
1122 return FALSE;
1123 }
1125 self->wait_keyframe = FALSE;
1126 }
1128 timestamp = GST_BUFFER_TIMESTAMP (buf);
1129 if (self->segment.format != GST_FORMAT_TIME ||
1130 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1131 goto no_qos;
1133 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1134 goto no_qos;
1136 qostime = gst_segment_to_running_time (&self->segment,
1137 GST_FORMAT_TIME, timestamp);
1138 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1139 /* out of segment */
1140 goto no_qos;
1142 /* see how our next timestamp relates to the latest qos timestamp. negative
1143 * values mean we are early, positive values mean we are too late. */
1144 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1146 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1147 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1148 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1149 self->qos_proportion);
1151 if (klass->can_drop_frame (self, buf, diff)) {
1152 GST_INFO_OBJECT (self, "dropping frame");
1153 return FALSE;
1154 }
1156 no_qos:
1157 return TRUE;
1158 }
1160 static gboolean
1161 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1162 gint64 diff)
1163 {
1164 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1165 GST_BUFFER_FLAG_DELTA_UNIT);
1167 if (diff >= 0 && !is_keyframe)
1168 return TRUE;
1170 return FALSE;
1171 }
1173 static GstFlowReturn
1174 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1175 {
1176 SizeT fd;
1178 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1179 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1180 GstFlowReturn ret = GST_FLOW_OK;
1181 Int32 err;
1182 GstBuffer *outbuf = NULL;
1183 GstCaps *outcaps = NULL;
1184 gboolean decode;
1186 normal:
1187 if (G_UNLIKELY (!self->engine)) {
1188 GST_ERROR_OBJECT (self, "no engine");
1189 gst_buffer_unref (buf);
1190 return GST_FLOW_ERROR;
1191 }
1193 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1194 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1196 decode = gst_ducati_viddec_do_qos (self, buf);
1197 if (!decode) {
1198 gst_buffer_unref (buf);
1199 return GST_FLOW_OK;
1200 }
1202 if (!self->need_out_buf)
1203 goto have_out_buf;
1205 /* do this before creating codec to ensure reverse caps negotiation
1206 * happens first:
1207 */
1208 allocate_buffer:
1209 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1210 GST_PAD_CAPS (self->srcpad), &outbuf);
1211 if (ret != GST_FLOW_OK) {
1212 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1213 gst_flow_get_name (ret));
1214 gst_buffer_unref (buf);
1215 return ret;
1216 }
1218 outcaps = GST_BUFFER_CAPS (outbuf);
1219 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1220 GstStructure *s;
1222 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1223 GST_BUFFER_SIZE (outbuf));
1225 s = gst_caps_get_structure (outcaps, 0);
1226 gst_structure_get_int (s, "rowstride", &self->stride);
1227 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1228 self->stride, self->padded_height);
1230 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1231 self->outsize, self->stride, outcaps);
1233 gst_pad_set_caps (self->srcpad, outcaps);
1235 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1236 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1237 GST_BUFFER_SIZE (outbuf), self->outsize);
1238 gst_buffer_unref (outbuf);
1239 goto allocate_buffer;
1240 }
1241 }
1243 if (G_UNLIKELY (!self->codec)) {
1244 if (!codec_create (self)) {
1245 GST_ERROR_OBJECT (self, "could not create codec");
1246 gst_buffer_unref (buf);
1247 gst_buffer_unref (outbuf);
1248 return GST_FLOW_ERROR;
1249 }
1250 }
1252 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1253 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1255 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1256 * internal pool while self->first_out_buffer == TRUE in order to simplify
1257 * things in case we need to renegotiate */
1258 self->inArgs->inputID =
1259 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1260 if (!self->inArgs->inputID) {
1261 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1262 gst_buffer_unref (buf);
1263 return GST_FLOW_ERROR;
1264 }
1265 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1267 have_out_buf:
1268 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1270 #ifdef USE_DTS_PTS_CODE
1271 if (ts != GST_CLOCK_TIME_NONE) {
1272 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1273 /* if next buffer has earlier ts than previous, then the ts
1274 * we are getting are definitely decode order (DTS):
1275 */
1276 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1277 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1278 self->ts_may_be_pts = FALSE;
1279 }
1280 self->last_dts = ts;
1281 }
1282 #endif
1284 if (self->in_size == 0 && outbuf) {
1285 GST_DEBUG_OBJECT (self, "no input, skipping process");
1287 gst_buffer_unref (outbuf);
1288 return GST_FLOW_OK;
1289 }
1291 self->inArgs->numBytes = self->in_size;
1292 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1293 /* XDM_MemoryType required by drm to allcoate buffer */
1294 self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1296 err = codec_process (self, TRUE, FALSE, &ret);
1297 if (err) {
1298 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1299 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1300 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1301 self->error_strings);
1303 return GST_FLOW_ERROR;
1304 }
1306 if (ret != GST_FLOW_OK) {
1307 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1308 gst_flow_get_name (ret));
1310 return ret;
1311 }
1313 self->first_in_buffer = FALSE;
1315 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1316 /* The copy could be avoided by playing with the buffer pointer,
1317 but it seems to be rare and for not many bytes */
1318 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1319 self->outArgs->bytesConsumed, self->in_size,
1320 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1321 if (self->outArgs->bytesConsumed > 0) {
1322 if (self->outArgs->bytesConsumed > self->in_size) {
1323 GST_WARNING_OBJECT (self,
1324 "Codec claims to have used more bytes than supplied");
1325 self->in_size = 0;
1326 } else {
1327 if (self->outArgs->bytesConsumed < self->in_size) {
1328 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1329 self->in_size - self->outArgs->bytesConsumed);
1330 }
1331 self->in_size -= self->outArgs->bytesConsumed;
1332 }
1333 }
1334 } else {
1335 self->in_size = 0;
1336 }
1338 if (self->outArgs->outBufsInUseFlag) {
1339 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1340 self->need_out_buf = FALSE;
1341 } else {
1342 self->need_out_buf = TRUE;
1343 }
1345 if (buf) {
1346 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1347 GST_BUFFER_SIZE (buf));
1348 ts = GST_BUFFER_TIMESTAMP (buf);
1349 goto allocate_buffer;
1350 }
1352 if (self->needs_flushing)
1353 gst_ducati_viddec_codec_flush (self, FALSE);
1355 return GST_FLOW_OK;
1356 }
1358 static gboolean
1359 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1360 {
1361 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1362 gboolean ret = TRUE;
1364 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1366 switch (GST_EVENT_TYPE (event)) {
1367 case GST_EVENT_NEWSEGMENT:
1368 {
1369 gboolean update;
1370 GstFormat fmt;
1371 gint64 start, stop, time;
1372 gdouble rate, arate;
1374 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1375 &start, &stop, &time);
1376 gst_segment_set_newsegment_full (&self->segment, update,
1377 rate, arate, fmt, start, stop, time);
1378 break;
1379 }
1380 case GST_EVENT_EOS:
1381 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1382 GST_ERROR_OBJECT (self, "could not flush on eos");
1383 ret = FALSE;
1384 }
1385 break;
1386 case GST_EVENT_FLUSH_STOP:
1387 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1388 GST_ERROR_OBJECT (self, "could not flush");
1389 gst_event_unref (event);
1390 ret = FALSE;
1391 }
1392 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1393 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1394 self->qos_proportion = 1;
1395 self->need_out_buf = TRUE;
1396 break;
1397 default:
1398 break;
1399 }
1401 if (ret)
1402 ret = gst_pad_push_event (self->srcpad, event);
1403 GST_LOG_OBJECT (self, "end");
1405 return ret;
1406 }
1408 static gboolean
1409 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1410 {
1411 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1412 gboolean ret = TRUE;
1414 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1416 switch (GST_EVENT_TYPE (event)) {
1417 case GST_EVENT_QOS:
1418 {
1419 gdouble proportion;
1420 GstClockTimeDiff diff;
1421 GstClockTime timestamp;
1423 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1425 GST_OBJECT_LOCK (self);
1426 self->qos_proportion = proportion;
1427 self->qos_earliest_time = timestamp + 2 * diff;
1428 GST_OBJECT_UNLOCK (self);
1430 GST_DEBUG_OBJECT (self,
1431 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1432 proportion, GST_TIME_ARGS (timestamp), diff);
1434 ret = gst_pad_push_event (self->sinkpad, event);
1435 break;
1436 }
1437 default:
1438 ret = gst_pad_push_event (self->sinkpad, event);
1439 break;
1440 }
1442 GST_LOG_OBJECT (self, "end");
1444 return ret;
1445 }
1447 static GstStateChangeReturn
1448 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1449 {
1450 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1451 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1452 gboolean supported;
1454 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1455 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1456 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1458 switch (transition) {
1459 case GST_STATE_CHANGE_NULL_TO_READY:
1460 if (!engine_open (self)) {
1461 GST_ERROR_OBJECT (self, "could not open");
1462 return GST_STATE_CHANGE_FAILURE;
1463 }
1464 /* try to create/destroy the codec here, it may not be supported */
1465 supported = codec_create (self);
1466 codec_delete (self);
1467 self->codec = NULL;
1468 if (!supported) {
1469 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1470 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1471 engine_close (self);
1472 return GST_STATE_CHANGE_FAILURE;
1473 }
1474 break;
1475 default:
1476 break;
1477 }
1479 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1481 if (ret == GST_STATE_CHANGE_FAILURE)
1482 goto leave;
1484 switch (transition) {
1485 case GST_STATE_CHANGE_PAUSED_TO_READY:
1486 self->interlaced = FALSE;
1487 self->send_crop_event = TRUE;
1488 gst_ducati_viddec_codec_flush (self, FALSE);
1489 break;
1490 case GST_STATE_CHANGE_READY_TO_NULL:
1491 codec_delete (self);
1492 engine_close (self);
1493 break;
1494 default:
1495 break;
1496 }
1498 leave:
1499 GST_LOG_OBJECT (self, "end");
1501 return ret;
1502 }
1504 /* GObject vmethod implementations */
1507 static void
1508 gst_ducati_viddec_get_property (GObject * obj,
1509 guint prop_id, GValue * value, GParamSpec * pspec)
1510 {
1511 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1514 switch (prop_id) {
1515 case PROP_VERSION:{
1516 int err;
1517 char *version = NULL;
1519 if (!self->engine)
1520 engine_open (self);
1522 if (!self->codec)
1523 codec_create (self);
1525 if (self->codec) {
1526 version = dce_alloc (VERSION_LENGTH);
1527 if (version) {
1528 self->status->data.buf = (XDAS_Int8 *) version;
1529 self->status->data.bufSize = VERSION_LENGTH;
1531 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1532 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1533 self->dynParams, self->status);
1535 if (err) {
1536 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1537 } else
1538 GST_DEBUG ("Codec version %s", self->status->data.buf);
1540 self->status->data.buf = NULL;
1541 self->status->data.bufSize = 0;
1542 dce_free (version);
1543 }
1544 }
1545 break;
1546 }
1547 case PROP_MAX_REORDER_FRAMES:
1548 g_value_set_int (value, self->backlog_max_maxframes);
1549 break;
1550 case PROP_CODEC_DEBUG_INFO:
1551 g_value_set_boolean (value, self->codec_debug_info);
1552 break;
1553 default:{
1554 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1555 break;
1556 }
1557 }
1558 }
1560 static void
1561 gst_ducati_viddec_set_property (GObject * obj,
1562 guint prop_id, const GValue * value, GParamSpec * pspec)
1563 {
1564 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1566 switch (prop_id) {
1567 case PROP_MAX_REORDER_FRAMES:
1568 self->backlog_max_maxframes = g_value_get_int (value);
1569 break;
1570 case PROP_CODEC_DEBUG_INFO:
1571 self->codec_debug_info = g_value_get_boolean (value);
1572 break;
1573 default:{
1574 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1575 break;
1576 }
1577 }
1578 }
1580 static void
1581 gst_ducati_viddec_finalize (GObject * obj)
1582 {
1583 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1585 codec_delete (self);
1586 engine_close (self);
1588 /* Will unref the remaining buffers if needed */
1589 g_hash_table_unref (self->passed_in_bufs);
1590 if (self->codec_data) {
1591 gst_buffer_unref (self->codec_data);
1592 self->codec_data = NULL;
1593 }
1595 G_OBJECT_CLASS (parent_class)->finalize (obj);
1596 }
1598 static void
1599 gst_ducati_viddec_base_init (gpointer gclass)
1600 {
1601 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1603 gst_element_class_add_pad_template (element_class,
1604 gst_static_pad_template_get (&src_factory));
1605 }
1607 static void
1608 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1609 {
1610 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1611 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1613 gobject_class->get_property =
1614 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1615 gobject_class->set_property =
1616 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1617 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1618 gstelement_class->change_state =
1619 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1621 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1622 klass->allocate_params =
1623 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1624 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1625 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1626 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1627 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1628 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1629 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1630 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1632 g_object_class_install_property (gobject_class, PROP_VERSION,
1633 g_param_spec_string ("version", "Version",
1634 "The codec version string", "",
1635 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1637 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1638 g_param_spec_int ("max-reorder-frames",
1639 "Maximum number of frames needed for reordering",
1640 "The maximum number of frames needed for reordering output frames. "
1641 "Only meaningful for codecs with B frames. 0 means no reordering. "
1642 "This value will be used if the correct value cannot be inferred "
1643 "from the stream. Too low a value may cause misordering, too high "
1644 "will cause extra latency.",
1645 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1646 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1648 g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1649 g_param_spec_boolean ("codec-debug-info",
1650 "Gather debug info from the codec",
1651 "Gather and log relevant debug information from the codec. "
1652 "What is gathered is typically codec specific", FALSE,
1653 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1654 }
1656 static void
1657 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1658 {
1659 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1661 gst_ducati_set_generic_error_strings (self->error_strings);
1663 self->sinkpad =
1664 gst_pad_new_from_template (gst_element_class_get_pad_template
1665 (gstelement_class, "sink"), "sink");
1666 gst_pad_set_setcaps_function (self->sinkpad,
1667 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1668 gst_pad_set_chain_function (self->sinkpad,
1669 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1670 gst_pad_set_event_function (self->sinkpad,
1671 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1673 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1674 gst_pad_set_event_function (self->srcpad,
1675 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1676 gst_pad_set_query_function (self->srcpad,
1677 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1678 gst_pad_set_getcaps_function (self->srcpad,
1679 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1681 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1682 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1684 self->input_width = 0;
1685 self->input_height = 0;
1686 /* sane defaults in case we need to create codec without caps negotiation
1687 * (for example, to get 'version' property)
1688 */
1689 self->width = 128;
1690 self->height = 128;
1691 self->fps_n = -1;
1692 self->fps_d = -1;
1694 self->first_in_buffer = TRUE;
1695 self->first_out_buffer = FALSE;
1696 self->interlaced = FALSE;
1697 self->send_crop_event = TRUE;
1699 #ifdef USE_DTS_PTS_CODE
1700 self->dts_ridx = self->dts_widx = 0;
1701 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1702 self->ts_may_be_pts = TRUE;
1703 self->ts_is_pts = FALSE;
1704 #endif
1706 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1708 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1710 self->qos_proportion = 1;
1711 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1712 self->wait_keyframe = TRUE;
1714 self->need_out_buf = TRUE;
1715 self->device = NULL;
1716 self->input_bo = NULL;
1718 self->backlog_maxframes = 0;
1719 self->backlog_nframes = 0;
1720 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1722 self->codec_debug_info = FALSE;
1724 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1725 NULL, (GDestroyNotify) gst_buffer_unref);
1726 }