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