2 * Copyright (C) 2011, Hewlett-Packard Development Company, L.P.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
4 * Copyright (C) 2013, Collabora Ltd.
5 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation
10 * version 2.1 of the License.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
31 #define __VCCOREVER__ 0x04000000
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wredundant-decls"
36 #pragma GCC optimize ("gnu89-inline")
39 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
40 #include <gst/gl/gl.h>
41 #include <gst/gl/egl/gsteglimagememory.h>
44 #if defined (USE_OMX_TARGET_RPI) && defined(__GNUC__)
45 #pragma GCC reset_options
46 #pragma GCC diagnostic pop
49 //#define CODEC_DEC_INTPUT_DUMP
50 //#define CODEC_DEC_OUTPUT_DUMP
54 #include "gstomxbufferpool.h"
55 #include "gstomxvideo.h"
56 #include "gstomxvideodec.h"
58 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category);
59 #define GST_CAT_DEFAULT gst_omx_video_dec_debug_category
62 static void gst_omx_video_dec_finalize (GObject * object);
64 static GstStateChangeReturn
65 gst_omx_video_dec_change_state (GstElement * element,
66 GstStateChange transition);
68 static gboolean gst_omx_video_dec_open (GstVideoDecoder * decoder);
69 static gboolean gst_omx_video_dec_close (GstVideoDecoder * decoder);
70 static gboolean gst_omx_video_dec_start (GstVideoDecoder * decoder);
71 static gboolean gst_omx_video_dec_stop (GstVideoDecoder * decoder);
72 static gboolean gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
73 GstVideoCodecState * state);
74 static gboolean gst_omx_video_dec_flush (GstVideoDecoder * decoder);
75 static GstFlowReturn gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
76 GstVideoCodecFrame * frame);
77 static GstFlowReturn gst_omx_video_dec_finish (GstVideoDecoder * decoder);
78 static gboolean gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec,
81 static GstFlowReturn gst_omx_video_dec_drain (GstOMXVideoDec * self);
83 static OMX_ERRORTYPE gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec *
85 static OMX_ERRORTYPE gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec
88 #ifdef TIZEN_FEATURE_OMX
89 static gboolean gst_omx_video_dec_acquire_request_flush_buffer (GstOMXVideoDec * self, GstBuffer ** flush_request_buffer);
90 static gboolean gst_omx_video_dec_handle_event (GstVideoDecoder * decoder, GstEvent *event);
98 /* class initialization */
101 GST_DEBUG_CATEGORY_INIT (gst_omx_video_dec_debug_category, "omxvideodec", 0, \
102 "debug category for gst-omx video decoder base class");
105 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec,
106 GST_TYPE_VIDEO_DECODER, DEBUG_INIT);
109 gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
111 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
112 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
113 GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
115 gobject_class->finalize = gst_omx_video_dec_finalize;
117 element_class->change_state =
118 GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state);
120 video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_dec_open);
121 video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_dec_close);
122 video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_dec_start);
123 video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_dec_stop);
124 video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_dec_flush);
125 video_decoder_class->set_format =
126 GST_DEBUG_FUNCPTR (gst_omx_video_dec_set_format);
127 video_decoder_class->handle_frame =
128 GST_DEBUG_FUNCPTR (gst_omx_video_dec_handle_frame);
129 video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_dec_finish);
130 video_decoder_class->decide_allocation =
131 GST_DEBUG_FUNCPTR (gst_omx_video_dec_decide_allocation);
133 #ifdef TIZEN_FEATURE_OMX
134 video_decoder_class->sink_event = GST_DEBUG_FUNCPTR (gst_omx_video_dec_handle_event);
137 klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
138 klass->cdata.default_src_template_caps =
139 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
140 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
144 "width = " GST_VIDEO_SIZE_RANGE ", "
145 "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE ", "
146 "format = (string)SN12";
150 gst_omx_video_dec_init (GstOMXVideoDec * self)
152 gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
153 gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
155 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (self));
157 g_mutex_init (&self->drain_lock);
158 g_cond_init (&self->drain_cond);
160 #ifdef TIZEN_FEATURE_OMX
167 gst_omx_video_dec_open (GstVideoDecoder * decoder)
169 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
170 GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
171 gint in_port_index, out_port_index;
173 GST_DEBUG_OBJECT (self, "Opening decoder");
176 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
177 klass->cdata.component_name, klass->cdata.component_role,
179 self->started = FALSE;
184 if (gst_omx_component_get_state (self->dec,
185 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
188 in_port_index = klass->cdata.in_port_index;
189 out_port_index = klass->cdata.out_port_index;
191 if (in_port_index == -1 || out_port_index == -1) {
192 OMX_PORT_PARAM_TYPE param;
195 GST_OMX_INIT_STRUCT (¶m);
198 gst_omx_component_get_parameter (self->dec, OMX_IndexParamVideoInit,
200 if (err != OMX_ErrorNone) {
201 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
202 gst_omx_error_to_string (err), err);
207 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
208 (guint) param.nPorts, (guint) param.nStartPortNumber);
209 in_port_index = param.nStartPortNumber + 0;
210 out_port_index = param.nStartPortNumber + 1;
214 self->dec_in_port = gst_omx_component_add_port (self->dec, in_port_index);
215 self->dec_out_port = gst_omx_component_add_port (self->dec, out_port_index);
217 if (!self->dec_in_port || !self->dec_out_port)
220 #ifdef TIZEN_FEATURE_OMX
221 self->bufmgr = tbm_bufmgr_init(self->drm_fd);
222 if (self->bufmgr == NULL) {
223 GST_ERROR_OBJECT (self, "TBM initialization failed.");
227 #if defined(USE_OMX_TARGET_EXYNOS) || defined(USE_OMX_TARGET_EXYNOS64)
229 /* set plateform specific gem buffer settings. */
231 EnableGemBuffersParams gem_param;
232 OMX_INDEXTYPE index = OMX_IndexComponentStartUnused;
234 err = gst_omx_component_get_extension_index (self->dec, (OMX_STRING) EXYNOS_INDEX_PARAM_STORE_METADATA_BUFFER, &index);
235 if (err != OMX_ErrorNone) {
236 GST_WARNING_OBJECT (self, "Failed to get extension index : %s (0x%08x)",
237 gst_omx_error_to_string (err), err);
240 OMX_INIT_PARAM (gem_param);
241 gem_param.enable = OMX_TRUE;
242 gem_param.nPortIndex = 1;
244 err = gst_omx_component_set_parameter(self->dec, index, &gem_param);
245 if (err != OMX_ErrorNone) {
246 GST_ERROR_OBJECT (self, "Failed to set platform specific buffer: %s (0x%08x)",
247 gst_omx_error_to_string (err), err);
250 self->dec_in_port->use_buffer = klass->cdata.in_port_usebuffer;
251 self->dec_out_port->use_buffer = klass->cdata.out_port_usebuffer;
256 GST_DEBUG_OBJECT (self, "Opened decoder");
258 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
259 GST_DEBUG_OBJECT (self, "Opening EGL renderer");
261 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
262 "OMX.broadcom.egl_render", NULL, klass->cdata.hacks);
264 if (!self->egl_render)
267 if (gst_omx_component_get_state (self->egl_render,
268 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
272 OMX_PORT_PARAM_TYPE param;
275 GST_OMX_INIT_STRUCT (¶m);
278 gst_omx_component_get_parameter (self->egl_render,
279 OMX_IndexParamVideoInit, ¶m);
280 if (err != OMX_ErrorNone) {
281 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
282 gst_omx_error_to_string (err), err);
287 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u", param.nPorts,
288 param.nStartPortNumber);
289 in_port_index = param.nStartPortNumber + 0;
290 out_port_index = param.nStartPortNumber + 1;
295 gst_omx_component_add_port (self->egl_render, in_port_index);
297 gst_omx_component_add_port (self->egl_render, out_port_index);
299 if (!self->egl_in_port || !self->egl_out_port)
302 GST_DEBUG_OBJECT (self, "Opened EGL renderer");
309 gst_omx_video_dec_shutdown (GstOMXVideoDec * self)
313 GST_DEBUG_OBJECT (self, "Shutting down decoder");
315 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
316 state = gst_omx_component_get_state (self->egl_render, 0);
317 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
318 if (state > OMX_StateIdle) {
319 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
320 gst_omx_component_set_state (self->dec, OMX_StateIdle);
321 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
322 gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
324 gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
325 gst_omx_component_set_state (self->dec, OMX_StateLoaded);
327 gst_omx_port_deallocate_buffers (self->dec_in_port);
328 gst_omx_video_dec_deallocate_output_buffers (self);
329 gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
330 if (state > OMX_StateLoaded) {
331 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
332 gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
336 /* Otherwise we didn't use EGL and just fall back to
337 * shutting down the decoder */
340 state = gst_omx_component_get_state (self->dec, 0);
341 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
342 if (state > OMX_StateIdle) {
343 gst_omx_component_set_state (self->dec, OMX_StateIdle);
344 gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
346 gst_omx_component_set_state (self->dec, OMX_StateLoaded);
347 gst_omx_port_deallocate_buffers (self->dec_in_port);
348 gst_omx_video_dec_deallocate_output_buffers (self);
349 if (state > OMX_StateLoaded)
350 gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
353 #ifdef TIZEN_FEATURE_OMX
354 /* uninitialize tbm buffer manager */
355 if(self->bufmgr != NULL){
356 tbm_bufmgr_deinit(self->bufmgr);
360 if(self->drm_fd != -1) {
361 GST_DEBUG_OBJECT (self, "close drm fd");
371 gst_omx_video_dec_close (GstVideoDecoder * decoder)
373 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
375 GST_DEBUG_OBJECT (self, "Closing decoder");
377 if (!gst_omx_video_dec_shutdown (self))
380 self->dec_in_port = NULL;
381 self->dec_out_port = NULL;
383 gst_omx_component_free (self->dec);
386 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
387 self->egl_in_port = NULL;
388 self->egl_out_port = NULL;
389 if (self->egl_render)
390 gst_omx_component_free (self->egl_render);
391 self->egl_render = NULL;
394 self->started = FALSE;
396 GST_DEBUG_OBJECT (self, "Closed decoder");
402 gst_omx_video_dec_finalize (GObject * object)
404 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
406 g_mutex_clear (&self->drain_lock);
407 g_cond_clear (&self->drain_cond);
409 G_OBJECT_CLASS (gst_omx_video_dec_parent_class)->finalize (object);
412 static GstStateChangeReturn
413 gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition)
415 GstOMXVideoDec *self;
416 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
418 g_return_val_if_fail (GST_IS_OMX_VIDEO_DEC (element),
419 GST_STATE_CHANGE_FAILURE);
420 self = GST_OMX_VIDEO_DEC (element);
422 switch (transition) {
423 case GST_STATE_CHANGE_NULL_TO_READY:
425 case GST_STATE_CHANGE_READY_TO_PAUSED:
426 self->downstream_flow_ret = GST_FLOW_OK;
427 self->draining = FALSE;
428 self->started = FALSE;
430 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
432 case GST_STATE_CHANGE_PAUSED_TO_READY:
433 if (self->dec_in_port)
434 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
435 if (self->dec_out_port)
436 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
437 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
438 if (self->egl_in_port)
439 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
440 if (self->egl_out_port)
441 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
444 g_mutex_lock (&self->drain_lock);
445 self->draining = FALSE;
446 g_cond_broadcast (&self->drain_cond);
447 g_mutex_unlock (&self->drain_lock);
454 GST_ELEMENT_CLASS (gst_omx_video_dec_parent_class)->change_state
455 (element, transition);
457 if (ret == GST_STATE_CHANGE_FAILURE)
460 switch (transition) {
461 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
463 case GST_STATE_CHANGE_PAUSED_TO_READY:
464 self->downstream_flow_ret = GST_FLOW_FLUSHING;
465 self->started = FALSE;
467 if (!gst_omx_video_dec_shutdown (self))
468 ret = GST_STATE_CHANGE_FAILURE;
470 case GST_STATE_CHANGE_READY_TO_NULL:
479 #ifdef CODEC_DEC_INTPUT_DUMP /* for decoder input dump */
481 decoder_input_dump (GstOMXBuffer * buf, gboolean use_buffer)
484 gchar filename[100]={0};
487 temp = use_buffer ? buf->mm_vbuffer->data[0] : buf->omx_buf->pBuffer;
489 sprintf(filename, "/tmp/dec_input_dump.out");
490 fp = fopen(filename, "ab");
492 fwrite(temp, buf->omx_buf->nFilledLen, 1, fp);
498 #ifdef CODEC_DEC_OUTPUT_DUMP /* for decoder output dump */
500 decoder_output_dump(GstOMXVideoDec *self, MMVideoBuffer *outbuf)
502 char *temp = (char *)outbuf->data[0];
504 char filename[100]={0};
508 GST_ERROR_OBJECT (self, "codec dec output dump start. w = %d, h = %d", outbuf->width[0], outbuf->height[0]);
510 sprintf(filename, "/tmp/dec_output_dump_%d_%d.yuv", outbuf->width[0], outbuf->height[0]);
511 fp = fopen(filename, "ab");
513 for (i = 0; i < outbuf->height[0]; i++) {
514 ret = fwrite(temp, outbuf->width[0], 1, fp);
515 temp += outbuf->stride_width[0];
518 temp = (char *)outbuf->data[1];
520 for(i = 0; i < outbuf->height[1]; i++) {
521 ret = fwrite(temp, outbuf->width[1], 1, fp);
522 temp += outbuf->stride_width[1];
525 GST_ERROR_OBJECT (self,"codec dec output dumped!! ret = %d", ret);
531 gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self,
532 GstOMXBuffer * inbuf, GstBuffer * outbuf)
534 GstVideoCodecState *state =
535 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
536 GstVideoInfo *vinfo = &state->info;
537 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->dec_out_port->port_def;
538 gboolean ret = FALSE;
539 #ifndef TIZEN_FEATURE_OMX
543 if (vinfo->width != port_def->format.video.nFrameWidth ||
544 vinfo->height != port_def->format.video.nFrameHeight) {
545 GST_ERROR_OBJECT (self, "Resolution do not match: port=%ux%u vinfo=%dx%d",
546 (guint) port_def->format.video.nFrameWidth,
547 (guint) port_def->format.video.nFrameHeight,
548 vinfo->width, vinfo->height);
552 /* Same strides and everything */
553 #ifndef TIZEN_FEATURE_OMX
554 if (gst_buffer_get_size (outbuf) == inbuf->omx_buf->nFilledLen) {
555 GstMapInfo map = GST_MAP_INFO_INIT;
557 if (!gst_buffer_map (outbuf, &map, GST_MAP_WRITE)) {
558 GST_ERROR_OBJECT (self, "Failed to map output buffer");
563 inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset,
564 inbuf->omx_buf->nFilledLen);
565 gst_buffer_unmap (outbuf, &map);
571 /* Different strides */
572 #ifndef TIZEN_FEATURE_OMX
573 if (gst_video_frame_map (&frame, vinfo, outbuf, GST_MAP_WRITE)) {
574 const guint nstride = port_def->format.video.nStride;
575 const guint nslice = port_def->format.video.nSliceHeight;
576 guint src_stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
577 guint src_size[GST_VIDEO_MAX_PLANES] = { nstride * nslice, 0, };
578 gint dst_width[GST_VIDEO_MAX_PLANES] = { 0, };
579 gint dst_height[GST_VIDEO_MAX_PLANES] =
580 { GST_VIDEO_INFO_HEIGHT (vinfo), 0, };
585 switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
586 #ifndef TIZEN_FEATURE_OMX
587 case GST_VIDEO_FORMAT_ABGR:
588 case GST_VIDEO_FORMAT_ARGB:
589 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 4;
591 case GST_VIDEO_FORMAT_RGB16:
592 case GST_VIDEO_FORMAT_BGR16:
593 case GST_VIDEO_FORMAT_YUY2:
594 case GST_VIDEO_FORMAT_UYVY:
595 case GST_VIDEO_FORMAT_YVYU:
596 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 2;
598 case GST_VIDEO_FORMAT_GRAY8:
599 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
601 case GST_VIDEO_FORMAT_I420:
602 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
603 src_stride[1] = nstride / 2;
604 src_size[1] = (src_stride[1] * nslice) / 2;
605 dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
606 dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
607 src_stride[2] = nstride / 2;
608 src_size[2] = (src_stride[1] * nslice) / 2;
609 dst_width[2] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
610 dst_height[2] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
612 case GST_VIDEO_FORMAT_NV12:
613 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
614 src_stride[1] = nstride;
615 src_size[1] = src_stride[1] * nslice / 2;
616 dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
617 dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
619 case GST_VIDEO_FORMAT_NV16:
620 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
621 src_stride[1] = nstride;
622 src_size[1] = src_stride[1] * nslice;
623 dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
624 dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo);
627 #ifdef TIZEN_FEATURE_OMX
628 case GST_VIDEO_FORMAT_SN12:
629 case GST_VIDEO_FORMAT_ST12: {
630 GstMemory *mem = NULL;
632 MMVideoBuffer *mm_vbuffer = NULL;
633 mm_vbuffer = (MMVideoBuffer*)(inbuf->omx_buf->pBuffer);
635 if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
636 GST_LOG_OBJECT (self, "dec output buf: bo[0] :%p, bo[1] : %p, fd[0]:%d fd[1]:%d fd[2]:%d w[0]:%d h[0]:%d buf_share_method:%d",
637 mm_vbuffer->handle.bo[0], mm_vbuffer->handle.bo[1], mm_vbuffer->handle.dmabuf_fd[0], mm_vbuffer->handle.dmabuf_fd[1], mm_vbuffer->handle.dmabuf_fd[2],
638 mm_vbuffer->width[0], mm_vbuffer->height[0], mm_vbuffer->type);
639 } else if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
640 GST_LOG_OBJECT (self, "dec output uses hw addr");
642 GST_WARNING_OBJECT (self, "dec output buf has TBM_BO buf_share_method");
644 #ifdef CODEC_DEC_OUTPUT_DUMP
645 decoder_output_dump(self, mm_vbuffer);
647 if (gst_buffer_n_memory (outbuf) < 2) {
648 data = g_malloc0 (sizeof (MMVideoBuffer));
649 mem = gst_memory_new_wrapped (0, data, sizeof (MMVideoBuffer), 0, sizeof (MMVideoBuffer), data, g_free);
650 gst_buffer_append_memory (outbuf, mem);
652 GstMapInfo info = GST_MAP_INFO_INIT;
654 mem = gst_buffer_peek_memory (outbuf, 1);
655 gst_memory_map (mem, &info, GST_MAP_WRITE);
657 gst_memory_unmap (mem, &info);
659 memcpy (data, mm_vbuffer, sizeof (MMVideoBuffer));
667 g_assert_not_reached ();
670 #ifndef TIZEN_FEATURE_OMX
671 src = inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset;
672 for (p = 0; p < GST_VIDEO_INFO_N_PLANES (vinfo); p++) {
677 dst = GST_VIDEO_FRAME_PLANE_DATA (&frame, p);
679 for (h = 0; h < dst_height[p]; h++) {
680 memcpy (dst, data, dst_width[p]);
681 dst += GST_VIDEO_INFO_PLANE_STRIDE (vinfo, p);
682 data += src_stride[p];
688 #ifndef TIZEN_FEATURE_OMX
689 gst_video_frame_unmap (&frame);
692 GST_ERROR_OBJECT (self, "Can't map output buffer to frame");
699 GST_BUFFER_PTS (outbuf) =
700 gst_util_uint64_scale (inbuf->omx_buf->nTimeStamp, GST_SECOND,
701 OMX_TICKS_PER_SECOND);
702 if (inbuf->omx_buf->nTickCount != 0)
703 GST_BUFFER_DURATION (outbuf) =
704 gst_util_uint64_scale (inbuf->omx_buf->nTickCount, GST_SECOND,
705 OMX_TICKS_PER_SECOND);
708 gst_video_codec_state_unref (state);
714 gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
716 OMX_ERRORTYPE err = OMX_ErrorNone;
718 GstBufferPool *pool = NULL;
719 GstStructure *config;
720 gboolean eglimage = FALSE, add_videometa = FALSE;
721 GstCaps *caps = NULL;
722 guint min = 0, max = 0;
723 GstVideoCodecState *state =
724 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
726 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
727 port = self->eglimage ? self->egl_out_port : self->dec_out_port;
729 port = self->dec_out_port;
732 pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
734 GstAllocator *allocator;
736 config = gst_buffer_pool_get_config (pool);
737 if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min, &max)) {
738 GST_ERROR_OBJECT (self, "Can't get buffer pool params");
739 gst_structure_free (config);
740 err = OMX_ErrorUndefined;
743 if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) {
744 GST_ERROR_OBJECT (self, "Can't get buffer pool allocator");
745 gst_structure_free (config);
746 err = OMX_ErrorUndefined;
750 /* Need at least 2 buffers for anything meaningful */
751 min = MAX (MAX (min, port->port_def.nBufferCountMin), 4);
754 } else if (max < port->port_def.nBufferCountMin || max < 2) {
755 /* Can't use pool because can't have enough buffers */
756 gst_caps_replace (&caps, NULL);
761 add_videometa = gst_buffer_pool_config_has_option (config,
762 GST_BUFFER_POOL_OPTION_VIDEO_META);
763 gst_structure_free (config);
765 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
766 eglimage = self->eglimage && (allocator
767 && g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0);
769 /* TODO: Implement something that works for other targets too */
772 caps = caps ? gst_caps_ref (caps) : NULL;
774 GST_DEBUG_OBJECT (self, "Trying to use pool %p with caps %" GST_PTR_FORMAT
775 " and memory type %s", pool, caps,
776 (allocator ? allocator->mem_type : "(null)"));
778 gst_caps_replace (&caps, NULL);
779 min = max = port->port_def.nBufferCountMin;
780 GST_DEBUG_OBJECT (self, "No pool available, not negotiated yet");
783 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
784 /* Will retry without EGLImage */
785 if (self->eglimage && !eglimage) {
786 GST_DEBUG_OBJECT (self,
787 "Wanted to use EGLImage but downstream doesn't support it");
788 err = OMX_ErrorUndefined;
794 self->out_port_pool =
795 gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port);
797 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
799 GList *buffers = NULL;
800 GList *images = NULL;
802 GstBufferPoolAcquireParams params = { 0, };
803 EGLDisplay egl_display = EGL_NO_DISPLAY;
805 GST_DEBUG_OBJECT (self, "Trying to allocate %d EGLImages", min);
807 for (i = 0; i < min; i++) {
811 if (gst_buffer_pool_acquire_buffer (pool, &buffer, ¶ms) != GST_FLOW_OK
812 || gst_buffer_n_memory (buffer) != 1
813 || !(mem = gst_buffer_peek_memory (buffer, 0))
814 || g_strcmp0 (mem->allocator->mem_type,
815 GST_EGL_IMAGE_MEMORY_TYPE) != 0) {
816 GST_INFO_OBJECT (self, "Failed to allocated %d-th EGLImage", i);
817 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
818 g_list_free (images);
821 /* TODO: For non-RPi targets we want to use the normal memory code below */
822 /* Retry without EGLImage */
823 err = OMX_ErrorUndefined;
827 buffers = g_list_append (buffers, buffer);
828 gst_egl_image_memory_set_orientation (mem,
829 GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP);
830 images = g_list_append (images, gst_egl_image_memory_get_image (mem));
831 if (egl_display == EGL_NO_DISPLAY)
832 egl_display = gst_egl_image_memory_get_display (mem);
835 GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min);
837 /* Everything went fine? */
839 GST_DEBUG_OBJECT (self, "Setting EGLDisplay");
840 self->egl_out_port->port_def.format.video.pNativeWindow = egl_display;
842 gst_omx_port_update_port_definition (self->egl_out_port,
843 &self->egl_out_port->port_def);
844 if (err != OMX_ErrorNone) {
845 GST_INFO_OBJECT (self,
846 "Failed to set EGLDisplay on port: %s (0x%08x)",
847 gst_omx_error_to_string (err), err);
848 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
849 g_list_free (images);
850 /* TODO: For non-RPi targets we want to use the normal memory code below */
851 /* Retry without EGLImage */
856 if (min != port->port_def.nBufferCountActual) {
857 err = gst_omx_port_update_port_definition (port, NULL);
858 if (err == OMX_ErrorNone) {
859 port->port_def.nBufferCountActual = min;
860 err = gst_omx_port_update_port_definition (port, &port->port_def);
863 if (err != OMX_ErrorNone) {
864 GST_INFO_OBJECT (self,
865 "Failed to configure %u output buffers: %s (0x%08x)", min,
866 gst_omx_error_to_string (err), err);
867 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
868 g_list_free (images);
869 /* TODO: For non-RPi targets we want to use the normal memory code below */
870 /* Retry without EGLImage */
876 if (!gst_omx_port_is_enabled (port)) {
877 err = gst_omx_port_set_enabled (port, TRUE);
878 if (err != OMX_ErrorNone) {
879 GST_INFO_OBJECT (self,
880 "Failed to enable port: %s (0x%08x)",
881 gst_omx_error_to_string (err), err);
882 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
883 g_list_free (images);
884 /* TODO: For non-RPi targets we want to use the normal memory code below */
885 /* Retry without EGLImage */
890 err = gst_omx_port_use_eglimages (port, images);
891 g_list_free (images);
893 if (err != OMX_ErrorNone) {
894 GST_INFO_OBJECT (self,
895 "Failed to pass EGLImages to port: %s (0x%08x)",
896 gst_omx_error_to_string (err), err);
897 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
898 /* TODO: For non-RPi targets we want to use the normal memory code below */
899 /* Retry without EGLImage */
903 err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
904 if (err != OMX_ErrorNone) {
905 GST_INFO_OBJECT (self,
906 "Failed to wait until port is enabled: %s (0x%08x)",
907 gst_omx_error_to_string (err), err);
908 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
909 /* TODO: For non-RPi targets we want to use the normal memory code below */
910 /* Retry without EGLImage */
914 GST_DEBUG_OBJECT (self, "Populating internal buffer pool");
915 GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool =
916 GST_BUFFER_POOL (gst_object_ref (pool));
917 for (l = buffers; l; l = l->next) {
918 g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers,
921 g_list_free (buffers);
922 /* All good and done, set caps below */
928 /* If not using EGLImage or trying to use EGLImage failed */
930 gboolean was_enabled = TRUE;
932 if (min != port->port_def.nBufferCountActual) {
933 err = gst_omx_port_update_port_definition (port, NULL);
934 if (err == OMX_ErrorNone) {
935 port->port_def.nBufferCountActual = min;
936 err = gst_omx_port_update_port_definition (port, &port->port_def);
939 if (err != OMX_ErrorNone) {
940 GST_ERROR_OBJECT (self,
941 "Failed to configure %u output buffers: %s (0x%08x)", min,
942 gst_omx_error_to_string (err), err);
947 if (!gst_omx_port_is_enabled (port)) {
948 err = gst_omx_port_set_enabled (port, TRUE);
949 if (err != OMX_ErrorNone) {
950 GST_INFO_OBJECT (self,
951 "Failed to enable port: %s (0x%08x)",
952 gst_omx_error_to_string (err), err);
957 #ifdef TIZEN_FEATURE_OMX
958 err = gst_omx_port_tbm_allocate_dec_buffers (port, self->bufmgr, port->use_buffer);
960 err = gst_omx_port_allocate_buffers (port);
962 if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) {
963 GST_ERROR_OBJECT (self,
964 "Failed to allocate required number of buffers %d, trying less and copying",
966 min = port->port_def.nBufferCountMin;
969 err = gst_omx_port_set_enabled (port, FALSE);
970 if (err != OMX_ErrorNone) {
971 GST_INFO_OBJECT (self,
972 "Failed to disable port again: %s (0x%08x)",
973 gst_omx_error_to_string (err), err);
978 if (min != port->port_def.nBufferCountActual) {
979 err = gst_omx_port_update_port_definition (port, NULL);
980 if (err == OMX_ErrorNone) {
981 port->port_def.nBufferCountActual = min;
982 err = gst_omx_port_update_port_definition (port, &port->port_def);
985 if (err != OMX_ErrorNone) {
986 GST_ERROR_OBJECT (self,
987 "Failed to configure %u output buffers: %s (0x%08x)", min,
988 gst_omx_error_to_string (err), err);
992 #ifdef TIZEN_FEATURE_OMX
993 err = gst_omx_port_tbm_allocate_dec_buffers (port, self->bufmgr, port->use_buffer);
995 err = gst_omx_port_allocate_buffers (port);
997 /* Can't provide buffers downstream in this case */
998 gst_caps_replace (&caps, NULL);
1001 if (err != OMX_ErrorNone) {
1002 GST_ERROR_OBJECT (self, "Failed to allocate %d buffers: %s (0x%08x)", min,
1003 gst_omx_error_to_string (err), err);
1008 err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
1009 if (err != OMX_ErrorNone) {
1010 GST_ERROR_OBJECT (self,
1011 "Failed to wait until port is enabled: %s (0x%08x)",
1012 gst_omx_error_to_string (err), err);
1020 err = OMX_ErrorNone;
1023 config = gst_buffer_pool_get_config (self->out_port_pool);
1026 gst_buffer_pool_config_add_option (config,
1027 GST_BUFFER_POOL_OPTION_VIDEO_META);
1029 gst_buffer_pool_config_set_params (config, caps,
1030 self->dec_out_port->port_def.nBufferSize, min, max);
1032 if (!gst_buffer_pool_set_config (self->out_port_pool, config)) {
1033 GST_INFO_OBJECT (self, "Failed to set config on internal pool");
1034 gst_object_unref (self->out_port_pool);
1035 self->out_port_pool = NULL;
1039 GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = TRUE;
1040 /* This now allocates all the buffers */
1041 if (!gst_buffer_pool_set_active (self->out_port_pool, TRUE)) {
1042 GST_INFO_OBJECT (self, "Failed to activate internal pool");
1043 gst_object_unref (self->out_port_pool);
1044 self->out_port_pool = NULL;
1046 GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = FALSE;
1048 } else if (self->out_port_pool) {
1049 gst_object_unref (self->out_port_pool);
1050 self->out_port_pool = NULL;
1054 if (!self->out_port_pool && err == OMX_ErrorNone)
1055 GST_DEBUG_OBJECT (self,
1056 "Not using our internal pool and copying buffers for downstream");
1059 gst_caps_unref (caps);
1061 gst_object_unref (pool);
1063 gst_video_codec_state_unref (state);
1068 static OMX_ERRORTYPE
1069 gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
1073 if (self->out_port_pool) {
1074 gst_buffer_pool_set_active (self->out_port_pool, FALSE);
1076 gst_buffer_pool_wait_released (self->out_port_pool);
1078 GST_OMX_BUFFER_POOL (self->out_port_pool)->deactivated = TRUE;
1079 gst_object_unref (self->out_port_pool);
1080 self->out_port_pool = NULL;
1082 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1084 gst_omx_port_deallocate_buffers (self->
1085 eglimage ? self->egl_out_port : self->dec_out_port);
1087 err = gst_omx_port_deallocate_buffers (self->dec_out_port);
1093 static OMX_ERRORTYPE
1094 gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self)
1098 GstVideoCodecState *state;
1099 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1100 GstVideoFormat format;
1102 /* At this point the decoder output port is disabled */
1104 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1106 OMX_STATETYPE egl_state;
1108 if (self->eglimage) {
1109 /* Nothing to do here, we could however fall back to non-EGLImage in theory */
1110 port = self->egl_out_port;
1111 err = OMX_ErrorNone;
1114 /* Set up egl_render */
1116 self->eglimage = TRUE;
1118 gst_omx_port_get_port_definition (self->dec_out_port, &port_def);
1119 GST_VIDEO_DECODER_STREAM_LOCK (self);
1120 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1121 GST_VIDEO_FORMAT_RGBA, port_def.format.video.nFrameWidth,
1122 port_def.format.video.nFrameHeight, self->input_state);
1124 /* at this point state->caps is NULL */
1126 gst_caps_unref (state->caps);
1127 state->caps = gst_video_info_to_caps (&state->info);
1128 gst_caps_set_features (state->caps, 0,
1129 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, NULL));
1131 /* try to negotiate with caps feature */
1132 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1134 GST_DEBUG_OBJECT (self,
1135 "Failed to negotiate with feature %s",
1136 GST_CAPS_FEATURE_MEMORY_EGL_IMAGE);
1139 gst_caps_replace (&state->caps, NULL);
1141 /* fallback: try to use EGLImage even if it is not in the caps feature */
1142 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1143 gst_video_codec_state_unref (state);
1144 GST_ERROR_OBJECT (self, "Failed to negotiate RGBA for EGLImage");
1145 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1150 gst_video_codec_state_unref (state);
1151 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1153 /* Now link it all together */
1155 err = gst_omx_port_set_enabled (self->egl_in_port, FALSE);
1156 if (err != OMX_ErrorNone)
1159 err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1160 if (err != OMX_ErrorNone)
1163 err = gst_omx_port_set_enabled (self->egl_out_port, FALSE);
1164 if (err != OMX_ErrorNone)
1167 err = gst_omx_port_wait_enabled (self->egl_out_port, 1 * GST_SECOND);
1168 if (err != OMX_ErrorNone)
1172 #define OMX_IndexParamBrcmVideoEGLRenderDiscardMode 0x7f0000db
1173 OMX_CONFIG_PORTBOOLEANTYPE discardMode;
1174 memset (&discardMode, 0, sizeof (discardMode));
1175 discardMode.nSize = sizeof (discardMode);
1176 discardMode.nPortIndex = 220;
1177 discardMode.nVersion.nVersion = OMX_VERSION;
1178 discardMode.bEnabled = OMX_FALSE;
1179 if (gst_omx_component_set_parameter (self->egl_render,
1180 OMX_IndexParamBrcmVideoEGLRenderDiscardMode,
1181 &discardMode) != OMX_ErrorNone)
1183 #undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode
1186 err = gst_omx_setup_tunnel (self->dec_out_port, self->egl_in_port);
1187 if (err != OMX_ErrorNone)
1190 err = gst_omx_port_set_enabled (self->egl_in_port, TRUE);
1191 if (err != OMX_ErrorNone)
1194 err = gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1195 if (err != OMX_ErrorNone)
1198 err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1199 if (err != OMX_ErrorNone)
1202 if (gst_omx_component_get_state (self->egl_render,
1203 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1206 err = gst_omx_video_dec_allocate_output_buffers (self);
1207 if (err != OMX_ErrorNone)
1210 if (gst_omx_component_set_state (self->egl_render,
1211 OMX_StateExecuting) != OMX_ErrorNone)
1214 if (gst_omx_component_get_state (self->egl_render,
1215 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1219 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
1220 if (err != OMX_ErrorNone)
1224 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
1225 if (err != OMX_ErrorNone)
1229 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
1230 if (err != OMX_ErrorNone)
1233 err = gst_omx_port_populate (self->egl_out_port);
1234 if (err != OMX_ErrorNone)
1237 err = gst_omx_port_set_enabled (self->dec_out_port, TRUE);
1238 if (err != OMX_ErrorNone)
1241 err = gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1242 if (err != OMX_ErrorNone)
1246 err = gst_omx_port_mark_reconfigured (self->dec_out_port);
1247 if (err != OMX_ErrorNone)
1250 err = gst_omx_port_mark_reconfigured (self->egl_out_port);
1251 if (err != OMX_ErrorNone)
1259 gst_omx_port_set_enabled (self->dec_out_port, FALSE);
1260 gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1261 egl_state = gst_omx_component_get_state (self->egl_render, 0);
1262 if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
1263 if (egl_state > OMX_StateIdle) {
1264 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1265 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1267 gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
1269 gst_omx_video_dec_deallocate_output_buffers (self);
1270 gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
1272 if (egl_state > OMX_StateLoaded) {
1273 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1277 /* After this egl_render should be deactivated
1278 * and the decoder's output port disabled */
1279 self->eglimage = FALSE;
1282 port = self->dec_out_port;
1285 GST_VIDEO_DECODER_STREAM_LOCK (self);
1287 gst_omx_port_get_port_definition (port, &port_def);
1288 g_assert (port_def.format.video.eCompressionFormat == OMX_VIDEO_CodingUnused);
1291 gst_omx_video_get_format_from_omx (port_def.format.video.eColorFormat);
1293 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1294 GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1295 port_def.format.video.eColorFormat);
1296 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1297 err = OMX_ErrorUndefined;
1301 GST_DEBUG_OBJECT (self,
1302 "Setting output state: format %s (%d), width %u, height %u",
1303 gst_video_format_to_string (format),
1304 port_def.format.video.eColorFormat,
1305 (guint) port_def.format.video.nFrameWidth,
1306 (guint) port_def.format.video.nFrameHeight);
1308 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1309 format, port_def.format.video.nFrameWidth,
1310 port_def.format.video.nFrameHeight, self->input_state);
1312 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1313 gst_video_codec_state_unref (state);
1314 GST_ERROR_OBJECT (self, "Failed to negotiate");
1315 err = OMX_ErrorUndefined;
1316 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1320 gst_video_codec_state_unref (state);
1322 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1324 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1327 err = gst_omx_video_dec_allocate_output_buffers (self);
1328 if (err != OMX_ErrorNone)
1331 err = gst_omx_port_populate (port);
1332 if (err != OMX_ErrorNone)
1335 err = gst_omx_port_mark_reconfigured (port);
1336 if (err != OMX_ErrorNone)
1345 gst_omx_video_dec_clean_older_frames (GstOMXVideoDec * self,
1346 GstOMXBuffer * buf, GList * frames)
1349 GstClockTime timestamp;
1351 timestamp = gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
1352 OMX_TICKS_PER_SECOND);
1354 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1355 /* We could release all frames stored with pts < timestamp since the
1356 * decoder will likely output frames in display order */
1357 for (l = frames; l; l = l->next) {
1358 GstVideoCodecFrame *tmp = l->data;
1360 if (tmp->pts < timestamp) {
1361 gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1362 GST_LOG_OBJECT (self,
1363 "discarding ghost frame %p (#%d) PTS:%" GST_TIME_FORMAT " DTS:%"
1364 GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1365 GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1367 gst_video_codec_frame_unref (tmp);
1371 /* We will release all frames with invalid timestamp because we don't even
1372 * know if they will be output some day. */
1373 for (l = frames; l; l = l->next) {
1374 GstVideoCodecFrame *tmp = l->data;
1376 if (!GST_CLOCK_TIME_IS_VALID (tmp->pts)) {
1377 gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1378 GST_LOG_OBJECT (self,
1379 "discarding frame %p (#%d) with invalid PTS:%" GST_TIME_FORMAT
1380 " DTS:%" GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1381 GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1383 gst_video_codec_frame_unref (tmp);
1388 g_list_free (frames);
1392 copy_frame (const GstVideoInfo * info, GstBuffer * outbuf)
1394 GstVideoInfo out_info, tmp_info;
1396 GstVideoFrame out_frame, tmp_frame;
1401 tmpbuf = gst_buffer_new_and_alloc (out_info.size);
1403 gst_video_frame_map (&out_frame, &out_info, outbuf, GST_MAP_READ);
1404 gst_video_frame_map (&tmp_frame, &tmp_info, tmpbuf, GST_MAP_WRITE);
1405 gst_video_frame_copy (&tmp_frame, &out_frame);
1406 gst_video_frame_unmap (&out_frame);
1407 gst_video_frame_unmap (&tmp_frame);
1409 gst_buffer_unref (outbuf);
1415 gst_omx_video_dec_loop (GstOMXVideoDec * self)
1418 GstOMXBuffer *buf = NULL;
1419 GstVideoCodecFrame *frame;
1420 GstFlowReturn flow_ret = GST_FLOW_OK;
1421 GstOMXAcquireBufferReturn acq_return;
1422 GstClockTimeDiff deadline;
1424 #ifdef TIZEN_FEATURE_OMX
1425 GstBuffer *flush_request_buffer = NULL;
1426 GstMessage *msg = NULL;
1429 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1430 port = self->eglimage ? self->egl_out_port : self->dec_out_port;
1432 port = self->dec_out_port;
1435 acq_return = gst_omx_port_acquire_buffer (port, &buf);
1436 if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1437 goto component_error;
1438 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1440 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1444 if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (self)) ||
1445 acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1446 GstVideoCodecState *state;
1447 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1448 GstVideoFormat format;
1450 GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1452 /* Reallocate all buffers */
1453 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1454 && gst_omx_port_is_enabled (port)) {
1455 #ifdef TIZEN_FEATURE_OMX
1456 if (gst_omx_video_dec_acquire_request_flush_buffer (self, &flush_request_buffer)) {
1457 flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), flush_request_buffer);
1459 if (flow_ret != GST_FLOW_OK) {
1460 gst_buffer_unref (flush_request_buffer);
1461 flush_request_buffer = NULL;
1462 goto reconfigure_error;
1466 err = gst_omx_port_set_enabled (port, FALSE);
1467 if (err != OMX_ErrorNone)
1468 goto reconfigure_error;
1470 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1471 if (err != OMX_ErrorNone)
1472 goto reconfigure_error;
1474 err = gst_omx_video_dec_deallocate_output_buffers (self);
1475 if (err != OMX_ErrorNone)
1476 goto reconfigure_error;
1478 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1479 if (err != OMX_ErrorNone)
1480 goto reconfigure_error;
1483 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1484 /* We have the possibility to reconfigure everything now */
1485 err = gst_omx_video_dec_reconfigure_output_port (self);
1486 if (err != OMX_ErrorNone)
1487 goto reconfigure_error;
1488 #ifdef TIZEN_FEATURE_OMX
1489 msg = gst_message_new_element (GST_OBJECT_CAST (self), gst_structure_new ("prepare-decode-buffers",
1490 "num_buffers", G_TYPE_INT, self->dec_out_port->port_def.nBufferCountActual,
1491 "extra_num_buffers", G_TYPE_INT, EXTRA_DECODER_OUTPUT_BUF, NULL));
1493 gst_element_post_message (GST_ELEMENT_CAST (self), msg);
1496 /* Just update caps */
1497 GST_VIDEO_DECODER_STREAM_LOCK (self);
1499 gst_omx_port_get_port_definition (port, &port_def);
1500 g_assert (port_def.format.video.eCompressionFormat ==
1501 OMX_VIDEO_CodingUnused);
1504 gst_omx_video_get_format_from_omx (port_def.format.
1505 video.eColorFormat);
1507 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1508 GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1509 port_def.format.video.eColorFormat);
1511 gst_omx_port_release_buffer (port, buf);
1512 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1516 GST_DEBUG_OBJECT (self,
1517 "Setting output state: format %s (%d), width %u, height %u",
1518 gst_video_format_to_string (format),
1519 port_def.format.video.eColorFormat,
1520 (guint) port_def.format.video.nFrameWidth,
1521 (guint) port_def.format.video.nFrameHeight);
1523 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1524 format, port_def.format.video.nFrameWidth,
1525 port_def.format.video.nFrameHeight, self->input_state);
1527 /* Take framerate and pixel-aspect-ratio from sinkpad caps */
1529 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1531 gst_omx_port_release_buffer (port, buf);
1532 gst_video_codec_state_unref (state);
1536 gst_video_codec_state_unref (state);
1538 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1541 /* Now get a buffer */
1542 if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1547 g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1549 /* This prevents a deadlock between the srcpad stream
1550 * lock and the videocodec stream lock, if ::reset()
1551 * is called at the wrong time
1553 if (gst_omx_port_is_flushing (port)) {
1554 GST_DEBUG_OBJECT (self, "Flushing");
1555 gst_omx_port_release_buffer (port, buf);
1559 GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
1560 (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);
1562 GST_VIDEO_DECODER_STREAM_LOCK (self);
1563 frame = gst_omx_video_find_nearest_frame (buf,
1564 gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1566 /* So we have a timestamped OMX buffer and get, or not, corresponding frame.
1567 * Assuming decoder output frames in display order, frames preceding this
1568 * frame could be discarded as they seems useless due to e.g interlaced
1569 * stream, corrupted input data...
1570 * In any cases, not likely to be seen again. so drop it before they pile up
1571 * and use all the memory. */
1572 gst_omx_video_dec_clean_older_frames (self, buf,
1573 gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1576 && (deadline = gst_video_decoder_get_max_decode_time
1577 (GST_VIDEO_DECODER (self), frame)) < 0) {
1578 GST_WARNING_OBJECT (self,
1579 "Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
1580 GST_TIME_ARGS (-deadline));
1581 flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1583 } else if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->eglimage)) {
1584 GstBuffer *outbuf = NULL;
1586 /* This sometimes happens at EOS or if the input is not properly framed,
1587 * let's handle it gracefully by allocating a new buffer for the current
1588 * caps and filling it
1591 GST_ERROR_OBJECT (self, "No corresponding frame found");
1593 if (self->out_port_pool) {
1595 GstBufferPoolAcquireParams params = { 0, };
1597 n = port->buffers->len;
1598 for (i = 0; i < n; i++) {
1599 GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1606 GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1608 gst_buffer_pool_acquire_buffer (self->out_port_pool, &outbuf,
1610 if (flow_ret != GST_FLOW_OK) {
1611 gst_omx_port_release_buffer (port, buf);
1612 goto invalid_buffer;
1615 if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
1617 copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1622 gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self));
1623 if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) {
1624 gst_buffer_unref (outbuf);
1625 gst_omx_port_release_buffer (port, buf);
1626 goto invalid_buffer;
1629 #ifdef TIZEN_FEATURE_OMX
1631 MMVideoBuffer *mm_vbuffer = NULL;
1632 GstMemory *mem = NULL;
1633 guint8 *data = NULL;
1634 mm_vbuffer = (MMVideoBuffer*)(buf->omx_buf->pBuffer);
1636 if (gst_buffer_n_memory (outbuf) < 2) {
1637 data = g_malloc0 (sizeof (MMVideoBuffer));
1638 mem = gst_memory_new_wrapped (0, data, sizeof(MMVideoBuffer), 0, sizeof(MMVideoBuffer), data, g_free);
1639 gst_buffer_append_memory (outbuf, mem);
1641 GstMapInfo info = GST_MAP_INFO_INIT;
1642 mem = gst_buffer_peek_memory (outbuf, 1);
1643 gst_memory_map (mem, &info, GST_MAP_WRITE);
1645 gst_memory_unmap (mem, &info);
1647 memcpy(data, mm_vbuffer, sizeof(MMVideoBuffer));
1650 if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
1651 GST_LOG_OBJECT (self, "frame not found: bo[0] :%p, bo[1] : %p, fd[0]:%d fd[1]:%d fd[2]:%d w[0]:%d h[0]:%d buf_share_method:%d",
1652 mm_vbuffer->handle.bo[0], mm_vbuffer->handle.bo[1], mm_vbuffer->handle.dmabuf_fd[0], mm_vbuffer->handle.dmabuf_fd[1], mm_vbuffer->handle.dmabuf_fd[2],
1653 mm_vbuffer->width[0], mm_vbuffer->height[0], mm_vbuffer->type);
1654 } else if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
1655 GST_LOG_OBJECT (self, "dec output uses hw addr");
1657 GST_WARNING_OBJECT (self, "dec output buf has TBM_BO buf_share_method");
1661 flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf);
1662 } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
1663 if (self->out_port_pool) {
1665 GstBuffer *outbuf = NULL;
1666 GstBufferPoolAcquireParams params = { 0, };
1668 n = port->buffers->len;
1669 for (i = 0; i < n; i++) {
1670 GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1677 GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1679 gst_buffer_pool_acquire_buffer (self->out_port_pool,
1680 &frame->output_buffer, ¶ms);
1681 if (flow_ret != GST_FLOW_OK) {
1683 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1685 gst_omx_port_release_buffer (port, buf);
1686 goto invalid_buffer;
1689 if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy){
1691 copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1693 frame->output_buffer = outbuf;
1696 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1700 if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1701 gst_buffer_replace (&frame->output_buffer, NULL);
1704 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1706 gst_omx_port_release_buffer (port, buf);
1707 goto invalid_buffer;
1710 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1716 gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER
1717 (self), frame)) == GST_FLOW_OK) {
1718 /* FIXME: This currently happens because of a race condition too.
1719 * We first need to reconfigure the output port and then the input
1720 * port if both need reconfiguration.
1722 if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1723 gst_buffer_replace (&frame->output_buffer, NULL);
1725 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1727 gst_omx_port_release_buffer (port, buf);
1728 goto invalid_buffer;
1731 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1735 } else if (frame != NULL) {
1736 flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1740 GST_DEBUG_OBJECT (self, "Read frame from component");
1742 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1745 err = gst_omx_port_release_buffer (port, buf);
1746 if (err != OMX_ErrorNone)
1750 self->downstream_flow_ret = flow_ret;
1752 if (flow_ret != GST_FLOW_OK)
1755 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1761 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1762 ("OpenMAX component in error state %s (0x%08x)",
1763 gst_omx_component_get_last_error_string (self->dec),
1764 gst_omx_component_get_last_error (self->dec)));
1765 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1766 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1767 self->downstream_flow_ret = GST_FLOW_ERROR;
1768 self->started = FALSE;
1774 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1775 g_mutex_lock (&self->drain_lock);
1776 if (self->draining) {
1777 self->draining = FALSE;
1778 g_cond_broadcast (&self->drain_cond);
1780 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1781 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1782 self->started = FALSE;
1783 g_mutex_unlock (&self->drain_lock);
1789 g_mutex_lock (&self->drain_lock);
1790 if (self->draining) {
1791 GstQuery *query = gst_query_new_drain ();
1793 /* Drain the pipeline to reclaim all memories back to the pool */
1794 if (!gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (self), query))
1795 GST_DEBUG_OBJECT (self, "drain query failed");
1796 gst_query_unref (query);
1798 GST_DEBUG_OBJECT (self, "Drained");
1799 self->draining = FALSE;
1800 g_cond_broadcast (&self->drain_cond);
1801 flow_ret = GST_FLOW_OK;
1802 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1804 GST_DEBUG_OBJECT (self, "Component signalled EOS");
1805 flow_ret = GST_FLOW_EOS;
1807 g_mutex_unlock (&self->drain_lock);
1809 GST_VIDEO_DECODER_STREAM_LOCK (self);
1810 self->downstream_flow_ret = flow_ret;
1812 /* Here we fallback and pause the task for the EOS case */
1813 if (flow_ret != GST_FLOW_OK)
1816 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1823 if (flow_ret == GST_FLOW_EOS) {
1824 GST_DEBUG_OBJECT (self, "EOS");
1826 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1827 gst_event_new_eos ());
1828 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1829 self->started = FALSE;
1830 } else if (flow_ret < GST_FLOW_EOS) {
1831 GST_ELEMENT_ERROR (self, STREAM, FAILED,
1832 ("Internal data stream error."), ("stream stopped, reason %s",
1833 gst_flow_get_name (flow_ret)));
1835 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1836 gst_event_new_eos ());
1837 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1838 self->started = FALSE;
1839 } else if (flow_ret == GST_FLOW_FLUSHING) {
1840 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1841 g_mutex_lock (&self->drain_lock);
1842 if (self->draining) {
1843 self->draining = FALSE;
1844 g_cond_broadcast (&self->drain_cond);
1846 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1847 self->started = FALSE;
1848 g_mutex_unlock (&self->drain_lock);
1850 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1856 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1857 ("Unable to reconfigure output port"));
1858 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1859 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1860 self->downstream_flow_ret = GST_FLOW_ERROR;
1861 self->started = FALSE;
1867 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1868 ("Invalid sized input buffer"));
1869 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1870 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1871 self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
1872 self->started = FALSE;
1873 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1879 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1880 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1881 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1882 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1883 self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
1884 self->started = FALSE;
1889 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1890 ("Failed to relase output buffer to component: %s (0x%08x)",
1891 gst_omx_error_to_string (err), err));
1892 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1893 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1894 self->downstream_flow_ret = GST_FLOW_ERROR;
1895 self->started = FALSE;
1896 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1902 gst_omx_video_dec_start (GstVideoDecoder * decoder)
1904 GstOMXVideoDec *self;
1906 self = GST_OMX_VIDEO_DEC (decoder);
1908 self->last_upstream_ts = 0;
1909 self->downstream_flow_ret = GST_FLOW_OK;
1915 gst_omx_video_dec_stop (GstVideoDecoder * decoder)
1917 GstOMXVideoDec *self;
1919 self = GST_OMX_VIDEO_DEC (decoder);
1921 GST_DEBUG_OBJECT (self, "Stopping decoder");
1923 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
1924 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
1926 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1927 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
1928 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
1931 gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
1933 if (gst_omx_component_get_state (self->dec, 0) > OMX_StateIdle)
1934 gst_omx_component_set_state (self->dec, OMX_StateIdle);
1935 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1936 if (gst_omx_component_get_state (self->egl_render, 0) > OMX_StateIdle)
1937 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1940 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1941 self->started = FALSE;
1943 g_mutex_lock (&self->drain_lock);
1944 self->draining = FALSE;
1945 g_cond_broadcast (&self->drain_cond);
1946 g_mutex_unlock (&self->drain_lock);
1948 gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
1949 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1950 gst_omx_component_get_state (self->egl_render, 1 * GST_SECOND);
1953 gst_buffer_replace (&self->codec_data, NULL);
1955 if (self->input_state)
1956 gst_video_codec_state_unref (self->input_state);
1957 self->input_state = NULL;
1959 GST_DEBUG_OBJECT (self, "Stopped decoder");
1965 gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
1967 OMX_VIDEO_PARAM_PORTFORMATTYPE param;
1969 GstCaps *comp_supported_caps;
1970 GList *negotiation_map = NULL, *l;
1971 GstCaps *templ_caps, *intersection;
1972 GstVideoFormat format;
1974 const gchar *format_str = NULL;
1975 #ifdef TIZEN_FEATURE_OMX
1976 const gchar *format_tmp;
1980 GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream");
1982 templ_caps = gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (self));
1984 gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (self), templ_caps);
1985 gst_caps_unref (templ_caps);
1987 GST_DEBUG_OBJECT (self, "Allowed downstream caps: %" GST_PTR_FORMAT,
1991 gst_omx_video_get_supported_colorformats (self->dec_out_port,
1994 comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
1996 if (!gst_caps_is_empty (comp_supported_caps)) {
1999 tmp = gst_caps_intersect (comp_supported_caps, intersection);
2000 gst_caps_unref (intersection);
2003 gst_caps_unref (comp_supported_caps);
2005 if (gst_caps_is_empty (intersection)) {
2006 gst_caps_unref (intersection);
2007 GST_ERROR_OBJECT (self, "Empty caps");
2008 g_list_free_full (negotiation_map,
2009 (GDestroyNotify) gst_omx_video_negotiation_map_free);
2013 #ifdef TIZEN_FEATURE_OMX
2014 for(i = 0; i < gst_caps_get_size (intersection); i++)
2016 s = gst_caps_get_structure (intersection, i);
2017 if ((format_tmp = gst_structure_get_string (s, "format"))) {
2019 if (!strncmp (format_tmp, "S", 1)) {
2020 format_str = format_tmp;
2021 GST_DEBUG_OBJECT (self, "SEC format found");
2028 intersection = gst_caps_truncate (intersection);
2029 intersection = gst_caps_fixate (intersection);
2031 s = gst_caps_get_structure (intersection, 0);
2032 format_str = gst_structure_get_string (s, "format");
2033 GST_DEBUG_OBJECT (self, "first structure will be fixated");
2039 gst_video_format_from_string (format_str)) ==
2040 GST_VIDEO_FORMAT_UNKNOWN) {
2041 GST_ERROR_OBJECT (self, "Invalid caps: %" GST_PTR_FORMAT, intersection);
2042 gst_caps_unref (intersection);
2043 g_list_free_full (negotiation_map,
2044 (GDestroyNotify) gst_omx_video_negotiation_map_free);
2048 GST_OMX_INIT_STRUCT (¶m);
2049 param.nPortIndex = self->dec_out_port->index;
2051 for (l = negotiation_map; l; l = l->next) {
2052 GstOMXVideoNegotiationMap *m = l->data;
2054 if (m->format == format) {
2055 param.eColorFormat = m->type;
2060 GST_DEBUG_OBJECT (self, "Negotiating color format %s (%d)", format_str,
2061 param.eColorFormat);
2063 /* We must find something here */
2064 g_assert (l != NULL);
2065 g_list_free_full (negotiation_map,
2066 (GDestroyNotify) gst_omx_video_negotiation_map_free);
2069 gst_omx_component_set_parameter (self->dec,
2070 OMX_IndexParamVideoPortFormat, ¶m);
2071 if (err != OMX_ErrorNone) {
2072 GST_ERROR_OBJECT (self, "Failed to set video port format: %s (0x%08x)",
2073 gst_omx_error_to_string (err), err);
2076 gst_caps_unref (intersection);
2077 return (err == OMX_ErrorNone);
2081 gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
2082 GstVideoCodecState * state)
2084 GstOMXVideoDec *self;
2085 GstOMXVideoDecClass *klass;
2086 GstVideoInfo *info = &state->info;
2087 gboolean is_format_change = FALSE;
2088 gboolean needs_disable = FALSE;
2089 OMX_PARAM_PORTDEFINITIONTYPE port_def;
2091 self = GST_OMX_VIDEO_DEC (decoder);
2092 klass = GST_OMX_VIDEO_DEC_GET_CLASS (decoder);
2094 GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
2096 gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
2098 /* Check if the caps change is a real format change or if only irrelevant
2099 * parts of the caps have changed or nothing at all.
2101 is_format_change |= port_def.format.video.nFrameWidth != info->width;
2102 is_format_change |= port_def.format.video.nFrameHeight != info->height;
2103 is_format_change |= (port_def.format.video.xFramerate == 0
2104 && info->fps_n != 0)
2105 || (port_def.format.video.xFramerate !=
2106 (info->fps_n << 16) / (info->fps_d));
2107 is_format_change |= (self->codec_data != state->codec_data);
2108 if (klass->is_format_change)
2110 klass->is_format_change (self, self->dec_in_port, state);
2113 gst_omx_component_get_state (self->dec,
2114 GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2115 /* If the component is not in Loaded state and a real format change happens
2116 * we have to disable the port and re-allocate all buffers. If no real
2117 * format change happened we can just exit here.
2119 if (needs_disable && !is_format_change) {
2120 GST_DEBUG_OBJECT (self,
2121 "Already running and caps did not change the format");
2122 if (self->input_state)
2123 gst_video_codec_state_unref (self->input_state);
2124 self->input_state = gst_video_codec_state_ref (state);
2128 if (needs_disable && is_format_change) {
2129 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2130 GstOMXPort *out_port =
2131 self->eglimage ? self->egl_out_port : self->dec_out_port;
2133 GstOMXPort *out_port = self->dec_out_port;
2136 GST_DEBUG_OBJECT (self, "Need to disable and drain decoder");
2138 gst_omx_video_dec_drain (self);
2139 gst_omx_video_dec_flush (decoder);
2140 gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE);
2142 if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
2143 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2144 gst_omx_video_dec_stop (GST_VIDEO_DECODER (self));
2145 gst_omx_video_dec_close (GST_VIDEO_DECODER (self));
2146 GST_VIDEO_DECODER_STREAM_LOCK (self);
2148 if (!gst_omx_video_dec_open (GST_VIDEO_DECODER (self)))
2150 needs_disable = FALSE;
2151 #ifdef TIZEN_FEATURE_OMX
2152 gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
2155 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2156 if (self->eglimage) {
2157 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2158 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2159 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2160 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2163 if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone)
2166 if (gst_omx_port_wait_buffers_released (self->dec_in_port,
2167 5 * GST_SECOND) != OMX_ErrorNone)
2170 if (gst_omx_port_deallocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2173 if (gst_omx_port_wait_enabled (self->dec_in_port,
2174 1 * GST_SECOND) != OMX_ErrorNone)
2176 #ifndef TIZEN_FEATURE_OMX
2177 if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone)
2180 if (gst_omx_port_wait_buffers_released (out_port,
2181 1 * GST_SECOND) != OMX_ErrorNone)
2184 if (gst_omx_video_dec_deallocate_output_buffers (self) != OMX_ErrorNone)
2187 if (gst_omx_port_wait_enabled (out_port, 1 * GST_SECOND) != OMX_ErrorNone)
2190 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2191 if (self->eglimage) {
2192 OMX_STATETYPE egl_state;
2194 egl_state = gst_omx_component_get_state (self->egl_render, 0);
2195 if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
2197 if (egl_state > OMX_StateIdle) {
2198 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
2199 gst_omx_component_set_state (self->dec, OMX_StateIdle);
2200 egl_state = gst_omx_component_get_state (self->egl_render,
2202 gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
2204 gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
2205 gst_omx_component_set_state (self->dec, OMX_StateLoaded);
2207 gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
2209 if (egl_state > OMX_StateLoaded) {
2210 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
2213 gst_omx_component_set_state (self->dec, OMX_StateIdle);
2215 gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2216 gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2218 self->eglimage = FALSE;
2222 if (self->input_state)
2223 gst_video_codec_state_unref (self->input_state);
2224 self->input_state = NULL;
2226 GST_DEBUG_OBJECT (self, "Decoder drained and disabled");
2229 port_def.format.video.nFrameWidth = info->width;
2230 port_def.format.video.nFrameHeight = info->height;
2231 if (info->fps_n == 0)
2232 port_def.format.video.xFramerate = 0;
2234 port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
2236 GST_DEBUG_OBJECT (self, "Setting inport port definition");
2238 if (gst_omx_port_update_port_definition (self->dec_in_port,
2239 &port_def) != OMX_ErrorNone)
2242 if (klass->set_format) {
2243 if (!klass->set_format (self, self->dec_in_port, state)) {
2244 GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2249 GST_DEBUG_OBJECT (self, "Updating outport port definition");
2250 if (gst_omx_port_update_port_definition (self->dec_out_port,
2251 NULL) != OMX_ErrorNone)
2254 gst_buffer_replace (&self->codec_data, state->codec_data);
2255 self->input_state = gst_video_codec_state_ref (state);
2257 GST_DEBUG_OBJECT (self, "Enabling component");
2259 if (needs_disable) {
2260 if (gst_omx_port_set_enabled (self->dec_in_port, TRUE) != OMX_ErrorNone)
2262 #ifdef TIZEN_FEATURE_OMX
2263 if (gst_omx_port_tbm_allocate_dec_buffers (self->dec_in_port,
2264 self->bufmgr, self->dec_in_port->use_buffer) != OMX_ErrorNone)
2267 if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2270 #ifndef TIZEN_FEATURE_OMX
2271 if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2272 if (gst_omx_port_set_enabled (self->dec_out_port, TRUE) != OMX_ErrorNone)
2274 if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2277 if (gst_omx_port_wait_enabled (self->dec_out_port,
2278 5 * GST_SECOND) != OMX_ErrorNone)
2282 if (gst_omx_port_wait_enabled (self->dec_in_port,
2283 5 * GST_SECOND) != OMX_ErrorNone)
2286 if (gst_omx_port_mark_reconfigured (self->dec_in_port) != OMX_ErrorNone)
2289 if (!gst_omx_video_dec_negotiate (self))
2290 GST_LOG_OBJECT (self, "Negotiation failed, will get output format later");
2292 if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2293 /* Disable output port */
2294 if (gst_omx_port_set_enabled (self->dec_out_port, FALSE) != OMX_ErrorNone)
2297 if (gst_omx_port_wait_enabled (self->dec_out_port,
2298 1 * GST_SECOND) != OMX_ErrorNone)
2301 if (gst_omx_component_set_state (self->dec,
2302 OMX_StateIdle) != OMX_ErrorNone)
2305 /* Need to allocate buffers to reach Idle state */
2306 #ifdef TIZEN_FEATURE_OMX
2307 if (gst_omx_port_tbm_allocate_dec_buffers (self->dec_in_port,
2308 self->bufmgr, self->dec_in_port->use_buffer) != OMX_ErrorNone)
2310 if (gst_omx_port_tbm_allocate_dec_buffers (self->dec_out_port,
2311 self->bufmgr, self->dec_out_port->use_buffer) != OMX_ErrorNone)
2314 if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2316 if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2321 if (gst_omx_component_set_state (self->dec,
2322 OMX_StateIdle) != OMX_ErrorNone)
2325 /* Need to allocate buffers to reach Idle state */
2326 #ifdef TIZEN_FEATURE_OMX
2327 if (gst_omx_port_tbm_allocate_dec_buffers (self->dec_in_port,
2328 self->bufmgr, self->dec_in_port->use_buffer) != OMX_ErrorNone)
2330 if (gst_omx_port_tbm_allocate_dec_buffers (self->dec_out_port,
2331 self->bufmgr, self->dec_out_port->use_buffer) != OMX_ErrorNone)
2334 if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2336 if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2341 if (gst_omx_component_get_state (self->dec,
2342 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2345 if (gst_omx_component_set_state (self->dec,
2346 OMX_StateExecuting) != OMX_ErrorNone)
2349 if (gst_omx_component_get_state (self->dec,
2350 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2354 /* Unset flushing to allow ports to accept data again */
2355 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2356 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2358 if (gst_omx_component_get_last_error (self->dec) != OMX_ErrorNone) {
2359 GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2360 gst_omx_component_get_last_error_string (self->dec),
2361 gst_omx_component_get_last_error (self->dec));
2365 self->downstream_flow_ret = GST_FLOW_OK;
2370 gst_omx_video_dec_flush (GstVideoDecoder * decoder)
2372 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
2373 OMX_ERRORTYPE err = OMX_ErrorNone;
2375 GST_DEBUG_OBJECT (self, "Flushing decoder");
2377 if (gst_omx_component_get_state (self->dec, 0) == OMX_StateLoaded)
2380 /* 0) Pause the components */
2381 if (gst_omx_component_get_state (self->dec, 0) == OMX_StateExecuting) {
2382 gst_omx_component_set_state (self->dec, OMX_StatePause);
2383 gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2385 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2386 if (self->eglimage) {
2387 if (gst_omx_component_get_state (self->egl_render, 0) == OMX_StateExecuting) {
2388 gst_omx_component_set_state (self->egl_render, OMX_StatePause);
2389 gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2394 /* 1) Wait until the srcpad loop is stopped,
2395 * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
2396 * caused by using this lock from inside the loop function */
2397 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2398 gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
2399 GST_DEBUG_OBJECT (self, "Flushing -- task stopped");
2400 GST_VIDEO_DECODER_STREAM_LOCK (self);
2402 /* 2) Flush the ports */
2403 GST_DEBUG_OBJECT (self, "flushing ports");
2404 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2405 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2407 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2408 if (self->eglimage) {
2409 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2410 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2414 /* 3) Resume components */
2415 gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2416 gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2417 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2418 if (self->eglimage) {
2419 gst_omx_component_set_state (self->egl_render, OMX_StateExecuting);
2420 gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2424 /* 4) Unset flushing to allow ports to accept data again */
2425 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2426 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2428 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2429 if (self->eglimage) {
2430 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
2431 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
2432 err = gst_omx_port_populate (self->egl_out_port);
2433 gst_omx_port_mark_reconfigured (self->egl_out_port);
2435 err = gst_omx_port_populate (self->dec_out_port);
2438 err = gst_omx_port_populate (self->dec_out_port);
2441 if (err != OMX_ErrorNone) {
2442 GST_WARNING_OBJECT (self, "Failed to populate output port: %s (0x%08x)",
2443 gst_omx_error_to_string (err), err);
2446 /* Reset our state */
2447 self->last_upstream_ts = 0;
2448 self->downstream_flow_ret = GST_FLOW_OK;
2449 self->started = FALSE;
2450 GST_DEBUG_OBJECT (self, "Flush finished");
2455 static GstFlowReturn
2456 gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
2457 GstVideoCodecFrame * frame)
2459 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2460 GstOMXVideoDec *self;
2461 GstOMXVideoDecClass *klass;
2464 GstBuffer *codec_data = NULL;
2465 guint offset = 0, size;
2466 GstClockTime timestamp, duration;
2469 self = GST_OMX_VIDEO_DEC (decoder);
2470 klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2472 GST_DEBUG_OBJECT (self, "Handling frame");
2474 if (!self->started) {
2475 if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
2476 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
2479 GST_DEBUG_OBJECT (self, "Starting task");
2480 gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
2481 (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL);
2484 timestamp = frame->pts;
2485 duration = frame->duration;
2487 if (self->downstream_flow_ret != GST_FLOW_OK) {
2488 gst_video_codec_frame_unref (frame);
2489 return self->downstream_flow_ret;
2492 if (klass->prepare_frame) {
2495 ret = klass->prepare_frame (self, frame);
2496 if (ret != GST_FLOW_OK) {
2497 GST_ERROR_OBJECT (self, "Preparing frame failed: %s",
2498 gst_flow_get_name (ret));
2499 gst_video_codec_frame_unref (frame);
2504 port = self->dec_in_port;
2506 size = gst_buffer_get_size (frame->input_buffer);
2507 while (offset < size) {
2508 /* Make sure to release the base class stream lock, otherwise
2509 * _loop() can't call _finish_frame() and we might block forever
2510 * because no input buffers are released */
2511 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2512 acq_ret = gst_omx_port_acquire_buffer (port, &buf);
2514 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
2515 GST_VIDEO_DECODER_STREAM_LOCK (self);
2516 goto component_error;
2517 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
2518 GST_VIDEO_DECODER_STREAM_LOCK (self);
2520 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
2521 /* Reallocate all buffers */
2522 err = gst_omx_port_set_enabled (port, FALSE);
2523 if (err != OMX_ErrorNone) {
2524 GST_VIDEO_DECODER_STREAM_LOCK (self);
2525 goto reconfigure_error;
2528 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
2529 if (err != OMX_ErrorNone) {
2530 GST_VIDEO_DECODER_STREAM_LOCK (self);
2531 goto reconfigure_error;
2534 err = gst_omx_port_deallocate_buffers (port);
2535 if (err != OMX_ErrorNone) {
2536 GST_VIDEO_DECODER_STREAM_LOCK (self);
2537 goto reconfigure_error;
2540 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
2541 if (err != OMX_ErrorNone) {
2542 GST_VIDEO_DECODER_STREAM_LOCK (self);
2543 goto reconfigure_error;
2546 err = gst_omx_port_set_enabled (port, TRUE);
2547 if (err != OMX_ErrorNone) {
2548 GST_VIDEO_DECODER_STREAM_LOCK (self);
2549 goto reconfigure_error;
2551 #ifdef TIZEN_FEATURE_OMX
2552 err = gst_omx_port_tbm_allocate_dec_buffers (port, self->bufmgr, port->use_buffer);
2554 err = gst_omx_port_allocate_buffers (port);
2556 if (err != OMX_ErrorNone) {
2557 GST_VIDEO_DECODER_STREAM_LOCK (self);
2558 goto reconfigure_error;
2561 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
2562 if (err != OMX_ErrorNone) {
2563 GST_VIDEO_DECODER_STREAM_LOCK (self);
2564 goto reconfigure_error;
2567 err = gst_omx_port_mark_reconfigured (port);
2568 if (err != OMX_ErrorNone) {
2569 GST_VIDEO_DECODER_STREAM_LOCK (self);
2570 goto reconfigure_error;
2573 /* Now get a new buffer and fill it */
2574 GST_VIDEO_DECODER_STREAM_LOCK (self);
2577 GST_VIDEO_DECODER_STREAM_LOCK (self);
2579 g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
2581 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
2582 gst_omx_port_release_buffer (port, buf);
2586 if (self->downstream_flow_ret != GST_FLOW_OK) {
2587 gst_omx_port_release_buffer (port, buf);
2591 if (self->codec_data) {
2592 GST_DEBUG_OBJECT (self, "Passing codec data to the component");
2594 codec_data = self->codec_data;
2596 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <
2597 gst_buffer_get_size (codec_data)) {
2598 gst_omx_port_release_buffer (port, buf);
2599 goto too_large_codec_data;
2602 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
2603 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2604 buf->omx_buf->nFilledLen = gst_buffer_get_size (codec_data);;
2606 #ifdef TIZEN_FEATURE_OMX
2607 if (port->use_buffer) {
2608 gst_buffer_extract (codec_data, 0,
2609 (OMX_U8 *) buf->mm_vbuffer->data[0] + buf->omx_buf->nOffset,
2610 buf->omx_buf->nFilledLen);
2612 gst_buffer_extract (codec_data, 0,
2613 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2614 buf->omx_buf->nFilledLen);
2616 #ifdef CODEC_DEC_INTPUT_DUMP
2617 decoder_input_dump (buf, port->use_buffer);
2621 if (GST_CLOCK_TIME_IS_VALID (timestamp))
2622 buf->omx_buf->nTimeStamp =
2623 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
2625 buf->omx_buf->nTimeStamp = 0;
2626 buf->omx_buf->nTickCount = 0;
2628 self->started = TRUE;
2629 err = gst_omx_port_release_buffer (port, buf);
2630 gst_buffer_replace (&self->codec_data, NULL);
2631 if (err != OMX_ErrorNone)
2633 /* Acquire new buffer for the actual frame */
2637 /* Now handle the frame */
2638 GST_DEBUG_OBJECT (self, "Passing frame offset %d to the component", offset);
2640 /* Copy the buffer content in chunks of size as requested
2642 buf->omx_buf->nFilledLen =
2643 MIN (size - offset, buf->omx_buf->nAllocLen - buf->omx_buf->nOffset);
2644 GST_DEBUG_OBJECT (self, "nFilledLen %lu, %p", buf->omx_buf->nFilledLen, buf->omx_buf->pBuffer);
2646 #ifdef TIZEN_FEATURE_OMX
2647 if (port->use_buffer) {
2648 gst_buffer_extract (frame->input_buffer, offset,
2649 (OMX_U8 *) buf->mm_vbuffer->data[0] + buf->omx_buf->nOffset,
2650 buf->omx_buf->nFilledLen);
2652 gst_buffer_extract (frame->input_buffer, offset,
2653 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2654 buf->omx_buf->nFilledLen);
2656 #ifdef CODEC_DEC_INTPUT_DUMP
2657 decoder_input_dump (buf, port->use_buffer);
2660 if (timestamp != GST_CLOCK_TIME_NONE) {
2661 buf->omx_buf->nTimeStamp =
2662 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
2663 self->last_upstream_ts = timestamp;
2665 buf->omx_buf->nTimeStamp = 0;
2668 if (duration != GST_CLOCK_TIME_NONE && offset == 0) {
2669 buf->omx_buf->nTickCount =
2670 gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
2671 self->last_upstream_ts += duration;
2673 buf->omx_buf->nTickCount = 0;
2676 if (offset == 0 && GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
2677 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
2680 * - OMX_BUFFERFLAG_DECODEONLY for buffers that are outside
2684 offset += buf->omx_buf->nFilledLen;
2687 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2689 self->started = TRUE;
2690 err = gst_omx_port_release_buffer (port, buf);
2691 if (err != OMX_ErrorNone)
2695 gst_video_codec_frame_unref (frame);
2697 GST_DEBUG_OBJECT (self, "Passed frame to component");
2699 return self->downstream_flow_ret;
2703 gst_video_codec_frame_unref (frame);
2704 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2705 ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
2706 (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
2707 return GST_FLOW_ERROR;
2712 gst_video_codec_frame_unref (frame);
2714 return self->downstream_flow_ret;
2717 too_large_codec_data:
2719 gst_video_codec_frame_unref (frame);
2720 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2721 ("codec_data larger than supported by OpenMAX port "
2722 "(%" G_GSIZE_FORMAT " > %u)", gst_buffer_get_size (codec_data),
2723 (guint) self->dec_in_port->port_def.nBufferSize));
2724 return GST_FLOW_ERROR;
2729 gst_video_codec_frame_unref (frame);
2730 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2731 ("OpenMAX component in error state %s (0x%08x)",
2732 gst_omx_component_get_last_error_string (self->dec),
2733 gst_omx_component_get_last_error (self->dec)));
2734 return GST_FLOW_ERROR;
2739 gst_video_codec_frame_unref (frame);
2740 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
2741 return GST_FLOW_FLUSHING;
2745 gst_video_codec_frame_unref (frame);
2746 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2747 ("Unable to reconfigure input port"));
2748 return GST_FLOW_ERROR;
2752 gst_video_codec_frame_unref (frame);
2753 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2754 ("Failed to relase input buffer to component: %s (0x%08x)",
2755 gst_omx_error_to_string (err), err));
2756 return GST_FLOW_ERROR;
2760 static GstFlowReturn
2761 gst_omx_video_dec_finish (GstVideoDecoder * decoder)
2763 GstOMXVideoDec *self;
2765 self = GST_OMX_VIDEO_DEC (decoder);
2767 return gst_omx_video_dec_drain (self);
2770 static GstFlowReturn
2771 gst_omx_video_dec_drain (GstOMXVideoDec * self)
2773 GstOMXVideoDecClass *klass;
2775 GstOMXAcquireBufferReturn acq_ret;
2778 GST_DEBUG_OBJECT (self, "Draining component");
2780 klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2782 if (!self->started) {
2783 GST_DEBUG_OBJECT (self, "Component not started yet");
2786 self->started = FALSE;
2788 if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
2789 GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
2793 /* Make sure to release the base class stream lock, otherwise
2794 * _loop() can't call _finish_frame() and we might block forever
2795 * because no input buffers are released */
2796 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2798 /* Send an EOS buffer to the component and let the base
2799 * class drop the EOS event. We will send it later when
2800 * the EOS buffer arrives on the output port. */
2801 acq_ret = gst_omx_port_acquire_buffer (self->dec_in_port, &buf);
2802 if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
2803 GST_VIDEO_DECODER_STREAM_LOCK (self);
2804 GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
2806 return GST_FLOW_ERROR;
2809 g_mutex_lock (&self->drain_lock);
2810 self->draining = TRUE;
2811 buf->omx_buf->nFilledLen = 0;
2812 buf->omx_buf->nTimeStamp =
2813 gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
2815 buf->omx_buf->nTickCount = 0;
2816 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
2817 err = gst_omx_port_release_buffer (self->dec_in_port, buf);
2818 if (err != OMX_ErrorNone) {
2819 GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
2820 gst_omx_error_to_string (err), err);
2821 g_mutex_unlock (&self->drain_lock);
2822 GST_VIDEO_DECODER_STREAM_LOCK (self);
2823 return GST_FLOW_ERROR;
2826 GST_DEBUG_OBJECT (self, "Waiting until component is drained");
2828 if (G_UNLIKELY (self->dec->hacks & GST_OMX_HACK_DRAIN_MAY_NOT_RETURN)) {
2829 gint64 wait_until = g_get_monotonic_time () + G_TIME_SPAN_SECOND / 2;
2831 if (!g_cond_wait_until (&self->drain_cond, &self->drain_lock, wait_until))
2832 GST_WARNING_OBJECT (self, "Drain timed out");
2834 GST_DEBUG_OBJECT (self, "Drained component");
2837 g_cond_wait (&self->drain_cond, &self->drain_lock);
2838 GST_DEBUG_OBJECT (self, "Drained component");
2841 g_mutex_unlock (&self->drain_lock);
2842 GST_VIDEO_DECODER_STREAM_LOCK (self);
2844 self->started = FALSE;
2850 gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
2852 GstBufferPool *pool;
2853 GstStructure *config;
2855 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2861 gst_query_parse_allocation (query, &caps, NULL);
2862 if (caps && gst_video_info_from_caps (&info, caps)
2863 && info.finfo->format == GST_VIDEO_FORMAT_RGBA) {
2864 gboolean found = FALSE;
2865 GstCapsFeatures *feature = gst_caps_get_features (caps, 0);
2866 /* Prefer an EGLImage allocator if available and we want to use it */
2867 n = gst_query_get_n_allocation_params (query);
2868 for (i = 0; i < n; i++) {
2869 GstAllocator *allocator;
2870 GstAllocationParams params;
2872 gst_query_parse_nth_allocation_param (query, i, &allocator, ¶ms);
2874 if (g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0) {
2876 gst_query_set_nth_allocation_param (query, 0, allocator, ¶ms);
2877 while (gst_query_get_n_allocation_params (query) > 1)
2878 gst_query_remove_nth_allocation_param (query, 1);
2881 gst_object_unref (allocator);
2888 /* if try to negotiate with caps feature memory:EGLImage
2889 * and if allocator is not of type memory EGLImage then fails */
2891 && gst_caps_features_contains (feature,
2892 GST_CAPS_FEATURE_MEMORY_EGL_IMAGE) && !found) {
2899 if (!GST_VIDEO_DECODER_CLASS
2900 (gst_omx_video_dec_parent_class)->decide_allocation (bdec, query))
2903 g_assert (gst_query_get_n_allocation_pools (query) > 0);
2904 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
2905 g_assert (pool != NULL);
2907 config = gst_buffer_pool_get_config (pool);
2908 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
2909 gst_buffer_pool_config_add_option (config,
2910 GST_BUFFER_POOL_OPTION_VIDEO_META);
2912 gst_buffer_pool_set_config (pool, config);
2913 gst_object_unref (pool);
2918 #ifdef TIZEN_FEATURE_OMX
2920 gst_omx_video_dec_acquire_request_flush_buffer (GstOMXVideoDec * self, GstBuffer ** flush_request_buffer)
2922 guint8 *dummy_data = NULL;
2923 GstBuffer *buf = NULL;
2924 MMVideoBuffer *mm_vbuffer = NULL;
2926 GST_DEBUG_OBJECT (self, "flush buffer request");
2928 if (self->out_port_pool) {
2929 if (gst_buffer_pool_is_active(self->out_port_pool)) {
2930 dummy_data = g_malloc0(128*128);
2931 buf = gst_buffer_new_wrapped(dummy_data, 128*128);
2932 mm_vbuffer = g_malloc(sizeof(MMVideoBuffer));
2934 mm_vbuffer->type = MM_VIDEO_BUFFER_TYPE_TBM_BO;
2935 mm_vbuffer->size[0] = 0;
2936 mm_vbuffer->flush_request = TRUE;
2938 gst_buffer_append_memory(buf,
2939 gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, mm_vbuffer, sizeof(MMVideoBuffer), 0,
2940 sizeof(MMVideoBuffer), mm_vbuffer, g_free));
2942 *flush_request_buffer = buf;
2944 GST_DEBUG_OBJECT (self, "flush buffer requested");
2947 GST_DEBUG_OBJECT (self, "the out port pool has not yet been activated");
2951 GST_DEBUG_OBJECT (self, "the output port has not yet been activated");
2957 gst_omx_video_dec_handle_event (GstVideoDecoder * decoder,
2960 GstOMXVideoDec *self;
2962 self = GST_OMX_VIDEO_DEC (decoder);
2964 GST_DEBUG_OBJECT (self, "event: %s", GST_EVENT_TYPE_NAME (event));
2966 switch (GST_EVENT_TYPE (event)) {
2967 case GST_EVENT_FLUSH_START:
2969 gst_omx_port_flush_start (self->dec_in_port, TRUE);
2970 gst_omx_port_flush_start (self->dec_out_port, TRUE);
2973 case GST_EVENT_FLUSH_STOP:
2975 gst_omx_port_flush_start (self->dec_in_port, FALSE);
2976 gst_omx_port_flush_start (self->dec_out_port, FALSE);
2983 return GST_VIDEO_DECODER_CLASS (gst_omx_video_dec_parent_class)->sink_event (decoder, event);