bd485d899288681713390df1cbf3051f2d1985ef
1 #define USE_DTS_PTS_CODE
2 /*
3 * GStreamer
4 * Copyright (c) 2010, Texas Instruments Incorporated
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
25 #include "gstducatividdec.h"
26 #include "gstducatibufferpriv.h"
28 #define VERSION_LENGTH 256
29 GST_BOILERPLATE (GstDucatiVidDec, gst_ducati_viddec, GstElement,
30 GST_TYPE_ELEMENT);
32 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
33 GST_PAD_SRC,
34 GST_PAD_ALWAYS,
35 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("NV12"))
36 );
38 enum
39 {
40 PROP_0,
41 PROP_VERSION,
42 PROP_MAX_REORDER_FRAMES,
43 PROP_CODEC_DEBUG_INFO
44 };
46 /* helper functions */
48 static void
49 engine_close (GstDucatiVidDec * self)
50 {
51 if (self->params) {
52 dce_free (self->params);
53 self->params = NULL;
54 }
56 if (self->dynParams) {
57 dce_free (self->dynParams);
58 self->dynParams = NULL;
59 }
61 if (self->status) {
62 dce_free (self->status);
63 self->status = NULL;
64 }
66 if (self->inBufs) {
67 dce_free (self->inBufs);
68 self->inBufs = NULL;
69 }
71 if (self->outBufs) {
72 dce_free (self->outBufs);
73 self->outBufs = NULL;
74 }
76 if (self->inArgs) {
77 dce_free (self->inArgs);
78 self->inArgs = NULL;
79 }
81 if (self->outArgs) {
82 dce_free (self->outArgs);
83 self->outArgs = NULL;
84 }
86 if (self->engine) {
87 Engine_close (self->engine);
88 self->engine = NULL;
89 }
91 if (self->device) {
92 dce_deinit (self->device);
93 self->device = NULL;
94 }
95 }
97 static gboolean
98 engine_open (GstDucatiVidDec * self)
99 {
100 gboolean ret;
101 int ec;
103 if (G_UNLIKELY (self->engine)) {
104 return TRUE;
105 }
107 if (self->device == NULL) {
108 self->device = dce_init ();
109 if (self->device == NULL) {
110 GST_ERROR_OBJECT (self, "dce_init() failed");
111 return FALSE;
112 }
113 }
115 GST_DEBUG_OBJECT (self, "opening engine");
117 self->engine = Engine_open ((String) "ivahd_vidsvr", NULL, &ec);
118 if (G_UNLIKELY (!self->engine)) {
119 GST_ERROR_OBJECT (self, "could not create engine");
120 return FALSE;
121 }
123 ret = GST_DUCATIVIDDEC_GET_CLASS (self)->allocate_params (self,
124 sizeof (IVIDDEC3_Params), sizeof (IVIDDEC3_DynamicParams),
125 sizeof (IVIDDEC3_Status), sizeof (IVIDDEC3_InArgs),
126 sizeof (IVIDDEC3_OutArgs));
128 return ret;
129 }
131 static void
132 codec_delete (GstDucatiVidDec * self)
133 {
134 if (self->pool) {
135 gst_drm_buffer_pool_destroy (self->pool);
136 self->pool = NULL;
137 }
139 if (self->codec) {
140 GST_DEBUG ("Calling VIDDEC3_delete");
141 VIDDEC3_delete (self->codec);
142 self->codec = NULL;
143 }
145 if (self->input_bo) {
146 omap_bo_del (self->input_bo);
147 self->input_bo = NULL;
148 }
149 }
151 static gboolean
152 codec_create (GstDucatiVidDec * self)
153 {
154 gint err, n;
155 const gchar *codec_name;
156 char *version = NULL;
158 codec_delete (self);
160 if (G_UNLIKELY (!self->engine)) {
161 GST_ERROR_OBJECT (self, "no engine");
162 return FALSE;
163 }
165 /* these need to be set before VIDDEC3_create */
166 self->params->maxWidth = self->width;
167 self->params->maxHeight = self->height;
169 codec_name = GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name;
171 /* create codec: */
172 GST_DEBUG_OBJECT (self, "creating codec: %s", codec_name);
173 self->codec =
174 VIDDEC3_create (self->engine, (String) codec_name, self->params);
176 if (!self->codec) {
177 return FALSE;
178 }
180 GST_DEBUG ("Calling VIDDEC3_control XDM_SETPARAMS");
181 err =
182 VIDDEC3_control (self->codec, XDM_SETPARAMS, self->dynParams,
183 self->status);
184 if (err) {
185 GST_ERROR_OBJECT (self, "failed XDM_SETPARAMS");
186 return FALSE;
187 }
189 self->first_in_buffer = TRUE;
190 self->first_out_buffer = FALSE;
192 version = dce_alloc (VERSION_LENGTH);
193 if (version) {
194 self->status->data.buf = (XDAS_Int8 *) version;
195 self->status->data.bufSize = VERSION_LENGTH;
197 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
198 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
199 self->dynParams, self->status);
201 if (err) {
202 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
203 } else
204 GST_DEBUG ("Codec version %s", self->status->data.buf);
206 self->status->data.buf = NULL;
207 self->status->data.bufSize = 0;
208 dce_free (version);
210 }
213 /* allocate input buffer and initialize inBufs: */
214 /* FIXME: needed size here has nothing to do with width * height */
215 self->input_bo = omap_bo_new (self->device,
216 self->width * self->height, OMAP_BO_WC);
217 self->input = omap_bo_map (self->input_bo);
218 self->inBufs->numBufs = 1;
219 /* IPC requires dmabuf fd in place of bo handle */
220 self->inBufs->descs[0].buf = (XDAS_Int8 *) omap_bo_dmabuf (self->input_bo);
222 /* Actual buffers will be set later, as they will be different for every
223 frame. We allow derived classes to add their own buffers, however, so
224 we initialize the number of outBufs here, counting the number of extra
225 buffers required, including "holes" in planes, which may not be filled
226 if not assigned. */
227 self->outBufs->numBufs = 2; /* luma and chroma planes, always */
228 for (n = 0; n < 3; n++)
229 if (self->params->metadataType[n] != IVIDEO_METADATAPLANE_NONE)
230 self->outBufs->numBufs = 2 + n + 1;
232 return TRUE;
233 }
235 static inline GstBuffer *
236 codec_buffer_pool_get (GstDucatiVidDec * self, GstBuffer * buf)
237 {
238 if (G_UNLIKELY (!self->pool)) {
239 guint size = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
240 self->padded_width, self->padded_height);
242 GST_DEBUG_OBJECT (self, "creating bufferpool");
243 self->pool = gst_drm_buffer_pool_new (GST_ELEMENT (self),
244 dce_get_fd (), GST_PAD_CAPS (self->srcpad), size);
245 }
246 return GST_BUFFER (gst_drm_buffer_pool_get (self->pool, FALSE));
247 }
249 static GstDucatiBufferPriv *
250 get_buffer_priv (GstDucatiVidDec * self, GstBuffer * buf)
251 {
252 GstDucatiBufferPriv *priv = gst_ducati_buffer_priv_get (buf);
253 if (!priv) {
254 GstVideoFormat format = GST_VIDEO_FORMAT_NV12;
255 GstDmaBuf *dmabuf = gst_buffer_get_dma_buf (buf);
257 /* if it isn't a dmabuf buffer that we can import, then there
258 * is nothing we can do with it:
259 */
260 if (!dmabuf) {
261 GST_DEBUG_OBJECT (self, "not importing non dmabuf buffer");
262 return NULL;
263 }
265 priv = gst_ducati_buffer_priv_new ();
267 priv->bo = omap_bo_from_dmabuf (self->device, gst_dma_buf_get_fd (dmabuf));
269 priv->uv_offset = gst_video_format_get_component_offset (format,
270 1, self->stride, self->padded_height);
271 priv->size = gst_video_format_get_size (format,
272 self->stride, self->padded_height);
274 gst_ducati_buffer_priv_set (buf, priv);
275 gst_mini_object_unref (GST_MINI_OBJECT (priv));
276 }
277 return priv;
278 }
280 static XDAS_Int32
281 codec_prepare_outbuf (GstDucatiVidDec * self, GstBuffer ** buf,
282 gboolean force_internal)
283 {
284 GstDucatiBufferPriv *priv = NULL;
285 GstDmaBuf *dmabuf = NULL;
287 if (!force_internal)
288 priv = get_buffer_priv (self, *buf);
290 if (!priv) {
291 GstBuffer *orig = *buf;
293 GST_DEBUG_OBJECT (self, "internal bufferpool forced");
294 *buf = codec_buffer_pool_get (self, NULL);
295 GST_BUFFER_TIMESTAMP (*buf) = GST_BUFFER_TIMESTAMP (orig);
296 GST_BUFFER_DURATION (*buf) = GST_BUFFER_DURATION (orig);
297 gst_buffer_unref (orig);
298 return codec_prepare_outbuf (self, buf, FALSE);
299 }
301 /* There are at least two buffers. Derived classes may add codec specific
302 buffers (eg, debug info) after these two if they want to. */
303 dmabuf = gst_buffer_get_dma_buf (*buf);
304 /* XDM_MemoryType required by drm to allcoate buffer */
305 self->outBufs->descs[0].memType = XDM_MEMTYPE_RAW;
306 /* IPC requires dmabuf fd in place of bo handle */
307 self->outBufs->descs[0].buf = (XDAS_Int8 *) gst_dma_buf_get_fd (dmabuf);
308 self->outBufs->descs[0].bufSize.bytes = priv->uv_offset;
309 self->outBufs->descs[1].memType = XDM_MEMTYPE_RAW;
310 /* For singleplaner buffer pass a single dmabuf fd for both the outBufs
311 ie: self->outBufs->descs[0].buf and self->outBufs->descs[1].buf
312 should point to a single buffer fd and need to update the
313 descs[0].bufSize.bytes with the size of luminance(Y) data
314 and descs[1].bufSize.bytes with crominance(UV) */
315 self->outBufs->descs[1].buf = (XDAS_Int8 *) self->outBufs->descs[0].buf;
316 self->outBufs->descs[1].bufSize.bytes = priv->size - priv->uv_offset;
318 return (XDAS_Int32) * buf;
319 }
321 static GstBuffer *
322 codec_get_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
323 {
324 GstBuffer *buf = (GstBuffer *) id;
326 if (buf) {
327 g_hash_table_insert (self->passed_in_bufs, buf, buf);
329 gst_buffer_ref (buf);
330 }
331 return buf;
332 }
334 static void
335 codec_unlock_outbuf (GstDucatiVidDec * self, XDAS_Int32 id)
336 {
337 GstBuffer *buf = (GstBuffer *) id;
338 SizeT fd;
340 if (buf) {
341 GST_DEBUG_OBJECT (self, "free buffer: %d %p", id, buf);
342 /* Get dmabuf fd of the buffer to unlock */
343 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf(buf));
344 /* Must unlock the buffer before free */
345 dce_buf_unlock(1,&fd);
346 g_hash_table_remove (self->passed_in_bufs, buf);
347 }
348 }
350 /* Called when playing in reverse */
351 static GstFlowReturn
352 gst_ducati_viddec_push_latest (GstDucatiVidDec * self)
353 {
354 GstBuffer *buf;
356 if (self->backlog_nframes == 0)
357 return GST_FLOW_OK;
359 /* send it, giving away the ref */
360 buf = self->backlog_frames[--self->backlog_nframes];
361 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
362 buf);
363 return gst_pad_push (self->srcpad, buf);
364 }
366 static GstFlowReturn
367 gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
368 {
369 guint64 earliest_order = G_MAXUINT64;
370 guint earliest_index = 0, i;
371 GstBuffer *buf;
373 if (self->backlog_nframes == 0)
374 return GST_FLOW_OK;
376 /* work out which frame has the earliest poc */
377 for (i = 0; i < self->backlog_nframes; i++) {
378 guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
379 if (earliest_order == G_MAXUINT64 || order < earliest_order) {
380 earliest_order = order;
381 earliest_index = i;
382 }
383 }
385 /* send it, giving away the ref */
386 buf = self->backlog_frames[earliest_index];
387 self->backlog_frames[earliest_index] =
388 self->backlog_frames[--self->backlog_nframes];
389 GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
390 buf);
391 return gst_pad_push (self->srcpad, buf);
392 }
394 static void
395 gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
396 {
397 if (self->segment.format == GST_FORMAT_TIME &&
398 self->segment.rate < (gdouble) 0.0) {
399 /* negative rate */
400 /* push everything on the backlog, ignoring errors */
401 while (self->backlog_nframes > 0) {
402 gst_ducati_viddec_push_latest (self);
403 }
404 } else {
405 /* push everything on the backlog, ignoring errors */
406 while (self->backlog_nframes > 0) {
407 gst_ducati_viddec_push_earliest (self);
408 }
409 }
410 }
412 static gint
413 codec_process (GstDucatiVidDec * self, gboolean send, gboolean flush,
414 GstFlowReturn * flow_ret)
415 {
416 gint err;
417 GstClockTime t;
418 GstBuffer *outbuf = NULL;
419 gint i;
420 SizeT fd;
421 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
422 GstFlowReturn ret = GST_FLOW_OK;
423 if (flow_ret)
424 /* never leave flow_ret uninitialized */
425 *flow_ret = GST_FLOW_OK;
427 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
428 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
430 if (self->inArgs->inputID != 0) {
431 /* Get dmabuf fd of the buffer to lock it*/
432 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf((GstBuffer *) self->inArgs->inputID));
433 /* Must lock all the buffer passed to ducati */
434 GST_DEBUG_OBJECT (self, "dce_buf_lock(inputID: %08x", self->inArgs->inputID);
435 dce_buf_lock(1,&fd);
436 }
438 GST_DEBUG_OBJECT (self, "Calling VIDDEC3_process, inputID: %08x", self->inArgs->inputID);
439 t = gst_util_get_timestamp ();
440 err = VIDDEC3_process (self->codec,
441 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
442 t = gst_util_get_timestamp () - t;
443 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
444 (gint) (t / 1000000));
446 if (err) {
447 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
448 err, self->outArgs->extendedError);
449 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
450 self->error_strings);
452 GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
453 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
454 self->dynParams, self->status);
455 if (err) {
456 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
457 err, self->status->extendedError);
458 gst_ducati_log_extended_error_info (self->status->extendedError,
459 self->error_strings);
460 }
462 if (flush)
463 err = XDM_EFAIL;
464 else
465 err = klass->handle_error (self, err,
466 self->outArgs->extendedError, self->status->extendedError);
467 }
469 /* we now let the codec decide */
470 self->dynParams->newFrameFlag = XDAS_FALSE;
472 if (err == XDM_EFAIL)
473 goto skip_outbuf_processing;
475 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
476 gboolean interlaced;
478 GST_DEBUG_OBJECT (self, "VIDDEC3_process outputID[%d]: %08x",
479 i, self->outArgs->outputID[i]);
480 interlaced =
481 self->outArgs->displayBufs.bufDesc[0].contentType ==
482 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
484 if (interlaced) {
485 GstBuffer *buf = GST_BUFFER (self->outArgs->outputID[i]);
486 if (!buf || !gst_buffer_is_metadata_writable (buf)) {
487 GST_ERROR_OBJECT (self, "Cannot change buffer flags!!");
488 } else {
489 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_TFF);
490 GST_BUFFER_FLAG_UNSET (buf, GST_VIDEO_BUFFER_RFF);
491 if (self->outArgs->displayBufs.bufDesc[0].topFieldFirstFlag)
492 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_TFF);
493 if (self->outArgs->displayBufs.bufDesc[0].repeatFirstFieldFlag)
494 GST_BUFFER_FLAG_SET (buf, GST_VIDEO_BUFFER_RFF);
495 }
496 }
498 /* Getting an extra reference for the decoder */
499 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
501 /* if send is FALSE, don't try to renegotiate as we could be flushing during
502 * a PAUSED->READY state change
503 */
504 if (send && interlaced != self->interlaced) {
505 GstCaps *caps;
507 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
508 "thinks interlaced=%d... trusting codec", self->interlaced,
509 interlaced);
511 self->interlaced = interlaced;
513 caps =
514 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
515 GST_INFO_OBJECT (self, "changing interlace field in caps");
516 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
517 NULL);
518 if (self->pool) gst_drm_buffer_pool_set_caps (self->pool, caps);
519 if (!gst_pad_set_caps (self->srcpad, caps)) {
520 GST_ERROR_OBJECT (self,
521 "downstream didn't want to change interlace mode");
522 err = XDM_EFAIL;
523 }
524 gst_caps_unref (caps);
526 /* this buffer still has the old caps so we skip it */
527 send = FALSE;
528 }
530 if (G_UNLIKELY (self->send_crop_event) && send) {
531 gint crop_width, crop_height;
533 /* send region of interest to sink on first buffer: */
534 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
536 crop_width = r->bottomRight.x - r->topLeft.x;
537 crop_height = r->bottomRight.y - r->topLeft.y;
539 if (crop_width > self->input_width)
540 crop_width = self->input_width;
541 if (crop_height > self->input_height)
542 crop_height = self->input_height;
544 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
545 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
546 crop_width, crop_height);
548 gst_pad_push_event (self->srcpad,
549 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
550 crop_width, crop_height));
552 if (self->crop)
553 gst_video_crop_unref (self->crop);
555 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
556 crop_width, crop_height);
558 self->send_crop_event = FALSE;
559 }
561 if (G_UNLIKELY (self->first_out_buffer) && send) {
562 GstDRMBufferPool *pool;
563 self->first_out_buffer = FALSE;
565 /* Destroy the pool so the buffers we used so far are eventually released.
566 * The pool will be recreated if needed.
567 */
568 pool = self->pool;
569 self->pool = NULL;
570 if (pool) gst_drm_buffer_pool_destroy (pool);
571 }
573 if (send) {
574 GstClockTime ts;
576 ts = GST_BUFFER_TIMESTAMP (outbuf);
578 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
579 i, outbuf, GST_TIME_ARGS (ts));
581 #ifdef USE_DTS_PTS_CODE
582 if (self->ts_may_be_pts) {
583 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
584 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
585 "enabling ts_is_pts");
586 self->ts_is_pts = TRUE;
587 }
588 }
589 #endif
591 self->last_pts = ts;
593 if (self->dts_ridx != self->dts_widx) {
594 ts = self->dts_queue[self->dts_ridx++ % NDTS];
595 }
597 if (self->ts_is_pts) {
598 /* if we have a queued DTS from demuxer, use that instead: */
599 GST_BUFFER_TIMESTAMP (outbuf) = ts;
600 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
601 i, outbuf, GST_TIME_ARGS (ts));
602 }
604 if (GST_BUFFER_CAPS (outbuf) &&
605 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
606 GST_PAD_CAPS (self->srcpad))) {
607 /* this looks a bit scary but it's really just to change the interlace=
608 * field in caps when we start as !interlaced and the codec detects
609 * otherwise */
610 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
611 "interlace mismatch");
612 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
613 }
615 if (self->crop)
616 gst_buffer_set_video_crop (outbuf, self->crop);
618 ret = klass->push_output (self, outbuf);
619 if (flow_ret)
620 *flow_ret = ret;
621 if (ret != GST_FLOW_OK) {
622 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
623 /* just unref the remaining buffers (if any) */
624 send = FALSE;
625 }
626 } else {
627 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
628 i, outbuf);
630 gst_buffer_unref (outbuf);
631 }
632 }
634 skip_outbuf_processing:
635 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
636 GST_DEBUG_OBJECT (self, "VIDDEC3_process freeBufID[%d]: %08x",
637 i, self->outArgs->freeBufID[i]);
638 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
639 }
641 return err;
642 }
644 /** call control(FLUSH), and then process() to pop out all buffers */
645 gboolean
646 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
647 {
648 gint err = FALSE;
649 int prev_num_in_bufs, prev_num_out_bufs;
651 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
653 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
655 /* note: flush is synchronized against _chain() to avoid calling
656 * the codec from multiple threads
657 */
658 GST_PAD_STREAM_LOCK (self->sinkpad);
660 #ifdef USE_DTS_PTS_CODE
661 self->dts_ridx = self->dts_widx = 0;
662 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
663 self->ts_may_be_pts = TRUE;
664 self->ts_is_pts = FALSE;
665 #endif
666 self->wait_keyframe = TRUE;
667 self->in_size = 0;
668 self->needs_flushing = FALSE;
669 self->need_out_buf = TRUE;
671 if (G_UNLIKELY (self->first_in_buffer)) {
672 goto out;
673 }
675 if (G_UNLIKELY (!self->codec)) {
676 GST_WARNING_OBJECT (self, "no codec");
677 goto out;
678 }
681 GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
682 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
683 if (err) {
684 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
685 goto out;
686 }
688 prev_num_in_bufs = self->inBufs->numBufs;
689 prev_num_out_bufs = self->outBufs->numBufs;
691 self->inBufs->descs[0].bufSize.bytes = 0;
692 self->inBufs->numBufs = 0;
693 self->inArgs->numBytes = 0;
694 self->inArgs->inputID = 0;
695 self->outBufs->numBufs = 0;
697 do {
698 err = codec_process (self, eos, TRUE, NULL);
699 } while (err != XDM_EFAIL);
701 /* We flushed the decoder, we can now remove the buffer that have never been
702 * unrefed in it */
703 g_hash_table_remove_all (self->passed_in_bufs);
705 /* reset outArgs in case we're flushing in codec_process trying to do error
706 * recovery */
707 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
708 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
710 self->dynParams->newFrameFlag = XDAS_TRUE;
712 /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
713 self->inBufs->numBufs = prev_num_in_bufs;
714 self->outBufs->numBufs = prev_num_out_bufs;
716 /* on a flush, it is normal (and not an error) for the last _process() call
717 * to return an error..
718 */
719 err = XDM_EOK;
721 out:
722 GST_PAD_STREAM_UNLOCK (self->sinkpad);
723 GST_DEBUG_OBJECT (self, "done");
725 return !err;
726 }
728 /* GstDucatiVidDec vmethod default implementations */
730 static gboolean
731 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
732 {
733 const GValue *codec_data;
734 gint w, h;
736 if (gst_structure_get_int (s, "width", &self->input_width) &&
737 gst_structure_get_int (s, "height", &self->input_height)) {
739 h = ALIGN2 (self->input_height, 4); /* round up to MB */
740 w = ALIGN2 (self->input_width, 4); /* round up to MB */
742 /* if we've already created codec, but the resolution has changed, we
743 * need to re-create the codec:
744 */
745 if (G_UNLIKELY (self->codec)) {
746 if ((h != self->height) || (w != self->width)) {
747 codec_delete (self);
748 }
749 }
751 self->width = w;
752 self->height = h;
754 codec_data = gst_structure_get_value (s, "codec_data");
756 if (codec_data) {
757 GstBuffer *buffer = gst_value_get_buffer (codec_data);
758 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
759 self->codec_data = gst_buffer_ref (buffer);
760 }
762 return TRUE;
763 }
765 return FALSE;
766 }
768 static gboolean
769 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
770 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
771 {
773 /* allocate params: */
774 self->params = dce_alloc (params_sz);
775 if (G_UNLIKELY (!self->params)) {
776 return FALSE;
777 }
778 self->params->size = params_sz;
779 self->params->maxFrameRate = 30000;
780 self->params->maxBitRate = 10000000;
782 self->params->dataEndianness = XDM_BYTE;
783 self->params->forceChromaFormat = XDM_YUV_420SP;
784 self->params->operatingMode = IVIDEO_DECODE_ONLY;
786 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
787 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
788 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
789 self->params->numInputDataUnits = 0;
790 self->params->numOutputDataUnits = 0;
792 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
793 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
794 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
795 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
797 /* allocate dynParams: */
798 self->dynParams = dce_alloc (dynparams_sz);
799 if (G_UNLIKELY (!self->dynParams)) {
800 return FALSE;
801 }
802 self->dynParams->size = dynparams_sz;
803 self->dynParams->decodeHeader = XDM_DECODE_AU;
804 self->dynParams->displayWidth = 0;
805 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
806 self->dynParams->newFrameFlag = XDAS_TRUE;
808 /* allocate status: */
809 self->status = dce_alloc (status_sz);
810 if (G_UNLIKELY (!self->status)) {
811 return FALSE;
812 }
813 memset (self->status, 0, status_sz);
814 self->status->size = status_sz;
816 /* allocate inBufs/outBufs: */
817 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
818 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
819 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
820 return FALSE;
821 }
823 /* allocate inArgs/outArgs: */
824 self->inArgs = dce_alloc (inargs_sz);
825 self->outArgs = dce_alloc (outargs_sz);
826 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
827 return FALSE;
828 }
829 self->inArgs->size = inargs_sz;
830 self->outArgs->size = outargs_sz;
832 return TRUE;
833 }
835 static GstBuffer *
836 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
837 {
838 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
839 push_input (self, GST_BUFFER_DATA (self->codec_data),
840 GST_BUFFER_SIZE (self->codec_data));
841 }
843 /* just copy entire buffer */
844 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
845 gst_buffer_unref (buf);
847 return NULL;
848 }
850 static GstFlowReturn
851 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
852 {
853 GstFlowReturn ret = GST_FLOW_OK;
855 if (self->segment.format == GST_FORMAT_TIME &&
856 self->segment.rate < (gdouble) 0.0) {
857 /* negative rate: reverse playback */
859 if (self->backlog_nframes > 0 &&
860 (GST_BUFFER_TIMESTAMP (self->backlog_frames[0]) >
861 GST_BUFFER_TIMESTAMP (buf))) {
862 /* push out all backlog frames, since we have a buffer that is
863 earlier than any other in the list */
864 while (self->backlog_nframes > 0) {
865 ret = gst_ducati_viddec_push_latest (self);
866 if (ret != GST_FLOW_OK)
867 break;
868 }
869 }
870 /* add the frame to the list, the array will own the ref */
871 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
872 buf);
873 if (self->backlog_nframes < MAX_BACKLOG_ARRAY_SIZE) {
874 self->backlog_frames[self->backlog_nframes++] = buf;
875 } else {
876 /* No space in the re-order buffer, drop the frame */
877 GST_WARNING_OBJECT (self, "Dropping buffer %" GST_PTR_FORMAT, buf);
878 gst_buffer_unref (buf);
879 }
881 } else {
882 /* if no reordering info was set, just send the buffer */
883 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
884 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
885 return gst_pad_push (self->srcpad, buf);
886 }
888 /* add the frame to the list, the array will own the ref */
889 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog",
890 buf);
891 self->backlog_frames[self->backlog_nframes++] = buf;
893 /* push till we have no more than the max needed, or error */
894 while (self->backlog_nframes > self->backlog_maxframes) {
895 ret = gst_ducati_viddec_push_earliest (self);
896 if (ret != GST_FLOW_OK)
897 break;
898 }
899 }
900 return ret;
901 }
903 static gint
904 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
905 gint extended_error, gint status_extended_error)
906 {
907 if (XDM_ISFATALERROR (extended_error))
908 ret = XDM_EFAIL;
909 else
910 ret = XDM_EOK;
912 return ret;
913 }
915 /* GstElement vmethod implementations */
917 static gboolean
918 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
919 {
920 gboolean ret = TRUE;
921 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
922 GstStructure *s;
923 GstCaps *outcaps = NULL;
924 GstStructure *out_s;
925 gint par_width, par_height;
926 gboolean par_present;
928 s = gst_caps_get_structure (caps, 0);
929 if (!klass->parse_caps (self, s)) {
930 GST_WARNING_OBJECT (self, "missing required fields");
931 ret = FALSE;
932 goto out;
933 }
935 /* update output/padded sizes */
936 klass->update_buffer_size (self);
938 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
939 self->fps_n = 0;
940 self->fps_d = 1;
941 }
942 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
943 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
944 &par_width, &par_height);
946 outcaps = gst_pad_get_allowed_caps (self->srcpad);
947 if (outcaps) {
948 outcaps = gst_caps_make_writable (outcaps);
949 gst_caps_truncate (outcaps);
950 if (gst_caps_is_empty (outcaps)) {
951 gst_caps_unref (outcaps);
952 outcaps = NULL;
953 }
954 }
956 if (!outcaps) {
957 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
958 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
959 }
961 out_s = gst_caps_get_structure (outcaps, 0);
962 gst_structure_set (out_s,
963 "width", G_TYPE_INT, self->padded_width,
964 "height", G_TYPE_INT, self->padded_height,
965 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
966 if (par_present)
967 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
968 par_width, par_height, NULL);
970 if (self->interlaced)
971 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
973 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
974 0, self->padded_width);
976 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
977 self->stride, self->padded_height);
979 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
980 self->outsize, self->stride, outcaps);
982 if (!self->first_in_buffer) {
983 /* Caps changed mid stream. We flush the codec to unlock all the potentially
984 * locked buffers. This is needed for downstream sinks that provide a
985 * buffer pool and need to destroy all the outstanding buffers before they
986 * can negotiate new caps (hello v4l2sink).
987 */
988 gst_ducati_viddec_codec_flush (self, FALSE);
989 }
991 /* (re)send a crop event when caps change */
992 self->send_crop_event = TRUE;
994 ret = gst_pad_set_caps (self->srcpad, outcaps);
996 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
998 /* default to no reordering */
999 self->backlog_maxframes = 0;
1001 out:
1002 if (outcaps)
1003 gst_caps_unref (outcaps);
1005 return ret;
1006 }
1008 static gboolean
1009 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
1010 {
1011 gboolean ret = TRUE;
1012 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
1013 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1015 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
1017 ret = klass->set_sink_caps (self, caps);
1019 gst_object_unref (self);
1021 return ret;
1022 }
1024 static GstCaps *
1025 gst_ducati_viddec_src_getcaps (GstPad * pad)
1026 {
1027 GstCaps *caps = NULL;
1029 caps = GST_PAD_CAPS (pad);
1030 if (caps == NULL) {
1031 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
1032 } else {
1033 return gst_caps_copy (caps);
1034 }
1035 }
1037 static gboolean
1038 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
1039 GstQuery * query, gboolean * forward)
1040 {
1041 gboolean res = TRUE;
1043 switch (GST_QUERY_TYPE (query)) {
1044 case GST_QUERY_BUFFERS:
1045 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
1046 gst_query_set_buffers_count (query, self->min_buffers);
1048 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
1049 self->padded_width, self->padded_height);
1050 gst_query_set_buffers_dimensions (query,
1051 self->padded_width, self->padded_height);
1052 *forward = FALSE;
1053 break;
1054 case GST_QUERY_LATENCY:
1055 {
1056 gboolean live;
1057 GstClockTime min, max, latency;
1059 if (self->fps_d == 0) {
1060 GST_INFO_OBJECT (self, "not ready to report latency");
1061 res = FALSE;
1062 break;
1063 }
1065 gst_query_parse_latency (query, &live, &min, &max);
1066 if (self->fps_n != 0)
1067 latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
1068 else
1069 latency = 0;
1071 /* Take into account the backlog frames for reordering */
1072 latency *= (self->backlog_maxframes + 1);
1074 if (min == GST_CLOCK_TIME_NONE)
1075 min = latency;
1076 else
1077 min += latency;
1079 if (max != GST_CLOCK_TIME_NONE)
1080 max += latency;
1082 GST_INFO_OBJECT (self,
1083 "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1084 GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1085 gst_query_set_latency (query, live, min, max);
1086 break;
1087 }
1088 default:
1089 break;
1090 }
1093 return res;
1094 }
1096 static gboolean
1097 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
1098 {
1099 gboolean res = TRUE, forward = TRUE;
1100 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1101 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1103 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1104 res = klass->query (self, pad, query, &forward);
1105 if (res && forward)
1106 res = gst_pad_query_default (pad, query);
1108 return res;
1109 }
1111 static gboolean
1112 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1113 {
1114 GstClockTime timestamp, qostime;
1115 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1116 gint64 diff;
1118 if (self->wait_keyframe) {
1119 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1120 GST_INFO_OBJECT (self, "skipping until the next keyframe");
1121 return FALSE;
1122 }
1124 self->wait_keyframe = FALSE;
1125 }
1127 timestamp = GST_BUFFER_TIMESTAMP (buf);
1128 if (self->segment.format != GST_FORMAT_TIME ||
1129 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1130 goto no_qos;
1132 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1133 goto no_qos;
1135 qostime = gst_segment_to_running_time (&self->segment,
1136 GST_FORMAT_TIME, timestamp);
1137 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1138 /* out of segment */
1139 goto no_qos;
1141 /* see how our next timestamp relates to the latest qos timestamp. negative
1142 * values mean we are early, positive values mean we are too late. */
1143 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1145 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1146 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1147 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1148 self->qos_proportion);
1150 if (klass->can_drop_frame (self, buf, diff)) {
1151 GST_INFO_OBJECT (self, "dropping frame");
1152 return FALSE;
1153 }
1155 no_qos:
1156 return TRUE;
1157 }
1159 static gboolean
1160 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1161 gint64 diff)
1162 {
1163 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1164 GST_BUFFER_FLAG_DELTA_UNIT);
1166 if (diff >= 0 && !is_keyframe)
1167 return TRUE;
1169 return FALSE;
1170 }
1172 static GstFlowReturn
1173 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1174 {
1175 SizeT fd;
1177 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1178 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1179 GstFlowReturn ret = GST_FLOW_OK;
1180 Int32 err;
1181 GstBuffer *outbuf = NULL;
1182 GstCaps *outcaps = NULL;
1183 gboolean decode;
1185 normal:
1186 if (G_UNLIKELY (!self->engine)) {
1187 GST_ERROR_OBJECT (self, "no engine");
1188 gst_buffer_unref (buf);
1189 return GST_FLOW_ERROR;
1190 }
1192 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1193 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1195 decode = gst_ducati_viddec_do_qos (self, buf);
1196 if (!decode) {
1197 gst_buffer_unref (buf);
1198 return GST_FLOW_OK;
1199 }
1201 if (!self->need_out_buf)
1202 goto have_out_buf;
1204 /* do this before creating codec to ensure reverse caps negotiation
1205 * happens first:
1206 */
1207 allocate_buffer:
1208 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1209 GST_PAD_CAPS (self->srcpad), &outbuf);
1210 if (ret != GST_FLOW_OK) {
1211 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1212 gst_flow_get_name (ret));
1213 gst_buffer_unref (buf);
1214 return ret;
1215 }
1217 outcaps = GST_BUFFER_CAPS (outbuf);
1218 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1219 GstStructure *s;
1221 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1222 GST_BUFFER_SIZE (outbuf));
1224 s = gst_caps_get_structure (outcaps, 0);
1225 gst_structure_get_int (s, "rowstride", &self->stride);
1226 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1227 self->stride, self->padded_height);
1229 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1230 self->outsize, self->stride, outcaps);
1232 gst_pad_set_caps (self->srcpad, outcaps);
1234 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1235 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1236 GST_BUFFER_SIZE (outbuf), self->outsize);
1237 gst_buffer_unref (outbuf);
1238 goto allocate_buffer;
1239 }
1240 }
1242 if (G_UNLIKELY (!self->codec)) {
1243 if (!codec_create (self)) {
1244 GST_ERROR_OBJECT (self, "could not create codec");
1245 gst_buffer_unref (buf);
1246 gst_buffer_unref (outbuf);
1247 return GST_FLOW_ERROR;
1248 }
1249 }
1251 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1252 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1254 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1255 * internal pool while self->first_out_buffer == TRUE in order to simplify
1256 * things in case we need to renegotiate */
1257 self->inArgs->inputID =
1258 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1259 if (!self->inArgs->inputID) {
1260 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1261 gst_buffer_unref (buf);
1262 return GST_FLOW_ERROR;
1263 }
1264 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1266 have_out_buf:
1267 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1269 #ifdef USE_DTS_PTS_CODE
1270 if (ts != GST_CLOCK_TIME_NONE) {
1271 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1272 /* if next buffer has earlier ts than previous, then the ts
1273 * we are getting are definitely decode order (DTS):
1274 */
1275 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1276 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1277 self->ts_may_be_pts = FALSE;
1278 }
1279 self->last_dts = ts;
1280 }
1281 #endif
1283 if (self->in_size == 0 && outbuf) {
1284 GST_DEBUG_OBJECT (self, "no input, skipping process");
1286 gst_buffer_unref (outbuf);
1287 return GST_FLOW_OK;
1288 }
1290 self->inArgs->numBytes = self->in_size;
1291 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1292 /* XDM_MemoryType required by drm to allcoate buffer */
1293 self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1295 err = codec_process (self, TRUE, FALSE, &ret);
1296 if (err) {
1297 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1298 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1299 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1300 self->error_strings);
1302 return GST_FLOW_ERROR;
1303 }
1305 if (ret != GST_FLOW_OK) {
1306 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1307 gst_flow_get_name (ret));
1309 return ret;
1310 }
1312 self->first_in_buffer = FALSE;
1314 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1315 /* The copy could be avoided by playing with the buffer pointer,
1316 but it seems to be rare and for not many bytes */
1317 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1318 self->outArgs->bytesConsumed, self->in_size,
1319 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1320 if (self->outArgs->bytesConsumed > 0) {
1321 if (self->outArgs->bytesConsumed > self->in_size) {
1322 GST_WARNING_OBJECT (self,
1323 "Codec claims to have used more bytes than supplied");
1324 self->in_size = 0;
1325 } else {
1326 if (self->outArgs->bytesConsumed < self->in_size) {
1327 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1328 self->in_size - self->outArgs->bytesConsumed);
1329 }
1330 self->in_size -= self->outArgs->bytesConsumed;
1331 }
1332 }
1333 } else {
1334 self->in_size = 0;
1335 }
1337 if (self->outArgs->outBufsInUseFlag) {
1338 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1339 self->need_out_buf = FALSE;
1340 } else {
1341 self->need_out_buf = TRUE;
1342 }
1344 if (buf) {
1345 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1346 GST_BUFFER_SIZE (buf));
1347 ts = GST_BUFFER_TIMESTAMP (buf);
1348 goto allocate_buffer;
1349 }
1351 if (self->needs_flushing)
1352 gst_ducati_viddec_codec_flush (self, FALSE);
1354 return GST_FLOW_OK;
1355 }
1357 static gboolean
1358 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1359 {
1360 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1361 gboolean ret = TRUE;
1363 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1365 switch (GST_EVENT_TYPE (event)) {
1366 case GST_EVENT_NEWSEGMENT:
1367 {
1368 gboolean update;
1369 GstFormat fmt;
1370 gint64 start, stop, time;
1371 gdouble rate, arate;
1373 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1374 &start, &stop, &time);
1375 gst_segment_set_newsegment_full (&self->segment, update,
1376 rate, arate, fmt, start, stop, time);
1377 break;
1378 }
1379 case GST_EVENT_EOS:
1380 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1381 GST_ERROR_OBJECT (self, "could not flush on eos");
1382 ret = FALSE;
1383 }
1384 break;
1385 case GST_EVENT_FLUSH_STOP:
1386 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1387 GST_ERROR_OBJECT (self, "could not flush");
1388 gst_event_unref (event);
1389 ret = FALSE;
1390 }
1391 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1392 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1393 self->qos_proportion = 1;
1394 self->need_out_buf = TRUE;
1395 break;
1396 default:
1397 break;
1398 }
1400 if (ret)
1401 ret = gst_pad_push_event (self->srcpad, event);
1402 GST_LOG_OBJECT (self, "end");
1404 return ret;
1405 }
1407 static gboolean
1408 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1409 {
1410 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1411 gboolean ret = TRUE;
1413 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1415 switch (GST_EVENT_TYPE (event)) {
1416 case GST_EVENT_QOS:
1417 {
1418 gdouble proportion;
1419 GstClockTimeDiff diff;
1420 GstClockTime timestamp;
1422 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1424 GST_OBJECT_LOCK (self);
1425 self->qos_proportion = proportion;
1426 self->qos_earliest_time = timestamp + 2 * diff;
1427 GST_OBJECT_UNLOCK (self);
1429 GST_DEBUG_OBJECT (self,
1430 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1431 proportion, GST_TIME_ARGS (timestamp), diff);
1433 ret = gst_pad_push_event (self->sinkpad, event);
1434 break;
1435 }
1436 default:
1437 ret = gst_pad_push_event (self->sinkpad, event);
1438 break;
1439 }
1441 GST_LOG_OBJECT (self, "end");
1443 return ret;
1444 }
1446 static GstStateChangeReturn
1447 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1448 {
1449 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1450 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1451 gboolean supported;
1453 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1454 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1455 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1457 switch (transition) {
1458 case GST_STATE_CHANGE_NULL_TO_READY:
1459 if (!engine_open (self)) {
1460 GST_ERROR_OBJECT (self, "could not open");
1461 return GST_STATE_CHANGE_FAILURE;
1462 }
1463 /* try to create/destroy the codec here, it may not be supported */
1464 supported = codec_create (self);
1465 codec_delete (self);
1466 self->codec = NULL;
1467 if (!supported) {
1468 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1469 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1470 engine_close (self);
1471 return GST_STATE_CHANGE_FAILURE;
1472 }
1473 break;
1474 default:
1475 break;
1476 }
1478 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1480 if (ret == GST_STATE_CHANGE_FAILURE)
1481 goto leave;
1483 switch (transition) {
1484 case GST_STATE_CHANGE_PAUSED_TO_READY:
1485 self->interlaced = FALSE;
1486 self->send_crop_event = TRUE;
1487 gst_ducati_viddec_codec_flush (self, FALSE);
1488 break;
1489 case GST_STATE_CHANGE_READY_TO_NULL:
1490 codec_delete (self);
1491 engine_close (self);
1492 break;
1493 default:
1494 break;
1495 }
1497 leave:
1498 GST_LOG_OBJECT (self, "end");
1500 return ret;
1501 }
1503 /* GObject vmethod implementations */
1506 static void
1507 gst_ducati_viddec_get_property (GObject * obj,
1508 guint prop_id, GValue * value, GParamSpec * pspec)
1509 {
1510 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1513 switch (prop_id) {
1514 case PROP_VERSION:{
1515 int err;
1516 char *version = NULL;
1518 if (!self->engine)
1519 engine_open (self);
1521 if (!self->codec)
1522 codec_create (self);
1524 if (self->codec) {
1525 version = dce_alloc (VERSION_LENGTH);
1526 if (version) {
1527 self->status->data.buf = (XDAS_Int8 *) version;
1528 self->status->data.bufSize = VERSION_LENGTH;
1530 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1531 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1532 self->dynParams, self->status);
1534 if (err) {
1535 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1536 } else
1537 GST_DEBUG ("Codec version %s", self->status->data.buf);
1539 self->status->data.buf = NULL;
1540 self->status->data.bufSize = 0;
1541 dce_free (version);
1542 }
1543 }
1544 break;
1545 }
1546 case PROP_MAX_REORDER_FRAMES:
1547 g_value_set_int (value, self->backlog_max_maxframes);
1548 break;
1549 case PROP_CODEC_DEBUG_INFO:
1550 g_value_set_boolean (value, self->codec_debug_info);
1551 break;
1552 default:{
1553 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1554 break;
1555 }
1556 }
1557 }
1559 static void
1560 gst_ducati_viddec_set_property (GObject * obj,
1561 guint prop_id, const GValue * value, GParamSpec * pspec)
1562 {
1563 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1565 switch (prop_id) {
1566 case PROP_MAX_REORDER_FRAMES:
1567 self->backlog_max_maxframes = g_value_get_int (value);
1568 break;
1569 case PROP_CODEC_DEBUG_INFO:
1570 self->codec_debug_info = g_value_get_boolean (value);
1571 break;
1572 default:{
1573 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1574 break;
1575 }
1576 }
1577 }
1579 static void
1580 gst_ducati_viddec_finalize (GObject * obj)
1581 {
1582 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1584 codec_delete (self);
1585 engine_close (self);
1587 /* Will unref the remaining buffers if needed */
1588 g_hash_table_unref (self->passed_in_bufs);
1589 if (self->codec_data) {
1590 gst_buffer_unref (self->codec_data);
1591 self->codec_data = NULL;
1592 }
1594 G_OBJECT_CLASS (parent_class)->finalize (obj);
1595 }
1597 static void
1598 gst_ducati_viddec_base_init (gpointer gclass)
1599 {
1600 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1602 gst_element_class_add_pad_template (element_class,
1603 gst_static_pad_template_get (&src_factory));
1604 }
1606 static void
1607 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1608 {
1609 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1610 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1612 gobject_class->get_property =
1613 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1614 gobject_class->set_property =
1615 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1616 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1617 gstelement_class->change_state =
1618 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1620 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1621 klass->allocate_params =
1622 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1623 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1624 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1625 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1626 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1627 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1628 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1629 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1631 g_object_class_install_property (gobject_class, PROP_VERSION,
1632 g_param_spec_string ("version", "Version",
1633 "The codec version string", "",
1634 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1636 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1637 g_param_spec_int ("max-reorder-frames",
1638 "Maximum number of frames needed for reordering",
1639 "The maximum number of frames needed for reordering output frames. "
1640 "Only meaningful for codecs with B frames. 0 means no reordering. "
1641 "This value will be used if the correct value cannot be inferred "
1642 "from the stream. Too low a value may cause misordering, too high "
1643 "will cause extra latency.",
1644 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1645 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1647 g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1648 g_param_spec_boolean ("codec-debug-info",
1649 "Gather debug info from the codec",
1650 "Gather and log relevant debug information from the codec. "
1651 "What is gathered is typically codec specific", FALSE,
1652 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1653 }
1655 static void
1656 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1657 {
1658 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1660 gst_ducati_set_generic_error_strings (self->error_strings);
1662 self->sinkpad =
1663 gst_pad_new_from_template (gst_element_class_get_pad_template
1664 (gstelement_class, "sink"), "sink");
1665 gst_pad_set_setcaps_function (self->sinkpad,
1666 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1667 gst_pad_set_chain_function (self->sinkpad,
1668 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1669 gst_pad_set_event_function (self->sinkpad,
1670 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1672 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1673 gst_pad_set_event_function (self->srcpad,
1674 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1675 gst_pad_set_query_function (self->srcpad,
1676 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1677 gst_pad_set_getcaps_function (self->srcpad,
1678 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1680 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1681 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1683 self->input_width = 0;
1684 self->input_height = 0;
1685 /* sane defaults in case we need to create codec without caps negotiation
1686 * (for example, to get 'version' property)
1687 */
1688 self->width = 128;
1689 self->height = 128;
1690 self->fps_n = -1;
1691 self->fps_d = -1;
1693 self->first_in_buffer = TRUE;
1694 self->first_out_buffer = FALSE;
1695 self->interlaced = FALSE;
1696 self->send_crop_event = TRUE;
1698 #ifdef USE_DTS_PTS_CODE
1699 self->dts_ridx = self->dts_widx = 0;
1700 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1701 self->ts_may_be_pts = TRUE;
1702 self->ts_is_pts = FALSE;
1703 #endif
1705 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1707 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1709 self->qos_proportion = 1;
1710 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1711 self->wait_keyframe = TRUE;
1713 self->need_out_buf = TRUE;
1714 self->device = NULL;
1715 self->input_bo = NULL;
1717 self->backlog_maxframes = 0;
1718 self->backlog_nframes = 0;
1719 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1721 self->codec_debug_info = FALSE;
1723 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1724 NULL, (GDestroyNotify) gst_buffer_unref);
1725 }