summaryrefslogtreecommitdiff
path: root/omx/gstomxvideodec.c
diff options
context:
space:
mode:
Diffstat (limited to 'omx/gstomxvideodec.c')
-rw-r--r--omx/gstomxvideodec.c641
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,
+ &params) != 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,
+ &params) != 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 (&param);
+ param.nPortIndex = self->dec_out_port->index;
+ param.bUseNvBuffer = OMX_TRUE;
+ err = gst_omx_component_set_parameter (self->dec, eIndex, &param);
+ } 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 (&param);
+ param.nPortIndex = self->dec_out_port->index;
+ param.bUseNvBuffer = OMX_TRUE;
+ err = gst_omx_component_set_parameter (self->dec, eIndex, &param);
+ } 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,