diff options
Diffstat (limited to 'omx/gstomxvideodec.c')
-rw-r--r-- | omx/gstomxvideodec.c | 641 |
1 files changed, 603 insertions, 38 deletions
diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c index 74a71d4..9b9d6ec 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -3,6 +3,7 @@ * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd. * Copyright (C) 2013, Collabora Ltd. * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk> + * Copyright (c) 2013 - 2015, NVIDIA CORPORATION. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -38,7 +39,7 @@ #pragma GCC optimize ("gnu89-inline") #endif -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) +#if (defined (USE_OMX_TARGET_RPI) || defined (USE_OMX_TARGET_TEGRA)) && defined (HAVE_GST_EGL) #include <gst/egl/egl.h> #endif @@ -54,6 +55,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category); #define GST_CAT_DEFAULT gst_omx_video_dec_debug_category +#ifdef USE_OMX_TARGET_TEGRA +#define DEFAULT_USE_OMXDEC_RES FALSE +#endif + typedef struct _GstOMXMemory GstOMXMemory; typedef struct _GstOMXMemoryAllocator GstOMXMemoryAllocator; typedef struct _GstOMXMemoryAllocatorClass GstOMXMemoryAllocatorClass; @@ -76,6 +81,28 @@ struct _GstOMXMemoryAllocatorClass }; #define GST_OMX_MEMORY_TYPE "openmax" +#define GST_OMX_SINK_MEMORY_TYPE "omxsink" + +#define DEFAULT_SKIP_FRAME_TYPE GST_DECODE_ALL +#define GST_TYPE_OMX_VID_DEC_SKIP_FRAMES (gst_video_dec_skip_frames ()) +static GType +gst_video_dec_skip_frames (void) +{ + static GType qtype = 0; + + if (qtype == 0) { + static const GEnumValue values[] = { + {GST_DECODE_ALL, "GST_OMX_DECODE_ALL_FRAMES", "DECODE_ALL_Frames"}, + {GST_SKIP_NON_REF_FRAMES, "GST_OMX_DECODE_SKIP_NON_REF_FRAMES", + "SKIP_NON_REF_FRAMES"}, + {GST_DECODE_KEY_FRAMES, "GST_OMX_DECODE_KEY_FRAMES", "DECODE_KEY_FRAMES"}, + {0, NULL, NULL} + }; + + qtype = g_enum_register_static ("H264SkipFrame", values); + } + return qtype; +} static GstMemory * gst_omx_memory_allocator_alloc_dummy (GstAllocator * allocator, gsize size, @@ -214,6 +241,7 @@ gst_omx_memory_allocator_alloc (GstAllocator * allocator, GstMemoryFlags flags, */ static GQuark gst_omx_buffer_data_quark = 0; +extern GQuark gst_omx_sink_data_quark; #define GST_OMX_BUFFER_POOL(pool) ((GstOMXBufferPool *) pool) typedef struct _GstOMXBufferPool GstOMXBufferPool; @@ -265,6 +293,9 @@ GType gst_omx_buffer_pool_get_type (void); G_DEFINE_TYPE (GstOMXBufferPool, gst_omx_buffer_pool, GST_TYPE_BUFFER_POOL); +static void +gst_omx_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer); + static gboolean gst_omx_buffer_pool_start (GstBufferPool * bpool) { @@ -287,8 +318,14 @@ static gboolean gst_omx_buffer_pool_stop (GstBufferPool * bpool) { GstOMXBufferPool *pool = GST_OMX_BUFFER_POOL (bpool); + GstBuffer *buf; + guint i; /* Remove any buffers that are there */ + for (i = 0; i < pool->port->buffers->len; i++) { + buf = g_ptr_array_index (pool->buffers, i); + gst_omx_buffer_pool_free_buffer (bpool, buf); + } g_ptr_array_set_size (pool->buffers, 0); if (pool->caps) @@ -437,30 +474,58 @@ gst_omx_buffer_pool_alloc_buffer (GstBufferPool * bpool, gsize offset[4] = { 0, }; gint stride[4] = { 0, }; - switch (pool->video_info.finfo->format) { - case GST_VIDEO_FORMAT_I420: - offset[0] = 0; - stride[0] = pool->port->port_def.format.video.nStride; - offset[1] = - stride[0] * pool->port->port_def.format.video.nSliceHeight; - stride[1] = pool->port->port_def.format.video.nStride / 2; - offset[2] = - offset[1] + - stride[1] * (pool->port->port_def.format.video.nSliceHeight / 2); - stride[2] = pool->port->port_def.format.video.nStride / 2; - break; - case GST_VIDEO_FORMAT_NV12: +#ifdef USE_OMX_TARGET_TEGRA + OMX_INDEXTYPE eIndex; + GstOMXVideoDec *self = (GstOMXVideoDec *) pool->element; + OMX_ERRORTYPE eError = OMX_ErrorUndefined; + + eError = OMX_GetExtensionIndex (self->dec->handle, + (OMX_STRING) NVX_INDEX_CONFIG_VIDEOPLANESINFO, &eIndex); + + if (eError == OMX_ErrorNone) { + NVX_CONFIG_VIDEOPLANESINFO oInfo; + + GST_OMX_INIT_STRUCT (&oInfo); + + eError = OMX_GetConfig (self->dec->handle, eIndex, &oInfo); + + if (eError == OMX_ErrorNone) { offset[0] = 0; - stride[0] = pool->port->port_def.format.video.nStride; - offset[1] = - stride[0] * pool->port->port_def.format.video.nSliceHeight; - stride[1] = pool->port->port_def.format.video.nStride; - break; - default: - g_assert_not_reached (); - break; + stride[0] = oInfo.nAlign[0][0]; + offset[1] = oInfo.nAlign[0][0] * oInfo.nAlign[0][1]; + stride[1] = oInfo.nAlign[1][0] << 1; + offset[2] = offset[1] + stride[1] * oInfo.nAlign[1][1]; + stride[2] = oInfo.nAlign[2][0]; + } } + if (eError != OMX_ErrorNone) +#endif + switch (pool->video_info.finfo->format) { + case GST_VIDEO_FORMAT_I420: + offset[0] = 0; + stride[0] = pool->port->port_def.format.video.nStride; + offset[1] = + stride[0] * pool->port->port_def.format.video.nSliceHeight; + stride[1] = pool->port->port_def.format.video.nStride / 2; + offset[2] = + offset[1] + + stride[1] * (pool->port->port_def.format.video.nSliceHeight / + 2); + stride[2] = pool->port->port_def.format.video.nStride / 2; + break; + case GST_VIDEO_FORMAT_NV12: + offset[0] = 0; + stride[0] = pool->port->port_def.format.video.nStride; + offset[1] = + stride[0] * pool->port->port_def.format.video.nSliceHeight; + stride[1] = pool->port->port_def.format.video.nStride; + break; + default: + g_assert_not_reached (); + break; + } + gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE, GST_VIDEO_INFO_FORMAT (&pool->video_info), GST_VIDEO_INFO_WIDTH (&pool->video_info), @@ -524,6 +589,23 @@ gst_omx_buffer_pool_acquire_buffer (GstBufferPool * bpool, && g_strcmp0 (mem->allocator->mem_type, GST_OMX_MEMORY_TYPE) == 0); mem->size = ((GstOMXMemory *) mem)->buf->omx_buf->nFilledLen; mem->offset = ((GstOMXMemory *) mem)->buf->omx_buf->nOffset; + } else { +#ifdef USE_OMX_TARGET_TEGRA + GstMemory *mem = gst_buffer_peek_memory (buf, 0); + if (mem + && g_strcmp0 (mem->allocator->mem_type, + GST_OMX_SINK_MEMORY_TYPE) == 0) { + GstOMXBuffer *omxbuf = + gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf), + gst_omx_buffer_data_quark); + mem->size = omxbuf->omx_buf->nFilledLen; + mem->offset = omxbuf->omx_buf->nOffset; + omxbuf = + gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf), + gst_omx_sink_data_quark); + omxbuf->omx_buf->nFlags |= OMX_BUFFERFLAG_NV_BUFFER; + } +#endif } } else { /* Acquire any buffer that is available to be filled by upstream */ @@ -689,7 +771,13 @@ static OMX_ERRORTYPE gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec enum { - PROP_0 + PROP_0, +#ifdef USE_OMX_TARGET_TEGRA + PROP_USE_OMXDEC_RES, + PROP_USE_FULL_FRAME, + PROP_DISABLE_DPB, + PROP_SKIP_FRAME +#endif }; /* class initialization */ @@ -703,6 +791,60 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstOMXVideoDec, gst_omx_video_dec, GST_TYPE_VIDEO_DECODER, DEBUG_INIT); static void +gst_omx_video_dec_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object); + + switch (prop_id) { +#ifdef USE_OMX_TARGET_TEGRA + case PROP_USE_OMXDEC_RES: + self->use_omxdec_res = g_value_get_boolean (value); + break; + case PROP_USE_FULL_FRAME: + self->full_frame_data = g_value_get_boolean (value); + break; + case PROP_DISABLE_DPB: + self->disable_dpb = g_value_get_boolean (value); + break; + case PROP_SKIP_FRAME: + self->skip_frames = g_value_get_enum (value); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_omx_video_dec_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object); + + switch (prop_id) { +#ifdef USE_OMX_TARGET_TEGRA + case PROP_USE_OMXDEC_RES: + g_value_set_boolean (value, self->use_omxdec_res); + break; + case PROP_USE_FULL_FRAME: + g_value_set_boolean (value, self->full_frame_data); + break; + case PROP_DISABLE_DPB: + g_value_set_boolean (value, self->disable_dpb); + break; + case PROP_SKIP_FRAME: + g_value_set_enum (value, self->skip_frames); + break; +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); @@ -711,6 +853,38 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass) gobject_class->finalize = gst_omx_video_dec_finalize; + gobject_class->set_property = gst_omx_video_dec_set_property; + gobject_class->get_property = gst_omx_video_dec_get_property; + +#ifdef USE_OMX_TARGET_TEGRA + g_object_class_install_property (gobject_class, PROP_USE_OMXDEC_RES, + g_param_spec_boolean ("use-omxdec-res", + "Use resolution from omx decoder(for debugging purpose)", + "Omx decoder resolution to be used(for debugging purpose)", + DEFAULT_USE_OMXDEC_RES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_USE_FULL_FRAME, + g_param_spec_boolean ("full-frame", + "Full Frame data", + "Whether or not the data is full framed", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DISABLE_DPB, + g_param_spec_boolean ("disable-dpb", + "Disable H.264 DPB buffer", + "Set to disable H.264 DPB buffer for low latency", + FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SKIP_FRAME, + g_param_spec_enum ("skip-frames", + "Skip frames", + "Which type of frames to skip during decoding", + GST_TYPE_OMX_VID_DEC_SKIP_FRAMES, + DEFAULT_SKIP_FRAME_TYPE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_PLAYING)); +#endif + element_class->change_state = GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state); @@ -733,11 +907,33 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass) "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE; } +OMX_ERRORTYPE +gst_omx_set_full_frame_data_property (OMX_HANDLETYPE omx_handle) +{ + OMX_INDEXTYPE eIndex; + OMX_ERRORTYPE eError = OMX_ErrorNone; + OMX_CONFIG_BOOLEANTYPE full_frame_data; + GST_OMX_INIT_STRUCT (&full_frame_data); + eError = + OMX_GetExtensionIndex (omx_handle, + (OMX_STRING) "OMX.Nvidia.index.param.vdecfullframedata", &eIndex); + if (eError == OMX_ErrorNone) { + full_frame_data.bEnabled = OMX_TRUE; + OMX_SetParameter (omx_handle, eIndex, &full_frame_data); + } + return eError; +} + static void gst_omx_video_dec_init (GstOMXVideoDec * self) { gst_video_decoder_set_packetized (GST_VIDEO_DECODER (self), TRUE); +#ifdef USE_OMX_TARGET_TEGRA + self->use_omxdec_res = DEFAULT_USE_OMXDEC_RES; + self->full_frame_data = FALSE; +#endif + g_mutex_init (&self->drain_lock); g_cond_init (&self->drain_cond); } @@ -797,6 +993,16 @@ gst_omx_video_dec_open (GstVideoDecoder * decoder) GST_DEBUG_OBJECT (self, "Opened decoder"); +#ifdef USE_OMX_TARGET_TEGRA + { + OMX_PARAM_PORTDEFINITIONTYPE port_def; + + gst_omx_port_get_port_definition (self->dec_in_port, &port_def); + port_def.format.video.nFrameWidth = port_def.format.video.nFrameHeight = 0; + gst_omx_port_update_port_definition (self->dec_in_port, &port_def); + } +#endif + #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) GST_DEBUG_OBJECT (self, "Opening EGL renderer"); self->egl_render = @@ -876,7 +1082,7 @@ gst_omx_video_dec_shutdown (GstOMXVideoDec * self) } } - /* Otherwise we didn't use EGL and just fall back to + /* Otherwise we didn't use EGL and just fall back to * shutting down the decoder */ #endif @@ -1136,6 +1342,10 @@ gst_omx_video_dec_fill_buffer (GstOMXVideoDec * self, } /* Different strides */ +#ifdef USE_OMX_TARGET_TEGRA + /*TODO: get videoplanesinfo() for TEGRA, currently this path is not used */ + return FALSE; +#endif switch (vinfo->finfo->format) { case GST_VIDEO_FORMAT_I420:{ @@ -1259,6 +1469,7 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) GstBufferPool *pool; GstStructure *config; gboolean eglimage = FALSE, add_videometa = FALSE; + gboolean shared_buffer = FALSE; GstCaps *caps = NULL; guint min = 0, max = 0; GstVideoCodecState *state = @@ -1292,13 +1503,18 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) add_videometa = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) +#if (defined (USE_OMX_TARGET_RPI) || defined (USE_OMX_TARGET_TEGRA)) && defined (HAVE_GST_EGL) eglimage = self->eglimage && (allocator && g_strcmp0 (allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0); -#else - /* TODO: Implement something that works for other targets too */ - eglimage = FALSE; #endif + +#if defined (USE_OMX_TARGET_TEGRA) + if (!eglimage) { + shared_buffer = (allocator + && g_strcmp0 (allocator->mem_type, GST_OMX_SINK_MEMORY_TYPE) == 0); + } +#endif + caps = caps ? gst_caps_ref (caps) : NULL; GST_DEBUG_OBJECT (self, "Trying to use pool %p with caps %" GST_PTR_FORMAT @@ -1460,10 +1676,165 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self) } } } +#elif defined (USE_OMX_TARGET_TEGRA) + if (eglimage || shared_buffer) { + GList *buffers = NULL; + GList *pBuffers = NULL; + GList *l; + gint i; + GstBufferPoolAcquireParams params = { 0, }; + GstMapInfo map = GST_MAP_INFO_INIT; + GList *images = NULL; + + if (eglimage) { + GST_DEBUG_OBJECT (self, "Trying to allocate %d EGLImages", min); + + for (i = 0; i < min; i++) { + GstBuffer *buffer; + GstMemory *mem; + + if (gst_buffer_pool_acquire_buffer (pool, &buffer, + ¶ms) != GST_FLOW_OK || gst_buffer_n_memory (buffer) != 1 + || !(mem = gst_buffer_peek_memory (buffer, 0)) + || g_strcmp0 (mem->allocator->mem_type, + GST_EGL_IMAGE_MEMORY_TYPE) != 0) { + GST_INFO_OBJECT (self, "Failed to allocated %d-th EGLImage", i); + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + g_list_free (images); + buffers = NULL; + images = NULL; + err = OMX_ErrorUndefined; + goto done; + } + + buffers = g_list_append (buffers, buffer); + gst_egl_image_memory_set_orientation (mem, + GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP); + images = g_list_append (images, gst_egl_image_memory_get_image (mem)); + } + + GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min); + } else { + GST_DEBUG_OBJECT (self, "Trying to Use %d OMX Buffers", min); + + for (i = 0; i < min; i++) { + GstBuffer *buffer; + GstMemory *mem = NULL; + + if (gst_buffer_pool_acquire_buffer (pool, &buffer, + ¶ms) != GST_FLOW_OK || gst_buffer_n_memory (buffer) != 1 + || !(mem = gst_buffer_peek_memory (buffer, 0)) + || !(gst_memory_map (mem, &map, GST_MAP_WRITE)) + || g_strcmp0 (mem->allocator->mem_type, + GST_OMX_SINK_MEMORY_TYPE) != 0) { + GST_INFO_OBJECT (self, "Failed to use %d-th OMX Buffer", i); + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + g_list_free (pBuffers); + buffers = NULL; + pBuffers = NULL; + if (map.memory == mem) + gst_memory_unmap (mem, &map); + err = OMX_ErrorUndefined; + goto done; + } + + buffers = g_list_append (buffers, buffer); + pBuffers = g_list_append (pBuffers, map.data); + gst_memory_unmap (mem, &map); + } + + GST_DEBUG_OBJECT (self, "Allocated %d OMX Buffers", min); + } + + if (min != port->port_def.nBufferCountActual) { + err = gst_omx_port_update_port_definition (port, NULL); + if (err == OMX_ErrorNone) { + port->port_def.nBufferCountActual = min; + err = gst_omx_port_update_port_definition (port, &port->port_def); + } + + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to configure %u output buffers: %s (0x%08x)", min, + gst_omx_error_to_string (err), err); + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + goto done; + } + } + + if (!gst_omx_port_is_enabled (port)) { + + NVX_PARAM_USENVBUFFER param; + OMX_INDEXTYPE eIndex; + + GST_DEBUG_OBJECT (self, "Setting decoder to use Nvmm buffer"); + + err = gst_omx_component_get_index (self->dec, + (char *) NVX_INDEX_CONFIG_USENVBUFFER, &eIndex); + + if (!eglimage) { + if (err == OMX_ErrorNone) { + GST_OMX_INIT_STRUCT (¶m); + param.nPortIndex = self->dec_out_port->index; + param.bUseNvBuffer = OMX_TRUE; + err = gst_omx_component_set_parameter (self->dec, eIndex, ¶m); + } else { + GST_WARNING_OBJECT (self, "Coudn't get extension index for %s", + (char *) NVX_INDEX_CONFIG_USENVBUFFER); + goto done; + } + } + + if (err != OMX_ErrorNone) { + GST_WARNING_OBJECT (self, "Couldn't use HW Accelerated path"); + goto done; + } + + err = gst_omx_port_set_enabled (port, TRUE); + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to enable port: %s (0x%08x)", + gst_omx_error_to_string (err), err); + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + goto done; + } + } + + if (eglimage) + err = gst_omx_port_use_eglimages (port, images); + else + err = gst_omx_port_use_buffers (port, pBuffers); + + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to pass OMX Buffers to port: %s (0x%08x)", + gst_omx_error_to_string (err), err); + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + goto done; + } + + err = gst_omx_port_wait_enabled (port, 2 * GST_SECOND); + if (err != OMX_ErrorNone) { + GST_INFO_OBJECT (self, + "Failed to wait until port is enabled: %s (0x%08x)", + gst_omx_error_to_string (err), err); + g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref); + goto done; + } + + GST_DEBUG_OBJECT (self, "Populating internal buffer pool"); + GST_OMX_BUFFER_POOL (self->out_port_pool)->other_pool = + GST_BUFFER_POOL (gst_object_ref (pool)); + for (l = buffers; l; l = l->next) { + g_ptr_array_add (GST_OMX_BUFFER_POOL (self->out_port_pool)->buffers, + l->data); + } + g_list_free (buffers); + } #endif /* If not using EGLImage or trying to use EGLImage failed */ - if (!eglimage) { + if (!eglimage && !shared_buffer) { gboolean was_enabled = TRUE; if (min != port->port_def.nBufferCountActual) { @@ -1615,6 +1986,74 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self) return err; } +#if defined (USE_OMX_TARGET_TEGRA) && defined (HAVE_GST_EGL) +static NvBufType +gst_omx_video_dec_negotiate_nv_caps (GstOMXVideoDec * self, + GstVideoCodecState * state) +{ + GstPad *peer = NULL; + OMX_ERRORTYPE err = OMX_ErrorNone; + + peer = gst_pad_get_peer (GST_VIDEO_DECODER_SRC_PAD (self)); + + if (peer) { + GstCaps *icaps; + GstCapsFeatures *ift; + + icaps = gst_video_info_to_caps (&state->info); + icaps = gst_caps_make_writable (icaps); + + ift = gst_caps_features_new ("memory:EGLImage"); + gst_caps_set_features (icaps, 0, ift); + + if (gst_pad_query_accept_caps (peer, icaps)) { + gst_caps_unref (icaps); + gst_object_unref (peer); + return BUF_EGL; + } else { + gst_caps_features_add (ift, "memory:NVMM"); + gst_caps_features_remove (ift, "memory:EGLImage"); + + if (gst_pad_query_accept_caps (peer, icaps)) { + gst_caps_unref (icaps); + gst_object_unref (peer); + if (!gst_omx_port_is_enabled (self->dec_out_port)) { + NVX_PARAM_USENVBUFFER param; + OMX_INDEXTYPE eIndex; + + GST_DEBUG_OBJECT (self, "Setting decoder to use Nvmm buffer"); + + err = gst_omx_component_get_index (self->dec, + (char *) NVX_INDEX_CONFIG_USENVBUFFER, &eIndex); + + if (err == OMX_ErrorNone) { + GST_OMX_INIT_STRUCT (¶m); + param.nPortIndex = self->dec_out_port->index; + param.bUseNvBuffer = OMX_TRUE; + err = gst_omx_component_set_parameter (self->dec, eIndex, ¶m); + } else { + GST_WARNING_OBJECT (self, "Coudn't get extension index for %s", + (char *) NVX_INDEX_CONFIG_USENVBUFFER); + goto done; + } + + if (err != OMX_ErrorNone) { + GST_WARNING_OBJECT (self, "Couldn't use HW Accelerated path"); + goto done; + } + } + return BUF_NVMM; + } + } + + gst_caps_unref (icaps); + gst_object_unref (peer); + } +done: + return BUF_NB; +} +#endif + static OMX_ERRORTYPE gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self) { @@ -1624,6 +2063,10 @@ gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self) OMX_PARAM_PORTDEFINITIONTYPE port_def; GstVideoFormat format; +#if defined (USE_OMX_TARGET_TEGRA) && defined (HAVE_GST_EGL) + NvBufType nv_buf = BUF_NB; +#endif + /* At this point the decoder output port is disabled */ #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) @@ -1750,7 +2193,6 @@ gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self) if (err != OMX_ErrorNone) goto no_egl; - err = gst_omx_port_mark_reconfigured (self->dec_out_port); if (err != OMX_ErrorNone) goto no_egl; @@ -1817,6 +2259,68 @@ gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self) break; } +#ifdef USE_OMX_TARGET_TEGRA + if (!self->use_omxdec_res) { + OMX_INDEXTYPE eIndex; + OMX_ERRORTYPE eError; + OMX_U32 frame_size; + + eError = OMX_GetExtensionIndex (self->dec->handle, + (OMX_STRING) NVX_INDEX_CONFIG_VIDEOPLANESINFO, &eIndex); + + if (eError == OMX_ErrorNone) { + NVX_CONFIG_VIDEOPLANESINFO oInfo; + + GST_OMX_INIT_STRUCT (&oInfo); + + eError = OMX_GetConfig (self->dec->handle, eIndex, &oInfo); + if (eError == OMX_ErrorNone) { + GstOMXPort *iport = self->dec_in_port; + OMX_PARAM_PORTDEFINITIONTYPE iport_def; + + GST_OMX_INIT_STRUCT (&iport_def); + gst_omx_port_get_port_definition (iport, &iport_def); + + if (iport_def.format.video.nFrameWidth && + iport_def.format.video.nFrameHeight) { + switch (format) { + case GST_VIDEO_FORMAT_NV12: + oInfo.nAlign[0][0] = + GST_ROUND_UP_4 (iport_def.format.video.nFrameWidth); + oInfo.nAlign[0][1] = + GST_ROUND_UP_2 (iport_def.format.video.nFrameHeight); + oInfo.nAlign[1][0] = + (GST_ROUND_UP_4 (iport_def.format.video.nFrameWidth)) >> 1; + oInfo.nAlign[1][1] = + (GST_ROUND_UP_2 (iport_def.format.video.nFrameHeight)) >> 1; + frame_size = + oInfo.nAlign[0][0] * oInfo.nAlign[0][1] + + oInfo.nAlign[1][0] * oInfo.nAlign[1][1]; + break; + default: + eError = OMX_ErrorUnsupportedSetting; + break; + } + + if (eError == OMX_ErrorNone) + eError = OMX_SetConfig (self->dec->handle, eIndex, &oInfo); + } else + eError = OMX_ErrorUnsupportedSetting; + } + } + + if (eError == OMX_ErrorNone) { + port_def.nBufferSize = frame_size; + gst_omx_port_update_port_definition (port, &port_def); + gst_omx_port_get_port_definition (port, &port_def); + + } else + g_warning ("omxvideodec: failed to set output video alignment %x", + eError); + + } +#endif + GST_DEBUG_OBJECT (self, "Setting output state: format %s, width %u, height %u", gst_video_format_to_string (format), @@ -1833,6 +2337,23 @@ gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self) err = OMX_ErrorUndefined; goto done; } +#if defined (USE_OMX_TARGET_TEGRA) && defined (HAVE_GST_EGL) + { + nv_buf = gst_omx_video_dec_negotiate_nv_caps (self, state); + if (nv_buf == BUF_EGL) { + state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self), + GST_VIDEO_FORMAT_RGBA, port_def.format.video.nFrameWidth, + port_def.format.video.nFrameHeight, self->input_state); + + if (gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) { + self->eglimage = TRUE; + } else { + GST_ERROR_OBJECT (self, "Failed to negotiate RGBA for EGLImage"); + self->eglimage = FALSE; + } + } + } +#endif gst_video_codec_state_unref (state); @@ -1895,6 +2416,10 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) /* Reallocate all buffers */ if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE && gst_omx_port_is_enabled (port)) { + gst_pad_push_event (GST_VIDEO_DECODER_SRC_PAD (self), + gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, + gst_structure_new_empty("ReleaseLastBuffer"))); + err = gst_omx_port_set_enabled (port, FALSE); if (err != OMX_ErrorNone) goto reconfigure_error; @@ -2353,6 +2878,7 @@ gst_omx_video_dec_get_supported_colorformats (GstOMXVideoDec * self) if (err == OMX_ErrorNone || err == OMX_ErrorNoMore) { switch (param.eColorFormat) { + case OMX_COLOR_FormatYUV420Planar: case OMX_COLOR_FormatYUV420PackedPlanar: m = g_slice_new (VideoNegotiationMap); @@ -2538,6 +3064,7 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (self, "Need to disable and drain decoder"); gst_omx_video_dec_drain (self, FALSE); + gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE); gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE); /* Wait until the srcpad loop is finished, @@ -2568,23 +3095,26 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder, if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone) return FALSE; - if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone) - return FALSE; if (gst_omx_port_wait_buffers_released (self->dec_in_port, 5 * GST_SECOND) != OMX_ErrorNone) return FALSE; - if (gst_omx_port_wait_buffers_released (out_port, - 1 * GST_SECOND) != OMX_ErrorNone) - return FALSE; if (gst_omx_port_deallocate_buffers (self->dec_in_port) != OMX_ErrorNone) return FALSE; - if (gst_omx_video_dec_deallocate_output_buffers (self) != OMX_ErrorNone) - return FALSE; if (gst_omx_port_wait_enabled (self->dec_in_port, 1 * GST_SECOND) != OMX_ErrorNone) return FALSE; + +#ifndef USE_OMX_TARGET_TEGRA + if (gst_omx_port_set_enabled (out_port, FALSE) != OMX_ErrorNone) + return FALSE; + if (gst_omx_port_wait_buffers_released (out_port, + 1 * GST_SECOND) != OMX_ErrorNone) + return FALSE; + if (gst_omx_video_dec_deallocate_output_buffers (self) != OMX_ErrorNone) + return FALSE; if (gst_omx_port_wait_enabled (out_port, 1 * GST_SECOND) != OMX_ErrorNone) return FALSE; +#endif #if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) if (self->eglimage) { @@ -2792,10 +3322,12 @@ gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder, return GST_FLOW_EOS; } +#ifndef USE_OMX_TARGET_TEGRA if (!self->started && !GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) { gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame); return GST_FLOW_OK; } +#endif timestamp = frame->pts; duration = frame->duration; @@ -2950,6 +3482,8 @@ gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder, buf->omx_buf->nTimeStamp = gst_util_uint64_scale (timestamp, OMX_TICKS_PER_SECOND, GST_SECOND); self->last_upstream_ts = timestamp; + } else if (duration != GST_CLOCK_TIME_NONE) { + buf->omx_buf->nTimeStamp = self->last_upstream_ts + duration; } else { buf->omx_buf->nTimeStamp = 0; } @@ -3155,8 +3689,13 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) { GstBufferPool *pool; GstStructure *config; + GstCaps *caps; + guint max = 0, min = 0, size; + GstOMXPort *port; + GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (bdec); + OMX_ERRORTYPE err = OMX_ErrorNone; -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) +#if (defined (USE_OMX_TARGET_RPI) || defined (USE_OMX_TARGET_TEGRA)) && defined (HAVE_GST_EGL) { GstCaps *caps; gint i, n; @@ -3193,6 +3732,32 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query) gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); g_assert (pool != NULL); +#ifdef USE_OMX_TARGET_TEGRA + port = self->dec_out_port; + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_get_params (config, &caps, &size, &min, &max); + + min = MAX (MAX (min, port->port_def.nBufferCountMin), 4); + + if (min != port->port_def.nBufferCountActual) { + err = gst_omx_port_update_port_definition (port, NULL); + if (err == OMX_ErrorNone) { + port->port_def.nBufferCountActual = min; + err = gst_omx_port_update_port_definition (port, &port->port_def); + } + if (err == OMX_ErrorNone) { + gst_buffer_pool_config_set_params (config, caps, size, min, max); + if (!gst_buffer_pool_set_config (pool, config)) { + GST_INFO_OBJECT (self, "Failed to set config on internal pool"); + } + } else { + gst_structure_free (config); + } + } else { + gst_structure_free (config); + } +#endif + config = gst_buffer_pool_get_config (pool); if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL)) { gst_buffer_pool_config_add_option (config, |