[112/906] git-svn-id: svn://svn.wobow.com/GStreamer_playground/gst-plugins-gl@552 93df14bb-0f41-7a43-8087-d3e2a2f0e464

This commit is contained in:
Julien Isorce 2008-06-28 15:38:41 +00:00 committed by Tim-Philipp Müller
parent edda6cc72d
commit 8807e62119
2 changed files with 318 additions and 107 deletions

View file

@ -28,6 +28,7 @@
static void gst_gl_display_finalize (GObject * object);
static gpointer gst_gl_display_glutThreadFunc (GstGLDisplay* display);
static void gst_gl_display_glutCreateWindow (GstGLDisplay* display);
static void gst_gl_display_glutInitUpload (GstGLDisplay* display);
static void gst_gl_display_glutGenerateOutputVideoFBO (GstGLDisplay *display);
static void gst_gl_display_glutGenerateFBO (GstGLDisplay *display);
static void gst_gl_display_glutUseFBO (GstGLDisplay *display);
@ -98,6 +99,7 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass)
{
display->mutex = g_mutex_new ();
display->texturePool = g_queue_new ();
display->cond_init_upload = g_cond_new ();
display->cond_make = g_cond_new ();
display->cond_fill = g_cond_new ();
display->cond_clear = g_cond_new ();
@ -117,6 +119,7 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass)
display->textureFBO = 0;
display->textureFBOWidth = 0;
display->textureFBOHeight = 0;
display->upload_video_format = 0;
display->requestedFBO = 0;
display->requestedDepthBuffer = 0;
@ -180,6 +183,8 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass)
display->clientDrawCallback = NULL;
display->title = g_string_new ("OpenGL renderer ");
display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL;
display->GLSLProgram_YUY2 = 0;
display->GLSLProgram_UYVY = 0;
display->GLSLProgram_I420_YV12 = 0;
@ -341,6 +346,10 @@ gst_gl_display_finalize (GObject *object)
g_mutex_free (display->mutex);
display->mutex = NULL;
}
if (display->cond_init_upload) {
g_cond_free (display->cond_init_upload);
display->cond_init_upload = NULL;
}
if (display->cond_make) {
g_cond_free (display->cond_make);
display->cond_make = NULL;
@ -437,9 +446,9 @@ gst_gl_display_glutThreadFunc (GstGLDisplay *display)
gst_gl_display_glutCreateWindow (display);
gst_gl_display_unlock (display);
g_print ("Glut mainLoop start\n");
g_print ("gl mainLoop started\n");
glutMainLoop ();
g_print ("Glut mainLoop exited\n");
g_print ("gl mainLoop exited\n");
return NULL;
}
@ -474,7 +483,10 @@ gst_gl_display_glutCreateWindow (GstGLDisplay *display)
//Init glew
err = glewInit();
if (err != GLEW_OK)
{
GST_DEBUG ("Error: %s", glewGetErrorString(err));
display->isAlive = FALSE;
}
else
{
//OpenGL > 2.1.0 and Glew > 1.5.0
@ -500,17 +512,43 @@ gst_gl_display_glutCreateWindow (GstGLDisplay *display)
if ((opengl_version_major < 1 && opengl_version_minor < 4) ||
(glew_version_major < 1 && glew_version_minor < 4) )
{
//turn off the pipeline, the old drivers are not yet supported
g_print ("Required OpenGL >= 1.4.0 and Glew >= 1.4.0\n");
g_assert_not_reached ();
display->isAlive = FALSE;
}
}
//setup callbacks
glutReshapeFunc (gst_gl_display_onReshape);
glutDisplayFunc (gst_gl_display_draw);
glutCloseFunc (gst_gl_display_onClose);
//insert glut context to the map
display->glutWinId = glutWinId;
g_hash_table_insert (gst_gl_display_map, GUINT_TO_POINTER (glutWinId), display);
//check glut id validity
g_assert (glutGetWindow() == glutWinId);
GST_DEBUG ("Context %d initialized", display->glutWinId);
//release display constructor
g_cond_signal (display->cond_create);
}
/* Called in the gl thread */
static void
gst_gl_display_glutInitUpload (GstGLDisplay *display)
{
glutSetWindow (display->glutWinId);
//Frame buffer object is a requirement for every cases
if (GLEW_EXT_framebuffer_object)
{
//a texture must be attached to the FBO
guint fake_texture = 0;
GST_DEBUG ("Context %d, EXT_framebuffer_object supported: yes", glutWinId);
g_print ("Context %d, EXT_framebuffer_object supported: yes\n", display->glutWinId);
//-- init intput frame buffer object (video -> GL)
@ -524,7 +562,7 @@ gst_gl_display_glutCreateWindow (GstGLDisplay *display)
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
display->textureFBOWidth, display->textureFBOHeight);
//setup a texture to render to
//a fake texture is attached to the upload FBO (cannot init without it)
glGenTextures (1, &fake_texture);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fake_texture);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
@ -547,56 +585,120 @@ gst_gl_display_glutCreateWindow (GstGLDisplay *display)
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glDeleteTextures (1, &fake_texture);
}
else
{
GST_DEBUG ("Context %d, EXT_framebuffer_object supported: no", glutWinId);
g_assert_not_reached ();
//turn off the pipeline because Frame buffer object is a requirement
g_print ("Context %d, EXT_framebuffer_object supported: no\n", display->glutWinId);
display->isAlive = FALSE;
}
//check if fragment program is available, then load them
if (GLEW_ARB_vertex_program)
switch (display->upload_video_format)
{
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_ARGB:
case GST_VIDEO_FORMAT_ABGR:
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_BGR:
//color space conversion is not needed
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_AYUV:
//color space conversion is needed
{
//check if fragment shader is available, then load them
if (GLEW_ARB_fragment_shader)
{
g_print ("Context %d, ARB_fragment_shader supported: yes\n", display->glutWinId);
display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL;
switch (display->upload_video_format)
{
case GST_VIDEO_FORMAT_YUY2:
{
gchar program[2048];
GST_DEBUG ("Context %d, ARB_fragment_program supported: yes", glutWinId);
//from video to texture
sprintf (program, display->textFProgram_YUY2_UYVY, 'r', 'g', 'a');
display->GLSLProgram_YUY2 = gst_gl_display_loadGLSLprogram (program);
}
break;
case GST_VIDEO_FORMAT_UYVY:
{
gchar program[2048];
sprintf (program, display->textFProgram_YUY2_UYVY, 'a', 'b', 'r');
display->GLSLProgram_UYVY = gst_gl_display_loadGLSLprogram (program);
}
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
display->GLSLProgram_I420_YV12 = gst_gl_display_loadGLSLprogram (display->textFProgram_I420_YV12);
break;
case GST_VIDEO_FORMAT_AYUV:
display->GLSLProgram_AYUV = gst_gl_display_loadGLSLprogram (display->textFProgram_AYUV);
break;
default:
g_assert_not_reached ();
}
}
//check if YCBCR MESA is available
else if (GLEW_MESA_ycbcr_texture)
{
//GLSL and Color Matrix are not available on your drivers, switch to YCBCR MESA
g_print ("Context %d, ARB_fragment_shader supported: no\n", display->glutWinId);
g_print ("Context %d, GLEW_ARB_imaging supported: no\n", display->glutWinId);
g_print ("Context %d, GLEW_MESA_ycbcr_texture supported: yes\n", display->glutWinId);
display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MESA;
switch (display->upload_video_format)
{
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_AYUV:
//turn off the pipeline because
//MESA only support YUY2 and UYVY
display->isAlive = FALSE;
break;
default:
g_assert_not_reached ();
}
}
//check if color matrix is available
else if (GLEW_ARB_imaging)
{
//GLSL is not available on your drivers, switch to Color Matrix
g_print ("Context %d, ARB_fragment_shader supported: no\n", display->glutWinId);
g_print ("Context %d, GLEW_ARB_imaging supported: yes\n", display->glutWinId);
display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MATRIX;
}
else
{
GST_DEBUG ("Context %d, ARB_fragment_program supported: no", glutWinId);
g_print ("Context %d, ARB_fragment_shader supported: no\n", display->glutWinId);
g_print ("Context %d, GLEW_ARB_imaging supported: no\n", display->glutWinId);
g_print ("Context %d, GLEW_MESA_ycbcr_texture supported: no\n", display->glutWinId);
//turn off the pipeline because colorspace conversion is not possible
display->isAlive = FALSE;
}
}
break;
default:
g_assert_not_reached ();
}
//setup callbacks
glutReshapeFunc (gst_gl_display_onReshape);
glutDisplayFunc (gst_gl_display_draw);
glutCloseFunc (gst_gl_display_onClose);
//insert glut context to the map
display->glutWinId = glutWinId;
g_hash_table_insert (gst_gl_display_map, GUINT_TO_POINTER (glutWinId), display);
//check glut id validity
g_assert (glutGetWindow() == glutWinId);
GST_DEBUG ("Context %d initialized", display->glutWinId);
//release display constructor
g_cond_signal (display->cond_create);
g_cond_signal (display->cond_init_upload);
}
@ -686,7 +788,7 @@ gst_gl_display_glutGenerateOutputVideoFBO (GstGLDisplay *display)
g_assert_not_reached ();
}
if (GLEW_ARB_vertex_program)
if (GLEW_ARB_fragment_shader)
{
gchar program[2048];
@ -1082,6 +1184,9 @@ gst_gl_display_glutDispatchAction (GstGLDisplayMsg* msg)
case GST_GL_DISPLAY_ACTION_RESHAPE:
gst_gl_display_glutReshapeWindow (msg->display);
break;
case GST_GL_DISPLAY_ACTION_INIT_UPLOAD:
gst_gl_display_glutInitUpload (msg->display);
break;
case GST_GL_DISPLAY_ACTION_PREPARE:
gst_gl_display_glutPrepareTexture (msg->display);
break;
@ -1140,6 +1245,7 @@ gst_gl_display_checkMsgValidity (GstGLDisplayMsg *msg)
case GST_GL_DISPLAY_ACTION_DESTROY:
case GST_GL_DISPLAY_ACTION_VISIBLE:
case GST_GL_DISPLAY_ACTION_RESHAPE:
case GST_GL_DISPLAY_ACTION_INIT_UPLOAD:
case GST_GL_DISPLAY_ACTION_PREPARE:
case GST_GL_DISPLAY_ACTION_CHANGE:
case GST_GL_DISPLAY_ACTION_CLEAR:
@ -1282,6 +1388,20 @@ gst_gl_display_resizeWindow (GstGLDisplay* display, gint width, gint height)
gst_gl_display_unlock (display);
}
/* Called by gst gl elements */
void
gst_gl_display_init_upload (GstGLDisplay* display, GstVideoFormat video_format,
guint gl_width, guint gl_height)
{
gst_gl_display_lock (display);
display->upload_video_format = video_format;
display->textureFBOWidth = gl_width;
display->textureFBOHeight = gl_height;
gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_INIT_UPLOAD, display);
g_cond_wait (display->cond_init_upload, display->mutex);
gst_gl_display_unlock (display);
}
/* Called by gstglbuffer */
void
@ -1505,6 +1625,10 @@ gst_gl_display_set_windowId (GstGLDisplay* display, gulong winId)
display->textureFBOWidth, display->textureFBOHeight,
winId,
TRUE);
//init colorspace conversion if needed
gst_gl_display_init_upload (display, display->upload_video_format,
display->textureFBOWidth, display->textureFBOHeight);
}
@ -1670,7 +1794,10 @@ void gst_gl_display_make_texture (GstGLDisplay* display)
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
switch (display->colorspace_conversion)
{
case GST_GL_DISPLAY_CONVERSION_GLSL:
case GST_GL_DISPLAY_CONVERSION_MATRIX:
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE_ALPHA,
width, height,
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
@ -1682,6 +1809,40 @@ void gst_gl_display_make_texture (GstGLDisplay* display)
width, height,
0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
break;
case GST_GL_DISPLAY_CONVERSION_MESA:
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA,
width, height,
0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, NULL);
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_FORMAT_UYVY:
switch (display->colorspace_conversion)
{
case GST_GL_DISPLAY_CONVERSION_GLSL:
case GST_GL_DISPLAY_CONVERSION_MATRIX:
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE_ALPHA,
width, height,
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
gst_gl_display_gen_texture (display, &display->currentTexture_u);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture_u);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
width, height,
0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
break;
case GST_GL_DISPLAY_CONVERSION_MESA:
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA,
width, height,
0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, NULL);
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
@ -1742,7 +1903,10 @@ gst_gl_display_fill_texture (GstGLDisplay * display)
GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, data);
break;
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:
switch (display->colorspace_conversion)
{
case GST_GL_DISPLAY_CONVERSION_GLSL:
case GST_GL_DISPLAY_CONVERSION_MATRIX:
glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
@ -1751,6 +1915,37 @@ gst_gl_display_fill_texture (GstGLDisplay * display)
GST_ROUND_UP_2 (width) / 2, height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
break;
case GST_GL_DISPLAY_CONVERSION_MESA:
glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, data);
display->currentVideo_format = GST_VIDEO_FORMAT_RGBx;
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_FORMAT_UYVY:
switch (display->colorspace_conversion)
{
case GST_GL_DISPLAY_CONVERSION_GLSL:
case GST_GL_DISPLAY_CONVERSION_MATRIX:
glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture_u);
glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0,
GST_ROUND_UP_2 (width) / 2, height,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
break;
case GST_GL_DISPLAY_CONVERSION_MESA:
glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, data);
display->currentVideo_format = GST_VIDEO_FORMAT_RGBx;
break;
default:
g_assert_not_reached ();
}
break;
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
{

View file

@ -41,12 +41,21 @@
typedef struct _GstGLDisplay GstGLDisplay;
typedef struct _GstGLDisplayClass GstGLDisplayClass;
//Color space conversion metthod
typedef enum {
GST_GL_DISPLAY_CONVERSION_GLSL, //ARB_fragment_shade
GST_GL_DISPLAY_CONVERSION_MATRIX, //ARB_imaging
GST_GL_DISPLAY_CONVERSION_MESA, //MESA_ycbcr_texture
} GstGLDisplayConversion;
//Message type
typedef enum {
GST_GL_DISPLAY_ACTION_CREATE,
GST_GL_DISPLAY_ACTION_DESTROY,
GST_GL_DISPLAY_ACTION_VISIBLE,
GST_GL_DISPLAY_ACTION_RESHAPE,
GST_GL_DISPLAY_ACTION_INIT_UPLOAD,
GST_GL_DISPLAY_ACTION_PREPARE,
GST_GL_DISPLAY_ACTION_CHANGE,
GST_GL_DISPLAY_ACTION_CLEAR,
@ -63,7 +72,7 @@ typedef enum {
} GstGLDisplayAction;
//Message to communicate with the glut thread
//Message to communicate with the gl thread
typedef struct _GstGLDisplayMsg {
GstGLDisplayAction action;
gint glutWinId;
@ -92,6 +101,7 @@ struct _GstGLDisplay {
GQueue* texturePool;
GCond* cond_init_upload;
GCond* cond_make;
GCond* cond_fill;
GCond* cond_clear;
@ -120,6 +130,7 @@ struct _GstGLDisplay {
GLuint textureFBO;
GLuint textureFBOWidth;
GLuint textureFBOHeight;
GstVideoFormat upload_video_format;
//filter frame buffer object (GL -> GL)
GLuint requestedFBO;
@ -179,6 +190,9 @@ struct _GstGLDisplay {
GLuint recordedTextureWidth;
GLuint recordedTextureHeight;
//colorspace conversion method
GstGLDisplayConversion colorspace_conversion;
//from video to texture
gchar* textFProgram_YUY2_UYVY;
@ -235,6 +249,8 @@ void gst_gl_display_setClientReshapeCallback (GstGLDisplay* display, CRCB cb);
void gst_gl_display_setClientDrawCallback (GstGLDisplay* display, CDCB cb);
void gst_gl_display_setVisibleWindow (GstGLDisplay* display, gboolean visible);
void gst_gl_display_resizeWindow (GstGLDisplay* display, gint width, gint height);
void gst_gl_display_init_upload (GstGLDisplay* display, GstVideoFormat video_format,
guint gl_width, guint gl_height);
void gst_gl_display_prepare_texture (GstGLDisplay* display, guint* pTexture);
void gst_gl_display_do_upload (GstGLDisplay* display, GstVideoFormat video_format,
gint video_width, gint video_height, gpointer data,