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_OUTPUT_DUMP
53 #include "gstomxbufferpool.h"
54 #include "gstomxvideo.h"
55 #include "gstomxvideodec.h"
57 GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category);
58 #define GST_CAT_DEFAULT gst_omx_video_dec_debug_category
61 static void gst_omx_video_dec_finalize (GObject * object);
63 static GstStateChangeReturn
64 gst_omx_video_dec_change_state (GstElement * element,
65 GstStateChange transition);
67 static gboolean gst_omx_video_dec_open (GstVideoDecoder * decoder);
68 static gboolean gst_omx_video_dec_close (GstVideoDecoder * decoder);
69 static gboolean gst_omx_video_dec_start (GstVideoDecoder * decoder);
70 static gboolean gst_omx_video_dec_stop (GstVideoDecoder * decoder);
71 static gboolean gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
72 GstVideoCodecState * state);
73 static gboolean gst_omx_video_dec_flush (GstVideoDecoder * decoder);
74 static GstFlowReturn gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
75 GstVideoCodecFrame * frame);
76 static GstFlowReturn gst_omx_video_dec_finish (GstVideoDecoder * decoder);
77 static gboolean gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec,
80 static GstFlowReturn gst_omx_video_dec_drain (GstOMXVideoDec * self);
82 static OMX_ERRORTYPE gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec *
84 static OMX_ERRORTYPE gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec
92 /* class initialization */
95 GST_DEBUG_CATEGORY_INIT (gst_omx_video_dec_debug_category, "omxvideodec", 0, \
96 "debug category for gst-omx video decoder base class");
99 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec,
100 GST_TYPE_VIDEO_DECODER, DEBUG_INIT);
103 gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
105 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
106 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
107 GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass);
109 gobject_class->finalize = gst_omx_video_dec_finalize;
111 element_class->change_state =
112 GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state);
114 video_decoder_class->open = GST_DEBUG_FUNCPTR (gst_omx_video_dec_open);
115 video_decoder_class->close = GST_DEBUG_FUNCPTR (gst_omx_video_dec_close);
116 video_decoder_class->start = GST_DEBUG_FUNCPTR (gst_omx_video_dec_start);
117 video_decoder_class->stop = GST_DEBUG_FUNCPTR (gst_omx_video_dec_stop);
118 video_decoder_class->flush = GST_DEBUG_FUNCPTR (gst_omx_video_dec_flush);
119 video_decoder_class->set_format =
120 GST_DEBUG_FUNCPTR (gst_omx_video_dec_set_format);
121 video_decoder_class->handle_frame =
122 GST_DEBUG_FUNCPTR (gst_omx_video_dec_handle_frame);
123 video_decoder_class->finish = GST_DEBUG_FUNCPTR (gst_omx_video_dec_finish);
124 video_decoder_class->decide_allocation =
125 GST_DEBUG_FUNCPTR (gst_omx_video_dec_decide_allocation);
127 klass->cdata.type = GST_OMX_COMPONENT_TYPE_FILTER;
128 klass->cdata.default_src_template_caps =
129 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
130 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
134 "width = " GST_VIDEO_SIZE_RANGE ", "
135 "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE;
139 gst_omx_video_dec_init (GstOMXVideoDec * self)
141 gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE);
142 gst_video_decoder_set_use_default_pad_acceptcaps (GST_VIDEO_DECODER_CAST
144 GST_PAD_SET_ACCEPT_TEMPLATE (GST_VIDEO_DECODER_SINK_PAD (self));
146 g_mutex_init (&self->drain_lock);
147 g_cond_init (&self->drain_cond);
149 #ifdef GST_TIZEN_MODIFICATION
150 self->hTBMBufMgr = NULL;
156 gst_omx_video_dec_open (GstVideoDecoder * decoder)
158 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
159 GstOMXVideoDecClass *klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
160 gint in_port_index, out_port_index;
162 GST_DEBUG_OBJECT (self, "Opening decoder");
165 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
166 klass->cdata.component_name, klass->cdata.component_role,
168 self->started = FALSE;
173 if (gst_omx_component_get_state (self->dec,
174 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
177 in_port_index = klass->cdata.in_port_index;
178 out_port_index = klass->cdata.out_port_index;
180 if (in_port_index == -1 || out_port_index == -1) {
181 OMX_PORT_PARAM_TYPE param;
184 GST_OMX_INIT_STRUCT (¶m);
187 gst_omx_component_get_parameter (self->dec, OMX_IndexParamVideoInit,
189 if (err != OMX_ErrorNone) {
190 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
191 gst_omx_error_to_string (err), err);
196 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u",
197 (guint) param.nPorts, (guint) param.nStartPortNumber);
198 in_port_index = param.nStartPortNumber + 0;
199 out_port_index = param.nStartPortNumber + 1;
202 self->dec_in_port = gst_omx_component_add_port (self->dec, in_port_index);
203 self->dec_out_port = gst_omx_component_add_port (self->dec, out_port_index);
205 if (!self->dec_in_port || !self->dec_out_port)
208 #ifdef GST_TIZEN_MODIFICATION
210 self->hTBMBufMgr = tbm_bufmgr_init(self->drm_fd);
211 if(self->hTBMBufMgr == NULL){
212 GST_ERROR_OBJECT (self, "TBM initialization failed.");
216 GST_DEBUG_OBJECT (self, "Opened decoder");
218 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
219 GST_DEBUG_OBJECT (self, "Opening EGL renderer");
221 gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
222 "OMX.broadcom.egl_render", NULL, klass->cdata.hacks);
224 if (!self->egl_render)
227 if (gst_omx_component_get_state (self->egl_render,
228 GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
232 OMX_PORT_PARAM_TYPE param;
235 GST_OMX_INIT_STRUCT (¶m);
238 gst_omx_component_get_parameter (self->egl_render,
239 OMX_IndexParamVideoInit, ¶m);
240 if (err != OMX_ErrorNone) {
241 GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
242 gst_omx_error_to_string (err), err);
247 GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u", param.nPorts,
248 param.nStartPortNumber);
249 in_port_index = param.nStartPortNumber + 0;
250 out_port_index = param.nStartPortNumber + 1;
255 gst_omx_component_add_port (self->egl_render, in_port_index);
257 gst_omx_component_add_port (self->egl_render, out_port_index);
259 if (!self->egl_in_port || !self->egl_out_port)
262 GST_DEBUG_OBJECT (self, "Opened EGL renderer");
269 gst_omx_video_dec_shutdown (GstOMXVideoDec * self)
273 GST_DEBUG_OBJECT (self, "Shutting down decoder");
275 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
276 state = gst_omx_component_get_state (self->egl_render, 0);
277 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
278 if (state > OMX_StateIdle) {
279 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
280 gst_omx_component_set_state (self->dec, OMX_StateIdle);
281 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
282 gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
284 gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
285 gst_omx_component_set_state (self->dec, OMX_StateLoaded);
287 gst_omx_port_deallocate_buffers (self->dec_in_port);
288 gst_omx_video_dec_deallocate_output_buffers (self);
289 gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
290 if (state > OMX_StateLoaded) {
291 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
292 gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
296 /* Otherwise we didn't use EGL and just fall back to
297 * shutting down the decoder */
300 state = gst_omx_component_get_state (self->dec, 0);
301 if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
302 if (state > OMX_StateIdle) {
303 gst_omx_component_set_state (self->dec, OMX_StateIdle);
304 gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
306 gst_omx_component_set_state (self->dec, OMX_StateLoaded);
307 gst_omx_port_deallocate_buffers (self->dec_in_port);
308 gst_omx_video_dec_deallocate_output_buffers (self);
309 if (state > OMX_StateLoaded)
310 gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
313 #ifdef GST_TIZEN_MODIFICATION
314 /* uninitialize tbm buffer manager */
315 if(self->hTBMBufMgr != NULL){
316 tbm_bufmgr_deinit(self->hTBMBufMgr);
317 self->hTBMBufMgr = NULL;
320 if(self->drm_fd != -1) {
321 GST_DEBUG_OBJECT (self, "close drm fd");
331 gst_omx_video_dec_close (GstVideoDecoder * decoder)
333 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
335 GST_DEBUG_OBJECT (self, "Closing decoder");
337 if (!gst_omx_video_dec_shutdown (self))
340 self->dec_in_port = NULL;
341 self->dec_out_port = NULL;
343 gst_omx_component_free (self->dec);
346 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
347 self->egl_in_port = NULL;
348 self->egl_out_port = NULL;
349 if (self->egl_render)
350 gst_omx_component_free (self->egl_render);
351 self->egl_render = NULL;
354 self->started = FALSE;
356 GST_DEBUG_OBJECT (self, "Closed decoder");
362 gst_omx_video_dec_finalize (GObject * object)
364 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
366 g_mutex_clear (&self->drain_lock);
367 g_cond_clear (&self->drain_cond);
369 G_OBJECT_CLASS (gst_omx_video_dec_parent_class)->finalize (object);
372 static GstStateChangeReturn
373 gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition)
375 GstOMXVideoDec *self;
376 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
378 g_return_val_if_fail (GST_IS_OMX_VIDEO_DEC (element),
379 GST_STATE_CHANGE_FAILURE);
380 self = GST_OMX_VIDEO_DEC (element);
382 switch (transition) {
383 case GST_STATE_CHANGE_NULL_TO_READY:
385 case GST_STATE_CHANGE_READY_TO_PAUSED:
386 self->downstream_flow_ret = GST_FLOW_OK;
387 self->draining = FALSE;
388 self->started = FALSE;
390 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
392 case GST_STATE_CHANGE_PAUSED_TO_READY:
393 if (self->dec_in_port)
394 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
395 if (self->dec_out_port)
396 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
397 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
398 if (self->egl_in_port)
399 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
400 if (self->egl_out_port)
401 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
404 g_mutex_lock (&self->drain_lock);
405 self->draining = FALSE;
406 g_cond_broadcast (&self->drain_cond);
407 g_mutex_unlock (&self->drain_lock);
413 if (ret == GST_STATE_CHANGE_FAILURE)
417 GST_ELEMENT_CLASS (gst_omx_video_dec_parent_class)->change_state
418 (element, transition);
420 if (ret == GST_STATE_CHANGE_FAILURE)
423 switch (transition) {
424 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
426 case GST_STATE_CHANGE_PAUSED_TO_READY:
427 self->downstream_flow_ret = GST_FLOW_FLUSHING;
428 self->started = FALSE;
430 if (!gst_omx_video_dec_shutdown (self))
431 ret = GST_STATE_CHANGE_FAILURE;
433 case GST_STATE_CHANGE_READY_TO_NULL:
442 #ifdef CODEC_DEC_OUTPUT_DUMP /* for decoder output dump */
444 decoder_output_dump(GstOMXVideoDec *self, MMVideoBuffer *outbuf)
446 char *temp = (char *)outbuf->data[0];
448 char filename[100]={0};
452 GST_ERROR_OBJECT (self, "codec dec output dump start. w = %d, h = %d", outbuf->width[0], outbuf->height[0]);
454 sprintf(filename, "/tmp/dec_output_dump_%d_%d.yuv", outbuf->stride_width[0], outbuf->height[0]);
455 fp = fopen(filename, "ab");
457 for (i = 0; i < outbuf->height[0]; i++) {
458 ret = fwrite(temp, outbuf->width[0], 1, fp);
459 temp += outbuf->stride_width[0];
462 temp = (char *)outbuf->data[1];
464 for(i = 0; i < outbuf->height[1]; i++) {
465 ret = fwrite(temp, outbuf->width[1], 1, fp);
466 temp += outbuf->stride_width[1];
469 GST_ERROR_OBJECT (self,"codec dec output dumped!! ret = %d", ret);
475 gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self,
476 GstOMXBuffer * inbuf, GstBuffer * outbuf)
478 GstVideoCodecState *state =
479 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
480 GstVideoInfo *vinfo = &state->info;
481 OMX_PARAM_PORTDEFINITIONTYPE *port_def = &self->dec_out_port->port_def;
482 gboolean ret = FALSE;
485 if (vinfo->width != port_def->format.video.nFrameWidth ||
486 vinfo->height != port_def->format.video.nFrameHeight) {
487 GST_ERROR_OBJECT (self, "Resolution do not match: port=%ux%u vinfo=%dx%d",
488 (guint) port_def->format.video.nFrameWidth,
489 (guint) port_def->format.video.nFrameHeight,
490 vinfo->width, vinfo->height);
494 /* Same strides and everything */
496 if (gst_buffer_get_size (outbuf) == inbuf->omx_buf->nFilledLen) {
497 GstMapInfo map = GST_MAP_INFO_INIT;
499 if (!gst_buffer_map (outbuf, &map, GST_MAP_WRITE)) {
500 GST_ERROR_OBJECT (self, "Failed to map output buffer");
505 inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset,
506 inbuf->omx_buf->nFilledLen);
507 gst_buffer_unmap (outbuf, &map);
513 /* Different strides */
514 if (gst_video_frame_map (&frame, vinfo, outbuf, GST_MAP_WRITE)) {
515 const guint nstride = port_def->format.video.nStride;
516 const guint nslice = port_def->format.video.nSliceHeight;
517 guint src_stride[GST_VIDEO_MAX_PLANES] = { nstride, 0, };
518 guint src_size[GST_VIDEO_MAX_PLANES] = { nstride * nslice, 0, };
519 gint dst_width[GST_VIDEO_MAX_PLANES] = { 0, };
520 gint dst_height[GST_VIDEO_MAX_PLANES] =
521 { GST_VIDEO_INFO_HEIGHT (vinfo), 0, };
525 switch (GST_VIDEO_INFO_FORMAT (vinfo)) {
526 case GST_VIDEO_FORMAT_ABGR:
527 case GST_VIDEO_FORMAT_ARGB:
528 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 4;
530 case GST_VIDEO_FORMAT_RGB16:
531 case GST_VIDEO_FORMAT_BGR16:
532 case GST_VIDEO_FORMAT_YUY2:
533 case GST_VIDEO_FORMAT_UYVY:
534 case GST_VIDEO_FORMAT_YVYU:
535 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo) * 2;
537 case GST_VIDEO_FORMAT_GRAY8:
538 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
540 case GST_VIDEO_FORMAT_I420:
541 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
542 src_stride[1] = nstride / 2;
543 src_size[1] = (src_stride[1] * nslice) / 2;
544 dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
545 dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
546 src_stride[2] = nstride / 2;
547 src_size[2] = (src_stride[1] * nslice) / 2;
548 dst_width[2] = GST_VIDEO_INFO_WIDTH (vinfo) / 2;
549 dst_height[2] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
551 case GST_VIDEO_FORMAT_NV12:
552 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
553 src_stride[1] = nstride;
554 src_size[1] = src_stride[1] * nslice / 2;
555 dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
556 dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo) / 2;
558 case GST_VIDEO_FORMAT_NV16:
559 dst_width[0] = GST_VIDEO_INFO_WIDTH (vinfo);
560 src_stride[1] = nstride;
561 src_size[1] = src_stride[1] * nslice;
562 dst_width[1] = GST_VIDEO_INFO_WIDTH (vinfo);
563 dst_height[1] = GST_VIDEO_INFO_HEIGHT (vinfo);
565 case GST_VIDEO_FORMAT_SN12:
566 case GST_VIDEO_FORMAT_ST12:{
567 GstMemory *mem_imgb = NULL;
568 void *imgb_data = NULL;
569 #ifdef GST_TIZEN_MODIFICATION
570 MMVideoBuffer *mm_vbuffer = NULL;
571 mm_vbuffer = (MMVideoBuffer*)(inbuf->omx_buf->pBuffer);
572 mm_vbuffer->type = MM_VIDEO_BUFFER_TYPE_TBM_BO;
574 if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
575 GST_LOG_OBJECT (self, "dec output buf: fd[0]:%d fd[1]:%d fd[2]:%d w[0]:%d h[0]:%d buf_share_method:%d",
576 mm_vbuffer->handle.dmabuf_fd[0], mm_vbuffer->handle.dmabuf_fd[1], mm_vbuffer->handle.dmabuf_fd[2],
577 mm_vbuffer->width[0], mm_vbuffer->height[0], mm_vbuffer->type);
578 } else if (mm_vbuffer->type == MM_VIDEO_BUFFER_TYPE_PHYSICAL_ADDRESS) {
579 GST_LOG_OBJECT (self, "dec output uses hw addr");
581 GST_WARNING_OBJECT (self, "dec output buf has TBM_BO buf_share_method");
583 #ifdef CODEC_DEC_OUTPUT_DUMP
584 decoder_output_dump(self, mm_vbuffer);
587 if (gst_buffer_n_memory(outbuf) < 2) {
588 imgb_data = g_malloc0(sizeof(*mm_vbuffer));
589 mem_imgb = gst_memory_new_wrapped(0, imgb_data, sizeof(*mm_vbuffer), 0, sizeof(*mm_vbuffer), imgb_data, g_free);
590 gst_buffer_append_memory(outbuf, mem_imgb);
592 GstMapInfo imgb_info = GST_MAP_INFO_INIT;
593 mem_imgb = gst_buffer_peek_memory(outbuf, 1);
594 gst_memory_map(mem_imgb, &imgb_info, GST_MAP_WRITE);
595 imgb_data = imgb_info.data;
596 gst_memory_unmap(mem_imgb, &imgb_info);
598 #ifdef GST_TIZEN_MODIFICATION
599 memcpy(imgb_data, mm_vbuffer, sizeof(MMVideoBuffer));
606 g_assert_not_reached ();
610 src = inbuf->omx_buf->pBuffer + inbuf->omx_buf->nOffset;
611 for (p = 0; p < GST_VIDEO_INFO_N_PLANES (vinfo); p++) {
616 dst = GST_VIDEO_FRAME_PLANE_DATA (&frame, p);
618 for (h = 0; h < dst_height[p]; h++) {
619 memcpy (dst, data, dst_width[p]);
620 dst += GST_VIDEO_INFO_PLANE_STRIDE (vinfo, p);
621 data += src_stride[p];
626 gst_video_frame_unmap (&frame);
629 GST_ERROR_OBJECT (self, "Can't map output buffer to frame");
635 GST_BUFFER_PTS (outbuf) =
636 gst_util_uint64_scale (inbuf->omx_buf->nTimeStamp, GST_SECOND,
637 OMX_TICKS_PER_SECOND);
638 if (inbuf->omx_buf->nTickCount != 0)
639 GST_BUFFER_DURATION (outbuf) =
640 gst_util_uint64_scale (inbuf->omx_buf->nTickCount, GST_SECOND,
641 OMX_TICKS_PER_SECOND);
644 gst_video_codec_state_unref (state);
650 gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
652 OMX_ERRORTYPE err = OMX_ErrorNone;
654 GstBufferPool *pool = NULL;
655 GstStructure *config;
656 gboolean eglimage = FALSE, add_videometa = FALSE;
657 GstCaps *caps = NULL;
658 guint min = 0, max = 0;
659 GstVideoCodecState *state =
660 gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
662 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
663 port = self->eglimage ? self->egl_out_port : self->dec_out_port;
665 port = self->dec_out_port;
668 pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
670 GstAllocator *allocator;
672 config = gst_buffer_pool_get_config (pool);
673 if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min, &max)) {
674 GST_ERROR_OBJECT (self, "Can't get buffer pool params");
675 gst_structure_free (config);
676 err = OMX_ErrorUndefined;
679 if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) {
680 GST_ERROR_OBJECT (self, "Can't get buffer pool allocator");
681 gst_structure_free (config);
682 err = OMX_ErrorUndefined;
686 /* Need at least 2 buffers for anything meaningful */
687 min = MAX (MAX (min, port->port_def.nBufferCountMin), 4);
690 } else if (max < port->port_def.nBufferCountMin || max < 2) {
691 /* Can't use pool because can't have enough buffers */
692 gst_caps_replace (&caps, NULL);
697 add_videometa = gst_buffer_pool_config_has_option (config,
698 GST_BUFFER_POOL_OPTION_VIDEO_META);
699 gst_structure_free (config);
701 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
702 eglimage = self->eglimage && (allocator
703 && g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0);
705 /* TODO: Implement something that works for other targets too */
708 caps = caps ? gst_caps_ref (caps) : NULL;
710 GST_DEBUG_OBJECT (self, "Trying to use pool %p with caps %" GST_PTR_FORMAT
711 " and memory type %s", pool, caps,
712 (allocator ? allocator->mem_type : "(null)"));
714 gst_caps_replace (&caps, NULL);
715 min = max = port->port_def.nBufferCountMin;
716 GST_DEBUG_OBJECT (self, "No pool available, not negotiated yet");
719 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
720 /* Will retry without EGLImage */
721 if (self->eglimage && !eglimage) {
722 GST_DEBUG_OBJECT (self,
723 "Wanted to use EGLImage but downstream doesn't support it");
724 err = OMX_ErrorUndefined;
730 self->out_port_pool =
731 gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port);
733 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
735 GList *buffers = NULL;
736 GList *images = NULL;
738 GstBufferPoolAcquireParams params = { 0, };
739 EGLDisplay egl_display = EGL_NO_DISPLAY;
741 GST_DEBUG_OBJECT (self, "Trying to allocate %d EGLImages", min);
743 for (i = 0; i < min; i++) {
747 if (gst_buffer_pool_acquire_buffer (pool, &buffer, ¶ms) != GST_FLOW_OK
748 || gst_buffer_n_memory (buffer) != 1
749 || !(mem = gst_buffer_peek_memory (buffer, 0))
750 || g_strcmp0 (mem->allocator->mem_type,
751 GST_EGL_IMAGE_MEMORY_TYPE) != 0) {
752 GST_INFO_OBJECT (self, "Failed to allocated %d-th EGLImage", i);
753 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
754 g_list_free (images);
757 /* TODO: For non-RPi targets we want to use the normal memory code below */
758 /* Retry without EGLImage */
759 err = OMX_ErrorUndefined;
763 buffers = g_list_append (buffers, buffer);
764 gst_egl_image_memory_set_orientation (mem,
765 GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP);
766 images = g_list_append (images, gst_egl_image_memory_get_image (mem));
767 if (egl_display == EGL_NO_DISPLAY)
768 egl_display = gst_egl_image_memory_get_display (mem);
771 GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min);
773 /* Everything went fine? */
775 GST_DEBUG_OBJECT (self, "Setting EGLDisplay");
776 self->egl_out_port->port_def.format.video.pNativeWindow = egl_display;
778 gst_omx_port_update_port_definition (self->egl_out_port,
779 &self->egl_out_port->port_def);
780 if (err != OMX_ErrorNone) {
781 GST_INFO_OBJECT (self,
782 "Failed to set EGLDisplay on port: %s (0x%08x)",
783 gst_omx_error_to_string (err), err);
784 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
785 g_list_free (images);
786 /* TODO: For non-RPi targets we want to use the normal memory code below */
787 /* Retry without EGLImage */
792 if (min != port->port_def.nBufferCountActual) {
793 err = gst_omx_port_update_port_definition (port, NULL);
794 if (err == OMX_ErrorNone) {
795 port->port_def.nBufferCountActual = min;
796 err = gst_omx_port_update_port_definition (port, &port->port_def);
799 if (err != OMX_ErrorNone) {
800 GST_INFO_OBJECT (self,
801 "Failed to configure %u output buffers: %s (0x%08x)", min,
802 gst_omx_error_to_string (err), err);
803 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
804 g_list_free (images);
805 /* TODO: For non-RPi targets we want to use the normal memory code below */
806 /* Retry without EGLImage */
812 if (!gst_omx_port_is_enabled (port)) {
813 err = gst_omx_port_set_enabled (port, TRUE);
814 if (err != OMX_ErrorNone) {
815 GST_INFO_OBJECT (self,
816 "Failed to enable port: %s (0x%08x)",
817 gst_omx_error_to_string (err), err);
818 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
819 g_list_free (images);
820 /* TODO: For non-RPi targets we want to use the normal memory code below */
821 /* Retry without EGLImage */
826 err = gst_omx_port_use_eglimages (port, images);
827 g_list_free (images);
829 if (err != OMX_ErrorNone) {
830 GST_INFO_OBJECT (self,
831 "Failed to pass EGLImages to port: %s (0x%08x)",
832 gst_omx_error_to_string (err), err);
833 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
834 /* TODO: For non-RPi targets we want to use the normal memory code below */
835 /* Retry without EGLImage */
839 err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
840 if (err != OMX_ErrorNone) {
841 GST_INFO_OBJECT (self,
842 "Failed to wait until port is enabled: %s (0x%08x)",
843 gst_omx_error_to_string (err), err);
844 g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
845 /* TODO: For non-RPi targets we want to use the normal memory code below */
846 /* Retry without EGLImage */
850 GST_DEBUG_OBJECT (self, "Populating internal buffer pool");
851 GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool =
852 GST_BUFFER_POOL (gst_object_ref (pool));
853 for (l = buffers; l; l = l->next) {
854 g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers,
857 g_list_free (buffers);
858 /* All good and done, set caps below */
864 /* If not using EGLImage or trying to use EGLImage failed */
866 gboolean was_enabled = TRUE;
868 if (min != port->port_def.nBufferCountActual) {
869 err = gst_omx_port_update_port_definition (port, NULL);
870 if (err == OMX_ErrorNone) {
871 port->port_def.nBufferCountActual = min;
872 err = gst_omx_port_update_port_definition (port, &port->port_def);
875 if (err != OMX_ErrorNone) {
876 GST_ERROR_OBJECT (self,
877 "Failed to configure %u output buffers: %s (0x%08x)", min,
878 gst_omx_error_to_string (err), err);
883 if (!gst_omx_port_is_enabled (port)) {
884 err = gst_omx_port_set_enabled (port, TRUE);
885 if (err != OMX_ErrorNone) {
886 GST_INFO_OBJECT (self,
887 "Failed to enable port: %s (0x%08x)",
888 gst_omx_error_to_string (err), err);
893 #ifdef GST_TIZEN_MODIFICATION
894 err = gst_omx_port_tbm_allocate_dec_buffers(port, self->hTBMBufMgr,
895 self->dec_in_port->port_def.format.video.eCompressionFormat);
897 err = gst_omx_port_allocate_buffers (port);
899 if (err != OMX_ErrorNone && min > port->port_def.nBufferCountMin) {
900 GST_ERROR_OBJECT (self,
901 "Failed to allocate required number of buffers %d, trying less and copying",
903 min = port->port_def.nBufferCountMin;
906 err = gst_omx_port_set_enabled (port, FALSE);
907 if (err != OMX_ErrorNone) {
908 GST_INFO_OBJECT (self,
909 "Failed to disable port again: %s (0x%08x)",
910 gst_omx_error_to_string (err), err);
915 if (min != port->port_def.nBufferCountActual) {
916 err = gst_omx_port_update_port_definition (port, NULL);
917 if (err == OMX_ErrorNone) {
918 port->port_def.nBufferCountActual = min;
919 err = gst_omx_port_update_port_definition (port, &port->port_def);
922 if (err != OMX_ErrorNone) {
923 GST_ERROR_OBJECT (self,
924 "Failed to configure %u output buffers: %s (0x%08x)", min,
925 gst_omx_error_to_string (err), err);
929 #ifdef GST_TIZEN_MODIFICATION
930 err = gst_omx_port_tbm_allocate_dec_buffers(port, self->hTBMBufMgr,
931 self->dec_in_port->port_def.format.video.eCompressionFormat);
933 err = gst_omx_port_allocate_buffers (port);
935 /* Can't provide buffers downstream in this case */
936 gst_caps_replace (&caps, NULL);
939 if (err != OMX_ErrorNone) {
940 GST_ERROR_OBJECT (self, "Failed to allocate %d buffers: %s (0x%08x)", min,
941 gst_omx_error_to_string (err), err);
946 err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND);
947 if (err != OMX_ErrorNone) {
948 GST_ERROR_OBJECT (self,
949 "Failed to wait until port is enabled: %s (0x%08x)",
950 gst_omx_error_to_string (err), err);
961 config = gst_buffer_pool_get_config (self->out_port_pool);
964 gst_buffer_pool_config_add_option (config,
965 GST_BUFFER_POOL_OPTION_VIDEO_META);
967 gst_buffer_pool_config_set_params (config, caps,
968 self->dec_out_port->port_def.nBufferSize, min, max);
970 if (!gst_buffer_pool_set_config (self->out_port_pool, config)) {
971 GST_INFO_OBJECT (self, "Failed to set config on internal pool");
972 gst_object_unref (self->out_port_pool);
973 self->out_port_pool = NULL;
977 GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = TRUE;
978 /* This now allocates all the buffers */
979 if (!gst_buffer_pool_set_active (self->out_port_pool, TRUE)) {
980 GST_INFO_OBJECT (self, "Failed to activate internal pool");
981 gst_object_unref (self->out_port_pool);
982 self->out_port_pool = NULL;
984 GST_OMX_BUFFER_POOL (self->out_port_pool)->allocating = FALSE;
986 } else if (self->out_port_pool) {
987 gst_object_unref (self->out_port_pool);
988 self->out_port_pool = NULL;
992 if (!self->out_port_pool && err == OMX_ErrorNone)
993 GST_DEBUG_OBJECT (self,
994 "Not using our internal pool and copying buffers for downstream");
997 gst_caps_unref (caps);
999 gst_object_unref (pool);
1001 gst_video_codec_state_unref (state);
1006 static OMX_ERRORTYPE
1007 gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
1011 if (self->out_port_pool) {
1012 gst_buffer_pool_set_active (self->out_port_pool, FALSE);
1014 gst_buffer_pool_wait_released (self->out_port_pool);
1016 GST_OMX_BUFFER_POOL (self->out_port_pool)->deactivated = TRUE;
1017 gst_object_unref (self->out_port_pool);
1018 self->out_port_pool = NULL;
1020 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1022 gst_omx_port_deallocate_buffers (self->
1023 eglimage ? self->egl_out_port : self->dec_out_port);
1025 err = gst_omx_port_deallocate_buffers (self->dec_out_port);
1031 static OMX_ERRORTYPE
1032 gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self)
1036 GstVideoCodecState *state;
1037 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1038 GstVideoFormat format;
1040 /* At this point the decoder output port is disabled */
1042 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1044 OMX_STATETYPE egl_state;
1046 if (self->eglimage) {
1047 /* Nothing to do here, we could however fall back to non-EGLImage in theory */
1048 port = self->egl_out_port;
1049 err = OMX_ErrorNone;
1052 /* Set up egl_render */
1054 self->eglimage = TRUE;
1056 gst_omx_port_get_port_definition (self->dec_out_port, &port_def);
1057 GST_VIDEO_DECODER_STREAM_LOCK (self);
1058 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1059 GST_VIDEO_FORMAT_RGBA, port_def.format.video.nFrameWidth,
1060 port_def.format.video.nFrameHeight, self->input_state);
1062 /* at this point state->caps is NULL */
1064 gst_caps_unref (state->caps);
1065 state->caps = gst_video_info_to_caps (&state->info);
1066 gst_caps_set_features (state->caps, 0,
1067 gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE, NULL));
1069 /* try to negotiate with caps feature */
1070 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1072 GST_DEBUG_OBJECT (self,
1073 "Failed to negotiate with feature %s",
1074 GST_CAPS_FEATURE_MEMORY_EGL_IMAGE);
1077 gst_caps_replace (&state->caps, NULL);
1079 /* fallback: try to use EGLImage even if it is not in the caps feature */
1080 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1081 gst_video_codec_state_unref (state);
1082 GST_ERROR_OBJECT (self, "Failed to negotiate RGBA for EGLImage");
1083 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1088 gst_video_codec_state_unref (state);
1089 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1091 /* Now link it all together */
1093 err = gst_omx_port_set_enabled (self->egl_in_port, FALSE);
1094 if (err != OMX_ErrorNone)
1097 err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1098 if (err != OMX_ErrorNone)
1101 err = gst_omx_port_set_enabled (self->egl_out_port, FALSE);
1102 if (err != OMX_ErrorNone)
1105 err = gst_omx_port_wait_enabled (self->egl_out_port, 1 * GST_SECOND);
1106 if (err != OMX_ErrorNone)
1110 #define OMX_IndexParamBrcmVideoEGLRenderDiscardMode 0x7f0000db
1111 OMX_CONFIG_PORTBOOLEANTYPE discardMode;
1112 memset (&discardMode, 0, sizeof (discardMode));
1113 discardMode.nSize = sizeof (discardMode);
1114 discardMode.nPortIndex = 220;
1115 discardMode.nVersion.nVersion = OMX_VERSION;
1116 discardMode.bEnabled = OMX_FALSE;
1117 if (gst_omx_component_set_parameter (self->egl_render,
1118 OMX_IndexParamBrcmVideoEGLRenderDiscardMode,
1119 &discardMode) != OMX_ErrorNone)
1121 #undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode
1124 err = gst_omx_setup_tunnel (self->dec_out_port, self->egl_in_port);
1125 if (err != OMX_ErrorNone)
1128 err = gst_omx_port_set_enabled (self->egl_in_port, TRUE);
1129 if (err != OMX_ErrorNone)
1132 err = gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1133 if (err != OMX_ErrorNone)
1136 err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
1137 if (err != OMX_ErrorNone)
1140 if (gst_omx_component_get_state (self->egl_render,
1141 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
1144 err = gst_omx_video_dec_allocate_output_buffers (self);
1145 if (err != OMX_ErrorNone)
1148 if (gst_omx_component_set_state (self->egl_render,
1149 OMX_StateExecuting) != OMX_ErrorNone)
1152 if (gst_omx_component_get_state (self->egl_render,
1153 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
1157 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
1158 if (err != OMX_ErrorNone)
1162 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
1163 if (err != OMX_ErrorNone)
1167 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
1168 if (err != OMX_ErrorNone)
1171 err = gst_omx_port_populate (self->egl_out_port);
1172 if (err != OMX_ErrorNone)
1175 err = gst_omx_port_set_enabled (self->dec_out_port, TRUE);
1176 if (err != OMX_ErrorNone)
1179 err = gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1180 if (err != OMX_ErrorNone)
1184 err = gst_omx_port_mark_reconfigured (self->dec_out_port);
1185 if (err != OMX_ErrorNone)
1188 err = gst_omx_port_mark_reconfigured (self->egl_out_port);
1189 if (err != OMX_ErrorNone)
1197 gst_omx_port_set_enabled (self->dec_out_port, FALSE);
1198 gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
1199 egl_state = gst_omx_component_get_state (self->egl_render, 0);
1200 if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
1201 if (egl_state > OMX_StateIdle) {
1202 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1203 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1205 gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
1207 gst_omx_video_dec_deallocate_output_buffers (self);
1208 gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
1210 if (egl_state > OMX_StateLoaded) {
1211 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
1215 /* After this egl_render should be deactivated
1216 * and the decoder's output port disabled */
1217 self->eglimage = FALSE;
1220 port = self->dec_out_port;
1223 GST_VIDEO_DECODER_STREAM_LOCK (self);
1225 gst_omx_port_get_port_definition (port, &port_def);
1226 g_assert (port_def.format.video.eCompressionFormat == OMX_VIDEO_CodingUnused);
1229 gst_omx_video_get_format_from_omx (port_def.format.video.eColorFormat);
1231 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1232 GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1233 port_def.format.video.eColorFormat);
1234 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1235 err = OMX_ErrorUndefined;
1239 GST_DEBUG_OBJECT (self,
1240 "Setting output state: format %s (%d), width %u, height %u",
1241 gst_video_format_to_string (format),
1242 port_def.format.video.eColorFormat,
1243 (guint) port_def.format.video.nFrameWidth,
1244 (guint) port_def.format.video.nFrameHeight);
1246 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1247 format, port_def.format.video.nFrameWidth,
1248 port_def.format.video.nFrameHeight, self->input_state);
1250 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1251 gst_video_codec_state_unref (state);
1252 GST_ERROR_OBJECT (self, "Failed to negotiate");
1253 err = OMX_ErrorUndefined;
1254 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1258 gst_video_codec_state_unref (state);
1260 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1262 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1265 err = gst_omx_video_dec_allocate_output_buffers (self);
1266 if (err != OMX_ErrorNone)
1269 err = gst_omx_port_populate (port);
1270 if (err != OMX_ErrorNone)
1273 err = gst_omx_port_mark_reconfigured (port);
1274 if (err != OMX_ErrorNone)
1283 gst_omx_video_dec_clean_older_frames (GstOMXVideoDec * self,
1284 GstOMXBuffer * buf, GList * frames)
1287 GstClockTime timestamp;
1289 timestamp = gst_util_uint64_scale (buf->omx_buf->nTimeStamp, GST_SECOND,
1290 OMX_TICKS_PER_SECOND);
1292 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1293 /* We could release all frames stored with pts < timestamp since the
1294 * decoder will likely output frames in display order */
1295 for (l = frames; l; l = l->next) {
1296 GstVideoCodecFrame *tmp = l->data;
1298 if (tmp->pts < timestamp) {
1299 gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1300 GST_LOG_OBJECT (self,
1301 "discarding ghost frame %p (#%d) PTS:%" GST_TIME_FORMAT " DTS:%"
1302 GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1303 GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1305 gst_video_codec_frame_unref (tmp);
1309 /* We will release all frames with invalid timestamp because we don't even
1310 * know if they will be output some day. */
1311 for (l = frames; l; l = l->next) {
1312 GstVideoCodecFrame *tmp = l->data;
1314 if (!GST_CLOCK_TIME_IS_VALID (tmp->pts)) {
1315 gst_video_decoder_release_frame (GST_VIDEO_DECODER (self), tmp);
1316 GST_LOG_OBJECT (self,
1317 "discarding frame %p (#%d) with invalid PTS:%" GST_TIME_FORMAT
1318 " DTS:%" GST_TIME_FORMAT, tmp, tmp->system_frame_number,
1319 GST_TIME_ARGS (tmp->pts), GST_TIME_ARGS (tmp->dts));
1321 gst_video_codec_frame_unref (tmp);
1326 g_list_free (frames);
1330 copy_frame (const GstVideoInfo * info, GstBuffer * outbuf)
1332 GstVideoInfo out_info, tmp_info;
1334 GstVideoFrame out_frame, tmp_frame;
1339 tmpbuf = gst_buffer_new_and_alloc (out_info.size);
1341 gst_video_frame_map (&out_frame, &out_info, outbuf, GST_MAP_READ);
1342 gst_video_frame_map (&tmp_frame, &tmp_info, tmpbuf, GST_MAP_WRITE);
1343 gst_video_frame_copy (&tmp_frame, &out_frame);
1344 gst_video_frame_unmap (&out_frame);
1345 gst_video_frame_unmap (&tmp_frame);
1347 gst_buffer_unref (outbuf);
1353 gst_omx_video_dec_loop (GstOMXVideoDec * self)
1356 GstOMXBuffer *buf = NULL;
1357 GstVideoCodecFrame *frame;
1358 GstFlowReturn flow_ret = GST_FLOW_OK;
1359 GstOMXAcquireBufferReturn acq_return;
1360 GstClockTimeDiff deadline;
1363 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1364 port = self->eglimage ? self->egl_out_port : self->dec_out_port;
1366 port = self->dec_out_port;
1369 acq_return = gst_omx_port_acquire_buffer (port, &buf);
1370 if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
1371 goto component_error;
1372 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
1374 } else if (acq_return == GST_OMX_ACQUIRE_BUFFER_EOS) {
1378 if (!gst_pad_has_current_caps (GST_VIDEO_DECODER_SRC_PAD (self)) ||
1379 acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1380 GstVideoCodecState *state;
1381 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1382 GstVideoFormat format;
1384 GST_DEBUG_OBJECT (self, "Port settings have changed, updating caps");
1386 /* Reallocate all buffers */
1387 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE
1388 && gst_omx_port_is_enabled (port)) {
1389 err = gst_omx_port_set_enabled (port, FALSE);
1390 if (err != OMX_ErrorNone)
1391 goto reconfigure_error;
1393 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
1394 if (err != OMX_ErrorNone)
1395 goto reconfigure_error;
1397 err = gst_omx_video_dec_deallocate_output_buffers (self);
1398 if (err != OMX_ErrorNone)
1399 goto reconfigure_error;
1401 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
1402 if (err != OMX_ErrorNone)
1403 goto reconfigure_error;
1406 if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
1407 /* We have the possibility to reconfigure everything now */
1408 err = gst_omx_video_dec_reconfigure_output_port (self);
1409 if (err != OMX_ErrorNone)
1410 goto reconfigure_error;
1412 /* Just update caps */
1413 GST_VIDEO_DECODER_STREAM_LOCK (self);
1415 gst_omx_port_get_port_definition (port, &port_def);
1416 g_assert (port_def.format.video.eCompressionFormat ==
1417 OMX_VIDEO_CodingUnused);
1420 gst_omx_video_get_format_from_omx (port_def.format.
1421 video.eColorFormat);
1423 if (format == GST_VIDEO_FORMAT_UNKNOWN) {
1424 GST_ERROR_OBJECT (self, "Unsupported color format: %d",
1425 port_def.format.video.eColorFormat);
1427 gst_omx_port_release_buffer (port, buf);
1428 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1432 GST_DEBUG_OBJECT (self,
1433 "Setting output state: format %s (%d), width %u, height %u",
1434 gst_video_format_to_string (format),
1435 port_def.format.video.eColorFormat,
1436 (guint) port_def.format.video.nFrameWidth,
1437 (guint) port_def.format.video.nFrameHeight);
1439 state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
1440 format, port_def.format.video.nFrameWidth,
1441 port_def.format.video.nFrameHeight, self->input_state);
1443 /* Take framerate and pixel-aspect-ratio from sinkpad caps */
1445 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
1447 gst_omx_port_release_buffer (port, buf);
1448 gst_video_codec_state_unref (state);
1452 gst_video_codec_state_unref (state);
1454 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1457 /* Now get a buffer */
1458 if (acq_return != GST_OMX_ACQUIRE_BUFFER_OK) {
1463 g_assert (acq_return == GST_OMX_ACQUIRE_BUFFER_OK);
1465 /* This prevents a deadlock between the srcpad stream
1466 * lock and the videocodec stream lock, if ::reset()
1467 * is called at the wrong time
1469 if (gst_omx_port_is_flushing (port)) {
1470 GST_DEBUG_OBJECT (self, "Flushing");
1471 gst_omx_port_release_buffer (port, buf);
1475 GST_DEBUG_OBJECT (self, "Handling buffer: 0x%08x %" G_GUINT64_FORMAT,
1476 (guint) buf->omx_buf->nFlags, (guint64) buf->omx_buf->nTimeStamp);
1478 GST_VIDEO_DECODER_STREAM_LOCK (self);
1479 frame = gst_omx_video_find_nearest_frame (buf,
1480 gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1482 /* So we have a timestamped OMX buffer and get, or not, corresponding frame.
1483 * Assuming decoder output frames in display order, frames preceding this
1484 * frame could be discarded as they seems useless due to e.g interlaced
1485 * stream, corrupted input data...
1486 * In any cases, not likely to be seen again. so drop it before they pile up
1487 * and use all the memory. */
1488 gst_omx_video_dec_clean_older_frames (self, buf,
1489 gst_video_decoder_get_frames (GST_VIDEO_DECODER (self)));
1492 && (deadline = gst_video_decoder_get_max_decode_time
1493 (GST_VIDEO_DECODER (self), frame)) < 0) {
1494 GST_WARNING_OBJECT (self,
1495 "Frame is too late, dropping (deadline %" GST_TIME_FORMAT ")",
1496 GST_TIME_ARGS (-deadline));
1497 flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1499 } else if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->eglimage)) {
1500 GstBuffer *outbuf = NULL;
1502 /* This sometimes happens at EOS or if the input is not properly framed,
1503 * let's handle it gracefully by allocating a new buffer for the current
1504 * caps and filling it
1507 GST_ERROR_OBJECT (self, "No corresponding frame found");
1509 if (self->out_port_pool) {
1511 GstBufferPoolAcquireParams params = { 0, };
1513 n = port->buffers->len;
1514 for (i = 0; i < n; i++) {
1515 GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1522 GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1524 gst_buffer_pool_acquire_buffer (self->out_port_pool, &outbuf,
1526 if (flow_ret != GST_FLOW_OK) {
1527 gst_omx_port_release_buffer (port, buf);
1528 goto invalid_buffer;
1531 if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy)
1533 copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1539 gst_video_decoder_allocate_output_buffer (GST_VIDEO_DECODER (self));
1540 if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) {
1541 gst_buffer_unref (outbuf);
1542 gst_omx_port_release_buffer (port, buf);
1543 goto invalid_buffer;
1547 flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf);
1548 } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
1549 if (self->out_port_pool) {
1552 GstBufferPoolAcquireParams params = { 0, };
1554 n = port->buffers->len;
1555 for (i = 0; i < n; i++) {
1556 GstOMXBuffer *tmp = g_ptr_array_index (port->buffers, i);
1563 GST_OMX_BUFFER_POOL (self->out_port_pool)->current_buffer_index = i;
1565 gst_buffer_pool_acquire_buffer (self->out_port_pool,
1566 &frame->output_buffer, ¶ms);
1567 if (flow_ret != GST_FLOW_OK) {
1569 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1571 gst_omx_port_release_buffer (port, buf);
1572 goto invalid_buffer;
1575 if (GST_OMX_BUFFER_POOL (self->out_port_pool)->need_copy){
1577 copy_frame (&GST_OMX_BUFFER_POOL (self->out_port_pool)->video_info,
1579 frame->output_buffer = outbuf;
1582 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1586 if(!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1587 gst_buffer_replace (&frame->output_buffer, NULL);
1589 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1591 gst_omx_port_release_buffer (port, buf);
1592 goto invalid_buffer;
1595 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1601 gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER
1602 (self), frame)) == GST_FLOW_OK) {
1603 /* FIXME: This currently happens because of a race condition too.
1604 * We first need to reconfigure the output port and then the input
1605 * port if both need reconfiguration.
1607 if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
1608 gst_buffer_replace (&frame->output_buffer, NULL);
1610 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1612 gst_omx_port_release_buffer (port, buf);
1613 goto invalid_buffer;
1616 gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
1620 } else if (frame != NULL) {
1621 flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
1625 GST_DEBUG_OBJECT (self, "Read frame from component");
1627 GST_DEBUG_OBJECT (self, "Finished frame: %s", gst_flow_get_name (flow_ret));
1630 err = gst_omx_port_release_buffer (port, buf);
1631 if (err != OMX_ErrorNone)
1635 self->downstream_flow_ret = flow_ret;
1637 if (flow_ret != GST_FLOW_OK)
1640 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1646 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
1647 ("OpenMAX component in error state %s (0x%08x)",
1648 gst_omx_component_get_last_error_string (self->dec),
1649 gst_omx_component_get_last_error (self->dec)));
1650 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1651 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1652 self->downstream_flow_ret = GST_FLOW_ERROR;
1653 self->started = FALSE;
1659 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1660 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1661 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1662 self->started = FALSE;
1668 g_mutex_lock (&self->drain_lock);
1669 if (self->draining) {
1670 GstQuery *query = gst_query_new_drain ();
1672 /* Drain the pipeline to reclaim all memories back to the pool */
1673 if (!gst_pad_peer_query (GST_VIDEO_DECODER_SRC_PAD (self), query))
1674 GST_DEBUG_OBJECT (self, "drain query failed");
1675 gst_query_unref (query);
1677 GST_DEBUG_OBJECT (self, "Drained");
1678 self->draining = FALSE;
1679 g_cond_broadcast (&self->drain_cond);
1680 flow_ret = GST_FLOW_OK;
1681 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1683 GST_DEBUG_OBJECT (self, "Component signalled EOS");
1684 flow_ret = GST_FLOW_EOS;
1686 g_mutex_unlock (&self->drain_lock);
1688 GST_VIDEO_DECODER_STREAM_LOCK (self);
1689 self->downstream_flow_ret = flow_ret;
1691 /* Here we fallback and pause the task for the EOS case */
1692 if (flow_ret != GST_FLOW_OK)
1695 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1702 if (flow_ret == GST_FLOW_EOS) {
1703 GST_DEBUG_OBJECT (self, "EOS");
1705 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1706 gst_event_new_eos ());
1707 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1708 self->started = FALSE;
1709 } else if (flow_ret < GST_FLOW_EOS) {
1710 GST_ELEMENT_ERROR (self, STREAM, FAILED,
1711 ("Internal data stream error."), ("stream stopped, reason %s",
1712 gst_flow_get_name (flow_ret)));
1714 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self),
1715 gst_event_new_eos ());
1716 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1717 self->started = FALSE;
1718 } else if (flow_ret == GST_FLOW_FLUSHING) {
1719 GST_DEBUG_OBJECT (self, "Flushing -- stopping task");
1720 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1721 self->started = FALSE;
1723 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1729 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1730 ("Unable to reconfigure output port"));
1731 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1732 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1733 self->downstream_flow_ret = GST_FLOW_ERROR;
1734 self->started = FALSE;
1740 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1741 ("Invalid sized input buffer"));
1742 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1743 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1744 self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
1745 self->started = FALSE;
1746 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1752 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL), ("Failed to set caps"));
1753 gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), gst_event_new_eos ());
1754 gst_pad_pause_task (GST_VIDEO_DECODER_SRC_PAD (self));
1755 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1756 self->downstream_flow_ret = GST_FLOW_NOT_NEGOTIATED;
1757 self->started = FALSE;
1762 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
1763 ("Failed to relase output buffer to component: %s (0x%08x)",
1764 gst_omx_error_to_string (err), err));
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;
1769 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
1775 gst_omx_video_dec_start (GstVideoDecoder * decoder)
1777 GstOMXVideoDec *self;
1779 self = GST_OMX_VIDEO_DEC (decoder);
1781 self->last_upstream_ts = 0;
1782 self->downstream_flow_ret = GST_FLOW_OK;
1788 gst_omx_video_dec_stop (GstVideoDecoder * decoder)
1790 GstOMXVideoDec *self;
1792 self = GST_OMX_VIDEO_DEC (decoder);
1794 GST_DEBUG_OBJECT (self, "Stopping decoder");
1796 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
1797 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
1799 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1800 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
1801 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
1804 gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
1806 if (gst_omx_component_get_state (self->dec, 0) > OMX_StateIdle)
1807 gst_omx_component_set_state (self->dec, OMX_StateIdle);
1808 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1809 if (gst_omx_component_get_state (self->egl_render, 0) > OMX_StateIdle)
1810 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
1813 self->downstream_flow_ret = GST_FLOW_FLUSHING;
1814 self->started = FALSE;
1816 g_mutex_lock (&self->drain_lock);
1817 self->draining = FALSE;
1818 g_cond_broadcast (&self->drain_cond);
1819 g_mutex_unlock (&self->drain_lock);
1821 gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
1822 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
1823 gst_omx_component_get_state (self->egl_render, 1 * GST_SECOND);
1826 gst_buffer_replace (&self->codec_data, NULL);
1828 if (self->input_state)
1829 gst_video_codec_state_unref (self->input_state);
1830 self->input_state = NULL;
1832 GST_DEBUG_OBJECT (self, "Stopped decoder");
1838 gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
1840 OMX_VIDEO_PARAM_PORTFORMATTYPE param;
1842 GstCaps *comp_supported_caps;
1843 GList *negotiation_map = NULL, *l;
1844 GstCaps *templ_caps, *intersection;
1845 GstVideoFormat format;
1847 const gchar *format_str;
1848 #ifdef GST_TIZEN_MODIFICATION
1851 EnableGemBuffersParams gemBuffers;
1854 GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream");
1856 templ_caps = gst_pad_get_pad_template_caps (GST_VIDEO_DECODER_SRC_PAD (self));
1858 gst_pad_peer_query_caps (GST_VIDEO_DECODER_SRC_PAD (self), templ_caps);
1859 gst_caps_unref (templ_caps);
1861 GST_DEBUG_OBJECT (self, "Allowed downstream caps: %" GST_PTR_FORMAT,
1865 gst_omx_video_get_supported_colorformats (self->dec_out_port,
1868 comp_supported_caps = gst_omx_video_get_caps_for_map (negotiation_map);
1870 if (!gst_caps_is_empty (comp_supported_caps)) {
1873 tmp = gst_caps_intersect (comp_supported_caps, intersection);
1874 gst_caps_unref (intersection);
1877 gst_caps_unref (comp_supported_caps);
1879 if (gst_caps_is_empty (intersection)) {
1880 gst_caps_unref (intersection);
1881 GST_ERROR_OBJECT (self, "Empty caps");
1882 g_list_free_full (negotiation_map,
1883 (GDestroyNotify) gst_omx_video_negotiation_map_free);
1887 for(i=0; i<gst_caps_get_size(intersection); i++)
1889 s = gst_caps_get_structure (intersection, i);
1890 format_tmp = gst_structure_get_string (s, "format");
1892 if(!strncmp(format_tmp, "S", 1)) {
1893 format_str = format_tmp;
1894 GST_DEBUG_OBJECT (self, "SEC format found");
1900 intersection = gst_caps_truncate (intersection);
1901 intersection = gst_caps_fixate (intersection);
1903 s = gst_caps_get_structure (intersection, 0);
1904 format_str = gst_structure_get_string (s, "format");
1905 GST_DEBUG_OBJECT (self, "first structure will be fixated");
1910 gst_video_format_from_string (format_str)) ==
1911 GST_VIDEO_FORMAT_UNKNOWN) {
1912 GST_ERROR_OBJECT (self, "Invalid caps: %" GST_PTR_FORMAT, intersection);
1913 gst_caps_unref (intersection);
1914 g_list_free_full (negotiation_map,
1915 (GDestroyNotify) gst_omx_video_negotiation_map_free);
1919 GST_OMX_INIT_STRUCT (¶m);
1920 param.nPortIndex = self->dec_out_port->index;
1922 for (l = negotiation_map; l; l = l->next) {
1923 GstOMXVideoNegotiationMap *m = l->data;
1925 if (m->format == format) {
1926 param.eColorFormat = m->type;
1931 GST_DEBUG_OBJECT (self, "Negotiating color format %s (%d)", format_str,
1932 param.eColorFormat);
1934 /* We must find something here */
1935 g_assert (l != NULL);
1936 g_list_free_full (negotiation_map,
1937 (GDestroyNotify) gst_omx_video_negotiation_map_free);
1940 gst_omx_component_set_parameter (self->dec,
1941 OMX_IndexParamVideoPortFormat, ¶m);
1942 if (err != OMX_ErrorNone) {
1943 GST_ERROR_OBJECT (self, "Failed to set video port format: %s (0x%08x)",
1944 gst_omx_error_to_string (err), err);
1947 /* set plateform specific gem buffer settings. */
1949 /* Set platform specific buffer settings. to avoid plane support error.. */
1950 #ifdef GST_TIZEN_MODIFICATION
1951 OMX_INIT_STRUCTURE(gemBuffers);
1952 gemBuffers.enable = OMX_TRUE;
1953 gemBuffers.nPortIndex = 1;
1955 gst_omx_component_set_parameter (self->dec,
1956 OMX_IndexParamEnablePlatformSpecificBuffers,&gemBuffers);
1957 if (err != OMX_ErrorNone) {
1958 GST_ERROR_OBJECT (self, "Failed to set video port format: %s (0x%08x)",
1959 gst_omx_error_to_string (err), err);
1962 gst_caps_unref (intersection);
1963 return (err == OMX_ErrorNone);
1967 gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
1968 GstVideoCodecState * state)
1970 GstOMXVideoDec *self;
1971 GstOMXVideoDecClass *klass;
1972 GstVideoInfo *info = &state->info;
1973 gboolean is_format_change = FALSE;
1974 gboolean needs_disable = FALSE;
1975 OMX_PARAM_PORTDEFINITIONTYPE port_def;
1977 self = GST_OMX_VIDEO_DEC (decoder);
1978 klass = GST_OMX_VIDEO_DEC_GET_CLASS (decoder);
1980 GST_DEBUG_OBJECT (self, "Setting new caps %" GST_PTR_FORMAT, state->caps);
1982 gst_omx_port_get_port_definition (self->dec_in_port, &port_def);
1984 /* Check if the caps change is a real format change or if only irrelevant
1985 * parts of the caps have changed or nothing at all.
1987 is_format_change |= port_def.format.video.nFrameWidth != info->width;
1988 is_format_change |= port_def.format.video.nFrameHeight != info->height;
1989 is_format_change |= (port_def.format.video.xFramerate == 0
1990 && info->fps_n != 0)
1991 || (port_def.format.video.xFramerate !=
1992 (info->fps_n << 16) / (info->fps_d));
1993 is_format_change |= (self->codec_data != state->codec_data);
1994 if (klass->is_format_change)
1996 klass->is_format_change (self, self->dec_in_port, state);
1999 gst_omx_component_get_state (self->dec,
2000 GST_CLOCK_TIME_NONE) != OMX_StateLoaded;
2001 /* If the component is not in Loaded state and a real format change happens
2002 * we have to disable the port and re-allocate all buffers. If no real
2003 * format change happened we can just exit here.
2005 if (needs_disable && !is_format_change) {
2006 GST_DEBUG_OBJECT (self,
2007 "Already running and caps did not change the format");
2008 if (self->input_state)
2009 gst_video_codec_state_unref (self->input_state);
2010 self->input_state = gst_video_codec_state_ref (state);
2014 if (needs_disable && is_format_change) {
2015 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2016 GstOMXPort *out_port =
2017 self->eglimage ? self->egl_out_port : self->dec_out_port;
2019 GstOMXPort *out_port = self->dec_out_port;
2022 GST_DEBUG_OBJECT (self, "Need to disable and drain decoder");
2024 gst_omx_video_dec_drain (self);
2025 gst_omx_video_dec_flush (decoder);
2026 gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE);
2028 if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) {
2029 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2030 gst_omx_video_dec_stop (GST_VIDEO_DECODER (self));
2031 gst_omx_video_dec_close (GST_VIDEO_DECODER (self));
2032 GST_VIDEO_DECODER_STREAM_LOCK (self);
2034 if (!gst_omx_video_dec_open (GST_VIDEO_DECODER (self)))
2036 needs_disable = FALSE;
2038 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2039 if (self->eglimage) {
2040 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2041 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2042 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2043 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2047 if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone)
2049 if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone)
2051 if (gst_omx_port_wait_buffers_released (self->dec_in_port,
2052 5 * GST_SECOND) != OMX_ErrorNone)
2054 if (gst_omx_port_wait_buffers_released (out_port,
2055 1 * GST_SECOND) != OMX_ErrorNone)
2057 if (gst_omx_port_deallocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2059 if (gst_omx_video_dec_deallocate_output_buffers (self) != OMX_ErrorNone)
2061 if (gst_omx_port_wait_enabled (self->dec_in_port,
2062 1 * GST_SECOND) != OMX_ErrorNone)
2064 if (gst_omx_port_wait_enabled (out_port, 1 * GST_SECOND) != OMX_ErrorNone)
2067 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2068 if (self->eglimage) {
2069 OMX_STATETYPE egl_state;
2071 egl_state = gst_omx_component_get_state (self->egl_render, 0);
2072 if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
2074 if (egl_state > OMX_StateIdle) {
2075 gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
2076 gst_omx_component_set_state (self->dec, OMX_StateIdle);
2077 egl_state = gst_omx_component_get_state (self->egl_render,
2079 gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
2081 gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
2082 gst_omx_component_set_state (self->dec, OMX_StateLoaded);
2084 gst_omx_close_tunnel (self->dec_out_port, self->egl_in_port);
2086 if (egl_state > OMX_StateLoaded) {
2087 gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
2090 gst_omx_component_set_state (self->dec, OMX_StateIdle);
2092 gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2093 gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2095 self->eglimage = FALSE;
2099 if (self->input_state)
2100 gst_video_codec_state_unref (self->input_state);
2101 self->input_state = NULL;
2103 GST_DEBUG_OBJECT (self, "Decoder drained and disabled");
2106 port_def.format.video.nFrameWidth = info->width;
2107 port_def.format.video.nFrameHeight = info->height;
2108 if (info->fps_n == 0)
2109 port_def.format.video.xFramerate = 0;
2111 port_def.format.video.xFramerate = (info->fps_n << 16) / (info->fps_d);
2113 GST_DEBUG_OBJECT (self, "Setting inport port definition");
2115 if (gst_omx_port_update_port_definition (self->dec_in_port,
2116 &port_def) != OMX_ErrorNone)
2119 if (klass->set_format) {
2120 if (!klass->set_format (self, self->dec_in_port, state)) {
2121 GST_ERROR_OBJECT (self, "Subclass failed to set the new format");
2126 GST_DEBUG_OBJECT (self, "Updating outport port definition");
2127 if (gst_omx_port_update_port_definition (self->dec_out_port,
2128 NULL) != OMX_ErrorNone)
2131 gst_buffer_replace (&self->codec_data, state->codec_data);
2132 self->input_state = gst_video_codec_state_ref (state);
2134 GST_DEBUG_OBJECT (self, "Enabling component");
2136 if (needs_disable) {
2137 if (gst_omx_port_set_enabled (self->dec_in_port, TRUE) != OMX_ErrorNone)
2139 #ifdef GST_TIZEN_MODIFICATION
2140 if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_in_port, self->hTBMBufMgr, 0) != OMX_ErrorNone)
2143 if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2147 if ((klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2148 if (gst_omx_port_set_enabled (self->dec_out_port, TRUE) != OMX_ErrorNone)
2150 if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2153 if (gst_omx_port_wait_enabled (self->dec_out_port,
2154 5 * GST_SECOND) != OMX_ErrorNone)
2158 if (gst_omx_port_wait_enabled (self->dec_in_port,
2159 5 * GST_SECOND) != OMX_ErrorNone)
2161 if (gst_omx_port_mark_reconfigured (self->dec_in_port) != OMX_ErrorNone)
2164 if (!gst_omx_video_dec_negotiate (self))
2165 GST_LOG_OBJECT (self, "Negotiation failed, will get output format later");
2167 if (!(klass->cdata.hacks & GST_OMX_HACK_NO_DISABLE_OUTPORT)) {
2168 #ifndef GST_TIZEN_MODIFICATION
2169 /* Disable output port */
2170 if (gst_omx_port_set_enabled (self->dec_out_port, FALSE) != OMX_ErrorNone)
2173 if (gst_omx_port_wait_enabled (self->dec_out_port,
2174 1 * GST_SECOND) != OMX_ErrorNone)
2177 if (gst_omx_component_set_state (self->dec,
2178 OMX_StateIdle) != OMX_ErrorNone)
2181 /* Need to allocate buffers to reach Idle state */
2182 #ifdef GST_TIZEN_MODIFICATION
2183 if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_in_port, self->hTBMBufMgr, 0) != OMX_ErrorNone)
2185 if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_out_port, self->hTBMBufMgr,
2186 self->dec_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
2189 if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2191 if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2196 if (gst_omx_component_set_state (self->dec,
2197 OMX_StateIdle) != OMX_ErrorNone)
2200 /* Need to allocate buffers to reach Idle state */
2201 #ifdef GST_TIZEN_MODIFICATION
2202 if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_in_port, self->hTBMBufMgr, 0) != OMX_ErrorNone)
2204 if(gst_omx_port_tbm_allocate_dec_buffers(self->dec_out_port, self->hTBMBufMgr,
2205 self->dec_in_port->port_def.format.video.eCompressionFormat) != OMX_ErrorNone)
2208 if (gst_omx_port_allocate_buffers (self->dec_in_port) != OMX_ErrorNone)
2210 if (gst_omx_port_allocate_buffers (self->dec_out_port) != OMX_ErrorNone)
2215 if (gst_omx_component_get_state (self->dec,
2216 GST_CLOCK_TIME_NONE) != OMX_StateIdle)
2219 if (gst_omx_component_set_state (self->dec,
2220 OMX_StateExecuting) != OMX_ErrorNone)
2223 if (gst_omx_component_get_state (self->dec,
2224 GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
2228 /* Unset flushing to allow ports to accept data again */
2229 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2230 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2232 if (gst_omx_component_get_last_error (self->dec) != OMX_ErrorNone) {
2233 GST_ERROR_OBJECT (self, "Component in error state: %s (0x%08x)",
2234 gst_omx_component_get_last_error_string (self->dec),
2235 gst_omx_component_get_last_error (self->dec));
2239 self->downstream_flow_ret = GST_FLOW_OK;
2244 gst_omx_video_dec_flush (GstVideoDecoder * decoder)
2246 GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (decoder);
2247 OMX_ERRORTYPE err = OMX_ErrorNone;
2249 GST_DEBUG_OBJECT (self, "Flushing decoder");
2251 if (gst_omx_component_get_state (self->dec, 0) == OMX_StateLoaded)
2254 /* 0) Pause the components */
2255 if (gst_omx_component_get_state (self->dec, 0) == OMX_StateExecuting) {
2256 gst_omx_component_set_state (self->dec, OMX_StatePause);
2257 gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2259 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2260 if (self->eglimage) {
2261 if (gst_omx_component_get_state (self->egl_render, 0) == OMX_StateExecuting) {
2262 gst_omx_component_set_state (self->egl_render, OMX_StatePause);
2263 gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2268 /* 1) Wait until the srcpad loop is stopped,
2269 * unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
2270 * caused by using this lock from inside the loop function */
2271 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2272 gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
2273 GST_DEBUG_OBJECT (self, "Flushing -- task stopped");
2274 GST_VIDEO_DECODER_STREAM_LOCK (self);
2276 /* 2) Flush the ports */
2277 GST_DEBUG_OBJECT (self, "flushing ports");
2278 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
2279 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
2281 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2282 if (self->eglimage) {
2283 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
2284 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
2288 /* 3) Resume components */
2289 gst_omx_component_set_state (self->dec, OMX_StateExecuting);
2290 gst_omx_component_get_state (self->dec, GST_CLOCK_TIME_NONE);
2291 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2292 if (self->eglimage) {
2293 gst_omx_component_set_state (self->egl_render, OMX_StateExecuting);
2294 gst_omx_component_get_state (self->egl_render, GST_CLOCK_TIME_NONE);
2298 /* 4) Unset flushing to allow ports to accept data again */
2299 gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, FALSE);
2300 gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
2302 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2303 if (self->eglimage) {
2304 gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
2305 gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
2306 err = gst_omx_port_populate (self->egl_out_port);
2307 gst_omx_port_mark_reconfigured (self->egl_out_port);
2309 err = gst_omx_port_populate (self->dec_out_port);
2312 err = gst_omx_port_populate (self->dec_out_port);
2315 if (err != OMX_ErrorNone) {
2316 GST_WARNING_OBJECT (self, "Failed to populate output port: %s (0x%08x)",
2317 gst_omx_error_to_string (err), err);
2320 /* Reset our state */
2321 self->last_upstream_ts = 0;
2322 self->downstream_flow_ret = GST_FLOW_OK;
2323 self->started = FALSE;
2324 GST_DEBUG_OBJECT (self, "Flush finished");
2329 static GstFlowReturn
2330 gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder,
2331 GstVideoCodecFrame * frame)
2333 GstOMXAcquireBufferReturn acq_ret = GST_OMX_ACQUIRE_BUFFER_ERROR;
2334 GstOMXVideoDec *self;
2335 GstOMXVideoDecClass *klass;
2338 GstBuffer *codec_data = NULL;
2339 guint offset = 0, size;
2340 GstClockTime timestamp, duration;
2343 self = GST_OMX_VIDEO_DEC (decoder);
2344 klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2346 GST_DEBUG_OBJECT (self, "Handling frame");
2348 if (!self->started) {
2349 if (!GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
2350 gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
2353 GST_DEBUG_OBJECT (self, "Starting task");
2354 gst_pad_start_task (GST_VIDEO_DECODER_SRC_PAD (self),
2355 (GstTaskFunction) gst_omx_video_dec_loop, decoder, NULL);
2358 timestamp = frame->pts;
2359 duration = frame->duration;
2361 if (self->downstream_flow_ret != GST_FLOW_OK) {
2362 gst_video_codec_frame_unref (frame);
2363 return self->downstream_flow_ret;
2366 if (klass->prepare_frame) {
2369 ret = klass->prepare_frame (self, frame);
2370 if (ret != GST_FLOW_OK) {
2371 GST_ERROR_OBJECT (self, "Preparing frame failed: %s",
2372 gst_flow_get_name (ret));
2373 gst_video_codec_frame_unref (frame);
2378 port = self->dec_in_port;
2380 size = gst_buffer_get_size (frame->input_buffer);
2381 while (offset < size) {
2382 /* Make sure to release the base class stream lock, otherwise
2383 * _loop() can't call _finish_frame() and we might block forever
2384 * because no input buffers are released */
2385 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2386 acq_ret = gst_omx_port_acquire_buffer (port, &buf);
2388 if (acq_ret == GST_OMX_ACQUIRE_BUFFER_ERROR) {
2389 GST_VIDEO_DECODER_STREAM_LOCK (self);
2390 goto component_error;
2391 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_FLUSHING) {
2392 GST_VIDEO_DECODER_STREAM_LOCK (self);
2394 } else if (acq_ret == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
2395 /* Reallocate all buffers */
2396 err = gst_omx_port_set_enabled (port, FALSE);
2397 if (err != OMX_ErrorNone) {
2398 GST_VIDEO_DECODER_STREAM_LOCK (self);
2399 goto reconfigure_error;
2402 err = gst_omx_port_wait_buffers_released (port, 5 * GST_SECOND);
2403 if (err != OMX_ErrorNone) {
2404 GST_VIDEO_DECODER_STREAM_LOCK (self);
2405 goto reconfigure_error;
2408 err = gst_omx_port_deallocate_buffers (port);
2409 if (err != OMX_ErrorNone) {
2410 GST_VIDEO_DECODER_STREAM_LOCK (self);
2411 goto reconfigure_error;
2414 err = gst_omx_port_wait_enabled (port, 1 * GST_SECOND);
2415 if (err != OMX_ErrorNone) {
2416 GST_VIDEO_DECODER_STREAM_LOCK (self);
2417 goto reconfigure_error;
2420 err = gst_omx_port_set_enabled (port, TRUE);
2421 if (err != OMX_ErrorNone) {
2422 GST_VIDEO_DECODER_STREAM_LOCK (self);
2423 goto reconfigure_error;
2425 #ifdef GST_TIZEN_MODIFICATION
2426 err = gst_omx_port_tbm_allocate_dec_buffers(port, self->hTBMBufMgr,
2427 self->dec_in_port->port_def.format.video.eCompressionFormat);
2429 err = gst_omx_port_allocate_buffers (port);
2431 if (err != OMX_ErrorNone) {
2432 GST_VIDEO_DECODER_STREAM_LOCK (self);
2433 goto reconfigure_error;
2436 err = gst_omx_port_wait_enabled (port, 5 * GST_SECOND);
2437 if (err != OMX_ErrorNone) {
2438 GST_VIDEO_DECODER_STREAM_LOCK (self);
2439 goto reconfigure_error;
2442 err = gst_omx_port_mark_reconfigured (port);
2443 if (err != OMX_ErrorNone) {
2444 GST_VIDEO_DECODER_STREAM_LOCK (self);
2445 goto reconfigure_error;
2448 /* Now get a new buffer and fill it */
2449 GST_VIDEO_DECODER_STREAM_LOCK (self);
2452 GST_VIDEO_DECODER_STREAM_LOCK (self);
2454 g_assert (acq_ret == GST_OMX_ACQUIRE_BUFFER_OK && buf != NULL);
2456 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <= 0) {
2457 gst_omx_port_release_buffer (port, buf);
2461 if (self->downstream_flow_ret != GST_FLOW_OK) {
2462 gst_omx_port_release_buffer (port, buf);
2466 if (self->codec_data) {
2467 GST_DEBUG_OBJECT (self, "Passing codec data to the component");
2469 codec_data = self->codec_data;
2471 if (buf->omx_buf->nAllocLen - buf->omx_buf->nOffset <
2472 gst_buffer_get_size (codec_data)) {
2473 gst_omx_port_release_buffer (port, buf);
2474 goto too_large_codec_data;
2477 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
2478 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2479 buf->omx_buf->nFilledLen = gst_buffer_get_size (codec_data);;
2481 #ifdef GST_TIZEN_MODIFICATION
2482 gst_buffer_extract (codec_data, 0,
2483 buf->mm_vbuffer->data[0] + buf->omx_buf->nOffset,
2484 buf->omx_buf->nFilledLen);
2486 gst_buffer_extract (codec_data, 0,
2487 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2488 buf->omx_buf->nFilledLen);
2491 if (GST_CLOCK_TIME_IS_VALID (timestamp))
2492 buf->omx_buf->nTimeStamp =
2493 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
2495 buf->omx_buf->nTimeStamp = 0;
2496 buf->omx_buf->nTickCount = 0;
2498 self->started = TRUE;
2499 err = gst_omx_port_release_buffer (port, buf);
2500 gst_buffer_replace (&self->codec_data, NULL);
2501 if (err != OMX_ErrorNone)
2503 /* Acquire new buffer for the actual frame */
2507 /* Now handle the frame */
2508 GST_DEBUG_OBJECT (self, "Passing frame offset %d to the component", offset);
2510 /* Copy the buffer content in chunks of size as requested
2512 buf->omx_buf->nFilledLen =
2513 MIN (size - offset, buf->omx_buf->nAllocLen - buf->omx_buf->nOffset);
2514 GST_DEBUG_OBJECT (self, "nFilledLen %d, %p", buf->omx_buf->nFilledLen, buf->omx_buf->pBuffer);
2516 #ifdef GST_TIZEN_MODIFICATION
2517 gst_buffer_extract (frame->input_buffer, offset,
2518 buf->mm_vbuffer->data[0] + buf->omx_buf->nOffset,
2519 buf->omx_buf->nFilledLen);
2521 gst_buffer_extract (frame->input_buffer, offset,
2522 buf->omx_buf->pBuffer + buf->omx_buf->nOffset,
2523 buf->omx_buf->nFilledLen);
2526 if (timestamp != GST_CLOCK_TIME_NONE) {
2527 buf->omx_buf->nTimeStamp =
2528 gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND);
2529 self->last_upstream_ts = timestamp;
2531 buf->omx_buf->nTimeStamp = 0;
2534 if (duration != GST_CLOCK_TIME_NONE && offset == 0) {
2535 buf->omx_buf->nTickCount =
2536 gst_util_uint64_scale (duration, OMX_TICKS_PER_SECOND, GST_SECOND);
2537 self->last_upstream_ts += duration;
2539 buf->omx_buf->nTickCount = 0;
2542 if (offset == 0 && GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame))
2543 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
2546 * - OMX_BUFFERFLAG_DECODEONLY for buffers that are outside
2550 offset += buf->omx_buf->nFilledLen;
2553 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
2555 self->started = TRUE;
2556 err = gst_omx_port_release_buffer (port, buf);
2557 if (err != OMX_ErrorNone)
2561 gst_video_codec_frame_unref (frame);
2563 GST_DEBUG_OBJECT (self, "Passed frame to component");
2565 return self->downstream_flow_ret;
2569 gst_video_codec_frame_unref (frame);
2570 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2571 ("Got OpenMAX buffer with no free space (%p, %u/%u)", buf,
2572 (guint) buf->omx_buf->nOffset, (guint) buf->omx_buf->nAllocLen));
2573 return GST_FLOW_ERROR;
2578 gst_video_codec_frame_unref (frame);
2580 return self->downstream_flow_ret;
2583 too_large_codec_data:
2585 gst_video_codec_frame_unref (frame);
2586 GST_ELEMENT_ERROR (self, STREAM, FORMAT, (NULL),
2587 ("codec_data larger than supported by OpenMAX port "
2588 "(%" G_GSIZE_FORMAT " > %u)", gst_buffer_get_size (codec_data),
2589 (guint) self->dec_in_port->port_def.nBufferSize));
2590 return GST_FLOW_ERROR;
2595 gst_video_codec_frame_unref (frame);
2596 GST_ELEMENT_ERROR (self, LIBRARY, FAILED, (NULL),
2597 ("OpenMAX component in error state %s (0x%08x)",
2598 gst_omx_component_get_last_error_string (self->dec),
2599 gst_omx_component_get_last_error (self->dec)));
2600 return GST_FLOW_ERROR;
2605 gst_video_codec_frame_unref (frame);
2606 GST_DEBUG_OBJECT (self, "Flushing -- returning FLUSHING");
2607 return GST_FLOW_FLUSHING;
2611 gst_video_codec_frame_unref (frame);
2612 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2613 ("Unable to reconfigure input port"));
2614 return GST_FLOW_ERROR;
2618 gst_video_codec_frame_unref (frame);
2619 GST_ELEMENT_ERROR (self, LIBRARY, SETTINGS, (NULL),
2620 ("Failed to relase input buffer to component: %s (0x%08x)",
2621 gst_omx_error_to_string (err), err));
2622 return GST_FLOW_ERROR;
2626 static GstFlowReturn
2627 gst_omx_video_dec_finish (GstVideoDecoder * decoder)
2629 GstOMXVideoDec *self;
2631 self = GST_OMX_VIDEO_DEC (decoder);
2633 return gst_omx_video_dec_drain (self);
2636 static GstFlowReturn
2637 gst_omx_video_dec_drain (GstOMXVideoDec * self)
2639 GstOMXVideoDecClass *klass;
2641 GstOMXAcquireBufferReturn acq_ret;
2644 GST_DEBUG_OBJECT (self, "Draining component");
2646 klass = GST_OMX_VIDEO_DEC_GET_CLASS (self);
2648 if (!self->started) {
2649 GST_DEBUG_OBJECT (self, "Component not started yet");
2652 self->started = FALSE;
2654 if ((klass->cdata.hacks & GST_OMX_HACK_NO_EMPTY_EOS_BUFFER)) {
2655 GST_WARNING_OBJECT (self, "Component does not support empty EOS buffers");
2659 /* Make sure to release the base class stream lock, otherwise
2660 * _loop() can't call _finish_frame() and we might block forever
2661 * because no input buffers are released */
2662 GST_VIDEO_DECODER_STREAM_UNLOCK (self);
2664 /* Send an EOS buffer to the component and let the base
2665 * class drop the EOS event. We will send it later when
2666 * the EOS buffer arrives on the output port. */
2667 acq_ret = gst_omx_port_acquire_buffer (self->dec_in_port, &buf);
2668 if (acq_ret != GST_OMX_ACQUIRE_BUFFER_OK) {
2669 GST_VIDEO_DECODER_STREAM_LOCK (self);
2670 GST_ERROR_OBJECT (self, "Failed to acquire buffer for draining: %d",
2672 return GST_FLOW_ERROR;
2675 g_mutex_lock (&self->drain_lock);
2676 self->draining = TRUE;
2677 buf->omx_buf->nFilledLen = 0;
2678 buf->omx_buf->nTimeStamp =
2679 gst_util_uint64_scale (self->last_upstream_ts, OMX_TICKS_PER_SECOND,
2681 buf->omx_buf->nTickCount = 0;
2682 buf->omx_buf->nFlags |= OMX_BUFFERFLAG_EOS;
2683 err = gst_omx_port_release_buffer (self->dec_in_port, buf);
2684 if (err != OMX_ErrorNone) {
2685 GST_ERROR_OBJECT (self, "Failed to drain component: %s (0x%08x)",
2686 gst_omx_error_to_string (err), err);
2687 g_mutex_unlock (&self->drain_lock);
2688 GST_VIDEO_DECODER_STREAM_LOCK (self);
2689 return GST_FLOW_ERROR;
2692 GST_DEBUG_OBJECT (self, "Waiting until component is drained");
2694 if (G_UNLIKELY (self->dec->hacks & GST_OMX_HACK_DRAIN_MAY_NOT_RETURN)) {
2695 gint64 wait_until = g_get_monotonic_time () + G_TIME_SPAN_SECOND / 2;
2697 if (!g_cond_wait_until (&self->drain_cond, &self->drain_lock, wait_until))
2698 GST_WARNING_OBJECT (self, "Drain timed out");
2700 GST_DEBUG_OBJECT (self, "Drained component");
2703 g_cond_wait (&self->drain_cond, &self->drain_lock);
2704 GST_DEBUG_OBJECT (self, "Drained component");
2707 g_mutex_unlock (&self->drain_lock);
2708 GST_VIDEO_DECODER_STREAM_LOCK (self);
2710 self->started = FALSE;
2716 gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
2718 GstBufferPool *pool;
2719 GstStructure *config;
2721 #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_GL)
2727 gst_query_parse_allocation (query, &caps, NULL);
2728 if (caps && gst_video_info_from_caps (&info, caps)
2729 && info.finfo->format == GST_VIDEO_FORMAT_RGBA) {
2730 gboolean found = FALSE;
2731 GstCapsFeatures *feature = gst_caps_get_features (caps, 0);
2732 /* Prefer an EGLImage allocator if available and we want to use it */
2733 n = gst_query_get_n_allocation_params (query);
2734 for (i = 0; i < n; i++) {
2735 GstAllocator *allocator;
2736 GstAllocationParams params;
2738 gst_query_parse_nth_allocation_param (query, i, &allocator, ¶ms);
2740 if (g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0) {
2742 gst_query_set_nth_allocation_param (query, 0, allocator, ¶ms);
2743 while (gst_query_get_n_allocation_params (query) > 1)
2744 gst_query_remove_nth_allocation_param (query, 1);
2747 gst_object_unref (allocator);
2754 /* if try to negotiate with caps feature memory:EGLImage
2755 * and if allocator is not of type memory EGLImage then fails */
2757 && gst_caps_features_contains (feature,
2758 GST_CAPS_FEATURE_MEMORY_EGL_IMAGE) && !found) {
2765 if (!GST_VIDEO_DECODER_CLASS
2766 (gst_omx_video_dec_parent_class)->decide_allocation (bdec, query))
2769 g_assert (gst_query_get_n_allocation_pools (query) > 0);
2770 gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
2771 g_assert (pool != NULL);
2773 config = gst_buffer_pool_get_config (pool);
2774 if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) {
2775 gst_buffer_pool_config_add_option (config,
2776 GST_BUFFER_POOL_OPTION_VIDEO_META);
2778 gst_buffer_pool_set_config (pool, config);
2779 gst_object_unref (pool);