mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 02:31:03 +00:00
[330/906] Can now share textures with an external gl context
The external opengl context must be specify when creating our OpenGL context (glx) or just after (wgl). When calling glXCreateContext or wglShareLists, the external opengl context must not be current. Then our gl context can be current in the gl thread while the external gl context is current in an other thread. See tests/examples/clutter/cluttershare.c
This commit is contained in:
parent
b47fc234ef
commit
87a1652216
14 changed files with 287 additions and 50 deletions
|
@ -158,6 +158,9 @@ gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass)
|
|||
display->upload_data_height = 0;
|
||||
display->upload_data = NULL;
|
||||
|
||||
//foreign gl context
|
||||
display->external_gl_context = 0;
|
||||
|
||||
//filter gen fbo
|
||||
display->gen_fbo_width = 0;
|
||||
display->gen_fbo_height = 0;
|
||||
|
@ -527,7 +530,8 @@ gst_gl_display_thread_create_context (GstGLDisplay * display)
|
|||
GLenum err = 0;
|
||||
|
||||
display->gl_window =
|
||||
gst_gl_window_new (display->upload_width, display->upload_height);
|
||||
gst_gl_window_new (display->upload_width, display->upload_height,
|
||||
display->external_gl_context);
|
||||
|
||||
if (!display->gl_window) {
|
||||
display->isAlive = FALSE;
|
||||
|
@ -2065,12 +2069,13 @@ gst_gl_display_new (void)
|
|||
* Called by the first gl element of a video/x-raw-gl flow */
|
||||
void
|
||||
gst_gl_display_create_context (GstGLDisplay * display,
|
||||
GLint width, GLint height)
|
||||
GLint width, GLint height, guint64 external_gl_context)
|
||||
{
|
||||
gst_gl_display_lock (display);
|
||||
|
||||
display->upload_width = width;
|
||||
display->upload_height = height;
|
||||
display->external_gl_context = external_gl_context;
|
||||
|
||||
display->gl_thread = g_thread_create (
|
||||
(GThreadFunc) gst_gl_display_thread_create_context, display, TRUE, NULL);
|
||||
|
|
|
@ -135,6 +135,9 @@ struct _GstGLDisplay
|
|||
gint upload_data_height;
|
||||
gpointer upload_data;
|
||||
|
||||
//foreign gl context
|
||||
guint64 external_gl_context;
|
||||
|
||||
//filter gen fbo
|
||||
GLuint gen_fbo_width;
|
||||
GLuint gen_fbo_height;
|
||||
|
@ -236,7 +239,7 @@ GType gst_gl_display_get_type (void);
|
|||
GstGLDisplay *gst_gl_display_new (void);
|
||||
|
||||
void gst_gl_display_create_context (GstGLDisplay * display,
|
||||
GLint width, GLint height);
|
||||
GLint width, GLint height, guint64 external_gl_context);
|
||||
gboolean gst_gl_display_redisplay (GstGLDisplay * display, GLuint texture,
|
||||
gint width, gint height);
|
||||
|
||||
|
|
|
@ -79,10 +79,9 @@ struct _GstGLWindowClass {
|
|||
GQuark gst_gl_window_error_quark (void);
|
||||
GType gst_gl_window_get_type (void);
|
||||
|
||||
GstGLWindow * gst_gl_window_new (gint width, gint height);
|
||||
GstGLWindow * gst_gl_window_new (gint width, gint height, guint64 external_gl_context);
|
||||
|
||||
void gst_gl_window_set_external_window_id (GstGLWindow *window, guint64 id);
|
||||
void gst_gl_window_set_external_gl_context (GstGLWindow *window, guint64 context);
|
||||
void gst_gl_window_set_draw_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data);
|
||||
void gst_gl_window_set_resize_callback (GstGLWindow *window, GstGLWindowCB2 callback, gpointer data);
|
||||
void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data);
|
||||
|
|
|
@ -146,7 +146,7 @@ gst_gl_window_init (GstGLWindow * window)
|
|||
|
||||
/* Must be called in the gl thread */
|
||||
GstGLWindow *
|
||||
gst_gl_window_new (gint width, gint height)
|
||||
gst_gl_window_new (gint width, gint height, guint64 external_gl_context)
|
||||
{
|
||||
GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
|
||||
GstGLWindowPrivate *priv = window->priv;
|
||||
|
@ -229,12 +229,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
|
|||
g_debug ("failed to register current thread, cannot set external window id");
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_external_gl_context (GstGLWindow * window, guint64 context)
|
||||
{
|
||||
g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
|
||||
}
|
||||
|
||||
/* Must be called in the gl thread */
|
||||
void
|
||||
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
|
||||
|
|
|
@ -51,6 +51,7 @@ struct _GstGLWindowPrivate
|
|||
HWND internal_win_id;
|
||||
HDC device;
|
||||
HGLRC gl_context;
|
||||
HGLRC external_gl_context;
|
||||
GstGLWindowCB draw_cb;
|
||||
gpointer draw_data;
|
||||
GstGLWindowCB2 resize_cb;
|
||||
|
@ -143,7 +144,7 @@ gst_gl_window_init (GstGLWindow * window)
|
|||
|
||||
/* Must be called in the gl thread */
|
||||
GstGLWindow *
|
||||
gst_gl_window_new (gint width, gint height)
|
||||
gst_gl_window_new (gint width, gint height, guint64 external_gl_context)
|
||||
{
|
||||
GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
|
||||
GstGLWindowPrivate *priv = window->priv;
|
||||
|
@ -160,6 +161,7 @@ gst_gl_window_new (gint width, gint height)
|
|||
priv->internal_win_id = 0;
|
||||
priv->device = 0;
|
||||
priv->gl_context = 0;
|
||||
priv->external_gl_context = (HGLRC) external_gl_context;
|
||||
priv->draw_cb = NULL;
|
||||
priv->draw_data = NULL;
|
||||
priv->resize_cb = NULL;
|
||||
|
@ -226,12 +228,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
|
|||
rect.bottom, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_external_gl_context (GstGLWindow * window, guint64 context)
|
||||
{
|
||||
g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
|
||||
}
|
||||
|
||||
/* Must be called in the gl thread */
|
||||
void
|
||||
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
|
||||
|
@ -411,6 +407,14 @@ window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
if (!wglMakeCurrent (priv->device, priv->gl_context))
|
||||
g_debug ("failed to make opengl context current %d, %x\r\n", hWnd,
|
||||
GetLastError ());
|
||||
|
||||
if (priv->external_gl_context) {
|
||||
if (!wglShareLists (priv->gl_context, priv->external_gl_context))
|
||||
g_debug ("failed to share opengl context %lud with %lud\n",
|
||||
priv->gl_context, priv->external_gl_context);
|
||||
else
|
||||
g_debug ("share opengl context succeed\n");
|
||||
}
|
||||
}
|
||||
|
||||
SetProp (hWnd, "gl_window", window);
|
||||
|
|
|
@ -48,6 +48,7 @@ struct _GstGLWindowPrivate
|
|||
EGLDisplay display;
|
||||
EGLSurface surface;
|
||||
EGLContext gl_context;
|
||||
EGLContext external_gl_context;
|
||||
GstGLWindowCB draw_cb;
|
||||
gpointer draw_data;
|
||||
GstGLWindowCB2 resize_cb;
|
||||
|
@ -140,7 +141,7 @@ gst_gl_window_init (GstGLWindow * window)
|
|||
|
||||
/* Must be called in the gl thread */
|
||||
GstGLWindow *
|
||||
gst_gl_window_new (gint width, gint height)
|
||||
gst_gl_window_new (gint width, gint height, guint64 external_gl_context)
|
||||
{
|
||||
GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
|
||||
GstGLWindowPrivate *priv = window->priv;
|
||||
|
@ -158,6 +159,7 @@ gst_gl_window_new (gint width, gint height)
|
|||
priv->display = 0;
|
||||
priv->surface = 0;
|
||||
priv->gl_context = 0;
|
||||
priv->external_gl_context = (EGLContext) external_gl_context;
|
||||
priv->draw_cb = NULL;
|
||||
priv->draw_data = NULL;
|
||||
priv->resize_cb = NULL;
|
||||
|
@ -224,12 +226,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
|
|||
rect.bottom, FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_external_gl_context (GstGLWindow * window, guint64 context)
|
||||
{
|
||||
g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
|
||||
}
|
||||
|
||||
/* Must be called in the gl thread */
|
||||
void
|
||||
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
|
||||
|
@ -402,7 +398,7 @@ window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|||
priv->surface, hWnd, EGLErrorString ());
|
||||
|
||||
priv->gl_context =
|
||||
eglCreateContext (priv->display, config, EGL_NO_CONTEXT,
|
||||
eglCreateContext (priv->display, config, priv->external_gl_context,
|
||||
contextAttribs);
|
||||
if (priv->gl_context != EGL_NO_CONTEXT)
|
||||
g_debug ("gl context created: %d\n", priv->gl_context);
|
||||
|
|
|
@ -242,7 +242,7 @@ gst_gl_window_init (GstGLWindow * window)
|
|||
|
||||
/* Must be called in the gl thread */
|
||||
GstGLWindow *
|
||||
gst_gl_window_new (gint width, gint height)
|
||||
gst_gl_window_new (gint width, gint height, guint64 external_gl_context)
|
||||
{
|
||||
GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
|
||||
GstGLWindowPrivate *priv = window->priv;
|
||||
|
@ -379,7 +379,8 @@ gst_gl_window_new (gint width, gint height)
|
|||
XSetWMProtocols (priv->device, priv->internal_win_id, wm_atoms, 2);
|
||||
|
||||
priv->gl_context =
|
||||
glXCreateContext (priv->device, priv->visual_info, NULL, TRUE);
|
||||
glXCreateContext (priv->device, priv->visual_info,
|
||||
(GLXContext) external_gl_context, TRUE);
|
||||
|
||||
g_debug ("gl context id: %ld\n", (gulong) priv->gl_context);
|
||||
|
||||
|
@ -446,12 +447,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_external_gl_context (GstGLWindow * window, guint64 context)
|
||||
{
|
||||
g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
|
||||
gpointer data)
|
||||
|
|
|
@ -247,7 +247,7 @@ gst_gl_window_init (GstGLWindow * window)
|
|||
|
||||
/* Must be called in the gl thread */
|
||||
GstGLWindow *
|
||||
gst_gl_window_new (gint width, gint height)
|
||||
gst_gl_window_new (gint width, gint height, guint64 external_gl_context)
|
||||
{
|
||||
GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
|
||||
GstGLWindowPrivate *priv = window->priv;
|
||||
|
@ -395,7 +395,7 @@ gst_gl_window_new (gint width, gint height)
|
|||
(gulong) priv->gl_display, EGLErrorString ());
|
||||
|
||||
priv->gl_context =
|
||||
eglCreateContext (priv->gl_display, config, EGL_NO_CONTEXT,
|
||||
eglCreateContext (priv->gl_display, config, (EGLContext) external_gl_context,
|
||||
context_attrib);
|
||||
if (priv->gl_context != EGL_NO_CONTEXT)
|
||||
g_debug ("gl context created: %ld\n", (gulong) priv->gl_context);
|
||||
|
@ -448,12 +448,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_external_gl_context (GstGLWindow * window, guint64 context)
|
||||
{
|
||||
g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
|
||||
}
|
||||
|
||||
void
|
||||
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
|
||||
gpointer data)
|
||||
|
|
|
@ -395,7 +395,7 @@ gst_gl_colorscale_set_caps (GstBaseTransform * bt, GstCaps * incaps,
|
|||
|
||||
//init unvisible opengl context
|
||||
gst_gl_display_create_context (colorscale->display,
|
||||
colorscale->output_video_width, colorscale->output_video_height);
|
||||
colorscale->output_video_width, colorscale->output_video_height, 0);
|
||||
|
||||
//blocking call, init colorspace conversion if needed
|
||||
gst_gl_display_init_upload (colorscale->display,
|
||||
|
|
|
@ -514,7 +514,7 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||
|
||||
//init opengl context
|
||||
gst_gl_display_create_context (glimage_sink->display,
|
||||
glimage_sink->width, glimage_sink->height);
|
||||
glimage_sink->width, glimage_sink->height, 0);
|
||||
|
||||
if (glimage_sink->window_id)
|
||||
gst_gl_display_set_window_id (glimage_sink->display,
|
||||
|
|
|
@ -364,7 +364,7 @@ gst_gl_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
|
|||
gltestsrc->display = gst_gl_display_new ();
|
||||
|
||||
gst_gl_display_create_context (gltestsrc->display,
|
||||
gltestsrc->width, gltestsrc->height);
|
||||
gltestsrc->width, gltestsrc->height, 0);
|
||||
|
||||
gst_gl_display_gen_fbo (gltestsrc->display, gltestsrc->width,
|
||||
gltestsrc->height, &gltestsrc->fbo, &gltestsrc->depthbuffer);
|
||||
|
|
|
@ -123,7 +123,8 @@ static GstStaticPadTemplate gst_gl_upload_sink_pad_template =
|
|||
/* Properties */
|
||||
enum
|
||||
{
|
||||
PROP_0
|
||||
PROP_0,
|
||||
PROP_EXTERNAL_OPENGL_CONTEXT
|
||||
};
|
||||
|
||||
#define DEBUG_INIT(bla) \
|
||||
|
@ -186,6 +187,12 @@ gst_gl_upload_class_init (GstGLUploadClass * klass)
|
|||
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_upload_get_unit_size;
|
||||
GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer =
|
||||
gst_gl_upload_prepare_output_buffer;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_EXTERNAL_OPENGL_CONTEXT,
|
||||
g_param_spec_uint64 ("external_opengl_context",
|
||||
"External OpenGL context",
|
||||
"Give an external OpenGL context with which to share textures",
|
||||
0, _UI64_MAX, 0, G_PARAM_WRITABLE));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -198,9 +205,14 @@ static void
|
|||
gst_gl_upload_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
//GstGLUpload* upload = GST_GL_UPLOAD (object);
|
||||
GstGLUpload *upload = GST_GL_UPLOAD (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_EXTERNAL_OPENGL_CONTEXT:
|
||||
{
|
||||
upload->external_gl_context = g_value_get_uint64 (value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -227,6 +239,7 @@ gst_gl_upload_reset (GstGLUpload * upload)
|
|||
g_object_unref (upload->display);
|
||||
upload->display = NULL;
|
||||
}
|
||||
upload->external_gl_context = 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -438,7 +451,8 @@ gst_gl_upload_set_caps (GstBaseTransform * bt, GstCaps * incaps,
|
|||
|
||||
//init unvisible opengl context
|
||||
gst_gl_display_create_context (upload->display,
|
||||
upload->gl_width, upload->gl_height);
|
||||
upload->gl_width, upload->gl_height,
|
||||
upload->external_gl_context);
|
||||
|
||||
//init colorspace conversion if needed
|
||||
gst_gl_display_init_upload (upload->display, upload->video_format,
|
||||
|
|
|
@ -54,6 +54,7 @@ struct _GstGLUpload
|
|||
gint video_height;
|
||||
gint gl_width;
|
||||
gint gl_height;
|
||||
guint64 external_gl_context;
|
||||
};
|
||||
|
||||
struct _GstGLUploadClass
|
||||
|
|
232
tests/examples/clutter/cluttershare.c
Normal file
232
tests/examples/clutter/cluttershare.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <GL/glew.h>
|
||||
#ifdef WIN32
|
||||
#include <GL/wglew.h>
|
||||
#else
|
||||
#include <GL/glxew.h>
|
||||
#endif
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
/* This example shows how to use textures that come from a
|
||||
* gst-plugins-gl pipeline, into the clutter framework
|
||||
*/
|
||||
|
||||
/* hack */
|
||||
typedef struct _GstGLBuffer GstGLBuffer;
|
||||
struct _GstGLBuffer {
|
||||
GstBuffer buffer;
|
||||
|
||||
GObject *obj;
|
||||
|
||||
gint width;
|
||||
gint height;
|
||||
GLuint texture;
|
||||
};
|
||||
|
||||
/* clutter scene */
|
||||
ClutterActor*
|
||||
setup_stage (ClutterStage * stage)
|
||||
{
|
||||
/* timeline */
|
||||
|
||||
ClutterTimeline *timeline = clutter_timeline_new (120, 50);
|
||||
clutter_timeline_set_loop (timeline, TRUE);
|
||||
clutter_timeline_start (timeline);
|
||||
|
||||
/* effect template */
|
||||
|
||||
ClutterEffectTemplate *effect_template = clutter_effect_template_new (timeline, CLUTTER_ALPHA_SINE_INC);
|
||||
|
||||
/* texture actor */
|
||||
|
||||
ClutterActor *texture_actor = clutter_texture_new ();
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (stage), texture_actor);
|
||||
clutter_actor_set_position (texture_actor, 300, 170);
|
||||
clutter_actor_set_scale (texture_actor, 0.8, 0.8);
|
||||
clutter_effect_rotate (effect_template, texture_actor,
|
||||
CLUTTER_Z_AXIS, 180.0,
|
||||
50, 50, 0,
|
||||
CLUTTER_ROTATE_CW,
|
||||
NULL, NULL);
|
||||
clutter_actor_show (texture_actor);
|
||||
g_object_set_data (G_OBJECT (texture_actor), "stage", stage);
|
||||
|
||||
g_object_unref (effect_template);
|
||||
g_object_unref (timeline);
|
||||
|
||||
/* rectangle actor */
|
||||
|
||||
ClutterColor rect_color = { 125, 50, 200, 255 };
|
||||
ClutterActor* actorRect = clutter_rectangle_new_with_color (&rect_color);
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (stage), actorRect);
|
||||
clutter_actor_set_size (actorRect, 50, 50);
|
||||
clutter_actor_set_position (actorRect, 300, 300);
|
||||
clutter_effect_rotate (effect_template, actorRect,
|
||||
CLUTTER_Z_AXIS, 180.0,
|
||||
25, 25, 0,
|
||||
CLUTTER_ROTATE_CW,
|
||||
NULL, NULL);
|
||||
clutter_actor_show (actorRect);
|
||||
|
||||
return texture_actor;
|
||||
}
|
||||
|
||||
/* put a gst gl buffer in the texture actor */
|
||||
gboolean
|
||||
update_texture_actor (gpointer data)
|
||||
{
|
||||
GstGLBuffer *gst_gl_buf = (GstGLBuffer *) data;
|
||||
|
||||
/* Create a cogl texture from the gst gl texture */
|
||||
glEnable (GL_TEXTURE_2D);
|
||||
glBindTexture (GL_TEXTURE_2D, gst_gl_buf->texture);
|
||||
CoglHandle cogl_texture = cogl_texture_new_from_foreign (gst_gl_buf->texture,
|
||||
GL_TEXTURE_2D, gst_gl_buf->width, gst_gl_buf->height, 0, 0, COGL_PIXEL_FORMAT_RGBA_8888);
|
||||
cogl_texture_set_filters (cogl_texture, GL_LINEAR, GL_LINEAR);
|
||||
glDisable (GL_TEXTURE_2D);
|
||||
|
||||
/* Previous cogl texture is replaced and so its ref counter discreases to 0.
|
||||
* According to the source code, glDeleteTexture is not called when the previous
|
||||
* ref counter of the previous cogl texture is reaching 0 because is_foreign is TRUE */
|
||||
ClutterTexture *texture_actor = g_type_get_qdata (G_TYPE_FROM_INSTANCE (gst_gl_buf), g_quark_from_string ("texture_actor"));
|
||||
clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (texture_actor), cogl_texture);
|
||||
cogl_texture_unref (cogl_texture);
|
||||
|
||||
/* Keep a ref on the current gst_gl_buffer associated to the texture_actor.
|
||||
* The old gst_gl_buffer is unref */
|
||||
g_object_set_data_full (G_OBJECT (texture_actor), "gst_gl_buffer",
|
||||
gst_gl_buf, (GDestroyNotify) gst_mini_object_unref);
|
||||
|
||||
/* we can now show the clutter scene if not yet visible */
|
||||
ClutterActor *stage = g_object_get_data (G_OBJECT (texture_actor), "stage");
|
||||
if (!CLUTTER_ACTOR_IS_VISIBLE (stage))
|
||||
clutter_actor_show_all (stage);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* fakesink handoff callback */
|
||||
void
|
||||
on_gst_buffer (GstElement* element, GstBuffer* buf, GstPad* pad, ClutterActor* texture_actor)
|
||||
{
|
||||
/* increase ref because our pipeline and clutter scene have not a same framerate */
|
||||
gst_buffer_ref (buf);
|
||||
|
||||
/* Just to avoid a global variable of texture_actor
|
||||
* Texture_actor is not null because callback connection is set after the
|
||||
* texture_actor was being setted up */
|
||||
g_assert (texture_actor);
|
||||
g_type_set_qdata (G_TYPE_FROM_INSTANCE (buf), g_quark_from_string ("texture_actor"), texture_actor);
|
||||
|
||||
/* Here we are in the pipeline thread. It means that this thread may be
|
||||
* not the same as the clutter thread
|
||||
* make sure that the texture actor is updated in the clutter thread */
|
||||
clutter_threads_add_idle (update_texture_actor, buf);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
/* init clutter then gstreamer */
|
||||
|
||||
clutter_init (&argc, &argv);
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
/* init glew */
|
||||
|
||||
GLenum err = glewInit ();
|
||||
if (err != GLEW_OK)
|
||||
g_debug ("failed to init GLEW: %s", glewGetErrorString (err));
|
||||
|
||||
/* retrieve and turn off clutter opengl context */
|
||||
|
||||
#ifdef WIN32
|
||||
HGLRC clutter_gl_context = wglGetCurrentContext ();
|
||||
HDC clutter_dc = wglGetCurrentDC ();
|
||||
wglMakeCurrent (0, 0);
|
||||
#else
|
||||
Display *clutter_display = clutter_x11_get_default_display ();
|
||||
Window clutter_win = clutter_x11_get_stage_window (CLUTTER_STAGE (stage));
|
||||
GLXContext clutter_gl_context = glXGetCurrentContext ();
|
||||
glXMakeCurrent (clutter_display, None, 0);
|
||||
#endif
|
||||
|
||||
/* setup gstreamer pipeline */
|
||||
|
||||
GstPipeline *pipeline =
|
||||
GST_PIPELINE (gst_parse_launch
|
||||
("videotestsrc ! video/x-raw-rgb, bpp=32, depth=32, width=320, height=240, framerate=(fraction)30/1 ! "
|
||||
"glupload ! fakesink sync=1", NULL));
|
||||
|
||||
/* clutter_gl_context is an external OpenGL context with which gst-plugins-gl want to share textures */
|
||||
GstElement *glupload = gst_bin_get_by_name (GST_BIN (pipeline), "glupload0");
|
||||
g_object_set (G_OBJECT (glupload), "external-opengl-context", (guint64) GPOINTER_TO_UINT (clutter_gl_context), NULL);
|
||||
g_object_unref (glupload);
|
||||
|
||||
/* play pipeline */
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
|
||||
GstState state = GST_STATE_PLAYING;
|
||||
if (gst_element_get_state (GST_ELEMENT (pipeline), &state, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS)
|
||||
{
|
||||
g_debug ("failed to play pipeline\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* turn on back clutter opengl context */
|
||||
|
||||
#ifdef WIN32
|
||||
wglMakeCurrent (clutter_dc, clutter_gl_context);
|
||||
#else
|
||||
glXMakeCurrent (clutter_display, clutter_win, clutter_gl_context);
|
||||
#endif
|
||||
|
||||
/* clutter stage */
|
||||
|
||||
ClutterActor* stage = clutter_stage_get_default ();
|
||||
clutter_actor_set_size (stage, 640, 480);
|
||||
clutter_actor_set_position (stage, 0, 0);
|
||||
clutter_stage_set_title (CLUTTER_STAGE (stage), "clutter and gst-plugins-gl");
|
||||
ClutterActor *clutter_texture = setup_stage (CLUTTER_STAGE (stage));
|
||||
|
||||
/* set a callback to retrieve the gst gl textures */
|
||||
|
||||
GstElement *fakesink = gst_bin_get_by_name (GST_BIN (pipeline), "fakesink0");
|
||||
g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
|
||||
g_signal_connect (fakesink, "handoff", G_CALLBACK (on_gst_buffer), clutter_texture);
|
||||
g_object_unref (fakesink);
|
||||
|
||||
/* main loop */
|
||||
|
||||
clutter_main ();
|
||||
|
||||
/* deinit */
|
||||
|
||||
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
|
||||
g_object_unref (pipeline);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue