From: Matthew Waters Date: Sun, 16 Sep 2012 11:23:09 +0000 (+1000) Subject: [573/906] add upload and download library objects X-Git-Tag: 1.19.3~511^2~1989^2~1930 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3ee54d3135063c7a6247121e5995d62d02780732;p=platform%2Fupstream%2Fgstreamer.git [573/906] add upload and download library objects allows multiple upload pipelines that previously wasn't possible (i.e. upload RGB and I420 and ... on the same GstGLDisplay) --- diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index fbdb12a..e65234f 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -28,8 +28,11 @@ #include +#include #include #include "gstgldisplay.h" +#include "gstgldownload.h" +#include "gstglmemory.h" #ifndef GLEW_VERSION_MAJOR #define GLEW_VERSION_MAJOR 4 @@ -57,7 +60,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); G_DEFINE_TYPE_WITH_CODE (GstGLDisplay, gst_gl_display, G_TYPE_OBJECT, DEBUG_INIT); static void gst_gl_display_finalize (GObject * object); -void gst_gl_display_check_framebuffer_status (void); /* Called in the gl thread, protected by lock and unlock */ gpointer gst_gl_display_thread_create_context (GstGLDisplay * display); @@ -66,10 +68,6 @@ void gst_gl_display_thread_run_generic (GstGLDisplay * display); #ifdef OPENGL_ES2 void gst_gl_display_thread_init_redisplay (GstGLDisplay * display); #endif -void gst_gl_display_thread_init_upload (GstGLDisplay * display); -void gst_gl_display_thread_do_upload (GstGLDisplay * display); -void gst_gl_display_thread_init_download (GstGLDisplay * display); -void gst_gl_display_thread_do_download (GstGLDisplay * display); void gst_gl_display_thread_gen_fbo (GstGLDisplay * display); void gst_gl_display_thread_use_fbo (GstGLDisplay * display); void gst_gl_display_thread_use_fbo_v2 (GstGLDisplay * display); @@ -86,14 +84,6 @@ void gst_gl_display_on_close (GstGLDisplay * display); void gst_gl_display_del_texture_thread (GstGLDisplay * display, GLuint * pTexture); -/* To not make gst_gl_display_thread_do_upload - * and gst_gl_display_thread_do_download too big */ -void gst_gl_display_thread_init_upload_fbo (GstGLDisplay * display); -void gst_gl_display_thread_do_upload_make (GstGLDisplay * display); -void gst_gl_display_thread_do_upload_fill (GstGLDisplay * display); -void gst_gl_display_thread_do_upload_draw (GstGLDisplay * display); -void gst_gl_display_thread_do_download_draw_rgb (GstGLDisplay * display); -void gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display); void gst_gl_display_gen_texture_window_cb (GstGLDisplay * display); //------------------------------------------------------------ @@ -118,7 +108,6 @@ gst_gl_display_init (GstGLDisplay * display) display->gl_thread = NULL; display->gl_window = NULL; display->isAlive = TRUE; - display->texture_pool = g_hash_table_new (g_direct_hash, g_direct_equal); //conditions display->cond_create_context = g_cond_new (); @@ -146,20 +135,7 @@ gst_gl_display_init (GstGLDisplay * display) display->clientDrawCallback = NULL; display->client_data = NULL; - //upload - display->upload_fbo = 0; - display->upload_depth_buffer = 0; - display->upload_outtex = 0; - display->upload_intex = 0; - display->upload_intex_u = 0; - display->upload_intex_v = 0; - display->upload_width = 0; - display->upload_height = 0; - display->upload_video_format = GST_VIDEO_FORMAT_RGBx; - display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL; - display->upload_data_width = 0; - display->upload_data_height = 0; - display->upload_frame = NULL; + display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL; //foreign gl context display->external_gl_context = 0; @@ -192,225 +168,17 @@ gst_gl_display_init (GstGLDisplay * display) display->del_fbo = 0; display->del_depth_buffer = 0; - //download - display->download_fbo = 0; - display->download_depth_buffer = 0; - display->download_texture = 0; - display->download_texture_u = 0; - display->download_texture_v = 0; - display->download_width = 0; - display->download_height = 0; - display->download_video_format = 0; - display->download_frame = NULL; - display->ouput_texture = 0; - display->ouput_texture_width = 0; - display->ouput_texture_height = 0; - //action gen and del shader display->gen_shader_fragment_source = NULL; display->gen_shader_vertex_source = NULL; display->gen_shader = NULL; display->del_shader = NULL; - //fragment shader upload - display->shader_upload_YUY2 = NULL; - display->shader_upload_UYVY = NULL; - display->shader_upload_I420_YV12 = NULL; - display->shader_upload_AYUV = NULL; - -#ifdef OPENGL_ES2 - display->shader_upload_attr_position_loc = 0; - display->shader_upload_attr_texture_loc = 0; -#endif - - //fragment shader download - display->shader_download_YUY2 = NULL; - display->shader_download_UYVY = NULL; - display->shader_download_I420_YV12 = NULL; - display->shader_download_AYUV = NULL; - -#ifdef OPENGL_ES2 - display->shader_download_attr_position_loc = 0; - display->shader_download_attr_texture_loc = 0; - display->shader_download_RGB = NULL; -#endif - - //YUY2:r,g,a - //UYVY:a,b,r - display->text_shader_upload_YUY2_UYVY = -#ifndef OPENGL_ES2 - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect Ytex, UVtex;\n" -#else - "precision mediump float;\n" - "varying vec2 v_texCoord;\n" "uniform sampler2D Ytex, UVtex;\n" -#endif - "void main(void) {\n" " float fx, fy, y, u, v, r, g, b;\n" -#ifndef OPENGL_ES2 - " fx = gl_TexCoord[0].x;\n" - " fy = gl_TexCoord[0].y;\n" - " y = texture2DRect(Ytex,vec2(fx,fy)).%c;\n" - " u = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n" - " v = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n" -#else - " fx = v_texCoord.x;\n" - " fy = v_texCoord.y;\n" - " y = texture2D(Ytex,vec2(fx,fy)).%c;\n" - " u = texture2D(UVtex,vec2(fx*0.5,fy)).%c;\n" - " v = texture2D(UVtex,vec2(fx*0.5,fy)).%c;\n" -#endif - " y=1.164*(y-0.0627);\n" - " u=u-0.5;\n" - " v=v-0.5;\n" - " r = y+1.5958*v;\n" - " g = y-0.39173*u-0.81290*v;\n" - " b = y+2.017*u;\n" " gl_FragColor = vec4(r, g, b, 1.0);\n" "}\n"; - - //ATI: "*0.5", "" - //normal: "", "*0.5" - display->text_shader_upload_I420_YV12 = -#ifndef OPENGL_ES2 - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect Ytex,Utex,Vtex;\n" -#else - "precision mediump float;\n" - "varying vec2 v_texCoord;\n" "uniform sampler2D Ytex,Utex,Vtex;\n" -#endif - "void main(void) {\n" " float r,g,b,y,u,v;\n" -#ifndef OPENGL_ES2 - " vec2 nxy = gl_TexCoord[0].xy;\n" - " y=texture2DRect(Ytex,nxy%s).r;\n" - " u=texture2DRect(Utex,nxy%s).r;\n" - " v=texture2DRect(Vtex,nxy*0.5).r;\n" -#else - " vec2 nxy = v_texCoord.xy;\n" - " y=texture2D(Ytex,nxy).r;\n" - " u=texture2D(Utex,nxy).r;\n" " v=texture2D(Vtex,nxy).r;\n" -#endif - " y=1.1643*(y-0.0625);\n" - " u=u-0.5;\n" - " v=v-0.5;\n" - " r=y+1.5958*v;\n" - " g=y-0.39173*u-0.81290*v;\n" - " b=y+2.017*u;\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\n"; - - display->text_shader_upload_AYUV = -#ifndef OPENGL_ES2 - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect tex;\n" -#else - "precision mediump float;\n" - "varying vec2 v_texCoord;\n" "uniform sampler2D tex;\n" -#endif - "void main(void) {\n" " float r,g,b,y,u,v;\n" -#ifndef OPENGL_ES2 - " vec2 nxy=gl_TexCoord[0].xy;\n" - " y=texture2DRect(tex,nxy).r;\n" - " u=texture2DRect(tex,nxy).g;\n" " v=texture2DRect(tex,nxy).b;\n" -#else - " vec2 nxy = v_texCoord.xy;\n" - " y=texture2D(tex,nxy).g;\n" - " u=texture2D(tex,nxy).b;\n" " v=texture2D(tex,nxy).a;\n" -#endif - " y=1.1643*(y-0.0625);\n" - " u=u-0.5;\n" - " v=v-0.5;\n" - " r=y+1.5958*v;\n" - " g=y-0.39173*u-0.81290*v;\n" - " b=y+2.017*u;\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\n"; - - //YUY2:y2,u,y1,v - //UYVY:v,y1,u,y2 - display->text_shader_download_YUY2_UYVY = -#ifndef OPENGL_ES2 - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect tex;\n" -#else - "precision mediump float;\n" - "varying vec2 v_texCoord;\n" "uniform sampler2D tex;\n" -#endif - "void main(void) {\n" " float fx,fy,r,g,b,r2,g2,b2,y1,y2,u,v;\n" -#ifndef OPENGL_ES2 - " fx = gl_TexCoord[0].x;\n" - " fy = gl_TexCoord[0].y;\n" - " r=texture2DRect(tex,vec2(fx*2.0,fy)).r;\n" - " g=texture2DRect(tex,vec2(fx*2.0,fy)).g;\n" - " b=texture2DRect(tex,vec2(fx*2.0,fy)).b;\n" - " r2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).r;\n" - " g2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).g;\n" - " b2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).b;\n" -#else - " fx = v_texCoord.x;\n" - " fy = v_texCoord.y;\n" - " r=texture2D(tex,vec2(fx*2.0,fy)).r;\n" - " g=texture2D(tex,vec2(fx*2.0,fy)).g;\n" - " b=texture2D(tex,vec2(fx*2.0,fy)).b;\n" - " r2=texture2D(tex,vec2(fx*2.0+1.0,fy)).r;\n" - " g2=texture2D(tex,vec2(fx*2.0+1.0,fy)).g;\n" - " b2=texture2D(tex,vec2(fx*2.0+1.0,fy)).b;\n" -#endif - " y1=0.299011*r + 0.586987*g + 0.114001*b;\n" - " y2=0.299011*r2 + 0.586987*g2 + 0.114001*b2;\n" - " u=-0.148246*r -0.29102*g + 0.439266*b;\n" - " v=0.439271*r - 0.367833*g - 0.071438*b ;\n" - " y1=0.858885*y1 + 0.0625;\n" - " y2=0.858885*y2 + 0.0625;\n" - " u=u + 0.5;\n" " v=v + 0.5;\n" " gl_FragColor=vec4(%s);\n" "}\n"; - - //no OpenGL ES 2.0 support because for now it's not possible - //to attach multiple textures to a frame buffer object - display->text_shader_download_I420_YV12 = - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect tex;\n" - "uniform float w, h;\n" - "void main(void) {\n" - " float r,g,b,r2,b2,g2,y,u,v;\n" - " vec2 nxy=gl_TexCoord[0].xy;\n" - " vec2 nxy2=nxy*2.0;\n" - " r=texture2DRect(tex,nxy).r;\n" - " g=texture2DRect(tex,nxy).g;\n" - " b=texture2DRect(tex,nxy).b;\n" - " r2=texture2DRect(tex,nxy2).r;\n" - " g2=texture2DRect(tex,nxy2).g;\n" - " b2=texture2DRect(tex,nxy2).b;\n" - " y=0.299011*r + 0.586987*g + 0.114001*b;\n" - " u=-0.148246*r2 -0.29102*g2 + 0.439266*b2;\n" - " v=0.439271*r2 - 0.367833*g2 - 0.071438*b2 ;\n" - " y=0.858885*y + 0.0625;\n" - " u=u + 0.5;\n" - " v=v + 0.5;\n" - " gl_FragData[0] = vec4(y, 0.0, 0.0, 1.0);\n" - " gl_FragData[1] = vec4(u, 0.0, 0.0, 1.0);\n" - " gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n" "}\n"; - - display->text_shader_download_AYUV = -#ifndef OPENGL_ES2 - "#extension GL_ARB_texture_rectangle : enable\n" - "uniform sampler2DRect tex;\n" -#else - "precision mediump float;\n" - "varying vec2 v_texCoord;\n" "uniform sampler2D tex;\n" -#endif - "void main(void) {\n" " float r,g,b,y,u,v;\n" -#ifndef OPENGL_ES2 - " vec2 nxy=gl_TexCoord[0].xy;\n" - " r=texture2DRect(tex,nxy).r;\n" - " g=texture2DRect(tex,nxy).g;\n" " b=texture2DRect(tex,nxy).b;\n" -#else - " vec2 nxy=v_texCoord.xy;\n" - " r=texture2D(tex,nxy).r;\n" - " g=texture2D(tex,nxy).g;\n" " b=texture2D(tex,nxy).b;\n" -#endif - " y=0.299011*r + 0.586987*g + 0.114001*b;\n" - " u=-0.148246*r -0.29102*g + 0.439266*b;\n" - " v=0.439271*r - 0.367833*g - 0.071438*b ;\n" - " y=0.858885*y + 0.0625;\n" " u=u + 0.5;\n" " v=v + 0.5;\n" -#ifndef OPENGL_ES2 - " gl_FragColor=vec4(y,u,v,1.0);\n" -#else - " gl_FragColor=vec4(1.0,y,u,v);\n" -#endif - "}\n"; + display->uploads = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, + g_object_unref); + display->downloads = + g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, + g_object_unref); #ifdef OPENGL_ES2 display->redisplay_vertex_shader_str = @@ -430,36 +198,11 @@ gst_gl_display_init (GstGLDisplay * display) "{ \n" " gl_FragColor = texture2D( s_texture, v_texCoord );\n" "} \n"; - - display->text_vertex_shader_upload = - "attribute vec4 a_position; \n" - "attribute vec2 a_texCoord; \n" - "varying vec2 v_texCoord; \n" - "void main() \n" - "{ \n" - " gl_Position = a_position; \n" - " v_texCoord = a_texCoord; \n" "} \n"; - - display->text_vertex_shader_download = - "attribute vec4 a_position; \n" - "attribute vec2 a_texCoord; \n" - "varying vec2 v_texCoord; \n" - "void main() \n" - "{ \n" - " gl_Position = a_position; \n" - " v_texCoord = a_texCoord; \n" "} \n"; - - display->text_fragment_shader_download_RGB = - "precision mediump float; \n" - "varying vec2 v_texCoord; \n" - "uniform sampler2D s_texture; \n" - "void main() \n" - "{ \n" - " gl_FragColor = texture2D( s_texture, v_texCoord );\n" - "} \n"; #endif display->error_message = NULL; + + gst_gl_memory_init (); } static void @@ -494,14 +237,6 @@ gst_gl_display_finalize (GObject * object) GST_ERROR ("gl thread returned a not null pointer"); display->gl_thread = NULL; } - - if (display->texture_pool) { - //texture pool is empty after destroying the gl context - if (g_hash_table_size (display->texture_pool) != 0) - GST_ERROR ("texture pool is not empty"); - g_hash_table_unref (display->texture_pool); - display->texture_pool = NULL; - } if (display->mutex) { g_mutex_free (display->mutex); display->mutex = NULL; @@ -531,6 +266,14 @@ gst_gl_display_finalize (GObject * object) g_free (display->error_message); display->error_message = NULL; } + if (display->uploads) { + g_hash_table_destroy (display->uploads); + display->uploads = NULL; + } + if (display->downloads) { + g_hash_table_destroy (display->downloads); + display->downloads = NULL; + } } @@ -679,99 +422,6 @@ gst_gl_display_thread_create_context (GstGLDisplay * display) void gst_gl_display_thread_destroy_context (GstGLDisplay * display) { - //colorspace_conversion specific - switch (display->upload_colorspace_conversion) { - case GST_GL_DISPLAY_CONVERSION_MESA: - case GST_GL_DISPLAY_CONVERSION_MATRIX: - break; - case GST_GL_DISPLAY_CONVERSION_GLSL: - { - glUseProgramObjectARB (0); - if (display->shader_upload_YUY2) { - g_object_unref (G_OBJECT (display->shader_upload_YUY2)); - display->shader_upload_YUY2 = NULL; - } - if (display->shader_upload_UYVY) { - g_object_unref (G_OBJECT (display->shader_upload_UYVY)); - display->shader_upload_UYVY = NULL; - } - if (display->shader_upload_I420_YV12) { - g_object_unref (G_OBJECT (display->shader_upload_I420_YV12)); - display->shader_upload_I420_YV12 = NULL; - } - if (display->shader_upload_AYUV) { - g_object_unref (G_OBJECT (display->shader_upload_AYUV)); - display->shader_upload_AYUV = NULL; - } - if (display->shader_download_YUY2) { - g_object_unref (G_OBJECT (display->shader_download_YUY2)); - display->shader_download_YUY2 = NULL; - } - if (display->shader_download_UYVY) { - g_object_unref (G_OBJECT (display->shader_download_UYVY)); - display->shader_download_UYVY = NULL; - } - if (display->shader_download_I420_YV12) { - g_object_unref (G_OBJECT (display->shader_download_I420_YV12)); - display->shader_download_I420_YV12 = NULL; - } - if (display->shader_download_AYUV) { - g_object_unref (G_OBJECT (display->shader_download_AYUV)); - display->shader_download_AYUV = NULL; - } -#ifdef OPENGL_ES2 - if (display->shader_download_RGB) { - g_object_unref (G_OBJECT (display->shader_download_RGB)); - display->shader_download_RGB = NULL; - } -#endif - } - break; - default: - GST_ERROR ("Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - - if (display->upload_fbo) { - glDeleteFramebuffersEXT (1, &display->upload_fbo); - display->upload_fbo = 0; - } - if (display->upload_depth_buffer) { - glDeleteRenderbuffersEXT (1, &display->upload_depth_buffer); - display->upload_depth_buffer = 0; - } - if (display->download_fbo) { - glDeleteFramebuffersEXT (1, &display->download_fbo); - display->download_fbo = 0; - } - if (display->download_depth_buffer) { - glDeleteRenderbuffersEXT (1, &display->download_depth_buffer); - display->download_depth_buffer = 0; - } - if (display->download_texture) { - glDeleteTextures (1, &display->download_texture); - display->download_texture = 0; - } - if (display->download_texture_u) { - glDeleteTextures (1, &display->download_texture_u); - display->download_texture_u = 0; - } - if (display->download_texture_v) { - glDeleteTextures (1, &display->download_texture_v); - display->download_texture_v = 0; - } - if (display->upload_intex != 0) { - glDeleteTextures (1, &display->upload_intex); - display->upload_intex = 0; - } - if (display->upload_intex_u != 0) { - glDeleteTextures (1, &display->upload_intex_u); - display->upload_intex_u = 0; - } - if (display->upload_intex_v != 0) { - glDeleteTextures (1, &display->upload_intex_v); - display->upload_intex_v = 0; - } #ifdef OPENGL_ES2 if (display->redisplay_shader) { g_object_unref (G_OBJECT (display->redisplay_shader)); @@ -779,12 +429,6 @@ gst_gl_display_thread_destroy_context (GstGLDisplay * display) } #endif -/* GST_INFO ("Cleaning texture pool"); - - //clean up the texture pool - g_hash_table_foreach_remove (display->texture_pool, - gst_gl_display_texture_pool_func_clean, NULL);*/ - GST_INFO ("Context destroyed"); } @@ -828,866 +472,99 @@ gst_gl_display_thread_init_redisplay (GstGLDisplay * display) } #endif - /* Called in the gl thread */ void -gst_gl_display_thread_init_upload (GstGLDisplay * display) +gst_gl_display_thread_gen_fbo (GstGLDisplay * display) { - GST_TRACE ("initializing upload for format:%i", display->upload_video_format); - - 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 - //but if the size is different we need to redraw it - //using fbo - if (display->upload_width != display->upload_data_width || - display->upload_height != display->upload_data_height) - gst_gl_display_thread_init_upload_fbo (display); - 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 - /* shouldn't we require ARB_shading_language_100? --Filippo */ - if (GLEW_ARB_fragment_shader) { - -#ifdef OPENGL_ES2 - GError *error = NULL; -#endif - - GST_INFO ("Context, ARB_fragment_shader supported: yes"); + //a texture must be attached to the FBO + GLuint fake_texture = 0; - display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL; + GST_TRACE ("creating FBO dimensions:%ux%u", display->gen_fbo_width, + display->gen_fbo_height); - gst_gl_display_thread_init_upload_fbo (display); - if (!display->isAlive) - break; + //-- generate frame buffer object - switch (display->upload_video_format) { - case GST_VIDEO_FORMAT_YUY2: - { - gchar text_shader_upload_YUY2[2048]; - sprintf (text_shader_upload_YUY2, - display->text_shader_upload_YUY2_UYVY, 'r', 'g', 'a'); + if (!GLEW_EXT_framebuffer_object) { + //turn off the pipeline because Frame buffer object is a not present + gst_gl_display_set_error (display, + "Context, EXT_framebuffer_object not supported"); + return; + } + //setup FBO + glGenFramebuffersEXT (1, &display->generated_fbo); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->generated_fbo); - display->shader_upload_YUY2 = gst_gl_shader_new (); -#ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check (display->shader_upload_YUY2, - text_shader_upload_YUY2, GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for uploading YUY2"); - g_object_unref (G_OBJECT (display->shader_upload_YUY2)); - display->shader_upload_YUY2 = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_upload_YUY2, - display->text_vertex_shader_upload); - gst_gl_shader_set_fragment_source (display->shader_upload_YUY2, - text_shader_upload_YUY2); - - gst_gl_shader_compile (display->shader_upload_YUY2, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_upload_YUY2)); - display->shader_upload_YUY2 = NULL; - } else { - display->shader_upload_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_YUY2, "a_position"); - display->shader_upload_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_YUY2, "a_texCoord"); - } -#endif - } - break; - case GST_VIDEO_FORMAT_UYVY: - { - gchar text_shader_upload_UYVY[2048]; - sprintf (text_shader_upload_UYVY, + //setup the render buffer for depth + glGenRenderbuffersEXT (1, &display->generated_depth_buffer); + glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, display->generated_depth_buffer); #ifndef OPENGL_ES2 - display->text_shader_upload_YUY2_UYVY, 'a', 'b', 'r'); + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, + display->gen_fbo_width, display->gen_fbo_height); + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, + display->gen_fbo_width, display->gen_fbo_height); #else - display->text_shader_upload_YUY2_UYVY, 'a', 'r', 'b'); + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, + display->gen_fbo_width, display->gen_fbo_height); #endif - display->shader_upload_UYVY = gst_gl_shader_new (); + //setup a texture to render to + glGenTextures (1, &fake_texture); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fake_texture); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, + display->gen_fbo_width, display->gen_fbo_height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, NULL); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); -#ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check (display->shader_upload_UYVY, - text_shader_upload_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for uploading UYVY"); - g_object_unref (G_OBJECT (display->shader_upload_UYVY)); - display->shader_upload_UYVY = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_upload_UYVY, - display->text_vertex_shader_upload); - gst_gl_shader_set_fragment_source (display->shader_upload_UYVY, - text_shader_upload_UYVY); - - gst_gl_shader_compile (display->shader_upload_UYVY, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_upload_UYVY)); - display->shader_upload_UYVY = NULL; - } else { - display->shader_upload_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_UYVY, "a_position"); - display->shader_upload_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_UYVY, "a_texCoord"); - } -#endif - } - break; - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - { -#ifndef OPENGL_ES2 - gchar text_shader_upload_I420_YV12[2048]; - if ((g_ascii_strncasecmp ("ATI", (gchar *) glGetString (GL_VENDOR), - 3) == 0) - && (g_ascii_strncasecmp ("ATI Mobility Radeon HD", - (gchar *) glGetString (GL_RENDERER), 22) != 0) - && (g_ascii_strncasecmp ("ATI Radeon HD", - (gchar *) glGetString (GL_RENDERER), 13) != 0)) - sprintf (text_shader_upload_I420_YV12, - display->text_shader_upload_I420_YV12, "*0.5", ""); - else - sprintf (text_shader_upload_I420_YV12, - display->text_shader_upload_I420_YV12, "", "*0.5"); -#endif + //attach the texture to the FBO to renderer to + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, fake_texture, 0); - display->shader_upload_I420_YV12 = gst_gl_shader_new (); + //attach the depth render buffer to the FBO + glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, display->generated_depth_buffer); #ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check - (display->shader_upload_I420_YV12, text_shader_upload_I420_YV12, - GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for uploading I420 or YV12"); - g_object_unref (G_OBJECT (display->shader_upload_I420_YV12)); - display->shader_upload_I420_YV12 = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_upload_I420_YV12, - display->text_vertex_shader_upload); - gst_gl_shader_set_fragment_source (display->shader_upload_I420_YV12, - display->text_shader_upload_I420_YV12); - - gst_gl_shader_compile (display->shader_upload_I420_YV12, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_upload_I420_YV12)); - display->shader_upload_I420_YV12 = NULL; - } else { - display->shader_upload_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_I420_YV12, "a_position"); - display->shader_upload_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_I420_YV12, "a_texCoord"); - } + glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, display->generated_depth_buffer); #endif - } - break; - case GST_VIDEO_FORMAT_AYUV: - { - display->shader_upload_AYUV = gst_gl_shader_new (); -#ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check (display->shader_upload_AYUV, - display->text_shader_upload_AYUV, - GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for uploading AYUV"); - g_object_unref (G_OBJECT (display->shader_upload_AYUV)); - display->shader_upload_AYUV = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_upload_AYUV, - display->text_vertex_shader_upload); - gst_gl_shader_set_fragment_source (display->shader_upload_AYUV, - display->text_shader_upload_AYUV); - - gst_gl_shader_compile (display->shader_upload_AYUV, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_upload_AYUV)); - display->shader_upload_AYUV = NULL; - } else { - display->shader_upload_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_AYUV, "a_position"); - display->shader_upload_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_upload_AYUV, "a_texCoord"); - } -#endif - } - break; - default: - gst_gl_display_set_error (display, - "Unsupported upload video format %d", - display->upload_video_format); - } - } - //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 - GST_INFO ("Context, ARB_fragment_shader supported: no"); - GST_INFO ("Context, GLEW_MESA_ycbcr_texture supported: yes"); - - display->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MESA; - - switch (display->upload_video_format) { - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - //color space conversion is not needed - //but if the size is different we need to redraw it - //using fbo - if (display->upload_width != display->upload_data_width || - display->upload_height != display->upload_data_height) - gst_gl_display_thread_init_upload_fbo (display); - 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 - gst_gl_display_set_error (display, - "Your MESA version only supports YUY2 and UYVY (GLSL is required for others yuv formats)"); - break; - default: - gst_gl_display_set_error (display, - "Unsupported upload video format %d", - display->upload_video_format); - } - } - //check if color matrix is available - else if (GLEW_ARB_imaging) { - //GLSL is not available on your drivers, switch to Color Matrix - GST_INFO ("Context, ARB_fragment_shader supported: no"); - GST_INFO ("Context, GLEW_MESA_ycbcr_texture supported: no"); - GST_INFO ("Context, GLEW_ARB_imaging supported: yes"); + if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != + GL_FRAMEBUFFER_COMPLETE_EXT) + gst_gl_display_set_error (display, "GL framebuffer status incomplete"); - display->upload_colorspace_conversion = - GST_GL_DISPLAY_CONVERSION_MATRIX; + //unbind the FBO + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); - //turn off the pipeline because we do not support it yet - gst_gl_display_set_error (display, - "Colorspace conversion using Color Matrix is not yet supported"); - } else { - //turn off the pipeline because colorspace conversion is not possible - gst_gl_display_set_error (display, - "ARB_fragment_shader supported, GLEW_ARB_imaging supported, GLEW_MESA_ycbcr_texture supported, not supported"); - } - } - break; - default: - gst_gl_display_set_error (display, "Unsupported upload video format %d", - display->upload_video_format); - } + glDeleteTextures (1, &fake_texture); } -/* Called by the idle function */ +/* Called in the gl thread */ void -gst_gl_display_thread_do_upload (GstGLDisplay * display) +gst_gl_display_thread_use_fbo (GstGLDisplay * display) { - GST_TRACE ("uploading video frame %" GST_PTR_FORMAT " with dimensions: %ix%i", - display->upload_frame, display->upload_data_width, - display->upload_data_height); +#ifdef OPENGL_ES2 + GLint viewport_dim[4]; +#endif - gst_gl_display_thread_do_upload_fill (display); + GST_TRACE ("Binding v1 FBO %u dimensions:%ux%u with texture:%u " + "dimensions:%ux%u", display->use_fbo, display->use_fbo_width, + display->use_fbo_height, display->use_fbo_texture, + display->input_texture_width, display->input_texture_height); - 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 - //but if the size is different we need to redraw it - //using fbo - if (display->upload_width != display->upload_data_width || - display->upload_height != display->upload_data_height) - gst_gl_display_thread_do_upload_draw (display); - 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: - { - switch (display->upload_colorspace_conversion) { - case GST_GL_DISPLAY_CONVERSION_GLSL: - //color space conversion is needed - gst_gl_display_thread_do_upload_draw (display); - break; - case GST_GL_DISPLAY_CONVERSION_MATRIX: - //color space conversion is needed - //not yet supported - break; - case GST_GL_DISPLAY_CONVERSION_MESA: - //color space conversion is not needed - //but if the size is different we need to redraw it - //using fbo - if (display->upload_width != display->upload_data_width || - display->upload_height != display->upload_data_height) - gst_gl_display_thread_do_upload_draw (display); - break; - default: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - } - break; - default: - gst_gl_display_set_error (display, "Unsupported upload video format %d", - display->upload_video_format); - } -} + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->use_fbo); + //setup a texture to render to + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->use_fbo_texture); -/* Called in the gl thread */ -void -gst_gl_display_thread_init_download (GstGLDisplay * display) -{ - GST_TRACE ("initializing download for format %i", - display->download_video_format); - - switch (display->download_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 - { - - if (GLEW_EXT_framebuffer_object) { - GST_INFO ("Context, EXT_framebuffer_object supported: yes"); - - //-- init output frame buffer object (GL -> video) - - //setup FBO - glGenFramebuffersEXT (1, &display->download_fbo); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->download_fbo); - - //setup the render buffer for depth - glGenRenderbuffersEXT (1, &display->download_depth_buffer); - glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, - display->download_depth_buffer); -#ifndef OPENGL_ES2 - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, - display->download_width, display->download_height); - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, - display->download_width, display->download_height); -#else - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, - display->download_width, display->download_height); -#endif - - //setup a first texture to render to - glGenTextures (1, &display->download_texture); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->download_texture); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - display->download_width, display->download_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - //attach the first texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, display->download_texture, 0); - - switch (display->download_video_format) { - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - case GST_VIDEO_FORMAT_AYUV: - //only one attached texture is needed - break; - - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - //setup a second texture to render to - glGenTextures (1, &display->download_texture_u); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, - display->download_texture_u); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - display->download_width, display->download_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - //attach the second texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, - display->download_texture_u, 0); - - //setup a third texture to render to - glGenTextures (1, &display->download_texture_v); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, - display->download_texture_v); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - display->download_width, display->download_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - //attach the third texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_RECTANGLE_ARB, - display->download_texture_v, 0); - - display->multipleRT[0] = GL_COLOR_ATTACHMENT0_EXT; - display->multipleRT[1] = GL_COLOR_ATTACHMENT1_EXT; - display->multipleRT[2] = GL_COLOR_ATTACHMENT2_EXT; - break; - default: - gst_gl_display_set_error (display, - "Unsupported download video format %d", - display->download_video_format); - } - - //attach the depth render buffer to the FBO - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, - GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, - display->download_depth_buffer); - -#ifndef OPENGL_ES2 - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, - GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, - display->download_depth_buffer); -#endif - - gst_gl_display_check_framebuffer_status (); - - if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != - GL_FRAMEBUFFER_COMPLETE_EXT) - gst_gl_display_set_error (display, - "GL framebuffer status incomplete"); - - //unbind the FBO - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); - } else { - //turn off the pipeline because Frame buffer object is a requirement when using filters - //or when using GLSL colorspace conversion - gst_gl_display_set_error (display, - "Context, EXT_framebuffer_object supported: no"); - } - } - break; - default: - gst_gl_display_set_error (display, "Unsupported download video format %d", - display->download_video_format); - } - - switch (display->download_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 -#ifdef OPENGL_ES2 - { - //glGetTexImage2D no available in OpenGL ES 2.0 - GError *error = NULL; - display->shader_download_RGB = gst_gl_shader_new (); - - gst_gl_shader_set_vertex_source (display->shader_download_RGB, - display->text_vertex_shader_download); - gst_gl_shader_set_fragment_source (display->shader_download_RGB, - display->text_fragment_shader_download_RGB); - - gst_gl_shader_compile (display->shader_download_RGB, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_download_RGB)); - display->shader_download_RGB = NULL; - } else { - display->shader_download_attr_position_loc = - gst_gl_shader_get_attribute_location (display->shader_download_RGB, - "a_position"); - display->shader_download_attr_texture_loc = - gst_gl_shader_get_attribute_location (display->shader_download_RGB, - "a_texCoord"); - } - } -#endif - 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 - //GLSL is a requirement for donwload - if (GLEW_ARB_fragment_shader) { - -#ifdef OPENGL_ES2 - GError *error = NULL; -#endif - - switch (display->download_video_format) { - case GST_VIDEO_FORMAT_YUY2: - { - gchar text_shader_download_YUY2[2048]; - sprintf (text_shader_download_YUY2, - display->text_shader_download_YUY2_UYVY, "y2,u,y1,v"); - - display->shader_download_YUY2 = gst_gl_shader_new (); -#ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check (display->shader_download_YUY2, - text_shader_download_YUY2, GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for downloading YUY2"); - g_object_unref (G_OBJECT (display->shader_download_YUY2)); - display->shader_download_YUY2 = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_download_YUY2, - display->text_vertex_shader_download); - gst_gl_shader_set_fragment_source (display->shader_download_YUY2, - text_shader_download_YUY2); - - gst_gl_shader_compile (display->shader_download_YUY2, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_download_YUY2)); - display->shader_download_YUY2 = NULL; - } else { - display->shader_download_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_download_YUY2, "a_position"); - display->shader_download_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_download_YUY2, "a_texCoord"); - } -#endif - } - break; - case GST_VIDEO_FORMAT_UYVY: - { - gchar text_shader_download_UYVY[2048]; - sprintf (text_shader_download_UYVY, - display->text_shader_download_YUY2_UYVY, "v,y1,u,y2"); - - display->shader_download_UYVY = gst_gl_shader_new (); - -#ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check (display->shader_download_UYVY, - text_shader_download_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for downloading UYVY"); - g_object_unref (G_OBJECT (display->shader_download_UYVY)); - display->shader_download_UYVY = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_download_UYVY, - display->text_vertex_shader_download); - gst_gl_shader_set_fragment_source (display->shader_download_UYVY, - text_shader_download_UYVY); - - gst_gl_shader_compile (display->shader_download_UYVY, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_download_UYVY)); - display->shader_download_UYVY = NULL; - } else { - display->shader_download_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_download_UYVY, "a_position"); - display->shader_download_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_download_UYVY, "a_texCoord"); - } -#endif - - } - break; - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - display->shader_download_I420_YV12 = gst_gl_shader_new (); - if (!gst_gl_shader_compile_and_check - (display->shader_download_I420_YV12, - display->text_shader_download_I420_YV12, - GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for downloading I420 or YV12"); - g_object_unref (G_OBJECT (display->shader_download_I420_YV12)); - display->shader_download_I420_YV12 = NULL; - } - break; - case GST_VIDEO_FORMAT_AYUV: - display->shader_download_AYUV = gst_gl_shader_new (); - -#ifndef OPENGL_ES2 - if (!gst_gl_shader_compile_and_check (display->shader_download_AYUV, - display->text_shader_download_AYUV, - GST_GL_SHADER_FRAGMENT_SOURCE)) { - gst_gl_display_set_error (display, - "Failed to initialize shader for downloading AYUV"); - g_object_unref (G_OBJECT (display->shader_download_AYUV)); - display->shader_download_AYUV = NULL; - } -#else - gst_gl_shader_set_vertex_source (display->shader_download_AYUV, - display->text_vertex_shader_download); - gst_gl_shader_set_fragment_source (display->shader_download_AYUV, - display->text_shader_download_AYUV); - - gst_gl_shader_compile (display->shader_download_AYUV, &error); - if (error) { - gst_gl_display_set_error (display, "%s", error->message); - g_error_free (error); - error = NULL; - gst_gl_shader_use (NULL); - g_object_unref (G_OBJECT (display->shader_download_AYUV)); - display->shader_download_AYUV = NULL; - } else { - display->shader_download_attr_position_loc = - gst_gl_shader_get_attribute_location - (display->shader_download_AYUV, "a_position"); - display->shader_download_attr_texture_loc = - gst_gl_shader_get_attribute_location - (display->shader_download_AYUV, "a_texCoord"); - } -#endif - break; - default: - gst_gl_display_set_error (display, - "Unsupported download video format %d", - display->download_video_format); - } - } else { - //turn off the pipeline because colorspace conversion is not possible - gst_gl_display_set_error (display, - "Context, ARB_fragment_shader supported: no"); - } - } - break; - default: - gst_gl_display_set_error (display, "Unsupported download video format %d", - display->download_video_format); - } -} - - -/* Called in the gl thread */ -void -gst_gl_display_thread_do_download (GstGLDisplay * display) -{ - GstVideoFormat video_format = - GST_VIDEO_INFO_FORMAT (&display->download_frame->info); - - GST_TRACE ("downloading image format:%i, dimensions:%ux%u", video_format, - GST_VIDEO_INFO_WIDTH (&display->download_frame->info), - GST_VIDEO_INFO_HEIGHT (&display->download_frame->info)); - - switch (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 - gst_gl_display_thread_do_download_draw_rgb (display); - 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 - gst_gl_display_thread_do_download_draw_yuv (display); - break; - default: - gst_gl_display_set_error (display, "Unsupported download video format %d", - video_format); - } -} - - -/* Called in the gl thread */ -void -gst_gl_display_thread_gen_fbo (GstGLDisplay * display) -{ - //a texture must be attached to the FBO - GLuint fake_texture = 0; - - GST_TRACE ("creating FBO dimensions:%ux%u", display->gen_fbo_width, - display->gen_fbo_height); - - //-- generate frame buffer object - - if (!GLEW_EXT_framebuffer_object) { - //turn off the pipeline because Frame buffer object is a not present - gst_gl_display_set_error (display, - "Context, EXT_framebuffer_object not supported"); - return; - } - //setup FBO - glGenFramebuffersEXT (1, &display->generated_fbo); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->generated_fbo); - - //setup the render buffer for depth - glGenRenderbuffersEXT (1, &display->generated_depth_buffer); - glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, display->generated_depth_buffer); -#ifndef OPENGL_ES2 - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, - display->gen_fbo_width, display->gen_fbo_height); - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, - display->gen_fbo_width, display->gen_fbo_height); -#else - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, - display->gen_fbo_width, display->gen_fbo_height); -#endif - - //setup a texture to render to - glGenTextures (1, &fake_texture); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, fake_texture); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - display->gen_fbo_width, display->gen_fbo_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - //attach the texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, fake_texture, 0); - - //attach the depth render buffer to the FBO - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, display->generated_depth_buffer); - -#ifndef OPENGL_ES2 - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, display->generated_depth_buffer); -#endif - - if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != - GL_FRAMEBUFFER_COMPLETE_EXT) - gst_gl_display_set_error (display, "GL framebuffer status incomplete"); - - //unbind the FBO - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); - - glDeleteTextures (1, &fake_texture); -} - - -/* Called in the gl thread */ -void -gst_gl_display_thread_use_fbo (GstGLDisplay * display) -{ -#ifdef OPENGL_ES2 - GLint viewport_dim[4]; -#endif - - GST_TRACE ("Binding v1 FBO %u dimensions:%ux%u with texture:%u " - "dimensions:%ux%u", display->use_fbo, display->use_fbo_width, - display->use_fbo_height, display->use_fbo_texture, - display->input_texture_width, display->input_texture_height); - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->use_fbo); - - //setup a texture to render to - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->use_fbo_texture); - - //attach the texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, display->use_fbo_texture, 0); + //attach the texture to the FBO to renderer to + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, display->use_fbo_texture, 0); if (GLEW_ARB_fragment_shader) gst_gl_shader_use (NULL); @@ -1875,20 +752,6 @@ gst_gl_display_thread_del_shader (GstGLDisplay * display) void -gst_gl_display_lock (GstGLDisplay * display) -{ - g_mutex_lock (display->mutex); -} - - -void -gst_gl_display_unlock (GstGLDisplay * display) -{ - g_mutex_unlock (display->mutex); -} - - -void gst_gl_display_on_resize (GstGLDisplay * display, gint width, gint height) { GST_TRACE ("GL Window resized to %ux%u", width, height); @@ -1938,7 +801,7 @@ gst_gl_display_on_draw (GstGLDisplay * display) GST_TRACE ("on draw"); //make sure that the environnement is clean - if (display->upload_colorspace_conversion == GST_GL_DISPLAY_CONVERSION_GLSL) + if (display->colorspace_conversion == GST_GL_DISPLAY_CONVERSION_GLSL) glUseProgramObjectARB (0); #ifndef OPENGL_ES2 @@ -2076,13 +939,13 @@ gst_gl_display_gen_texture_thread (GstGLDisplay * display, GLuint * pTexture, break; case GST_VIDEO_FORMAT_YUY2: case GST_VIDEO_FORMAT_UYVY: - switch (display->upload_colorspace_conversion) { + switch (display->colorspace_conversion) { case GST_GL_DISPLAY_CONVERSION_GLSL: case GST_GL_DISPLAY_CONVERSION_MATRIX: glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); break; - case GST_GL_DISPLAY_CONVERSION_MESA: +/* case GST_GL_DISPLAY_CONVERSION_MESA: if (display->upload_width != display->upload_data_width || display->upload_height != display->upload_data_height) glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, @@ -2090,10 +953,10 @@ gst_gl_display_gen_texture_thread (GstGLDisplay * display, GLuint * pTexture, else glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA, width, height, 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, NULL); - break; + break;*/ default: gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); + display->colorspace_conversion); } break; case GST_VIDEO_FORMAT_I420: @@ -2103,8 +966,9 @@ gst_gl_display_gen_texture_thread (GstGLDisplay * display, GLuint * pTexture, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); break; default: - gst_gl_display_set_error (display, "Unsupported upload video format %d", - display->upload_video_format); +// gst_gl_display_set_error (display, "Unsupported upload video format %d", +// display->upload_video_format); + break; } glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -2123,6 +987,29 @@ gst_gl_display_del_texture_thread (GstGLDisplay * display, GLuint * pTexture) glDeleteTextures (1, pTexture); } + +//------------------------------------------------------------ +//--------------------- END PRIVATE ------------------------- +//------------------------------------------------------------ + + +//------------------------------------------------------------ +//---------------------- BEGIN PUBLIC ------------------------ +//------------------------------------------------------------ + +void +gst_gl_display_lock (GstGLDisplay * display) +{ + g_mutex_lock (display->mutex); +} + + +void +gst_gl_display_unlock (GstGLDisplay * display) +{ + g_mutex_unlock (display->mutex); +} + /* called in the gl thread */ void gst_gl_display_check_framebuffer_status (void) @@ -2157,17 +1044,6 @@ gst_gl_display_check_framebuffer_status (void) } } - -//------------------------------------------------------------ -//--------------------- END PRIVATE ------------------------- -//------------------------------------------------------------ - - -//------------------------------------------------------------ -//---------------------- BEGIN PUBLIC ------------------------ -//------------------------------------------------------------ - - /* Called by the first gl element of a video/x-raw-gl flow */ GstGLDisplay * gst_gl_display_new (void) @@ -2283,95 +1159,7 @@ gst_gl_display_del_texture (GstGLDisplay * display, GLuint * pTexture) gst_gl_display_unlock (display); } - -/* Called by the first gl element of a video/x-raw-gl flow */ -gboolean -gst_gl_display_init_upload (GstGLDisplay * display, GstVideoFormat video_format, - guint gl_width, guint gl_height, gint video_width, gint video_height) -{ - gboolean isAlive = FALSE; - - gst_gl_display_lock (display); - display->upload_video_format = video_format; - display->upload_width = gl_width; - display->upload_height = gl_height; - display->upload_data_width = video_width; - display->upload_data_height = video_height; - gst_gl_window_send_message (display->gl_window, - GST_GL_WINDOW_CB (gst_gl_display_thread_init_upload), display); - isAlive = display->isAlive; - gst_gl_display_unlock (display); - - return isAlive; -} - - -/* Called by the first gl element of a video/x-raw-gl flow */ -gboolean -gst_gl_display_do_upload (GstGLDisplay * display, GLuint texture, - GstVideoFrame * frame) -{ - gboolean isAlive = TRUE; - - gst_gl_display_lock (display); - isAlive = display->isAlive; - if (isAlive) { - display->upload_outtex = texture; - display->upload_frame = frame; - gst_gl_window_send_message (display->gl_window, - GST_GL_WINDOW_CB (gst_gl_display_thread_do_upload), display); - isAlive = display->isAlive; - } - gst_gl_display_unlock (display); - - return isAlive; -} - - -/* Called by the gldownload and glcolorscale element */ -gboolean -gst_gl_display_init_download (GstGLDisplay * display, - GstVideoFormat video_format, gint width, gint height) -{ - gboolean isAlive = FALSE; - - gst_gl_display_lock (display); - display->download_video_format = video_format; - display->download_width = width; - display->download_height = height; - gst_gl_window_send_message (display->gl_window, - GST_GL_WINDOW_CB (gst_gl_display_thread_init_download), display); - isAlive = display->isAlive; - gst_gl_display_unlock (display); - - return isAlive; -} - - -/* Called by the gldownload and glcolorscale element */ -gboolean -gst_gl_display_do_download (GstGLDisplay * display, GLuint texture, - GstVideoFrame * frame) -{ - gboolean isAlive = TRUE; - - gst_gl_display_lock (display); - isAlive = display->isAlive; - if (isAlive) { - //data size is aocciated to the glcontext size - display->download_frame = frame; - display->ouput_texture = texture; - gst_gl_window_send_message (display->gl_window, - GST_GL_WINDOW_CB (gst_gl_display_thread_do_download), display); - isAlive = display->isAlive; - } - gst_gl_display_unlock (display); - - return isAlive; -} - - -/* Called by gltestsrc and glfilter */ +/* Called by gltestsrc and glfilter */ gboolean gst_gl_display_gen_fbo (GstGLDisplay * display, gint width, gint height, GLuint * fbo, GLuint * depthbuffer) @@ -2573,1056 +1361,6 @@ gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activate) gst_gl_display_unlock (display); } - //------------------------------------------------------------ //------------------------ END PUBLIC ------------------------ //------------------------------------------------------------ - -/* called by gst_gl_display_thread_init_upload (in the gl thread) */ -void -gst_gl_display_thread_init_upload_fbo (GstGLDisplay * display) -{ - //Frame buffer object is a requirement for every cases - if (GLEW_EXT_framebuffer_object) { - //a texture must be attached to the FBO - GLuint fake_texture = 0; - - GST_INFO ("Context, EXT_framebuffer_object supported: yes"); - - //-- init intput frame buffer object (video -> GL) - - //setup FBO - glGenFramebuffersEXT (1, &display->upload_fbo); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->upload_fbo); - - //setup the render buffer for depth - glGenRenderbuffersEXT (1, &display->upload_depth_buffer); - glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, display->upload_depth_buffer); -#ifndef OPENGL_ES2 - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, - display->upload_width, display->upload_height); - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, - display->upload_width, display->upload_height); -#else - glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, - display->upload_width, display->upload_height); -#endif - - //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, - display->upload_width, display->upload_height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - //attach the texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, fake_texture, 0); - - //attach the depth render buffer to the FBO - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, display->upload_depth_buffer); - -#ifndef OPENGL_ES2 - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, display->upload_depth_buffer); -#endif - - gst_gl_display_check_framebuffer_status (); - - if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != - GL_FRAMEBUFFER_COMPLETE_EXT) - gst_gl_display_set_error (display, "GL framebuffer status incomplete"); - - //unbind the FBO - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); - - glDeleteTextures (1, &fake_texture); - - //alloc texture (related to upload) memory only on time - gst_gl_display_thread_do_upload_make (display); - } else { - //turn off the pipeline because Frame buffer object is a not present - gst_gl_display_set_error (display, - "Context, EXT_framebuffer_object supported: no"); - } -} - -/* called by gst_gl_display_thread_do_upload (in the gl thread) */ -void -gst_gl_display_thread_do_upload_make (GstGLDisplay * display) -{ - gint width = display->upload_data_width; - gint height = display->upload_data_height; - - glGenTextures (1, &display->upload_intex); - - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - 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: - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - break; - case GST_VIDEO_FORMAT_RGB: - case GST_VIDEO_FORMAT_BGR: - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, - width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - break; - case GST_VIDEO_FORMAT_AYUV: - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL); - break; - case GST_VIDEO_FORMAT_YUY2: - switch (display->upload_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); - glGenTextures (1, &display->upload_intex_u); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_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: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - break; - case GST_VIDEO_FORMAT_UYVY: - switch (display->upload_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); - glGenTextures (1, &display->upload_intex_u); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_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: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - break; - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, - width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); - - glGenTextures (1, &display->upload_intex_u); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_u); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, - GST_ROUND_UP_2 (width) / 2, - GST_ROUND_UP_2 (height) / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); - - glGenTextures (1, &display->upload_intex_v); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_v); - glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, - GST_ROUND_UP_2 (width) / 2, - GST_ROUND_UP_2 (height) / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); - break; - - default: - gst_gl_display_set_error (display, "Unsupported upload video format %d", - display->upload_video_format); - } -} - - -/* called by gst_gl_display_thread_do_upload (in the gl thread) */ -void -gst_gl_display_thread_do_upload_fill (GstGLDisplay * display) -{ - GstVideoInfo vinfo; - gint width, height; - GstVideoFrame *frame; - - frame = display->upload_frame; - vinfo = frame->info; - width = GST_VIDEO_INFO_WIDTH (&vinfo); - height = GST_VIDEO_INFO_HEIGHT (&vinfo); - - switch (display->upload_video_format) { - case GST_VIDEO_FORMAT_RGB: - case GST_VIDEO_FORMAT_BGR: - 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: - //color space conversion is not needed - if (display->upload_width != display->upload_data_width || - display->upload_height != display->upload_data_height) - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - else - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_outtex); - 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: - switch (display->upload_colorspace_conversion) { - case GST_GL_DISPLAY_CONVERSION_GLSL: - case GST_GL_DISPLAY_CONVERSION_MATRIX: - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - break; - case GST_GL_DISPLAY_CONVERSION_MESA: - if (display->upload_width != display->upload_data_width || - display->upload_height != display->upload_data_height) - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - else - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_outtex); - break; - default: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - break; - default: - gst_gl_display_set_error (display, "Unsupported upload video format %d", - display->upload_video_format); - } - - switch (display->upload_video_format) { - case GST_VIDEO_FORMAT_RGB: - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_RGB, GL_UNSIGNED_BYTE, frame->data[0]); - break; - case GST_VIDEO_FORMAT_BGR: - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_BGR, GL_UNSIGNED_BYTE, frame->data[0]); - break; - case GST_VIDEO_FORMAT_RGBx: - case GST_VIDEO_FORMAT_RGBA: - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_RGBA, GL_UNSIGNED_BYTE, frame->data[0]); - break; - case GST_VIDEO_FORMAT_BGRx: - case GST_VIDEO_FORMAT_BGRA: - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_BGRA, GL_UNSIGNED_BYTE, frame->data[0]); - break; - case GST_VIDEO_FORMAT_AYUV: - case GST_VIDEO_FORMAT_xRGB: - case GST_VIDEO_FORMAT_ARGB: - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, frame->data[0]); - break; - case GST_VIDEO_FORMAT_xBGR: - case GST_VIDEO_FORMAT_ABGR: - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, frame->data[0]); - break; - case GST_VIDEO_FORMAT_YUY2: - switch (display->upload_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, frame->data[0]); - - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_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, frame->data[0]); - 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, frame->data[0]); - break; - default: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - break; - case GST_VIDEO_FORMAT_UYVY: - switch (display->upload_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, frame->data[0]); - - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_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, frame->data[0]); - 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, frame->data[0]); - break; - default: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - break; - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - { - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, - GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[0]); - - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_u); - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, - GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2, - GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[1]); - - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_v); - glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, - GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2, - GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[2]); - } - break; - default: - gst_gl_display_set_error (display, "Unsupported upload video format %d", - display->upload_video_format); - } - - //make sure no texture is in use in our opengl context - //in case we want to use the upload texture in an other opengl context - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0); -} - - -/* called by gst_gl_display_thread_do_upload (in the gl thread) */ -void -gst_gl_display_thread_do_upload_draw (GstGLDisplay * display) -{ - -#ifdef OPENGL_ES2 - GLint viewport_dim[4]; - - const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f, - 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, - 0.0f, .0f, - -1.0f, 1.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 1.0f, 0.0f, - 1.0f, 1.0f - }; - - GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; -#endif - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->upload_fbo); - - //setup a texture to render to -#ifndef OPENGL_ES2 - glEnable (GL_TEXTURE_RECTANGLE_ARB); -#endif - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_outtex); - - //attach the texture to the FBO to renderer to - glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, display->upload_outtex, 0); - - if (GLEW_ARB_fragment_shader) - gst_gl_shader_use (NULL); - -#ifndef OPENGL_ES2 - glPushAttrib (GL_VIEWPORT_BIT); - - glMatrixMode (GL_PROJECTION); - glPushMatrix (); - glLoadIdentity (); - gluOrtho2D (0.0, display->upload_width, 0.0, display->upload_height); - - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); - glLoadIdentity (); -#else // OPENGL_ES2 - glGetIntegerv (GL_VIEWPORT, viewport_dim); -#endif - - glViewport (0, 0, display->upload_width, display->upload_height); - -#ifndef OPENGL_ES2 - glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); -#endif - - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - 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: - { -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#else - glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_upload_attr_position_loc); - glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); -#endif - -#ifndef OPENGL_ES2 - glEnable (GL_TEXTURE_RECTANGLE_ARB); -#endif - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); -#ifndef OPENGL_ES2 - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -#endif - } - break; - - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - { - switch (display->upload_colorspace_conversion) { - case GST_GL_DISPLAY_CONVERSION_GLSL: - case GST_GL_DISPLAY_CONVERSION_MATRIX: - { - GstGLShader *shader_upload_YUY2_UYVY = NULL; - - switch (display->upload_video_format) { - case GST_VIDEO_FORMAT_YUY2: - shader_upload_YUY2_UYVY = display->shader_upload_YUY2; - break; - case GST_VIDEO_FORMAT_UYVY: - shader_upload_YUY2_UYVY = display->shader_upload_UYVY; - break; - default: - gst_gl_display_set_error (display, - "Upload video format inconsistency %d", - display->upload_video_format); - } - - gst_gl_shader_use (shader_upload_YUY2_UYVY); - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#else - glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_upload_attr_position_loc); - glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); -#endif - - glActiveTextureARB (GL_TEXTURE1_ARB); - gst_gl_shader_set_uniform_1i (shader_upload_YUY2_UYVY, "UVtex", 1); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_u); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (shader_upload_YUY2_UYVY, "Ytex", 0); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - } - break; - case GST_GL_DISPLAY_CONVERSION_MESA: - { - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - glEnable (GL_TEXTURE_RECTANGLE_ARB); -#endif - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); -#ifndef OPENGL_ES2 - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); -#endif - } - break; - default: - gst_gl_display_set_error (display, "Unknow colorspace conversion %d", - display->upload_colorspace_conversion); - } - } - break; - - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - { - gst_gl_shader_use (display->shader_upload_I420_YV12); - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#else - glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_upload_attr_position_loc); - glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); -#endif - - glActiveTextureARB (GL_TEXTURE1_ARB); - gst_gl_shader_set_uniform_1i (display->shader_upload_I420_YV12, "Utex", - 1); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_u); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - glActiveTextureARB (GL_TEXTURE2_ARB); - gst_gl_shader_set_uniform_1i (display->shader_upload_I420_YV12, "Vtex", - 2); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex_v); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (display->shader_upload_I420_YV12, "Ytex", - 0); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - } - break; - - case GST_VIDEO_FORMAT_AYUV: - { - gst_gl_shader_use (display->shader_upload_AYUV); - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#else - glVertexAttribPointer (display->shader_upload_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_upload_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_upload_attr_position_loc); - glEnableVertexAttribArray (display->shader_upload_attr_texture_loc); -#endif - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (display->shader_upload_AYUV, "tex", 0); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - } - break; - - default: - GST_ERROR ("Unsupported upload video format %d", - display->upload_video_format); - - } //end switch display->currentVideo_format - -#ifndef OPENGL_ES2 - glBegin (GL_QUADS); - glTexCoord2i (display->upload_data_width, 0); - glVertex2f (1.0f, -1.0f); - glTexCoord2i (0, 0); - glVertex2f (-1.0f, -1.0f); - glTexCoord2i (0, display->upload_data_height); - glVertex2f (-1.0f, 1.0f); - glTexCoord2i (display->upload_data_width, display->upload_data_height); - glVertex2f (1.0f, 1.0f); - glEnd (); - - glDrawBuffer (GL_NONE); -#else //OPENGL_ES2 - glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); -#endif - - //we are done with the shader - if (display->upload_colorspace_conversion == GST_GL_DISPLAY_CONVERSION_GLSL) - glUseProgramObjectARB (0); - -#ifndef OPENGL_ES2 - glDisable (GL_TEXTURE_RECTANGLE_ARB); - - glMatrixMode (GL_PROJECTION); - glPopMatrix (); - glMatrixMode (GL_MODELVIEW); - glPopMatrix (); - glPopAttrib (); -#else - glViewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], - viewport_dim[3]); -#endif - - gst_gl_display_check_framebuffer_status (); - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); -} - - -/* called by gst_gl_display_thread_do_download (in the gl thread) */ -void -gst_gl_display_thread_do_download_draw_rgb (GstGLDisplay * display) -{ - GstVideoFormat video_format = display->download_video_format; - GstVideoFrame *frame = display->download_frame; - -#ifndef OPENGL_ES2 - if (display->upload_colorspace_conversion == GST_GL_DISPLAY_CONVERSION_GLSL) - glUseProgramObjectARB (0); - glEnable (GL_TEXTURE_RECTANGLE_ARB); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); -#else - gint width = GST_VIDEO_INFO_WIDTH (&frame->info); - gint height = GST_VIDEO_INFO_HEIGHT (&frame->info); - - const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f, - 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, - 0.0f, 0.0f, - -1.0f, 1.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 1.0f, 0.0f, - 1.0f, 1.0f - }; - - GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; - - glViewport (0, 0, width, height); - - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - gst_gl_shader_use (display->shader_download_RGB); - - glVertexAttribPointer (display->shader_download_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_download_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_download_attr_position_loc); - glEnableVertexAttribArray (display->shader_download_attr_texture_loc); - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (display->shader_download_RGB, "s_texture", 0); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); - - glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); - - glUseProgramObjectARB (0); -#endif - - switch (video_format) { - case GST_VIDEO_FORMAT_RGBA: - case GST_VIDEO_FORMAT_RGBx: -#ifndef OPENGL_ES2 - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - GL_UNSIGNED_BYTE, frame->data[0]); -#else - glReadPixels (0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, - frame->data[0]); -#endif - break; - case GST_VIDEO_FORMAT_xRGB: - case GST_VIDEO_FORMAT_ARGB: -#ifndef OPENGL_ES2 -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8, frame->data[0]); -#else - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, frame->data[0]); -#endif /* G_BYTE_ORDER */ -#else /* OPENGL_ES2 */ -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, - frame->data[0]); -#else - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, frame->data[0]); -#endif /* G_BYTE_ORDER */ -#endif /* !OPENGL_ES2 */ - break; - case GST_VIDEO_FORMAT_BGRx: - case GST_VIDEO_FORMAT_BGRA: -#ifndef OPENGL_ES2 - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, - GL_UNSIGNED_BYTE, frame->data[0]); -#endif - break; - case GST_VIDEO_FORMAT_xBGR: - case GST_VIDEO_FORMAT_ABGR: -#ifndef OPENGL_ES2 -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - GL_UNSIGNED_INT_8_8_8_8, frame->data[0]); -#else - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, - GL_UNSIGNED_INT_8_8_8_8_REV, frame->data[0]); -#endif /* G_BYTE_ORDER */ -#endif /* !OPENGL_ES2 */ - break; - case GST_VIDEO_FORMAT_RGB: -#ifndef OPENGL_ES2 - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, - GL_UNSIGNED_BYTE, frame->data[0]); -#else - glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, - frame->data[0]); -#endif - break; - case GST_VIDEO_FORMAT_BGR: -#ifndef OPENGL_ES2 - glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGR, - GL_UNSIGNED_BYTE, frame->data[0]); -#endif - break; - default: - gst_gl_display_set_error (display, - "Download video format inconsistency %d", video_format); - } - -#ifndef OPENGL_ES2 - glReadBuffer (GL_NONE); - glDisable (GL_TEXTURE_RECTANGLE_ARB); -#endif -} - - -/* called by gst_gl_display_thread_do_download (in the gl thread) */ -void -gst_gl_display_thread_do_download_draw_yuv (GstGLDisplay * display) -{ - gint width, height; - GstVideoFormat video_format; - GstVideoInfo vinfo; - GstVideoFrame *frame; - -#ifdef OPENGL_ES2 - GLint viewport_dim[4]; - - const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f, - 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, - 0.0f, .0f, - -1.0f, 1.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 1.0f, 0.0f, - 1.0f, 1.0f - }; - - GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; -#endif - - frame = display->download_frame; - vinfo = frame->info; - width = GST_VIDEO_INFO_WIDTH (&vinfo); - height = GST_VIDEO_INFO_HEIGHT (&vinfo); - video_format = GST_VIDEO_INFO_FORMAT (&vinfo); - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->download_fbo); - -#ifndef OPENGL_ES2 - glPushAttrib (GL_VIEWPORT_BIT); - - glMatrixMode (GL_PROJECTION); - glPushMatrix (); - glLoadIdentity (); - gluOrtho2D (0.0, width, 0.0, height); - - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); - glLoadIdentity (); -#else // OPENGL_ES2 - glGetIntegerv (GL_VIEWPORT, viewport_dim); -#endif - - glViewport (0, 0, width, height); - - switch (video_format) { - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: - { - GstGLShader *shader_download_YUY2_UYVY = NULL; - - switch (video_format) { - case GST_VIDEO_FORMAT_YUY2: - shader_download_YUY2_UYVY = display->shader_download_YUY2; - break; - case GST_VIDEO_FORMAT_UYVY: - shader_download_YUY2_UYVY = display->shader_download_UYVY; - break; - default: - gst_gl_display_set_error (display, - "Download video format inconsistensy %d", video_format); - } -#ifndef OPENGL_ES2 - glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); -#endif - - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - gst_gl_shader_use (shader_download_YUY2_UYVY); - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#else - glVertexAttribPointer (display->shader_download_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_download_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_download_attr_position_loc); - glEnableVertexAttribArray (display->shader_download_attr_texture_loc); -#endif - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (shader_download_YUY2_UYVY, "tex", 0); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); - } - break; - - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - { -#ifndef OPENGL_ES2 - glDrawBuffers (3, display->multipleRT); -#endif - - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - gst_gl_shader_use (display->shader_download_I420_YV12); - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#endif - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (display->shader_download_I420_YV12, "tex", - 0); - gst_gl_shader_set_uniform_1f (display->shader_download_I420_YV12, "w", - (gfloat) display->ouput_texture_width); - gst_gl_shader_set_uniform_1f (display->shader_download_I420_YV12, "h", - (gfloat) display->ouput_texture_height); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); - } - break; - - case GST_VIDEO_FORMAT_AYUV: - { -#ifndef OPENGL_ES2 - glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); -#endif - - glClearColor (0.0, 0.0, 0.0, 0.0); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - gst_gl_shader_use (display->shader_download_AYUV); - -#ifndef OPENGL_ES2 - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); -#else - glVertexAttribPointer (display->shader_download_attr_position_loc, 3, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); - glVertexAttribPointer (display->shader_download_attr_texture_loc, 2, - GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); - - glEnableVertexAttribArray (display->shader_download_attr_position_loc); - glEnableVertexAttribArray (display->shader_download_attr_texture_loc); -#endif - - glActiveTextureARB (GL_TEXTURE0_ARB); - gst_gl_shader_set_uniform_1i (display->shader_download_AYUV, "tex", 0); - glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture); - } - break; - - default: - gst_gl_display_set_error (display, - "Download video format inconsistensy %d", video_format); - - } //end switch display->currentVideo_format - -#ifndef OPENGL_ES2 - glBegin (GL_QUADS); - glTexCoord2i (0, 0); - glVertex2f (-1.0f, -1.0f); - glTexCoord2i (width, 0); - glVertex2f (1.0f, -1.0f); - glTexCoord2i (width, height); - glVertex2f (1.0f, 1.0f); - glTexCoord2i (0, height); - glVertex2f (-1.0f, 1.0f); - glEnd (); - - glDrawBuffer (GL_NONE); -#else //OPENGL_ES2 - glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); -#endif - - //dot not check if GLSL is available - //because download yuv is not available - //without GLSL (whereas rgb is) - glUseProgramObjectARB (0); - -#ifndef OPENGL_ES2 - glDisable (GL_TEXTURE_RECTANGLE_ARB); - glMatrixMode (GL_PROJECTION); - glPopMatrix (); - glMatrixMode (GL_MODELVIEW); - glPopMatrix (); - glPopAttrib (); -#else - glViewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], - viewport_dim[3]); -#endif - - gst_gl_display_check_framebuffer_status (); - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->download_fbo); -#ifndef OPENGL_ES2 - glReadBuffer (GL_COLOR_ATTACHMENT0_EXT); -#endif - - switch (video_format) { - case GST_VIDEO_FORMAT_AYUV: -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - glReadPixels (0, 0, width, height, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8, GST_VIDEO_FRAME_PLANE_DATA (frame, 0)); -#else - glReadPixels (0, 0, width, height, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, GST_VIDEO_FRAME_PLANE_DATA (frame, 0)); -#endif - break; - case GST_VIDEO_FORMAT_YUY2: - case GST_VIDEO_FORMAT_UYVY: -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, height, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8_REV, frame->data[0]); -#else - glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, height, GL_BGRA, - GL_UNSIGNED_INT_8_8_8_8, frame->data[0]); -#endif - break; - case GST_VIDEO_FORMAT_I420: - case GST_VIDEO_FORMAT_YV12: - { - glReadPixels (0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, - GST_VIDEO_FRAME_COMP_DATA (frame, 0)); - -#ifndef OPENGL_ES2 - glReadBuffer (GL_COLOR_ATTACHMENT1_EXT); -#endif - - glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, - GST_ROUND_UP_2 (height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE, - GST_VIDEO_FRAME_COMP_DATA (frame, 1)); - -#ifndef OPENGL_ES2 - glReadBuffer (GL_COLOR_ATTACHMENT2_EXT); -#endif - - glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, - GST_ROUND_UP_2 (height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE, - GST_VIDEO_FRAME_COMP_DATA (frame, 2)); - } - break; - default: - gst_gl_display_set_error (display, - "Download video format inconsistensy %d", video_format); - } -#ifndef OPENGL_ES2 - glReadBuffer (GL_NONE); -#endif - - gst_gl_display_check_framebuffer_status (); - - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); -} diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h index 8f77e53..5103ede 100644 --- a/gst-libs/gst/gl/gstgldisplay.h +++ b/gst-libs/gst/gl/gstgldisplay.h @@ -27,6 +27,8 @@ #include "gstglwindow.h" #include "gstglshader.h" +#include "gstglupload.h" +#include "gstgldownload.h" G_BEGIN_DECLS @@ -125,20 +127,10 @@ struct _GstGLDisplay CDCB clientDrawCallback; gpointer client_data; - //upload - GLuint upload_fbo; - GLuint upload_depth_buffer; - GLuint upload_outtex; - GLuint upload_intex; - GLuint upload_intex_u; - GLuint upload_intex_v; - GLuint upload_width; - GLuint upload_height; - GstVideoFormat upload_video_format; - GstGLDisplayConversion upload_colorspace_conversion; - gint upload_data_width; - gint upload_data_height; - GstVideoFrame *upload_frame; + GstGLDisplayConversion colorspace_conversion; + + GHashTable *uploads; + GHashTable *downloads; //foreign gl context gulong external_gl_context; @@ -171,21 +163,6 @@ struct _GstGLDisplay GLuint del_fbo; GLuint del_depth_buffer; - //download - GLuint download_fbo; - GLuint download_depth_buffer; - GLuint download_texture; - GLuint download_texture_u; - GLuint download_texture_v; - gint download_width; - gint download_height; - GstVideoFormat download_video_format; - GstVideoFrame *download_frame; - GLenum multipleRT[3]; - GLuint ouput_texture; - GLuint ouput_texture_width; - GLuint ouput_texture_height; - //action gen and del shader const gchar *gen_shader_fragment_source; const gchar *gen_shader_vertex_source; @@ -209,25 +186,6 @@ struct _GstGLDisplay GLint shader_upload_attr_texture_loc; #endif - //fragement shader download - gchar *text_shader_download_YUY2_UYVY; - GstGLShader *shader_download_YUY2; - GstGLShader *shader_download_UYVY; - - gchar *text_shader_download_I420_YV12; - GstGLShader *shader_download_I420_YV12; - - gchar *text_shader_download_AYUV; - GstGLShader *shader_download_AYUV; - -#ifdef OPENGL_ES2 - gchar *text_vertex_shader_download; - GLint shader_download_attr_position_loc; - GLint shader_download_attr_texture_loc; - gchar *text_fragment_shader_download_RGB; - GstGLShader *shader_download_RGB; -#endif - gchar *error_message; }; @@ -266,10 +224,6 @@ gboolean gst_gl_display_init_upload (GstGLDisplay * display, gint video_width, gint video_height); gboolean gst_gl_display_do_upload (GstGLDisplay * display, GLuint texture, GstVideoFrame * frame); -gboolean gst_gl_display_init_download (GstGLDisplay * display, - GstVideoFormat video_format, gint width, gint height); -gboolean gst_gl_display_do_download (GstGLDisplay * display, GLuint texture, - GstVideoFrame *frame); gboolean gst_gl_display_gen_fbo (GstGLDisplay * display, gint width, gint height, GLuint * fbo, GLuint * depthbuffer); @@ -301,6 +255,10 @@ void gst_gl_display_activate_gl_context (GstGLDisplay * display, gboolean activa /* Must be called inside a lock/unlock on display, or within the glthread */ void gst_gl_display_set_error (GstGLDisplay * display, const char * format, ...); +void gst_gl_display_check_framebuffer_status (void); + +void gst_gl_display_lock (GstGLDisplay * display); +void gst_gl_display_unlock (GstGLDisplay * display); G_END_DECLS diff --git a/gst-libs/gst/gl/gstgldownload.c b/gst-libs/gst/gl/gstgldownload.c new file mode 100644 index 0000000..3a66533 --- /dev/null +++ b/gst-libs/gst/gl/gstgldownload.c @@ -0,0 +1,1136 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstgldownload.h" +#include "gstglmemory.h" + +static void _do_download (GstGLDisplay * display, GstGLDownload * download); +static void _do_download_draw_rgb (GstGLDisplay * display, + GstGLDownload * download); +static void _do_download_draw_yuv (GstGLDisplay * display, + GstGLDownload * download); +static void _init_download (GstGLDisplay * display, GstGLDownload * download); +static void _init_download_shader (GstGLDisplay * display, + GstGLDownload * download); +static gboolean gst_gl_download_perform_with_data_unlocked (GstGLDownload * + download, GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]); + +/* YUY2:y2,u,y1,v + UYVY:v,y1,u,y2 */ +static gchar *text_shader_download_YUY2_UYVY = +#ifndef OPENGL_ES2 + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect tex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" "uniform sampler2D tex;\n" +#endif + "void main(void) {\n" " float fx,fy,r,g,b,r2,g2,b2,y1,y2,u,v;\n" +#ifndef OPENGL_ES2 + " fx = gl_TexCoord[0].x;\n" + " fy = gl_TexCoord[0].y;\n" + " r=texture2DRect(tex,vec2(fx*2.0,fy)).r;\n" + " g=texture2DRect(tex,vec2(fx*2.0,fy)).g;\n" + " b=texture2DRect(tex,vec2(fx*2.0,fy)).b;\n" + " r2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).r;\n" + " g2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).g;\n" + " b2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).b;\n" +#else + " fx = v_texCoord.x;\n" + " fy = v_texCoord.y;\n" + " r=texture2D(tex,vec2(fx*2.0,fy)).r;\n" + " g=texture2D(tex,vec2(fx*2.0,fy)).g;\n" + " b=texture2D(tex,vec2(fx*2.0,fy)).b;\n" + " r2=texture2D(tex,vec2(fx*2.0+1.0,fy)).r;\n" + " g2=texture2D(tex,vec2(fx*2.0+1.0,fy)).g;\n" + " b2=texture2D(tex,vec2(fx*2.0+1.0,fy)).b;\n" +#endif + " y1=0.299011*r + 0.586987*g + 0.114001*b;\n" + " y2=0.299011*r2 + 0.586987*g2 + 0.114001*b2;\n" + " u=-0.148246*r -0.29102*g + 0.439266*b;\n" + " v=0.439271*r - 0.367833*g - 0.071438*b ;\n" + " y1=0.858885*y1 + 0.0625;\n" + " y2=0.858885*y2 + 0.0625;\n" + " u=u + 0.5;\n" " v=v + 0.5;\n" " gl_FragColor=vec4(%s);\n" "}\n"; + +/* no OpenGL ES 2.0 support because for now it's not possible + * to attach multiple textures to a frame buffer object + */ +static gchar *text_shader_download_I420_YV12 = + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect tex;\n" + "uniform float w, h;\n" + "void main(void) {\n" + " float r,g,b,r2,b2,g2,y,u,v;\n" + " vec2 nxy=gl_TexCoord[0].xy;\n" + " vec2 nxy2=nxy*2.0;\n" + " r=texture2DRect(tex,nxy).r;\n" + " g=texture2DRect(tex,nxy).g;\n" + " b=texture2DRect(tex,nxy).b;\n" + " r2=texture2DRect(tex,nxy2).r;\n" + " g2=texture2DRect(tex,nxy2).g;\n" + " b2=texture2DRect(tex,nxy2).b;\n" + " y=0.299011*r + 0.586987*g + 0.114001*b;\n" + " u=-0.148246*r2 -0.29102*g2 + 0.439266*b2;\n" + " v=0.439271*r2 - 0.367833*g2 - 0.071438*b2 ;\n" + " y=0.858885*y + 0.0625;\n" + " u=u + 0.5;\n" + " v=v + 0.5;\n" + " gl_FragData[0] = vec4(y, 0.0, 0.0, 1.0);\n" + " gl_FragData[1] = vec4(u, 0.0, 0.0, 1.0);\n" + " gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n" "}\n"; + +static gchar *text_shader_download_AYUV = +#ifndef OPENGL_ES2 + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect tex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" "uniform sampler2D tex;\n" +#endif + "void main(void) {\n" " float r,g,b,y,u,v;\n" +#ifndef OPENGL_ES2 + " vec2 nxy=gl_TexCoord[0].xy;\n" + " r=texture2DRect(tex,nxy).r;\n" + " g=texture2DRect(tex,nxy).g;\n" " b=texture2DRect(tex,nxy).b;\n" +#else + " vec2 nxy=v_texCoord.xy;\n" + " r=texture2D(tex,nxy).r;\n" + " g=texture2D(tex,nxy).g;\n" " b=texture2D(tex,nxy).b;\n" +#endif + " y=0.299011*r + 0.586987*g + 0.114001*b;\n" + " u=-0.148246*r -0.29102*g + 0.439266*b;\n" + " v=0.439271*r - 0.367833*g - 0.071438*b ;\n" + " y=0.858885*y + 0.0625;\n" " u=u + 0.5;\n" " v=v + 0.5;\n" +#ifndef OPENGL_ES2 + " gl_FragColor=vec4(y,u,v,1.0);\n" +#else + " gl_FragColor=vec4(1.0,y,u,v);\n" +#endif + "}\n"; + +#ifdef OPENGL_ES2 +static gchar *text_vertex_shader_download = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" "} \n"; + +static gchar *text_fragment_shader_download_RGB = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; +#endif + +GST_DEBUG_CATEGORY_STATIC (gst_gl_download_debug); +#define GST_CAT_DEFAULT gst_gl_download_debug + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_gl_download_debug, "gldownload", 0, "download"); + +G_DEFINE_TYPE_WITH_CODE (GstGLDownload, gst_gl_download, G_TYPE_OBJECT, + DEBUG_INIT); +static void gst_gl_download_finalize (GObject * object); + +#define GST_GL_DOWNLOAD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + GST_TYPE_GL_DOWNLOAD, GstGLDownloadPrivate)) + +static void +gst_gl_download_class_init (GstGLDownloadClass * klass) +{ + G_OBJECT_CLASS (klass)->finalize = gst_gl_download_finalize; +} + +static void +gst_gl_download_init (GstGLDownload * download) +{ + download->display = NULL; + + g_mutex_init (&download->lock); + + download->fbo = 0; + download->depth_buffer = 0; + download->in_texture = 0; + download->shader = NULL; + +#ifdef OPENGL_ES2 + download->shader_attr_position_loc = 0; + download->shader_attr_texture_loc = 0; +#endif + + gst_video_info_init (&download->info); +} + +GstGLDownload * +gst_gl_download_new (GstGLDisplay * display) +{ + GstGLDownload *download; + + download = g_object_new (GST_TYPE_GL_DOWNLOAD, NULL); + + download->display = g_object_ref (display); + + return download; +} + +static void +gst_gl_download_finalize (GObject * object) +{ + GstGLDownload *download; + guint i; + + download = GST_GL_DOWNLOAD (object); + + for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) { + if (download->out_texture[i]) { + gst_gl_display_del_texture (download->display, &download->out_texture[i]); + download->out_texture[i] = 0; + } + } + if (download->in_texture) { + gst_gl_display_del_texture (download->display, &download->in_texture); + download->in_texture = 0; + } + if (download->fbo || download->depth_buffer) { + gst_gl_display_del_fbo (download->display, download->fbo, + download->depth_buffer); + download->fbo = 0; + download->depth_buffer = 0; + } + if (download->shader) { + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } + + if (download->display) { + g_object_unref (G_OBJECT (download->display)); + download->display = NULL; + } + + g_mutex_clear (&download->lock); +} + +gboolean +gst_gl_download_init_format (GstGLDownload * download, GstVideoFormat v_format, + guint width, guint height) +{ + GstVideoInfo info; + + g_return_val_if_fail (download != NULL, FALSE); + g_return_val_if_fail (v_format != GST_VIDEO_FORMAT_UNKNOWN, FALSE); + g_return_val_if_fail (v_format != GST_VIDEO_FORMAT_ENCODED, FALSE); + g_return_val_if_fail (width > 0 && height > 0, FALSE); + + g_mutex_lock (&download->lock); + + gst_video_info_set_format (&info, v_format, width, height); + + download->info = info; + + gst_gl_display_thread_add (download->display, + (GstGLDisplayThreadFunc) _init_download, download); + + g_mutex_unlock (&download->lock); + + return TRUE; +} + +gboolean +gst_gl_download_perform_with_memory (GstGLDownload * download, + GstGLMemory * gl_mem) +{ + gpointer data[GST_VIDEO_MAX_PLANES]; + guint i; + gboolean ret; + + g_return_val_if_fail (download != NULL, FALSE); + + if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_DOWNLOAD_INITTED)) + return FALSE; + + if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD)) { + return FALSE; + } + + g_mutex_lock (&download->lock); + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) { + data[i] = (guint8 *) gl_mem->data + + GST_VIDEO_INFO_PLANE_OFFSET (&download->info, i); + } + + ret = + gst_gl_download_perform_with_data_unlocked (download, gl_mem->tex_id, + data); + + GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_DOWNLOAD); + + g_mutex_unlock (&download->lock); + + return ret; +} + +gboolean +gst_gl_download_perform_with_data (GstGLDownload * download, GLuint texture_id, + gpointer data[GST_VIDEO_MAX_PLANES]) +{ + gboolean ret; + + g_return_val_if_fail (download != NULL, FALSE); + + g_mutex_lock (&download->lock); + + ret = gst_gl_download_perform_with_data_unlocked (download, texture_id, data); + + g_mutex_unlock (&download->lock); + + return ret; +} + +static gboolean +gst_gl_download_perform_with_data_unlocked (GstGLDownload * download, + GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]) +{ + guint i; + + g_return_val_if_fail (download != NULL, FALSE); + g_return_val_if_fail (texture_id > 0, FALSE); + g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&download->info) != + GST_VIDEO_FORMAT_UNKNOWN + && GST_VIDEO_INFO_FORMAT (&download->info) != GST_VIDEO_FORMAT_ENCODED, + FALSE); + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) { + g_return_val_if_fail (data[i] != NULL, FALSE); + } + + download->in_texture = texture_id; + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&download->info); i++) { + download->data[i] = data[i]; + } + + gst_gl_display_thread_add (download->display, + (GstGLDisplayThreadFunc) _do_download, download); + + return TRUE; +} + +GstGLDownload * +gst_gl_display_find_download (GstGLDisplay * display, GstVideoFormat v_format, + guint width, guint height) +{ + GstGLDownload *ret; + guint64 *key; + + /* this limits the width and the height to 2^29-1 = 536870911 */ + key = g_malloc (sizeof (guint64 *)); + *key = v_format | ((guint64) width << 6) | ((guint64) height << 35); + + gst_gl_display_lock (display); + + ret = g_hash_table_lookup (display->downloads, key); + + if (!ret) { + ret = gst_gl_download_new (display); + + g_hash_table_insert (display->downloads, key, ret); + } + + gst_gl_display_unlock (display); + + return ret; +} + +static void +_init_download (GstGLDisplay * display, GstGLDownload * download) +{ + GstVideoFormat v_format; + guint width, height; + + width = GST_VIDEO_INFO_WIDTH (&download->info); + height = GST_VIDEO_INFO_HEIGHT (&download->info); + v_format = GST_VIDEO_INFO_FORMAT (&download->info); + + GST_TRACE ("initializing texture download for format %d", v_format); + + switch (v_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 */ + { + + if (!GLEW_EXT_framebuffer_object) { + /* Frame buffer object is a requirement + * when using GLSL colorspace conversion + */ + gst_gl_display_set_error (display, + "Context, EXT_framebuffer_object supported: no"); + } + GST_INFO ("Context, EXT_framebuffer_object supported: yes"); + + /* setup FBO */ + if (!download->fbo && !download->depth_buffer) { + glGenFramebuffersEXT (1, &download->fbo); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, download->fbo); + + /* setup the render buffer for depth */ + glGenRenderbuffersEXT (1, &download->depth_buffer); + glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, download->depth_buffer); +#ifndef OPENGL_ES2 + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, + width, height); + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, + width, height); +#else + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, + width, height); +#endif + } + + /* setup a first texture to render to */ + glGenTextures (1, &download->out_texture[0]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->out_texture[0]); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + /* attach the first texture to the FBO to renderer to */ + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, download->out_texture[0], 0); + + if (v_format == GST_VIDEO_FORMAT_I420 || + v_format == GST_VIDEO_FORMAT_YV12) { + /* setup a second texture to render to */ + glGenTextures (1, &download->out_texture[1]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->out_texture[1]); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + /* attach the second texture to the FBO to renderer to */ + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, + download->out_texture[1], 0); + + /* setup a third texture to render to */ + glGenTextures (1, &download->out_texture[2]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->out_texture[2]); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + /* attach the third texture to the FBO to renderer to */ + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_RECTANGLE_ARB, + download->out_texture[2], 0); + } + + /* attach the depth render buffer to the FBO */ + glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, download->depth_buffer); + +#ifndef OPENGL_ES2 + glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, + GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, + download->depth_buffer); +#endif + + gst_gl_display_check_framebuffer_status (); + + if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != + GL_FRAMEBUFFER_COMPLETE_EXT) { + gst_gl_display_set_error (display, "GL framebuffer status incomplete"); + } + + /* unbind the FBO */ + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); + } + break; + default: + break; + gst_gl_display_set_error (display, "Unsupported download video format %d", + v_format); + g_assert_not_reached (); + } + + _init_download_shader (display, download); +} + +static void +_init_download_shader (GstGLDisplay * display, GstGLDownload * download) +{ + GstVideoFormat v_format; + + v_format = GST_VIDEO_INFO_FORMAT (&download->info); + + switch (v_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 */ +#ifdef OPENGL_ES2 + { + /* glGetTexImage2D not available in OpenGL ES 2.0 */ + GError *error = NULL; + download->shader = gst_gl_shader_new (); + + gst_gl_shader_set_vertex_source (download->shader, + text_vertex_shader_download); + gst_gl_shader_set_fragment_source (download->shader, + text_fragment_shader_download_RGB); + + gst_gl_shader_compile (download->shader, &error); + if (error) { + gst_gl_display_set_error (download, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } else { + download->shader_attr_position_loc = + gst_gl_shader_get_attribute_location (download->shader, + "a_position"); + download->shader_attr_texture_loc = + gst_gl_shader_get_attribute_location (download->shader, + "a_texCoord"); + } + } +#endif + 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 + * GLSL is a requirement for donwload + */ + if (!GLEW_ARB_fragment_shader) { + /* colorspace conversion is not possible */ + gst_gl_display_set_error (display, + "Context, ARB_fragment_shader supported: no"); + return; + } +#ifdef OPENGL_ES2 + GError *error = NULL; +#endif + + switch (v_format) { + case GST_VIDEO_FORMAT_YUY2: + { + gchar text_shader_download_YUY2[2048]; + sprintf (text_shader_download_YUY2, + text_shader_download_YUY2_UYVY, "y2,u,y1,v"); + + download->shader = gst_gl_shader_new (); +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check (download->shader, + text_shader_download_YUY2, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for downloading YUY2"); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (download->shader, + text_vertex_shader_download); + gst_gl_shader_set_fragment_source (download->shader, + text_shader_download_YUY2); + + gst_gl_shader_compile (download->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } else { + download->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (download->shader, "a_position"); + download->shader_attr_texture_loc = + gst_gl_shader_get_attribute_location + (download->shader, "a_texCoord"); + } +#endif + } + break; + case GST_VIDEO_FORMAT_UYVY: + { + gchar text_shader_download_UYVY[2048]; + sprintf (text_shader_download_UYVY, + text_shader_download_YUY2_UYVY, "v,y1,u,y2"); + + download->shader = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check (download->shader, + text_shader_download_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for downloading UYVY"); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (download->shader, + text_vertex_shader_download); + gst_gl_shader_set_fragment_source (download->shader, + text_shader_download_UYVY); + + gst_gl_shader_compile (download->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } else { + download->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (download->shader, "a_position"); + download->shader_attr_texture_loc = + gst_gl_shader_get_attribute_location + (download->shader, "a_texCoord"); + } +#endif + + } + break; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + download->shader = gst_gl_shader_new (); + if (!gst_gl_shader_compile_and_check (download->shader, + text_shader_download_I420_YV12, + GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for downloading I420 or YV12"); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } + break; + case GST_VIDEO_FORMAT_AYUV: + download->shader = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check (download->shader, + text_shader_download_AYUV, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for downloading AYUV"); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (download->shader, + text_vertex_shader_download); + gst_gl_shader_set_fragment_source (download->shader, + text_shader_download_AYUV); + + gst_gl_shader_compile (download->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (download->shader)); + download->shader = NULL; + } else { + download->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (download->shader, "a_position"); + download->shader_attr_texture_loc = + gst_gl_shader_get_attribute_location + (download->shader, "a_texCoord"); + } +#endif + break; + default: + gst_gl_display_set_error (display, + "Unsupported download video format %d", v_format); + g_assert_not_reached (); + break; + } + } + break; + default: + gst_gl_display_set_error (display, "Unsupported download video format %d", + v_format); + g_assert_not_reached (); + break; + } +} + +/* Called in the gl thread */ +static void +_do_download (GstGLDisplay * display, GstGLDownload * download) +{ + GstVideoFormat v_format; + guint width, height; + + width = GST_VIDEO_INFO_WIDTH (&download->info); + height = GST_VIDEO_INFO_HEIGHT (&download->info); + v_format = GST_VIDEO_INFO_FORMAT (&download->info); + + GST_TRACE ("downloading texture:%u format:%d, dimensions:%ux%u", + download->in_texture, v_format, width, height); + + switch (v_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 */ + _do_download_draw_rgb (display, download); + 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 */ + _do_download_draw_yuv (display, download); + break; + default: + gst_gl_display_set_error (display, "Unsupported download video format %d", + v_format); + g_assert_not_reached (); + break; + } +} + +/* called by _do_download (in the gl thread) */ +static void +_do_download_draw_rgb (GstGLDisplay * display, GstGLDownload * download) +{ + GstVideoFormat v_format; + +#ifndef OPENGL_ES2 + if (download->display->colorspace_conversion == + GST_GL_DISPLAY_CONVERSION_GLSL) + glUseProgramObjectARB (0); + glEnable (GL_TEXTURE_RECTANGLE_ARB); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->in_texture); +#else + guint width, height; + + width = GST_VIDEO_INFO_WIDTH (&download->info); + height = GST_VIDEO_INFO_HEIGHT (&download->info); + + const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f + }; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + glViewport (0, 0, width, height); + + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gst_gl_shader_use (download->shader); + + glVertexAttribPointer (download->shader_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); + glVertexAttribPointer (download->shader_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (download->shader_attr_position_loc); + glEnableVertexAttribArray (download->shader_attr_texture_loc); + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (download->shader, "s_texture", 0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->in_texture); + + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + + glUseProgramObjectARB (0); +#endif + + v_format = GST_VIDEO_INFO_FORMAT (&download->info); + + switch (v_format) { + case GST_VIDEO_FORMAT_RGBA: + case GST_VIDEO_FORMAT_RGBx: +#ifndef OPENGL_ES2 + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, + GL_UNSIGNED_BYTE, download->data[0]); +#else + glReadPixels (0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, + download->data[0]); +#endif + break; + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_ARGB: +#ifndef OPENGL_ES2 +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8, download->data[0]); +#else + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]); +#endif /* G_BYTE_ORDER */ +#else /* OPENGL_ES2 */ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, + download->data[0]); +#else + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]); +#endif /* G_BYTE_ORDER */ +#endif /* !OPENGL_ES2 */ + break; + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_BGRA: +#ifndef OPENGL_ES2 + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, + GL_UNSIGNED_BYTE, download->data[0]); +#endif + break; + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_ABGR: +#ifndef OPENGL_ES2 +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8, download->data[0]); +#else + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]); +#endif /* G_BYTE_ORDER */ +#endif /* !OPENGL_ES2 */ + break; + case GST_VIDEO_FORMAT_RGB: +#ifndef OPENGL_ES2 + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, + GL_UNSIGNED_BYTE, download->data[0]); +#else + glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, + download->data[0]); +#endif + break; + case GST_VIDEO_FORMAT_BGR: +#ifndef OPENGL_ES2 + glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGR, + GL_UNSIGNED_BYTE, download->data[0]); +#endif + break; + default: + gst_gl_display_set_error (display, + "Download video format inconsistency %d", v_format); + g_assert_not_reached (); + break; + } + +#ifndef OPENGL_ES2 + glReadBuffer (GL_NONE); + glDisable (GL_TEXTURE_RECTANGLE_ARB); +#endif +} + + +/* called by _do_download (in the gl thread) */ +static void +_do_download_draw_yuv (GstGLDisplay * display, GstGLDownload * download) +{ + GstVideoFormat v_format; + guint width, height; + + GLenum multipleRT[] = { + GL_COLOR_ATTACHMENT0_EXT, + GL_COLOR_ATTACHMENT1_EXT, + GL_COLOR_ATTACHMENT2_EXT + }; + +#ifdef OPENGL_ES2 + GLint viewport_dim[4]; + + const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, .0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f + }; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; +#endif + + width = GST_VIDEO_INFO_WIDTH (&download->info); + height = GST_VIDEO_INFO_HEIGHT (&download->info); + v_format = GST_VIDEO_INFO_FORMAT (&download->info); + + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, download->fbo); + +#ifndef OPENGL_ES2 + glPushAttrib (GL_VIEWPORT_BIT); + + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + gluOrtho2D (0.0, width, 0.0, height); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + glLoadIdentity (); +#else /* OPENGL_ES2 */ + glGetIntegerv (GL_VIEWPORT, viewport_dim); +#endif + + glViewport (0, 0, width, height); + + switch (v_format) { + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + case GST_VIDEO_FORMAT_AYUV: + { +#ifndef OPENGL_ES2 + glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); +#endif + + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gst_gl_shader_use (download->shader); + +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); +#else + glVertexAttribPointer (download->shader_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); + glVertexAttribPointer (download->shader_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (download->shader_attr_position_loc); + glEnableVertexAttribArray (download->shader_attr_texture_loc); +#endif + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (download->shader, "tex", 0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->in_texture); + } + break; + + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + { +#ifndef OPENGL_ES2 + glDrawBuffers (3, multipleRT); +#endif + + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gst_gl_shader_use (download->shader); + +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); +#endif + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (download->shader, "tex", 0); + gst_gl_shader_set_uniform_1f (download->shader, "w", (gfloat) width); + gst_gl_shader_set_uniform_1f (download->shader, "h", (gfloat) height); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, download->in_texture); + } + break; + + default: + break; + gst_gl_display_set_error (display, + "Download video format inconsistensy %d", v_format); + + } + +#ifndef OPENGL_ES2 + glBegin (GL_QUADS); + glTexCoord2i (0, 0); + glVertex2f (-1.0f, -1.0f); + glTexCoord2i (width, 0); + glVertex2f (1.0f, -1.0f); + glTexCoord2i (width, height); + glVertex2f (1.0f, 1.0f); + glTexCoord2i (0, height); + glVertex2f (-1.0f, 1.0f); + glEnd (); + + glDrawBuffer (GL_NONE); +#else /* OPENGL_ES2 */ + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); +#endif + + /* don't check if GLSL is available + * because download yuv is not available + * without GLSL (whereas rgb is) + */ + glUseProgramObjectARB (0); + +#ifndef OPENGL_ES2 + glDisable (GL_TEXTURE_RECTANGLE_ARB); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); + glPopAttrib (); +#else + glViewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], + viewport_dim[3]); +#endif + + gst_gl_display_check_framebuffer_status (); + + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); + + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, download->fbo); +#ifndef OPENGL_ES2 + glReadBuffer (GL_COLOR_ATTACHMENT0_EXT); +#endif + + switch (v_format) { + case GST_VIDEO_FORMAT_AYUV: +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + glReadPixels (0, 0, width, height, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8, download->data[0]); +#else + glReadPixels (0, 0, width, height, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]); +#endif + break; + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, height, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8_REV, download->data[0]); +#else + glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, height, GL_BGRA, + GL_UNSIGNED_INT_8_8_8_8, download->data[0]); +#endif + break; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + { + glReadPixels (0, 0, width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, + download->data[0]); + +#ifndef OPENGL_ES2 + glReadBuffer (GL_COLOR_ATTACHMENT1_EXT); +#endif + + glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, + GST_ROUND_UP_2 (height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE, + download->data[1]); + +#ifndef OPENGL_ES2 + glReadBuffer (GL_COLOR_ATTACHMENT2_EXT); +#endif + + glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, + GST_ROUND_UP_2 (height) / 2, GL_LUMINANCE, GL_UNSIGNED_BYTE, + download->data[2]); + } + break; + default: + break; + gst_gl_display_set_error (display, + "Download video format inconsistensy %d", v_format); + g_assert_not_reached (); + } +#ifndef OPENGL_ES2 + glReadBuffer (GL_NONE); +#endif + + gst_gl_display_check_framebuffer_status (); + + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); +} diff --git a/gst-libs/gst/gl/gstgldownload.h b/gst-libs/gst/gl/gstgldownload.h new file mode 100644 index 0000000..6fb9b45 --- /dev/null +++ b/gst-libs/gst/gl/gstgldownload.h @@ -0,0 +1,93 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * 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. + */ + +#ifndef __GST_GL_DOWNLOAD_H__ +#define __GST_GL_DOWNLOAD_H__ + +#include +#include + +#include "gstglshader.h" +#include "gstgldisplay.h" + +G_BEGIN_DECLS + +/* forward declare */ +typedef struct _GstGLMemory GstGLMemory; +typedef struct _GstGLDisplay GstGLDisplay; + +GType gst_gl_download_get_type (void); +#define GST_TYPE_GL_DOWNLOAD (gst_gl_download_get_type()) +#define GST_GL_DOWNLOAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DOWNLOAD,GstGLDownload)) +#define GST_GL_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLDownloadClass)) +#define GST_IS_GL_DOWNLOAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DOWNLOAD)) +#define GST_IS_GL_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_DOWNLOAD)) +#define GST_GL_DOWNLOAD_CAST(obj) ((GstGLDownload*)(obj)) + +typedef struct _GstGLDownload GstGLDownload; +typedef struct _GstGLDownloadClass GstGLDownloadClass; + +struct _GstGLDownload +{ + GObject parent; + + GMutex lock; + + GstGLDisplay *display; + + gpointer data[GST_VIDEO_MAX_PLANES]; + + /* used for the conversion */ + GLuint fbo; + GLuint depth_buffer; + GLuint in_texture; + GLuint out_texture[GST_VIDEO_MAX_PLANES]; + GstGLShader *shader; +#ifdef OPENGL_ES2 + GLint shader_attr_position_loc; + GLint shader_attr_texture_loc; +#endif + + /* output data */ + GstVideoInfo info; + + /* */ + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLDownloadClass +{ + GObjectClass object_class; +}; + +GstGLDownload * gst_gl_download_new (GstGLDisplay * display); + +gboolean gst_gl_download_init_format (GstGLDownload * download, GstVideoFormat v_format, + guint width, guint height); +gboolean gst_gl_download_perform_with_memory (GstGLDownload * download, GstGLMemory * gl_mem); +gboolean gst_gl_download_perform_with_data (GstGLDownload * download, GLuint texture_id, + gpointer data[GST_VIDEO_MAX_PLANES]); + +GstGLDownload * gst_gl_display_find_download (GstGLDisplay * display, GstVideoFormat v_format, + guint width, guint height); + +G_END_DECLS + +#endif /* __GST_GL_DOWNLOAD_H__ */ diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c new file mode 100644 index 0000000..fefe2b0 --- /dev/null +++ b/gst-libs/gst/gl/gstglupload.c @@ -0,0 +1,1365 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstglupload.h" +#include "gstglmemory.h" + +static void _do_upload (GstGLDisplay * display, GstGLUpload * upload); +static void _do_upload_draw (GstGLDisplay * display, GstGLUpload * upload); +static void _do_upload_fill (GstGLDisplay * display, GstGLUpload * upload); +static void _do_upload_make (GstGLDisplay * display, GstGLUpload * upload); +static void _init_upload (GstGLDisplay * display, GstGLUpload * upload); +static void _init_upload_fbo (GstGLDisplay * display, GstGLUpload * upload); +static gboolean gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload, + GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]); + +/* YUY2:r,g,a + UYVY:a,b,r */ +static gchar *text_shader_YUY2_UYVY = +#ifndef OPENGL_ES2 + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect Ytex, UVtex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" "uniform sampler2D Ytex, UVtex;\n" +#endif + "void main(void) {\n" " float fx, fy, y, u, v, r, g, b;\n" +#ifndef OPENGL_ES2 + " fx = gl_TexCoord[0].x;\n" + " fy = gl_TexCoord[0].y;\n" + " y = texture2DRect(Ytex,vec2(fx,fy)).%c;\n" + " u = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n" + " v = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n" +#else + " fx = v_texCoord.x;\n" + " fy = v_texCoord.y;\n" + " y = texture2D(Ytex,vec2(fx,fy)).%c;\n" + " u = texture2D(UVtex,vec2(fx*0.5,fy)).%c;\n" + " v = texture2D(UVtex,vec2(fx*0.5,fy)).%c;\n" +#endif + " y=1.164*(y-0.0627);\n" + " u=u-0.5;\n" + " v=v-0.5;\n" + " r = y+1.5958*v;\n" + " g = y-0.39173*u-0.81290*v;\n" + " b = y+2.017*u;\n" " gl_FragColor = vec4(r, g, b, 1.0);\n" "}\n"; + +/* ATI: "*0.5", "" + normal: "", "*0.5" */ +static gchar *text_shader_I420_YV12 = +#ifndef OPENGL_ES2 + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect Ytex,Utex,Vtex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" "uniform sampler2D Ytex,Utex,Vtex;\n" +#endif + "void main(void) {\n" " float r,g,b,y,u,v;\n" +#ifndef OPENGL_ES2 + " vec2 nxy = gl_TexCoord[0].xy;\n" + " y=texture2DRect(Ytex,nxy%s).r;\n" + " u=texture2DRect(Utex,nxy%s).r;\n" " v=texture2DRect(Vtex,nxy*0.5).r;\n" +#else + " vec2 nxy = v_texCoord.xy;\n" + " y=texture2D(Ytex,nxy).r;\n" + " u=texture2D(Utex,nxy).r;\n" " v=texture2D(Vtex,nxy).r;\n" +#endif + " y=1.1643*(y-0.0625);\n" + " u=u-0.5;\n" + " v=v-0.5;\n" + " r=y+1.5958*v;\n" + " g=y-0.39173*u-0.81290*v;\n" + " b=y+2.017*u;\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\n"; + +static gchar *text_shader_AYUV = +#ifndef OPENGL_ES2 + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect tex;\n" +#else + "precision mediump float;\n" + "varying vec2 v_texCoord;\n" "uniform sampler2D tex;\n" +#endif + "void main(void) {\n" " float r,g,b,y,u,v;\n" +#ifndef OPENGL_ES2 + " vec2 nxy=gl_TexCoord[0].xy;\n" + " y=texture2DRect(tex,nxy).r;\n" + " u=texture2DRect(tex,nxy).g;\n" " v=texture2DRect(tex,nxy).b;\n" +#else + " vec2 nxy = v_texCoord.xy;\n" + " y=texture2D(tex,nxy).g;\n" + " u=texture2D(tex,nxy).b;\n" " v=texture2D(tex,nxy).a;\n" +#endif + " y=1.1643*(y-0.0625);\n" + " u=u-0.5;\n" + " v=v-0.5;\n" + " r=y+1.5958*v;\n" + " g=y-0.39173*u-0.81290*v;\n" + " b=y+2.017*u;\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\n"; + +#ifdef OPENGL_ES2 +static gchar *text_vertex_shader = + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " v_texCoord = a_texCoord; \n" "} \n"; +#endif + +GST_DEBUG_CATEGORY_STATIC (gst_gl_upload_debug); +#define GST_CAT_DEFAULT gst_gl_upload_debug + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_gl_upload_debug, "glupload", 0, "upload"); + +G_DEFINE_TYPE_WITH_CODE (GstGLUpload, gst_gl_upload, G_TYPE_OBJECT, DEBUG_INIT); +static void gst_gl_upload_finalize (GObject * object); + +#define GST_GL_UPLOAD_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ + GST_TYPE_GL_UPLOAD, GstGLUploadPrivate)) + +static void +gst_gl_upload_class_init (GstGLUploadClass * klass) +{ + G_OBJECT_CLASS (klass)->finalize = gst_gl_upload_finalize; +} + +static void +gst_gl_upload_init (GstGLUpload * upload) +{ + upload->display = NULL; + + g_mutex_init (&upload->lock); + + upload->fbo = 0; + upload->depth_buffer = 0; + upload->out_texture = 0; + upload->shader = NULL; + +#ifdef OPENGL_ES2 + upload->shader_attr_position_loc = 0; + upload->shader_attr_texture_loc = 0; +#endif + + gst_video_info_init (&upload->info); +} + +GstGLUpload * +gst_gl_upload_new (GstGLDisplay * display) +{ + GstGLUpload *upload; + + upload = g_object_new (GST_TYPE_GL_UPLOAD, NULL); + + upload->display = g_object_ref (display); + + g_mutex_init (&upload->lock); + + return upload; +} + +static void +gst_gl_upload_finalize (GObject * object) +{ + GstGLUpload *upload; + guint i; + + upload = GST_GL_UPLOAD (object); + + for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) { + if (upload->in_texture[i]) { + gst_gl_display_del_texture (upload->display, &upload->in_texture[i]); + upload->in_texture[i] = 0; + } + } + if (upload->out_texture) { + gst_gl_display_del_texture (upload->display, &upload->out_texture); + upload->out_texture = 0; + } + if (upload->fbo || upload->depth_buffer) { + gst_gl_display_del_fbo (upload->display, upload->fbo, upload->depth_buffer); + upload->fbo = 0; + upload->depth_buffer = 0; + } + if (upload->shader) { + g_object_unref (G_OBJECT (upload->shader)); + upload->shader = NULL; + } + + if (upload->display) { + g_object_unref (G_OBJECT (upload->display)); + upload->display = NULL; + } +} + +gboolean +gst_gl_upload_init_format (GstGLUpload * upload, GstVideoFormat v_format, + guint width, guint height) +{ + GstVideoInfo info; + + g_return_val_if_fail (upload != NULL, FALSE); + g_return_val_if_fail (v_format != GST_VIDEO_FORMAT_UNKNOWN, FALSE); + g_return_val_if_fail (v_format != GST_VIDEO_FORMAT_ENCODED, FALSE); + g_return_val_if_fail (width > 0 && height > 0, FALSE); + + g_mutex_lock (&upload->lock); + + if (upload->initted) { + g_mutex_unlock (&upload->lock); + return FALSE; + } else { + upload->initted = TRUE; + } + + gst_video_info_set_format (&info, v_format, width, height); + + upload->info = info; + + gst_gl_display_thread_add (upload->display, + (GstGLDisplayThreadFunc) _init_upload, upload); + + g_mutex_unlock (&upload->lock); + + return TRUE; +} + +gboolean +gst_gl_upload_perform_with_memory (GstGLUpload * upload, GstGLMemory * gl_mem) +{ + gpointer data[GST_VIDEO_MAX_PLANES]; + guint i; + gboolean ret; + + g_return_val_if_fail (upload != NULL, FALSE); + + if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_UPLOAD_INITTED)) + return FALSE; + + if (!GST_GL_MEMORY_FLAG_IS_SET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD)) + return FALSE; + + g_mutex_lock (&upload->lock); + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->info); i++) { + data[i] = (guint8 *) gl_mem->data + + GST_VIDEO_INFO_PLANE_OFFSET (&upload->info, i); + } + + ret = gst_gl_upload_perform_with_data_unlocked (upload, gl_mem->tex_id, data); + + GST_GL_MEMORY_FLAG_UNSET (gl_mem, GST_GL_MEMORY_FLAG_NEED_UPLOAD); + + g_mutex_unlock (&upload->lock); + + return ret; +} + +gboolean +gst_gl_upload_perform_with_data (GstGLUpload * upload, GLuint texture_id, + gpointer data[GST_VIDEO_MAX_PLANES]) +{ + gboolean ret; + + g_return_val_if_fail (upload != NULL, FALSE); + + g_mutex_lock (&upload->lock); + + ret = gst_gl_upload_perform_with_data_unlocked (upload, texture_id, data); + + g_mutex_unlock (&upload->lock); + + return ret; +} + +static gboolean +gst_gl_upload_perform_with_data_unlocked (GstGLUpload * upload, + GLuint texture_id, gpointer data[GST_VIDEO_MAX_PLANES]) +{ + guint i; + + g_return_val_if_fail (upload != NULL, FALSE); + g_return_val_if_fail (texture_id > 0, FALSE); + g_return_val_if_fail (GST_VIDEO_INFO_FORMAT (&upload->info) != + GST_VIDEO_FORMAT_UNKNOWN + && GST_VIDEO_INFO_FORMAT (&upload->info) != GST_VIDEO_FORMAT_ENCODED, + FALSE); + + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->info); i++) { + g_return_val_if_fail (data[i] != NULL, FALSE); + } + + upload->out_texture = texture_id; + for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&upload->info); i++) { + upload->data[i] = data[i]; + } + + gst_gl_display_thread_add (upload->display, + (GstGLDisplayThreadFunc) _do_upload, upload); + + return TRUE; +} + +GstGLUpload * +gst_gl_display_find_upload (GstGLDisplay * display, GstVideoFormat v_format, + guint width, guint height) +{ + GstGLUpload *ret; + guint64 *key; + + key = g_malloc (sizeof (guint64 *)); + *key = v_format | ((guint64) width << 6) | ((guint64) height << 35); + + gst_gl_display_lock (display); + + ret = g_hash_table_lookup (display->uploads, key); + + if (!ret) { + ret = gst_gl_upload_new (display); + + g_hash_table_insert (display->uploads, key, ret); + } + + gst_gl_display_unlock (display); + + return ret; +} + +/* Called in the gl thread */ +void +_init_upload (GstGLDisplay * display, GstGLUpload * upload) +{ + GstVideoFormat v_format; + + v_format = GST_VIDEO_INFO_FORMAT (&upload->info); + + GST_TRACE ("initializing texture upload for format:%d", v_format); + + switch (v_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 */ + /* shouldn't we require ARB_shading_language_100? --Filippo */ + if (GLEW_ARB_fragment_shader) { + +#ifdef OPENGL_ES2 + GError *error = NULL; +#endif + + GST_INFO ("Context, ARB_fragment_shader supported: yes"); + + display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL; + + _init_upload_fbo (display, upload); + + switch (v_format) { + case GST_VIDEO_FORMAT_YUY2: + { + gchar text_shader_YUY2[2048]; + sprintf (text_shader_YUY2, text_shader_YUY2_UYVY, 'r', 'g', 'a'); + + upload->shader = gst_gl_shader_new (); +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check (upload->shader, + text_shader_YUY2, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for uploading YUY2"); + g_object_unref (G_OBJECT (upload->shader)); + upload->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (upload->shader, + text_vertex_shader); + gst_gl_shader_set_fragment_source (upload->shader, + text_shader_YUY2); + + gst_gl_shader_compile (upload->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (upload->shader)); + display->shader = NULL; + } else { + upload->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_position"); + upload->shader_attr_texture_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_texCoord"); + } +#endif + } + break; + case GST_VIDEO_FORMAT_UYVY: + { + gchar text_shader_UYVY[2048]; + sprintf (text_shader_UYVY, +#ifndef OPENGL_ES2 + text_shader_YUY2_UYVY, 'a', 'b', 'r'); +#else + text_shader_YUY2_UYVY, 'a', 'r', 'b'); +#endif + + upload->shader = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check (upload->shader, + text_shader_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for uploading UYVY"); + g_object_unref (G_OBJECT (upload->shader)); + upload->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (upload->shader, + text_vertex_shader); + gst_gl_shader_set_fragment_source (upload->shader, + text_shader_UYVY); + + gst_gl_shader_compile (upload->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (display->shader)); + display->shader = NULL; + } else { + display->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_position"); + display->shader_upload_attr_texture_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_texCoord"); + } +#endif + } + break; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + { +#ifndef OPENGL_ES2 + gchar text_shader[2048]; + if ((g_ascii_strncasecmp ("ATI", (gchar *) glGetString (GL_VENDOR), + 3) == 0) + && (g_ascii_strncasecmp ("ATI Mobility Radeon HD", + (gchar *) glGetString (GL_RENDERER), 22) != 0) + && (g_ascii_strncasecmp ("ATI Radeon HD", + (gchar *) glGetString (GL_RENDERER), 13) != 0)) + sprintf (text_shader, text_shader_I420_YV12, "*0.5", ""); + else + sprintf (text_shader, text_shader_I420_YV12, "", "*0.5"); +#endif + + upload->shader = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check + (upload->shader, text_shader, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for uploading I420 or YV12"); + g_object_unref (G_OBJECT (upload->shader)); + upload->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (upload->shader, + text_vertex_shader); + gst_gl_shader_set_fragment_source (upload->shader, text_shader); + + gst_gl_shader_compile (upload->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (upload->shader)); + display->shader = NULL; + } else { + display->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_position"); + display->shader_attr_texture_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_texCoord"); + } +#endif + } + break; + case GST_VIDEO_FORMAT_AYUV: + { + upload->shader = gst_gl_shader_new (); + +#ifndef OPENGL_ES2 + if (!gst_gl_shader_compile_and_check (upload->shader, + text_shader_AYUV, GST_GL_SHADER_FRAGMENT_SOURCE)) { + gst_gl_display_set_error (display, + "Failed to initialize shader for uploading AYUV"); + g_object_unref (G_OBJECT (upload->shader)); + upload->shader = NULL; + } +#else + gst_gl_shader_set_vertex_source (upload->shader, + text_vertex_shader); + gst_gl_shader_set_fragment_source (upload->shader, + text_shader_AYUV); + + gst_gl_shader_compile (upload->shader, &error); + if (error) { + gst_gl_display_set_error (display, "%s", error->message); + g_error_free (error); + error = NULL; + gst_gl_shader_use (NULL); + g_object_unref (G_OBJECT (upload->shader)); + upload->shader = NULL; + } else { + upload->shader_attr_position_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_position"); + upload->shader_upload_attr_texture_loc = + gst_gl_shader_get_attribute_location + (upload->shader, "a_texCoord"); + } +#endif + } + break; + default: + gst_gl_display_set_error (display, + "Unsupported upload video format %d", v_format); + break; + } + } + /* 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 + */ + GST_INFO ("Context, ARB_fragment_shader supported: no"); + GST_INFO ("Context, GLEW_MESA_ycbcr_texture supported: yes"); + + display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MESA; + + switch (v_format) { + case GST_VIDEO_FORMAT_YUY2: + case GST_VIDEO_FORMAT_UYVY: + /* color space conversion is not needed */ + break; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + case GST_VIDEO_FORMAT_AYUV: + /* MESA only supports YUY2 and UYVY */ + gst_gl_display_set_error (display, + "Your MESA version only supports YUY2 and UYVY (GLSL is required for others yuv formats)"); + break; + default: + gst_gl_display_set_error (display, + "Unsupported upload video format %d", v_format); + break; + } + } + /* check if color matrix is available (not supported) */ + else if (GLEW_ARB_imaging) { + /* GLSL is not available on your drivers, switch to Color Matrix */ + GST_INFO ("Context, ARB_fragment_shader supported: no"); + GST_INFO ("Context, GLEW_MESA_ycbcr_texture supported: no"); + GST_INFO ("Context, GLEW_ARB_imaging supported: yes"); + + display->colorspace_conversion = GST_GL_DISPLAY_CONVERSION_MATRIX; + + gst_gl_display_set_error (display, + "Colorspace conversion using Color Matrix is not yet supported"); + } else { + /* colorspace conversion is not possible */ + gst_gl_display_set_error (display, + "ARB_fragment_shader supported, GLEW_ARB_imaging supported, GLEW_MESA_ycbcr_texture supported, not supported"); + } + } + break; + default: + gst_gl_display_set_error (display, "Unsupported upload video format %d", + v_format); + break; + } +} + + +/* called by _init_upload (in the gl thread) */ +void +_init_upload_fbo (GstGLDisplay * display, GstGLUpload * upload) +{ + guint width, height; + GLuint fake_texture = 0; /* a FBO must hava texture to init */ + + width = GST_VIDEO_INFO_WIDTH (&upload->info); + height = GST_VIDEO_INFO_HEIGHT (&upload->info); + + if (!GLEW_EXT_framebuffer_object) { + /* turn off the pipeline because Frame buffer object is a not present */ + gst_gl_display_set_error (display, + "Context, EXT_framebuffer_object supported: no"); + return; + } + + GST_INFO ("Context, EXT_framebuffer_object supported: yes"); + + /* setup FBO */ + glGenFramebuffersEXT (1, &upload->fbo); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, upload->fbo); + + /* setup the render buffer for depth */ + glGenRenderbuffersEXT (1, &upload->depth_buffer); + glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, upload->depth_buffer); +#ifndef OPENGL_ES2 + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, + width, height); + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, + width, height); +#else + glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, + width, height); +#endif + + /* 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, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + /* attach the texture to the FBO to renderer to */ + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, fake_texture, 0); + + /* attach the depth render buffer to the FBO */ + glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, upload->depth_buffer); + +#ifndef OPENGL_ES2 + glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, upload->depth_buffer); +#endif + + gst_gl_display_check_framebuffer_status (); + + if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != + GL_FRAMEBUFFER_COMPLETE_EXT) + gst_gl_display_set_error (display, "GL framebuffer status incomplete"); + + /* unbind the FBO */ + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); + + glDeleteTextures (1, &fake_texture); + + _do_upload_make (display, upload); +} + +/* Called by the idle function in the gl thread */ +void +_do_upload (GstGLDisplay * display, GstGLUpload * upload) +{ + GstVideoFormat v_format; + guint width, height; + + width = GST_VIDEO_INFO_WIDTH (&upload->info); + height = GST_VIDEO_INFO_HEIGHT (&upload->info); + v_format = GST_VIDEO_INFO_FORMAT (&upload->info); + + GST_TRACE ("uploading texture:%u dimensions: %ux%u", upload->out_texture, + width, height); + + _do_upload_fill (display, upload); + + switch (v_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: + { + switch (display->colorspace_conversion) { + case GST_GL_DISPLAY_CONVERSION_GLSL: + /* color space conversion is needed */ + _do_upload_draw (display, upload); + break; + case GST_GL_DISPLAY_CONVERSION_MATRIX: + /* color space conversion is needed */ + /* not yet supported */ + break; + case GST_GL_DISPLAY_CONVERSION_MESA: + /* color space conversion is not needed */ + break; + default: + gst_gl_display_set_error (display, "Unknown colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + } + break; + default: + gst_gl_display_set_error (display, "Unsupported upload video format %d", + v_format); + g_assert_not_reached (); + break; + } +} + +/* called by gst_gl_display_thread_do_upload (in the gl thread) */ +void +_do_upload_make (GstGLDisplay * display, GstGLUpload * upload) +{ + GstVideoFormat v_format; + guint width, height; + + width = GST_VIDEO_INFO_WIDTH (&upload->info); + height = GST_VIDEO_INFO_HEIGHT (&upload->info); + v_format = GST_VIDEO_INFO_FORMAT (&upload->info); + + glGenTextures (1, &upload->in_texture[0]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + switch (v_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: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, + width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + break; + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_BGR: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, + width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + break; + case GST_VIDEO_FORMAT_AYUV: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, + width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL); + break; + case GST_VIDEO_FORMAT_YUY2: + 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); + glGenTextures (1, &upload->in_texture[1]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + 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: + gst_gl_display_set_error (display, "Unknown colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + 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); + glGenTextures (1, &upload->in_texture[1]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + 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: + gst_gl_display_set_error (display, "Unknown colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + break; + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &upload->in_texture[1]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + GST_ROUND_UP_2 (width) / 2, + GST_ROUND_UP_2 (height) / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + + glGenTextures (1, &upload->in_texture[2]); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[2]); + glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, + GST_ROUND_UP_2 (width) / 2, + GST_ROUND_UP_2 (height) / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); + break; + + default: + gst_gl_display_set_error (display, "Unsupported upload video format %d", + v_format); + g_assert_not_reached (); + break; + } +} + + +/* called by gst_gl_display_thread_do_upload (in the gl thread) */ +void +_do_upload_fill (GstGLDisplay * display, GstGLUpload * upload) +{ + GstVideoFormat v_format; + guint width, height; + + width = GST_VIDEO_INFO_WIDTH (&upload->info); + height = GST_VIDEO_INFO_HEIGHT (&upload->info); + v_format = GST_VIDEO_INFO_FORMAT (&upload->info); + + switch (v_format) { + case GST_VIDEO_FORMAT_RGB: + case GST_VIDEO_FORMAT_BGR: + 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: + /* color space conversion is not needed */ + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->out_texture); + 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: + switch (display->colorspace_conversion) { + case GST_GL_DISPLAY_CONVERSION_GLSL: + case GST_GL_DISPLAY_CONVERSION_MATRIX: + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + break; + case GST_GL_DISPLAY_CONVERSION_MESA: + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->out_texture); + break; + default: + gst_gl_display_set_error (display, "Unknown colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + break; + default: + gst_gl_display_set_error (display, "Unsupported upload video format %d", + v_format); + g_assert_not_reached (); + break; + } + + switch (v_format) { + case GST_VIDEO_FORMAT_RGB: + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_RGB, GL_UNSIGNED_BYTE, upload->data[0]); + break; + case GST_VIDEO_FORMAT_BGR: + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_BGR, GL_UNSIGNED_BYTE, upload->data[0]); + break; + case GST_VIDEO_FORMAT_RGBx: + case GST_VIDEO_FORMAT_RGBA: + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_RGBA, GL_UNSIGNED_BYTE, upload->data[0]); + break; + case GST_VIDEO_FORMAT_BGRx: + case GST_VIDEO_FORMAT_BGRA: + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_BGRA, GL_UNSIGNED_BYTE, upload->data[0]); + break; + case GST_VIDEO_FORMAT_AYUV: + case GST_VIDEO_FORMAT_xRGB: + case GST_VIDEO_FORMAT_ARGB: + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, upload->data[0]); + break; + case GST_VIDEO_FORMAT_xBGR: + case GST_VIDEO_FORMAT_ABGR: + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, upload->data[0]); + break; + case GST_VIDEO_FORMAT_YUY2: + 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, upload->data[0]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + 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, upload->data[0]); + 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, upload->data[0]); + break; + default: + gst_gl_display_set_error (display, "Unknow colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + 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, upload->data[0]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + 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, upload->data[0]); + 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, upload->data[0]); + break; + default: + gst_gl_display_set_error (display, "Unknow colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + break; + case GST_VIDEO_FORMAT_I420: + { + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_LUMINANCE, GL_UNSIGNED_BYTE, upload->data[0]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, + GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2, + GL_LUMINANCE, GL_UNSIGNED_BYTE, upload->data[1]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[2]); + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, + GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2, + GL_LUMINANCE, GL_UNSIGNED_BYTE, upload->data[2]); + } + break; + case GST_VIDEO_FORMAT_YV12: /* same as I420 except plane 1+2 swapped */ + { + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height, + GL_LUMINANCE, GL_UNSIGNED_BYTE, upload->data[0]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[2]); + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, + GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2, + GL_LUMINANCE, GL_UNSIGNED_BYTE, upload->data[1]); + + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, + GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2, + GL_LUMINANCE, GL_UNSIGNED_BYTE, upload->data[2]); + } + break; + default: + gst_gl_display_set_error (display, "Unsupported upload video format %d", + v_format); + g_assert_not_reached (); + break; + } + + /* make sure no texture is in use in our opengl context + * in case we want to use the upload texture in an other opengl context + */ + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0); +} + + +/* called by _do_upload (in the gl thread) */ +void +_do_upload_draw (GstGLDisplay * display, GstGLUpload * upload) +{ + GstVideoFormat v_format; + guint width, height; + +#ifdef OPENGL_ES2 + GLint viewport_dim[4]; + + const GLfloat vVertices[] = { 1.0f, -1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, + 0.0f, .0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f + }; + + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; +#endif + + width = GST_VIDEO_INFO_WIDTH (&upload->info); + height = GST_VIDEO_INFO_HEIGHT (&upload->info); + v_format = GST_VIDEO_INFO_FORMAT (&upload->info); + + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, upload->fbo); + + /* setup a texture to render to */ +#ifndef OPENGL_ES2 + glEnable (GL_TEXTURE_RECTANGLE_ARB); +#endif + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->out_texture); + + /* attach the texture to the FBO to renderer to */ + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, upload->out_texture, 0); + + if (GLEW_ARB_fragment_shader) + gst_gl_shader_use (NULL); + +#ifndef OPENGL_ES2 + glPushAttrib (GL_VIEWPORT_BIT); + + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + gluOrtho2D (0.0, width, 0.0, height); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + glLoadIdentity (); +#else /* OPENGL_ES2 */ + glGetIntegerv (GL_VIEWPORT, viewport_dim); +#endif + + glViewport (0, 0, width, height); + +#ifndef OPENGL_ES2 + glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); +#endif + + glClearColor (0.0, 0.0, 0.0, 0.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + switch (v_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: + { +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); +#else + glVertexAttribPointer (upload->shader_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); + glVertexAttribPointer (upload->shader_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (upload->shader_attr_position_loc); + glEnableVertexAttribArray (upload->shader_attr_texture_loc); +#endif + +#ifndef OPENGL_ES2 + glEnable (GL_TEXTURE_RECTANGLE_ARB); +#endif + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); +#ifndef OPENGL_ES2 + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#endif + } + 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: + { + gst_gl_shader_use (upload->shader); + +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); +#else + glVertexAttribPointer (upload->shader_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); + glVertexAttribPointer (upload->shader_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (upload->shader_attr_position_loc); + glEnableVertexAttribArray (upload->shader_attr_texture_loc); +#endif + + glActiveTextureARB (GL_TEXTURE1_ARB); + gst_gl_shader_set_uniform_1i (upload->shader, "UVtex", 1); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (upload->shader, "Ytex", 0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + } + break; + case GST_GL_DISPLAY_CONVERSION_MESA: + { + +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glEnable (GL_TEXTURE_RECTANGLE_ARB); +#endif + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); +#ifndef OPENGL_ES2 + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#endif + } + break; + default: + gst_gl_display_set_error (display, "Unknow colorspace conversion %d", + display->colorspace_conversion); + g_assert_not_reached (); + break; + } + } + break; + + case GST_VIDEO_FORMAT_I420: + case GST_VIDEO_FORMAT_YV12: + { + gst_gl_shader_use (upload->shader); + +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); +#else + glVertexAttribPointer (upload->shader_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); + glVertexAttribPointer (upload->shader_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (upload->shader_attr_position_loc); + glEnableVertexAttribArray (upload->shader_attr_texture_loc); +#endif + + glActiveTextureARB (GL_TEXTURE1_ARB); + gst_gl_shader_set_uniform_1i (upload->shader, "Utex", 1); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[1]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + glActiveTextureARB (GL_TEXTURE2_ARB); + gst_gl_shader_set_uniform_1i (upload->shader, "Vtex", 2); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[2]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (upload->shader, "Ytex", 0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + } + break; + + case GST_VIDEO_FORMAT_AYUV: + { + gst_gl_shader_use (upload->shader); + +#ifndef OPENGL_ES2 + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); +#else + glVertexAttribPointer (upload->shader_attr_position_loc, 3, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices); + glVertexAttribPointer (upload->shader_attr_texture_loc, 2, + GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]); + + glEnableVertexAttribArray (upload->shader_attr_position_loc); + glEnableVertexAttribArray (upload->shader_attr_texture_loc); +#endif + + glActiveTextureARB (GL_TEXTURE0_ARB); + gst_gl_shader_set_uniform_1i (upload->shader, "tex", 0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, upload->in_texture[0]); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + } + break; + + default: + gst_gl_display_set_error (display, "Unsupported upload video format %d", + v_format); + g_assert_not_reached (); + break; + + } /* end switch display->currentVideo_format */ + +#ifndef OPENGL_ES2 + glBegin (GL_QUADS); + glTexCoord2i (width, 0); + glVertex2f (1.0f, -1.0f); + glTexCoord2i (0, 0); + glVertex2f (-1.0f, -1.0f); + glTexCoord2i (0, height); + glVertex2f (-1.0f, 1.0f); + glTexCoord2i (width, height); + glVertex2f (1.0f, 1.0f); + glEnd (); + + glDrawBuffer (GL_NONE); +#else /* OPENGL_ES2 */ + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); +#endif + + /* we are done with the shader */ + if (display->colorspace_conversion == GST_GL_DISPLAY_CONVERSION_GLSL) + glUseProgramObjectARB (0); + +#ifndef OPENGL_ES2 + glDisable (GL_TEXTURE_RECTANGLE_ARB); + + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); + glPopAttrib (); +#else + glViewport (viewport_dim[0], viewport_dim[1], viewport_dim[2], + viewport_dim[3]); +#endif + + gst_gl_display_check_framebuffer_status (); + + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0); +} diff --git a/gst-libs/gst/gl/gstglupload.h b/gst-libs/gst/gl/gstglupload.h new file mode 100644 index 0000000..ebe63b0 --- /dev/null +++ b/gst-libs/gst/gl/gstglupload.h @@ -0,0 +1,95 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * + * 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. + */ + +#ifndef __GST_GL_UPLOAD_H__ +#define __GST_GL_UPLOAD_H__ + +#include +#include + +#include "gstglshader.h" +#include "gstgldisplay.h" + +G_BEGIN_DECLS + +/* forward declare */ +typedef struct _GstGLMemory GstGLMemory; +typedef struct _GstGLDisplay GstGLDisplay; + +GType gst_gl_upload_get_type (void); +#define GST_TYPE_GL_UPLOAD (gst_gl_upload_get_type()) +#define GST_GL_UPLOAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_UPLOAD,GstGLUpload)) +#define GST_GL_UPLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLUploadClass)) +#define GST_IS_GL_UPLOAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_UPLOAD)) +#define GST_IS_GL_UPLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_UPLOAD)) +#define GST_GL_UPLOAD_CAST(obj) ((GstGLUpload*)(obj)) + +typedef struct _GstGLUpload GstGLUpload; +typedef struct _GstGLUploadClass GstGLUploadClass; + +struct _GstGLUpload +{ + GObject parent; + + GMutex lock; + + GstGLDisplay *display; + + gpointer data[GST_VIDEO_MAX_PLANES]; + gboolean initted; + + /* used for the conversion */ + GLuint fbo; + GLuint depth_buffer; + GLuint out_texture; + GLuint in_texture[GST_VIDEO_MAX_PLANES]; + GstGLShader *shader; +#ifdef OPENGL_ES2 + GLint shader_attr_position_loc; + GLint shader_attr_texture_loc; +#endif + + /* output data */ + GstVideoInfo info; + + /* */ + gpointer _reserved[GST_PADDING]; +}; + +struct _GstGLUploadClass +{ + GObjectClass object_class; +}; + +GstGLUpload * gst_gl_upload_new (GstGLDisplay * display); + +gboolean gst_gl_upload_init_format (GstGLUpload * upload, GstVideoFormat v_format, + guint width, guint height); + +gboolean gst_gl_upload_perform_with_memory (GstGLUpload * upload, GstGLMemory * gl_mem); +gboolean gst_gl_upload_perform_with_data (GstGLUpload * upload, GLuint texture_id, + gpointer data[GST_VIDEO_MAX_PLANES]); + +GstGLUpload * gst_gl_display_find_upload (GstGLDisplay * display, GstVideoFormat v_format, + guint width, guint height); + +G_END_DECLS + +#endif /* __GST_GL_UPLOAD_H__ */