summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2013-02-25 11:55:04 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2013-03-26 14:00:03 +0100
commit8a1bb1b4a36d584646b3c57dd46947b09c47f943 (patch)
treebda4192f89ac28c2f03ff1537783a3c63d228a35
parentd0a5a9a9bff14e35048994ae6c9f0dde621f2cc4 (diff)
downloadgst-omx-8a1bb1b4a36d584646b3c57dd46947b09c47f943.tar.gz
omxvideodec: Add support for egl_render on RPi
-rw-r--r--configure.ac1
-rw-r--r--omx/Makefile.am3
-rw-r--r--omx/gstomx.c8
-rw-r--r--omx/gstomx.h4
-rw-r--r--omx/gstomxvideodec.c786
-rw-r--r--omx/gstomxvideodec.h11
6 files changed, 714 insertions, 99 deletions
diff --git a/configure.ac b/configure.ac
index 2b4b16a..fdf0835 100644
--- a/configure.ac
+++ b/configure.ac
@@ -145,6 +145,7 @@ AG_GST_CHECK_GST_CONTROLLER($GST_API_VERSION, [$GST_REQ], yes)
AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no)
AG_GST_CHECK_GST_PLUGINS_BASE($GST_API_VERSION, [$GST_REQ], yes)
AM_CONDITIONAL(HAVE_GST_CHECK, test "x$HAVE_GST_CHECK" = "xyes")
+PKG_CHECK_MODULES([GST_PLUGINS_BAD], [gstreamer-plugins-bad-1.0])
dnl Check for documentation xrefs
GLIB_PREFIX="`$PKG_CONFIG --variable=prefix glib-2.0`"
diff --git a/omx/Makefile.am b/omx/Makefile.am
index 14ec993..9c7bed1 100644
--- a/omx/Makefile.am
+++ b/omx/Makefile.am
@@ -53,10 +53,13 @@ endif
libgstomx_la_CFLAGS = \
-DGST_USE_UNSTABLE_API=1 \
$(OMX_INCLUDEPATH) \
+ $(GST_PLUGINS_BAD_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS)
libgstomx_la_LIBADD = \
+ $(GST_PLUGINS_BAD_LIBS) \
+ -lgstegl-@GST_API_VERSION@ \
$(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-@GST_API_VERSION@ \
-lgstpbutils-@GST_API_VERSION@ \
diff --git a/omx/gstomx.c b/omx/gstomx.c
index f542954..faf307d 100644
--- a/omx/gstomx.c
+++ b/omx/gstomx.c
@@ -1066,14 +1066,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);
@@ -1111,14 +1107,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);
diff --git a/omx/gstomx.h b/omx/gstomx.h
index b5d8379..3afcbdb 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
diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c
index 976f58e..c9d01a6 100644
--- a/omx/gstomxvideodec.c
+++ b/omx/gstomxvideodec.c
@@ -27,6 +27,7 @@
#include <gst/gst.h>
#include <gst/video/gstvideometa.h>
#include <gst/video/gstvideopool.h>
+#include <gst/egl/egl.h>
#include <string.h>
#include "gstomxvideodec.h"
@@ -776,6 +777,53 @@ gst_omx_video_dec_open (GstVideoDecoder * decoder)
GST_DEBUG_OBJECT (self, "Opened decoder");
+#ifdef USE_OMX_TARGET_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;
}
@@ -786,6 +834,32 @@ gst_omx_video_dec_shutdown (GstOMXVideoDec * self)
GST_DEBUG_OBJECT (self, "Shutting down decoder");
+#ifdef USE_OMX_TARGET_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) {
@@ -818,6 +892,14 @@ gst_omx_video_dec_close (GstVideoDecoder * decoder)
gst_omx_component_free (self->dec);
self->dec = NULL;
+#ifdef USE_OMX_TARGET_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;
+#endif
+
self->started = FALSE;
GST_DEBUG_OBJECT (self, "Closed decoder");
@@ -861,6 +943,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_OMX_TARGET_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;
@@ -948,7 +1036,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);
@@ -978,7 +1066,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);
@@ -1155,13 +1243,14 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
GstVideoCodecState *state =
gst_video_decoder_get_output_state (GST_VIDEO_DECODER (self));
+#ifdef USE_OMX_TARGET_RPI
+ port = self->eglimage ? self->egl_out_port : self->dec_out_port;
+#else
port = self->dec_out_port;
+#endif
pool = gst_video_decoder_get_buffer_pool (GST_VIDEO_DECODER (self));
- /* FIXME: Enable this once there's a way to request downstream to
- * release all our buffers, e.g.
- * http://cgit.freedesktop.org/~wtay/gstreamer/log/?h=release-pool */
- if (FALSE && pool) {
+ if (pool) {
GstAllocator *allocator;
config = gst_buffer_pool_get_config (pool);
@@ -1182,8 +1271,13 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
add_videometa = gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_META);
- /* TODO: Implement something here */
+#ifdef USE_OMX_TARGET_RPI
+ 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
caps = caps ? gst_caps_ref (caps) : NULL;
GST_DEBUG_OBJECT (self, "Trying to use pool %p with caps %" GST_PTR_FORMAT
@@ -1195,11 +1289,157 @@ gst_omx_video_dec_allocate_output_buffers (GstOMXVideoDec * self)
GST_DEBUG_OBJECT (self, "No pool available, not negotiated yet");
}
+#ifdef USE_OMX_TARGET_RPI
+ /* Will retry without EGLImage */
+ if (self->eglimage && !eglimage) {
+ GST_DEBUG_OBJECT (self,
+ "Wanted to use EGLImage but downstream doesn't support it");
+ err = OMX_ErrorUndefined;
+ goto done;
+ }
+#endif
+
if (caps)
self->out_port_pool =
gst_omx_buffer_pool_new (GST_ELEMENT_CAST (self), self->dec, port);
- /* TODO: Implement EGLImage handling and usage of other downstream buffers */
+#ifdef USE_OMX_TARGET_RPI
+ if (eglimage) {
+ GList *buffers = NULL;
+ GList *images = NULL;
+ gint i;
+ GstBufferPoolAcquireParams params = { 0, };
+ GstEGLDisplay *display = NULL;
+
+ 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;
+ if (display)
+ gst_egl_display_unref (display);
+ display = NULL;
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ err = OMX_ErrorUndefined;
+ goto done;
+ }
+
+ buffers = g_list_append (buffers, buffer);
+ gst_egl_image_memory_set_orientation (mem,
+ GST_EGL_IMAGE_ORIENTATION_X_NORMAL_Y_FLIP);
+ images = g_list_append (images, gst_egl_image_memory_get_image (mem));
+ if (!display)
+ display = gst_egl_image_memory_get_display (mem);
+ }
+
+ GST_DEBUG_OBJECT (self, "Allocated %d EGLImages successfully", min);
+
+ /* Everything went fine? */
+ if (eglimage) {
+ GST_DEBUG_OBJECT (self, "Setting EGLDisplay");
+ self->egl_out_port->port_def.format.video.pNativeWindow =
+ gst_egl_display_get (display);
+ err =
+ gst_omx_port_update_port_definition (self->egl_out_port,
+ &self->egl_out_port->port_def);
+ if (display)
+ gst_egl_display_unref (display);
+ display = NULL;
+ 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_full (buffers, (GDestroyNotify) gst_buffer_unref);
+ g_list_free (images);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ goto done;
+ } else {
+ GList *l;
+
+ 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 %n output buffers: %s (0x%08x)", min,
+ gst_omx_error_to_string (err), err);
+ g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
+ 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_full (buffers, (GDestroyNotify) gst_buffer_unref);
+ 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);
+ g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
+ /* 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);
+ g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
+ /* TODO: For non-RPi targets we want to use the normal memory code below */
+ /* Retry without EGLImage */
+ 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);
+ /* All good and done, set caps below */
+ }
+ }
+ }
+#endif
/* If not using EGLImage or trying to use EGLImage failed */
if (!eglimage) {
@@ -1336,11 +1576,259 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
if (self->out_port_pool) {
gst_buffer_pool_set_active (self->out_port_pool, FALSE);
+ gst_buffer_pool_wait_released (self->out_port_pool);
GST_OMX_BUFFER_POOL (self->out_port_pool)->deactivated = TRUE;
gst_object_unref (self->out_port_pool);
self->out_port_pool = NULL;
}
+#ifdef USE_OMX_TARGET_RPI
+ err =
+ gst_omx_port_deallocate_buffers (self->
+ eglimage ? self->egl_out_port : self->dec_out_port);
+#else
err = gst_omx_port_deallocate_buffers (self->dec_out_port);
+#endif
+
+ 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_OMX_TARGET_RPI
+ {
+ OMX_STATETYPE egl_state;
+
+ if (self->eglimage) {
+ /* Nothing to do here, we could however fall back to non-EGLImage in theory */
+ err = OMX_ErrorNone;
+ goto enable_port;
+ } else {
+ /* Set up egl_render */
+
+ self->eglimage = 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 0x7f0000dc
+ 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_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->eglimage = 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_OMX_TARGET_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;
}
@@ -1348,7 +1836,7 @@ gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec * self)
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;
@@ -1356,6 +1844,12 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
GstClockTimeDiff deadline;
OMX_ERRORTYPE err;
+#ifdef USE_OMX_TARGET_RPI
+ port = self->eglimage ? 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;
@@ -1393,68 +1887,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 (self->dec_out_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 (self->dec_out_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 */
@@ -1489,7 +1978,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)) {
GstBuffer *outbuf;
/* This sometimes happens at EOS or if the input is not properly framed,
@@ -1532,7 +2021,7 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self)
}
flow_ret = gst_pad_push (GST_VIDEO_DECODER_SRC_PAD (self), outbuf);
- } else if (buf->omx_buf->nFilledLen > 0) {
+ } else if (buf->omx_buf->nFilledLen > 0 || buf->eglimage) {
if (self->out_port_pool) {
gint i, n;
GstBufferPoolAcquireParams params = { 0, };
@@ -1748,10 +2237,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_OMX_TARGET_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_OMX_TARGET_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_FLUSHING;
self->started = FALSE;
@@ -1763,6 +2261,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_OMX_TARGET_RPI
+ gst_omx_component_get_state (self->egl_render, 1 * GST_SECOND);
+#endif
gst_buffer_replace (&self->codec_data, NULL);
@@ -1790,12 +2291,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;
@@ -1807,10 +2313,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
@@ -1997,10 +2501,17 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder,
}
if (needs_disable && is_format_change) {
+#ifdef USE_OMX_TARGET_RPI
+ GstOMXPort *out_port =
+ self->eglimage ? 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
@@ -2019,26 +2530,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_OMX_TARGET_RPI
+ if (self->eglimage) {
+ 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->eglimage = 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);
@@ -2154,6 +2721,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_OMX_TARGET_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 */
@@ -2166,6 +2738,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_OMX_TARGET_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;
@@ -2567,6 +3144,35 @@ gst_omx_video_dec_decide_allocation (GstVideoDecoder * bdec, GstQuery * query)
GstBufferPool *pool;
GstStructure *config;
+#ifdef USE_OMX_TARGET_RPI
+ {
+ GstCaps *caps;
+ gint i, n;
+ GstVideoInfo info;
+
+ gst_query_parse_allocation (query, &caps, NULL);
+ if (caps && gst_video_info_from_caps (&info, caps)
+ && info.finfo->format == GST_VIDEO_FORMAT_RGBA) {
+ /* Prefer an EGLImage allocator if available and we want to use it */
+ n = gst_query_get_n_allocation_params (query);
+ for (i = 0; i < n; i++) {
+ GstAllocator *allocator;
+ GstAllocationParams params;
+
+ gst_query_parse_nth_allocation_param (query, i, &allocator, &params);
+ if (allocator
+ && g_strcmp0 (allocator->mem_type,
+ GST_EGL_IMAGE_MEMORY_TYPE) == 0) {
+ gst_query_set_nth_allocation_param (query, 0, allocator, &params);
+ while (gst_query_get_n_allocation_params (query) > 1)
+ gst_query_remove_nth_allocation_param (query, 1);
+ break;
+ }
+ }
+ }
+ }
+#endif
+
if (!GST_VIDEO_DECODER_CLASS
(gst_omx_video_dec_parent_class)->decide_allocation (bdec, query))
return FALSE;
diff --git a/omx/gstomxvideodec.h b/omx/gstomxvideodec.h
index 8f0f98b..3978865 100644
--- a/omx/gstomxvideodec.h
+++ b/omx/gstomxvideodec.h
@@ -21,6 +21,10 @@
#ifndef __GST_OMX_VIDEO_DEC_H__
#define __GST_OMX_VIDEO_DEC_H__
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideodecoder.h>
@@ -52,7 +56,7 @@ struct _GstOMXVideoDec
/* < protected > */
GstOMXComponent *dec;
GstOMXPort *dec_in_port, *dec_out_port;
-
+
GstBufferPool *in_port_pool, *out_port_pool;
/* < private > */
@@ -74,6 +78,11 @@ struct _GstOMXVideoDec
gboolean eos;
GstFlowReturn downstream_flow_ret;
+#ifdef USE_OMX_TARGET_RPI
+ GstOMXComponent *egl_render;
+ GstOMXPort *egl_in_port, *egl_out_port;
+ gboolean eglimage;
+#endif
};
struct _GstOMXVideoDecClass