summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosep Torra <n770galaxy@gmail.com>2013-04-05 17:21:46 +0200
committerJosep Torra <n770galaxy@gmail.com>2013-05-10 09:37:08 +0200
commitfdb29933cc56e8f83d219b93650c38ec08842230 (patch)
tree3e10e165767376dfe9d49084acf11ea7e428381a
parent65a5473ee7f5b151e4f0b975e168c72deb9910f3 (diff)
omxvideodec: implement EGL transport
-rw-r--r--omx/Makefile.am7
-rw-r--r--omx/gstomx.c16
-rw-r--r--omx/gstomx.h8
-rw-r--r--omx/gstomxvideodec.c927
-rw-r--r--omx/gstomxvideodec.h30
5 files changed, 863 insertions, 125 deletions
diff --git a/omx/Makefile.am b/omx/Makefile.am
index b563404..da1ab50 100644
--- a/omx/Makefile.am
+++ b/omx/Makefile.am
@@ -17,6 +17,10 @@ VP8_C_FILES=gstomxvp8dec.c
VP8_H_FILES=gstomxvp8dec.h
endif
+if HAVE_EGL
+GST_EGL_LIBS = $(top_builddir)/gst/egl/libgstegl-$(GST_MAJORMINOR).la
+endif
+
libgstopenmax_la_SOURCES = \
gstomx.c \
gstomxvideodec.c \
@@ -73,7 +77,8 @@ libgstopenmax_la_LIBADD = \
-lgstpbutils-@GST_MAJORMINOR@ \
-lgstvideo-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) \
- $(GST_LIBS)
+ $(GST_LIBS) \
+ $(GST_EGL_LIBS)
libgstopenmax_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/omx/gstomx.c b/omx/gstomx.c
index 374acf7..8bd1435 100644
--- a/omx/gstomx.c
+++ b/omx/gstomx.c
@@ -1069,14 +1069,10 @@ gst_omx_component_setup_tunnel (GstOMXComponent * comp1, GstOMXPort * port1,
OMX_ERRORTYPE err;
g_return_val_if_fail (comp1 != NULL, OMX_ErrorUndefined);
- g_return_val_if_fail (comp1->state == OMX_StateLoaded
- || !port1->port_def.bEnabled, OMX_ErrorUndefined);
g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
OMX_ErrorUndefined);
g_return_val_if_fail (comp2 != NULL, OMX_ErrorUndefined);
- g_return_val_if_fail (comp2->state == OMX_StateLoaded
- || !port2->port_def.bEnabled, OMX_ErrorUndefined);
g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
OMX_ErrorUndefined);
@@ -1114,14 +1110,10 @@ gst_omx_component_close_tunnel (GstOMXComponent * comp1, GstOMXPort * port1,
OMX_ERRORTYPE err;
g_return_val_if_fail (comp1 != NULL, OMX_ErrorUndefined);
- g_return_val_if_fail (comp1->state == OMX_StateLoaded
- || !port1->port_def.bEnabled, OMX_ErrorUndefined);
g_return_val_if_fail (port1 != NULL, OMX_ErrorUndefined);
g_return_val_if_fail (port1->port_def.eDir == OMX_DirOutput,
OMX_ErrorUndefined);
g_return_val_if_fail (comp2 != NULL, OMX_ErrorUndefined);
- g_return_val_if_fail (comp2->state == OMX_StateLoaded
- || !port2->port_def.bEnabled, OMX_ErrorUndefined);
g_return_val_if_fail (port2 != NULL, OMX_ErrorUndefined);
g_return_val_if_fail (port2->port_def.eDir == OMX_DirInput,
OMX_ErrorUndefined);
@@ -1611,6 +1603,7 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
OMX_ERRORTYPE err = OMX_ErrorNone;
gint i;
const GList *l;
+ gint eglimage = 0;
g_assert (!port->buffers || port->buffers->len == 0);
@@ -1661,17 +1654,18 @@ gst_omx_port_allocate_buffers_unlocked (GstOMXPort * port,
err =
OMX_UseBuffer (comp->handle, &buf->omx_buf, port->index, buf,
port->port_def.nBufferSize, l->data);
- buf->eglimage = FALSE;
+ buf->eglimage = -1;
} else if (images) {
err =
OMX_UseEGLImage (comp->handle, &buf->omx_buf, port->index, buf,
l->data);
- buf->eglimage = TRUE;
+ buf->eglimage = eglimage;
+ eglimage++;
} else {
err =
OMX_AllocateBuffer (comp->handle, &buf->omx_buf, port->index, buf,
port->port_def.nBufferSize);
- buf->eglimage = FALSE;
+ buf->eglimage = -1;
}
if (err != OMX_ErrorNone) {
diff --git a/omx/gstomx.h b/omx/gstomx.h
index 5cb06ca..b89dfd7 100644
--- a/omx/gstomx.h
+++ b/omx/gstomx.h
@@ -48,6 +48,10 @@
#include <OMX_Core.h>
#include <OMX_Component.h>
+#ifdef USE_OMX_TARGET_RPI
+#include <OMX_Broadcom.h>
+#endif
+
#ifdef GST_OMX_STRUCT_PACKING
#pragma pack()
#endif
@@ -265,8 +269,8 @@ struct _GstOMXBuffer {
/* Cookie of the settings when this buffer was allocated */
gint settings_cookie;
- /* TRUE if this is an EGLImage */
- gboolean eglimage;
+ /* > -1 if this is an EGLImage */
+ gint eglimage;
};
struct _GstOMXClassData {
diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c
index 9ab97ca..e91413b 100644
--- a/omx/gstomxvideodec.c
+++ b/omx/gstomxvideodec.c
@@ -3,6 +3,8 @@
* 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, Fluendo S.A.
+ * Author: Josep Torra <josep@fluendo.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -32,6 +34,8 @@
GST_DEBUG_CATEGORY_STATIC (gst_omx_video_dec_debug_category);
#define GST_CAT_DEFAULT gst_omx_video_dec_debug_category
+#define N_EGL_IMAGES 4
+
typedef struct _BufferIdentification BufferIdentification;
struct _BufferIdentification
{
@@ -46,6 +50,10 @@ buffer_identification_free (BufferIdentification * id)
/* prototypes */
static void gst_omx_video_dec_finalize (GObject * object);
+static void gst_omx_video_dec_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_omx_video_dec_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
static GstStateChangeReturn
gst_omx_video_dec_change_state (GstElement * element,
@@ -74,6 +82,9 @@ static OMX_ERRORTYPE gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec
enum
{
PROP_0
+#ifdef USE_EGL_RPI
+ , PROP_POOL
+#endif
};
/* class initialization */
@@ -98,6 +109,15 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (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_EGL_RPI
+ g_object_class_install_property (gobject_class, PROP_POOL,
+ g_param_spec_boxed ("pool", "Pool", "The EGL pool",
+ GST_TYPE_EGL_IMAGE_MEMORY_POOL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_omx_video_dec_change_state);
@@ -115,6 +135,9 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass)
klass->cdata.default_src_template_caps = "video/x-raw-yuv, "
"width = " GST_VIDEO_SIZE_RANGE ", "
+ "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE
+ "; video/x-raw-rgb, "
+ "width = " GST_VIDEO_SIZE_RANGE ", "
"height = " GST_VIDEO_SIZE_RANGE ", " "framerate = " GST_VIDEO_FPS_RANGE;
}
@@ -182,6 +205,53 @@ gst_omx_video_dec_open (GstVideoDecoder * decoder)
GST_DEBUG_OBJECT (self, "Opened decoder");
+#ifdef USE_EGL_RPI
+ GST_DEBUG_OBJECT (self, "Opening EGL renderer");
+ self->egl_render =
+ gst_omx_component_new (GST_OBJECT_CAST (self), klass->cdata.core_name,
+ "OMX.broadcom.egl_render", NULL, klass->cdata.hacks);
+
+ if (!self->egl_render)
+ return FALSE;
+
+ if (gst_omx_component_get_state (self->egl_render,
+ GST_CLOCK_TIME_NONE) != OMX_StateLoaded)
+ return FALSE;
+
+ {
+ OMX_PORT_PARAM_TYPE param;
+ OMX_ERRORTYPE err;
+
+ GST_OMX_INIT_STRUCT (&param);
+
+ err =
+ gst_omx_component_get_parameter (self->egl_render,
+ OMX_IndexParamVideoInit, &param);
+ if (err != OMX_ErrorNone) {
+ GST_WARNING_OBJECT (self, "Couldn't get port information: %s (0x%08x)",
+ gst_omx_error_to_string (err), err);
+ /* Fallback */
+ in_port_index = 0;
+ out_port_index = 1;
+ } else {
+ GST_DEBUG_OBJECT (self, "Detected %u ports, starting at %u", param.nPorts,
+ param.nStartPortNumber);
+ in_port_index = param.nStartPortNumber + 0;
+ out_port_index = param.nStartPortNumber + 1;
+ }
+ }
+
+ self->egl_in_port =
+ gst_omx_component_add_port (self->egl_render, in_port_index);
+ self->egl_out_port =
+ gst_omx_component_add_port (self->egl_render, out_port_index);
+
+ if (!self->egl_in_port || !self->egl_out_port)
+ return FALSE;
+
+ GST_DEBUG_OBJECT (self, "Opened EGL renderer");
+#endif
+
return TRUE;
}
@@ -192,6 +262,32 @@ gst_omx_video_dec_shutdown (GstOMXVideoDec * self)
GST_DEBUG_OBJECT (self, "Shutting down decoder");
+#ifdef USE_EGL_RPI
+ state = gst_omx_component_get_state (self->egl_render, 0);
+ if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
+ if (state > OMX_StateIdle) {
+ gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
+ gst_omx_component_set_state (self->dec, OMX_StateIdle);
+ gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
+ gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
+ }
+ gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
+ gst_omx_component_set_state (self->dec, OMX_StateLoaded);
+
+ gst_omx_port_deallocate_buffers (self->dec_in_port);
+ gst_omx_video_dec_deallocate_output_buffers (self);
+ gst_omx_component_close_tunnel (self->dec, self->dec_out_port,
+ self->egl_render, self->egl_in_port);
+ if (state > OMX_StateLoaded) {
+ gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
+ gst_omx_component_get_state (self->dec, 1 * GST_SECOND);
+ }
+ }
+
+ /* Otherwise we didn't use EGL and just fall back to
+ * shutting down the decoder */
+#endif
+
state = gst_omx_component_get_state (self->dec, 0);
if (state > OMX_StateLoaded || state == OMX_StateInvalid) {
if (state > OMX_StateIdle) {
@@ -224,6 +320,19 @@ gst_omx_video_dec_close (GstVideoDecoder * decoder)
gst_omx_component_free (self->dec);
self->dec = NULL;
+#ifdef USE_EGL_RPI
+ self->egl_in_port = NULL;
+ self->egl_out_port = NULL;
+ if (self->egl_render)
+ gst_omx_component_free (self->egl_render);
+ self->egl_render = NULL;
+
+ if (self->egl_display)
+ gst_egl_display_unref (self->egl_display);
+
+ self->egl_display = NULL;
+#endif
+
self->started = FALSE;
GST_DEBUG_OBJECT (self, "Closed decoder");
@@ -232,6 +341,45 @@ gst_omx_video_dec_close (GstVideoDecoder * decoder)
}
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_EGL_RPI
+ case PROP_POOL:
+ if (self->out_port_pool) {
+ gst_egl_image_memory_pool_unref (self->out_port_pool);
+ }
+ self->out_port_pool = g_value_get_boxed (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_EGL_RPI
+ case PROP_POOL:
+ g_value_set_boxed (value, self->out_port_pool);
+ break;
+#endif
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
gst_omx_video_dec_finalize (GObject * object)
{
GstOMXVideoDec *self = GST_OMX_VIDEO_DEC (object);
@@ -267,6 +415,12 @@ gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition)
gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
if (self->dec_out_port)
gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
+#ifdef USE_EGL_RPI
+ if (self->egl_in_port)
+ gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
+ if (self->egl_out_port)
+ gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
+#endif
g_mutex_lock (self->drain_lock);
self->draining = FALSE;
@@ -352,7 +506,7 @@ _find_nearest_frame (GstOMXVideoDec * self, GstOMXBuffer * buf)
}
}
- if (best_id) {
+ if (FALSE && best_id) {
for (l = frames; l && l != best_l; l = l->next) {
GstVideoCodecFrame *tmp = l->data;
BufferIdentification *id = gst_video_codec_frame_get_user_data (tmp);
@@ -382,7 +536,7 @@ _find_nearest_frame (GstOMXVideoDec * self, GstOMXBuffer * buf)
}
}
- if (finish_frames) {
+ if (FALSE && finish_frames) {
g_warning ("Too old frames, bug in decoder -- please file a bug");
for (l = finish_frames; l; l = l->next) {
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), l->data);
@@ -568,12 +722,121 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
{
OMX_ERRORTYPE err = OMX_ErrorNone;
GstOMXPort *port;
- guint min;
+ guint min = 1;
gboolean was_enabled = TRUE;
+ GstVideoCodecState *state =
+ gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
+ GstVideoInfo *vinfo = &state->info;
+
+#ifdef USE_EGL_RPI
+ if (self->egl_transport_active) {
+ GList *images = NULL;
+
+ port = self->egl_out_port;
+ min = N_EGL_IMAGES;
+
+ if (!self->out_port_pool) {
+ gst_element_post_message (GST_ELEMENT_CAST (self),
+ gst_message_new_need_egl_pool (GST_OBJECT (self), min,
+ vinfo->width, vinfo->height));
+ if (!self->out_port_pool) {
+ err = OMX_ErrorUndefined;
+ goto done;
+ }
+ }
+
+ if (self->egl_display) {
+ gst_egl_display_unref (self->egl_display);
+ }
+ self->egl_display =
+ gst_egl_image_memory_pool_get_display (self->out_port_pool);
+ images = gst_egl_image_memory_pool_get_images (self->out_port_pool);
+
+ if (images) {
+ GST_DEBUG_OBJECT (self, "Setting EGLDisplay");
+ self->egl_out_port->port_def.format.video.pNativeWindow =
+ gst_egl_display_get (self->egl_display);
+ err =
+ gst_omx_port_update_port_definition (self->egl_out_port,
+ &self->egl_out_port->port_def);
+
+ if (err != OMX_ErrorNone) {
+ GST_INFO_OBJECT (self,
+ "Failed to set EGLDisplay on port: %s (0x%08x)",
+ gst_omx_error_to_string (err), err);
+ g_list_free (images);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ goto done;
+ } else {
+ 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 (images);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+
+ goto done;
+ }
+ }
+
+ if (!gst_omx_port_is_enabled (port)) {
+ 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 (images);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ goto done;
+ }
+ }
+ err = gst_omx_port_use_eglimages (port, images);
+ g_list_free (images);
+
+ if (err != OMX_ErrorNone) {
+ GST_INFO_OBJECT (self,
+ "Failed to pass EGLImages to port: %s (0x%08x)",
+ gst_omx_error_to_string (err), err);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ 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);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ goto done;
+ }
+ GST_DEBUG_OBJECT (self, "Activate EGL memory pool");
+ gst_egl_image_memory_pool_set_active (self->out_port_pool, TRUE);
+ }
+ /* All good and done */
+ err = OMX_ErrorNone;
+ goto done;
+ }
+ } else {
+ port = self->dec_out_port;
+ }
+#else
port = self->dec_out_port;
+#endif
- min = MAX (1, port->port_def.nBufferCountMin);
+ min = MAX (min, port->port_def.nBufferCountMin);
if (min != port->port_def.nBufferCountActual) {
err = gst_omx_port_update_port_definition (port, NULL);
@@ -621,7 +884,7 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
if (err != OMX_ErrorNone) {
GST_ERROR_OBJECT (self,
- "Failed to configure %n output buffers: %s (0x%08x)", min,
+ "Failed to configure %u output buffers: %s (0x%08x)", min,
gst_omx_error_to_string (err), err);
goto done;
}
@@ -649,7 +912,7 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
err = OMX_ErrorNone;
done:
-
+ gst_video_codec_state_unref (state);
return err;
}
@@ -657,16 +920,279 @@ static OMX_ERRORTYPE
gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
{
OMX_ERRORTYPE err;
+ GstOMXPort *port = self->dec_out_port;
+
+#ifdef USE_EGL_RPI
+ if (self->out_port_pool) {
+ gst_egl_image_memory_pool_set_active (self->out_port_pool, FALSE);
+ gst_egl_image_memory_pool_wait_released (self->out_port_pool);
+ gst_egl_image_memory_pool_unref (self->out_port_pool);
+ self->out_port_pool = NULL;
+ }
+ if (self->egl_transport_active) {
+ port = self->egl_out_port;
+ }
+#endif
+
+ err = gst_omx_port_deallocate_buffers (port);
+
+ return err;
+}
+
+static OMX_ERRORTYPE
+gst_omx_video_dec_reconfigure_output_port (GstOMXVideoDec * self)
+{
+ GstOMXPort *port;
+ OMX_ERRORTYPE err;
+ GstVideoCodecState *state;
+ OMX_PARAM_PORTDEFINITIONTYPE port_def;
+ GstVideoFormat format;
+
+ /* At this point the decoder output port is disabled */
+
+#ifdef USE_EGL_RPI
+ if (!self->egl_transport_allowed) {
+ goto no_egl;
+ } else {
+ OMX_STATETYPE egl_state;
+
+ if (self->egl_transport_active) {
+ /* Nothing to do here, we could however fall back to non-EGLImage in theory */
+ port = self->egl_out_port;
+ err = OMX_ErrorNone;
+ goto enable_port;
+ } else {
+ /* Set up egl_render */
+ self->egl_transport_active = TRUE;
+ gst_omx_port_get_port_definition (self->dec_out_port, &port_def);
+ GST_VIDEO_DECODER_STREAM_LOCK (self);
+ 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))) {
+ gst_video_codec_state_unref (state);
+ GST_ERROR_OBJECT (self, "Failed to negotiate RGBA for EGLImage");
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+ goto no_egl;
+ }
+
+ gst_video_codec_state_unref (state);
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+
+ /* Now link it all together */
+
+ err = gst_omx_port_set_enabled (self->egl_in_port, FALSE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_set_enabled (self->egl_out_port, FALSE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_wait_enabled (self->egl_out_port, 1 * GST_SECOND);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ {
+#define OMX_IndexParamBrcmVideoEGLRenderDiscardMode 0x7f0000db
+ OMX_CONFIG_PORTBOOLEANTYPE discardMode;
+ memset (&discardMode, 0, sizeof (discardMode));
+ discardMode.nSize = sizeof (discardMode);
+ discardMode.nPortIndex = 220;
+ discardMode.nVersion.nVersion = OMX_VERSION;
+ discardMode.bEnabled = OMX_FALSE;
+ if (gst_omx_component_set_parameter (self->egl_render,
+ OMX_IndexParamBrcmVideoEGLRenderDiscardMode,
+ &discardMode) != OMX_ErrorNone)
+ goto no_egl;
+#undef OMX_IndexParamBrcmVideoEGLRenderDiscardMode
+ }
+
+ err =
+ gst_omx_component_setup_tunnel (self->dec, self->dec_out_port,
+ self->egl_render, self->egl_in_port);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_set_enabled (self->egl_in_port, TRUE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_wait_enabled (self->egl_in_port, 1 * GST_SECOND);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ if (gst_omx_component_get_state (self->egl_render,
+ GST_CLOCK_TIME_NONE) != OMX_StateIdle)
+ goto no_egl;
+
+ err = gst_omx_video_dec_allocate_output_buffers (self);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ if (gst_omx_component_set_state (self->egl_render,
+ OMX_StateExecuting) != OMX_ErrorNone)
+ goto no_egl;
+
+ if (gst_omx_component_get_state (self->egl_render,
+ GST_CLOCK_TIME_NONE) != OMX_StateExecuting)
+ goto no_egl;
+
+ err =
+ gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err =
+ gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err =
+ gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_populate (self->egl_out_port);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_set_enabled (self->dec_out_port, TRUE);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
- err = gst_omx_port_deallocate_buffers (self->dec_out_port);
+ err = gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+
+ err = gst_omx_port_mark_reconfigured (self->dec_out_port);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ err = gst_omx_port_mark_reconfigured (self->egl_out_port);
+ if (err != OMX_ErrorNone)
+ goto no_egl;
+
+ goto done;
+ }
+
+ no_egl:
+
+ gst_omx_port_set_enabled (self->dec_out_port, FALSE);
+ gst_omx_port_wait_enabled (self->dec_out_port, 1 * GST_SECOND);
+ egl_state = gst_omx_component_get_state (self->egl_render, 0);
+ if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
+ if (egl_state > OMX_StateIdle) {
+ gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
+ gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
+ }
+ gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
+
+ gst_omx_video_dec_deallocate_output_buffers (self);
+ gst_omx_component_close_tunnel (self->dec, self->dec_out_port,
+ self->egl_render, self->egl_in_port);
+
+ if (egl_state > OMX_StateLoaded) {
+ gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
+ }
+ }
+
+ /* After this egl_render should be deactivated
+ * and the decoder's output port disabled */
+ self->egl_transport_active = FALSE;
+ }
+#endif
+ port = self->dec_out_port;
+
+ /* Update caps */
+ GST_VIDEO_DECODER_STREAM_LOCK (self);
+
+ gst_omx_port_get_port_definition (port, &port_def);
+ g_assert (port_def.format.video.eCompressionFormat == OMX_VIDEO_CodingUnused);
+
+ switch (port_def.format.video.eColorFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ case OMX_COLOR_FormatYUV420PackedPlanar:
+ GST_DEBUG_OBJECT (self, "Output is I420 (%d)",
+ port_def.format.video.eColorFormat);
+ format = GST_VIDEO_FORMAT_I420;
+ break;
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ GST_DEBUG_OBJECT (self, "Output is NV12 (%d)",
+ port_def.format.video.eColorFormat);
+ format = GST_VIDEO_FORMAT_NV12;
+ break;
+ default:
+ GST_ERROR_OBJECT (self, "Unsupported color format: %d",
+ port_def.format.video.eColorFormat);
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+ err = OMX_ErrorUndefined;
+ goto done;
+ break;
+ }
+
+ GST_DEBUG_OBJECT (self,
+ "Setting output state: format %s, width %d, height %d",
+ gst_video_format_to_string (format),
+ port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight);
+
+ state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
+ format, port_def.format.video.nFrameWidth,
+ port_def.format.video.nFrameHeight, self->input_state);
+
+ if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
+ gst_video_codec_state_unref (state);
+ GST_ERROR_OBJECT (self, "Failed to negotiate");
+ err = OMX_ErrorUndefined;
+ goto done;
+ }
+
+ gst_video_codec_state_unref (state);
+
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+
+#ifdef USE_EGL_RPI
+enable_port:
+#endif
+ err = gst_omx_video_dec_allocate_output_buffers (self);
+ if (err != OMX_ErrorNone)
+ goto done;
+
+ err = gst_omx_port_populate (port);
+ if (err != OMX_ErrorNone)
+ goto done;
+
+ err = gst_omx_port_mark_reconfigured (port);
+ if (err != OMX_ErrorNone)
+ goto done;
+
+done:
return err;
}
static void
+gst_omx_video_dec_release_egl_buffer (GstOMXBuffer * buf)
+{
+ g_return_if_fail (buf != NULL);
+
+ gst_omx_port_release_buffer (buf->port, buf);
+}
+
+static void
gst_omx_video_dec_loop (GstOMXVideoDec * self)
{
- GstOMXPort *port = self->dec_out_port;
+ GstOMXPort *port;
GstOMXBuffer *buf = NULL;
GstVideoCodecFrame *frame;
GstFlowReturn flow_ret = GST_FLOW_OK;
@@ -674,6 +1200,12 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
GstClockTimeDiff deadline;
OMX_ERRORTYPE err;
+#ifdef USE_EGL_RPI
+ port = self->egl_transport_active ? self->egl_out_port : self->dec_out_port;
+#else
+ port = self->dec_out_port;
+#endif
+
acq_return = gst_omx_port_acquire_buffer (port, &buf);
if (acq_return == GST_OMX_ACQUIRE_BUFFER_ERROR) {
goto component_error;
@@ -711,68 +1243,63 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
goto reconfigure_error;
}
- GST_VIDEO_DECODER_STREAM_LOCK (self);
-
- gst_omx_port_get_port_definition (port, &port_def);
- g_assert (port_def.format.video.eCompressionFormat ==
- OMX_VIDEO_CodingUnused);
-
- switch (port_def.format.video.eColorFormat) {
- case OMX_COLOR_FormatYUV420Planar:
- case OMX_COLOR_FormatYUV420PackedPlanar:
- GST_DEBUG_OBJECT (self, "Output is I420 (%d)",
- port_def.format.video.eColorFormat);
- format = GST_VIDEO_FORMAT_I420;
- break;
- case OMX_COLOR_FormatYUV420SemiPlanar:
- GST_DEBUG_OBJECT (self, "Output is NV12 (%d)",
- port_def.format.video.eColorFormat);
- format = GST_VIDEO_FORMAT_NV12;
- break;
- default:
- GST_ERROR_OBJECT (self, "Unsupported color format: %d",
- port_def.format.video.eColorFormat);
- if (buf)
- gst_omx_port_release_buffer (self->dec_out_port, buf);
- GST_VIDEO_DECODER_STREAM_UNLOCK (self);
- goto caps_failed;
- break;
- }
-
- GST_DEBUG_OBJECT (self,
- "Setting output state: format %s, width %d, height %d",
- gst_video_format_to_string (format),
- port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight);
+ if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
+ /* We have the possibility to reconfigure everything now */
+ err = gst_omx_video_dec_reconfigure_output_port (self);
+ if (err != OMX_ErrorNone)
+ goto reconfigure_error;
+ } else {
+ /* Just update caps */
+ GST_VIDEO_DECODER_STREAM_LOCK (self);
- state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
- format, port_def.format.video.nFrameWidth,
- port_def.format.video.nFrameHeight, self->input_state);
+ gst_omx_port_get_port_definition (port, &port_def);
+ g_assert (port_def.format.video.eCompressionFormat ==
+ OMX_VIDEO_CodingUnused);
- /* Take framerate and pixel-aspect-ratio from sinkpad caps */
+ switch (port_def.format.video.eColorFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ case OMX_COLOR_FormatYUV420PackedPlanar:
+ GST_DEBUG_OBJECT (self, "Output is I420 (%d)",
+ port_def.format.video.eColorFormat);
+ format = GST_VIDEO_FORMAT_I420;
+ break;
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ GST_DEBUG_OBJECT (self, "Output is NV12 (%d)",
+ port_def.format.video.eColorFormat);
+ format = GST_VIDEO_FORMAT_NV12;
+ break;
+ default:
+ GST_ERROR_OBJECT (self, "Unsupported color format: %d",
+ port_def.format.video.eColorFormat);
+ if (buf)
+ gst_omx_port_release_buffer (port, buf);
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+ goto caps_failed;
+ break;
+ }
- if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
- if (buf)
- gst_omx_port_release_buffer (self->dec_out_port, buf);
- gst_video_codec_state_unref (state);
- goto caps_failed;
- }
+ GST_DEBUG_OBJECT (self,
+ "Setting output state: format %s, width %d, height %d",
+ gst_video_format_to_string (format),
+ port_def.format.video.nFrameWidth,
+ port_def.format.video.nFrameHeight);
- gst_video_codec_state_unref (state);
+ state = gst_video_decoder_set_output_state (GST_VIDEO_DECODER (self),
+ format, port_def.format.video.nFrameWidth,
+ port_def.format.video.nFrameHeight, self->input_state);
- GST_VIDEO_DECODER_STREAM_UNLOCK (self);
+ /* Take framerate and pixel-aspect-ratio from sinkpad caps */
- if (acq_return == GST_OMX_ACQUIRE_BUFFER_RECONFIGURE) {
- err = gst_omx_video_dec_allocate_output_buffers (self);
- if (err != OMX_ErrorNone)
- goto reconfigure_error;
+ if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
+ if (buf)
+ gst_omx_port_release_buffer (port, buf);
+ gst_video_codec_state_unref (state);
+ goto caps_failed;
+ }
- err = gst_omx_port_populate (port);
- if (err != OMX_ErrorNone)
- goto reconfigure_error;
+ gst_video_codec_state_unref (state);
- err = gst_omx_port_mark_reconfigured (port);
- if (err != OMX_ErrorNone)
- goto reconfigure_error;
+ GST_VIDEO_DECODER_STREAM_UNLOCK (self);
}
/* Now get a buffer */
@@ -787,9 +1314,9 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
* lock and the videocodec stream lock, if ::reset()
* is called at the wrong time
*/
- if (gst_omx_port_is_flushing (self->dec_out_port)) {
+ if (gst_omx_port_is_flushing (port)) {
GST_DEBUG_OBJECT (self, "Flushing");
- gst_omx_port_release_buffer (self->dec_out_port, buf);
+ gst_omx_port_release_buffer (port, buf);
goto flushing;
}
@@ -807,7 +1334,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
GST_TIME_ARGS (-deadline));
flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
frame = NULL;
- } else if (!frame && buf->omx_buf->nFilledLen > 0) {
+ } else if (!frame && (buf->omx_buf->nFilledLen > 0 || buf->eglimage > -1)) {
GstBuffer *outbuf;
/* This sometimes happens at EOS or if the input is not properly framed,
@@ -817,25 +1344,32 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
GST_ERROR_OBJECT (self, "No corresponding frame found");
- outbuf = gst_video_decoder_alloc_output_buffer (GST_VIDEO_DECODER (self));
-
- if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) {
- gst_buffer_unref (outbuf);
- gst_omx_port_release_buffer (port, buf);
- goto invalid_buffer;
+ if (self->out_port_pool) {
+ outbuf = gst_egl_image_memory_pool_acquire_buffer (self->out_port_pool,
+ buf->eglimage, buf,
+ (GDestroyNotify) gst_omx_video_dec_release_egl_buffer);
+ if (!outbuf) {
+ gst_omx_port_release_buffer (port, buf);
+ goto invalid_buffer;
+ }
+ buf = NULL;
+ } else {
+ outbuf = gst_video_decoder_alloc_output_buffer (GST_VIDEO_DECODER (self));
+ if (!gst_omx_video_dec_fill_buffer (self, buf, outbuf)) {
+ gst_buffer_unref (outbuf);
+ gst_omx_port_release_buffer (port, buf);
+ goto invalid_buffer;
+ }
}
flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf);
- } else if (buf->omx_buf->nFilledLen > 0) {
- if ((flow_ret =
- gst_video_decoder_alloc_output_frame (GST_VIDEO_DECODER
- (self), frame)) == GST_FLOW_OK) {
- /* FIXME: This currently happens because of a race condition too.
- * We first need to reconfigure the output port and then the input
- * port if both need reconfiguration.
- */
- if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
- gst_buffer_replace (&frame->output_buffer, NULL);
+ } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage > -1) {
+ if (self->out_port_pool) {
+ frame->output_buffer =
+ gst_egl_image_memory_pool_acquire_buffer (self->out_port_pool,
+ buf->eglimage, buf,
+ (GDestroyNotify) gst_omx_video_dec_release_egl_buffer);
+ if (!frame->output_buffer) {
flow_ret =
gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
frame = NULL;
@@ -845,6 +1379,27 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
flow_ret =
gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
frame = NULL;
+ buf = NULL;
+ } else {
+ if ((flow_ret =
+ gst_video_decoder_alloc_output_frame (GST_VIDEO_DECODER
+ (self), frame)) == GST_FLOW_OK) {
+ /* FIXME: This currently happens because of a race condition too.
+ * We first need to reconfigure the output port and then the input
+ * port if both need reconfiguration.
+ */
+ if (!gst_omx_video_dec_fill_buffer (self, buf, frame->output_buffer)) {
+ gst_buffer_replace (&frame->output_buffer, NULL);
+ flow_ret =
+ gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
+ frame = NULL;
+ gst_omx_port_release_buffer (port, buf);
+ goto invalid_buffer;
+ }
+ flow_ret =
+ gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame);
+ frame = NULL;
+ }
}
} else if (frame != NULL) {
flow_ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (self), frame);
@@ -1012,10 +1567,19 @@ gst_omx_video_dec_stop (GstVideoDecoder * decoder)
gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
+#ifdef USE_EGL_RPI
+ gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
+ gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
+#endif
+
gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder));
if (gst_omx_component_get_state (self->dec, 0) > OMX_StateIdle)
gst_omx_component_set_state (self->dec, OMX_StateIdle);
+#ifdef USE_EGL_RPI
+ if (gst_omx_component_get_state (self->egl_render, 0) > OMX_StateIdle)
+ gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
+#endif
self->downstream_flow_ret = GST_FLOW_WRONG_STATE;
self->started = FALSE;
@@ -1027,6 +1591,9 @@ gst_omx_video_dec_stop (GstVideoDecoder * decoder)
g_mutex_unlock (self->drain_lock);
gst_omx_component_get_state (self->dec, 5 * GST_SECOND);
+#ifdef USE_EGL_RPI
+ gst_omx_component_get_state (self->egl_render, 1 * GST_SECOND);
+#endif
gst_buffer_replace (&self->codec_data, NULL);
@@ -1054,12 +1621,17 @@ video_negotiation_map_free (VideoNegotiationMap * m)
static GList *
gst_omx_video_dec_get_supported_colorformats (GstOMXVideoDec * self)
{
- GstOMXPort *port = self->dec_out_port;
+ GstOMXComponent *comp;
+ GstOMXPort *port;
GstVideoCodecState *state = self->input_state;
OMX_VIDEO_PARAM_PORTFORMATTYPE param;
OMX_ERRORTYPE err;
GList *negotiation_map = NULL;
gint old_index;
+ VideoNegotiationMap *m;
+
+ port = self->dec_out_port;
+ comp = self->dec;
GST_OMX_INIT_STRUCT (&param);
param.nPortIndex = port->index;
@@ -1071,10 +1643,8 @@ gst_omx_video_dec_get_supported_colorformats (GstOMXVideoDec * self)
old_index = -1;
do {
- VideoNegotiationMap *m;
-
err =
- gst_omx_component_get_parameter (self->dec,
+ gst_omx_component_get_parameter (comp,
OMX_IndexParamVideoPortFormat, &param);
/* FIXME: Workaround for Bellagio that simply always
@@ -1117,7 +1687,7 @@ gst_omx_video_dec_get_supported_colorformats (GstOMXVideoDec * self)
}
static gboolean
-gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
+gst_omx_video_dec_negotiate (GstOMXVideoDec * self, GstVideoInfo * info)
{
OMX_VIDEO_PARAM_PORTFORMATTYPE param;
OMX_ERRORTYPE err;
@@ -1127,6 +1697,9 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
GstVideoFormat format;
GstStructure *s;
guint32 fourcc;
+#ifdef USE_EGL_RPI
+ gboolean peer_caps_are_any = FALSE;
+#endif
GST_DEBUG_OBJECT (self, "Trying to negotiate a video format with downstream");
@@ -1135,6 +1708,9 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
(self)));
peer_caps = gst_pad_peer_get_caps (GST_VIDEO_DECODER_SRC_PAD (self));
if (peer_caps) {
+#ifdef USE_EGL_RPI
+ peer_caps_are_any = gst_caps_is_any (peer_caps);
+#endif
intersection = gst_caps_intersect (templ_caps, peer_caps);
gst_caps_unref (templ_caps);
gst_caps_unref (peer_caps);
@@ -1142,11 +1718,56 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
intersection = templ_caps;
}
- GST_DEBUG_OBJECT (self, "Allowed downstream caps: %" GST_PTR_FORMAT,
- intersection);
+ comp_supported_caps = gst_caps_new_empty ();
+
+#ifdef USE_EGL_RPI
+ /* Hack to allow negotiate EGL transport in playbin2 */
+ if (peer_caps_are_any) {
+ if (!self->out_port_pool) {
+ /* Ask for an EGL pool */
+ gst_element_post_message (GST_ELEMENT_CAST (self),
+ gst_message_new_need_egl_pool (GST_OBJECT (self), N_EGL_IMAGES,
+ info->width, info->height));
+ /* If appliction provided one then allow EGL transport */
+ if (self->out_port_pool) {
+ self->egl_transport_allowed = TRUE;
+ gst_caps_append_structure (comp_supported_caps,
+ gst_structure_new ("video/x-raw-rgb",
+ "transport", G_TYPE_STRING, "egl", NULL));
+ }
+ }
+ } else {
+ gboolean egl_transport = FALSE;
+ GstCaps *filtered = gst_caps_new_empty ();
+ gint i, nstrus = gst_caps_get_size (intersection);
+
+ for (i = 0; i < nstrus; i++) {
+ s = gst_caps_get_structure (intersection, i);
+ if (gst_structure_has_name (s, "video/x-raw-rgb")) {
+ const gchar *transport;
+ if ((transport = gst_structure_get_string (s, "transport"))) {
+ if (g_strcmp0 (transport, "egl") == 0) {
+ gst_caps_append_structure (filtered, gst_structure_copy (s));
+ egl_transport = TRUE;
+ }
+ }
+ } else {
+ gst_caps_append_structure (filtered, gst_structure_copy (s));
+ }
+ }
+ gst_caps_unref (intersection);
+ intersection = filtered;
+
+ if (egl_transport) {
+ self->egl_transport_allowed = TRUE;
+ gst_caps_append_structure (comp_supported_caps,
+ gst_structure_new ("video/x-raw-rgb",
+ "transport", G_TYPE_STRING, "egl", NULL));
+ }
+ }
+#endif
negotiation_map = gst_omx_video_dec_get_supported_colorformats (self);
- comp_supported_caps = gst_caps_new_empty ();
for (l = negotiation_map; l; l = l->next) {
VideoNegotiationMap *map = l->data;
@@ -1156,6 +1777,9 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
gst_video_format_to_fourcc (map->format), NULL));
}
+ GST_DEBUG_OBJECT (self, "Allowed downstream caps: %" GST_PTR_FORMAT,
+ intersection);
+
if (!gst_caps_is_empty (comp_supported_caps)) {
GstCaps *tmp;
@@ -1177,6 +1801,14 @@ gst_omx_video_dec_negotiate (GstOMXVideoDec * self)
gst_pad_fixate_caps (GST_VIDEO_DECODER_SRC_PAD (self), intersection);
s = gst_caps_get_structure (intersection, 0);
+#ifdef USE_EGL_RPI
+ if (gst_structure_has_name (s, "video/x-raw-rgb")) {
+ g_list_free_full (negotiation_map,
+ (GDestroyNotify) video_negotiation_map_free);
+ GST_DEBUG_OBJECT (self, "Negotiated EGL transport");
+ return TRUE;
+ }
+#endif
if (!gst_structure_get_fourcc (s, "format", &fourcc) ||
(format =
gst_video_format_from_fourcc (fourcc)) == GST_VIDEO_FORMAT_UNKNOWN) {
@@ -1266,10 +1898,17 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
}
if (needs_disable && is_format_change) {
+#ifdef USE_EGL_RPI
+ GstOMXPort *out_port =
+ self->egl_transport_active ? self->egl_out_port : self->dec_out_port;
+#else
+ GstOMXPort *out_port = self->dec_out_port;
+#endif
+
GST_DEBUG_OBJECT (self, "Need to disable and drain decoder");
gst_omx_video_dec_drain (self, FALSE);
- gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
+ gst_omx_port_set_flushing (out_port, 5 * GST_SECOND, TRUE);
/* Wait until the srcpad loop is finished,
* unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
@@ -1288,26 +1927,82 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
return FALSE;
needs_disable = FALSE;
} else {
- if (gst_omx_port_set_enabled (self->dec_in_port, FALSE) != OMX_ErrorNone)
- return FALSE;
- if (gst_omx_port_set_enabled (self->dec_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 (self->dec_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;
- if (gst_omx_port_wait_enabled (self->dec_out_port,
- 1 * GST_SECOND) != OMX_ErrorNone)
- return FALSE;
+#ifdef USE_EGL_RPI
+ if (self->egl_transport_active) {
+ OMX_STATETYPE egl_state;
+
+ if (gst_omx_port_set_enabled (self->dec_in_port,
+ FALSE) != OMX_ErrorNone)
+ return FALSE;
+
+ if (gst_omx_port_set_enabled (self->dec_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 (self->dec_out_port,
+ 5 * GST_SECOND) != OMX_ErrorNone)
+ return FALSE;
+
+ if (gst_omx_port_deallocate_buffers (self->dec_in_port) !=
+ OMX_ErrorNone)
+ return FALSE;
+
+ if (gst_omx_port_wait_enabled (self->dec_in_port,
+ 1 * GST_SECOND) != OMX_ErrorNone)
+ return FALSE;
+
+ if (gst_omx_port_wait_enabled (self->dec_out_port,
+ 1 * GST_SECOND) != OMX_ErrorNone)
+ return FALSE;
+
+ egl_state = gst_omx_component_get_state (self->egl_render, 0);
+ if (egl_state > OMX_StateLoaded || egl_state == OMX_StateInvalid) {
+ if (egl_state > OMX_StateIdle) {
+ gst_omx_component_set_state (self->egl_render, OMX_StateIdle);
+ gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
+ }
+ gst_omx_component_set_state (self->egl_render, OMX_StateLoaded);
+
+ gst_omx_video_dec_deallocate_output_buffers (self);
+ gst_omx_component_close_tunnel (self->dec, self->dec_out_port,
+ self->egl_render, self->egl_in_port);
+
+ if (egl_state > OMX_StateLoaded) {
+ gst_omx_component_get_state (self->egl_render, 5 * GST_SECOND);
+ }
+ }
+ self->egl_transport_active = FALSE;
+ } else {
+#else
+ {
+ 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;
+ if (gst_omx_port_wait_enabled (out_port,
+ 1 * GST_SECOND) != OMX_ErrorNone)
+ return FALSE;
+#endif
+ }
}
if (self->input_state)
gst_video_codec_state_unref (self->input_state);
@@ -1357,7 +2052,7 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
if (gst_omx_port_mark_reconfigured (self->dec_in_port) != OMX_ErrorNone)
return FALSE;
} else {
- if (!gst_omx_video_dec_negotiate (self))
+ if (!gst_omx_video_dec_negotiate (self, info))
GST_LOG_OBJECT (self, "Negotiation failed, will get output format later");
/* Disable output port */
@@ -1423,6 +2118,11 @@ gst_omx_video_dec_reset (GstVideoDecoder * decoder, gboolean hard)
gst_omx_port_set_flushing (self->dec_in_port, 5 * GST_SECOND, TRUE);
gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, TRUE);
+#ifdef USE_EGL_RPI
+ gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, TRUE);
+ gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, TRUE);
+#endif
+
/* Wait until the srcpad loop is finished,
* unlock GST_VIDEO_DECODER_STREAM_LOCK to prevent deadlocks
* caused by using this lock from inside the loop function */
@@ -1435,6 +2135,11 @@ gst_omx_video_dec_reset (GstVideoDecoder * decoder, gboolean hard)
gst_omx_port_set_flushing (self->dec_out_port, 5 * GST_SECOND, FALSE);
gst_omx_port_populate (self->dec_out_port);
+#ifdef USE_EGL_RPI
+ gst_omx_port_set_flushing (self->egl_in_port, 5 * GST_SECOND, FALSE);
+ gst_omx_port_set_flushing (self->egl_out_port, 5 * GST_SECOND, FALSE);
+#endif
+
/* Start the srcpad loop again */
self->last_upstream_ts = 0;
self->eos = FALSE;
diff --git a/omx/gstomxvideodec.h b/omx/gstomxvideodec.h
index 6ae9453..9fdbe41 100644
--- a/omx/gstomxvideodec.h
+++ b/omx/gstomxvideodec.h
@@ -27,6 +27,24 @@
#include <gst/gst.h>
+#if defined(USE_EGL_RPI)
+#if defined (__GNUC__)
+#ifndef __VCCOREVER__
+#define __VCCOREVER__ 0x04000000
+#endif
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#pragma GCC optimize ("gnu89-inline")
+#endif
+
+#include <gst/egl/egl.h>
+
+#if defined (__GNUC__)
+#pragma GCC reset_options
+#pragma GCC diagnostic pop
+#endif
+#endif /* defined(USE_EGL_RPI) */
+
#ifdef HAVE_VIDEO_BASE_CLASSES
#include <gst/video/gstvideodecoder.h>
#else
@@ -80,6 +98,18 @@ struct _GstOMXVideoDec
gboolean eos;
GstFlowReturn downstream_flow_ret;
+
+#ifdef USE_EGL_RPI
+ gboolean egl_transport_allowed;
+ gboolean egl_transport_active;
+
+ GstEGLDisplay * egl_display;
+
+ GstOMXComponent *egl_render;
+ GstOMXPort *egl_in_port, *egl_out_port;
+
+ GstEGLImageMemoryPool * out_port_pool;
+#endif
};
struct _GstOMXVideoDecClass