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 = 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 if (self->inArgs->inputID != 0) {
406 /* Get dmabuf fd of the buffer to lock it*/
407 fd = gst_dma_buf_get_fd(gst_buffer_get_dma_buf((GstBuffer *) self->inArgs->inputID));
408 /* Must lock all the buffer passed to ducati */
409 dce_buf_lock(1,&fd);
410 }
412 GST_DEBUG ("Calling VIDDEC3_process");
413 t = gst_util_get_timestamp ();
414 err = VIDDEC3_process (self->codec,
415 self->inBufs, self->outBufs, self->inArgs, self->outArgs);
416 t = gst_util_get_timestamp () - t;
417 GST_DEBUG_OBJECT (self, "VIDDEC3_process took %10dns (%d ms)", (gint) t,
418 (gint) (t / 1000000));
420 if (err) {
421 GST_WARNING_OBJECT (self, "err=%d, extendedError=%08x",
422 err, self->outArgs->extendedError);
423 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
424 self->error_strings);
426 GST_DEBUG ("Calling VIDDEC3_control XDM_GETSTATUS");
427 err = VIDDEC3_control (self->codec, XDM_GETSTATUS,
428 self->dynParams, self->status);
429 if (err) {
430 GST_WARNING_OBJECT (self, "XDM_GETSTATUS: err=%d, extendedError=%08x",
431 err, self->status->extendedError);
432 gst_ducati_log_extended_error_info (self->status->extendedError,
433 self->error_strings);
434 }
436 if (flush)
437 err = XDM_EFAIL;
438 else
439 err = klass->handle_error (self, err,
440 self->outArgs->extendedError, self->status->extendedError);
441 }
443 /* we now let the codec decide */
444 self->dynParams->newFrameFlag = XDAS_FALSE;
446 if (err == XDM_EFAIL)
447 goto skip_outbuf_processing;
449 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->outputID[i]; i++) {
450 gboolean interlaced;
452 /* Getting an extra reference for the decoder */
453 outbuf = codec_get_outbuf (self, self->outArgs->outputID[i]);
454 interlaced =
455 self->outArgs->decodedBufs.contentType ==
456 IVIDEO_PROGRESSIVE ? FALSE : TRUE;
458 /* if send is FALSE, don't try to renegotiate as we could be flushing during
459 * a PAUSED->READY state change
460 */
461 if (send && interlaced != self->interlaced) {
462 GstCaps *caps;
464 GST_WARNING_OBJECT (self, "upstream set interlaced=%d but codec "
465 "thinks interlaced=%d... trusting codec", self->interlaced,
466 interlaced);
468 self->interlaced = interlaced;
470 caps =
471 gst_caps_make_writable (gst_pad_get_negotiated_caps (self->srcpad));
472 GST_INFO_OBJECT (self, "changing interlace field in caps");
473 gst_caps_set_simple (caps, "interlaced", G_TYPE_BOOLEAN, interlaced,
474 NULL);
475 gst_drm_buffer_pool_set_caps (self->pool, caps);
476 if (!gst_pad_set_caps (self->srcpad, caps)) {
477 GST_ERROR_OBJECT (self,
478 "downstream didn't want to change interlace mode");
479 err = XDM_EFAIL;
480 }
481 gst_caps_unref (caps);
483 /* this buffer still has the old caps so we skip it */
484 send = FALSE;
485 }
487 if (G_UNLIKELY (self->send_crop_event) && send) {
488 gint crop_width, crop_height;
490 /* send region of interest to sink on first buffer: */
491 XDM_Rect *r = &(self->outArgs->displayBufs.bufDesc[0].activeFrameRegion);
493 crop_width = r->bottomRight.x - r->topLeft.x;
494 crop_height = r->bottomRight.y - r->topLeft.y;
496 if (crop_width > self->input_width)
497 crop_width = self->input_width;
498 if (crop_height > self->input_height)
499 crop_height = self->input_height;
501 GST_INFO_OBJECT (self, "active frame region %d, %d, %d, %d, crop %dx%d",
502 r->topLeft.x, r->topLeft.y, r->bottomRight.x, r->bottomRight.y,
503 crop_width, crop_height);
505 gst_pad_push_event (self->srcpad,
506 gst_event_new_crop (r->topLeft.y, r->topLeft.x,
507 crop_width, crop_height));
509 if (self->crop)
510 gst_video_crop_unref (self->crop);
512 self->crop = gst_video_crop_new (r->topLeft.y, r->topLeft.x,
513 crop_width, crop_height);
515 self->send_crop_event = FALSE;
516 }
518 if (G_UNLIKELY (self->first_out_buffer) && send) {
519 GstDRMBufferPool *pool;
520 self->first_out_buffer = FALSE;
522 /* Destroy the pool so the buffers we used so far are eventually released.
523 * The pool will be recreated if needed.
524 */
525 pool = self->pool;
526 self->pool = NULL;
527 gst_drm_buffer_pool_destroy (pool);
528 }
530 if (send) {
531 GstClockTime ts;
533 ts = GST_BUFFER_TIMESTAMP (outbuf);
535 GST_DEBUG_OBJECT (self, "got buffer: %d %p (%" GST_TIME_FORMAT ")",
536 i, outbuf, GST_TIME_ARGS (ts));
538 #ifdef USE_DTS_PTS_CODE
539 if (self->ts_may_be_pts) {
540 if ((self->last_pts != GST_CLOCK_TIME_NONE) && (self->last_pts > ts)) {
541 GST_DEBUG_OBJECT (self, "detected PTS going backwards, "
542 "enabling ts_is_pts");
543 self->ts_is_pts = TRUE;
544 }
545 }
546 #endif
548 self->last_pts = ts;
550 if (self->dts_ridx != self->dts_widx) {
551 ts = self->dts_queue[self->dts_ridx++ % NDTS];
552 }
554 if (self->ts_is_pts) {
555 /* if we have a queued DTS from demuxer, use that instead: */
556 GST_BUFFER_TIMESTAMP (outbuf) = ts;
557 GST_DEBUG_OBJECT (self, "fixed ts: %d %p (%" GST_TIME_FORMAT ")",
558 i, outbuf, GST_TIME_ARGS (ts));
559 }
561 if (GST_BUFFER_CAPS (outbuf) &&
562 !gst_caps_is_equal (GST_BUFFER_CAPS (outbuf),
563 GST_PAD_CAPS (self->srcpad))) {
564 /* this looks a bit scary but it's really just to change the interlace=
565 * field in caps when we start as !interlaced and the codec detects
566 * otherwise */
567 GST_WARNING_OBJECT (self, "overriding buffer caps to fix "
568 "interlace mismatch");
569 outbuf = gst_buffer_make_metadata_writable (outbuf);
570 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (self->srcpad));
571 }
573 if (self->crop)
574 gst_buffer_set_video_crop (outbuf, self->crop);
576 ret = klass->push_output (self, outbuf);
577 if (flow_ret)
578 *flow_ret = ret;
579 if (ret != GST_FLOW_OK) {
580 GST_WARNING_OBJECT (self, "push failed %s", gst_flow_get_name (ret));
581 /* just unref the remaining buffers (if any) */
582 send = FALSE;
583 }
584 } else {
585 GST_DEBUG_OBJECT (self, "Buffer not pushed, dropping 'chain' ref: %d %p",
586 i, outbuf);
588 gst_buffer_unref (outbuf);
589 }
590 }
592 skip_outbuf_processing:
593 for (i = 0; i < IVIDEO2_MAX_IO_BUFFERS && self->outArgs->freeBufID[i]; i++) {
594 codec_unlock_outbuf (self, self->outArgs->freeBufID[i]);
595 }
597 return err;
598 }
600 /** call control(FLUSH), and then process() to pop out all buffers */
601 gboolean
602 gst_ducati_viddec_codec_flush (GstDucatiVidDec * self, gboolean eos)
603 {
604 gint err = FALSE;
605 int prev_num_in_bufs, prev_num_out_bufs;
607 GST_DEBUG_OBJECT (self, "flush: eos=%d", eos);
609 GST_DUCATIVIDDEC_GET_CLASS (self)->on_flush (self, eos);
611 /* note: flush is synchronized against _chain() to avoid calling
612 * the codec from multiple threads
613 */
614 GST_PAD_STREAM_LOCK (self->sinkpad);
616 #ifdef USE_DTS_PTS_CODE
617 self->dts_ridx = self->dts_widx = 0;
618 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
619 self->ts_may_be_pts = TRUE;
620 self->ts_is_pts = FALSE;
621 #endif
622 self->wait_keyframe = TRUE;
623 self->in_size = 0;
624 self->needs_flushing = FALSE;
625 self->need_out_buf = TRUE;
627 if (G_UNLIKELY (self->first_in_buffer)) {
628 goto out;
629 }
631 if (G_UNLIKELY (!self->codec)) {
632 GST_WARNING_OBJECT (self, "no codec");
633 goto out;
634 }
637 GST_DEBUG ("Calling VIDDEC3_control XDM_FLUSH");
638 err = VIDDEC3_control (self->codec, XDM_FLUSH, self->dynParams, self->status);
639 if (err) {
640 GST_ERROR_OBJECT (self, "failed XDM_FLUSH");
641 goto out;
642 }
644 prev_num_in_bufs = self->inBufs->numBufs;
645 prev_num_out_bufs = self->outBufs->numBufs;
647 self->inBufs->descs[0].bufSize.bytes = 0;
648 self->inBufs->numBufs = 0;
649 self->inArgs->numBytes = 0;
650 self->inArgs->inputID = 0;
651 self->outBufs->numBufs = 0;
653 do {
654 err = codec_process (self, eos, TRUE, NULL);
655 } while (err != XDM_EFAIL);
657 /* We flushed the decoder, we can now remove the buffer that have never been
658 * unrefed in it */
659 g_hash_table_remove_all (self->passed_in_bufs);
661 /* reset outArgs in case we're flushing in codec_process trying to do error
662 * recovery */
663 memset (&self->outArgs->outputID, 0, sizeof (self->outArgs->outputID));
664 memset (&self->outArgs->freeBufID, 0, sizeof (self->outArgs->freeBufID));
666 self->dynParams->newFrameFlag = XDAS_TRUE;
668 /* Reset the push buffer and YUV buffers, plus any codec specific buffers */
669 self->inBufs->numBufs = prev_num_in_bufs;
670 self->outBufs->numBufs = prev_num_out_bufs;
672 /* on a flush, it is normal (and not an error) for the last _process() call
673 * to return an error..
674 */
675 err = XDM_EOK;
677 out:
678 GST_PAD_STREAM_UNLOCK (self->sinkpad);
679 GST_DEBUG_OBJECT (self, "done");
681 return !err;
682 }
684 /* GstDucatiVidDec vmethod default implementations */
686 static gboolean
687 gst_ducati_viddec_parse_caps (GstDucatiVidDec * self, GstStructure * s)
688 {
689 const GValue *codec_data;
690 gint w, h;
692 if (gst_structure_get_int (s, "width", &self->input_width) &&
693 gst_structure_get_int (s, "height", &self->input_height)) {
695 h = ALIGN2 (self->input_height, 4); /* round up to MB */
696 w = ALIGN2 (self->input_width, 4); /* round up to MB */
698 /* if we've already created codec, but the resolution has changed, we
699 * need to re-create the codec:
700 */
701 if (G_UNLIKELY (self->codec)) {
702 if ((h != self->height) || (w != self->width)) {
703 codec_delete (self);
704 }
705 }
707 self->width = w;
708 self->height = h;
710 codec_data = gst_structure_get_value (s, "codec_data");
712 if (codec_data) {
713 GstBuffer *buffer = gst_value_get_buffer (codec_data);
714 GST_DEBUG_OBJECT (self, "codec_data: %" GST_PTR_FORMAT, buffer);
715 self->codec_data = gst_buffer_ref (buffer);
716 }
718 return TRUE;
719 }
721 return FALSE;
722 }
724 static gboolean
725 gst_ducati_viddec_allocate_params (GstDucatiVidDec * self, gint params_sz,
726 gint dynparams_sz, gint status_sz, gint inargs_sz, gint outargs_sz)
727 {
729 /* allocate params: */
730 self->params = dce_alloc (params_sz);
731 if (G_UNLIKELY (!self->params)) {
732 return FALSE;
733 }
734 self->params->size = params_sz;
735 self->params->maxFrameRate = 30000;
736 self->params->maxBitRate = 10000000;
738 self->params->dataEndianness = XDM_BYTE;
739 self->params->forceChromaFormat = XDM_YUV_420SP;
740 self->params->operatingMode = IVIDEO_DECODE_ONLY;
742 self->params->displayBufsMode = IVIDDEC3_DISPLAYBUFS_EMBEDDED;
743 self->params->inputDataMode = IVIDEO_ENTIREFRAME;
744 self->params->outputDataMode = IVIDEO_ENTIREFRAME;
745 self->params->numInputDataUnits = 0;
746 self->params->numOutputDataUnits = 0;
748 self->params->metadataType[0] = IVIDEO_METADATAPLANE_NONE;
749 self->params->metadataType[1] = IVIDEO_METADATAPLANE_NONE;
750 self->params->metadataType[2] = IVIDEO_METADATAPLANE_NONE;
751 self->params->errorInfoMode = IVIDEO_ERRORINFO_OFF;
753 /* allocate dynParams: */
754 self->dynParams = dce_alloc (dynparams_sz);
755 if (G_UNLIKELY (!self->dynParams)) {
756 return FALSE;
757 }
758 self->dynParams->size = dynparams_sz;
759 self->dynParams->decodeHeader = XDM_DECODE_AU;
760 self->dynParams->displayWidth = 0;
761 self->dynParams->frameSkipMode = IVIDEO_NO_SKIP;
762 self->dynParams->newFrameFlag = XDAS_TRUE;
764 /* allocate status: */
765 self->status = dce_alloc (status_sz);
766 if (G_UNLIKELY (!self->status)) {
767 return FALSE;
768 }
769 memset (self->status, 0, status_sz);
770 self->status->size = status_sz;
772 /* allocate inBufs/outBufs: */
773 self->inBufs = dce_alloc (sizeof (XDM2_BufDesc));
774 self->outBufs = dce_alloc (sizeof (XDM2_BufDesc));
775 if (G_UNLIKELY (!self->inBufs) || G_UNLIKELY (!self->outBufs)) {
776 return FALSE;
777 }
779 /* allocate inArgs/outArgs: */
780 self->inArgs = dce_alloc (inargs_sz);
781 self->outArgs = dce_alloc (outargs_sz);
782 if (G_UNLIKELY (!self->inArgs) || G_UNLIKELY (!self->outArgs)) {
783 return FALSE;
784 }
785 self->inArgs->size = inargs_sz;
786 self->outArgs->size = outargs_sz;
788 return TRUE;
789 }
791 static GstBuffer *
792 gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
793 {
794 if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
795 push_input (self, GST_BUFFER_DATA (self->codec_data),
796 GST_BUFFER_SIZE (self->codec_data));
797 }
799 /* just copy entire buffer */
800 push_input (self, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
801 gst_buffer_unref (buf);
803 return NULL;
804 }
806 static GstFlowReturn
807 gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
808 {
809 GstFlowReturn ret = GST_FLOW_OK;
811 /* if no reordering info was set, just send the buffer */
812 if (GST_BUFFER_OFFSET_END (buf) == GST_BUFFER_OFFSET_NONE) {
813 GST_DEBUG_OBJECT (self, "No reordering info on that buffer, sending now");
814 return gst_pad_push (self->srcpad, buf);
815 }
817 /* add the frame to the list, the array will own the ref */
818 GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
819 self->backlog_frames[self->backlog_nframes++] = buf;
821 /* push till we have no more than the max needed, or error */
822 while (self->backlog_nframes > self->backlog_maxframes) {
823 ret = gst_ducati_viddec_push_earliest (self);
824 if (ret != GST_FLOW_OK)
825 break;
826 }
828 return ret;
829 }
831 static gint
832 gst_ducati_viddec_handle_error (GstDucatiVidDec * self, gint ret,
833 gint extended_error, gint status_extended_error)
834 {
835 if (XDM_ISFATALERROR (extended_error))
836 ret = XDM_EFAIL;
837 else
838 ret = XDM_EOK;
840 return ret;
841 }
843 /* GstElement vmethod implementations */
845 static gboolean
846 gst_ducati_viddec_set_sink_caps (GstDucatiVidDec * self, GstCaps * caps)
847 {
848 gboolean ret = TRUE;
849 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
850 GstStructure *s;
851 GstCaps *outcaps = NULL;
852 GstStructure *out_s;
853 gint par_width, par_height;
854 gboolean par_present;
856 s = gst_caps_get_structure (caps, 0);
857 if (!klass->parse_caps (self, s)) {
858 GST_WARNING_OBJECT (self, "missing required fields");
859 ret = FALSE;
860 goto out;
861 }
863 /* update output/padded sizes */
864 klass->update_buffer_size (self);
866 if (!gst_structure_get_fraction (s, "framerate", &self->fps_n, &self->fps_d)) {
867 self->fps_n = 0;
868 self->fps_d = 1;
869 }
870 gst_structure_get_boolean (s, "interlaced", &self->interlaced);
871 par_present = gst_structure_get_fraction (s, "pixel-aspect-ratio",
872 &par_width, &par_height);
874 outcaps = gst_pad_get_allowed_caps (self->srcpad);
875 if (outcaps) {
876 outcaps = gst_caps_make_writable (outcaps);
877 gst_caps_truncate (outcaps);
878 if (gst_caps_is_empty (outcaps)) {
879 gst_caps_unref (outcaps);
880 outcaps = NULL;
881 }
882 }
884 if (!outcaps) {
885 outcaps = gst_caps_new_simple ("video/x-raw-yuv",
886 "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('N', 'V', '1', '2'), NULL);
887 }
889 out_s = gst_caps_get_structure (outcaps, 0);
890 gst_structure_set (out_s,
891 "width", G_TYPE_INT, self->padded_width,
892 "height", G_TYPE_INT, self->padded_height,
893 "framerate", GST_TYPE_FRACTION, self->fps_n, self->fps_d, NULL);
894 if (par_present)
895 gst_structure_set (out_s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
896 par_width, par_height, NULL);
898 if (self->interlaced)
899 gst_structure_set (out_s, "interlaced", G_TYPE_BOOLEAN, TRUE, NULL);
901 self->stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_NV12,
902 0, self->padded_width);
904 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
905 self->stride, self->padded_height);
907 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
908 self->outsize, self->stride, outcaps);
910 if (!self->first_in_buffer) {
911 /* Caps changed mid stream. We flush the codec to unlock all the potentially
912 * locked buffers. This is needed for downstream sinks that provide a
913 * buffer pool and need to destroy all the outstanding buffers before they
914 * can negotiate new caps (hello v4l2sink).
915 */
916 gst_ducati_viddec_codec_flush (self, FALSE);
917 }
919 /* (re)send a crop event when caps change */
920 self->send_crop_event = TRUE;
922 ret = gst_pad_set_caps (self->srcpad, outcaps);
924 GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
926 /* default to no reordering */
927 self->backlog_maxframes = 0;
929 out:
930 if (outcaps)
931 gst_caps_unref (outcaps);
933 return ret;
934 }
936 static gboolean
937 gst_ducati_viddec_sink_setcaps (GstPad * pad, GstCaps * caps)
938 {
939 gboolean ret = TRUE;
940 GstDucatiVidDec *self = GST_DUCATIVIDDEC (gst_pad_get_parent (pad));
941 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
943 GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
945 ret = klass->set_sink_caps (self, caps);
947 gst_object_unref (self);
949 return ret;
950 }
952 static GstCaps *
953 gst_ducati_viddec_src_getcaps (GstPad * pad)
954 {
955 GstCaps *caps = NULL;
957 caps = GST_PAD_CAPS (pad);
958 if (caps == NULL) {
959 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
960 } else {
961 return gst_caps_copy (caps);
962 }
963 }
965 static gboolean
966 gst_ducati_viddec_query (GstDucatiVidDec * self, GstPad * pad,
967 GstQuery * query, gboolean * forward)
968 {
969 gboolean res = TRUE;
971 switch (GST_QUERY_TYPE (query)) {
972 case GST_QUERY_BUFFERS:
973 GST_DEBUG_OBJECT (self, "min buffers: %d", self->min_buffers);
974 gst_query_set_buffers_count (query, self->min_buffers);
976 GST_DEBUG_OBJECT (self, "min dimensions: %dx%d",
977 self->padded_width, self->padded_height);
978 gst_query_set_buffers_dimensions (query,
979 self->padded_width, self->padded_height);
980 *forward = FALSE;
981 break;
982 case GST_QUERY_LATENCY:
983 {
984 gboolean live;
985 GstClockTime min, max, latency;
987 if (self->fps_d == 0) {
988 GST_INFO_OBJECT (self, "not ready to report latency");
989 res = FALSE;
990 break;
991 }
993 gst_query_parse_latency (query, &live, &min, &max);
994 if (self->fps_n != 0)
995 latency = gst_util_uint64_scale (GST_SECOND, self->fps_d, self->fps_n);
996 else
997 latency = 0;
999 /* Take into account the backlog frames for reordering */
1000 latency *= (self->backlog_maxframes + 1);
1002 if (min == GST_CLOCK_TIME_NONE)
1003 min = latency;
1004 else
1005 min += latency;
1007 if (max != GST_CLOCK_TIME_NONE)
1008 max += latency;
1010 GST_INFO_OBJECT (self,
1011 "latency %" GST_TIME_FORMAT " ours %" GST_TIME_FORMAT,
1012 GST_TIME_ARGS (min), GST_TIME_ARGS (latency));
1013 gst_query_set_latency (query, live, min, max);
1014 break;
1015 }
1016 default:
1017 break;
1018 }
1021 return res;
1022 }
1024 static gboolean
1025 gst_ducati_viddec_src_query (GstPad * pad, GstQuery * query)
1026 {
1027 gboolean res = TRUE, forward = TRUE;
1028 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1029 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1031 GST_DEBUG_OBJECT (self, "query: %" GST_PTR_FORMAT, query);
1032 res = klass->query (self, pad, query, &forward);
1033 if (res && forward)
1034 res = gst_pad_query_default (pad, query);
1036 return res;
1037 }
1039 static gboolean
1040 gst_ducati_viddec_do_qos (GstDucatiVidDec * self, GstBuffer * buf)
1041 {
1042 GstClockTime timestamp, qostime;
1043 GstDucatiVidDecClass *klass = GST_DUCATIVIDDEC_GET_CLASS (self);
1044 gint64 diff;
1046 if (self->wait_keyframe) {
1047 if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
1048 GST_INFO_OBJECT (self, "skipping until the next keyframe");
1049 return FALSE;
1050 }
1052 self->wait_keyframe = FALSE;
1053 }
1055 timestamp = GST_BUFFER_TIMESTAMP (buf);
1056 if (self->segment.format != GST_FORMAT_TIME ||
1057 self->qos_earliest_time == GST_CLOCK_TIME_NONE)
1058 goto no_qos;
1060 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
1061 goto no_qos;
1063 qostime = gst_segment_to_running_time (&self->segment,
1064 GST_FORMAT_TIME, timestamp);
1065 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (qostime)))
1066 /* out of segment */
1067 goto no_qos;
1069 /* see how our next timestamp relates to the latest qos timestamp. negative
1070 * values mean we are early, positive values mean we are too late. */
1071 diff = GST_CLOCK_DIFF (qostime, self->qos_earliest_time);
1073 GST_DEBUG_OBJECT (self, "QOS: qostime %" GST_TIME_FORMAT
1074 ", earliest %" GST_TIME_FORMAT " diff %" G_GINT64_FORMAT " proportion %f",
1075 GST_TIME_ARGS (qostime), GST_TIME_ARGS (self->qos_earliest_time), diff,
1076 self->qos_proportion);
1078 if (klass->can_drop_frame (self, buf, diff)) {
1079 GST_INFO_OBJECT (self, "dropping frame");
1080 return FALSE;
1081 }
1083 no_qos:
1084 return TRUE;
1085 }
1087 static gboolean
1088 gst_ducati_viddec_can_drop_frame (GstDucatiVidDec * self, GstBuffer * buf,
1089 gint64 diff)
1090 {
1091 gboolean is_keyframe = !GST_BUFFER_FLAG_IS_SET (buf,
1092 GST_BUFFER_FLAG_DELTA_UNIT);
1094 if (diff >= 0 && !is_keyframe)
1095 return TRUE;
1097 return FALSE;
1098 }
1100 GstElement *parser = NULL;
1102 static GstFlowReturn
1103 gst_ducati_viddec_chain (GstPad * pad, GstBuffer * buf)
1104 {
1105 GstElement *element = NULL;
1106 GstElement *pipe = NULL;
1107 GstPad *mypad = NULL;
1108 GstPad *peerpad = NULL;
1109 GstElement *peerelement = NULL;
1110 SizeT fd;
1112 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1113 GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
1114 GstFlowReturn ret = GST_FLOW_OK;
1115 Int32 err;
1116 GstBuffer *outbuf = NULL;
1117 GstCaps *outcaps = NULL;
1118 gboolean decode;
1120 element = gst_pad_get_parent_element (pad);
1121 pipe = GST_ELEMENT (gst_element_get_parent (element));
1122 mypad = gst_element_get_static_pad (element, "sink");
1123 peerpad = gst_pad_get_peer (mypad);
1124 peerelement = gst_pad_get_parent_element (peerpad);
1125 if (parser == NULL)
1126 {
1127 parser = gst_element_factory_make ("jpegparse", NULL);
1128 if (parser == NULL)
1129 {
1130 goto normal;
1131 }
1132 if (gst_bin_add (GST_BIN (pipe), parser) == FALSE)
1133 {
1134 gst_object_unref (parser);
1135 parser = NULL;
1136 goto normal;
1137 }
1138 gst_element_set_state (parser, GST_STATE_PAUSED);
1139 gst_element_unlink (peerelement, element);
1140 gst_element_link (parser, element);
1141 if (FALSE == gst_element_link (peerelement, parser))
1142 {
1143 gst_element_set_state (parser, GST_STATE_NULL);
1144 gst_element_unlink (parser, element);
1145 gst_element_link (peerelement, element);
1146 gst_bin_remove (GST_BIN (pipe), parser);
1147 goto normal;
1148 }
1149 gst_pad_chain (gst_element_get_static_pad (parser, "sink"), buf);
1150 return GST_FLOW_OK;
1151 }
1153 normal:
1154 if (G_UNLIKELY (!self->engine)) {
1155 GST_ERROR_OBJECT (self, "no engine");
1156 gst_buffer_unref (buf);
1157 return GST_FLOW_ERROR;
1158 }
1160 GST_DEBUG_OBJECT (self, "chain: %" GST_TIME_FORMAT " (%d bytes, flags %d)",
1161 GST_TIME_ARGS (ts), GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
1163 decode = gst_ducati_viddec_do_qos (self, buf);
1164 if (!decode) {
1165 gst_buffer_unref (buf);
1166 return GST_FLOW_OK;
1167 }
1169 if (!self->need_out_buf)
1170 goto have_out_buf;
1172 /* do this before creating codec to ensure reverse caps negotiation
1173 * happens first:
1174 */
1175 allocate_buffer:
1176 ret = gst_pad_alloc_buffer (self->srcpad, 0, self->outsize,
1177 GST_PAD_CAPS (self->srcpad), &outbuf);
1178 if (ret != GST_FLOW_OK) {
1179 GST_WARNING_OBJECT (self, "alloc_buffer failed %s",
1180 gst_flow_get_name (ret));
1181 gst_buffer_unref (buf);
1182 return ret;
1183 }
1185 outcaps = GST_BUFFER_CAPS (outbuf);
1186 if (outcaps && !gst_caps_is_equal (outcaps, GST_PAD_CAPS (self->srcpad))) {
1187 GstStructure *s;
1189 GST_INFO_OBJECT (self, "doing upstream negotiation bufsize %d",
1190 GST_BUFFER_SIZE (outbuf));
1192 s = gst_caps_get_structure (outcaps, 0);
1193 gst_structure_get_int (s, "rowstride", &self->stride);
1194 self->outsize = gst_video_format_get_size (GST_VIDEO_FORMAT_NV12,
1195 self->stride, self->padded_height);
1197 GST_INFO_OBJECT (self, "outsize %d stride %d outcaps: %" GST_PTR_FORMAT,
1198 self->outsize, self->stride, outcaps);
1200 gst_pad_set_caps (self->srcpad, outcaps);
1202 if (GST_BUFFER_SIZE (outbuf) != self->outsize) {
1203 GST_INFO_OBJECT (self, "dropping buffer (bufsize %d != outsize %d)",
1204 GST_BUFFER_SIZE (outbuf), self->outsize);
1205 gst_buffer_unref (outbuf);
1206 goto allocate_buffer;
1207 }
1208 }
1210 if (G_UNLIKELY (!self->codec)) {
1211 if (!codec_create (self)) {
1212 GST_ERROR_OBJECT (self, "could not create codec");
1213 gst_buffer_unref (buf);
1214 gst_buffer_unref (outbuf);
1215 return GST_FLOW_ERROR;
1216 }
1217 }
1219 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
1220 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
1222 /* Pass new output buffer to the decoder to decode into. Use buffers from the
1223 * internal pool while self->first_out_buffer == TRUE in order to simplify
1224 * things in case we need to renegotiate */
1225 self->inArgs->inputID =
1226 codec_prepare_outbuf (self, &outbuf, self->first_out_buffer);
1227 if (!self->inArgs->inputID) {
1228 GST_ERROR_OBJECT (self, "could not prepare output buffer");
1229 gst_buffer_unref (buf);
1230 return GST_FLOW_ERROR;
1231 }
1232 GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf);
1234 have_out_buf:
1235 buf = GST_DUCATIVIDDEC_GET_CLASS (self)->push_input (self, buf);
1237 #ifdef USE_DTS_PTS_CODE
1238 if (ts != GST_CLOCK_TIME_NONE) {
1239 self->dts_queue[self->dts_widx++ % NDTS] = ts;
1240 /* if next buffer has earlier ts than previous, then the ts
1241 * we are getting are definitely decode order (DTS):
1242 */
1243 if ((self->last_dts != GST_CLOCK_TIME_NONE) && (self->last_dts > ts)) {
1244 GST_DEBUG_OBJECT (self, "input timestamp definitely DTS");
1245 self->ts_may_be_pts = FALSE;
1246 }
1247 self->last_dts = ts;
1248 }
1249 #endif
1251 if (self->in_size == 0 && outbuf) {
1252 GST_DEBUG_OBJECT (self, "no input, skipping process");
1254 gst_buffer_unref (outbuf);
1255 return GST_FLOW_OK;
1256 }
1258 self->inArgs->numBytes = self->in_size;
1259 self->inBufs->descs[0].bufSize.bytes = self->in_size;
1260 /* XDM_MemoryType required by drm to allcoate buffer */
1261 self->inBufs->descs[0].memType = XDM_MEMTYPE_RAW;
1263 err = codec_process (self, TRUE, FALSE, &ret);
1264 if (err) {
1265 GST_ELEMENT_ERROR (self, STREAM, DECODE, (NULL),
1266 ("process returned error: %d %08x", err, self->outArgs->extendedError));
1267 gst_ducati_log_extended_error_info (self->outArgs->extendedError,
1268 self->error_strings);
1270 return GST_FLOW_ERROR;
1271 }
1273 if (ret != GST_FLOW_OK) {
1274 GST_WARNING_OBJECT (self, "push from codec_process failed %s",
1275 gst_flow_get_name (ret));
1277 return ret;
1278 }
1280 self->first_in_buffer = FALSE;
1282 if (self->params->inputDataMode != IVIDEO_ENTIREFRAME) {
1283 /* The copy could be avoided by playing with the buffer pointer,
1284 but it seems to be rare and for not many bytes */
1285 GST_DEBUG_OBJECT (self, "Consumed %d/%d (%d) bytes, %d left",
1286 self->outArgs->bytesConsumed, self->in_size,
1287 self->inArgs->numBytes, self->in_size - self->outArgs->bytesConsumed);
1288 if (self->outArgs->bytesConsumed > 0) {
1289 if (self->outArgs->bytesConsumed > self->in_size) {
1290 GST_WARNING_OBJECT (self,
1291 "Codec claims to have used more bytes than supplied");
1292 self->in_size = 0;
1293 } else {
1294 if (self->outArgs->bytesConsumed < self->in_size) {
1295 memmove (self->input, self->input + self->outArgs->bytesConsumed,
1296 self->in_size - self->outArgs->bytesConsumed);
1297 }
1298 self->in_size -= self->outArgs->bytesConsumed;
1299 }
1300 }
1301 } else {
1302 self->in_size = 0;
1303 }
1305 if (self->outArgs->outBufsInUseFlag) {
1306 GST_DEBUG_OBJECT (self, "outBufsInUseFlag set");
1307 self->need_out_buf = FALSE;
1308 } else {
1309 self->need_out_buf = TRUE;
1310 }
1312 if (buf) {
1313 GST_DEBUG_OBJECT (self, "found remaining data: %d bytes",
1314 GST_BUFFER_SIZE (buf));
1315 ts = GST_BUFFER_TIMESTAMP (buf);
1316 goto allocate_buffer;
1317 }
1319 if (self->needs_flushing)
1320 gst_ducati_viddec_codec_flush (self, FALSE);
1322 return GST_FLOW_OK;
1323 }
1325 static gboolean
1326 gst_ducati_viddec_event (GstPad * pad, GstEvent * event)
1327 {
1328 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1329 gboolean ret = TRUE;
1331 GST_DEBUG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1333 switch (GST_EVENT_TYPE (event)) {
1334 case GST_EVENT_NEWSEGMENT:
1335 {
1336 gboolean update;
1337 GstFormat fmt;
1338 gint64 start, stop, time;
1339 gdouble rate, arate;
1341 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
1342 &start, &stop, &time);
1343 gst_segment_set_newsegment_full (&self->segment, update,
1344 rate, arate, fmt, start, stop, time);
1345 break;
1346 }
1347 case GST_EVENT_EOS:
1348 if (!gst_ducati_viddec_codec_flush (self, TRUE)) {
1349 GST_ERROR_OBJECT (self, "could not flush on eos");
1350 ret = FALSE;
1351 }
1352 break;
1353 case GST_EVENT_FLUSH_STOP:
1354 if (!gst_ducati_viddec_codec_flush (self, FALSE)) {
1355 GST_ERROR_OBJECT (self, "could not flush");
1356 gst_event_unref (event);
1357 ret = FALSE;
1358 }
1359 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1360 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1361 self->qos_proportion = 1;
1362 self->need_out_buf = TRUE;
1363 break;
1364 default:
1365 break;
1366 }
1368 if (ret)
1369 ret = gst_pad_push_event (self->srcpad, event);
1370 GST_LOG_OBJECT (self, "end");
1372 return ret;
1373 }
1375 static gboolean
1376 gst_ducati_viddec_src_event (GstPad * pad, GstEvent * event)
1377 {
1378 GstDucatiVidDec *self = GST_DUCATIVIDDEC (GST_OBJECT_PARENT (pad));
1379 gboolean ret = TRUE;
1381 GST_LOG_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
1383 switch (GST_EVENT_TYPE (event)) {
1384 case GST_EVENT_QOS:
1385 {
1386 gdouble proportion;
1387 GstClockTimeDiff diff;
1388 GstClockTime timestamp;
1390 gst_event_parse_qos (event, &proportion, &diff, ×tamp);
1392 GST_OBJECT_LOCK (self);
1393 self->qos_proportion = proportion;
1394 self->qos_earliest_time = timestamp + 2 * diff;
1395 GST_OBJECT_UNLOCK (self);
1397 GST_DEBUG_OBJECT (self,
1398 "got QoS proportion %f %" GST_TIME_FORMAT ", %" G_GINT64_FORMAT,
1399 proportion, GST_TIME_ARGS (timestamp), diff);
1401 ret = gst_pad_push_event (self->sinkpad, event);
1402 break;
1403 }
1404 default:
1405 ret = gst_pad_push_event (self->sinkpad, event);
1406 break;
1407 }
1409 GST_LOG_OBJECT (self, "end");
1411 return ret;
1412 }
1414 static GstStateChangeReturn
1415 gst_ducati_viddec_change_state (GstElement * element, GstStateChange transition)
1416 {
1417 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1418 GstDucatiVidDec *self = GST_DUCATIVIDDEC (element);
1419 gboolean supported;
1421 GST_DEBUG_OBJECT (self, "begin: changing state %s -> %s",
1422 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
1423 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
1425 switch (transition) {
1426 case GST_STATE_CHANGE_NULL_TO_READY:
1427 if (!engine_open (self)) {
1428 GST_ERROR_OBJECT (self, "could not open");
1429 return GST_STATE_CHANGE_FAILURE;
1430 }
1431 /* try to create/destroy the codec here, it may not be supported */
1432 supported = codec_create (self);
1433 codec_delete (self);
1434 self->codec = NULL;
1435 if (!supported) {
1436 GST_ERROR_OBJECT (element, "Failed to create codec %s, not supported",
1437 GST_DUCATIVIDDEC_GET_CLASS (self)->codec_name);
1438 engine_close (self);
1439 return GST_STATE_CHANGE_FAILURE;
1440 }
1441 break;
1442 default:
1443 break;
1444 }
1446 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1448 if (ret == GST_STATE_CHANGE_FAILURE)
1449 goto leave;
1451 switch (transition) {
1452 case GST_STATE_CHANGE_PAUSED_TO_READY:
1453 self->interlaced = FALSE;
1454 self->send_crop_event = TRUE;
1455 gst_ducati_viddec_codec_flush (self, FALSE);
1456 break;
1457 case GST_STATE_CHANGE_READY_TO_NULL:
1458 codec_delete (self);
1459 engine_close (self);
1460 break;
1461 default:
1462 break;
1463 }
1465 leave:
1466 GST_LOG_OBJECT (self, "end");
1468 return ret;
1469 }
1471 /* GObject vmethod implementations */
1474 static void
1475 gst_ducati_viddec_get_property (GObject * obj,
1476 guint prop_id, GValue * value, GParamSpec * pspec)
1477 {
1478 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1481 switch (prop_id) {
1482 case PROP_VERSION:{
1483 int err;
1484 char *version = NULL;
1486 if (!self->engine)
1487 engine_open (self);
1489 if (!self->codec)
1490 codec_create (self);
1492 if (self->codec) {
1493 version = dce_alloc (VERSION_LENGTH);
1494 if (version) {
1495 self->status->data.buf = (XDAS_Int8 *) version;
1496 self->status->data.bufSize = VERSION_LENGTH;
1498 GST_DEBUG ("Calling VIDDEC3_control XDM_GETVERSION");
1499 err = VIDDEC3_control (self->codec, XDM_GETVERSION,
1500 self->dynParams, self->status);
1502 if (err) {
1503 GST_ERROR_OBJECT (self, "failed XDM_GETVERSION");
1504 } else
1505 GST_DEBUG ("Codec version %s", self->status->data.buf);
1507 self->status->data.buf = NULL;
1508 self->status->data.bufSize = 0;
1509 dce_free (version);
1510 }
1511 }
1512 break;
1513 }
1514 case PROP_MAX_REORDER_FRAMES:
1515 g_value_set_int (value, self->backlog_max_maxframes);
1516 break;
1517 case PROP_CODEC_DEBUG_INFO:
1518 g_value_set_boolean (value, self->codec_debug_info);
1519 break;
1520 default:{
1521 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1522 break;
1523 }
1524 }
1525 }
1527 static void
1528 gst_ducati_viddec_set_property (GObject * obj,
1529 guint prop_id, const GValue * value, GParamSpec * pspec)
1530 {
1531 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1533 switch (prop_id) {
1534 case PROP_MAX_REORDER_FRAMES:
1535 self->backlog_max_maxframes = g_value_get_int (value);
1536 break;
1537 case PROP_CODEC_DEBUG_INFO:
1538 self->codec_debug_info = g_value_get_boolean (value);
1539 break;
1540 default:{
1541 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
1542 break;
1543 }
1544 }
1545 }
1547 static void
1548 gst_ducati_viddec_finalize (GObject * obj)
1549 {
1550 GstDucatiVidDec *self = GST_DUCATIVIDDEC (obj);
1552 codec_delete (self);
1553 engine_close (self);
1555 /* Will unref the remaining buffers if needed */
1556 g_hash_table_unref (self->passed_in_bufs);
1557 if (self->codec_data) {
1558 gst_buffer_unref (self->codec_data);
1559 self->codec_data = NULL;
1560 }
1562 G_OBJECT_CLASS (parent_class)->finalize (obj);
1563 }
1565 static void
1566 gst_ducati_viddec_base_init (gpointer gclass)
1567 {
1568 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
1570 gst_element_class_add_pad_template (element_class,
1571 gst_static_pad_template_get (&src_factory));
1572 }
1574 static void
1575 gst_ducati_viddec_class_init (GstDucatiVidDecClass * klass)
1576 {
1577 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1578 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1580 gobject_class->get_property =
1581 GST_DEBUG_FUNCPTR (gst_ducati_viddec_get_property);
1582 gobject_class->set_property =
1583 GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_property);
1584 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ducati_viddec_finalize);
1585 gstelement_class->change_state =
1586 GST_DEBUG_FUNCPTR (gst_ducati_viddec_change_state);
1588 klass->parse_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_parse_caps);
1589 klass->allocate_params =
1590 GST_DEBUG_FUNCPTR (gst_ducati_viddec_allocate_params);
1591 klass->push_input = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_input);
1592 klass->handle_error = GST_DEBUG_FUNCPTR (gst_ducati_viddec_handle_error);
1593 klass->can_drop_frame = GST_DEBUG_FUNCPTR (gst_ducati_viddec_can_drop_frame);
1594 klass->query = GST_DEBUG_FUNCPTR (gst_ducati_viddec_query);
1595 klass->push_output = GST_DEBUG_FUNCPTR (gst_ducati_viddec_push_output);
1596 klass->on_flush = GST_DEBUG_FUNCPTR (gst_ducati_viddec_on_flush);
1597 klass->set_sink_caps = GST_DEBUG_FUNCPTR (gst_ducati_viddec_set_sink_caps);
1599 g_object_class_install_property (gobject_class, PROP_VERSION,
1600 g_param_spec_string ("version", "Version",
1601 "The codec version string", "",
1602 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
1604 g_object_class_install_property (gobject_class, PROP_MAX_REORDER_FRAMES,
1605 g_param_spec_int ("max-reorder-frames",
1606 "Maximum number of frames needed for reordering",
1607 "The maximum number of frames needed for reordering output frames. "
1608 "Only meaningful for codecs with B frames. 0 means no reordering. "
1609 "This value will be used if the correct value cannot be inferred "
1610 "from the stream. Too low a value may cause misordering, too high "
1611 "will cause extra latency.",
1612 0, MAX_BACKLOG_FRAMES, MAX_BACKLOG_FRAMES,
1613 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1615 g_object_class_install_property (gobject_class, PROP_CODEC_DEBUG_INFO,
1616 g_param_spec_boolean ("codec-debug-info",
1617 "Gather debug info from the codec",
1618 "Gather and log relevant debug information from the codec. "
1619 "What is gathered is typically codec specific", FALSE,
1620 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
1621 }
1623 static void
1624 gst_ducati_viddec_init (GstDucatiVidDec * self, GstDucatiVidDecClass * klass)
1625 {
1626 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1628 gst_ducati_set_generic_error_strings (self->error_strings);
1630 self->sinkpad =
1631 gst_pad_new_from_template (gst_element_class_get_pad_template
1632 (gstelement_class, "sink"), "sink");
1633 gst_pad_set_setcaps_function (self->sinkpad,
1634 GST_DEBUG_FUNCPTR (gst_ducati_viddec_sink_setcaps));
1635 gst_pad_set_chain_function (self->sinkpad,
1636 GST_DEBUG_FUNCPTR (gst_ducati_viddec_chain));
1637 gst_pad_set_event_function (self->sinkpad,
1638 GST_DEBUG_FUNCPTR (gst_ducati_viddec_event));
1640 self->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
1641 gst_pad_set_event_function (self->srcpad,
1642 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_event));
1643 gst_pad_set_query_function (self->srcpad,
1644 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_query));
1645 gst_pad_set_getcaps_function (self->srcpad,
1646 GST_DEBUG_FUNCPTR (gst_ducati_viddec_src_getcaps));
1648 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
1649 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
1651 self->input_width = 0;
1652 self->input_height = 0;
1653 /* sane defaults in case we need to create codec without caps negotiation
1654 * (for example, to get 'version' property)
1655 */
1656 self->width = 128;
1657 self->height = 128;
1658 self->fps_n = -1;
1659 self->fps_d = -1;
1661 self->first_in_buffer = TRUE;
1662 self->first_out_buffer = TRUE;
1663 self->interlaced = FALSE;
1664 self->send_crop_event = TRUE;
1666 #ifdef USE_DTS_PTS_CODE
1667 self->dts_ridx = self->dts_widx = 0;
1668 self->last_dts = self->last_pts = GST_CLOCK_TIME_NONE;
1669 self->ts_may_be_pts = TRUE;
1670 self->ts_is_pts = FALSE;
1671 #endif
1673 self->pageMemType = XDM_MEMTYPE_TILEDPAGE;
1675 gst_segment_init (&self->segment, GST_FORMAT_UNDEFINED);
1677 self->qos_proportion = 1;
1678 self->qos_earliest_time = GST_CLOCK_TIME_NONE;
1679 self->wait_keyframe = TRUE;
1681 self->need_out_buf = TRUE;
1682 self->device = NULL;
1683 self->input_bo = NULL;
1685 self->backlog_maxframes = 0;
1686 self->backlog_nframes = 0;
1687 self->backlog_max_maxframes = MAX_BACKLOG_FRAMES;
1689 self->codec_debug_info = FALSE;
1691 self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
1692 NULL, (GDestroyNotify) gst_buffer_unref);
1693 }