summaryrefslogtreecommitdiffstats
path: root/libvo
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2010-01-08 01:05:30 +0200
committerUoti Urpala <uau@glyph.nonexistent.invalid>2010-01-08 01:05:30 +0200
commit231b33a02fae95b260120349040106bfa34a3750 (patch)
tree23c4de0e6263b2d99966348d7003177b3b3e3740 /libvo
parent52126e574c7872ca95e7974cfe5445421b74f24c (diff)
parent92cd6dc3e916ae4275ff05d2b238fc778cfbfc6b (diff)
downloadmpv-231b33a02fae95b260120349040106bfa34a3750.tar.bz2
mpv-231b33a02fae95b260120349040106bfa34a3750.tar.xz
Merge svn changes up to r30165
Diffstat (limited to 'libvo')
-rw-r--r--libvo/csputils.c160
-rw-r--r--libvo/csputils.h56
-rw-r--r--libvo/gl_common.c143
-rw-r--r--libvo/gl_common.h12
-rw-r--r--libvo/vo_gl.c105
-rw-r--r--libvo/vo_gl2.c65
-rw-r--r--libvo/vo_ivtv.c2
-rw-r--r--libvo/vo_jpeg.c15
-rw-r--r--libvo/vo_png.c9
-rw-r--r--libvo/vo_pnm.c2
-rw-r--r--libvo/vo_v4l2.c2
-rw-r--r--libvo/vo_xv.c15
-rw-r--r--libvo/vo_xvmc.c4
-rw-r--r--libvo/vo_zr2.c10
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(&params->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(&params->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(&params);
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_forma