diff options
Diffstat (limited to 'src/video_out/video_out_opengl.c')
-rw-r--r-- | src/video_out/video_out_opengl.c | 216 |
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 } }; |