[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:
Julien Isorce 2009-04-18 13:57:44 +02:00 committed by Matthew Waters
parent b47fc234ef
commit 87a1652216
14 changed files with 287 additions and 50 deletions

View file

@ -158,6 +158,9 @@ gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass)
display->upload_data_height = 0; display->upload_data_height = 0;
display->upload_data = NULL; display->upload_data = NULL;
//foreign gl context
display->external_gl_context = 0;
//filter gen fbo //filter gen fbo
display->gen_fbo_width = 0; display->gen_fbo_width = 0;
display->gen_fbo_height = 0; display->gen_fbo_height = 0;
@ -527,7 +530,8 @@ gst_gl_display_thread_create_context (GstGLDisplay * display)
GLenum err = 0; GLenum err = 0;
display->gl_window = 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) { if (!display->gl_window) {
display->isAlive = FALSE; 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 */ * Called by the first gl element of a video/x-raw-gl flow */
void void
gst_gl_display_create_context (GstGLDisplay * display, gst_gl_display_create_context (GstGLDisplay * display,
GLint width, GLint height) GLint width, GLint height, guint64 external_gl_context)
{ {
gst_gl_display_lock (display); gst_gl_display_lock (display);
display->upload_width = width; display->upload_width = width;
display->upload_height = height; display->upload_height = height;
display->external_gl_context = external_gl_context;
display->gl_thread = g_thread_create ( display->gl_thread = g_thread_create (
(GThreadFunc) gst_gl_display_thread_create_context, display, TRUE, NULL); (GThreadFunc) gst_gl_display_thread_create_context, display, TRUE, NULL);

View file

@ -135,6 +135,9 @@ struct _GstGLDisplay
gint upload_data_height; gint upload_data_height;
gpointer upload_data; gpointer upload_data;
//foreign gl context
guint64 external_gl_context;
//filter gen fbo //filter gen fbo
GLuint gen_fbo_width; GLuint gen_fbo_width;
GLuint gen_fbo_height; GLuint gen_fbo_height;
@ -236,7 +239,7 @@ GType gst_gl_display_get_type (void);
GstGLDisplay *gst_gl_display_new (void); GstGLDisplay *gst_gl_display_new (void);
void gst_gl_display_create_context (GstGLDisplay * display, 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, gboolean gst_gl_display_redisplay (GstGLDisplay * display, GLuint texture,
gint width, gint height); gint width, gint height);

View file

@ -79,10 +79,9 @@ struct _GstGLWindowClass {
GQuark gst_gl_window_error_quark (void); GQuark gst_gl_window_error_quark (void);
GType gst_gl_window_get_type (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_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_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_resize_callback (GstGLWindow *window, GstGLWindowCB2 callback, gpointer data);
void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data); void gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data);

View file

@ -146,7 +146,7 @@ gst_gl_window_init (GstGLWindow * window)
/* Must be called in the gl thread */ /* Must be called in the gl thread */
GstGLWindow * 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); GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
GstGLWindowPrivate *priv = window->priv; 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"); 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 */ /* Must be called in the gl thread */
void void
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,

View file

@ -51,6 +51,7 @@ struct _GstGLWindowPrivate
HWND internal_win_id; HWND internal_win_id;
HDC device; HDC device;
HGLRC gl_context; HGLRC gl_context;
HGLRC external_gl_context;
GstGLWindowCB draw_cb; GstGLWindowCB draw_cb;
gpointer draw_data; gpointer draw_data;
GstGLWindowCB2 resize_cb; GstGLWindowCB2 resize_cb;
@ -143,7 +144,7 @@ gst_gl_window_init (GstGLWindow * window)
/* Must be called in the gl thread */ /* Must be called in the gl thread */
GstGLWindow * 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); GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
GstGLWindowPrivate *priv = window->priv; GstGLWindowPrivate *priv = window->priv;
@ -160,6 +161,7 @@ gst_gl_window_new (gint width, gint height)
priv->internal_win_id = 0; priv->internal_win_id = 0;
priv->device = 0; priv->device = 0;
priv->gl_context = 0; priv->gl_context = 0;
priv->external_gl_context = (HGLRC) external_gl_context;
priv->draw_cb = NULL; priv->draw_cb = NULL;
priv->draw_data = NULL; priv->draw_data = NULL;
priv->resize_cb = NULL; priv->resize_cb = NULL;
@ -226,12 +228,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
rect.bottom, FALSE); 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 */ /* Must be called in the gl thread */
void void
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, 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)) if (!wglMakeCurrent (priv->device, priv->gl_context))
g_debug ("failed to make opengl context current %d, %x\r\n", hWnd, g_debug ("failed to make opengl context current %d, %x\r\n", hWnd,
GetLastError ()); 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); SetProp (hWnd, "gl_window", window);

View file

@ -48,6 +48,7 @@ struct _GstGLWindowPrivate
EGLDisplay display; EGLDisplay display;
EGLSurface surface; EGLSurface surface;
EGLContext gl_context; EGLContext gl_context;
EGLContext external_gl_context;
GstGLWindowCB draw_cb; GstGLWindowCB draw_cb;
gpointer draw_data; gpointer draw_data;
GstGLWindowCB2 resize_cb; GstGLWindowCB2 resize_cb;
@ -140,7 +141,7 @@ gst_gl_window_init (GstGLWindow * window)
/* Must be called in the gl thread */ /* Must be called in the gl thread */
GstGLWindow * 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); GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
GstGLWindowPrivate *priv = window->priv; GstGLWindowPrivate *priv = window->priv;
@ -158,6 +159,7 @@ gst_gl_window_new (gint width, gint height)
priv->display = 0; priv->display = 0;
priv->surface = 0; priv->surface = 0;
priv->gl_context = 0; priv->gl_context = 0;
priv->external_gl_context = (EGLContext) external_gl_context;
priv->draw_cb = NULL; priv->draw_cb = NULL;
priv->draw_data = NULL; priv->draw_data = NULL;
priv->resize_cb = NULL; priv->resize_cb = NULL;
@ -224,12 +226,6 @@ gst_gl_window_set_external_window_id (GstGLWindow * window, guint64 id)
rect.bottom, FALSE); 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 */ /* Must be called in the gl thread */
void void
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, 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->surface, hWnd, EGLErrorString ());
priv->gl_context = priv->gl_context =
eglCreateContext (priv->display, config, EGL_NO_CONTEXT, eglCreateContext (priv->display, config, priv->external_gl_context,
contextAttribs); contextAttribs);
if (priv->gl_context != EGL_NO_CONTEXT) if (priv->gl_context != EGL_NO_CONTEXT)
g_debug ("gl context created: %d\n", priv->gl_context); g_debug ("gl context created: %d\n", priv->gl_context);

View file

@ -242,7 +242,7 @@ gst_gl_window_init (GstGLWindow * window)
/* Must be called in the gl thread */ /* Must be called in the gl thread */
GstGLWindow * 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); GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
GstGLWindowPrivate *priv = window->priv; 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); XSetWMProtocols (priv->device, priv->internal_win_id, wm_atoms, 2);
priv->gl_context = 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); 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 void
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
gpointer data) gpointer data)

View file

@ -247,7 +247,7 @@ gst_gl_window_init (GstGLWindow * window)
/* Must be called in the gl thread */ /* Must be called in the gl thread */
GstGLWindow * 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); GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
GstGLWindowPrivate *priv = window->priv; GstGLWindowPrivate *priv = window->priv;
@ -395,7 +395,7 @@ gst_gl_window_new (gint width, gint height)
(gulong) priv->gl_display, EGLErrorString ()); (gulong) priv->gl_display, EGLErrorString ());
priv->gl_context = priv->gl_context =
eglCreateContext (priv->gl_display, config, EGL_NO_CONTEXT, eglCreateContext (priv->gl_display, config, (EGLContext) external_gl_context,
context_attrib); context_attrib);
if (priv->gl_context != EGL_NO_CONTEXT) if (priv->gl_context != EGL_NO_CONTEXT)
g_debug ("gl context created: %ld\n", (gulong) priv->gl_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 void
gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback, gst_gl_window_set_draw_callback (GstGLWindow * window, GstGLWindowCB callback,
gpointer data) gpointer data)

View file

@ -395,7 +395,7 @@ gst_gl_colorscale_set_caps (GstBaseTransform * bt, GstCaps * incaps,
//init unvisible opengl context //init unvisible opengl context
gst_gl_display_create_context (colorscale->display, 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 //blocking call, init colorspace conversion if needed
gst_gl_display_init_upload (colorscale->display, gst_gl_display_init_upload (colorscale->display,

View file

@ -514,7 +514,7 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
//init opengl context //init opengl context
gst_gl_display_create_context (glimage_sink->display, 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) if (glimage_sink->window_id)
gst_gl_display_set_window_id (glimage_sink->display, gst_gl_display_set_window_id (glimage_sink->display,

View file

@ -364,7 +364,7 @@ gst_gl_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
gltestsrc->display = gst_gl_display_new (); gltestsrc->display = gst_gl_display_new ();
gst_gl_display_create_context (gltestsrc->display, 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, gst_gl_display_gen_fbo (gltestsrc->display, gltestsrc->width,
gltestsrc->height, &gltestsrc->fbo, &gltestsrc->depthbuffer); gltestsrc->height, &gltestsrc->fbo, &gltestsrc->depthbuffer);

View file

@ -123,7 +123,8 @@ static GstStaticPadTemplate gst_gl_upload_sink_pad_template =
/* Properties */ /* Properties */
enum enum
{ {
PROP_0 PROP_0,
PROP_EXTERNAL_OPENGL_CONTEXT
}; };
#define DEBUG_INIT(bla) \ #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)->get_unit_size = gst_gl_upload_get_unit_size;
GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer = GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer =
gst_gl_upload_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 static void
@ -198,9 +205,14 @@ static void
gst_gl_upload_set_property (GObject * object, guint prop_id, gst_gl_upload_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec) const GValue * value, GParamSpec * pspec)
{ {
//GstGLUpload* upload = GST_GL_UPLOAD (object); GstGLUpload *upload = GST_GL_UPLOAD (object);
switch (prop_id) { switch (prop_id) {
case PROP_EXTERNAL_OPENGL_CONTEXT:
{
upload->external_gl_context = g_value_get_uint64 (value);
break;
}
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -227,6 +239,7 @@ gst_gl_upload_reset (GstGLUpload * upload)
g_object_unref (upload->display); g_object_unref (upload->display);
upload->display = NULL; upload->display = NULL;
} }
upload->external_gl_context = 0;
} }
static gboolean static gboolean
@ -438,7 +451,8 @@ gst_gl_upload_set_caps (GstBaseTransform * bt, GstCaps * incaps,
//init unvisible opengl context //init unvisible opengl context
gst_gl_display_create_context (upload->display, 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 //init colorspace conversion if needed
gst_gl_display_init_upload (upload->display, upload->video_format, gst_gl_display_init_upload (upload->display, upload->video_format,

View file

@ -54,6 +54,7 @@ struct _GstGLUpload
gint video_height; gint video_height;
gint gl_width; gint gl_width;
gint gl_height; gint gl_height;
guint64 external_gl_context;
}; };
struct _GstGLUploadClass struct _GstGLUploadClass

View 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;
}