summaryrefslogtreecommitdiff
path: root/src/video_out/video_out_opengl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/video_out_opengl.c')
-rw-r--r--src/video_out/video_out_opengl.c216
1 files changed, 140 insertions, 76 deletions
diff --git a/src/video_out/video_out_opengl.c b/src/video_out/video_out_opengl.c
index ef0e83530..0d54dff1f 100644
--- a/src/video_out/video_out_opengl.c
+++ b/src/video_out/video_out_opengl.c
@@ -47,6 +47,12 @@
#include <ctype.h>
#include <pthread.h>
+#ifdef HAVE_FFMPEG_AVUTIL_H
+# include <mem.h>
+#else
+# include <libavutil/mem.h>
+#endif
+
/* defines for debugging extensions only */
/* #define GL_GLEXT_LEGACY */
#include <GL/gl.h>
@@ -88,11 +94,11 @@
#endif
#include "xine.h"
-#include "video_out.h"
+#include <xine/video_out.h>
-#include "xine_internal.h"
+#include <xine/xine_internal.h>
#include "yuv2rgb.h"
-#include "xineutils.h"
+#include <xine/xineutils.h>
#include "x11osd.h"
@@ -140,7 +146,6 @@ typedef struct {
int width, height, format, flags;
double ratio;
- uint8_t *chunk[4]; /* mem alloc by xmalloc_aligned */
uint8_t *rgb, *rgb_dst;
yuv2rgb_t *yuv2rgb; /* yuv2rgb converter set up for this frame */
@@ -199,12 +204,15 @@ typedef struct {
PFNMYGLGENTEXTURESEXTPROC glGenTexturesEXT;
PFNMYGLBINDTEXTUREEXTPROC glBindTextureEXT;
- int yuv2rgb_brightness;
- int yuv2rgb_contrast;
- int yuv2rgb_saturation;
+ int brightness;
+ int contrast;
+ int saturation;
uint8_t *yuv2rgb_cmap;
yuv2rgb_factory_t *yuv2rgb_factory;
+ /* color matrix switching */
+ int cm_yuv2rgb, cm_fragprog, cm_state;
+
/* Frame state */
opengl_frame_t *frame[NUM_FRAMES_BACKLOG];
x11osd *xoverlay;
@@ -241,6 +249,12 @@ typedef struct {
} opengl_render_t;
+/* import common color matrix stuff */
+#define CM_DRIVER_T opengl_driver_t
+#include "color_matrix.c"
+
+extern const int32_t Inverse_Table_6_9[8][4]; /* from yuv2rgb.c */
+
/*
* Render functions
*/
@@ -924,7 +938,48 @@ static int render_setup_torus (opengl_driver_t *this) {
static int render_setup_fp_yuv (opengl_driver_t *this) {
GLint errorpos;
int ret;
- static const char *fragprog_yuv =
+
+ int i = (this->cm_fragprog >> 1) & 7;
+ int vr = Inverse_Table_6_9[i][0];
+ int ug = Inverse_Table_6_9[i][2];
+ int vg = Inverse_Table_6_9[i][3];
+ int ub = Inverse_Table_6_9[i][1];
+ int ygain, yoffset;
+ /* TV set behaviour: contrast affects colour difference as well */
+ int saturation = (this->saturation * this->contrast + 64) / 128;
+
+ static char fragprog_yuv[512];
+ const char *s = "";
+
+ /* full range mode */
+ if (this->cm_fragprog & 1) {
+ ygain = (1000 * this->contrast + 64) / 128;
+ yoffset = this->brightness * ygain / 255;
+ /* be careful to stay within 32 bit */
+ vr = (saturation * (112 / 4) * vr + 127 * 16) / (127 * 128 / 4);
+ ug = (saturation * (112 / 4) * ug + 127 * 16) / (127 * 128 / 4);
+ vg = (saturation * (112 / 4) * vg + 127 * 16) / (127 * 128 / 4);
+ ub = (saturation * (112 / 4) * ub + 127 * 16) / (127 * 128 / 4);
+ } else {
+ ygain = (1000 * 255 * this->contrast + 219 * 64) / (219 * 128);
+ yoffset = (this->brightness - 16) * ygain / 255;
+ vr = (saturation * vr + 64) / 128;
+ ug = (saturation * ug + 64) / 128;
+ vg = (saturation * vg + 64) / 128;
+ ub = (saturation * ub + 64) / 128;
+ }
+
+ vr = 1000 * vr / 65536;
+ ug = 1000 * ug / 65536;
+ vg = 1000 * vg / 65536;
+ ub = 1000 * ub / 65536;
+
+ if (yoffset < 0) {
+ s = "-";
+ yoffset = -yoffset;
+ }
+
+ sprintf (fragprog_yuv,
"!!ARBfp1.0\n"
"ATTRIB tex = fragment.texcoord[0];"
"PARAM off = program.env[0];"
@@ -936,16 +991,28 @@ static int render_setup_fp_yuv (opengl_driver_t *this) {
"ADD u, v, off.xyww;"
"ADD v, v, off.zyww;"
"TEX tmp.x, u, texture[0], 2D;"
- "MAD res, res, 1.164, -0.073;" /* -1.164*16/255 */
+ "MAD res, res, %d.%03d, %s%d.%03d;"
"TEX tmp.y, v, texture[0], 2D;"
"SUB tmp, tmp, { .5, .5 };"
- "MAD res, { 0, -.391, 2.018 }, tmp.xxxw, res;"
- "MAD result.color, { 1.596, -.813, 0 }, tmp.yyyw, res;"
- "END";
+ "MAD res, { 0, -%d.%03d, %d.%03d }, tmp.xxxw, res;"
+ "MAD result.color, { %d.%03d, -%d.%03d, 0 }, tmp.yyyw, res;"
+ "END",
+ /* nasty: "%.3f" may use comma as decimal point... */
+ ygain / 1000, ygain % 1000,
+ s, yoffset / 1000, yoffset % 1000,
+ ug / 1000, ug % 1000,
+ ub / 1000, ub % 1000,
+ vr / 1000, vr % 1000,
+ vg / 1000, vg % 1000);
ret = render_setup_tex2d (this);
if (! this->has_fragprog)
return 0;
+
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "video_out_open_opengl_fragprog: b %d c %d s %d [%s]\n",
+ this->brightness, this->contrast, this->saturation, cm_names[this->cm_fragprog]);
+
if (this->fprog == (GLuint)-1)
this->glGenProgramsARB (1, &this->fprog);
this->glBindProgramARB (MYGL_FRAGMENT_PROGRAM_ARB, this->fprog);
@@ -1053,6 +1120,15 @@ static void *render_run (opengl_driver_t *this) {
this->render_frame_changed = 0;
pthread_mutex_unlock (&this->render_action_mutex);
if (this->context && frame) {
+ /* update fragprog if color matrix changed */
+ if (this->render_fun_id == 0) {
+ int cm = cm_from_frame ((vo_frame_t *)frame);
+ if (cm != this->cm_fragprog) {
+ this->cm_fragprog = cm;
+ this->render_action = RENDER_SETUP;
+ break;
+ }
+ }
XLockDisplay (this->display);
CHECKERR ("pre-render");
ret = 1;
@@ -1204,7 +1280,8 @@ static void *render_run (opengl_driver_t *this) {
static uint32_t opengl_get_capabilities (vo_driver_t *this_gen) {
/* opengl_driver_t *this = (opengl_driver_t *) this_gen; */
- uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2;
+ uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS
+ | VO_CAP_CONTRAST | VO_CAP_SATURATION | VO_CAP_COLOR_MATRIX | VO_CAP_FULLRANGE;
/* TODO: somehow performance goes down during the first few frames */
/* if (this->xoverlay) */
@@ -1215,7 +1292,8 @@ static uint32_t opengl_get_capabilities (vo_driver_t *this_gen) {
static void opengl_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src) {
opengl_frame_t *frame = (opengl_frame_t *) vo_img ;
-/* opengl_driver_t *this = (opengl_driver_t *) vo_img->driver; */
+ opengl_driver_t *this = (opengl_driver_t *) vo_img->driver;
+ int cm;
vo_img->proc_called = 1;
if (! frame->rgb_dst)
@@ -1231,6 +1309,16 @@ static void opengl_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src) {
return;
}
+ cm = cm_from_frame (vo_img);
+ if (cm != this->cm_yuv2rgb) {
+ this->cm_yuv2rgb = cm;
+ this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory,
+ this->brightness, this->contrast, this->saturation, cm);
+ xprintf (this->xine, XINE_VERBOSITY_LOG,
+ "video_out_opengl: b %d c %d s %d [%s]\n",
+ this->brightness, this->contrast, this->saturation, cm_names[cm]);
+ }
+
if (frame->format == XINE_IMGFMT_YV12)
frame->yuv2rgb->yuv2rgb_fun (frame->yuv2rgb, frame->rgb_dst,
src[0], src[1], src[2]);
@@ -1273,10 +1361,10 @@ static void opengl_frame_dispose (vo_frame_t *vo_img) {
frame->yuv2rgb->dispose (frame->yuv2rgb);
- free (frame->chunk[0]);
- free (frame->chunk[1]);
- free (frame->chunk[2]);
- free (frame->chunk[3]);
+ av_free (frame->vo_frame.base[0]);
+ av_free (frame->vo_frame.base[1]);
+ av_free (frame->vo_frame.base[2]);
+ av_free (frame->rgb);
free (frame);
}
@@ -1354,26 +1442,23 @@ static void opengl_update_frame_format (vo_driver_t *this_gen,
XLockDisplay (this->display);
/* (re-) allocate render space */
- free (frame->chunk[0]);
- free (frame->chunk[1]);
- free (frame->chunk[2]);
- free (frame->chunk[3]);
+ av_freep(&frame->vo_frame.base[0]);
+ av_freep(&frame->vo_frame.base[1]);
+ av_freep(&frame->vo_frame.base[2]);
+ av_freep(&frame->rgb);
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] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]);
- frame->vo_frame.base[1] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[1] * ((height+1)/2), (void **) &frame->chunk[1]);
- frame->vo_frame.base[2] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[2] * ((height+1)/2), (void **) &frame->chunk[2]);
+ 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 {
frame->vo_frame.pitches[0] = 8*((width + 3) / 4);
- frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]);
- frame->chunk[1] = NULL;
- frame->chunk[2] = NULL;
+ frame->vo_frame.base[0] = av_mallocz(frame->vo_frame.pitches[0] * height);
}
- frame->rgb = xine_xmalloc_aligned (16, BYTES_PER_PIXEL*width*height,
- (void **) &frame->chunk[3]);
+ frame->rgb = av_mallocz(BYTES_PER_PIXEL*width*height);
/* set up colorspace converter */
switch (flags) {
@@ -1601,11 +1686,11 @@ static int opengl_get_property (vo_driver_t *this_gen, int property) {
case VO_PROP_MAX_NUM_FRAMES:
return 15;
case VO_PROP_BRIGHTNESS:
- return this->yuv2rgb_brightness;
+ return this->brightness;
case VO_PROP_CONTRAST:
- return this->yuv2rgb_contrast;
+ return this->contrast;
case VO_PROP_SATURATION:
- return this->yuv2rgb_saturation;
+ return this->saturation;
case VO_PROP_WINDOW_WIDTH:
return this->sc.gui_width;
case VO_PROP_WINDOW_HEIGHT:
@@ -1631,30 +1716,24 @@ static int opengl_set_property (vo_driver_t *this_gen,
this->sc.force_redraw = 1; /* trigger re-calc of output size */
xprintf(this->xine, XINE_VERBOSITY_DEBUG,
- "video_out_opengl: aspect ratio changed to %s\n", _x_vo_scale_aspect_ratio_name(value));
+ "video_out_opengl: aspect ratio changed to %s\n", _x_vo_scale_aspect_ratio_name_table[value]);
break;
case VO_PROP_BRIGHTNESS:
- this->yuv2rgb_brightness = value;
- this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory,
- this->yuv2rgb_brightness,
- this->yuv2rgb_contrast,
- this->yuv2rgb_saturation);
+ this->brightness = value;
+ this->cm_yuv2rgb = 0;
+ this->cm_fragprog = 0;
this->sc.force_redraw = 1;
break;
case VO_PROP_CONTRAST:
- this->yuv2rgb_contrast = value;
- this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory,
- this->yuv2rgb_brightness,
- this->yuv2rgb_contrast,
- this->yuv2rgb_saturation);
+ this->contrast = value;
+ this->cm_yuv2rgb = 0;
+ this->cm_fragprog = 0;
this->sc.force_redraw = 1;
break;
case VO_PROP_SATURATION:
- this->yuv2rgb_saturation = value;
- this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory,
- this->yuv2rgb_brightness,
- this->yuv2rgb_contrast,
- this->yuv2rgb_saturation);
+ this->saturation = value;
+ this->cm_yuv2rgb = 0;
+ this->cm_fragprog = 0;
this->sc.force_redraw = 1;
break;
default:
@@ -1803,6 +1882,8 @@ static void opengl_dispose (vo_driver_t *this_gen) {
this->yuv2rgb_factory->dispose (this->yuv2rgb_factory);
+ cm_close (this);
+
if (this->xoverlay) {
XLockDisplay (this->display);
x11osd_destroy (this->xoverlay);
@@ -1878,16 +1959,13 @@ static vo_driver_t *opengl_open_plugin (video_driver_class_t *class_gen, const v
this->vo_driver.dispose = opengl_dispose;
this->vo_driver.redraw_needed = opengl_redraw_needed;
- this->yuv2rgb_brightness = 0;
- this->yuv2rgb_contrast = 128;
- this->yuv2rgb_saturation = 128;
+ this->brightness = 0;
+ this->contrast = 128;
+ this->saturation = 128;
- this->yuv2rgb_factory = yuv2rgb_factory_init (YUV_FORMAT, YUV_SWAP_MODE,
- NULL);
- this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory,
- this->yuv2rgb_brightness,
- this->yuv2rgb_contrast,
- this->yuv2rgb_saturation);
+ cm_init (this);
+
+ this->yuv2rgb_factory = yuv2rgb_factory_init (YUV_FORMAT, YUV_SWAP_MODE, NULL);
XLockDisplay (this->display);
this->xoverlay = x11osd_create (this->xine, this->display, this->screen,
@@ -2018,20 +2096,6 @@ static int opengl_verify_direct (x11_visual_t *vis) {
return ret;
}
-static char* opengl_get_identifier (video_driver_class_t *this_gen) {
- return "opengl";
-}
-
-static char* opengl_get_description (video_driver_class_t *this_gen) {
- return _("xine video output plugin using the OpenGL 3D graphics API");
-}
-
-static void opengl_dispose_class (video_driver_class_t *this_gen) {
- opengl_class_t *this = (opengl_class_t *) this_gen;
-
- free (this);
-}
-
static void *opengl_init_class (xine_t *xine, void *visual_gen) {
opengl_class_t *this;
@@ -2047,9 +2111,9 @@ static void *opengl_init_class (xine_t *xine, void *visual_gen) {
this = (opengl_class_t *) calloc (1, sizeof(opengl_class_t));
this->driver_class.open_plugin = opengl_open_plugin;
- this->driver_class.get_identifier = opengl_get_identifier;
- this->driver_class.get_description = opengl_get_description;
- this->driver_class.dispose = opengl_dispose_class;
+ this->driver_class.identifier = "opengl";
+ this->driver_class.description = N_("xine video output plugin using the OpenGL 3D graphics API");
+ this->driver_class.dispose = default_video_driver_class_dispose;
this->xine = xine;
return this;
@@ -2068,6 +2132,6 @@ static const vo_info_t vo_info_opengl = {
const plugin_info_t xine_plugin_info[] EXPORTED = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_VIDEO_OUT, 21, "opengl", XINE_VERSION_CODE, &vo_info_opengl, opengl_init_class },
+ { PLUGIN_VIDEO_OUT, 22, "opengl", XINE_VERSION_CODE, &vo_info_opengl, opengl_init_class },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};