mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-07 06:52:41 +00:00
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
This commit is contained in:
parent
4593f434a0
commit
f1c76ef921
2 changed files with 116 additions and 609 deletions
|
@ -13,11 +13,11 @@ testegl_LDADD = \
|
||||||
-lgstvideo-@GST_API_VERSION@ \
|
-lgstvideo-@GST_API_VERSION@ \
|
||||||
$(GST_BASE_LIBS) \
|
$(GST_BASE_LIBS) \
|
||||||
$(GST_LIBS) \
|
$(GST_LIBS) \
|
||||||
$(GST_EGL_LIBS)
|
$(GST_GL_LIBS)
|
||||||
|
|
||||||
testegl_CFLAGS = \
|
testegl_CFLAGS = \
|
||||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||||
$(GST_BASE_CFLAGS) \
|
$(GST_BASE_CFLAGS) \
|
||||||
$(GST_CFLAGS) \
|
$(GST_CFLAGS) \
|
||||||
$(GST_EGL_CFLAGS)
|
$(GST_GL_CFLAGS)
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ Copyright (C) 2013, Fluendo S.A.
|
||||||
@author: Josep Torra <josep@fluendo.com>
|
@author: Josep Torra <josep@fluendo.com>
|
||||||
Copyright (C) 2013, Video Experts Group LLC.
|
Copyright (C) 2013, Video Experts Group LLC.
|
||||||
@author: Ilya Smelykh <ilya@videoexpertsgroup.com>
|
@author: Ilya Smelykh <ilya@videoexpertsgroup.com>
|
||||||
|
Copyright (C) 2014 Julien Isorce <julien.isorce@collabora.co.uk>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
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 <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && defined (__GNUC__)
|
#if defined (USE_OMX_TARGET_RPI) && defined (__GNUC__)
|
||||||
#ifndef __VCCOREVER__
|
#ifndef __VCCOREVER__
|
||||||
#define __VCCOREVER__ 0x04000000
|
#define __VCCOREVER__ 0x04000000
|
||||||
#endif
|
#endif
|
||||||
|
@ -56,29 +57,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma GCC optimize ("gnu89-inline")
|
#pragma GCC optimize ("gnu89-inline")
|
||||||
#endif
|
#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 <GLES/gl.h>
|
#include <GLES/gl.h>
|
||||||
#include <GLES/glext.h>
|
#include <GLES/glext.h>
|
||||||
|
|
||||||
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && defined (__GNUC__)
|
#include <gst/gl/gl.h>
|
||||||
#ifndef __VCCOREVER__
|
#include <gst/gl/egl/gstgldisplay_egl.h>
|
||||||
#define __VCCOREVER__ 0x04000000
|
|
||||||
#endif
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
#pragma GCC diagnostic push
|
#include <bcm_host.h>
|
||||||
#pragma GCC diagnostic ignored "-Wredundant-decls"
|
|
||||||
#pragma GCC optimize ("gnu89-inline")
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EGL_EGLEXT_PROTOTYPES
|
#if defined (USE_OMX_TARGET_RPI) && defined (__GNUC__)
|
||||||
#include <gst/egl/egl.h>
|
|
||||||
|
|
||||||
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL) && defined (__GNUC__)
|
|
||||||
#pragma GCC reset_options
|
#pragma GCC reset_options
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
@ -93,7 +82,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#define TRACE_VC_MEMORY_ENABLED 0
|
#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) \
|
#define TRACE_VC_MEMORY(str) \
|
||||||
fprintf (stderr, "\n\n" str "\n"); \
|
fprintf (stderr, "\n\n" str "\n"); \
|
||||||
system ("vcdbg reloc >&2")
|
system ("vcdbg reloc >&2")
|
||||||
|
@ -135,8 +124,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
DISPMANX_DISPLAY_HANDLE_T dispman_display;
|
DISPMANX_DISPLAY_HANDLE_T dispman_display;
|
||||||
DISPMANX_ELEMENT_HANDLE_T dispman_element;
|
DISPMANX_ELEMENT_HANDLE_T dispman_element;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t screen_width;
|
uint32_t screen_width;
|
||||||
uint32_t screen_height;
|
uint32_t screen_height;
|
||||||
|
@ -165,17 +156,16 @@ typedef struct
|
||||||
/* GStreamer related resources */
|
/* GStreamer related resources */
|
||||||
GstElement *pipeline;
|
GstElement *pipeline;
|
||||||
GstElement *vsink;
|
GstElement *vsink;
|
||||||
GstEGLDisplay *gst_display;
|
GstGLDisplayEGL *gst_display;
|
||||||
|
|
||||||
/* Interthread comunication */
|
/* Interthread comunication */
|
||||||
GAsyncQueue *queue;
|
GAsyncQueue *queue;
|
||||||
GMutex *queue_lock;
|
GMutex queue_lock;
|
||||||
GCond *cond;
|
GCond cond;
|
||||||
gboolean flushing;
|
gboolean flushing;
|
||||||
GstMiniObject *popped_obj;
|
GstMiniObject *popped_obj;
|
||||||
GstBuffer *current_buffer;
|
GstBuffer *current_buffer;
|
||||||
|
|
||||||
GstBufferPool *pool;
|
|
||||||
/* GLib mainloop */
|
/* GLib mainloop */
|
||||||
GMainLoop *main_loop;
|
GMainLoop *main_loop;
|
||||||
GstBuffer *last_buffer;
|
GstBuffer *last_buffer;
|
||||||
|
@ -190,37 +180,6 @@ typedef struct
|
||||||
guint64 dropped;
|
guint64 dropped;
|
||||||
} APP_STATE_T;
|
} 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_ogl (APP_STATE_T * state);
|
||||||
static void init_model_proj (APP_STATE_T * state);
|
static void init_model_proj (APP_STATE_T * state);
|
||||||
static void reset_model (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 update_model (APP_STATE_T * state);
|
||||||
static void init_textures (APP_STATE_T * state);
|
static void init_textures (APP_STATE_T * state);
|
||||||
static APP_STATE_T _state, *state = &_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,
|
static gboolean queue_object (APP_STATE_T * state, GstMiniObject * obj,
|
||||||
gboolean synchronous);
|
gboolean synchronous);
|
||||||
|
|
||||||
|
@ -254,371 +211,6 @@ typedef enum
|
||||||
GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
|
GST_PLAY_FLAG_SOFT_COLORBALANCE = (1 << 10)
|
||||||
} GstPlayFlags;
|
} 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
|
* Name: init_ogl
|
||||||
*
|
*
|
||||||
|
@ -636,13 +228,17 @@ init_ogl (APP_STATE_T * state)
|
||||||
int32_t success = 0;
|
int32_t success = 0;
|
||||||
EGLBoolean result;
|
EGLBoolean result;
|
||||||
EGLint num_config;
|
EGLint num_config;
|
||||||
|
EGLNativeWindowType window_handle = (EGLNativeWindowType) 0;
|
||||||
|
|
||||||
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
static EGL_DISPMANX_WINDOW_T nativewindow;
|
static EGL_DISPMANX_WINDOW_T nativewindow;
|
||||||
|
|
||||||
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
||||||
VC_RECT_T dst_rect;
|
VC_RECT_T dst_rect;
|
||||||
VC_RECT_T src_rect;
|
VC_RECT_T src_rect;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//FIXME
|
||||||
static const EGLint attribute_list[] = {
|
static const EGLint attribute_list[] = {
|
||||||
EGL_RED_SIZE, 8,
|
EGL_RED_SIZE, 8,
|
||||||
EGL_GREEN_SIZE, 8,
|
EGL_GREEN_SIZE, 8,
|
||||||
|
@ -664,6 +260,7 @@ init_ogl (APP_STATE_T * state)
|
||||||
result = eglInitialize (state->display, NULL, NULL);
|
result = eglInitialize (state->display, NULL, NULL);
|
||||||
assert (EGL_FALSE != result);
|
assert (EGL_FALSE != result);
|
||||||
|
|
||||||
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
/* get an appropriate EGL frame buffer configuration
|
/* get an appropriate EGL frame buffer configuration
|
||||||
* this uses a BRCM extension that gets the closest match, rather
|
* this uses a BRCM extension that gets the closest match, rather
|
||||||
* than standard which returns anything that matches. */
|
* than standard which returns anything that matches. */
|
||||||
|
@ -671,12 +268,17 @@ init_ogl (APP_STATE_T * state)
|
||||||
eglSaneChooseConfigBRCM (state->display, attribute_list, &config, 1,
|
eglSaneChooseConfigBRCM (state->display, attribute_list, &config, 1,
|
||||||
&num_config);
|
&num_config);
|
||||||
assert (EGL_FALSE != result);
|
assert (EGL_FALSE != result);
|
||||||
|
#else
|
||||||
|
result =
|
||||||
|
eglChooseConfig (state->display, attribute_list, &config, 1, &num_config);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* create an EGL rendering context */
|
/* create an EGL rendering context */
|
||||||
state->context =
|
state->context =
|
||||||
eglCreateContext (state->display, config, EGL_NO_CONTEXT, NULL);
|
eglCreateContext (state->display, config, EGL_NO_CONTEXT, NULL);
|
||||||
assert (state->context != EGL_NO_CONTEXT);
|
assert (state->context != EGL_NO_CONTEXT);
|
||||||
|
|
||||||
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
/* create an EGL window surface */
|
/* create an EGL window surface */
|
||||||
success = graphics_get_display_size (0 /* LCD */ , &state->screen_width,
|
success = graphics_get_display_size (0 /* LCD */ , &state->screen_width,
|
||||||
&state->screen_height);
|
&state->screen_height);
|
||||||
|
@ -706,8 +308,11 @@ init_ogl (APP_STATE_T * state)
|
||||||
nativewindow.height = state->screen_height;
|
nativewindow.height = state->screen_height;
|
||||||
vc_dispmanx_update_submit_sync (dispman_update);
|
vc_dispmanx_update_submit_sync (dispman_update);
|
||||||
|
|
||||||
|
window_handle = &nativewindow;
|
||||||
|
#endif
|
||||||
|
|
||||||
state->surface =
|
state->surface =
|
||||||
eglCreateWindowSurface (state->display, config, &nativewindow, NULL);
|
eglCreateWindowSurface (state->display, config, window_handle, NULL);
|
||||||
assert (state->surface != EGL_NO_SURFACE);
|
assert (state->surface != EGL_NO_SURFACE);
|
||||||
|
|
||||||
/* connect the context to the surface */
|
/* connect the context to the surface */
|
||||||
|
@ -976,22 +581,20 @@ render_scene (APP_STATE_T * state)
|
||||||
static void
|
static void
|
||||||
update_image (APP_STATE_T * state, GstBuffer * buffer)
|
update_image (APP_STATE_T * state, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstMemory *mem = NULL;
|
GstVideoGLTextureUploadMeta *meta = NULL;
|
||||||
|
|
||||||
if (state->current_buffer) {
|
TRACE_VC_MEMORY_ONCE_FOR_ID ("before GstVideoGLTextureUploadMeta", gid0);
|
||||||
gst_buffer_unref (state->current_buffer);
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
state->current_buffer = gst_buffer_ref (buffer);
|
|
||||||
|
|
||||||
mem = gst_buffer_peek_memory (buffer, 0);
|
TRACE_VC_MEMORY_ONCE_FOR_ID ("after GstVideoGLTextureUploadMeta", gid1);
|
||||||
|
|
||||||
TRACE_VC_MEMORY_ONCE_FOR_ID ("before glEGLImageTargetTexture2DOES", gid0);
|
|
||||||
|
|
||||||
glBindTexture (GL_TEXTURE_2D, state->tex);
|
|
||||||
glEGLImageTargetTexture2DOES (GL_TEXTURE_2D,
|
|
||||||
gst_egl_image_memory_get_image (mem));
|
|
||||||
|
|
||||||
TRACE_VC_MEMORY_ONCE_FOR_ID ("after glEGLImageTargetTexture2DOES", gid1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -999,8 +602,8 @@ init_intercom (APP_STATE_T * state)
|
||||||
{
|
{
|
||||||
state->queue =
|
state->queue =
|
||||||
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
g_async_queue_new_full ((GDestroyNotify) gst_mini_object_unref);
|
||||||
state->queue_lock = g_mutex_new ();
|
g_mutex_init (&state->queue_lock);
|
||||||
state->cond = g_cond_new ();
|
g_cond_init (&state->cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1011,22 +614,13 @@ terminate_intercom (APP_STATE_T * state)
|
||||||
g_async_queue_unref (state->queue);
|
g_async_queue_unref (state->queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->queue_lock) {
|
g_mutex_clear (&state->queue_lock);
|
||||||
g_mutex_free (state->queue_lock);
|
g_cond_clear (&state->cond);
|
||||||
}
|
|
||||||
|
|
||||||
if (state->cond) {
|
|
||||||
g_cond_free (state->cond);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
flush_internal (APP_STATE_T * state)
|
flush_internal (APP_STATE_T * state)
|
||||||
{
|
{
|
||||||
if (state->current_buffer) {
|
|
||||||
gst_buffer_unref (state->current_buffer);
|
|
||||||
}
|
|
||||||
state->current_buffer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1034,18 +628,18 @@ flush_start (APP_STATE_T * state)
|
||||||
{
|
{
|
||||||
GstMiniObject *object = NULL;
|
GstMiniObject *object = NULL;
|
||||||
|
|
||||||
g_mutex_lock (state->queue_lock);
|
g_mutex_lock (&state->queue_lock);
|
||||||
state->flushing = TRUE;
|
state->flushing = TRUE;
|
||||||
g_cond_broadcast (state->cond);
|
g_cond_broadcast (&state->cond);
|
||||||
g_mutex_unlock (state->queue_lock);
|
g_mutex_unlock (&state->queue_lock);
|
||||||
|
|
||||||
while ((object = g_async_queue_try_pop (state->queue))) {
|
while ((object = g_async_queue_try_pop (state->queue))) {
|
||||||
gst_mini_object_unref (object);
|
gst_mini_object_unref (object);
|
||||||
}
|
}
|
||||||
g_mutex_lock (state->queue_lock);
|
g_mutex_lock (&state->queue_lock);
|
||||||
flush_internal (state);
|
flush_internal (state);
|
||||||
state->popped_obj = NULL;
|
state->popped_obj = NULL;
|
||||||
g_mutex_unlock (state->queue_lock);
|
g_mutex_unlock (&state->queue_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1053,14 +647,14 @@ flush_stop (APP_STATE_T * state)
|
||||||
{
|
{
|
||||||
GstMiniObject *object = NULL;
|
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)))) {
|
while ((object = GST_MINI_OBJECT_CAST (g_async_queue_try_pop (state->queue)))) {
|
||||||
gst_mini_object_unref (object);
|
gst_mini_object_unref (object);
|
||||||
}
|
}
|
||||||
flush_internal (state);
|
flush_internal (state);
|
||||||
state->popped_obj = NULL;
|
state->popped_obj = NULL;
|
||||||
state->flushing = FALSE;
|
state->flushing = FALSE;
|
||||||
g_mutex_unlock (state->queue_lock);
|
g_mutex_unlock (&state->queue_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1118,9 +712,9 @@ handle_queued_objects (APP_STATE_T * state)
|
||||||
{
|
{
|
||||||
GstMiniObject *object = NULL;
|
GstMiniObject *object = NULL;
|
||||||
|
|
||||||
g_mutex_lock (state->queue_lock);
|
g_mutex_lock (&state->queue_lock);
|
||||||
if (state->flushing) {
|
if (state->flushing) {
|
||||||
g_cond_broadcast (state->cond);
|
g_cond_broadcast (&state->cond);
|
||||||
goto beach;
|
goto beach;
|
||||||
} else if (g_async_queue_length (state->queue) == 0) {
|
} else if (g_async_queue_length (state->queue) == 0) {
|
||||||
goto beach;
|
goto beach;
|
||||||
|
@ -1139,38 +733,8 @@ handle_queued_objects (APP_STATE_T * state)
|
||||||
GstQuery *query = GST_QUERY_CAST (object);
|
GstQuery *query = GST_QUERY_CAST (object);
|
||||||
GstStructure *s = (GstStructure *) gst_query_get_structure (query);
|
GstStructure *s = (GstStructure *) gst_query_get_structure (query);
|
||||||
|
|
||||||
if (gst_structure_has_name (s, "eglglessink-allocate-eglimage")) {
|
if (gst_structure_has_name (s, "not-used")) {
|
||||||
GstBuffer *buffer;
|
g_assert_not_reached ();
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
@ -1193,11 +757,11 @@ handle_queued_objects (APP_STATE_T * state)
|
||||||
|
|
||||||
if (object) {
|
if (object) {
|
||||||
state->popped_obj = object;
|
state->popped_obj = object;
|
||||||
g_cond_broadcast (state->cond);
|
g_cond_broadcast (&state->cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
g_mutex_unlock (state->queue_lock);
|
g_mutex_unlock (&state->queue_lock);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1207,7 +771,7 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
|
||||||
{
|
{
|
||||||
gboolean res = TRUE;
|
gboolean res = TRUE;
|
||||||
|
|
||||||
g_mutex_lock (state->queue_lock);
|
g_mutex_lock (&state->queue_lock);
|
||||||
if (state->flushing) {
|
if (state->flushing) {
|
||||||
gst_mini_object_unref (obj);
|
gst_mini_object_unref (obj);
|
||||||
res = FALSE;
|
res = FALSE;
|
||||||
|
@ -1219,12 +783,12 @@ queue_object (APP_STATE_T * state, GstMiniObject * obj, gboolean synchronous)
|
||||||
if (synchronous) {
|
if (synchronous) {
|
||||||
/* Waiting for object to be handled */
|
/* Waiting for object to be handled */
|
||||||
do {
|
do {
|
||||||
g_cond_wait (state->cond, state->queue_lock);
|
g_cond_wait (&state->cond, &state->queue_lock);
|
||||||
} while (!state->flushing && state->popped_obj != obj);
|
} while (!state->flushing && state->popped_obj != obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
g_mutex_unlock (state->queue_lock);
|
g_mutex_unlock (&state->queue_lock);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1273,117 +837,38 @@ query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
||||||
{
|
{
|
||||||
APP_STATE_T *state = (APP_STATE_T *) user_data;
|
APP_STATE_T *state = (APP_STATE_T *) user_data;
|
||||||
GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
|
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)) {
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
case GST_QUERY_ALLOCATION:
|
case GST_QUERY_ALLOCATION:
|
||||||
{
|
{
|
||||||
GstBufferPool *pool;
|
platform = gst_gl_platform_to_string (GST_GL_PLATFORM_EGL);
|
||||||
GstStructure *config;
|
gl_apis = gst_gl_api_to_string (GST_GL_API_GLES1);
|
||||||
GstCaps *caps;
|
|
||||||
GstVideoInfo info;
|
|
||||||
gboolean need_pool;
|
|
||||||
guint size;
|
|
||||||
GstAllocator *allocator;
|
|
||||||
GstAllocationParams params;
|
|
||||||
|
|
||||||
gst_allocation_params_init (¶ms);
|
external_gl_context_desc =
|
||||||
|
gst_structure_new ("GstVideoGLTextureUploadMeta",
|
||||||
gst_query_parse_allocation (query, &caps, &need_pool);
|
"gst.gl.context.handle", G_TYPE_POINTER, state->context,
|
||||||
|
"gst.gl.context.type", G_TYPE_STRING, platform,
|
||||||
if (!caps) {
|
"gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
|
||||||
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);
|
|
||||||
gst_query_add_allocation_meta (query,
|
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");
|
GST_DEBUG ("done alocation");
|
||||||
return GST_PAD_PROBE_OK;
|
return GST_PAD_PROBE_OK;
|
||||||
break;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1396,9 +881,12 @@ query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
|
||||||
static gboolean
|
static gboolean
|
||||||
init_playbin_player (APP_STATE_T * state, const gchar * uri)
|
init_playbin_player (APP_STATE_T * state, const gchar * uri)
|
||||||
{
|
{
|
||||||
GstElement *vsink;
|
GstPad *pad = NULL;
|
||||||
|
GstPad *ghostpad = NULL;
|
||||||
vsink = gst_element_factory_make ("fakesink", "vsink");
|
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,
|
g_object_set (vsink, "sync", TRUE, "silent", TRUE, "qos", TRUE,
|
||||||
"enable-last-sample", FALSE,
|
"enable-last-sample", FALSE,
|
||||||
"max-lateness", 20 * GST_MSECOND, "signal-handoffs", TRUE, NULL);
|
"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, "preroll-handoff", G_CALLBACK (preroll_cb), state);
|
||||||
g_signal_connect (vsink, "handoff", G_CALLBACK (buffers_cb), state);
|
g_signal_connect (vsink, "handoff", G_CALLBACK (buffers_cb), state);
|
||||||
|
|
||||||
gst_pad_add_probe (gst_element_get_static_pad (vsink, "sink"),
|
gst_bin_add_many (GST_BIN (vbin), glfilter, vsink, NULL);
|
||||||
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, events_cb, state, NULL);
|
|
||||||
gst_pad_add_probe (gst_element_get_static_pad (vsink, "sink"),
|
pad = gst_element_get_static_pad (glfilter, "sink");
|
||||||
GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM, query_cb, state, NULL);
|
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 */
|
/* Instantiate and configure playbin */
|
||||||
state->pipeline = gst_element_factory_make ("playbin", "player");
|
state->pipeline = gst_element_factory_make ("playbin", "player");
|
||||||
g_object_set (state->pipeline, "uri", uri,
|
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);
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1427,6 +926,8 @@ init_parse_launch_player (APP_STATE_T * state, const gchar * spipeline)
|
||||||
GstElement *vsink;
|
GstElement *vsink;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
|
// FIXME handle parse
|
||||||
|
|
||||||
state->pipeline = gst_parse_launch (spipeline, &error);
|
state->pipeline = gst_parse_launch (spipeline, &error);
|
||||||
|
|
||||||
if (!state->pipeline) {
|
if (!state->pipeline) {
|
||||||
|
@ -1650,7 +1151,9 @@ qos_cb (GstBus * bus, GstMessage * msg, APP_STATE_T * state)
|
||||||
static void
|
static void
|
||||||
close_ogl (void)
|
close_ogl (void)
|
||||||
{
|
{
|
||||||
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
DISPMANX_UPDATE_HANDLE_T dispman_update;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* clear screen */
|
/* clear screen */
|
||||||
glClear (GL_COLOR_BUFFER_BIT);
|
glClear (GL_COLOR_BUFFER_BIT);
|
||||||
|
@ -1661,12 +1164,14 @@ close_ogl (void)
|
||||||
EGL_NO_CONTEXT);
|
EGL_NO_CONTEXT);
|
||||||
eglDestroySurface (state->display, state->surface);
|
eglDestroySurface (state->display, state->surface);
|
||||||
eglDestroyContext (state->display, state->context);
|
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);
|
dispman_update = vc_dispmanx_update_start (0);
|
||||||
vc_dispmanx_element_remove (dispman_update, state->dispman_element);
|
vc_dispmanx_element_remove (dispman_update, state->dispman_element);
|
||||||
vc_dispmanx_update_submit_sync (dispman_update);
|
vc_dispmanx_update_submit_sync (dispman_update);
|
||||||
vc_dispmanx_display_close (state->dispman_display);
|
vc_dispmanx_display_close (state->dispman_display);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
@ -1676,7 +1181,7 @@ open_ogl (void)
|
||||||
{
|
{
|
||||||
TRACE_VC_MEMORY ("state 0");
|
TRACE_VC_MEMORY ("state 0");
|
||||||
|
|
||||||
#if defined (USE_OMX_TARGET_RPI) && defined (HAVE_GST_EGL)
|
#if defined (USE_OMX_TARGET_RPI)
|
||||||
bcm_host_init ();
|
bcm_host_init ();
|
||||||
TRACE_VC_MEMORY ("after bcm_host_init");
|
TRACE_VC_MEMORY ("after bcm_host_init");
|
||||||
#endif
|
#endif
|
||||||
|
@ -1685,8 +1190,8 @@ open_ogl (void)
|
||||||
init_ogl (state);
|
init_ogl (state);
|
||||||
TRACE_VC_MEMORY ("after init_ogl");
|
TRACE_VC_MEMORY ("after init_ogl");
|
||||||
|
|
||||||
/* Wrap the EGL display */
|
/* Wrap the EGLDisplay to GstGLDisplayEGL */
|
||||||
state->gst_display = gst_egl_display_new (state->display, NULL);
|
state->gst_display = gst_gl_display_egl_new_with_egl_display (state->display);
|
||||||
|
|
||||||
/* Setup the model world */
|
/* Setup the model world */
|
||||||
init_model_proj (state);
|
init_model_proj (state);
|
||||||
|
@ -1730,9 +1235,11 @@ main (int argc, char **argv)
|
||||||
state->animate = TRUE;
|
state->animate = TRUE;
|
||||||
state->current_buffer = NULL;
|
state->current_buffer = NULL;
|
||||||
|
|
||||||
|
#if !GLIB_CHECK_VERSION (2, 31, 0)
|
||||||
/* must initialise the threading system before using any other GLib funtion */
|
/* must initialise the threading system before using any other GLib funtion */
|
||||||
if (!g_thread_supported ())
|
if (!g_thread_supported ())
|
||||||
g_thread_init (NULL);
|
g_thread_init (NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
ctx = g_option_context_new ("[ADDITIONAL ARGUMENTS]");
|
ctx = g_option_context_new ("[ADDITIONAL ARGUMENTS]");
|
||||||
g_option_context_add_main_entries (ctx, options, NULL);
|
g_option_context_add_main_entries (ctx, options, NULL);
|
||||||
|
|
Loading…
Reference in a new issue