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
30 static void gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass);
31 static void gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass);
32 static void gst_ducati_viddec_base_init (gpointer gclass);
33 static GstElementClass *parent_class = NULL;
34 void gst_drm_buffer_pool_set_caps (GstDRMBufferPool * self, GstCaps * caps);
37 void
38 gst_drm_buffer_pool_set_caps (GstDRMBufferPool * self, GstCaps * caps)
39 {
40 GstStructure *conf;
41 conf = gst_buffer_pool_get_config (GST_BUFFER_POOL (self));
42 gst_buffer_pool_config_set_params (conf, caps, self->size, 0, 0);
43 gst_drm_buffer_pool_set_config (GST_BUFFER_POOL (self), conf);
45 }
47 GType
48 gst_ducati_viddec_get_type (void)
49 {
50 static GType ducati_viddec_type = 0;
52 if (!ducati_viddec_type) {
53 static const GTypeInfo ducati_viddec_info = {
54 sizeof (GstDucatiVidDecClass),
55 (GBaseInitFunc) gst_ducati_viddec_base_init,
56 NULL,
57 (GClassInitFunc) gst_ducati_viddec_class_init,
58 NULL,
59 NULL,
60 sizeof (GstDucatiVidDec),
61 0,
62 (GInstanceInitFunc) gst_ducati_viddec_init,
63 };
65 ducati_viddec_type = g_type_register_static (GST_TYPE_ELEMENT,
66 "GstDucatiVidDec", &ducati_viddec_info, 0);
67 }
68 return ducati_viddec_type;
69 }
71 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
72 GST_PAD_SRC,
73 GST_PAD_ALWAYS,
74 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("NV12"))
75 );
77 enum
78 {
79 PROP_0,
80 PROP_VERSION,
81 PROP_MAX_REORDER_FRAMES,
82 PROP_CODEC_DEBUG_INFO
83 };
85 /* helper functions */
87 static void
88 engine_close (GstDucatiVidDec * self)
89 {
90 if (self->params) {
91 dce_free (self->params);
92 self->params = NULL;
93 }
95 if (self->dynParams) {
96 dce_free (self->dynParams);
97 self->dynParams = NULL;
98 }
100 if (self->status) {
101 dce_free (self->status);
102 self->status = NULL;
103 }
105 if (self->inBufs) {
106 dce_free (self->inBufs);
107 self->inBufs = NULL;
108 }
110 if (self->outBufs) {
111 dce_free (self->outBufs);
112 self->outBufs = NULL;
113 }
115 if (self->inArgs) {
116 dce_free (self->inArgs);
117 self->inArgs = NULL;
118 }
120 if (self->outArgs) {
121 dce_free (self->outArgs);
122 self->outArgs = NULL;
123 }
125 if (self->engine) {
126 Engine_close (self->engine);
127 self->engine = NULL;
128 }
130 if (self->device) {
131 dce_deinit (self->device);
132 self->device = NULL;
133 }
134 }
136 static gboolean
137 engine_open (GstDucatiVidDec * self)
138 {
139 gboolean ret;
140 int ec;
142 if (G_UNLIKELY (self->engine)) {
143 return TRUE;
144 }
146 if (self->device == NULL) {
147 self->device = dce_init ();
148 if (self->device == NULL) {
149 GST_ERROR_OBJECT (self, "dce_init() failed");
150 return FALSE;
151 }
152 }
154 GST_DEBUG_OBJECT (self, "opening engine");
156 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
157 if (G_UNLIKELY (!self->engine)) {
158 GST_ERROR_OBJECT (self, "could not create engine");
159 return FALSE;
160 }
162 ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
163 sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
164 sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
165 sizeof (IVIDDEC3_OutArgs));
167 return ret;
168 }
170 static void
171 codec_delete (GstDucatiVidDec * self)
172 {
173 if (self->pool) {
174 gst_drm_buffer_pool_destroy (self->pool);
175 self->pool = NULL;
176 }
178 if (self->codec) {
179 GST_DEBUG ("Calling VIDDEC3_delete");
180 VIDDEC3_delete (self->codec);
181 self->codec = NULL;
182 }
184 if (self->input_bo) {
185 close ((int) self->inBufs->descs[0].buf);
186 omap_bo_del (self->input_bo);
187 self->input_bo = NULL;
188 }
189 }
191 static gboolean
192 codec_create (GstDucatiVidDec * self)
193 {
194 gint err, n;
195 const gchar *codec_name;
196 char *version = NULL;
198 codec_delete (self);
200 if (G_UNLIKELY (!self->engine)) {
201 GST_ERROR_OBJECT (self, "no engine");
202 return FALSE;
203 }
205 /* these need to be set before VIDDEC3_create */
206 self->params->maxWidth = self->width;
207 self->params->maxHeight = self->height;
209 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
211 /* create codec: */
212 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
213 self->codec =
214 VIDDEC3_create (self->engine, (String) codec_name, self->params);
216 if (!self->codec) {
217 return FALSE;
218 }
220 GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
221 err =
222 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
223 self->status);
224 if (err) {
225 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
226 return FALSE;
227 }
229 self->first_in_buffer = TRUE;
230 self->first_out_buffer = FALSE;
232 version = dce_alloc (VERSION_LENGTH);
233 if (version) {
234 self->status->data.buf = (XDAS_Int8 *) version;
235 self->status->data.bufSize = VERSION_LENGTH;
237 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
238 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
239 self->dynParams, self->status);
241 if (err) {
242 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
243 } else
244 GST_DEBUG ("Codec version %s", self->status->data.buf);
246 self->status->data.buf = NULL;
247 self->status->data.bufSize = 0;
248 dce_free (version);
250 }
253 /* allocate input buffer and initialize inBufs: */
254 /* FIXME: needed size here has nothing to do with width * height */
255 self->input_bo = omap_bo_new (self->device,
256 self->width * self->height, OMAP_BO_WC);
257 self->input = omap_bo_map (self->input_bo);
258 self->inBufs->numBufs = 1;
259 /* IPC requires dmabuf fd in place of bo handle */
260 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
262 /* Actual buffers will be set later, as they will be different for every
263 frame. We allow derived classes to add their own buffers, however, so
264 we initialize the number of outBufs here, counting the number of extra
265 buffers required, including "holes" in planes, which may not be filled
266 if not assigned. */
267 self->outBufs->numBufs = 2; /* luma and chroma planes, always */
268 for (n = 0; n < 3; n++)
269 if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
270 self->outBufs->numBufs = 2 + n + 1;
272 return TRUE;
273 }
275 static inline GstBuffer *
276 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
277 {
278 GstBuffer *ret_buf;
279 if (G_UNLIKELY (!self->pool)) {
280 guint size =
281 GST_ROUND_UP_4 (self->padded_width) *
282 GST_ROUND_UP_2 (self->padded_height) * 3 / 2;
284 GST_DEBUG_OBJECT (self, "creating bufferpool");
285 GST_DEBUG_OBJECT (self, "%s\n",
286 gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
287 self->pool =
288 gst_drm_buffer_pool_new (GST_ELEMENT (self), dce_get_fd (),
289 gst_pad_get_current_caps (self->srcpad), size);
290 }
291 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
292 }
294 static GstMetaDucatiBufferPriv *
295 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
296 {
297 GstMetaDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
298 if (!priv) {
299 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
300 struct omap_bo *bo;
301 gint uv_offset, size;
303 GstMetaDmaBuf *dmabuf = gst_buffer_get_dma_buf_meta (buf);
305 /* if it isn't a dmabuf buffer that we can import, then there
306 * is nothing we can do with it:
307 */
308 if (!dmabuf) {
309 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
310 return NULL;
311 }
313 bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_meta_get_fd (dmabuf));
315 uv_offset =
316 GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height);
317 size =
318 GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) *
319 3 / 2;
321 priv = gst_ducati_buffer_priv_set (buf, bo, uv_offset, size);
322 }
323 return priv;
324 }
326 static XDAS_Int32
327 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
328 gboolean force_internal)
329 {
330 GstMetaDucatiBufferPriv *priv = NULL;
331 GstMetaDmaBuf *dmabuf = NULL;
333 if (!force_internal)
334 priv = get_buffer_priv (self, *buf);
336 if (!priv) {
337 GstBuffer *orig = *buf;
339 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
340 *buf = codec_buffer_pool_get (self, NULL);
341 GST_BUFFER_PTS (*buf) = GST_BUFFER_PTS (orig);
342 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
343 gst_buffer_unref (orig);
344 return codec_prepare_outbuf (self, buf, FALSE);
345 }
347 /* There are at least two buffers. Derived classes may add codec specific
348 buffers (eg, debug info) after these two if they want to. */
349 dmabuf = gst_buffer_get_dma_buf_meta (*buf);
350 /* XDM_MemoryType required by drm to allcoate buffer */
351 self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
352 /* IPC requires dmabuf fd in place of bo handle */
353 self->outBufs->descs[0].buf = (XDAS_Int8 *) gst_dma_buf_meta_get_fd (dmabuf);
354 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
355 self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
356 /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
357 ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
358 should point to a single buffer fd and need to update the
359 descs[0].bufSize.bytes with the size of luminance(Y) data
360 and descs[1].bufSize.bytes with crominance(UV) */
361 self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
362 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
364 return (XDAS_Int32) * buf;
365 }
367 static GstBuffer *
368 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
369 {
370 GstBuffer *buf = (GstBuffer *) id;
372 if (buf) {
373 g_hash_table_insert (self->passed_in_bufs, buf, buf);
375 gst_buffer_ref (buf);
376 }
377 return buf;
378 }
380 static void
381 do_dce_buf_unlock (GstBuffer * buf)
382 {
383 SizeT fd;
384 /* Get dmabuf fd of the buffer to unlock */
385 fd = gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta (buf));
387 dce_buf_unlock (1, &fd);
388 }
390 static void
391 dce_buf_free_all (GstBuffer * buf, gpointer key, GstDucatiVidDec * self)
392 {
393 if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
394 /* Buffer was not found in the hash table, remove it anyway */
395 gst_buffer_unref (buf);
396 }
397 }
399 static void
400 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
401 {
402 GstBuffer *buf = (GstBuffer *) id;
404 if (buf) {
405 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
406 /* Must unlock the buffer before free */
407 g_hash_table_remove (self->dce_locked_bufs, buf);
408 if (FALSE == g_hash_table_remove (self->passed_in_bufs, buf)) {
409 /* Buffer was not found in the hash table, remove it anyway */
410 gst_buffer_unref (buf);
411 }
412 }
413 }
415 /* Called when playing in reverse */
416 static GstFlowReturn
417 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
418 {
419 GstBuffer *buf;
421 if (self->backlog_nframes == 0)
422 return GST_FLOW_OK;
424 /* send it, giving away the ref */
425 buf = self->backlog_frames[--self->backlog_nframes];
426 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
427 buf);
428 return gst_pad_push (self->srcpad, buf);
429 }
431 static GstFlowReturn
432 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
433 {
434 guint64 earliest_order = G_MAXUINT64;
435 guint earliest_index = 0, i;
436 GstBuffer *buf;
438 if (self->backlog_nframes == 0)
439 return GST_FLOW_OK;
441 /* work out which frame has the earliest poc */
442 for (i = 0; i < self->backlog_nframes; i++) {
443 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
444 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
445 earliest_order = order;
446 earliest_index = i;
447 }
448 }
450 /* send it, giving away the ref */
451 buf = self->backlog_frames[earliest_index];
452 self->backlog_frames[earliest_index] =
453 self->backlog_frames[--self->backlog_nframes];
454 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
455 buf);
456 return gst_pad_push (self->srcpad, buf);
457 }
459 static void
460 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
461 {
462 if (self->segment.format == GST_FORMAT_TIME &&
463 self->segment.rate < (gdouble) 0.0) {
464 /* negative rate */
465 /* push everything on the backlog, ignoring errors */
466 while (self->backlog_nframes > 0) {
467 gst_ducati_viddec_push_latest (self);
468 }
469 } else {
470 /* push everything on the backlog, ignoring errors */
471 while (self->backlog_nframes > 0) {
472 gst_ducati_viddec_push_earliest (self);
473 }
474 }
475 }
477 static gint
478 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
479 GstFlowReturn * flow_ret)
480 {
481 gint err, getstatus_err;
482 GstClockTime t;
483 GstBuffer *outbuf = NULL;
484 gint i;
485 SizeT fd;
486 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
487 GstFlowReturn ret = GST_FLOW_OK;
488 if (flow_ret)
489 /* never leave flow_ret uninitialized */
490 *flow_ret = GST_FLOW_OK;
492 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
493 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
495 if (self->inArgs->inputID != 0) {
496 /* Check if this inputID was already sent to the codec */
497 if (g_hash_table_contains (self->dce_locked_bufs,
498 (gpointer) self->inArgs->inputID)) {
499 GstMetaDucatiBufferPriv *priv =
500 gst_ducati_buffer_priv_get ((GstBuffer *) self->inArgs->inputID);
502 GST_DEBUG_OBJECT (self, "Resending (inputID: %08x)",
503 self->inArgs->inputID);
504 /* Input ID needs to be resent to the codec for cases like H.264 field coded pictures.
505 The decoder indicates this by setting outArgs->outBufsInUseFlag */
506 self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
507 self->outBufs->descs[0].buf = (XDAS_Int8 *)
508 gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta ((GstBuffer *)
509 self->inArgs->inputID));
510 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
511 self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
512 self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
513 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
514 } else {
515 /* Get dmabuf fd of the buffer to lock it */
516 fd = gst_dma_buf_meta_get_fd (gst_buffer_get_dma_buf_meta ((GstBuffer *)
517 self->inArgs->inputID));
518 /* Must lock all the buffer passed to ducati */
519 GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x, fd: %d)",
520 self->inArgs->inputID, fd);
521 dce_buf_lock (1, &fd);
522 g_hash_table_insert (self->dce_locked_bufs,
523 (gpointer) self->inArgs->inputID, (gpointer) self->inArgs->inputID);
524 }
525 }
526 t = gst_util_get_timestamp ();
527 err = VIDDEC3_process (self->codec,
528 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
529 t = gst_util_get_timestamp () - t;
530 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
531 (gint) (t / 1000000));
533 if (err) {
534 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
535 err, self->outArgs->extendedError);
536 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
537 self->error_strings);
538 }
540 if (err || self->first_in_buffer) {
541 GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
542 getstatus_err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
543 self->dynParams, self->status);
544 if (getstatus_err) {
545 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
546 getstatus_err, self->status->extendedError);
547 gst_ducati_log_extended_error_info (self->status->extendedError,
548 self->error_strings);
549 }
551 if (!getstatus_err && self->first_in_buffer) {
552 if (send && self->status->maxNumDisplayBufs != 0) {
553 GstCaps *caps;
554 GST_WARNING_OBJECT (self, "changing max-ref-frames in caps to %d",
555 self->status->maxNumDisplayBufs);
557 caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
559 gst_caps_set_simple (caps, "max-ref-frames", G_TYPE_INT,
560 self->status->maxNumDisplayBufs, NULL);
561 if (self->pool)
562 gst_drm_buffer_pool_set_caps (self->pool, caps);
563 if (!gst_pad_set_caps (self->srcpad, caps)) {
564 GST_ERROR_OBJECT (self, "downstream didn't accept new caps");
565 err = XDM_EFAIL;
566 }
567 gst_caps_unref (caps);
568 }
569 }
570 }
572 if (err) {
573 if (flush)
574 err = XDM_EFAIL;
575 else
576 err = klass->handle_error (self, err,
577 self->outArgs->extendedError, self->status->extendedError);
578 }
580 /* we now let the codec decide */
581 self->dynParams->newFrameFlag = XDAS_FALSE;
583 if (err == XDM_EFAIL)
584 goto skip_outbuf_processing;
586 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
587 gboolean interlaced;
589 GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
590 i, self->outArgs->outputID[i]);
591 interlaced =
592 self->outArgs->displayBufs.bufDesc[0].contentType ==
593 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
595 if (interlaced) {
596 GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
597 if (!buf || !gst_buffer_is_writable (buf)) {
598 GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
599 } else {
600 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
601 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
602 if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
603 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_TFF);
604 if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
605 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_FLAG_RFF);
606 }
607 }
609 /* Getting an extra reference for the decoder */
610 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
612 /* if send is FALSE, don't try to renegotiate as we could be flushing during
613 * a PAUSED->READY state change
614 */
615 if (send && interlaced != self->interlaced) {
616 GstCaps *caps;
618 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
619 "thinks interlaced=%d... trusting codec", self->interlaced,
620 interlaced);
622 self->interlaced = interlaced;
624 caps = gst_caps_make_writable (gst_pad_get_current_caps (self->srcpad));
625 GST_INFO_OBJECT (self, "changing interlace field in caps");
626 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
627 NULL);
628 if (self->pool)
629 gst_drm_buffer_pool_set_caps (self->pool, caps);
630 if (!gst_pad_set_caps (self->srcpad, caps)) {
631 GST_ERROR_OBJECT (self,
632 "downstream didn't want to change interlace mode");
633 err = XDM_EFAIL;
634 }
635 gst_caps_unref (caps);
636 }
638 if (send) {
639 GstVideoCropMeta *crop = gst_buffer_get_video_crop_meta (outbuf);
640 if (crop) {
641 gint crop_width, crop_height;
642 /* send region of interest to sink on first buffer: */
643 XDM_Rect *r =
644 &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
646 crop_width = r->bottomRight.x - r->topLeft.x;
647 crop_height = r->bottomRight.y - r->topLeft.y;
649 if (crop_width > self->input_width)
650 crop_width = self->input_width;
651 if (crop_height > self->input_height)
652 crop_height = self->input_height;
654 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
655 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
656 crop_width, crop_height);
658 crop->x = r->topLeft.x;
659 crop->y = r->topLeft.y;
660 crop->width = crop_width;
661 crop->height = crop_height;
662 } else {
663 GST_INFO_OBJECT (self, "Crop metadata not present in buffer");
664 }
665 }
667 if (G_UNLIKELY (self->first_out_buffer) && send) {
668 GstDRMBufferPool *pool;
669 self->first_out_buffer = FALSE;
671 /* Destroy the pool so the buffers we used so far are eventually released.
672 * The pool will be recreated if needed.
673 */
674 pool = self->pool;
675 self->pool = NULL;
676 if (pool)
677 gst_drm_buffer_pool_destroy (pool);
678 }
680 if (send) {
681 GstClockTime ts;
683 ts = GST_BUFFER_PTS (outbuf);
685 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
686 i, outbuf, GST_TIME_ARGS (ts));
688 #ifdef USE_DTS_PTS_CODE
689 if (self->ts_may_be_pts) {
690 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
691 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
692 "enabling ts_is_pts");
693 self->ts_is_pts = TRUE;
694 }
695 }
696 #endif
698 self->last_pts = ts;
700 if (self->dts_ridx != self->dts_widx) {
701 ts = self->dts_queue[self->dts_ridx++ % NDTS];
702 }
704 if (self->ts_is_pts) {
705 /* if we have a queued DTS from demuxer, use that instead: */
706 GST_BUFFER_PTS (outbuf) = ts;
707 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
708 i, outbuf, GST_TIME_ARGS (ts));
709 }
711 ret = klass->push_output (self, outbuf);
712 if (flow_ret)
713 *flow_ret = ret;
714 if (ret != GST_FLOW_OK) {
715 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
716 /* just unref the remaining buffers (if any) */
717 send = FALSE;
718 }
719 } else {
720 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
721 i, outbuf);
723 gst_buffer_unref (outbuf);
724 }
725 }
727 skip_outbuf_processing:
728 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
729 GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
730 i, self->outArgs->freeBufID[i]);
731 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
732 }
734 return err;
735 }
737 /** call control(FLUSH), and then process() to pop out all buffers */
738 gboolean
739 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
740 {
741 gint err = FALSE;
742 int prev_num_in_bufs, prev_num_out_bufs;
744 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
746 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
748 /* note: flush is synchronized against _chain() to avoid calling
749 * the codec from multiple threads
750 */
751 GST_PAD_STREAM_LOCK (self->sinkpad);
753 #ifdef USE_DTS_PTS_CODE
754 self->dts_ridx = self->dts_widx = 0;
755 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
756 self->ts_may_be_pts = TRUE;
757 self->ts_is_pts = FALSE;
758 #endif
759 self->wait_keyframe = TRUE;
760 self->in_size = 0;
761 self->needs_flushing = FALSE;
762 self->need_out_buf = TRUE;
764 if (G_UNLIKELY (self->first_in_buffer)) {
765 goto out;
766 }
768 if (G_UNLIKELY (!self->codec)) {
769 GST_WARNING_OBJECT (self, "no codec");
770 goto out;
771 }
774 GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
775 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
776 if (err) {
777 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
778 goto out;
779 }
781 prev_num_in_bufs = self->inBufs->numBufs;
782 prev_num_out_bufs = self->outBufs->numBufs;
784 self->inBufs->descs[0].bufSize.bytes = 0;
785 self->inBufs->numBufs = 0;
786 self->inArgs->numBytes = 0;
787 self->inArgs->inputID = 0;
788 self->outBufs->numBufs = 0;
790 do {
791 err = codec_process (self, eos, TRUE, NULL);
792 } while (err != XDM_EFAIL);
794 /* We flushed the decoder, we can now remove the buffer that have never been
795 * unrefed in it */
796 g_hash_table_foreach (self->dce_locked_bufs, (GHFunc) dce_buf_free_all, self);
797 g_hash_table_remove_all (self->dce_locked_bufs);
798 g_hash_table_remove_all (self->passed_in_bufs);
800 /* reset outArgs in case we're flushing in codec_process trying to do error
801 * recovery */
802 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
803 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
805 self->dynParams->newFrameFlag = XDAS_TRUE;
807 /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
808 self->inBufs->numBufs = prev_num_in_bufs;
809 self->outBufs->numBufs = prev_num_out_bufs;
811 /* on a flush, it is normal (and not an error) for the last _process() call
812 * to return an error..
813 */
814 err = XDM_EOK;
816 out:
817 GST_PAD_STREAM_UNLOCK (self->sinkpad);
818 GST_DEBUG_OBJECT (self, "done");
820 return !err;
821 }
823 /* GstDucatiVidDec vmethod default implementations */
825 static gboolean
826 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
827 {
828 const GValue *codec_data;
829 gint w, h;
831 if (gst_structure_get_int (s, "width", &self->input_width) &&
832 gst_structure_get_int (s, "height", &self->input_height)) {
834 h = ALIGN2 (self->input_height, 4); /* round up to MB */
835 w = ALIGN2 (self->input_width, 4); /* round up to MB */
837 /* if we've already created codec, but the resolution has changed, we
838 * need to re-create the codec:
839 */
840 if (G_UNLIKELY ((self->codec) && ((h != self->height) || (w != self->width)
841 || self->codec_create_params_changed))) {
842 GST_DEBUG_OBJECT (self, "%dx%d => %dx%d, %d", self->width,
843 self->height, w, h, self->codec_create_params_changed);
844 codec_delete (self);
845 }
847 self->codec_create_params_changed = FALSE;
848 self->width = w;
849 self->height = h;
851 codec_data = gst_structure_get_value (s, "codec_data");
853 if (codec_data) {
854 int i;
855 GstMapInfo info;
856 gboolean mapped;
857 GstBuffer *buffer = gst_value_get_buffer (codec_data);
859 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
861 mapped = gst_buffer_map (buffer, &info, GST_MAP_READ);
862 GST_DEBUG_OBJECT (self, "codec_data dump, size = %d ", info.size);
863 for (i = 0; i < info.size; i++) {
864 GST_DEBUG_OBJECT (self, "%02x ", info.data[i]);
865 }
866 if (info.size) {
867 self->codecdata = g_slice_alloc (info.size);
868 if (self->codecdata) {
869 memcpy (self->codecdata, info.data, info.size);
870 } else {
871 GST_DEBUG_OBJECT (self, "g_slice_alloc failed");
872 }
873 self->codecdatasize = info.size;
874 }
875 if (mapped) {
876 gst_buffer_unmap (buffer, &info);
877 }
878 }
880 return TRUE;
881 }
883 return FALSE;
884 }
886 static gboolean
887 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
888 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
889 {
891 /* allocate params: */
892 self->params = dce_alloc (params_sz);
893 if (G_UNLIKELY (!self->params)) {
894 return FALSE;
895 }
896 self->params->size = params_sz;
897 self->params->maxFrameRate = 30000;
898 self->params->maxBitRate = 10000000;
900 self->params->dataEndianness = XDM_BYTE;
901 self->params->forceChromaFormat = XDM_YUV_420SP;
902 self->params->operatingMode = IVIDEO_DECODE_ONLY;
904 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
905 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
906 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
907 self->params->numInputDataUnits = 0;
908 self->params->numOutputDataUnits = 0;
910 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
911 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
912 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
913 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
915 /* allocate dynParams: */
916 self->dynParams = dce_alloc (dynparams_sz);
917 if (G_UNLIKELY (!self->dynParams)) {
918 return FALSE;
919 }
920 self->dynParams->size = dynparams_sz;
921 self->dynParams->decodeHeader = XDM_DECODE_AU;
922 self->dynParams->displayWidth = 0;
923 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
924 self->dynParams->newFrameFlag = XDAS_TRUE;
926 /* allocate status: */
927 self->status = dce_alloc (status_sz);
928 if (G_UNLIKELY (!self->status)) {
929 return FALSE;
930 }
931 memset (self->status, 0, status_sz);
932 self->status->size = status_sz;
934 /* allocate inBufs/outBufs: */
935 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
936 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
937 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
938 return FALSE;
939 }
941 /* allocate inArgs/outArgs: */
942 self->inArgs = dce_alloc (inargs_sz);
943 self->outArgs = dce_alloc (outargs_sz);
944 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
945 return FALSE;
946 }
947 self->inArgs->size = inargs_sz;
948 self->outArgs->size = outargs_sz;
950 return TRUE;
951 }
953 static GstBuffer *
954 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
955 {
956 GstMapInfo info;
957 gboolean mapped;
958 if (G_UNLIKELY (self->first_in_buffer) && self->codecdata) {
959 push_input (self, self->codecdata, self->codecdatasize);
960 }
961 /* just copy entire buffer */
963 mapped = gst_buffer_map (buf, &info, GST_MAP_READ);
964 if (mapped) {
965 push_input (self, info.data, info.size);
966 gst_buffer_unmap (buf, &info);
967 }
968 gst_buffer_unref (buf);
970 return NULL;
971 }
973 static GstFlowReturn
974 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
975 {
976 GstFlowReturn ret = GST_FLOW_OK;
978 if (self->segment.format == GST_FORMAT_TIME &&
979 self->segment.rate < (gdouble) 0.0) {
980 /* negative rate: reverse playback */
982 if (self->backlog_nframes > 0 &&
983 (GST_BUFFER_PTS (self->backlog_frames[0]) > GST_BUFFER_PTS (buf))) {
984 /* push out all backlog frames, since we have a buffer that is
985 earlier than any other in the list */
986 while (self->backlog_nframes > 0) {
987 ret = gst_ducati_viddec_push_latest (self);
988 if (ret != GST_FLOW_OK)
989 break;
990 }
991 }
992 /* add the frame to the list, the array will own the ref */
993 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
994 buf);
995 if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
996 self->backlog_frames[self->backlog_nframes++] = buf;
997 } else {
998 /* No space in the re-order buffer, drop the frame */
999 GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
1000 gst_buffer_unref (buf);
1001 }
1003 } else {
1004 /* if no reordering info was set, just send the buffer */
1005 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
1006 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
1007 return gst_pad_push (self->srcpad, buf);
1008 }
1010 /* add the frame to the list, the array will own the ref */
1011 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
1012 buf);
1013 self->backlog_frames[self->backlog_nframes++] = buf;
1015 /* push till we have no more than the max needed, or error */
1016 while (self->backlog_nframes > self->backlog_maxframes) {
1017 ret = gst_ducati_viddec_push_earliest (self);
1018 if (ret != GST_FLOW_OK)
1019 break;
1020 }
1021 }
1022 return ret;
1023 }
1025 static gint
1026 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
1027 gint extended_error, gint status_extended_error)
1028 {
1029 if (XDM_ISFATALERROR (extended_error))
1030 ret = XDM_EFAIL;
1031 else
1032 ret = XDM_EOK;
1034 return ret;
1035 }
1037 /* GstElement vmethod implementations */
1039 static gboolean
1040 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
1041 {
1042 gboolean ret = TRUE;
1043 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1044 GstStructure *s;
1045 GstCaps *outcaps = NULL;
1046 GstStructure *out_s;
1047 gint par_width, par_height;
1048 gboolean par_present;
1050 GST_INFO_OBJECT (self, "set_caps (sink): %" GST_PTR_FORMAT, caps);
1052 s = gst_caps_get_structure (caps, 0);
1053 if (!klass->parse_caps (self, s)) {
1054 GST_WARNING_OBJECT (self, "missing required fields");
1055 ret = FALSE;
1056 goto out;
1057 }
1059 /* update output/padded sizes */
1060 klass->update_buffer_size (self);
1062 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
1063 self->fps_n = 0;
1064 self->fps_d = 1;
1065 }
1066 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
1067 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
1068 &par_width, &par_height);
1070 outcaps = gst_pad_get_allowed_caps (self->srcpad);
1071 GST_DEBUG_OBJECT (self, "%s",
1072 gst_caps_to_string (gst_pad_get_current_caps (self->srcpad)));
1073 if (outcaps) {
1074 outcaps = gst_caps_make_writable (outcaps);
1075 outcaps = gst_caps_truncate (outcaps);
1076 if (gst_caps_is_empty (outcaps)) {
1077 gst_caps_unref (outcaps);
1078 outcaps = NULL;
1079 }
1080 }
1082 if (!outcaps) {
1083 outcaps = gst_caps_new_simple ("video/x-raw",
1084 "format", G_TYPE_STRING, "NV12", NULL);
1085 }
1087 out_s = gst_caps_get_structure (outcaps, 0);
1088 gst_structure_set (out_s,
1089 "width", G_TYPE_INT, self->padded_width,
1090 "height", G_TYPE_INT, self->padded_height,
1091 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
1092 if (par_present)
1093 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1094 par_width, par_height, NULL);
1096 if (self->interlaced)
1097 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
1099 self->stride = GST_ROUND_UP_4 (self->padded_width);
1101 self->outsize =
1102 GST_ROUND_UP_4 (self->stride) * GST_ROUND_UP_2 (self->padded_height) * 3 /
1103 2;
1105 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1106 self->outsize, self->stride, outcaps);
1108 if (!self->first_in_buffer) {
1109 /* Caps changed mid stream. We flush the codec to unlock all the potentially
1110 * locked buffers. This is needed for downstream sinks that provide a
1111 * buffer pool and need to destroy all the outstanding buffers before they
1112 * can negotiate new caps (hello v4l2sink).
1113 */
1114 gst_ducati_viddec_codec_flush (self, FALSE);
1115 }
1118 ret = gst_pad_set_caps (self->srcpad, outcaps);
1120 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
1122 /* default to no reordering */
1123 self->backlog_maxframes = 0;
1125 out:
1126 if (outcaps)
1127 gst_caps_unref (outcaps);
1129 return ret;
1130 }
1132 static gboolean
1133 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1134 {
1135 gboolean ret = TRUE;
1136 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1137 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1139 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1141 ret = klass->set_sink_caps (self, caps);
1143 gst_object_unref (self);
1145 return ret;
1146 }
1148 static GstCaps *
1149 gst_ducati_viddec_src_getcaps (GstPad * pad)
1150 {
1151 GstCaps *caps = NULL;
1153 caps = gst_pad_get_current_caps (pad);
1154 if (caps == NULL) {
1155 GstCaps *fil = gst_pad_get_pad_template_caps (pad);
1156 GST_DEBUG ("filter caps = %s \n", gst_caps_to_string (fil));
1157 return gst_caps_copy (fil);
1158 } else {
1159 return gst_caps_copy (caps);
1160 }
1161 }
1163 static gboolean
1164 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1165 GstQuery * query, gboolean * forward)
1166 {
1167 gboolean res = TRUE;
1169 switch (GST_QUERY_TYPE (query)) {
1170 case GST_QUERY_CAPS:
1171 {
1172 GstCaps *filter;
1173 filter = gst_ducati_viddec_src_getcaps (pad);
1174 gst_query_parse_caps (query, &filter);
1175 break;
1176 }
1177 case GST_QUERY_LATENCY:
1178 {
1179 gboolean live;
1180 GstClockTime min, max, latency;
1182 if (self->fps_d == 0) {
1183 GST_INFO_OBJECT (self, "not ready to report latency");
1184 res = FALSE;
1185 break;
1186 }
1188 gst_query_parse_latency (query, &live, &min, &max);
1189 if (self->fps_n != 0)
1190 latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1191 else
1192 latency = 0;
1194 /* Take into account the backlog frames for reordering */
1195 latency *= (self->backlog_maxframes + 1);
1197 if (min == GST_CLOCK_TIME_NONE)
1198 min = latency;
1199 else
1200 min += latency;
1202 if (max != GST_CLOCK_TIME_NONE)
1203 max += latency;
1205 GST_INFO_OBJECT (self,
1206 "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1207 GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1208 gst_query_set_latency (query, live, min, max);
1209 break;
1210 }
1211 default:
1212 break;
1213 }
1216 return res;
1217 }
1219 static gboolean
1220 gst_ducati_viddec_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1221 {
1222 gboolean res = TRUE, forward = TRUE;
1223 GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1224 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1226 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1227 res = klass->query (self, pad, query, &forward);
1228 if (res && forward)
1229 res = gst_pad_query_default (pad, parent, query);
1231 return res;
1232 }
1234 static gboolean
1235 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1236 {
1237 GstClockTime timestamp, qostime;
1238 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1239 gint64 diff;
1241 if (self->wait_keyframe) {
1242 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1243 GST_INFO_OBJECT (self, "skipping until the next keyframe");
1244 return FALSE;
1245 }
1247 self->wait_keyframe = FALSE;
1248 }
1250 timestamp = GST_BUFFER_PTS (buf);
1251 if (self->segment.format != GST_FORMAT_TIME ||
1252 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1253 goto no_qos;
1255 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1256 goto no_qos;
1258 qostime = gst_segment_to_running_time (&self->segment,
1259 GST_FORMAT_TIME, timestamp);
1260 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1261 /* out of segment */
1262 goto no_qos;
1264 /* see how our next timestamp relates to the latest qos timestamp. negative
1265 * values mean we are early, positive values mean we are too late. */
1266 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1268 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1269 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1270 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1271 self->qos_proportion);
1273 if (klass->can_drop_frame (self, buf, diff)) {
1274 GST_INFO_OBJECT (self, "dropping frame");
1275 return FALSE;
1276 }
1278 no_qos:
1279 return TRUE;
1280 }
1282 static gboolean
1283 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1284 gint64 diff)
1285 {
1286 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1287 GST_BUFFER_FLAG_DELTA_UNIT);
1289 if (diff >= 0 && !is_keyframe)
1290 return TRUE;
1292 return FALSE;
1293 }
1295 static GstFlowReturn
1296 gst_ducati_viddec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1297 {
1298 SizeT fd;
1300 GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1301 GstClockTime ts = GST_BUFFER_PTS (buf);
1302 GstFlowReturn ret = GST_FLOW_OK;
1303 Int32 err;
1304 GstBuffer *outbuf = NULL;
1305 GstCaps *outcaps = NULL;
1306 gboolean decode;
1308 GstQuery *query = NULL;
1309 guint min = 0;
1310 guint max = 0;
1311 guint size = 0;
1313 normal:
1314 if (G_UNLIKELY (!self->engine)) {
1315 GST_ERROR_OBJECT (self, "no engine");
1316 gst_buffer_unref (buf);
1317 return GST_FLOW_ERROR;
1318 }
1320 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1321 GST_TIME_ARGS (ts), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
1323 decode = gst_ducati_viddec_do_qos (self, buf);
1324 if (!decode) {
1325 gst_buffer_unref (buf);
1326 return GST_FLOW_OK;
1327 }
1329 if (!self->need_out_buf)
1330 goto have_out_buf;
1332 /* do this before creating codec to ensure reverse caps negotiation
1333 * happens first:
1334 */
1335 allocate_buffer:
1336 /* For plugins like VPE that allocate buffers to peers */
1337 if (!self->queried_external_pool) {
1338 query =
1339 gst_query_new_allocation (gst_pad_get_current_caps (self->srcpad),
1340 TRUE);
1341 if (gst_pad_peer_query (self->srcpad, query)) {
1342 gst_query_parse_nth_allocation_pool (query, 0, &self->externalpool, &size,
1343 &min, &max);
1344 }
1345 gst_query_unref (query);
1346 self->queried_external_pool = TRUE;
1347 }
1349 if (self->externalpool) {
1350 GstFlowReturn ret_acq_buf =
1351 gst_buffer_pool_acquire_buffer (GST_BUFFER_POOL (self->externalpool),
1352 &outbuf,
1353 NULL);
1354 if (ret_acq_buf == GST_FLOW_OK) {
1355 GstMetaDmaBuf *meta = gst_buffer_get_dma_buf_meta (outbuf);
1356 if (meta) {
1357 goto common;
1358 } else {
1359 gst_buffer_unref (outbuf);
1360 }
1361 }
1362 GST_WARNING_OBJECT (self, "acquire buffer from externalpool failed %s",
1363 gst_flow_get_name (ret_acq_buf));
1364 }
1366 aqcuire_from_own_pool:
1367 if (self->externalpool) {
1368 gst_object_unref (self->externalpool);
1369 self->externalpool = NULL;
1370 }
1371 outbuf = codec_buffer_pool_get (self, NULL);
1373 common:
1374 if (outbuf == NULL) {
1375 GST_WARNING_OBJECT (self, "alloc_buffer failed");
1376 gst_buffer_unref (buf);
1377 return GST_FLOW_ERROR;
1378 }
1380 if (G_UNLIKELY (!self->codec)) {
1381 if (!codec_create (self)) {
1382 GST_ERROR_OBJECT (self, "could not create codec");
1383 gst_buffer_unref (buf);
1384 gst_buffer_unref (outbuf);
1385 return GST_FLOW_ERROR;
1386 }
1387 }
1389 GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
1390 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1392 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1393 * internal pool while self->first_out_buffer == TRUE in order to simplify
1394 * things in case we need to renegotiate */
1395 self->inArgs->inputID =
1396 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1397 if (!self->inArgs->inputID) {
1398 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1399 gst_buffer_unref (buf);
1400 return GST_FLOW_ERROR;
1401 }
1402 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1404 have_out_buf:
1405 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1407 #ifdef USE_DTS_PTS_CODE
1408 if (ts != GST_CLOCK_TIME_NONE) {
1409 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1410 /* if next buffer has earlier ts than previous, then the ts
1411 * we are getting are definitely decode order (DTS):
1412 */
1413 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1414 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1415 self->ts_may_be_pts = FALSE;
1416 }
1417 self->last_dts = ts;
1418 }
1419 #endif
1421 if (self->in_size == 0 && outbuf) {
1422 GST_DEBUG_OBJECT (self, "no input, skipping process");
1424 gst_buffer_unref (outbuf);
1425 return GST_FLOW_OK;
1426 }
1428 self->inArgs->numBytes = self->in_size;
1429 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1430 /* XDM_MemoryType required by drm to allcoate buffer */
1431 self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1433 err = codec_process (self, TRUE, FALSE, &ret);
1434 if (err) {
1435 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1436 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1437 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1438 self->error_strings);
1440 return GST_FLOW_ERROR;
1441 }
1443 if (ret != GST_FLOW_OK) {
1444 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1445 gst_flow_get_name (ret));
1447 return ret;
1448 }
1450 self->first_in_buffer = FALSE;
1452 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1453 /* The copy could be avoided by playing with the buffer pointer,
1454 but it seems to be rare and for not many bytes */
1455 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1456 self->outArgs->bytesConsumed, self->in_size,
1457 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1458 if (self->outArgs->bytesConsumed > 0) {
1459 if (self->outArgs->bytesConsumed > self->in_size) {
1460 GST_WARNING_OBJECT (self,
1461 "Codec claims to have used more bytes than supplied");
1462 self->in_size = 0;
1463 } else {
1464 if (self->outArgs->bytesConsumed < self->in_size) {
1465 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1466 self->in_size - self->outArgs->bytesConsumed);
1467 }
1468 self->in_size -= self->outArgs->bytesConsumed;
1469 }
1470 }
1471 } else {
1472 self->in_size = 0;
1473 }
1475 if (self->outArgs->outBufsInUseFlag) {
1476 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1477 self->need_out_buf = FALSE;
1478 } else {
1479 self->need_out_buf = TRUE;
1480 }
1482 if (buf) {
1483 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1484 gst_buffer_get_size (buf));
1485 ts = GST_BUFFER_PTS (buf);
1486 goto allocate_buffer;
1487 }
1489 if (self->needs_flushing)
1490 gst_ducati_viddec_codec_flush (self, FALSE);
1492 return GST_FLOW_OK;
1493 }
1495 static gboolean
1496 gst_ducati_viddec_event (GstPad * pad, GstObject * parent, GstEvent * event)
1497 {
1498 GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1499 gboolean ret = TRUE;
1501 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1503 switch (GST_EVENT_TYPE (event)) {
1504 case GST_EVENT_CAPS:
1505 {
1506 GstCaps *caps;
1507 gst_event_parse_caps (event, &caps);
1508 return gst_ducati_viddec_sink_setcaps (pad, caps);
1509 break;
1510 }
1511 case GST_EVENT_SEGMENT:
1512 {
1514 gst_event_copy_segment (event, &self->segment);
1516 break;
1517 }
1518 case GST_EVENT_EOS:
1519 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1520 GST_ERROR_OBJECT (self, "could not flush on eos");
1521 ret = FALSE;
1522 }
1523 break;
1524 case GST_EVENT_FLUSH_STOP:
1525 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1526 GST_ERROR_OBJECT (self, "could not flush");
1527 gst_event_unref (event);
1528 ret = FALSE;
1529 }
1530 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1531 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1532 self->qos_proportion = 1;
1533 self->need_out_buf = TRUE;
1534 break;
1535 default:
1536 break;
1537 }
1539 if (ret)
1540 ret = gst_pad_push_event (self->srcpad, event);
1541 GST_LOG_OBJECT (self, "end");
1543 return ret;
1544 }
1546 static gboolean
1547 gst_ducati_viddec_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1548 {
1549 GstDucatiVidDec *self = GST_DUCATIVIDDEC (parent);
1550 gboolean ret = TRUE;
1552 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1554 switch (GST_EVENT_TYPE (event)) {
1555 case GST_EVENT_QOS:
1556 {
1557 gdouble proportion;
1558 GstClockTimeDiff diff;
1559 GstClockTime timestamp;
1560 GstQOSType type;
1562 gst_event_parse_qos (event, &type, &proportion, &diff, ×tamp);
1564 GST_OBJECT_LOCK (self);
1565 self->qos_proportion = proportion;
1566 self->qos_earliest_time = timestamp + 2 * diff;
1567 GST_OBJECT_UNLOCK (self);
1569 GST_DEBUG_OBJECT (self,
1570 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1571 proportion, GST_TIME_ARGS (timestamp), diff);
1573 ret = gst_pad_push_event (self->sinkpad, event);
1574 break;
1575 }
1576 default:
1577 ret = gst_pad_push_event (self->sinkpad, event);
1578 break;
1579 }
1581 GST_LOG_OBJECT (self, "end");
1583 return ret;
1584 }
1586 static GstStateChangeReturn
1587 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1588 {
1589 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1590 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1591 gboolean supported;
1593 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1594 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1595 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1597 switch (transition) {
1598 case GST_STATE_CHANGE_NULL_TO_READY:
1599 if (!engine_open (self)) {
1600 GST_ERROR_OBJECT (self, "could not open");
1601 return GST_STATE_CHANGE_FAILURE;
1602 }
1603 /* try to create/destroy the codec here, it may not be supported */
1604 supported = codec_create (self);
1605 codec_delete (self);
1606 self->codec = NULL;
1607 if (!supported) {
1608 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1609 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1610 engine_close (self);
1611 return GST_STATE_CHANGE_FAILURE;
1612 }
1613 break;
1614 default:
1615 break;
1616 }
1618 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1620 if (ret == GST_STATE_CHANGE_FAILURE)
1621 goto leave;
1623 switch (transition) {
1624 case GST_STATE_CHANGE_PAUSED_TO_READY:
1625 self->interlaced = FALSE;
1626 gst_ducati_viddec_codec_flush (self, FALSE);
1627 break;
1628 case GST_STATE_CHANGE_READY_TO_NULL:
1629 codec_delete (self);
1630 engine_close (self);
1631 break;
1632 default:
1633 break;
1634 }
1636 leave:
1637 GST_LOG_OBJECT (self, "end");
1639 return ret;
1640 }
1642 /* GObject vmethod implementations */
1645 static void
1646 gst_ducati_viddec_get_property (GObject * obj,
1647 guint prop_id, GValue * value, GParamSpec * pspec)
1648 {
1649 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1652 switch (prop_id) {
1653 case PROP_VERSION:{
1654 int err;
1655 char *version = NULL;
1657 if (!self->engine)
1658 engine_open (self);
1660 if (!self->codec)
1661 codec_create (self);
1663 if (self->codec) {
1664 version = dce_alloc (VERSION_LENGTH);
1665 if (version) {
1666 self->status->data.buf = (XDAS_Int8 *) version;
1667 self->status->data.bufSize = VERSION_LENGTH;
1669 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1670 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1671 self->dynParams, self->status);
1673 if (err) {
1674 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1675 } else
1676 GST_DEBUG ("Codec version %s", self->status->data.buf);
1678 self->status->data.buf = NULL;
1679 self->status->data.bufSize = 0;
1680 dce_free (version);
1681 }
1682 }
1683 break;
1684 }
1685 case PROP_MAX_REORDER_FRAMES:
1686 g_value_set_int (value, self->backlog_max_maxframes);
1687 break;
1688 case PROP_CODEC_DEBUG_INFO:
1689 g_value_set_boolean (value, self->codec_debug_info);
1690 break;
1691 default:{
1692 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1693 break;
1694 }
1695 }
1696 }
1698 static void
1699 gst_ducati_viddec_set_property (GObject * obj,
1700 guint prop_id, const GValue * value, GParamSpec * pspec)
1701 {
1702 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1704 switch (prop_id) {
1705 case PROP_MAX_REORDER_FRAMES:
1706 self->backlog_max_maxframes = g_value_get_int (value);
1707 break;
1708 case PROP_CODEC_DEBUG_INFO:
1709 self->codec_debug_info = g_value_get_boolean (value);
1710 break;
1711 default:{
1712 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1713 break;
1714 }
1715 }
1716 }
1718 static void
1719 gst_ducati_viddec_finalize (GObject * obj)
1720 {
1721 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1723 codec_delete (self);
1725 if (self->externalpool) {
1726 gst_object_unref (self->externalpool);
1727 self->externalpool = NULL;
1728 }
1730 engine_close (self);
1732 /* Will unref the remaining buffers if needed */
1733 g_hash_table_unref (self->dce_locked_bufs);
1734 g_hash_table_unref (self->passed_in_bufs);
1736 if (self->codecdata) {
1737 g_slice_free1 (self->codecdatasize, self->codecdata);
1738 self->codecdata = NULL;
1739 }
1741 G_OBJECT_CLASS (parent_class)->finalize (obj);
1742 }
1744 static void
1745 gst_ducati_viddec_base_init (gpointer gclass)
1746 {
1747 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1749 gst_element_class_add_pad_template (element_class,
1750 gst_static_pad_template_get (&src_factory));
1751 }
1753 static void
1754 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1755 {
1756 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1757 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1758 parent_class = g_type_class_peek_parent (klass);
1760 gobject_class->get_property =
1761 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1762 gobject_class->set_property =
1763 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1764 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1765 gstelement_class->change_state =
1766 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1768 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1769 klass->allocate_params =
1770 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1771 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1772 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1773 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1774 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1775 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1776 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1777 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1779 g_object_class_install_property (gobject_class, PROP_VERSION,
1780 g_param_spec_string ("version", "Version",
1781 "The codec version string", "",
1782 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1784 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1785 g_param_spec_int ("max-reorder-frames",
1786 "Maximum number of frames needed for reordering",
1787 "The maximum number of frames needed for reordering output frames. "
1788 "Only meaningful for codecs with B frames. 0 means no reordering. "
1789 "This value will be used if the correct value cannot be inferred "
1790 "from the stream. Too low a value may cause misordering, too high "
1791 "will cause extra latency.",
1792 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1793 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1795 g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1796 g_param_spec_boolean ("codec-debug-info",
1797 "Gather debug info from the codec",
1798 "Gather and log relevant debug information from the codec. "
1799 "What is gathered is typically codec specific", FALSE,
1800 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1801 }
1803 static void
1804 gst_ducati_viddec_init (GstDucatiVidDec * self, gpointer klass)
1805 {
1806 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1808 gst_ducati_set_generic_error_strings (self->error_strings);
1810 self->sinkpad =
1811 gst_pad_new_from_template (gst_element_class_get_pad_template
1812 (gstelement_class, "sink"), "sink");
1813 gst_pad_set_chain_function (self->sinkpad, gst_ducati_viddec_chain);
1814 gst_pad_set_event_function (self->sinkpad, gst_ducati_viddec_event);
1816 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1817 gst_pad_set_event_function (self->srcpad, gst_ducati_viddec_src_event);
1818 gst_pad_set_query_function (self->srcpad, gst_ducati_viddec_src_query);
1820 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1821 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1823 self->input_width = 0;
1824 self->input_height = 0;
1825 /* sane defaults in case we need to create codec without caps negotiation
1826 * (for example, to get 'version' property)
1827 */
1828 self->width = 128;
1829 self->height = 128;
1830 self->fps_n = -1;
1831 self->fps_d = -1;
1833 self->first_in_buffer = TRUE;
1834 self->first_out_buffer = FALSE;
1835 self->interlaced = FALSE;
1837 #ifdef USE_DTS_PTS_CODE
1838 self->dts_ridx = self->dts_widx = 0;
1839 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1840 self->ts_may_be_pts = TRUE;
1841 self->ts_is_pts = FALSE;
1842 #endif
1844 self->codec_create_params_changed = FALSE;
1846 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1848 self->queried_external_pool = FALSE;
1849 self->externalpool = NULL;
1851 self->codecdata = NULL;
1852 self->codecdatasize = 0;
1854 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1856 self->qos_proportion = 1;
1857 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1858 self->wait_keyframe = TRUE;
1860 self->need_out_buf = TRUE;
1861 self->device = NULL;
1862 self->input_bo = NULL;
1864 self->backlog_maxframes = 0;
1865 self->backlog_nframes = 0;
1866 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1868 self->codec_debug_info = FALSE;
1870 self->dce_locked_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1871 NULL, (GDestroyNotify) do_dce_buf_unlock);
1872 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1873 NULL, (GDestroyNotify) gst_buffer_unref);
1874 }