diff options
Diffstat (limited to 'libvo')
-rw-r--r-- | libvo/csputils.c | 160 | ||||
-rw-r--r-- | libvo/csputils.h | 56 | ||||
-rw-r--r-- | libvo/gl_common.c | 143 | ||||
-rw-r--r-- | libvo/gl_common.h | 12 | ||||
-rw-r--r-- | libvo/vo_gl.c | 105 | ||||
-rw-r--r-- | libvo/vo_gl2.c | 65 | ||||
-rw-r--r-- | libvo/vo_ivtv.c | 2 | ||||
-rw-r--r-- | libvo/vo_jpeg.c | 15 | ||||
-rw-r--r-- | libvo/vo_png.c | 9 | ||||
-rw-r--r-- | libvo/vo_pnm.c | 2 | ||||
-rw-r--r-- | libvo/vo_v4l2.c | 2 | ||||
-rw-r--r-- | libvo/vo_xv.c | 15 | ||||
-rw-r--r-- | libvo/vo_xvmc.c | 4 | ||||
-rw-r--r-- | libvo/vo_zr2.c | 10 |
14 files changed, 394 insertions, 206 deletions
diff --git a/libvo/csputils.c b/libvo/csputils.c new file mode 100644 index 0000000000..6f69ec4212 --- /dev/null +++ b/libvo/csputils.c @@ -0,0 +1,160 @@ +/* + * Common code related to colorspaces and conversion + * + * Copyleft (C) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de> + * + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdint.h> +#include <math.h> +#include "libavutil/common.h" +#include "csputils.h" + +/** + * \brief little helper function to create a lookup table for gamma + * \param map buffer to create map into + * \param size size of buffer + * \param gamma gamma value + */ +void mp_gen_gamma_map(uint8_t *map, int size, float gamma) { + int i; + if (gamma == 1.0) { + for (i = 0; i < size; i++) + map[i] = 255 * i / (size - 1); + return; + } + gamma = 1.0 / gamma; + for (i = 0; i < size; i++) { + float tmp = (float)i / (size - 1.0); + tmp = pow(tmp, gamma); + if (tmp > 1.0) tmp = 1.0; + if (tmp < 0.0) tmp = 0.0; + map[i] = 255 * tmp; + } +} + +/** + * \brief get the coefficients of the yuv -> rgb conversion matrix + * \param params struct specifying the properties of the conversion like brightness, ... + * \param yuv2rgb array to store coefficients into + * + * Note: contrast, hue and saturation will only work as expected with YUV formats, + * not with e.g. MP_CSP_XYZ + */ +void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]) { + float uvcos = params->saturation * cos(params->hue); + float uvsin = params->saturation * sin(params->hue); + int format = params->format; + int i; + const float (*uv_coeffs)[3]; + const float *level_adjust; + static const float yuv_pc_level_adjust[4] = {-16 / 255.0, -128 / 255.0, -128 / 255.0, 1.164}; + static const float yuv_tv_level_adjust[4] = {0, -128 / 255.0, -128 / 255.0, 0}; + static const float xyz_level_adjust[4] = {0, 0, 0, 0}; + static const float uv_coeffs_table[MP_CSP_COUNT][3][3] = { + [MP_CSP_DEFAULT] = { + {1, 0.000, 1.596}, + {1, -0.391, -0.813}, + {1, 2.018, 0.000} + }, + [MP_CSP_BT_601] = { + {1, 0.000, 1.403}, + {1, -0.344, -0.714}, + {1, 1.773, 0.000} + }, + [MP_CSP_BT_709] = { + {1, 0.0000, 1.5701}, + {1, -0.1870, -0.4664}, + {1, 1.8556, 0.0000} + }, + [MP_CSP_SMPTE_240M] = { + {1, 0.0000, 1.5756}, + {1, -0.2253, -0.5000}, + {1, 1.8270, 0.0000} + }, + [MP_CSP_EBU] = { + {1, 0.000, 1.140}, + {1, -0.396, -0.581}, + {1, 2.029, 0.000} + }, + [MP_CSP_XYZ] = { + { 3.2404542, -1.5371385, -0.4985314}, + {-0.9692660, 1.8760108, 0.0415560}, + { 0.0556434, -0.2040259, 1.0572252} + }, + }; + + if (format < 0 || format >= MP_CSP_COUNT) + format = MP_CSP_DEFAULT; + uv_coeffs = uv_coeffs_table[format]; + level_adjust = yuv_pc_level_adjust; + if (format == MP_CSP_XYZ) + level_adjust = xyz_level_adjust; + + for (i = 0; i < 3; i++) { + yuv2rgb[i][COL_C] = params->brightness; + yuv2rgb[i][COL_Y] = uv_coeffs[i][COL_Y] * level_adjust[COL_C] * params->contrast; + yuv2rgb[i][COL_C] += level_adjust[COL_Y] * yuv2rgb[i][COL_Y]; + yuv2rgb[i][COL_U] = uv_coeffs[i][COL_U] * uvcos + uv_coeffs[i][COL_V] * uvsin; + yuv2rgb[i][COL_C] += level_adjust[COL_U] * yuv2rgb[i][COL_U]; + yuv2rgb[i][COL_V] = uv_coeffs[i][COL_U] * uvsin + uv_coeffs[i][COL_V] * uvcos; + yuv2rgb[i][COL_C] += level_adjust[COL_V] * yuv2rgb[i][COL_V]; + // this "centers" contrast control so that e.g. a contrast of 0 + // leads to a grey image, not a black one + yuv2rgb[i][COL_C] += 0.5 - params->contrast / 2.0; + } +} + +//! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map +#define GMAP_SIZE (1024) +/** + * \brief generate a 3D YUV -> RGB map + * \param params struct containing parameters like brightness, gamma, ... + * \param map where to store map. Must provide space for (size + 2)^3 elements + * \param size size of the map, excluding border + */ +void mp_gen_yuv2rgb_map(struct mp_csp_params *params, unsigned char *map, int size) { + int i, j, k, l; + float step = 1.0 / size; + float y, u, v; + float yuv2rgb[3][4]; + unsigned char gmaps[3][GMAP_SIZE]; + mp_gen_gamma_map(gmaps[0], GMAP_SIZE, params->rgamma); + mp_gen_gamma_map(gmaps[1], GMAP_SIZE, params->ggamma); + mp_gen_gamma_map(gmaps[2], GMAP_SIZE, params->bgamma); + mp_get_yuv2rgb_coeffs(params, yuv2rgb); + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + yuv2rgb[i][j] *= GMAP_SIZE - 1; + v = 0; + for (i = -1; i <= size; i++) { + u = 0; + for (j = -1; j <= size; j++) { + y = 0; + for (k = -1; k <= size; k++) { + for (l = 0; l < 3; l++) { + float rgb = yuv2rgb[l][COL_Y] * y + yuv2rgb[l][COL_U] * u + yuv2rgb[l][COL_V] * v + yuv2rgb[l][COL_C]; + *map++ = gmaps[l][av_clip(rgb, 0, GMAP_SIZE - 1)]; + } + y += (k == -1 || k == size - 1) ? step / 2 : step; + } + u += (j == -1 || j == size - 1) ? step / 2 : step; + } + v += (i == -1 || i == size - 1) ? step / 2 : step; + } +} diff --git a/libvo/csputils.h b/libvo/csputils.h new file mode 100644 index 0000000000..4723c7006d --- /dev/null +++ b/libvo/csputils.h @@ -0,0 +1,56 @@ +/* + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPLAYER_CSPUTILS_H +#define MPLAYER_CSPUTILS_H + +#include <stdint.h> + +enum mp_csp_standard { + MP_CSP_DEFAULT, + MP_CSP_BT_601, + MP_CSP_BT_709, + MP_CSP_SMPTE_240M, + MP_CSP_EBU, + MP_CSP_XYZ, + MP_CSP_COUNT +}; + +struct mp_csp_params { + enum mp_csp_standard format; + float brightness; + float contrast; + float hue; + float saturation; + float rgamma; + float ggamma; + float bgamma; +}; + +void mp_gen_gamma_map(unsigned char *map, int size, float gamma); +#define ROW_R 0 +#define ROW_G 1 +#define ROW_B 2 +#define COL_Y 0 +#define COL_U 1 +#define COL_V 2 +#define COL_C 3 +void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]); +void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size); + +#endif /* MPLAYER_CSPUTILS_H */ diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 527c891327..b6bef7f1b7 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -34,7 +34,7 @@ #include <math.h> #include "old_vo_defines.h" #include "gl_common.h" -#include "libavutil/common.h" +#include "csputils.h" void (GLAPIENTRY *Begin)(GLenum); void (GLAPIENTRY *End)(void); @@ -235,6 +235,16 @@ int glFindFormat(uint32_t fmt, int *bpp, GLint *gl_texfmt, if (!gl_format) gl_format = &dummy2; if (!gl_type) gl_type = &dummy2; + if (mp_get_chroma_shift(fmt, NULL, NULL)) { + // reduce the possible cases a bit + if (IMGFMT_IS_YUVP16_LE(fmt)) + fmt = IMGFMT_420P16_LE; + else if (IMGFMT_IS_YUVP16_BE(fmt)) + fmt = IMGFMT_420P16_BE; + else + fmt = IMGFMT_YV12; + } + *bpp = IMGFMT_IS_BGR(fmt)?IMGFMT_BGR_DEPTH(fmt):IMGFMT_RGB_DEPTH(fmt); *gl_texfmt = 3; switch (fmt) { @@ -251,6 +261,13 @@ int glFindFormat(uint32_t fmt, int *bpp, GLint *gl_texfmt, *gl_format = GL_RGBA; *gl_type = GL_UNSIGNED_BYTE; break; + case IMGFMT_420P16: + supported = 0; // no native YUV support + *gl_texfmt = 1; + *bpp = 16; + *gl_format = GL_LUMINANCE; + *gl_type = GL_UNSIGNED_SHORT; + break; case IMGFMT_YV12: supported = 0; // no native YV12 support case IMGFMT_Y800: @@ -1005,78 +1022,6 @@ static void create_scaler_textures(int scaler, int *texu, char *texs) { } } -static void gen_gamma_map(unsigned char *map, int size, float gamma); - -#define ROW_R 0 -#define ROW_G 1 -#define ROW_B 2 -#define COL_Y 0 -#define COL_U 1 -#define COL_V 2 -#define COL_C 3 - -static void get_yuv2rgb_coeffs(gl_conversion_params_t *params, float yuv2rgb[3][4]) { - float uvcos = params->saturation * cos(params->hue); - float uvsin = params->saturation * sin(params->hue); - int i; - float uv_coeffs[3][2] = { - { 0.000, 1.596}, - {-0.391, -0.813}, - { 2.018, 0.000} - }; - for (i = 0; i < 3; i++) { - yuv2rgb[i][COL_C] = params->brightness; - yuv2rgb[i][COL_Y] = 1.164 * params->contrast; - yuv2rgb[i][COL_C] += (-16 / 255.0) * yuv2rgb[i][COL_Y]; - yuv2rgb[i][COL_U] = uv_coeffs[i][0] * uvcos + uv_coeffs[i][1] * uvsin; - yuv2rgb[i][COL_C] += (-128 / 255.0) * yuv2rgb[i][COL_U]; - yuv2rgb[i][COL_V] = uv_coeffs[i][0] * uvsin + uv_coeffs[i][1] * uvcos; - yuv2rgb[i][COL_C] += (-128 / 255.0) * yuv2rgb[i][COL_V]; - // this "centers" contrast control so that e.g. a contrast of 0 - // leads to a grey image, not a black one - yuv2rgb[i][COL_C] += 0.5 - params->contrast / 2.0; - } -} - -//! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map -#define GMAP_SIZE (1024) -/** - * \brief generate a 3D YUV -> RGB map - * \param params struct containing parameters like brightness, gamma, ... - * \param map where to store map. Must provide space for (size + 2)^3 elements - * \param size size of the map, excluding border - */ -static void gen_yuv2rgb_map(gl_conversion_params_t *params, unsigned char *map, int size) { - int i, j, k, l; - float step = 1.0 / size; - float y, u, v; - float yuv2rgb[3][4]; - unsigned char gmaps[3][GMAP_SIZE]; - gen_gamma_map(gmaps[0], GMAP_SIZE, params->rgamma); - gen_gamma_map(gmaps[1], GMAP_SIZE, params->ggamma); - gen_gamma_map(gmaps[2], GMAP_SIZE, params->bgamma); - get_yuv2rgb_coeffs(params, yuv2rgb); - for (i = 0; i < 3; i++) - for (j = 0; j < 4; j++) - yuv2rgb[i][j] *= GMAP_SIZE - 1; - v = 0; - for (i = -1; i <= size; i++) { - u = 0; - for (j = -1; j <= size; j++) { - y = 0; - for (k = -1; k <= size; k++) { - for (l = 0; l < 3; l++) { - float rgb = yuv2rgb[l][COL_Y] * y + yuv2rgb[l][COL_U] * u + yuv2rgb[l][COL_V] * v + yuv2rgb[l][COL_C]; - *map++ = gmaps[l][av_clip(rgb, 0, GMAP_SIZE - 1)]; - } - y += (k == -1 || k == size - 1) ? step / 2 : step; - } - u += (j == -1 || j == size - 1) ? step / 2 : step; - } - v += (i == -1 || i == size - 1) ? step / 2 : step; - } -} - //! resolution of texture for gamma lookup table #define LOOKUP_RES 512 //! resolution for 3D yuv->rgb conversion lookup table @@ -1098,9 +1043,9 @@ static void create_conv_textures(gl_conversion_params_t *params, int *texu, char texs[0] = (*texu)++; ActiveTexture(GL_TEXTURE0 + texs[0]); lookup_data = malloc(4 * LOOKUP_RES); - gen_gamma_map(lookup_data, LOOKUP_RES, params->rgamma); - gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, params->ggamma); - gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, params->bgamma); + mp_gen_gamma_map(lookup_data, LOOKUP_RES, params->csp_params.rgamma); + mp_gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, params->csp_params.ggamma); + mp_gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, params->csp_params.bgamma); glCreateClearTex(GL_TEXTURE_2D, GL_LUMINANCE8, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_LINEAR, LOOKUP_RES, 4, 0); glUploadTex(GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, lookup_data, @@ -1118,7 +1063,7 @@ static void create_conv_textures(gl_conversion_params_t *params, int *texu, char texs[0] = (*texu)++; ActiveTexture(GL_TEXTURE0 + texs[0]); lookup_data = malloc(3 * sz * sz * sz); - gen_yuv2rgb_map(params, lookup_data, LOOKUP_3DRES); + mp_gen_yuv2rgb_map(¶ms->csp_params, lookup_data, LOOKUP_3DRES); glAdjustAlignment(sz); PixelStorei(GL_UNPACK_ROW_LENGTH, 0); TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1, @@ -1324,10 +1269,10 @@ static void glSetupYUVFragprog(gl_conversion_params_t *params) { add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs, '0', 'r', rect, texw, texh, params->filter_strength); add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, - '1', 'g', rect, texw / 2, texh / 2, params->filter_strength); + '1', 'g', rect, params->chrom_texw, params->chrom_texh, params->filter_strength); add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs, - '2', 'b', rect, texw / 2, texh / 2, params->filter_strength); - get_yuv2rgb_coeffs(params, yuv2rgb); + '2', 'b', rect, params->chrom_texw, params->chrom_texh, params->filter_strength); + mp_get_yuv2rgb_coeffs(¶ms->csp_params, yuv2rgb); switch (YUV_CONVERSION(type)) { case YUV_CONVERSION_FRAGMENT: snprintf(prog_pos, prog_remain, yuv_prog_template, @@ -1342,7 +1287,7 @@ static void glSetupYUVFragprog(gl_conversion_params_t *params) { yuv2rgb[ROW_R][COL_U], yuv2rgb[ROW_G][COL_U], yuv2rgb[ROW_B][COL_U], yuv2rgb[ROW_R][COL_V], yuv2rgb[ROW_G][COL_V], yuv2rgb[ROW_B][COL_V], yuv2rgb[ROW_R][COL_C], yuv2rgb[ROW_G][COL_C], yuv2rgb[ROW_B][COL_C], - (float)1.0 / params->rgamma, (float)1.0 / params->bgamma, (float)1.0 / params->bgamma); + (float)1.0 / params->csp_params.rgamma, (float)1.0 / params->csp_params.bgamma, (float)1.0 / params->csp_params.bgamma); break; case YUV_CONVERSION_FRAGMENT_LOOKUP: snprintf(prog_pos, prog_remain, yuv_lookup_prog_template, @@ -1365,37 +1310,14 @@ static void glSetupYUVFragprog(gl_conversion_params_t *params) { } /** - * \brief little helper function to create a lookup table for gamma - * \param map buffer to create map into - * \param size size of buffer - * \param gamma gamma value - */ -static void gen_gamma_map(unsigned char *map, int size, float gamma) { - int i; - if (gamma == 1.0) { - for (i = 0; i < size; i++) - map[i] = 255 * i / (size - 1); - return; - } - gamma = 1.0 / gamma; - for (i = 0; i < size; i++) { - float tmp = (float)i / (size - 1.0); - tmp = pow(tmp, gamma); - if (tmp > 1.0) tmp = 1.0; - if (tmp < 0.0) tmp = 0.0; - map[i] = 255 * tmp; - } -} - -/** * \brief setup YUV->RGB conversion * \param parms struct containing parameters like conversion and scaler type, * brightness, ... * \ingroup glconversion */ void glSetupYUVConversion(gl_conversion_params_t *params) { - float uvcos = params->saturation * cos(params->hue); - float uvsin = params->saturation * sin(params->hue); + float uvcos = params->csp_params.saturation * cos(params->csp_params.hue); + float uvsin = params->csp_params.saturation * sin(params->csp_params.hue); switch (YUV_CONVERSION(params->type)) { case YUV_CONVERSION_COMBINERS: glSetupYUVCombiners(uvcos, uvsin); @@ -1497,14 +1419,19 @@ void glDisableYUVConversion(GLenum target, int type) { * \param sx width of texture in pixels * \param sy height of texture in pixels * \param rect_tex whether this texture uses texture_rectangle extension - * \param is_yv12 if set, also draw the textures from units 1 and 2 + * \param is_yv12 if != 0, also draw the textures from units 1 and 2, + * bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures * \param flip flip the texture upside down * \ingroup gltexture */ void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, int sx, int sy, int rect_tex, int is_yv12, int flip) { - GLfloat tx2 = tx / 2, ty2 = ty / 2, tw2 = tw / 2, th2 = th / 2; + int chroma_x_shift = (is_yv12 >> 8) & 31; + int chroma_y_shift = (is_yv12 >> 16) & 31; + GLfloat xscale = 1 << chroma_x_shift; + GLfloat yscale = 1 << chroma_y_shift; + GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale; if (!rect_tex) { tx /= sx; ty /= sy; tw /= sx; th /= sy; tx2 = tx, ty2 = ty, tw2 = tw, th2 = th; diff --git a/libvo/gl_common.h b/libvo/gl_common.h index e556718ec0..db20ebbc65 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -26,6 +26,7 @@ #include "mp_msg.h" #include "video_out.h" +#include "csputils.h" #ifdef CONFIG_GL_WIN32 #include <windows.h> @@ -329,18 +330,15 @@ int loadGPUProgram(GLenum target, char *prog); //! extract chrominance scaler out of type #define YUV_CHROM_SCALER(t) ((t >> YUV_CHROM_SCALER_SHIFT) & YUV_SCALER_MASK) /** \} */ + typedef struct { GLenum target; int type; - float brightness; - float contrast; - float hue; - float saturation; - float rgamma; - float ggamma; - float bgamma; + struct mp_csp_params csp_params; int texw; int texh; + int chrom_texw; + int chrom_texh; float filter_strength; } gl_conversion_params_t; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 9a2aafac31..b0c3a1507c 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -90,6 +90,8 @@ static int use_ycbcr; #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS) | (1 << YUV_CONVERSION_COMBINERS_ATI))) #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT)) static int use_yuv; +static int colorspace; +static int is_yuv; static int lscale; static int cscale; static float filter_strength; @@ -203,6 +205,7 @@ static void texSize(int w, int h, int *texw, int *texh) { //! maximum size of custom fragment program #define MAX_CUSTOM_PROG_SIZE (1024 * 1024) static void update_yuvconv(void) { + int xs, ys; float bri = eq_bri / 100.0; float cont = (eq_cont + 100) / 100.0; float hue = eq_hue / 100.0 * 3.1415927; @@ -211,8 +214,11 @@ static void update_yuvconv(void) { float ggamma = exp(log(8.0) * eq_ggamma / 100.0); float bgamma = exp(log(8.0) * eq_bgamma / 100.0); gl_conversion_params_t params = {gl_target, yuvconvtype, - bri, cont, hue, sat, rgamma, ggamma, bgamma, - texture_width, texture_height, filter_strength}; + {colorspace, bri, cont, hue, sat, rgamma, ggamma, bgamma}, + texture_width, texture_height, 0, 0, filter_strength}; + mp_get_chroma_shift(image_format, &xs, &ys); + params.chrom_texw = params.texw >> xs; + params.chrom_texh = params.texh >> ys; glSetupYUVConversion(¶ms); if (custom_prog) { FILE *f = fopen(custom_prog, "r"); @@ -475,8 +481,10 @@ static int initGl(uint32_t d_width, uint32_t d_height) { mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n", texture_width, texture_height); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { int i; + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); GenTextures(21, default_texs); default_texs[21] = 0; for (i = 0; i < 7; i++) { @@ -487,18 +495,18 @@ static int initGl(uint32_t d_width, uint32_t d_height) { } ActiveTexture(GL_TEXTURE1); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); if (mipmap_gen) TexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); ActiveTexture(GL_TEXTURE2); glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); if (mipmap_gen) TexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE); ActiveTexture(GL_TEXTURE0); BindTexture(gl_target, 0); } - if (image_format == IMGFMT_YV12 || custom_prog) + if (is_yuv || custom_prog) { if ((MASK_NOT_COMBINERS & (1 << use_yuv)) || custom_prog) { if (!GenPrograms || !BindProgram) { @@ -530,9 +538,12 @@ static int initGl(uint32_t d_width, uint32_t d_height) { static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) { + int xs, ys; image_height = height; image_width = width; image_format = format; + is_yuv = mp_get_chroma_shift(image_format, &xs, &ys) > 0; + is_yuv |= (xs << 8) | (ys << 16); glFindFormat(format, NULL, &gl_texfmt, &gl_format, &gl_type); vo_flipped = !!(flags & VOFLAG_FLIPPING); @@ -701,14 +712,14 @@ static void do_render(void) { // BindTexture(GL_TEXTURE_2D, texture_id); Color3f(1,1,1); - if (image_format == IMGFMT_YV12 || custom_prog) + if (is_yuv || custom_prog) glEnableYUVConversion(gl_target, yuvconvtype); glDrawTex(0, 0, image_width, image_height, 0, 0, image_width, image_height, texture_width, texture_height, - use_rectangle == 1, image_format == IMGFMT_YV12, + use_rectangle == 1, is_yuv, mpi_flipped ^ vo_flipped); - if (image_format == IMGFMT_YV12 || custom_prog) + if (is_yuv || custom_prog) glDisableYUVConversion(gl_target, yuvconvtype); } @@ -737,13 +748,15 @@ static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) mpi_flipped = stride[0] < 0; glUploadTex(gl_target, gl_format, gl_type, src[0], stride[0], x, y, w, h, slice_height); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); ActiveTexture(GL_TEXTURE1); glUploadTex(gl_target, gl_format, gl_type, src[1], stride[1], - x / 2, y / 2, w / 2, h / 2, slice_height); + x >> xs, y >> ys, w >> xs, h >> ys, slice_height); ActiveTexture(GL_TEXTURE2); glUploadTex(gl_target, gl_format, gl_type, src[2], stride[2], - x / 2, y / 2, w / 2, h / 2, slice_height); + x >> xs, y >> ys, w >> xs, h >> ys, slice_height); ActiveTexture(GL_TEXTURE0); } return 0; @@ -801,14 +814,16 @@ static uint32_t get_image(mp_image_t *mpi) { err_shown = 1; return VO_FALSE; } - if (mpi->imgfmt == IMGFMT_YV12) { - // YV12 + if (is_yuv) { + // planar YUV + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); mpi->flags |= MP_IMGFLAG_COMMON_STRIDE | MP_IMGFLAG_COMMON_PLANE; mpi->stride[0] = mpi->width; mpi->planes[1] = mpi->planes[0] + mpi->stride[0] * mpi->height; - mpi->stride[1] = mpi->width >> 1; - mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> 1); - mpi->stride[2] = mpi->width >> 1; + mpi->stride[1] = mpi->width >> xs; + mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> ys); + mpi->stride[2] = mpi->width >> xs; if (ati_hack && !mesa_buffer) { mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE; if (!gl_buffer_uv[0]) GenBuffers(2, gl_buffer_uv); @@ -858,17 +873,19 @@ static uint32_t draw_image(mp_image_t *mpi) { mpi2.flags = 0; mpi2.type = MP_IMGTYPE_TEMP; mpi2.width = mpi2.w; mpi2.height = mpi2.h; if (force_pbo && !(mpi->flags & MP_IMGFLAG_DIRECT) && !gl_bufferptr && get_image(&mpi2) == VO_TRUE) { - int bpp = mpi->imgfmt == IMGFMT_YV12 ? 8 : mpi->bpp; + int bpp = is_yuv ? 8 : mpi->bpp; + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); memcpy_pic(mpi2.planes[0], mpi->planes[0], mpi->w * bpp / 8, mpi->h, mpi2.stride[0], mpi->stride[0]); - if (mpi->imgfmt == IMGFMT_YV12) { - memcpy_pic(mpi2.planes[1], mpi->planes[1], mpi->w >> 1, mpi->h >> 1, mpi2.stride[1], mpi->stride[1]); - memcpy_pic(mpi2.planes[2], mpi->planes[2], mpi->w >> 1, mpi->h >> 1, mpi2.stride[2], mpi->stride[2]); + if (is_yuv) { + memcpy_pic(mpi2.planes[1], mpi->planes[1], mpi->w >> xs, mpi->h >> ys, mpi2.stride[1], mpi->stride[1]); + memcpy_pic(mpi2.planes[2], mpi->planes[2], mpi->w >> xs, mpi->h >> ys, mpi2.stride[2], mpi->stride[2]); } if (ati_hack) { // since we have to do a full upload we need to clear the borders clear_border(mpi2.planes[0], mpi->w * bpp / 8, mpi2.stride[0], mpi->h, mpi2.height, 0); - if (mpi->imgfmt == IMGFMT_YV12) { - clear_border(mpi2.planes[1], mpi->w >> 1, mpi2.stride[1], mpi->h >> 1, mpi2.height >> 1, 128); - clear_border(mpi2.planes[2], mpi->w >> 1, mpi2.stride[2], mpi->h >> 1, mpi2.height >> 1, 128); + if (is_yuv) { + clear_border(mpi2.planes[1], mpi->w >> xs, mpi2.stride[1], mpi->h >> ys, mpi2.height >> ys, 128); + clear_border(mpi2.planes[2], mpi->w >> xs, mpi2.stride[2], mpi->h >> ys, mpi2.height >> ys, 128); } } mpi = &mpi2; @@ -898,7 +915,9 @@ static uint32_t draw_image(mp_image_t *mpi) { } glUploadTex(gl_target, gl_format, gl_type, planes[0], stride[0], mpi->x, mpi->y, w, h, slice); - if (mpi->imgfmt == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) { BindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_buffer_uv[0]); UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); @@ -906,7 +925,7 @@ static uint32_t draw_image(mp_image_t *mpi) { } ActiveTexture(GL_TEXTURE1); glUploadTex(gl_target, gl_format, gl_type, planes[1], stride[1], - mpi->x / 2, mpi->y / 2, w / 2, h / 2, slice); + mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys, slice); if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) { BindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_buffer_uv[1]); UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); @@ -914,7 +933,7 @@ static uint32_t draw_image(mp_image_t *mpi) { } ActiveTexture(GL_TEXTURE2); glUploadTex(gl_target, gl_format, gl_type, planes[2], stride[2], - mpi->x / 2, mpi->y / 2, w / 2, h / 2, slice); + mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys, slice); ActiveTexture(GL_TEXTURE0); } if (mpi->flags & MP_IMGFLAG_DIRECT) { @@ -942,7 +961,8 @@ query_format(uint32_t format) caps |= VFCAP_OSD | VFCAP_EOSD | (scaled_osd ? 0 : VFCAP_EOSD_UNSCALED); if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA) return caps; - if (use_yuv && format == IMGFMT_YV12) + if (use_yuv && mp_get_chroma_shift(format, NULL, NULL) && + (IMGFMT_IS_YUVP16_NE(format) || !IMGFMT_IS_YUVP16(format))) return caps; // HACK, otherwise we get only b&w with some filters (e.g. -vf eq) // ideally MPlayer should be fixed instead not to use Y800 when it has the choice @@ -969,17 +989,24 @@ uninit(void) uninit_mpglcontext(&glctx); } +static int valid_csp(void *p) +{ + int *csp = p; + return *csp >= -1 && *csp < MP_CSP_COUNT; +} + static const opt_t subopts[] = { {"manyfmts", OPT_ARG_BOOL, &many_fmts, NULL}, {"osd", OPT_ARG_BOOL, &use_osd, NULL}, {"scaled-osd", OPT_ARG_BOOL, &scaled_osd, NULL}, {"aspect", OPT_ARG_BOOL, &use_aspect, NULL}, {"ycbcr", OPT_ARG_BOOL, &use_ycbcr, NULL}, - {"slice-height", OPT_ARG_INT, &slice_height, (opt_test_f)int_non_neg}, - {"rectangle", OPT_ARG_INT, &use_rectangle,(opt_test_f)int_non_neg}, - {"yuv", OPT_ARG_INT, &use_yuv, (opt_test_f)int_non_neg}, - {"lscale", OPT_ARG_INT, &lscale, (opt_test_f)int_non_neg}, - {"cscale", OPT_ARG_INT, &cscale, (opt_test_f)int_non_neg}, + {"slice-height", OPT_ARG_INT, &slice_height, int_non_neg}, + {"rectangle", OPT_ARG_INT, &use_rectangle,int_non_neg}, + {"yuv", OPT_ARG_INT, &use_yuv, int_non_neg}, + {"colorspace", OPT_ARG_INT, &colorspace, valid_csp}, + {"lscale", OPT_ARG_INT, &lscale, int_non_neg}, + {"cscale", OPT_ARG_INT, &cscale, int_non_neg}, {"filter-strength", OPT_ARG_FLOAT, &filter_strength, NULL}, {"ati-hack", OPT_ARG_BOOL, &ati_hack, NULL}, {"force-pbo", OPT_ARG_BOOL, &force_pbo, NULL}, @@ -1008,6 +1035,7 @@ static int preinit(const char *arg) use_aspect = 1; use_ycbcr = 0; use_yuv = 0; + colorspace = -1; lscale = 0; cscale = 0; filter_strength = 0.5; @@ -1063,6 +1091,13 @@ static int preinit(const char *arg) " 4: use fragment program with gamma correction via lookup.\n" " 5: use ATI-specific method (for older cards).\n" " 6: use lookup via 3D texture.\n" + " colorspace=<n>\n" + " 0: MPlayer's default YUV to RGB conversion\n" + " 1: YUV to RGB according to BT.601\n" + " 2: YUV to RGB according to BT.709\n" + " 3: YUV to RGB according to SMPT-240M\n" + " 4: YUV to RGB according to EBU\n" + " 5: XYZ to RGB\n" " lscale=<n>\n" " 0: use standard bilinear scaling for luma.\n" " 1: use improved bicubic scaling for luma.\n" @@ -1170,7 +1205,7 @@ static int control(uint32_t request, void *data) resize(vo_dwidth, vo_dheight); return VO_TRUE; case VOCTRL_GET_EQUALIZER: - if (image_format == IMGFMT_YV12) { + if (is_yuv) { struct voctrl_get_equalizer_args *args = data; int i; for (i = 0; eq_map[i].name; i++) @@ -1182,7 +1217,7 @@ static int control(uint32_t request, void *data) } break; case VOCTRL_SET_EQUALIZER: - if (image_format == IMGFMT_YV12) { + if (is_yuv) { struct voctrl_set_equalizer_args *args = data; int i; for (i = 0; eq_map[i].name; i++) diff --git a/libvo/vo_gl2.c b/libvo/vo_gl2.c index 73c09364f7..f1f69f3de2 100644 --- a/libvo/vo_gl2.c +++ b/libvo/vo_gl2.c @@ -85,6 +85,7 @@ static int isGL12 = GL_FALSE; static int gl_bilinear=1; static int gl_antialias=0; static int use_yuv; +static int is_yuv; static int use_glFinish; static void (*draw_alpha_fnc) @@ -181,7 +182,7 @@ static int initTextures(void) s*=2; texture_height=s; - if (image_format != IMGFMT_YV12) + if (!is_yuv) gl_internal_format = getInternalFormat(); /* Test the max texture size */ @@ -260,7 +261,7 @@ static int initTextures(void) glGenTextures (1, &(tsq->texobj)); glBindTexture (GL_TEXTURE_2D, tsq->texobj); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { glGenTextures(2, tsq->uvtexobjs); ActiveTexture(GL_TEXTURE1); glBindTexture (GL_TEXTURE_2D, tsq->uvtexobjs[0]); @@ -273,13 +274,15 @@ static int initTextures(void) texture_width, texture_height, 0); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { + int xs, ys; + mp_get_chroma_shift(image_format, &xs, &ys); ActiveTexture(GL_TEXTURE1); glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); ActiveTexture(GL_TEXTURE2); glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format, gl_bitmap_type, GL_LINEAR, - texture_width / 2, texture_height / 2, 128); + texture_width >> xs, texture_height >> ys, 128); ActiveTexture(GL_TEXTURE0); } @@ -378,7 +381,7 @@ static void drawTextureDisplay (void) glColor3f(1.0,1.0,1.0); - if (image_format == IMGFMT_YV12) + if (is_yuv) glEnableYUVConversion(GL_TEXTURE_2D, use_yuv); for (y = 0; y < texnumy; y++) { int thish = texture_height; @@ -389,7 +392,7 @@ static void drawTextureDisplay (void) if (x == texnumx - 1 && image_width % texture_width) thisw = image_width % texture_width; glBindTexture (GL_TEXTURE_2D, square->texobj); - if (image_format == IMGFMT_YV12) { + if (is_yuv) { ActiveTexture(GL_TEXTURE1); glBindTexture (GL_TEXTURE_2D, square |