void gst_gl_display_thread_run_generic (GstGLDisplay * display);
void gst_gl_display_thread_gen_texture (GstGLDisplay * display);
void gst_gl_display_thread_del_texture (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);
display->redisplay_texture = 0;
display->redisplay_texture_width = 0;
display->redisplay_texture_height = 0;
+#ifdef OPENGL_ES2
+ display->redisplay_shader = NULL;
+ display->redisplay_attr_position_loc = 0;
+ display->redisplay_attr_texture_loc = 0;
+#endif
//action gen and del texture
display->gen_texture = 0;
display->gen_shader = NULL;
display->del_shader = NULL;
- //fragement shader upload
+ //fragment shader upload
display->shader_upload_YUY2 = NULL;
display->shader_upload_UYVY = NULL;
display->shader_upload_I420_YV12 = NULL;
display->shader_upload_AYUV = NULL;
- //fragement shader download
+#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"
- " fx = gl_TexCoord[0].x;\n"
- " fy = gl_TexCoord[0].y;\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";
+ " 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"
- " vec2 nxy=gl_TexCoord[0].xy;\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";
+ " 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=clamp(y+1.5958*v, 0, 1);\n"
- " g=clamp(y-0.39173*u-0.81290*v, 0, 1);\n"
- " b=clamp(y+2.017*u, 0, 1);\n" " gl_FragColor=vec4(r,g,b,1.0);\n" "}\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"
" 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";
-
+ " 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"
" 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";
+ " 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" " gl_FragColor=vec4(y,u,v,1.0);\n" "}\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
+ display->redisplay_vertex_shader_str =
+ "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->redisplay_fragment_shader_str =
+ "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";
+
+ 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
}
static void
g_string_free (opengl_version, TRUE);
+#ifndef OPENGL_ES2
if ((opengl_version_major < 1) ||
(GLEW_VERSION_MAJOR < 1) ||
(opengl_version_major < 2 && opengl_version_major >= 1
GST_WARNING ("Required OpenGL >= 1.2.0 and Glew >= 1.4.0");
display->isAlive = FALSE;
}
+#else
+ if (!GL_ES_VERSION_2_0) {
+ GST_WARNING ("Required OpenGL ES > 2.0");
+ display->isAlive = FALSE;
+ }
+#endif
}
//setup callbacks
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:
display->upload_intex_v = 0;
}
+#ifdef OPENGL_ES2
+ if (display->redisplay_shader) {
+ g_object_unref (G_OBJECT (display->redisplay_shader));
+ display->redisplay_shader = NULL;
+ }
+#endif
+
GST_INFO ("Cleaning texture pool");
//clean up the texture pool
display->del_texture_width, display->del_texture_height);
}
+#ifdef OPENGL_ES2
+/* Called in the gl thread */
+void
+gst_gl_display_thread_init_redisplay (GstGLDisplay * display)
+{
+ GError *error = NULL;
+ display->redisplay_shader = gst_gl_shader_new ();
+
+ gst_gl_shader_set_vertex_source(display->redisplay_shader,
+ display->redisplay_vertex_shader_str);
+ gst_gl_shader_set_fragment_source(display->redisplay_shader,
+ display->redisplay_fragment_shader_str);
+
+ gst_gl_shader_compile (display->redisplay_shader, &error);
+ if (error) {
+ GST_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ } else {
+ display->redisplay_attr_position_loc =
+ gst_gl_shader_get_attribute_location (display->redisplay_shader,
+ "a_position");
+ display->redisplay_attr_texture_loc =
+ gst_gl_shader_get_attribute_location (display->redisplay_shader,
+ "a_texCoord");
+ }
+}
+#endif
+
/* Called in the gl thread */
void
//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->upload_colorspace_conversion = GST_GL_DISPLAY_CONVERSION_GLSL;
display->text_shader_upload_YUY2_UYVY, 'r', 'g', 'a');
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)) {
display->isAlive = FALSE;
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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,
+#ifndef OPENGL_ES2
display->text_shader_upload_YUY2_UYVY, 'a', 'b', 'r');
+#else
+ display->text_shader_upload_YUY2_UYVY, 'a', 'r', 'b');
+#endif
display->shader_upload_UYVY = gst_gl_shader_new ();
+
+#ifndef OPENGL_ES2
if (!gst_gl_shader_compile_and_check (display->shader_upload_UYVY,
text_shader_upload_UYVY, GST_GL_SHADER_FRAGMENT_SOURCE)) {
display->isAlive = FALSE;
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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)
else
sprintf (text_shader_upload_I420_YV12,
display->text_shader_upload_I420_YV12, "", "*0.5");
+#endif
display->shader_upload_I420_YV12 = gst_gl_shader_new ();
+
+#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)) {
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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");
+ }
+#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)) {
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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:
g_assert_not_reached ();
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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:
//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:
{
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)) {
display->isAlive = FALSE;
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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:
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)) {
display->isAlive = FALSE;
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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:
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)) {
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_ERROR ("%s", error->message);
+ g_error_free (error);
+ error = NULL;
+ gst_gl_shader_use (NULL);
+ display->isAlive = FALSE;
+ 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:
g_assert_not_reached ();
void
gst_gl_display_thread_use_fbo (GstGLDisplay * display)
{
+#ifdef OPENGL_ES2
+ GLint viewport_dim[4];
+#endif
+
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->use_fbo);
//setup a texture to render to
if (GLEW_ARB_fragment_shader)
gst_gl_shader_use (NULL);
-
+#ifndef OPENGL_ES2
glPushAttrib (GL_VIEWPORT_BIT);
-
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
+#else // OPENGL_ES2
+ glGetIntegerv(GL_VIEWPORT, viewport_dim);
+#endif
glViewport (0, 0, display->use_fbo_width, display->use_fbo_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);
display->input_texture_height, display->input_texture,
display->use_fbo_stuff);
+#ifndef OPENGL_ES2
glDrawBuffer (GL_NONE);
-
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
glPopAttrib ();
+#else
+ glViewport(viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]);
+#endif
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
}
//default reshape
else {
glViewport (0, 0, width, height);
+#ifndef OPENGL_ES2
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (0, width, 0, height);
glMatrixMode (GL_MODELVIEW);
+#endif
}
}
//default opengl scene
else {
+#ifndef OPENGL_ES2
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glEnd ();
glDisable (GL_TEXTURE_RECTANGLE_ARB);
- } //end default opengl scene
+
+#else //OPENGL_ES2
+
+ 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 };
+
+ glClear (GL_COLOR_BUFFER_BIT);
+
+ gst_gl_shader_use (display->redisplay_shader);
+
+ //Load the vertex position
+ glVertexAttribPointer (display->redisplay_attr_position_loc, 3, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), vVertices);
+
+ //Load the texture coordinate
+ glVertexAttribPointer (display->redisplay_attr_texture_loc, 2, GL_FLOAT,
+ GL_FALSE, 5 * sizeof(GLfloat), &vVertices[3]);
+
+ glEnableVertexAttribArray (display->redisplay_attr_position_loc);
+ glEnableVertexAttribArray (display->redisplay_attr_texture_loc);
+
+ glActiveTexture (GL_TEXTURE0);
+ glBindTexture (GL_TEXTURE_2D, display->redisplay_texture);
+ gst_gl_shader_set_uniform_1i (display->redisplay_shader, "s_texture", 0);
+
+ glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+#endif
+
+ }//end default opengl scene
}
gst_gl_display_lock (display);
isAlive = display->isAlive;
if (isAlive) {
+
+#ifdef OPENGL_ES2
+ if (!display->redisplay_shader) {
+ gst_gl_window_send_message (display->gl_window,
+ GST_GL_WINDOW_CB (gst_gl_display_thread_init_redisplay), display);
+ }
+#endif
+
if (texture) {
display->redisplay_texture = texture;
display->redisplay_texture_width = width;
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
if (GLEW_ARB_fragment_shader)
gst_gl_shader_use (NULL);
+#ifndef OPENGL_ES2
glPushAttrib (GL_VIEWPORT_BIT);
glMatrixMode (GL_PROJECTION);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
+#else // OPENGL_ES2
+ glGetIntegerv(GL_VIEWPORT, viewport_dim);
+#endif
glViewport (0, 0, display->upload_width, display->upload_height);
- glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT);
+#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);
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
glEnable (GL_TEXTURE_RECTANGLE_ARB);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex);
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
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);
break;
case GST_GL_DISPLAY_CONVERSION_MESA:
{
+
+#ifndef OPENGL_ES2
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
+#endif
glEnable (GL_TEXTURE_RECTANGLE_ARB);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->upload_intex);
{
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",
{
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);
} //end switch display->currentVideo_format
+#ifndef OPENGL_ES2
glBegin (GL_QUADS);
glTexCoord2i (display->upload_data_width, 0);
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);
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
glPopAttrib ();
+#else
+ glViewport(viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]);
+#endif
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
GstVideoFormat video_format = display->download_video_format;
gpointer data = display->download_data;
+#ifndef OPENGL_ES2
glEnable (GL_TEXTURE_RECTANGLE_ARB);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->ouput_texture);
+#else
+ gint width = display->ouput_texture_width;
+ gint height = display->ouput_texture_height;
+
+ 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);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+
+ glReadBuffer (GL_BACK);
+#endif
switch (video_format) {
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_xRGB:
case GST_VIDEO_FORMAT_ARGB:
+#ifndef OPENGL_ES2
glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data);
+#else
+ glReadPixels (0, 0, width, height, GL_RGBA,
+ GL_UNSIGNED_BYTE, data);
+#endif
break;
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_xBGR:
case GST_VIDEO_FORMAT_ABGR:
+#ifndef OPENGL_ES2
glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
GL_UNSIGNED_BYTE, data);
+#endif
break;
case GST_VIDEO_FORMAT_RGB:
+#ifndef OPENGL_ES2
glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB,
GL_UNSIGNED_BYTE, data);
+#else
+ glReadPixels (0, 0, width, height, GL_RGB,
+ GL_UNSIGNED_BYTE, data);
+#endif
break;
case GST_VIDEO_FORMAT_BGR:
+#ifndef OPENGL_ES2
glGetTexImage (GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGR,
GL_UNSIGNED_BYTE, data);
+#endif
break;
default:
g_assert_not_reached ();
GstVideoFormat video_format = display->download_video_format;
gpointer data = display->download_data;
+#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->download_fbo);
+#ifndef OPENGL_ES2
glPushAttrib (GL_VIEWPORT_BIT);
glMatrixMode (GL_PROJECTION);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
+#else // OPENGL_ES2
+ glGetIntegerv(GL_VIEWPORT, viewport_dim);
+#endif
glViewport (0, 0, width, height);
default:
g_assert_not_reached ();
}
-
+#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);
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",
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);
} //end switch display->currentVideo_format
+#ifndef OPENGL_ES2
glBegin (GL_QUADS);
glTexCoord2i (0, 0);
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 for now download is not available
- //without GLSL
+ //because download yuv is not available
+ //without GLSL (whereas rgb is)
glUseProgramObjectARB (0);
glDisable (GL_TEXTURE_RECTANGLE_ARB);
+#ifndef OPENGL_ES2
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
glPopAttrib ();
+#else
+ glViewport(viewport_dim[0], viewport_dim[1], viewport_dim[2], viewport_dim[3]);
+#endif
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
g_assert_not_reached ();
}
+ glReadBuffer (GL_NONE);
+
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
gst_gl_display_check_framebuffer_status ();
}
--- /dev/null
+/*
+ * GStreamer
+ * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglwindow.h"
+
+#define WM_GST_GL_WINDOW_CUSTOM (WM_APP+1)
+#define WM_GST_GL_WINDOW_QUIT (WM_APP+2)
+
+LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+const gchar* EGLErrorString();
+
+#define GST_GL_WINDOW_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_WINDOW, GstGLWindowPrivate))
+
+enum
+{
+ PROP_0
+};
+
+struct _GstGLWindowPrivate
+{
+ EGLNativeWindowType internal_win_id;
+ EGLDisplay display;
+ EGLSurface surface;
+ EGLContext gl_context;
+ GstGLWindowCB draw_cb;
+ gpointer draw_data;
+ GstGLWindowCB2 resize_cb;
+ gpointer resize_data;
+ GstGLWindowCB close_cb;
+ gpointer close_data;
+ gboolean is_closed;
+ gboolean visible;
+};
+
+G_DEFINE_TYPE (GstGLWindow, gst_gl_window, G_TYPE_OBJECT);
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "GstGLWindow"
+
+gboolean _gst_gl_window_debug = FALSE;
+
+HHOOK hHook;
+
+/* Must be called in the gl thread */
+static void
+gst_gl_window_finalize (GObject * object)
+{
+ GstGLWindow *window = GST_GL_WINDOW (object);
+ GstGLWindowPrivate *priv = window->priv;
+
+ G_OBJECT_CLASS (gst_gl_window_parent_class)->finalize (object);
+}
+
+static void
+gst_gl_window_log_handler (const gchar *domain, GLogLevelFlags flags,
+ const gchar *message, gpointer user_data)
+{
+ if (_gst_gl_window_debug) {
+ g_log_default_handler (domain, flags, message, user_data);
+ }
+}
+
+static void
+gst_gl_window_base_init (gpointer g_class)
+{
+}
+
+static void
+gst_gl_window_class_init (GstGLWindowClass * klass)
+{
+ GObjectClass *obj_class = G_OBJECT_CLASS (klass);
+ WNDCLASS wc;
+ ATOM atom = 0;
+ HINSTANCE hinstance = GetModuleHandle (NULL);
+
+ g_type_class_add_private (klass, sizeof (GstGLWindowPrivate));
+
+ obj_class->finalize = gst_gl_window_finalize;
+
+ atom = GetClassInfo (hinstance, "GSTGL", &wc);
+
+ if (atom == 0)
+ {
+ ZeroMemory (&wc, sizeof(WNDCLASS));
+
+ wc.lpfnWndProc = window_proc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hinstance;
+ wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
+ wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "GSTGL";
+
+ atom = RegisterClass (&wc);
+
+ if (atom == 0)
+ g_error ("Failed to register window class %x\r\n", GetLastError());
+ }
+}
+
+static void
+gst_gl_window_init (GstGLWindow *window)
+{
+ window->priv = GST_GL_WINDOW_GET_PRIVATE (window);
+
+ if (g_getenv ("GST_GL_WINDOW_DEBUG") != NULL)
+ _gst_gl_window_debug = TRUE;
+
+ g_log_set_handler ("GstGLWindow", G_LOG_LEVEL_DEBUG,
+ gst_gl_window_log_handler, NULL);
+}
+
+/* Must be called in the gl thread */
+GstGLWindow *
+gst_gl_window_new (gint width, gint height)
+{
+ GstGLWindow *window = g_object_new (GST_GL_TYPE_WINDOW, NULL);
+ GstGLWindowPrivate *priv = window->priv;
+ GstGLWindowClass* klass = GST_GL_WINDOW_GET_CLASS (window);
+
+ HINSTANCE hinstance = GetModuleHandle (NULL);
+
+ static gint x = 0;
+ static gint y = 0;
+
+ x += 20;
+ y += 20;
+
+ priv->internal_win_id = 0;
+ priv->display = 0;
+ priv->surface = 0;
+ priv->gl_context = 0;
+ priv->draw_cb = NULL;
+ priv->draw_data = NULL;
+ priv->resize_cb = NULL;
+ priv->resize_data = NULL;
+ priv->close_cb = NULL;
+ priv->close_data = NULL;
+ priv->is_closed = FALSE;
+ priv->visible = FALSE;
+
+ width += 2 * GetSystemMetrics (SM_CXSIZEFRAME);
+ height += 2 * GetSystemMetrics (SM_CYSIZEFRAME) + GetSystemMetrics (SM_CYCAPTION);
+
+ priv->internal_win_id = CreateWindow (
+ "GSTGL",
+ "OpenGL renderer",
+ WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, //WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION
+ x, y, width, height,
+ (HWND) NULL,
+ (HMENU) NULL,
+ hinstance,
+ window
+ );
+
+ if (!priv->internal_win_id)
+ {
+ g_debug ("failed to create gl window: %d\n", priv->internal_win_id);
+ return NULL;
+ }
+
+ g_debug ("gl window created: %d\n", priv->internal_win_id);
+
+ //display is set in the window_proc
+ if (!priv->display) {
+ g_object_unref (G_OBJECT (window));
+ return NULL;
+ }
+
+ ShowCursor (TRUE);
+
+ return window;
+}
+
+GQuark
+gst_gl_window_error_quark (void)
+{
+ return g_quark_from_static_string ("gst-gl-window-error");
+}
+
+void
+gst_gl_window_set_external_window_id (GstGLWindow *window, guint64 id)
+{
+ GstGLWindowPrivate *priv = window->priv;
+ WNDPROC window_parent_proc = (WNDPROC) (guint64) GetWindowLongPtr((HWND)id, GWL_WNDPROC);
+ RECT rect;
+
+ SetProp (priv->internal_win_id, "gl_window_parent_id", (HWND)id);
+ SetProp ((HWND)id, "gl_window_id", priv->internal_win_id);
+ SetProp ((HWND)id, "gl_window_parent_proc", (WNDPROC) window_parent_proc);
+ SetWindowLongPtr ((HWND)id, GWL_WNDPROC, (DWORD) (guint64) sub_class_proc);
+
+ SetWindowLongPtr (priv->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
+ SetParent (priv->internal_win_id, (HWND)id);
+
+ //take changes into account: SWP_FRAMECHANGED
+ GetClientRect ((HWND)id, &rect);
+ SetWindowPos (priv->internal_win_id, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom,
+ SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
+ MoveWindow (priv->internal_win_id, rect.left, rect.top, rect.right, rect.bottom, FALSE);
+}
+
+void
+gst_gl_window_set_external_gl_context (GstGLWindow *window, guint64 context)
+{
+ g_warning ("gst_gl_window_set_external_gl_context: not implemented\n");
+}
+
+/* Must be called in the gl thread */
+void
+gst_gl_window_set_draw_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data)
+{
+ GstGLWindowPrivate *priv = window->priv;
+
+ priv->draw_cb = callback;
+ priv->draw_data = data;
+}
+
+/* Must be called in the gl thread */
+void
+gst_gl_window_set_resize_callback (GstGLWindow *window, GstGLWindowCB2 callback , gpointer data)
+{
+ GstGLWindowPrivate *priv = window->priv;
+
+ priv->resize_cb = callback;
+ priv->resize_data = data;
+}
+
+/* Must be called in the gl thread */
+void
+gst_gl_window_set_close_callback (GstGLWindow *window, GstGLWindowCB callback, gpointer data)
+{
+ GstGLWindowPrivate *priv = window->priv;
+
+ priv->close_cb = callback;
+ priv->close_data = data;
+}
+
+void
+gst_gl_window_draw_unlocked (GstGLWindow *window)
+{
+ gst_gl_window_draw (window);
+}
+
+/* Thread safe */
+void
+gst_gl_window_draw (GstGLWindow *window)
+{
+ GstGLWindowPrivate *priv = window->priv;
+
+ if (!priv->visible)
+ {
+ ShowWindowAsync (priv->internal_win_id, SW_SHOW);
+ priv->visible = TRUE;
+ }
+
+ RedrawWindow (priv->internal_win_id, NULL, NULL,
+ RDW_NOERASE | RDW_INTERNALPAINT | RDW_INVALIDATE);
+}
+
+void
+gst_gl_window_run_loop (GstGLWindow *window)
+{
+ GstGLWindowPrivate *priv = window->priv;
+ gboolean running = TRUE;
+ gboolean bRet = FALSE;
+ MSG msg;
+
+ g_debug ("begin loop\n");
+
+ while (running && (bRet = GetMessage (&msg, NULL, 0, 0)) != 0)
+ {
+ if (bRet == -1)
+ {
+ g_error ("Failed to get message %x\r\n", GetLastError());
+ running = FALSE;
+ }
+ else
+ {
+ TranslateMessage (&msg);
+ DispatchMessage (&msg);
+ }
+ }
+
+ g_debug ("end loop\n");
+}
+
+/* Thread safe */
+void
+gst_gl_window_quit_loop (GstGLWindow *window, GstGLWindowCB callback, gpointer data)
+{
+ if (window)
+ {
+ GstGLWindowPrivate *priv = window->priv;
+ LRESULT res = PostMessage(priv->internal_win_id, WM_GST_GL_WINDOW_QUIT, (WPARAM) data, (LPARAM) callback);
+ g_assert (SUCCEEDED (res));
+ g_debug ("end loop requested\n");
+ }
+}
+
+/* Thread safe */
+void
+gst_gl_window_send_message (GstGLWindow *window, GstGLWindowCB callback, gpointer data)
+{
+ if (window)
+ {
+ GstGLWindowPrivate *priv = window->priv;
+ LRESULT res = SendMessage (priv->internal_win_id, WM_GST_GL_WINDOW_CUSTOM, (WPARAM) data, (LPARAM) callback);
+ g_assert (SUCCEEDED (res));
+ }
+}
+
+LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_CREATE) {
+
+ GstGLWindow *window = (GstGLWindow *) (((LPCREATESTRUCT) lParam)->lpCreateParams);
+
+ g_debug ("WM_CREATE\n");
+
+ g_assert (window);
+
+ {
+ EGLint majorVersion;
+ EGLint minorVersion;
+ EGLint numConfigs;
+ EGLConfig config;
+ EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
+
+ EGLint attribList[] =
+ {
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 8,
+ EGL_STENCIL_SIZE, 8,
+ EGL_SAMPLE_BUFFERS, EGL_DONT_CARE, //1
+ EGL_NONE
+ };
+
+ GstGLWindowPrivate *priv = window->priv;
+
+ priv->display = eglGetDisplay (GetDC (hWnd));
+ if (priv->display != EGL_NO_DISPLAY)
+ g_debug ("display retrieved: %d\n", priv->display);
+ else
+ g_debug ("failed to retrieve display %d, %s\n", hWnd, EGLErrorString());
+
+ if (eglInitialize (priv->display, &majorVersion, &minorVersion))
+ g_debug ("egl initialized: %d.%d\n", majorVersion, minorVersion);
+ else
+ g_debug ("failed to initialize egl %d, %s\n", priv->display, EGLErrorString());
+
+ if (eglGetConfigs (priv->display, NULL, 0, &numConfigs))
+ g_debug ("configs retrieved: %d\n", numConfigs);
+ else
+ g_debug ("failed to retrieve configs %d, %s\n", priv->display, EGLErrorString());
+
+ if (eglChooseConfig (priv->display, attribList, &config, 1, &numConfigs))
+ g_debug ("config set: %d, %d\n", config, numConfigs);
+ else
+ g_debug ("failed to set config %d, %s\n", priv->display, EGLErrorString());
+
+ priv->surface = eglCreateWindowSurface (priv->display, config, (EGLNativeWindowType)hWnd, NULL);
+ if (priv->surface != EGL_NO_SURFACE)
+ g_debug ("surface created: %d\n", priv->surface);
+ else
+ g_debug ("failed to create surface %d, %d, %d, %s\n", priv->display, priv->surface, hWnd, EGLErrorString());
+
+ priv->gl_context = eglCreateContext (priv->display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (priv->gl_context != EGL_NO_CONTEXT)
+ g_debug ("gl context created: %d\n", priv->gl_context);
+ else
+ g_debug ("failed to create glcontext %d, %d, s\n", priv->gl_context, hWnd, EGLErrorString());
+
+ ReleaseDC (hWnd, priv->display);
+
+ if (!eglMakeCurrent (priv->display, priv->surface, priv->surface, priv->gl_context))
+ g_debug ("failed to make opengl context current %d, %s\n", hWnd, EGLErrorString());
+ }
+
+ SetProp (hWnd, "gl_window", window);
+
+ return 0;
+ }
+ else if (GetProp(hWnd, "gl_window")) {
+
+ GstGLWindow *window = GetProp(hWnd, "gl_window");
+ GstGLWindowPrivate *priv = NULL;
+
+ g_assert (window);
+
+ priv = window->priv;
+
+ g_assert (priv);
+
+ g_assert (priv->internal_win_id == hWnd);
+
+ g_assert (priv->gl_context == eglGetCurrentContext());
+
+ switch ( uMsg ) {
+
+ case WM_SIZE:
+ {
+ if (priv->resize_cb)
+ priv->resize_cb (priv->resize_data, LOWORD(lParam), HIWORD(lParam));
+ break;
+ }
+
+ case WM_PAINT:
+ {
+ if (priv->draw_cb)
+ {
+ priv->draw_cb (priv->draw_data);
+ eglSwapBuffers (priv->display, priv->surface);
+ ValidateRect (hWnd, NULL);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ {
+ ShowWindowAsync (priv->internal_win_id, SW_HIDE);
+
+ if (priv->close_cb)
+ priv->close_cb (priv->close_data);
+
+ priv->draw_cb = NULL;
+ priv->draw_data = NULL;
+ priv->resize_cb = NULL;
+ priv->resize_data = NULL;
+ priv->close_cb = NULL;
+ priv->close_data = NULL;
+ break;
+ }
+
+ case WM_GST_GL_WINDOW_QUIT:
+ {
+ HWND parent_id = 0;
+ GstGLWindowCB destroy_cb = (GstGLWindowCB) lParam;
+
+ g_debug ("WM_CLOSE\n");
+
+ destroy_cb ((gpointer) wParam);
+
+ parent_id = GetProp (hWnd, "gl_window_parent_id");
+ if (parent_id)
+ {
+ WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc");
+
+ g_assert (parent_proc);
+
+ SetWindowLongPtr (parent_id, GWL_WNDPROC, (LONG) (guint64) parent_proc);
+ SetParent (hWnd, NULL);
+
+ RemoveProp (parent_id, "gl_window_parent_proc");
+ RemoveProp (hWnd, "gl_window_parent_id");
+ }
+
+ priv->is_closed = TRUE;
+ RemoveProp (hWnd, "gl_window");
+
+ if (!eglMakeCurrent (priv->display, priv->surface, priv->surface, EGL_NO_CONTEXT))
+ g_debug ("failed to make current null context %d, %s\n", priv->display, EGLErrorString());
+
+ if (priv->gl_context)
+ {
+ if (!eglDestroyContext (priv->display, priv->gl_context))
+ g_debug ("failed to destroy context %d, %s\n", priv->gl_context, EGLErrorString());
+ priv->gl_context = NULL;
+ }
+
+ if (priv->surface)
+ {
+ if (!eglDestroySurface (priv->display, priv->surface))
+ g_debug ("failed to destroy surface %d, %s\n", priv->surface, EGLErrorString());
+ priv->surface = NULL;
+ }
+
+ if (priv->surface)
+ {
+ if (!eglTerminate (priv->display))
+ g_debug ("failed to terminate display %d, %s\n", priv->display, EGLErrorString());
+ priv->surface = NULL;
+ }
+
+ if (priv->internal_win_id)
+ {
+ if (!DestroyWindow(priv->internal_win_id))
+ g_debug ("failed to destroy window %d, 0x%x\n", hWnd, GetLastError());
+ }
+
+ PostQuitMessage (0);
+ break;
+ }
+
+ case WM_CAPTURECHANGED:
+ {
+ g_debug ("WM_CAPTURECHANGED\n");
+ if (priv->draw_cb)
+ priv->draw_cb (priv->draw_data);
+ break;
+ }
+
+ case WM_GST_GL_WINDOW_CUSTOM:
+ {
+ if (!priv->is_closed)
+ {
+ GstGLWindowCB custom_cb = (GstGLWindowCB) lParam;
+ custom_cb ((gpointer) wParam);
+ }
+ break;
+ }
+
+ case WM_ERASEBKGND:
+ return TRUE;
+
+ default:
+ {
+ /* transmit messages to the parrent (ex: mouse/keyboard input) */
+ HWND parent_id = GetProp (hWnd, "gl_window_parent_id");
+ if (parent_id)
+ PostMessage (parent_id, uMsg, wParam, lParam);
+ return DefWindowProc (hWnd, uMsg, wParam, lParam);
+ }
+ }
+
+ return 0;
+ }
+ else
+ return DefWindowProc( hWnd, uMsg, wParam, lParam );
+}
+
+LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC window_parent_proc = GetProp (hWnd, "gl_window_parent_proc");
+
+ if (uMsg == WM_SIZE)
+ {
+ HWND gl_window_id = GetProp (hWnd, "gl_window_id");
+ MoveWindow (gl_window_id, 0, 0, LOWORD(lParam), HIWORD(lParam), FALSE);
+ }
+
+ return CallWindowProc (window_parent_proc, hWnd, uMsg, wParam, lParam);
+}
+
+const gchar* EGLErrorString()
+{
+ EGLint nErr = eglGetError();
+ switch(nErr){
+ case EGL_SUCCESS:
+ return "EGL_SUCCESS";
+ case EGL_BAD_DISPLAY:
+ return "EGL_BAD_DISPLAY";
+ case EGL_NOT_INITIALIZED:
+ return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS:
+ return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC:
+ return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE:
+ return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG:
+ return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT:
+ return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE:
+ return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_MATCH:
+ return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP:
+ return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW:
+ return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER:
+ return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE:
+ return "EGL_BAD_SURFACE";
+ default:
+ return "unknown";
+ }
+}