From: Julien Isorce Date: Fri, 25 Apr 2014 12:21:59 +0000 (+0100) Subject: testegl: port to gstgl API X-Git-Tag: 1.19.3~501^2~442 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f1c76ef92112acc7855d5715ac149a3620559f6a;p=platform%2Fupstream%2Fgstreamer.git testegl: port to gstgl API - append a glfilter just before fakesink So that we get gltexture or eglimages - propagate our EGLDisplay to the pipeline see GST_QUERY_CONTEXT - share our EGLContext with the iternal gl context of the pipeline, see GST_QUERY_ALLOCATION - use GstVideoGLTextureUploadMeta to upload the incoming gltexture or eglimage to our gl texture TODO: convert from GLESv1 to GLESv2 See https://bugzilla.gnome.org/show_bug.cgi?id=728940 --- diff --git a/examples/egl/Makefile.am b/examples/egl/Makefile.am index 0d32d08..8dc7027 100644 --- a/examples/egl/Makefile.am +++ b/examples/egl/Makefile.am @@ -13,11 +13,11 @@ testegl_LDADD = \ -lgstvideo-@GST_API_VERSION@ \ $(GST_BASE_LIBS) \ $(GST_LIBS) \ - $(GST_EGL_LIBS) + $(GST_GL_LIBS) testegl_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ $(GST_CFLAGS) \ - $(GST_EGL_CFLAGS) + $(GST_GL_CFLAGS) diff --git a/examples/egl/testegl.c b/examples/egl/testegl.c index 73d4374..727b655 100644 --- a/examples/egl/testegl.c +++ b/examples/egl/testegl.c @@ -5,6 +5,7 @@ Copyright (C) 2013, Fluendo S.A. @author: Josep Torra Copyright (C) 2013, Video Experts Group LLC. @author: Ilya Smelykh +Copyright (C) 2014 Julien Isorce All rights reserved. Redistribution and use in source and binary forms, with or without @@ -47,7 +48,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && defined (__GNUC__) +#if defined (USE_OMX_TARGET_RPI) && defined (__GNUC__) #ifndef __VCCOREVER__ #define __VCCOREVER__ 0x04000000 #endif @@ -56,29 +57,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma GCC optimize ("gnu89-inline") #endif -#include "bcm_host.h" - -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && defined (__GNUC__) -#pragma GCC reset_options -#pragma GCC diagnostic pop -#endif - #include #include -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && 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 +#include -#define EGL_EGLEXT_PROTOTYPES -#include +#if defined (USE_OMX_TARGET_RPI) +#include +#endif -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && defined (__GNUC__) +#if defined (USE_OMX_TARGET_RPI) && defined (__GNUC__) #pragma GCC reset_options #pragma GCC diagnostic pop #endif @@ -93,7 +82,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define TRACE_VC_MEMORY_ENABLED 0 -#if TRACE_VC_MEMORY_ENABLED +#if defined (USE_OMX_TARGET_RPI) && TRACE_VC_MEMORY_ENABLED #define TRACE_VC_MEMORY(str) \ fprintf (stderr, "\n\n" str "\n"); \ system ("vcdbg reloc >&2") @@ -135,8 +124,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef struct { +#if defined (USE_OMX_TARGET_RPI) DISPMANX_DISPLAY_HANDLE_T dispman_display; DISPMANX_ELEMENT_HANDLE_T dispman_element; +#endif uint32_t screen_width; uint32_t screen_height; @@ -165,17 +156,16 @@ typedef struct /* GStreamer related resources */ GstElement *pipeline; GstElement *vsink; - GstEGLDisplay *gst_display; + GstGLDisplayEGL *gst_display; /* Interthread comunication */ GAsyncQueue *queue; - GMutex *queue_lock; - GCond *cond; + GMutex queue_lock; + GCond cond; gboolean flushing; GstMiniObject *popped_obj; GstBuffer *current_buffer; - GstBufferPool *pool; /* GLib mainloop */ GMainLoop *main_loop; GstBuffer *last_buffer; @@ -190,37 +180,6 @@ typedef struct guint64 dropped; } APP_STATE_T; -typedef struct -{ - GThread *thread; - EGLImageKHR image; - GLuint texture; - APP_STATE_T *state; -} GstEGLGLESImageData; - -/* EGLImage memory, buffer pool, etc */ -typedef struct -{ - GstVideoBufferPool parent; - - APP_STATE_T *state; - GstAllocator *allocator; - GstAllocationParams params; - GstVideoInfo info; - gboolean add_metavideo; - gboolean want_eglimage; - GstEGLDisplay *display; -} GstCustomEGLImageBufferPool; - -typedef GstVideoBufferPoolClass GstCustomEGLImageBufferPoolClass; - -#define GST_CUSTOM_EGL_IMAGE_BUFFER_POOL(p) ((GstCustomEGLImageBufferPool*)(p)) - -GType gst_custom_egl_image_buffer_pool_get_type (void); - -G_DEFINE_TYPE (GstCustomEGLImageBufferPool, gst_custom_egl_image_buffer_pool, - GST_TYPE_VIDEO_BUFFER_POOL); - static void init_ogl (APP_STATE_T * state); static void init_model_proj (APP_STATE_T * state); static void reset_model (APP_STATE_T * state); @@ -230,8 +189,6 @@ static void redraw_scene (APP_STATE_T * state); static void update_model (APP_STATE_T * state); static void init_textures (APP_STATE_T * state); static APP_STATE_T _state, *state = &_state; -static GstBufferPool *gst_custom_egl_image_buffer_pool_new (APP_STATE_T * state, - GstEGLDisplay * display); static gboolean queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous); @@ -254,371 +211,6 @@ typedef enum GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10) } GstPlayFlags; -static gboolean -got_gl_error (const char *wtf) -{ - GLuint error = GL_NO_ERROR; - - if ((error = glGetError ()) != GL_NO_ERROR) { - GST_CAT_ERROR (GST_CAT_DEFAULT, "GL ERROR: %s returned 0x%04x", wtf, error); - return TRUE; - } - return FALSE; -} - -static gboolean -got_egl_error (const char *wtf) -{ - EGLint error; - - if ((error = eglGetError ()) != EGL_SUCCESS) { - GST_CAT_DEBUG (GST_CAT_DEFAULT, "EGL ERROR: %s returned 0x%04x", wtf, - error); - return TRUE; - } - - return FALSE; -} - -static void -image_data_free (GstEGLGLESImageData * data) -{ - if (data->thread == g_thread_self ()) { - eglDestroyImageKHR (state->display, data->image); - glDeleteTextures (1, &data->texture); - } else { - GstQuery *query; - GstStructure *s; - s = gst_structure_new ("eglglessink-deallocate-eglimage", - "EGLImage", G_TYPE_POINTER, data->image, - "GLTexture", G_TYPE_POINTER, data->texture, NULL); - query = gst_query_new_custom (GST_QUERY_CUSTOM, s); - queue_object (state, GST_MINI_OBJECT_CAST (query), FALSE); - } - g_slice_free (GstEGLGLESImageData, data); -} - -static GstBuffer * -gst_egl_allocate_eglimage (APP_STATE_T * ctx, - GstAllocator * allocator, GstVideoFormat format, gint width, gint height) -{ - GstEGLGLESImageData *data = NULL; - GstBuffer *buffer; - GstVideoInfo info; - gint i; - gint stride[3]; - gsize offset[3]; - GstMemory *mem[3] = { NULL, NULL, NULL }; - guint n_mem; - GstMemoryFlags flags = 0; - - memset (stride, 0, sizeof (stride)); - memset (offset, 0, sizeof (offset)); - - if (!gst_egl_image_memory_is_mappable ()) - flags |= GST_MEMORY_FLAG_NOT_MAPPABLE; - /* See https://bugzilla.gnome.org/show_bug.cgi?id=695203 */ - flags |= GST_MEMORY_FLAG_NO_SHARE; - - gst_video_info_set_format (&info, format, width, height); - - GST_DEBUG ("Allocating EGL Image format %s width %d height %d", - gst_video_format_to_string (format), width, height); - switch (format) { - case GST_VIDEO_FORMAT_RGBA:{ - gsize size; - - mem[0] = - gst_egl_image_allocator_alloc (allocator, ctx->gst_display, - GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&info), - GST_VIDEO_INFO_HEIGHT (&info), &size); - - if (mem[0]) { - stride[0] = size / GST_VIDEO_INFO_HEIGHT (&info); - n_mem = 1; - GST_MINI_OBJECT_FLAG_SET (mem[0], GST_MEMORY_FLAG_NO_SHARE); - } else { - data = g_slice_new0 (GstEGLGLESImageData); - data->thread = g_thread_self (); - data->state = ctx; - - stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (&info) * 4); - size = stride[0] * GST_VIDEO_INFO_HEIGHT (&info); - - glGenTextures (1, &data->texture); - if (got_gl_error ("glGenTextures")) - goto mem_error; - - glBindTexture (GL_TEXTURE_2D, data->texture); - if (got_gl_error ("glBindTexture")) - goto mem_error; - - /* Set 2D resizing params */ - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - /* If these are not set the texture image unit will return - * * (R, G, B, A) = black on glTexImage2D for non-POT width/height - * * frames. For a deeper explanation take a look at the OpenGL ES - * * documentation for glTexParameter */ - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (got_gl_error ("glTexParameteri")) - goto mem_error; - - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, - GST_VIDEO_INFO_WIDTH (&info), - GST_VIDEO_INFO_HEIGHT (&info), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - if (got_gl_error ("glTexImage2D")) - goto mem_error; - - data->image = - eglCreateImageKHR (gst_egl_display_get (ctx->gst_display), - ctx->context, EGL_GL_TEXTURE_2D_KHR, - (EGLClientBuffer) (guintptr) data->texture, NULL); - if (got_egl_error ("eglCreateImageKHR")) - goto mem_error; - - mem[0] = - gst_egl_image_allocator_wrap (allocator, ctx->gst_display, - data->image, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, flags, size, data, - (GDestroyNotify) image_data_free); - - n_mem = 1; - } - } - break; - default: - goto mem_error; - break; - } - - buffer = gst_buffer_new (); - gst_buffer_add_video_meta_full (buffer, 0, format, width, height, - GST_VIDEO_INFO_N_PLANES (&info), offset, stride); - - /* n_mem could be reused for planar colorspaces, for now its == 1 for RGBA */ - for (i = 0; i < n_mem; i++) - gst_buffer_append_memory (buffer, mem[i]); - - return buffer; -mem_error: - { - GST_ERROR ("Failed to create EGLImage"); - - if (data) - image_data_free (data); - - if (mem[0]) - gst_memory_unref (mem[0]); - - return NULL; - } - -} - -static const gchar ** -gst_custom_egl_image_buffer_pool_get_options (GstBufferPool * bpool) -{ - static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL - }; - - return options; -} - -static gboolean -gst_custom_egl_image_buffer_pool_set_config (GstBufferPool * bpool, - GstStructure * config) -{ - GstCustomEGLImageBufferPool *pool = GST_CUSTOM_EGL_IMAGE_BUFFER_POOL (bpool); - GstCaps *caps; - GstVideoInfo info; - - if (pool->allocator) - gst_object_unref (pool->allocator); - pool->allocator = NULL; - - if (!GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->set_config (bpool, - config)) - return FALSE; - - if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL) - || !caps) - return FALSE; - - if (!gst_video_info_from_caps (&info, caps)) - return FALSE; - - if (!gst_buffer_pool_config_get_allocator (config, &pool->allocator, - &pool->params)) - return FALSE; - if (pool->allocator) - gst_object_ref (pool->allocator); - - pool->add_metavideo = - gst_buffer_pool_config_has_option (config, - GST_BUFFER_POOL_OPTION_VIDEO_META); - - pool->want_eglimage = (pool->allocator - && g_strcmp0 (pool->allocator->mem_type, GST_EGL_IMAGE_MEMORY_TYPE) == 0); - - pool->info = info; - - return TRUE; -} - -static GstFlowReturn -gst_custom_egl_image_buffer_pool_alloc_buffer (GstBufferPool * bpool, - GstBuffer ** buffer, GstBufferPoolAcquireParams * params) -{ - GstCustomEGLImageBufferPool *pool = GST_CUSTOM_EGL_IMAGE_BUFFER_POOL (bpool); - *buffer = NULL; - - if (!pool->add_metavideo || !pool->want_eglimage) - return - GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->alloc_buffer (bpool, - buffer, params); - - if (!pool->allocator) - return GST_FLOW_NOT_NEGOTIATED; - - switch (pool->info.finfo->format) { - case GST_VIDEO_FORMAT_RGBA:{ - GstFlowReturn ret; - GstQuery *query; - GstStructure *s; - const GValue *v; - - s = gst_structure_new ("eglglessink-allocate-eglimage", - "format", GST_TYPE_VIDEO_FORMAT, pool->info.finfo->format, - "width", G_TYPE_INT, pool->info.width, - "height", G_TYPE_INT, pool->info.height, NULL); - query = gst_query_new_custom (GST_QUERY_CUSTOM, s); - - ret = queue_object (state, GST_MINI_OBJECT_CAST (query), TRUE); - - if (ret != TRUE || !gst_structure_has_field (s, "buffer")) { - GST_WARNING ("Fallback memory allocation"); - gst_query_unref (query); - return - GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->alloc_buffer - (bpool, buffer, params); - } - - v = gst_structure_get_value (s, "buffer"); - *buffer = GST_BUFFER_CAST (g_value_get_pointer (v)); - gst_query_unref (query); - - if (!*buffer) { - GST_WARNING ("Fallback memory allocation"); - return - GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->alloc_buffer - (bpool, buffer, params); - } - - return GST_FLOW_OK; - break; - } - default: - return - GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->alloc_buffer (bpool, - buffer, params); - break; - } - - return GST_FLOW_ERROR; -} - -static GstFlowReturn -gst_custom_egl_image_buffer_pool_acquire_buffer (GstBufferPool * bpool, - GstBuffer ** buffer, GstBufferPoolAcquireParams * params) -{ - GstFlowReturn ret; - GstCustomEGLImageBufferPool *pool; - - ret = - GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->acquire_buffer (bpool, - buffer, params); - if (ret != GST_FLOW_OK || !*buffer) - return ret; - - pool = GST_CUSTOM_EGL_IMAGE_BUFFER_POOL (bpool); - - /* XXX: Don't return the memory we just rendered, glEGLImageTargetTexture2DOES() - * keeps the EGLImage unmappable until the next one is uploaded - */ - if (*buffer && *buffer == pool->state->current_buffer) { - GstBuffer *oldbuf = *buffer; - - ret = - GST_BUFFER_POOL_CLASS - (gst_custom_egl_image_buffer_pool_parent_class)->acquire_buffer (bpool, - buffer, params); - gst_object_replace ((GstObject **) & oldbuf->pool, (GstObject *) pool); - gst_buffer_unref (oldbuf); - } - - return ret; -} - -static void -gst_custom_egl_image_buffer_pool_finalize (GObject * object) -{ - GstCustomEGLImageBufferPool *pool = GST_CUSTOM_EGL_IMAGE_BUFFER_POOL (object); - - if (pool->allocator) - gst_object_unref (pool->allocator); - pool->allocator = NULL; - - if (pool->display) - gst_egl_display_unref (pool->display); - pool->display = NULL; - - G_OBJECT_CLASS (gst_custom_egl_image_buffer_pool_parent_class)->finalize - (object); -} - -static void -gst_custom_egl_image_buffer_pool_class_init (GstCustomEGLImageBufferPoolClass * - klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass; - - gobject_class->finalize = gst_custom_egl_image_buffer_pool_finalize; - gstbufferpool_class->get_options = - gst_custom_egl_image_buffer_pool_get_options; - gstbufferpool_class->set_config = gst_custom_egl_image_buffer_pool_set_config; - gstbufferpool_class->alloc_buffer = - gst_custom_egl_image_buffer_pool_alloc_buffer; - gstbufferpool_class->acquire_buffer = - gst_custom_egl_image_buffer_pool_acquire_buffer; -} - -static void -gst_custom_egl_image_buffer_pool_init (GstCustomEGLImageBufferPool * pool) -{ -} - -static GstBufferPool * -gst_custom_egl_image_buffer_pool_new (APP_STATE_T * state, - GstEGLDisplay * display) -{ - GstCustomEGLImageBufferPool *pool; - - pool = g_object_new (gst_custom_egl_image_buffer_pool_get_type (), NULL); - pool->display = gst_egl_display_ref (state->gst_display); - pool->state = state; - - return (GstBufferPool *) pool; -} - /*********************************************************** * Name: init_ogl * @@ -636,13 +228,17 @@ init_ogl (APP_STATE_T * state) int32_t success = 0; EGLBoolean result; EGLint num_config; + EGLNativeWindowType window_handle = (EGLNativeWindowType) 0; +#if defined (USE_OMX_TARGET_RPI) static EGL_DISPMANX_WINDOW_T nativewindow; DISPMANX_UPDATE_HANDLE_T dispman_update; VC_RECT_T dst_rect; VC_RECT_T src_rect; +#endif + //FIXME static const EGLint attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, @@ -664,6 +260,7 @@ init_ogl (APP_STATE_T * state) result = eglInitialize (state->display, NULL, NULL); assert (EGL_FALSE != result); +#if defined (USE_OMX_TARGET_RPI) /* get an appropriate EGL frame buffer configuration * this uses a BRCM extension that gets the closest match, rather * than standard which returns anything that matches. */ @@ -671,12 +268,17 @@ init_ogl (APP_STATE_T * state) eglSaneChooseConfigBRCM (state->display, attribute_list, &config, 1, &num_config); assert (EGL_FALSE != result); +#else + result = + eglChooseConfig (state->display, attribute_list, &config, 1, &num_config); +#endif /* create an EGL rendering context */ state->context = eglCreateContext (state->display, config, EGL_NO_CONTEXT, NULL); assert (state->context != EGL_NO_CONTEXT); +#if defined (USE_OMX_TARGET_RPI) /* create an EGL window surface */ success = graphics_get_display_size (0 /* LCD */ , &state->screen_width, &state->screen_height); @@ -706,8 +308,11 @@ init_ogl (APP_STATE_T * state) nativewindow.height = state->screen_height; vc_dispmanx_update_submit_sync (dispman_update); + window_handle = &nativewindow; +#endif + state->surface = - eglCreateWindowSurface (state->display, config, &nativewindow, NULL); + eglCreateWindowSurface (state->display, config, window_handle, NULL); assert (state->surface != EGL_NO_SURFACE); /* connect the context to the surface */ @@ -976,22 +581,20 @@ render_scene (APP_STATE_T * state) static void update_image (APP_STATE_T * state, GstBuffer * buffer) { - GstMemory *mem = NULL; - - if (state->current_buffer) { - gst_buffer_unref (state->current_buffer); - } - state->current_buffer = gst_buffer_ref (buffer); - - mem = gst_buffer_peek_memory (buffer, 0); + GstVideoGLTextureUploadMeta *meta = NULL; - TRACE_VC_MEMORY_ONCE_FOR_ID ("before glEGLImageTargetTexture2DOES", gid0); + TRACE_VC_MEMORY_ONCE_FOR_ID ("before GstVideoGLTextureUploadMeta", gid0); - glBindTexture (GL_TEXTURE_2D, state->tex); - glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, - gst_egl_image_memory_get_image (mem)); + if ((meta = gst_buffer_get_video_gl_texture_upload_meta (buffer))) { + if (meta->n_textures == 1) { + guint ids[4] = { state->tex, 0, 0, 0 }; + if (!gst_video_gl_texture_upload_meta_upload (meta, ids)) { + GST_WARNING ("failed to upload eglimage to texture"); + } + } + } - TRACE_VC_MEMORY_ONCE_FOR_ID ("after glEGLImageTargetTexture2DOES", gid1); + TRACE_VC_MEMORY_ONCE_FOR_ID ("after GstVideoGLTextureUploadMeta", gid1); } static void @@ -999,8 +602,8 @@ init_intercom (APP_STATE_T * state) { state->queue = g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref); - state->queue_lock = g_mutex_new (); - state->cond = g_cond_new (); + g_mutex_init (&state->queue_lock); + g_cond_init (&state->cond); } static void @@ -1011,22 +614,13 @@ terminate_intercom (APP_STATE_T * state) g_async_queue_unref (state->queue); } - if (state->queue_lock) { - g_mutex_free (state->queue_lock); - } - - if (state->cond) { - g_cond_free (state->cond); - } + g_mutex_clear (&state->queue_lock); + g_cond_clear (&state->cond); } static void flush_internal (APP_STATE_T * state) { - if (state->current_buffer) { - gst_buffer_unref (state->current_buffer); - } - state->current_buffer = NULL; } static void @@ -1034,18 +628,18 @@ flush_start (APP_STATE_T * state) { GstMiniObject *object = NULL; - g_mutex_lock (state->queue_lock); + g_mutex_lock (&state->queue_lock); state->flushing = TRUE; - g_cond_broadcast (state->cond); - g_mutex_unlock (state->queue_lock); + g_cond_broadcast (&state->cond); + g_mutex_unlock (&state->queue_lock); while ((object = g_async_queue_try_pop (state->queue))) { gst_mini_object_unref (object); } - g_mutex_lock (state->queue_lock); + g_mutex_lock (&state->queue_lock); flush_internal (state); state->popped_obj = NULL; - g_mutex_unlock (state->queue_lock); + g_mutex_unlock (&state->queue_lock); } static void @@ -1053,14 +647,14 @@ flush_stop (APP_STATE_T * state) { GstMiniObject *object = NULL; - g_mutex_lock (state->queue_lock); + g_mutex_lock (&state->queue_lock); while ((object = GST_MINI_OBJECT_CAST (g_async_queue_try_pop (state->queue)))) { gst_mini_object_unref (object); } flush_internal (state); state->popped_obj = NULL; state->flushing = FALSE; - g_mutex_unlock (state->queue_lock); + g_mutex_unlock (&state->queue_lock); } static void @@ -1118,9 +712,9 @@ handle_queued_objects (APP_STATE_T * state) { GstMiniObject *object = NULL; - g_mutex_lock (state->queue_lock); + g_mutex_lock (&state->queue_lock); if (state->flushing) { - g_cond_broadcast (state->cond); + g_cond_broadcast (&state->cond); goto beach; } else if (g_async_queue_length (state->queue) == 0) { goto beach; @@ -1139,38 +733,8 @@ handle_queued_objects (APP_STATE_T * state) GstQuery *query = GST_QUERY_CAST (object); GstStructure *s = (GstStructure *) gst_query_get_structure (query); - if (gst_structure_has_name (s, "eglglessink-allocate-eglimage")) { - GstBuffer *buffer; - GstVideoFormat format; - gint width, height; - GValue v = { 0, }; - - if (!gst_structure_get_enum (s, "format", GST_TYPE_VIDEO_FORMAT, - (gint *) & format) - || !gst_structure_get_int (s, "width", &width) - || !gst_structure_get_int (s, "height", &height)) { - g_assert_not_reached (); - } - - buffer = - gst_egl_allocate_eglimage (state, - GST_CUSTOM_EGL_IMAGE_BUFFER_POOL (state->pool)->allocator, format, - width, height); - g_value_init (&v, G_TYPE_POINTER); - g_value_set_pointer (&v, buffer); - - gst_structure_set_value (s, "buffer", &v); - g_value_unset (&v); - } else if (gst_structure_has_name (s, "eglglessink-deallocate-eglimage")) { - gpointer _image, _texture; - EGLImageKHR image; - GLuint texture; - gst_structure_get (s, "EGLImage", G_TYPE_POINTER, &_image, "GLTexture", - G_TYPE_POINTER, &_texture, NULL); - image = (EGLImageKHR) _image; - texture = (GLuint) _texture; - eglDestroyImageKHR (state->display, image); - glDeleteTextures (1, &texture); + if (gst_structure_has_name (s, "not-used")) { + g_assert_not_reached (); } else { g_assert_not_reached (); } @@ -1193,11 +757,11 @@ handle_queued_objects (APP_STATE_T * state) if (object) { state->popped_obj = object; - g_cond_broadcast (state->cond); + g_cond_broadcast (&state->cond); } beach: - g_mutex_unlock (state->queue_lock); + g_mutex_unlock (&state->queue_lock); return FALSE; } @@ -1207,7 +771,7 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous) { gboolean res = TRUE; - g_mutex_lock (state->queue_lock); + g_mutex_lock (&state->queue_lock); if (state->flushing) { gst_mini_object_unref (obj); res = FALSE; @@ -1219,12 +783,12 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous) if (synchronous) { /* Waiting for object to be handled */ do { - g_cond_wait (state->cond, state->queue_lock); + g_cond_wait (&state->cond, &state->queue_lock); } while (!state->flushing && state->popped_obj != obj); } beach: - g_mutex_unlock (state->queue_lock); + g_mutex_unlock (&state->queue_lock); return res; } @@ -1273,117 +837,38 @@ query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) { APP_STATE_T *state = (APP_STATE_T *) user_data; GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info); + GstStructure *external_gl_context_desc = NULL; + gchar *platform = NULL; + gchar *gl_apis = NULL; switch (GST_QUERY_TYPE (query)) { case GST_QUERY_ALLOCATION: { - GstBufferPool *pool; - GstStructure *config; - GstCaps *caps; - GstVideoInfo info; - gboolean need_pool; - guint size; - GstAllocator *allocator; - GstAllocationParams params; - - gst_allocation_params_init (¶ms); - - gst_query_parse_allocation (query, &caps, &need_pool); - - if (!caps) { - GST_ERROR ("allocation query without caps"); - return GST_PAD_PROBE_OK; - } - - if (!gst_video_info_from_caps (&info, caps)) { - GST_ERROR ("allocation query with invalid caps"); - return GST_PAD_PROBE_OK; - } - - g_mutex_lock (state->queue_lock); - pool = state->pool ? gst_object_ref (state->pool) : NULL; - g_mutex_unlock (state->queue_lock); - - if (pool) { - GstCaps *pcaps; - - /* we had a pool, check caps */ - - config = gst_buffer_pool_get_config (pool); - gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL); - GST_DEBUG ("check existing pool caps %" GST_PTR_FORMAT - " with new caps %" GST_PTR_FORMAT, pcaps, caps); - - if (!gst_caps_is_equal (caps, pcaps)) { - GST_DEBUG ("pool has different caps"); - /* different caps, we can't use this pool */ - gst_object_unref (pool); - pool = NULL; - } - gst_structure_free (config); - } - - GST_DEBUG ("pool %p", pool); - if (pool == NULL && need_pool) { - GstVideoInfo info; - - if (!gst_video_info_from_caps (&info, caps)) { - GST_ERROR ("allocation query has invalid caps %" - GST_PTR_FORMAT, caps); - return GST_PAD_PROBE_OK; - } - - GST_DEBUG ("create new pool"); - state->pool = pool = - gst_custom_egl_image_buffer_pool_new (state, state->display); - GST_DEBUG ("done create new pool %p", pool); - /* the normal size of a frame */ - size = info.size; - - config = gst_buffer_pool_get_config (pool); - /* we need at least 2 buffer because we hold on to the last one */ - gst_buffer_pool_config_set_params (config, caps, size, 2, 0); - gst_buffer_pool_config_set_allocator (config, NULL, ¶ms); - if (!gst_buffer_pool_set_config (pool, config)) { - gst_object_unref (pool); - GST_ERROR ("failed to set pool configuration"); - return GST_PAD_PROBE_OK; - } - } - - if (pool) { - /* we need at least 2 buffer because we hold on to the last one */ - gst_query_add_allocation_pool (query, pool, size, 2, 0); - gst_object_unref (pool); - } - - /* First the default allocator */ - if (!gst_egl_image_memory_is_mappable ()) { - allocator = gst_allocator_find (NULL); - gst_query_add_allocation_param (query, allocator, ¶ms); - gst_object_unref (allocator); - } - - allocator = gst_egl_image_allocator_obtain (); - GST_WARNING ("Allocator obtained %p", allocator); - - if (!gst_egl_image_memory_is_mappable ()) - params.flags |= GST_MEMORY_FLAG_NOT_MAPPABLE; - gst_query_add_allocation_param (query, allocator, ¶ms); - gst_object_unref (allocator); - - gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL); + platform = gst_gl_platform_to_string (GST_GL_PLATFORM_EGL); + gl_apis = gst_gl_api_to_string (GST_GL_API_GLES1); + + external_gl_context_desc = + gst_structure_new ("GstVideoGLTextureUploadMeta", + "gst.gl.context.handle", G_TYPE_POINTER, state->context, + "gst.gl.context.type", G_TYPE_STRING, platform, + "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL); gst_query_add_allocation_meta (query, - GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL); + GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, + NULL /*external_gl_context_desc */ ); + gst_structure_free (external_gl_context_desc); + + g_free (gl_apis); + g_free (platform); GST_DEBUG ("done alocation"); return GST_PAD_PROBE_OK; break; } - case GST_QUERY_DRAIN: + + case GST_QUERY_CONTEXT: { - flush_internal (state); + return gst_gl_handle_context_query (state->pipeline, query, + (GstGLDisplay **) & state->gst_display); break; } default: @@ -1396,9 +881,12 @@ query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) static gboolean init_playbin_player (APP_STATE_T * state, const gchar * uri) { - GstElement *vsink; - - vsink = gst_element_factory_make ("fakesink", "vsink"); + GstPad *pad = NULL; + GstPad *ghostpad = NULL; + GstElement *vbin = gst_bin_new ("vbin"); + /* FIXME replace it by glcolorscale */ + GstElement *glfilter = gst_element_factory_make ("gleffects", "glfilter"); + GstElement *vsink = gst_element_factory_make ("fakesink", "vsink"); g_object_set (vsink, "sync", TRUE, "silent", TRUE, "qos", TRUE, "enable-last-sample", FALSE, "max-lateness", 20 * GST_MSECOND, "signal-handoffs", TRUE, NULL); @@ -1406,18 +894,29 @@ init_playbin_player (APP_STATE_T * state, const gchar * uri) g_signal_connect (vsink, "preroll-handoff", G_CALLBACK (preroll_cb), state); g_signal_connect (vsink, "handoff", G_CALLBACK (buffers_cb), state); - gst_pad_add_probe (gst_element_get_static_pad (vsink, "sink"), - GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, events_cb, state, NULL); - gst_pad_add_probe (gst_element_get_static_pad (vsink, "sink"), - GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM, query_cb, state, NULL); + gst_bin_add_many (GST_BIN (vbin), glfilter, vsink, NULL); + + pad = gst_element_get_static_pad (glfilter, "sink"); + ghostpad = gst_ghost_pad_new ("sink", pad); + gst_object_unref (pad); + gst_element_add_pad (vbin, ghostpad); + + gst_pad_add_probe (ghostpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, events_cb, + state, NULL); + gst_pad_add_probe (ghostpad, GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM, query_cb, + state, NULL); + + gst_element_link (glfilter, vsink); + + // FIXME unref ghostpad ? /* Instantiate and configure playbin */ state->pipeline = gst_element_factory_make ("playbin", "player"); g_object_set (state->pipeline, "uri", uri, - "video-sink", vsink, "flags", + "video-sink", vbin, "flags", GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_AUDIO, NULL); - state->vsink = gst_object_ref (vsink); + state->vsink = gst_object_ref (vsink); // FIXME vbin ? return TRUE; } @@ -1427,6 +926,8 @@ init_parse_launch_player (APP_STATE_T * state, const gchar * spipeline) GstElement *vsink; GError *error = NULL; + // FIXME handle parse + state->pipeline = gst_parse_launch (spipeline, &error); if (!state->pipeline) { @@ -1650,7 +1151,9 @@ qos_cb (GstBus * bus, GstMessage * msg, APP_STATE_T * state) static void close_ogl (void) { +#if defined (USE_OMX_TARGET_RPI) DISPMANX_UPDATE_HANDLE_T dispman_update; +#endif /* clear screen */ glClear (GL_COLOR_BUFFER_BIT); @@ -1661,12 +1164,14 @@ close_ogl (void) EGL_NO_CONTEXT); eglDestroySurface (state->display, state->surface); eglDestroyContext (state->display, state->context); - gst_egl_display_unref (state->gst_display); + gst_object_unref (state->gst_display); +#if defined (USE_OMX_TARGET_RPI) dispman_update = vc_dispmanx_update_start (0); vc_dispmanx_element_remove (dispman_update, state->dispman_element); vc_dispmanx_update_submit_sync (dispman_update); vc_dispmanx_display_close (state->dispman_display); +#endif } //============================================================================== @@ -1676,7 +1181,7 @@ open_ogl (void) { TRACE_VC_MEMORY ("state 0"); -#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) +#if defined (USE_OMX_TARGET_RPI) bcm_host_init (); TRACE_VC_MEMORY ("after bcm_host_init"); #endif @@ -1685,8 +1190,8 @@ open_ogl (void) init_ogl (state); TRACE_VC_MEMORY ("after init_ogl"); - /* Wrap the EGL display */ - state->gst_display = gst_egl_display_new (state->display, NULL); + /* Wrap the EGLDisplay to GstGLDisplayEGL */ + state->gst_display = gst_gl_display_egl_new_with_egl_display (state->display); /* Setup the model world */ init_model_proj (state); @@ -1730,9 +1235,11 @@ main (int argc, char **argv) state->animate = TRUE; state->current_buffer = NULL; +#if !GLIB_CHECK_VERSION (2, 31, 0) /* must initialise the threading system before using any other GLib funtion */ if (!g_thread_supported ()) g_thread_init (NULL); +#endif ctx = g_option_context_new ("[ADDITIONAL ARGUMENTS]"); g_option_context_add_main_entries (ctx, options, NULL);