OpenGL 2.0 vo driver
Christophe Thommeret <[email protected]> Thu, 10 May 2012 14:36:08 +0200
| Newsgroups | gmane.comp.video.xine.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi all, I've recently used an ati videocard and found that XV support is .. well .. not so good :) So, i've gone for opengl, and found that this one is quite limited. I've then written an OpenGL 2.0 video out plugin. It of course requires an OGL2 GPU/driver. It should gracefully fail to open if requirements aren't met. (ARB_texture_rectangle, ARB_texture_non_power_of_two, ARB_pixel_buffer_object, ARB_framebuffer_object, ARB_fragment_shader) It supports the following features: - Color Space Conversion (YV12 and YUY2) - Crop, Zoom - Scaled and Unscaled overlays - Hue, Saturation, Contrast, Brightness - Sharpness - Bicubic scaling -- Christophe Thommeret ------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/ _______________________________________________ xine-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/xine-devel
opengl2.diff
(text/x-patch, 56.9 KB)
diff -r 3c08d65400c4 src/video_out/Makefile.am
--- a/src/video_out/Makefile.am Thu Apr 19 09:43:05 2012 +0300
+++ b/src/video_out/Makefile.am Thu May 10 14:14:18 2012 +0200
@@ -30,6 +30,7 @@
endif
if ENABLE_OPENGL
opengl_module = xineplug_vo_out_opengl.la
+opengl2_module = xineplug_vo_out_opengl2.la
endif
if ENABLE_SUNFB
if ENABLE_SUNDGA
@@ -104,6 +105,7 @@
xineplug_LTLIBRARIES = $(xshm_module) $(xv_module) $(xvmc_module) \
$(opengl_module) \
+ $(opengl2_module) \
$(pgx64_module) $(pgx32_module)\
$(vidix_module) \
$(aa_module) \
@@ -154,6 +156,10 @@
$(GLUT_LIBS) $(GLU_LIBS) $(X_LIBS) $(PTHREAD_LIBS) $(DYNAMIC_LD_LIBS) $(LTLIBINTL)
xineplug_vo_out_opengl_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) $(AVUTIL_CFLAGS) -fno-strict-aliasing
+xineplug_vo_out_opengl2_la_SOURCES = video_out_opengl2.c
+xineplug_vo_out_opengl2_la_LIBADD = $(YUV_LIBS) $(OPENGL_LIBS) $(X_LIBS) $(PTHREAD_LIBS) $(DYNAMIC_LD_LIBS) $(LTLIBINTL)
+xineplug_vo_out_opengl2_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) $(AVUTIL_CFLAGS) -fno-strict-aliasing
+
xineplug_vo_out_pgx64_la_SOURCES = video_out_pgx64.c
xineplug_vo_out_pgx64_la_LIBADD = $(XINE_LIB) $(X_LIBS) $(SUNDGA_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL)
xineplug_vo_out_pgx64_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)
diff -r 3c08d65400c4 src/video_out/video_out_opengl2.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video_out/video_out_opengl2.c Thu May 10 14:14:18 2012 +0200
@@ -0,0 +1,1682 @@
+/*
+ * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle; remove-trailing-space on;
+ * Copyright (C) 20012 the xine project
+ * Copyright (C) 20012 Christophe Thommeret <[email protected]>
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *
+ * video_out_opengl2.c, a video output plugin using opengl 2.0
+ *
+ *
+ */
+
+/* #define LOG */
+#define LOG_MODULE "video_out_opengl2"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pthread.h>
+
+#include <xine.h>
+#include <xine/video_out.h>
+#include <xine/vo_scale.h>
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+
+#include "yuv2rgb.h"
+
+#ifdef HAVE_FFMPEG_AVUTIL_H
+# include <mem.h>
+#else
+# include <libavutil/mem.h>
+#endif
+
+#define GL_GLEXT_PROTOTYPES
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glx.h>
+
+
+
+typedef int (*GLXSWAPINTERVALSGI) ( int );
+
+typedef struct {
+ vo_frame_t vo_frame;
+ int width, height, format, flags;
+ double ratio;
+} opengl2_frame_t;
+
+
+
+typedef struct {
+ uint8_t *ovl_rgba;
+ int ovl_w, ovl_h;
+ int ovl_x, ovl_y;
+
+ GLuint tex;
+ int tex_w, tex_h;
+
+ int unscaled;
+ int vid_scale;
+} opengl2_overlay_t;
+
+
+
+typedef struct {
+ int compiled;
+ GLuint shader;
+ GLuint program;
+} opengl2_program_t;
+
+
+
+typedef struct {
+ GLuint y, u, v;
+ GLuint yuv;
+ int width;
+ int height;
+} opengl2_yuvtex_t;
+
+
+
+typedef struct {
+
+ vo_driver_t vo_driver;
+ vo_scale_t sc;
+
+ Display *display;
+ int screen;
+ Drawable drawable;
+ GLXContext context;
+
+ int texture_float;
+ opengl2_program_t yuv420_program;
+ opengl2_program_t yuv422_program;
+ opengl2_yuvtex_t yuvtex;
+ GLuint videoPBO;
+ GLuint fbo;
+ GLuint videoTex, videoTex2;
+ GLXSWAPINTERVALSGI mglXSwapInterval;
+
+ int ovl_changed;
+ int ovl_vid_scale;
+ int num_ovls;
+ opengl2_overlay_t overlays[XINE_VORAW_MAX_OVL];
+ yuv2rgb_factory_t *yuv2rgb_factory;
+ yuv2rgb_t *ovl_yuv2rgb;
+
+ opengl2_program_t sharpness_program;
+ float csc_matrix[3 * 4];
+ float *color_standard;
+ int update_csc;
+ int saturation;
+ int contrast;
+ int brightness;
+ int hue;
+ int sharpness;
+
+ opengl2_program_t bicubic_pass1_program;
+ opengl2_program_t bicubic_pass2_program;
+ GLuint bicubic_lut_texture;
+ GLuint bicubic_pass1_texture;
+ int bicubic_pass1_texture_width;
+ int bicubic_pass1_texture_height;
+ GLuint bicubic_fbo;
+ int scale_bicubic;
+
+ pthread_mutex_t drawable_lock;
+ uint32_t display_width;
+ uint32_t display_height;
+
+ config_values_t *config;
+
+ uint32_t capabilities;
+ xine_t *xine;
+
+ int zoom_x;
+ int zoom_y;
+} opengl2_driver_t;
+
+
+
+typedef struct {
+ video_driver_class_t driver_class;
+ GLXContext ctx;
+ xine_t *xine;
+} opengl2_class_t;
+
+
+
+static const char *bicubic_pass1_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect tex, lut;\n"
+"uniform float spline;\n"
+"void main() {\n"
+" vec2 coord = gl_TexCoord[0].xy;\n"
+" vec2 TexCoord = vec2( floor( coord.x - 0.5 ) + 0.5, coord.y );\n"
+" vec4 sum = vec4( 0.0 );\n"
+" float coefsum = 0.0;\n"
+" mat4 wlut;\n"
+" wlut[0] = texture2DRect( lut, vec2( abs( coord.x - TexCoord.x ) * 1000.0, spline ) );\n"
+" for( int x = -1; x <= 2; x++ ) {\n"
+" vec4 col = texture2DRect( tex, TexCoord + vec2( float( x ), 0.0) );\n"
+" sum += col * wlut[0][x+1];\n"
+" coefsum += wlut[0][x+1];\n"
+" }\n"
+" gl_FragColor = sum / coefsum;\n"
+"}\n";
+
+
+
+static const char *bicubic_pass2_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect tex, lut;\n"
+"uniform float spline;\n"
+"void main() {\n"
+" vec2 coord = gl_TexCoord[0].xy;\n"
+" vec2 TexCoord = vec2( coord.x, floor( coord.y - 0.5 ) + 0.5 );\n"
+" vec4 sum = vec4( 0.0 );\n"
+" float coefsum = 0.0;\n"
+" mat4 wlut;\n"
+" wlut[0] = texture2DRect( lut, vec2( abs( coord.y - TexCoord.y ) * 1000.0, spline ) );\n"
+" for( int y = -1; y <= 2; y++ ) {\n"
+" vec4 col = texture2DRect( tex, TexCoord + vec2( 0.0, float( y ) ) );\n"
+" sum += col * wlut[0][y+1];\n"
+" coefsum += wlut[0][y+1];\n"
+" }\n"
+" gl_FragColor = sum / coefsum;\n"
+"}\n";
+
+
+
+#define PI 3.14159265359
+#define LUTWIDTH 1000
+#define N_SPLINES 2
+#define CATMULLROM_SPLINE 0
+#define COS_SPLINE 1
+
+static float compute_cos_spline( float x )
+{
+ if ( x < 0.0 )
+ x = -x;
+ return 0.5 * cos( PI * x / 2.0 ) + 0.5;
+}
+
+static float compute_catmullrom_spline( float x )
+{
+ if ( x < 0.0 )
+ x = -x;
+ if ( x < 1.0 )
+ return ((9.0 * (x * x * x)) - (15.0 * (x * x)) + 6.0) / 6.0;
+ if ( x <= 2.0 )
+ return ((-3.0 * (x * x * x)) + (15.0 * (x * x)) - (24.0 * x) + 12.0) / 6.0;
+ return 0.0;
+}
+
+static int create_lut_texture( opengl2_driver_t *that )
+{
+ int i = 0;
+ float *lut = calloc( sizeof(float) * LUTWIDTH * 4 * N_SPLINES, 1 );
+ float t;
+ while ( i < LUTWIDTH ) {
+ t = (float)i / (float)LUTWIDTH;
+
+ lut[i * 4] = compute_catmullrom_spline( t + 1.0 );
+ lut[(i * 4) + 1] = compute_catmullrom_spline( t );
+ lut[(i * 4) + 2] = compute_catmullrom_spline( t - 1.0 );
+ lut[(i * 4) + 3] = compute_catmullrom_spline( t - 2.0 );
+
+ lut[(i * 4) + (LUTWIDTH * 4)] = compute_cos_spline( t + 1.0 );
+ lut[(i * 4) + (LUTWIDTH * 4) + 1] = compute_cos_spline( t );
+ lut[(i * 4) + (LUTWIDTH * 4) + 2] = compute_cos_spline( t - 1.0 );
+ lut[(i * 4) + (LUTWIDTH * 4) + 3] = compute_cos_spline( t - 2.0 );
+
+ ++i;
+ }
+
+ that->bicubic_lut_texture = 0;
+ glGenTextures( 1, &that->bicubic_lut_texture );
+ if ( !that->bicubic_lut_texture )
+ return 0;
+
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_lut_texture );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ 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 );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA32F, LUTWIDTH, N_SPLINES, 0, GL_RGBA, GL_FLOAT, lut );
+ free( lut );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+ return 1;
+}
+
+
+
+static const char *blur_sharpen_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect tex;\n"
+"uniform float value;\n"
+"void main() {\n"
+" vec2 pos = gl_TexCoord[0].xy;\n"
+" vec4 c1;\n"
+" float K;\n"
+" if ( value < 0.0 )\n"
+" K = value / 8.0;\n"
+" else\n"
+" K = value / 4.0;\n"
+" c1 = texture2DRect( tex, pos ) * (1.0 + (8.0 * K));\n"
+" c1 -= texture2DRect( tex, pos + vec2( 1.0, 0.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( -1.0, 0.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 0.0, 1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 0.0, -1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 1.0, 1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( -1.0, 1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( -1.0, -1.0 ) ) * K;\n"
+" c1 -= texture2DRect( tex, pos + vec2( 1.0, -1.0 ) ) * K;\n"
+" gl_FragColor = c1 ;\n"
+"}\n";
+
+
+
+static const char *yuv420_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect texY, texU, texV;\n"
+"uniform vec4 r_coefs, g_coefs, b_coefs;\n"
+"void main(void) {\n"
+" vec3 rgb;\n"
+" vec4 yuv;\n"
+" vec2 coord = gl_TexCoord[0].xy;\n"
+" yuv.r = texture2DRect(texY, vec2(coord.x, coord.y)).r;\n"
+" yuv.g = texture2DRect(texU, vec2(coord.x/2.0, coord.y/2.0)).r;\n"
+" yuv.b = texture2DRect(texV, vec2(coord.x/2.0, coord.y/2.0)).r;\n"
+" yuv.a = 1.0;\n"
+" rgb.r = dot( yuv, r_coefs );\n"
+" rgb.g = dot( yuv, g_coefs );\n"
+" rgb.b = dot( yuv, b_coefs );\n"
+" gl_FragColor = vec4(rgb, 1.0);\n"
+"}\n";
+
+
+
+static const char *yuv422_frag=
+"#extension GL_ARB_texture_rectangle : enable\n"
+"uniform sampler2DRect texYUV;\n"
+"uniform vec4 r_coefs, g_coefs, b_coefs;\n"
+"void main(void) {\n"
+" vec3 rgb;\n"
+" vec4 yuv;\n"
+" vec4 coord = gl_TexCoord[0].xyxx;\n"
+" coord.z -= step(1.0, mod(coord.x, 2.0));\n"
+" coord.w = coord.z + 1.0;\n"
+" yuv.r = texture2DRect(texYUV, coord.xy).r;\n"
+" yuv.g = texture2DRect(texYUV, coord.zy).a;\n"
+" yuv.b = texture2DRect(texYUV, coord.wy).a;\n"
+" yuv.a = 1.0;\n"
+" rgb.r = dot( yuv, r_coefs );\n"
+" rgb.g = dot( yuv, g_coefs );\n"
+" rgb.b = dot( yuv, b_coefs );\n"
+" gl_FragColor = vec4(rgb, 1.0);\n"
+"}\n";
+
+
+
+float yuv_601[] = {
+ 1.16438, 0.00000, 1.59603, -0.87420,
+ 1.16438, -0.39176, -0.81297, 0.53167,
+ 1.16438, 2.01723, 0.00000, -1.08563
+};
+
+float yuv_709[] = {
+ 1.16438, 0.00000, 1.79274, -0.97295,
+ 1.16438, -0.21325, -0.53291, 0.30148,
+ 1.16438, 2.11240, 0.00000, -1.13340
+};
+
+float yuv_240[] = {
+ 1.16438, 0.00000, 1.79411, -0.97363,
+ 1.16438, -0.25798, -0.54258, 0.32879,
+ 1.16438, 2.07871, 0.00000, -1.11649
+};
+
+static void load_csc_matrix( GLuint prog, float *cf )
+{
+ glUniform4f( glGetUniformLocationARB( prog, "r_coefs" ), cf[0], cf[1], cf[2], cf[3] );
+ glUniform4f( glGetUniformLocationARB( prog, "g_coefs" ), cf[4], cf[5], cf[6], cf[7] );
+ glUniform4f( glGetUniformLocationARB( prog, "b_coefs" ), cf[8], cf[9], cf[10], cf[11] );
+}
+
+
+
+static int opengl2_build_program( opengl2_program_t *prog, const char **source, const char *name )
+{
+ fprintf(stderr, "vo_opengl2 : compiling shader %s\n", name);
+ if ( !(prog->shader = glCreateShader( GL_FRAGMENT_SHADER )) )
+ return 0;
+ if ( !(prog->program = glCreateProgram()) )
+ return 0;
+
+ glShaderSource( prog->shader, 1, source, NULL );
+ glCompileShader( prog->shader );
+
+ GLint length;
+ GLchar *log;
+ glGetShaderiv( prog->shader, GL_INFO_LOG_LENGTH, &length );
+ log = (GLchar*)malloc( length );
+ if ( !log )
+ return 0;
+
+ glGetShaderInfoLog( prog->shader, length, &length, log );
+ if ( length ) {
+ fprintf( stderr, "Shader %s Compilation Log:\n", name );
+ fprintf( stderr, "%s", log );
+ }
+ free( log );
+
+ glAttachShader( prog->program, prog->shader );
+ glLinkProgram( prog->program );
+ glGetProgramiv( prog->program, GL_INFO_LOG_LENGTH, &length );
+ log = (GLchar*)malloc( length );
+ if ( !log )
+ return 0;
+
+ glGetProgramInfoLog( prog->program, length, &length, log );
+ if ( length ) {
+ fprintf( stderr, "Linking Log:\n" );
+ fprintf( stderr, "%s", log );
+ }
+ free( log );
+
+ prog->compiled = 1;
+
+ return 1;
+}
+
+
+
+static void opengl2_delete_program( opengl2_program_t *prog )
+{
+ glDeleteProgram( prog->program );
+ glDeleteShader( prog->shader );
+}
+
+
+
+static int opengl2_check_textures_size( opengl2_driver_t *this_gen, int w, int h )
+{
+ opengl2_driver_t *this = this_gen;
+ opengl2_yuvtex_t *ytex = &this->yuvtex;
+
+ if ( (w == ytex->width) && (h == ytex->height) )
+ return 1;
+
+ if ( ytex->y )
+ glDeleteTextures( 1, &ytex->y );
+ if ( ytex->u )
+ glDeleteTextures( 1, &ytex->u );
+ if ( ytex->v )
+ glDeleteTextures( 1, &ytex->v );
+ if ( ytex->yuv )
+ glDeleteTextures( 1, &ytex->yuv );
+ if ( this->videoTex )
+ glDeleteTextures( 1, &this->videoTex );
+ if ( this->videoTex2 )
+ glDeleteTextures( 1, &this->videoTex2 );
+
+ if ( !this->videoPBO ) {
+ glGenBuffers( 1, &this->videoPBO );
+ if ( !this->videoPBO )
+ return 0;
+ }
+
+ if ( !this->fbo ) {
+ glGenFramebuffers( 1, &this->fbo );
+ if ( !this->fbo )
+ return 0;
+ }
+
+ glGenTextures( 1, &this->videoTex );
+ if ( !this->videoTex )
+ return 0;
+
+ glGenTextures( 1, &this->videoTex2 );
+ if ( !this->videoTex2 )
+ return 0;
+
+ glGenTextures( 1, &ytex->y );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->y );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glGenTextures( 1, &ytex->u );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->u );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, w/2, h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glGenTextures( 1, &ytex->v );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->v );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE, w/2, h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glGenTextures( 1, &ytex->yuv );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, ytex->yuv );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE_ALPHA, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+
+ ytex->width = w;
+ ytex->height = h;
+
+ glGenTextures( 1, &this->videoTex );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->videoTex );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+
+ glGenTextures( 1, &this->videoTex2 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, this->videoTex2 );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, this->videoPBO );
+ glBufferData( GL_PIXEL_UNPACK_BUFFER_ARB, w * h * 2, NULL, GL_STREAM_DRAW );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
+
+ glBindFramebuffer( GL_FRAMEBUFFER, this->fbo );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, this->videoTex, 0 );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_RECTANGLE_ARB, this->videoTex2, 0 );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ return 1;
+}
+
+
+
+static void opengl2_overlay_clut_yuv2rgb(opengl2_driver_t *this, vo_overlay_t *overlay, opengl2_frame_t *frame)
+{
+ //fprintf(stderr, "opengl2_overlay_clut_yuv2rgb\n");
+ int i;
+ clut_t* clut = (clut_t*) overlay->color;
+
+ if (!overlay->rgb_clut) {
+ for ( i=0; i<sizeof(overlay->color)/sizeof(overlay->color[0]); i++ ) {
+ *((uint32_t *)&clut[i]) = this->ovl_yuv2rgb->yuv2rgb_single_pixel_fun(this->ovl_yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr);
+ }
+ overlay->rgb_clut++;
+ }
+ if (!overlay->hili_rgb_clut) {
+ clut = (clut_t*) overlay->hili_color;
+ for ( i=0; i<sizeof(overlay->color)/sizeof(overlay->color[0]); i++) {
+ *((uint32_t *)&clut[i]) = this->ovl_yuv2rgb->yuv2rgb_single_pixel_fun(this->ovl_yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr);
+ }
+ overlay->hili_rgb_clut++;
+ }
+}
+
+
+static int opengl2_process_ovl( opengl2_driver_t *this_gen, vo_overlay_t *overlay )
+{
+ //fprintf(stderr, "opengl2_process_ovl\n");
+ opengl2_overlay_t *ovl = &this_gen->overlays[this_gen->ovl_changed-1];
+
+ if ( overlay->width<=0 || overlay->height<=0 )
+ return 0;
+
+ if ( (overlay->width*overlay->height)!=(ovl->ovl_w*ovl->ovl_h) )
+ ovl->ovl_rgba = (uint8_t*)realloc( ovl->ovl_rgba, overlay->width*overlay->height*4 );
+ ovl->ovl_w = overlay->width;
+ ovl->ovl_h = overlay->height;
+ ovl->ovl_x = overlay->x;
+ ovl->ovl_y = overlay->y;
+ ovl->unscaled = overlay->unscaled;
+ if ( overlay->extent_width == -1 )
+ ovl->vid_scale = 1;
+ else
+ ovl->vid_scale = 0;
+
+ int num_rle = overlay->num_rle;
+ rle_elem_t *rle = overlay->rle;
+ uint8_t *rgba = ovl->ovl_rgba;
+ clut_t *low_colors = (clut_t*)overlay->color;
+ clut_t *hili_colors = (clut_t*)overlay->hili_color;
+ uint8_t *low_trans = overlay->trans;
+ uint8_t *hili_trans = overlay->hili_trans;
+ clut_t *colors;
+ uint8_t *trans;
+ uint8_t alpha;
+ int rlelen = 0;
+ uint8_t clr = 0;
+ int i, pos=0, x, y;
+
+ while ( num_rle>0 ) {
+ x = pos%ovl->ovl_w;
+ y = pos/ovl->ovl_w;
+ if ( (x>=overlay->hili_left && x<=overlay->hili_right) && (y>=overlay->hili_top && y<=overlay->hili_bottom) ) {
+ colors = hili_colors;
+ trans = hili_trans;
+ }
+ else {
+ colors = low_colors;
+ trans = low_trans;
+ }
+ rlelen = rle->len;
+ clr = rle->color;
+ alpha = trans[clr];
+ for ( i=0; i<rlelen; ++i ) {
+ if ( alpha == 0 ) {
+ rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0;
+ }
+ else {
+ rgba[0] = colors[clr].y;
+ rgba[1] = colors[clr].cr;
+ rgba[2] = colors[clr].cb;
+ rgba[3] = alpha*255/15;
+ }
+ rgba+= 4;
+ ++pos;
+ }
+ ++rle;
+ --num_rle;
+ }
+ return 1;
+}
+
+
+static void opengl2_overlay_begin (vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed)
+{
+ //fprintf(stderr, "opengl2_overlay_begin\n");
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ if ( changed )
+ this->ovl_changed = 1;
+}
+
+
+static void opengl2_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay)
+{
+ //fprintf(stderr, "opengl2_overlay_blend\n");
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+ opengl2_frame_t *frame = (opengl2_frame_t *) frame_gen;
+
+ if ( !this->ovl_changed || this->ovl_changed>XINE_VORAW_MAX_OVL )
+ return;
+
+ if (overlay->rle) {
+ if (!overlay->rgb_clut || !overlay->hili_rgb_clut)
+ opengl2_overlay_clut_yuv2rgb(this, overlay, frame);
+ if ( opengl2_process_ovl( this, overlay ) )
+ ++this->ovl_changed;
+ }
+}
+
+
+static void opengl2_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img)
+{
+ //fprintf(stderr, "opengl2_overlay_end\n");
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ if ( !this->ovl_changed )
+ return;
+
+ this->num_ovls = this->ovl_changed - 1;
+}
+
+
+
+
+static void opengl2_frame_proc_slice( vo_frame_t *vo_img, uint8_t **src )
+{
+ vo_img->proc_called = 1;
+}
+
+
+
+static void opengl2_frame_field( vo_frame_t *vo_img, int which_field )
+{
+}
+
+
+
+static void opengl2_frame_dispose( vo_frame_t *vo_img )
+{
+ opengl2_frame_t *frame = (opengl2_frame_t *) vo_img ;
+
+ av_free (frame->vo_frame.base[0]);
+ av_free (frame->vo_frame.base[1]);
+ av_free (frame->vo_frame.base[2]);
+ free (frame);
+}
+
+
+
+static vo_frame_t *opengl2_alloc_frame( vo_driver_t *this_gen )
+{
+ opengl2_frame_t *frame;
+
+ frame = (opengl2_frame_t *) calloc(1, sizeof(opengl2_frame_t));
+
+ if (!frame)
+ return NULL;
+
+ frame->vo_frame.base[0] = frame->vo_frame.base[1] = frame->vo_frame.base[2] = NULL;
+ frame->width = frame->height = frame->format = frame->flags = 0;
+
+ pthread_mutex_init (&frame->vo_frame.mutex, NULL);
+
+ /*
+ * supply required functions/fields
+ */
+ frame->vo_frame.proc_slice = opengl2_frame_proc_slice;
+ frame->vo_frame.proc_frame = NULL;
+ frame->vo_frame.field = opengl2_frame_field;
+ frame->vo_frame.dispose = opengl2_frame_dispose;
+ frame->vo_frame.driver = this_gen;
+
+ return (vo_frame_t *) frame;
+}
+
+
+
+static void opengl2_update_frame_format( vo_driver_t *this_gen, vo_frame_t *frame_gen,
+ uint32_t width, uint32_t height, double ratio, int format, int flags )
+{
+ opengl2_frame_t *frame = (opengl2_frame_t *) frame_gen;
+
+ /* Check frame size and format and reallocate if necessary */
+ if ( (frame->width != width) || (frame->height != height) || (frame->format != format) || (frame->flags != flags) ) {
+
+ /* (re-) allocate render space */
+ av_freep (&frame->vo_frame.base[0]);
+ av_freep (&frame->vo_frame.base[1]);
+ av_freep (&frame->vo_frame.base[2]);
+
+ if (format == XINE_IMGFMT_YV12) {
+ frame->vo_frame.pitches[0] = 8*((width + 7) / 8);
+ frame->vo_frame.pitches[1] = 8*((width + 15) / 16);
+ frame->vo_frame.pitches[2] = 8*((width + 15) / 16);
+ frame->vo_frame.base[0] = av_mallocz (frame->vo_frame.pitches[0] * height);
+ frame->vo_frame.base[1] = av_mallocz (frame->vo_frame.pitches[1] * ((height+1)/2));
+ frame->vo_frame.base[2] = av_mallocz (frame->vo_frame.pitches[2] * ((height+1)/2));
+ } else if (format == XINE_IMGFMT_YUY2){
+ frame->vo_frame.pitches[0] = 8*((width + 3) / 4);
+ frame->vo_frame.base[0] = av_mallocz (frame->vo_frame.pitches[0] * height);
+ }
+
+ frame->width = width;
+ frame->height = height;
+ frame->format = format;
+ frame->flags = flags;
+ }
+
+ frame->ratio = ratio;
+}
+
+
+
+static int opengl2_redraw_needed( vo_driver_t *this_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ _x_vo_scale_compute_ideal_size( &this->sc );
+ if ( _x_vo_scale_redraw_needed( &this->sc ) ) {
+ _x_vo_scale_compute_output_size( &this->sc );
+ return 1;
+ }
+ return 0;
+}
+
+
+
+static void opengl2_update_csc_matrix( opengl2_driver_t *that, opengl2_frame_t *frame )
+{
+ float *color_standard = (frame->height > 576) ? yuv_709 : yuv_601;
+
+ if ( that->update_csc || that->color_standard != color_standard ) {
+ float hue = that->hue/100.0;
+ float saturation = that->saturation/100.0;
+ float contrast = that->contrast/100.0;
+ float brightness = that->brightness/100.0;
+ float uvcos = saturation * cos( hue );
+ float uvsin = saturation * sin( hue );
+ float uc, vc;
+ int i;
+
+ for (i=0; i<3; ++i ) {
+ that->csc_matrix[(i * 4) + 0] = color_standard[(i * 4) + 0];
+ uc = color_standard[(i * 4) + 1];
+ vc = color_standard[(i * 4) + 2];
+
+ that->csc_matrix[(i * 4) + 3] = brightness - (16.0/219.0);
+ that->csc_matrix[(i * 4) + 1] = (uvcos * uc) + (uvsin * vc);
+ that->csc_matrix[(i * 4) + 3] += ((-128.0 / 255.0) * uvcos * uc) - ((128.0 / 255.0) * uvsin * vc);
+ that->csc_matrix[(i * 4) + 2] = (uvsin * uc) + (uvcos * vc);
+ that->csc_matrix[(i * 4) + 3] += ((-128.0 / 255.0) * uvsin * uc) - ((128.0 / 255.0) * uvcos * vc);
+
+ that->csc_matrix[(i * 4) + 0] *= contrast;
+ that->csc_matrix[(i * 4) + 1] *= contrast;
+ that->csc_matrix[(i * 4) + 2] *= contrast;
+ that->csc_matrix[(i * 4) + 3] *= contrast;
+ }
+
+ that->color_standard = color_standard;
+ that->update_csc = 0;
+ }
+}
+
+
+
+static void opengl2_update_overlays( opengl2_driver_t *that )
+{
+ int i, vid_scale=0, cancel_vid_scale=0;
+ opengl2_overlay_t *o;
+
+ if ( that->ovl_changed ) {
+ that->ovl_vid_scale = 0;
+ for ( i=0; i<that->num_ovls; ++i ) {
+ o = &that->overlays[i];
+
+ /* handle DVB subs scaling, e.g. 720x576->1920x1080 */
+ if ( o->vid_scale ) {
+ vid_scale = 1;
+ if ( o->ovl_w > 720 || o->ovl_h > 576 )
+ cancel_vid_scale = 1;
+ }
+
+ if ( o->tex && ((o->tex_w != o->ovl_w) || (o->tex_h != o->ovl_h)) ) {
+ glDeleteTextures( 1, &o->tex );
+ o->tex = 0;
+ }
+ if ( !o->tex ) {
+ glGenTextures( 1, &o->tex );
+ o->tex_w = o->ovl_w;
+ o->tex_h = o->ovl_h;
+ }
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, o->tex );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, o->tex_w, o->tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, o->ovl_rgba );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+ }
+ }
+
+ if ( that->ovl_changed && vid_scale && !cancel_vid_scale )
+ that->ovl_vid_scale = 1;
+
+ that->ovl_changed = 0;
+}
+
+
+
+static void opengl2_draw_scaled_overlays( opengl2_driver_t *that, opengl2_frame_t *frame )
+{
+ int i, ox, oy, ow, oh;
+ opengl2_overlay_t *o;
+
+ glEnable( GL_BLEND );
+ for ( i=0; i<that->num_ovls; ++i ) {
+ o = &that->overlays[i];
+ if ( o->unscaled )
+ continue;
+ ox = o->ovl_x; oy = o->ovl_y;
+ ow = o->ovl_w; oh = o->ovl_h;
+ if ( o->vid_scale && that->ovl_vid_scale ) {
+ float fx = frame->width / 720.0, fy = frame->height / 576.0;
+ ox *= fx; oy *= fy;
+ ow *= fx; oh *= fy;
+ }
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, o->tex );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( ox, oy, 0.);
+ glTexCoord2f( 0, o->tex_h ); glVertex3f( ox, oy + oh, 0.);
+ glTexCoord2f( o->tex_w, o->tex_h ); glVertex3f( ox + ow, oy + oh, 0.);
+ glTexCoord2f( o->tex_w, 0 ); glVertex3f( ox + ow, oy, 0.);
+ glEnd();
+ }
+ glDisable( GL_BLEND );
+}
+
+
+
+static void opengl2_draw_unscaled_overlays( opengl2_driver_t *that )
+{
+ int i;
+ opengl2_overlay_t *o;
+
+ glEnable( GL_BLEND );
+ for ( i=0; i<that->num_ovls; ++i ) {
+ o = &that->overlays[i];
+ if ( !o->unscaled )
+ continue;
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, o->tex );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( o->ovl_x, o->ovl_y, 0.);
+ glTexCoord2f( 0, o->tex_h ); glVertex3f( o->ovl_x, o->ovl_y + o->ovl_h, 0.);
+ glTexCoord2f( o->tex_w, o->tex_h ); glVertex3f( o->ovl_x + o->ovl_w, o->ovl_y + o->ovl_h, 0.);
+ glTexCoord2f( o->tex_w, 0 ); glVertex3f( o->ovl_x + o->ovl_w, o->ovl_y, 0.);
+ glEnd();
+ }
+ glDisable( GL_BLEND );
+}
+
+
+
+static GLuint opengl2_swap_textures( opengl2_driver_t *that, GLuint current_dest )
+{
+ if ( current_dest == that->videoTex ) {
+ glDrawBuffer( GL_COLOR_ATTACHMENT1 );
+ return that->videoTex2;
+ }
+
+ glDrawBuffer( GL_COLOR_ATTACHMENT0 );
+ return that->videoTex;
+}
+
+
+
+static GLuint opengl2_sharpness( opengl2_driver_t *that, opengl2_frame_t *frame, GLuint video_texture )
+{
+ GLuint ret = video_texture;
+
+ if ( !that->sharpness_program.compiled ) {
+ if ( !opengl2_build_program( &that->sharpness_program, &blur_sharpen_frag, "blur_sharpen_frag" ) )
+ return ret;
+ }
+
+ ret = opengl2_swap_textures( that, video_texture );
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, video_texture );
+
+ float value = that->sharpness / 100.0 * frame->width / 1920.0;
+
+ glUseProgram( that->sharpness_program.program );
+ glUniform1i( glGetUniformLocationARB( that->sharpness_program.program, "tex" ), 0 );
+ glUniform1f( glGetUniformLocationARB( that->sharpness_program.program, "value" ), value );
+ //fprintf(stderr, "vo_opengl2 : sharpness = %f\n", value);
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( 0, 0, 0.);
+ glTexCoord2f( 0, frame->height ); glVertex3f( 0, frame->height, 0.);
+ glTexCoord2f( frame->width, frame->height ); glVertex3f( frame->width, frame->height, 0.);
+ glTexCoord2f( frame->width, 0 ); glVertex3f( frame->width, 0, 0.);
+ glEnd();
+
+ glUseProgram( 0 );
+
+ return ret;
+}
+
+
+
+static int opengl2_draw_video_bicubic( opengl2_driver_t *that, int guiw, int guih, GLfloat u, GLfloat v, GLfloat u1, GLfloat v1,
+ GLfloat x, GLfloat y, GLfloat x1, GLfloat y1, GLuint video_texture )
+{
+ if ( !that->bicubic_lut_texture ) {
+ if ( !create_lut_texture( that ) )
+ return 0;
+ }
+
+ if ( !that->bicubic_pass1_program.compiled && !opengl2_build_program( &that->bicubic_pass1_program, &bicubic_pass1_frag, "bicubic_pass1_frag" ) )
+ return 0;
+ if ( !that->bicubic_pass2_program.compiled && !opengl2_build_program( &that->bicubic_pass2_program, &bicubic_pass2_frag, "bicubic_pass2_frag" ) )
+ return 0;
+ if ( !that->bicubic_fbo ) {
+ glGenFramebuffers( 1, &that->bicubic_fbo );
+ if ( !that->bicubic_fbo )
+ return 0;
+ }
+ if ( (that->bicubic_pass1_texture_width != (x1 - x)) || (that->bicubic_pass1_texture_height != (v1 - v) ) ) {
+ if ( that->bicubic_pass1_texture )
+ glDeleteTextures( 1, &that->bicubic_pass1_texture );
+ glGenTextures( 1, &that->bicubic_pass1_texture );
+ if ( !that->bicubic_pass1_texture )
+ return 0;
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_pass1_texture );
+ glTexImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, x1 - x, v1 - v, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, 0 );
+ that->bicubic_pass1_texture_width = x1 - x;
+ that->bicubic_pass1_texture_height = v1 - v;
+ }
+ glBindFramebuffer( GL_FRAMEBUFFER, that->bicubic_fbo );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, that->bicubic_pass1_texture, 0 );
+
+ glViewport( 0, 0, x1 - x, v1 - v );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, x1 - x, 0.0, v1 - v, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, video_texture );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_lut_texture );
+ glUseProgram( that->bicubic_pass1_program.program );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass1_program.program, "tex" ), 0 );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass1_program.program, "lut" ), 1 );
+ glUniform1f( glGetUniformLocationARB( that->bicubic_pass1_program.program, "spline" ), CATMULLROM_SPLINE );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( u, v ); glVertex3f( 0.0, 0.0, 0.);
+ glTexCoord2f( u, v1 ); glVertex3f( 0.0, v1 - v, 0.);
+ glTexCoord2f( u1, v1 ); glVertex3f( x1 - x, v1 - v, 0.);
+ glTexCoord2f( u1, v ); glVertex3f( x1 - x, 0.0, 0.);
+ glEnd();
+
+ glActiveTexture( GL_TEXTURE0 );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ glViewport( 0, 0, guiw, guih );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, guiw, guih, 0.0, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_pass1_texture );
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->bicubic_lut_texture );
+ glUseProgram( that->bicubic_pass2_program.program );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass2_program.program, "tex" ), 0 );
+ glUniform1i( glGetUniformLocationARB( that->bicubic_pass2_program.program, "lut" ), 1 );
+ glUniform1f( glGetUniformLocationARB( that->bicubic_pass2_program.program, "spline" ), CATMULLROM_SPLINE );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0.0, 0.0 ); glVertex3f( x, y, 0.);
+ glTexCoord2f( 0.0, v1 - v ); glVertex3f( x, y1, 0.);
+ glTexCoord2f( x1 - x, v1 - v ); glVertex3f( x1, y1, 0.);
+ glTexCoord2f( x1 - x, 0.0 ); glVertex3f( x1, y, 0.);
+ glEnd();
+
+ glUseProgram( 0 );
+
+ return 1;
+}
+
+
+
+static void opengl2_draw_video_bilinear( opengl2_driver_t *that, int guiw, int guih, GLfloat u, GLfloat v, GLfloat u1, GLfloat v1,
+ GLfloat x, GLfloat y, GLfloat x1, GLfloat y1, GLuint video_texture )
+{
+ glViewport( 0, 0, guiw, guih );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, guiw, guih, 0.0, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, video_texture );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( u, v ); glVertex3f( x, y, 0.);
+ glTexCoord2f( u, v1 ); glVertex3f( x, y1, 0.);
+ glTexCoord2f( u1, v1 ); glVertex3f( x1, y1, 0.);
+ glTexCoord2f( u1, v ); glVertex3f( x1, y, 0.);
+ glEnd();
+}
+
+
+
+static void opengl2_draw( opengl2_driver_t *that, opengl2_frame_t *frame )
+{
+ glXMakeCurrent( that->display, that->drawable, that->context );
+
+ if ( !opengl2_check_textures_size( that, frame->width, frame->height ) ) {
+ glXMakeCurrent( that->display, None, NULL );
+ return;
+ }
+
+ opengl2_update_csc_matrix( that, frame );
+
+ glBindFramebuffer( GL_FRAMEBUFFER, that->fbo );
+
+ if ( frame->format == XINE_IMGFMT_YV12 ) {
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.y );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, that->videoPBO );
+ void *mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[0], frame->vo_frame.pitches[0] * frame->height );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width, frame->height, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0 );
+ glActiveTexture( GL_TEXTURE1 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.u );
+ mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[1], frame->vo_frame.pitches[1] * ((frame->height+1)/2) );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width/2, frame->height/2, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0 );
+ glActiveTexture( GL_TEXTURE2 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.v );
+ mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[2], frame->vo_frame.pitches[2] * ((frame->height+1)/2) );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width/2, frame->height/2, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0 );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
+
+ glUseProgram( that->yuv420_program.program );
+ glUniform1i( glGetUniformLocationARB( that->yuv420_program.program, "texY" ), 0 );
+ glUniform1i( glGetUniformLocationARB( that->yuv420_program.program, "texU" ), 1 );
+ glUniform1i( glGetUniformLocationARB( that->yuv420_program.program, "texV" ), 2 );
+ load_csc_matrix( that->yuv420_program.program, that->csc_matrix );
+ }
+ else if ( frame->format == XINE_IMGFMT_YUY2 ) {
+ glActiveTexture( GL_TEXTURE0 );
+ glBindTexture( GL_TEXTURE_RECTANGLE_ARB, that->yuvtex.yuv );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, that->videoPBO );
+ void *mem = glMapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY );
+ memcpy( mem, frame->vo_frame.base[0], frame->vo_frame.pitches[0] * frame->height );
+ glUnmapBuffer( GL_PIXEL_UNPACK_BUFFER_ARB );
+ glTexSubImage2D( GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, frame->width, frame->height, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 0 );
+ glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0 );
+
+ glUseProgram( that->yuv422_program.program );
+ glUniform1i( glGetUniformLocationARB( that->yuv422_program.program, "texYUV" ), 0 );
+ load_csc_matrix( that->yuv422_program.program, that->csc_matrix );
+ }
+ else {
+ /* unknown format */
+ fprintf(stderr, "vo_opengl2: unknown image format\n" );
+ }
+
+ glViewport( 0, 0, frame->width, frame->height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glOrtho( 0.0, frame->width, 0.0, frame->height, -1.0, 1.0 );
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+
+ GLuint video_texture = that->videoTex;
+ glDrawBuffer( GL_COLOR_ATTACHMENT0 );
+
+ glBegin( GL_QUADS );
+ glTexCoord2f( 0, 0 ); glVertex3f( 0, 0, 0.);
+ glTexCoord2f( 0, frame->height ); glVertex3f( 0, frame->height, 0.);
+ glTexCoord2f( frame->width, frame->height ); glVertex3f( frame->width, frame->height, 0.);
+ glTexCoord2f( frame->width, 0 ); glVertex3f( frame->width, 0, 0.);
+ glEnd();
+
+ glUseProgram( 0 );
+
+ // post-processing
+ if ( that->sharpness != 0 )
+ video_texture = opengl2_sharpness( that, frame, video_texture );
+
+ // draw scaled overlays
+ opengl2_update_overlays( that );
+ opengl2_draw_scaled_overlays( that, frame );
+
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ // draw on screen
+ GLfloat u, u1, v, v1, x, x1, y, y1;
+
+ u = that->sc.displayed_xoffset;
+ v = that->sc.displayed_yoffset;
+ u1 = that->sc.displayed_width + that->sc.displayed_xoffset;
+ v1 = that->sc.displayed_height + that->sc.displayed_yoffset;
+ x = that->sc.output_xoffset;
+ y = that->sc.output_yoffset;
+ x1 = that->sc.output_xoffset + that->sc.output_width;
+ y1 = that->sc.output_yoffset + that->sc.output_height;
+
+ if ( that->scale_bicubic ) {
+ if ( !opengl2_draw_video_bicubic( that, that->sc.gui_width, that->sc.gui_height, u, v, u1, v1, x, y, x1, y1, video_texture ) )
+ opengl2_draw_video_bilinear( that, that->sc.gui_width, that->sc.gui_height, u, v, u1, v1, x, y, x1, y1, video_texture );
+ }
+ else
+ opengl2_draw_video_bilinear( that, that->sc.gui_width, that->sc.gui_height, u, v, u1, v1, x, y, x1, y1, video_texture );
+
+ // draw unscaled overlays
+ opengl2_draw_unscaled_overlays( that );
+
+ //if ( that->mglXSwapInterval )
+ //that->mglXSwapInterval( 1 );
+
+ glXSwapBuffers( that->display, that->drawable );
+
+ glXMakeCurrent( that->display, None, NULL );
+}
+
+
+
+static void opengl2_display_frame( vo_driver_t *this_gen, vo_frame_t *frame_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+ opengl2_frame_t *frame = (opengl2_frame_t *) frame_gen;
+
+ if ( (frame->width != this->sc.delivered_width) ||
+ (frame->height != this->sc.delivered_height) ||
+ (frame->ratio != this->sc.delivered_ratio) ||
+ (frame->vo_frame.crop_left != this->sc.crop_left) ||
+ (frame->vo_frame.crop_right != this->sc.crop_right) ||
+ (frame->vo_frame.crop_top != this->sc.crop_top) ||
+ (frame->vo_frame.crop_bottom != this->sc.crop_bottom) ) {
+ this->sc.force_redraw = 1; /* trigger re-calc of output size */
+ }
+
+ this->sc.delivered_height = frame->height;
+ this->sc.delivered_width = frame->width;
+ this->sc.delivered_ratio = frame->ratio;
+ this->sc.crop_left = frame->vo_frame.crop_left;
+ this->sc.crop_right = frame->vo_frame.crop_right;
+ this->sc.crop_top = frame->vo_frame.crop_top;
+ this->sc.crop_bottom = frame->vo_frame.crop_bottom;
+
+ opengl2_redraw_needed( this_gen );
+
+ pthread_mutex_lock(&this->drawable_lock); /* protect drawable from being changed */
+ opengl2_draw( this, frame );
+ pthread_mutex_unlock(&this->drawable_lock); /* allow changing drawable again */
+
+ frame->vo_frame.free( &frame->vo_frame );
+}
+
+
+
+static int opengl2_get_property( vo_driver_t *this_gen, int property )
+{
+ opengl2_driver_t *this = (opengl2_driver_t*)this_gen;
+
+ switch (property) {
+ case VO_PROP_MAX_NUM_FRAMES:
+ return 15;
+ case VO_PROP_WINDOW_WIDTH:
+ return this->sc.gui_width;
+ case VO_PROP_WINDOW_HEIGHT:
+ return this->sc.gui_height;
+ case VO_PROP_OUTPUT_WIDTH:
+ return this->sc.output_width;
+ case VO_PROP_OUTPUT_HEIGHT:
+ return this->sc.output_height;
+ case VO_PROP_OUTPUT_XOFFSET:
+ return this->sc.output_xoffset;
+ case VO_PROP_OUTPUT_YOFFSET:
+ return this->sc.output_yoffset;
+ case VO_PROP_HUE:
+ return this->hue;
+ case VO_PROP_SATURATION:
+ return this->saturation;
+ case VO_PROP_CONTRAST:
+ return this->contrast;
+ case VO_PROP_BRIGHTNESS:
+ return this->brightness;
+ case VO_PROP_SHARPNESS:
+ return this->sharpness;
+ case VO_PROP_ZOOM_X:
+ return this->zoom_x;
+ case VO_PROP_ZOOM_Y:
+ return this->zoom_y;
+ case VO_PROP_ASPECT_RATIO:
+ return this->sc.user_ratio;
+ }
+
+ return -1;
+}
+
+
+
+static int opengl2_set_property( vo_driver_t *this_gen, int property, int value )
+{
+ opengl2_driver_t *this = (opengl2_driver_t*)this_gen;
+
+ //fprintf(stderr,"opengl2_set_property: property=%d, value=%d\n", property, value );
+
+ switch (property) {
+ case VO_PROP_ZOOM_X:
+ if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
+ this->zoom_x = value;
+ this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP;
+ _x_vo_scale_compute_ideal_size( &this->sc );
+ this->sc.force_redraw = 1; //trigger re-calc of output size
+ }
+ break;
+ case VO_PROP_ZOOM_Y:
+ if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
+ this->zoom_y = value;
+ this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP;
+ _x_vo_scale_compute_ideal_size( &this->sc );
+ this->sc.force_redraw = 1; // trigger re-calc of output size
+ }
+ break;
+ case VO_PROP_ASPECT_RATIO:
+ if ( value>=XINE_VO_ASPECT_NUM_RATIOS )
+ value = XINE_VO_ASPECT_AUTO;
+ this->sc.user_ratio = value;
+ this->sc.force_redraw = 1; // trigger re-calc of output size
+ break;
+ case VO_PROP_HUE: this->hue = value; this->update_csc = 1; break;
+ case VO_PROP_SATURATION: this->saturation = value; this->update_csc = 1; break;
+ case VO_PROP_CONTRAST: this->contrast = value; this->update_csc = 1; break;
+ case VO_PROP_BRIGHTNESS: this->brightness = value; this->update_csc = 1; break;
+ case VO_PROP_SHARPNESS: this->sharpness = value; break;
+ }
+
+ return value;
+}
+
+
+
+static void opengl2_get_property_min_max( vo_driver_t *this_gen, int property, int *min, int *max )
+{
+ switch ( property ) {
+ case VO_PROP_HUE:
+ *max = 314; *min = -314; break;
+ case VO_PROP_SATURATION:
+ *max = 1000; *min = 0; break;
+ case VO_PROP_CONTRAST:
+ *max = 1000; *min = 0; break;
+ case VO_PROP_BRIGHTNESS:
+ *max = 100; *min = -100; break;
+ case VO_PROP_SHARPNESS:
+ *max = 100; *min = -100; break;
+ default:
+ *max = 0; *min = 0;
+ }
+}
+
+
+
+static int opengl2_gui_data_exchange( vo_driver_t *this_gen, int data_type, void *data )
+{
+ opengl2_driver_t *this = (opengl2_driver_t*)this_gen;
+
+ switch (data_type) {
+#ifndef XINE_DISABLE_DEPRECATED_FEATURES
+ case XINE_GUI_SEND_COMPLETION_EVENT:
+ break;
+#endif
+
+ case XINE_GUI_SEND_EXPOSE_EVENT: {
+ this->sc.force_redraw = 1;
+ break;
+ }
+
+ case XINE_GUI_SEND_DRAWABLE_CHANGED: {
+ pthread_mutex_lock(&this->drawable_lock); /* wait for other thread which is currently displaying */
+ this->drawable = (Drawable)data;
+ pthread_mutex_unlock(&this->drawable_lock);
+ this->sc.force_redraw = 1;
+ break;
+ }
+
+ case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: {
+ int x1, y1, x2, y2;
+ x11_rectangle_t *rect = data;
+
+ _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, &x1, &y1);
+ _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, &x2, &y2);
+ rect->x = x1;
+ rect->y = y1;
+ rect->w = x2-x1;
+ rect->h = y2-y1;
+ break;
+ }
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+static uint32_t opengl2_get_capabilities( vo_driver_t *this_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ return this->capabilities;
+}
+
+
+
+static void opengl2_set_bicubic( void *this_gen, xine_cfg_entry_t *entry )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ this->scale_bicubic = entry->num_value;
+ fprintf(stderr, "vo_opengl2: scale_bicubic=%d\n", this->scale_bicubic );
+}
+
+
+
+static void opengl2_dispose( vo_driver_t *this_gen )
+{
+ opengl2_driver_t *this = (opengl2_driver_t *) this_gen;
+
+ pthread_mutex_destroy(&this->drawable_lock);
+
+ glXMakeCurrent( this->display, this->drawable, this->context );
+
+ opengl2_delete_program( &this->yuv420_program );
+ opengl2_delete_program( &this->yuv422_program );
+
+ if ( this->sharpness_program.compiled )
+ opengl2_delete_program( &this->sharpness_program );
+
+ if ( this->bicubic_pass1_program.compiled )
+ opengl2_delete_program( &this->bicubic_pass1_program );
+ if ( this->bicubic_pass2_program.compiled )
+ opengl2_delete_program( &this->bicubic_pass2_program );
+ if ( this->bicubic_lut_texture )
+ glDeleteTextures( 1, &this->bicubic_lut_texture );
+ if ( this->bicubic_pass1_texture )
+ glDeleteTextures( 1, &this->bicubic_pass1_texture );
+ if ( this->bicubic_fbo )
+ glDeleteFramebuffers( 1, &this->bicubic_fbo );
+
+ if ( this->yuvtex.y )
+ glDeleteTextures( 1, &this->yuvtex.y );
+ if ( this->yuvtex.u )
+ glDeleteTextures( 1, &this->yuvtex.u );
+ if ( this->yuvtex.v )
+ glDeleteTextures( 1, &this->yuvtex.v );
+ if ( this->yuvtex.yuv )
+ glDeleteTextures( 1, &this->yuvtex.yuv );
+ if ( this->videoTex )
+ glDeleteTextures( 1, &this->videoTex );
+ if ( this->videoTex2 )
+ glDeleteTextures( 1, &this->videoTex2 );
+ if ( this->fbo )
+ glDeleteFramebuffers( 1, &this->fbo );
+ if ( this->videoPBO )
+ glDeleteBuffers( 1, &this->videoPBO );
+
+ int i;
+ for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) {
+ free( this->overlays[i].ovl_rgba );
+ glDeleteTextures( 1, &this->overlays[i].tex );
+ }
+
+ glXMakeCurrent( this->display, None, NULL );
+
+ glXDestroyContext( this->display, this->context );
+
+ this->ovl_yuv2rgb->dispose(this->ovl_yuv2rgb);
+ this->yuv2rgb_factory->dispose (this->yuv2rgb_factory);
+
+ free (this);
+}
+
+
+
+static vo_driver_t *opengl2_open_plugin( video_driver_class_t *class_gen, const void *visual_gen )
+{
+ opengl2_class_t *class = (opengl2_class_t *) class_gen;
+ x11_visual_t *visual = (x11_visual_t *) visual_gen;
+ opengl2_driver_t *this;
+ config_values_t *config = class->xine->config;
+
+ this = (opengl2_driver_t *) calloc(1, sizeof(opengl2_driver_t));
+
+ if (!this)
+ return NULL;
+
+ this->display = visual->display;
+ this->screen = visual->screen;
+ this->drawable = visual->d;
+ this->context = class->ctx;
+ pthread_mutex_init(&this->drawable_lock, 0);
+
+ _x_vo_scale_init(&this->sc, 1, 0, config);
+ this->sc.frame_output_cb = visual->frame_output_cb;
+ this->sc.dest_size_cb = visual->dest_size_cb;
+ this->sc.user_data = visual->user_data;
+ this->sc.user_ratio = XINE_VO_ASPECT_AUTO;
+
+ this->zoom_x = 100;
+ this->zoom_y = 100;
+
+ this->xine = class->xine;
+ this->config = config;
+
+ this->vo_driver.get_capabilities = opengl2_get_capabilities;
+ this->vo_driver.alloc_frame = opengl2_alloc_frame;
+ this->vo_driver.update_frame_format = opengl2_update_frame_format;
+ this->vo_driver.overlay_begin = opengl2_overlay_begin;
+ this->vo_driver.overlay_blend = opengl2_overlay_blend;
+ this->vo_driver.overlay_end = opengl2_overlay_end;
+ this->vo_driver.display_frame = opengl2_display_frame;
+ this->vo_driver.get_property = opengl2_get_property;
+ this->vo_driver.set_property = opengl2_set_property;
+ this->vo_driver.get_property_min_max = opengl2_get_property_min_max;
+ this->vo_driver.gui_data_exchange = opengl2_gui_data_exchange;
+ this->vo_driver.dispose = opengl2_dispose;
+ this->vo_driver.redraw_needed = opengl2_redraw_needed;
+
+ if ( !glXMakeCurrent( this->display, this->drawable, this->context ) ) {
+ fprintf(stderr, "vo_opengl2: MakeCurrent failed\n");
+ return NULL;
+ }
+
+ glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
+ glClearDepth( 1.0f );
+ glDepthFunc( GL_LEQUAL );
+ glDisable( GL_DEPTH_TEST );
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glDisable( GL_BLEND );
+ glShadeModel( GL_SMOOTH );
+ glEnable( GL_TEXTURE_RECTANGLE_ARB );
+ glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+ const char *extensions = glGetString( GL_EXTENSIONS );
+ if ( strstr( extensions, "ARB_texture_float" ) )
+ this->texture_float = 1;
+ else
+ this->texture_float = 0;
+
+#define INITWIDTH 720
+#define INITHEIGHT 576
+
+ this->yuvtex.y = this->yuvtex.u = this->yuvtex.v = this->yuvtex.yuv = 0;
+ this->yuvtex.width = this->yuvtex.height = 0;
+ this->fbo = this->videoPBO = this->videoTex = this->videoTex2 = 0;
+ if ( !opengl2_check_textures_size( this, INITWIDTH, INITHEIGHT ) )
+ return 0;
+
+ if ( !opengl2_build_program( &this->yuv420_program, &yuv420_frag, "yuv420_frag" ) )
+ return NULL;
+ if ( !opengl2_build_program( &this->yuv422_program, &yuv422_frag, "yuv422_frag" ) )
+ return NULL;
+
+ this->mglXSwapInterval = (GLXSWAPINTERVALSGI)glXGetProcAddressARB( (const GLubyte*)"glXSwapIntervalSGI" );
+
+ glXMakeCurrent( this->display, None, NULL );
+
+ this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | VO_CAP_UNSCALED_OVERLAY | VO_CAP_CUSTOM_EXTENT_OVERLAY;// | VO_CAP_ARGB_LAYER_OVERLAY | VO_CAP_VIDEO_WINDOW_OVERLAY;
+
+ this->capabilities |= VO_CAP_HUE;
+ this->capabilities |= VO_CAP_SATURATION;
+ this->capabilities |= VO_CAP_CONTRAST;
+ this->capabilities |= VO_CAP_BRIGHTNESS;
+
+ this->update_csc = 1;
+ this->color_standard = yuv_601;
+ this->hue = 0;
+ this->saturation = 100;
+ this->contrast = 100;
+ this->brightness = 0;
+ this->sharpness = 0;
+ this->sharpness_program.compiled = 0;
+
+ this->bicubic_pass1_program.compiled = 0;
+ this->bicubic_pass2_program.compiled = 0;
+ this->bicubic_lut_texture = 0;
+ this->bicubic_pass1_texture = 0;
+ this->bicubic_pass1_texture_width = 0;
+ this->bicubic_pass1_texture_height = 0;
+ this->bicubic_fbo = 0;
+
+ int i;
+ for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) {
+ this->overlays[i].ovl_w = this->overlays[i].ovl_h = 0;
+ this->overlays[i].ovl_rgba = (uint8_t*)malloc(2*2*4);
+ this->overlays[i].ovl_x = this->overlays[i].ovl_y = 0;
+ this->overlays[i].unscaled = 0;
+ this->overlays[i].tex = 0;
+ this->overlays[i].tex_w = this->overlays[i].tex_h = 0;
+ }
+ this->ovl_changed = 0;
+ this->num_ovls = 0;
+
+ this->yuv2rgb_factory = yuv2rgb_factory_init (MODE_24_BGR, 0, NULL);
+ this->ovl_yuv2rgb = this->yuv2rgb_factory->create_converter( this->yuv2rgb_factory );
+
+ if ( this->texture_float ) {
+ this->scale_bicubic = config->register_bool( config, "video.output.opengl2_bicubic_scaling", 0,
+ _("opengl2: use a bicubic algo to scale the video"),
+ _("Set to true if you want bicubic scaling.\n\n"),
+ 10, opengl2_set_bicubic, this );
+ }
+ else
+ this->scale_bicubic = 0;
+
+ fprintf(stderr, "vo_opengl2: initialized.\n");
+
+ return &this->vo_driver;
+}
+
+
+
+static int opengl2_check_platform( opengl2_class_t *this_gen, x11_visual_t *vis )
+{
+ int attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8,
+ GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 16, None };
+
+ Window root;
+ XVisualInfo *visinfo;
+ GLXContext ctx;
+ int ret = 1;
+
+ if ( !vis || !vis->display || !( root = RootWindow( vis->display, vis->screen ) ) )
+ return 0;
+
+ if ( !( visinfo = glXChooseVisual( vis->display, vis->screen, attribs ) ) )
+ return 0;
+
+ if ( !( ctx = glXCreateContext( vis->display, visinfo, NULL, GL_TRUE ) ) )
+ return 0;
+
+ if ( glXMakeCurrent( vis->display, root, ctx ) ) {
+ if ( !glXIsDirect( vis->display, ctx ) )
+ ret = 0;
+ const char *extensions = glGetString( GL_EXTENSIONS );
+ if ( !strstr( extensions, "ARB_texture_rectangle" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_texture_non_power_of_two" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_pixel_buffer_object" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_framebuffer_object" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_fragment_shader" ) )
+ ret = 0;
+ if ( !strstr( extensions, "ARB_vertex_shader" ) )
+ ret = 0;
+ glXMakeCurrent( vis->display, None, NULL );
+ }
+ else
+ ret = 0;
+
+ if ( !ret )
+ glXDestroyContext( vis->display, ctx );
+ else
+ this_gen->ctx = ctx;
+
+ return ret;
+}
+
+/*
+ * class functions
+ */
+
+static void *opengl2_init_class( xine_t *xine, void *visual_gen )
+{
+ opengl2_class_t *this = (opengl2_class_t *) calloc(1, sizeof(opengl2_class_t));
+
+ if ( !opengl2_check_platform( this, (x11_visual_t *)visual_gen ) )
+ return NULL;
+
+ this->driver_class.open_plugin = opengl2_open_plugin;
+ this->driver_class.identifier = "opengl2";
+ this->driver_class.description = N_("xine video output plugin using opengl 2.0");
+ this->driver_class.dispose = default_video_driver_class_dispose;
+ this->xine = xine;
+
+ return this;
+}
+
+
+
+static const vo_info_t vo_info_opengl2 = {
+ 7, /* priority */
+ XINE_VISUAL_TYPE_X11 /* visual type */
+};
+
+
+/*
+ * exported plugin catalog entry
+ */
+
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_VIDEO_OUT, 22, "opengl2", XINE_VERSION_CODE, &vo_info_opengl2, opengl2_init_class },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};