summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-12-07 23:41:29 +0100
committerwm4 <wm4@nowhere>2015-12-07 23:48:59 +0100
commit663415b914d48ea996a9b770f57b14f9ec8136db (patch)
treea38b685bc2f646b5012e6b4d58fce0f50120cf33 /video
parentc569d4f6ed7f8395d8c399bde048234065f0c65a (diff)
downloadmpv-663415b914d48ea996a9b770f57b14f9ec8136db.tar.bz2
mpv-663415b914d48ea996a9b770f57b14f9ec8136db.tar.xz
vo_opengl: fix issues with some obscure pixel formats
The computation of the tex_mul variable was broken in multiple ways. This variable is used e.g. by debanding for moving expansion of 10 bit fixed-point input to normalized range to another stage of processing. One obvious bug was that the rgb555 pixel format was broken. This format has component_bits=5, but obviously it's already sampled in normalized range, and does not need expansion. The tex_mul-free code path avoids this by not using the colormatrix. (The code was originally designed to work around dealing with the generally complicated pixel formats by only using the colormatrix in the YUV case.) Another possible bug was with 10 bit input. It expanded the input by bringing the [0,2^10) range to [0,1], and then treating the expanded input as 16 bit input. I didn't bother to check what this actually computed, but it's somewhat likely it was wrong anyway. Now it uses mp_get_csp_mul(), and disables expansion when computing the YUV matrix.
Diffstat (limited to 'video')
-rw-r--r--video/csputils.c28
-rw-r--r--video/csputils.h2
-rw-r--r--video/img_format.c6
-rw-r--r--video/img_format.h2
-rw-r--r--video/out/opengl/video.c12
5 files changed, 39 insertions, 11 deletions
diff --git a/video/csputils.c b/video/csputils.c
index 60cdc54746..1f0fa7d90e 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -552,6 +552,27 @@ void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params,
m->c[i] = brightness;
}
+// Get multiplication factor required if image data is fit within the LSBs of a
+// higher smaller bit depth isfixed-point texture data.
+double mp_get_csp_mul(enum mp_csp csp, int input_bits, int texture_bits)
+{
+ assert(texture_bits >= input_bits);
+
+ // Convenience for some irrelevant cases, e.g. rgb565 or disabling expansion.
+ if (!input_bits)
+ return 1;
+
+ // RGB always uses the full range available.
+ if (csp == MP_CSP_RGB)
+ return ((1LL << input_bits) - 1.) / ((1LL << texture_bits) - 1.);
+
+ if (csp == MP_CSP_XYZ)
+ return 1;
+
+ // High bit depth YUV uses a range shifted from 8 bit.
+ return (1LL << input_bits) / ((1LL << texture_bits) - 1.) * 255 / 256;
+}
+
/* Fill in the Y, U, V vectors of a yuv2rgb conversion matrix
* based on the given luma weights of the R, G and B components (lr, lg, lb).
* lr+lg+lb is assumed to equal 1.
@@ -642,10 +663,9 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *m)
m->m[i][2] = huesin * u + huecos * v;
}
- assert(params->input_bits >= 8);
- assert(params->texture_bits >= params->input_bits);
- double s = (1 << (params->input_bits-8)) / ((1<<params->texture_bits)-1.);
- // The values below are written in 0-255 scale
+ // The values below are written in 0-255 scale - thus bring s into range.
+ double s =
+ mp_get_csp_mul(colorspace, params->input_bits, params->texture_bits) / 255;
struct yuvlevels { double ymin, ymax, cmin, cmid; }
yuvlim = { 16*s, 235*s, 16*s, 128*s },
yuvfull = { 0*s, 255*s, 1*s, 128*s }, // '1' for symmetry around 128
diff --git a/video/csputils.h b/video/csputils.h
index df5da4a1c6..0a9b11af9d 100644
--- a/video/csputils.h
+++ b/video/csputils.h
@@ -251,6 +251,8 @@ struct mp_cmat {
void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest,
enum mp_render_intent intent, float cms_matrix[3][3]);
+double mp_get_csp_mul(enum mp_csp csp, int input_bits, int texture_bits);
+
void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, struct mp_csp_primaries prim,
enum mp_render_intent intent, struct mp_cmat *xyz2rgb);
void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *yuv2rgb);
diff --git a/video/img_format.c b/video/img_format.c
index 332bf3676f..42b4df45ab 100644
--- a/video/img_format.c
+++ b/video/img_format.c
@@ -174,6 +174,7 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
}
desc.plane_bits = planedepth[0];
+ desc.component_full_bits = desc.component_bits;
// Check whether any components overlap other components (per plane).
// We're cheating/simplifying here: we assume that this happens if a shift
@@ -241,6 +242,7 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
desc.bpp[p] == desc.bpp[0];
}
if (same_depth && pd->nb_components == desc.num_planes) {
+ desc.component_full_bits = (desc.component_bits + 7) / 8 * 8;
if (desc.flags & MP_IMGFLAG_YUV) {
desc.flags |= MP_IMGFLAG_YUV_P;
} else {
@@ -262,7 +264,9 @@ struct mp_imgfmt_desc mp_imgfmt_get_desc(int mpfmt)
if (pd->flags & AV_PIX_FMT_FLAG_HWACCEL) {
desc.flags |= MP_IMGFLAG_HWACCEL;
- desc.plane_bits = 8; // usually restricted to 8 bit; may change
+ desc.component_bits = 8; // usually restricted to 8 bit; may change
+ desc.component_full_bits = desc.component_bits;
+ desc.plane_bits = desc.component_bits;
}
if (desc.chroma_xs || desc.chroma_ys)
diff --git a/video/img_format.h b/video/img_format.h
index cd2ebf5360..0d8c699850 100644
--- a/video/img_format.h
+++ b/video/img_format.h
@@ -86,6 +86,8 @@ struct mp_imgfmt_desc {
int8_t bpp[MP_MAX_PLANES]; // bits per pixel
int8_t plane_bits; // number of bits in use for plane 0
int8_t component_bits; // number of bits per component (0 if uneven)
+ int8_t component_full_bits; // number of bits per component including
+ // internal padding (0 if uneven)
// chroma shifts per plane (provided for convenience with planar formats)
int8_t xs[MP_MAX_PLANES];
int8_t ys[MP_MAX_PLANES];
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index 790ced1e42..17fc809fe4 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -1327,9 +1327,9 @@ static void pass_read_video(struct gl_video *p)
struct gl_transform chromafix;
pass_set_image_textures(p, &p->image, &chromafix);
- int in_bits = p->image_desc.component_bits,
- tx_bits = (in_bits + 7) & ~7;
- float tex_mul = ((1 << tx_bits) - 1.0) / ((1 << in_bits) - 1.0);
+ float tex_mul = 1 / mp_get_csp_mul(p->image_params.colorspace,
+ p->image_desc.component_bits,
+ p->image_desc.component_full_bits);
struct src_tex prescaled_tex;
struct gl_transform offset = {{{0}}};
@@ -1465,7 +1465,7 @@ static void pass_convert_yuv(struct gl_video *p)
struct mp_csp_params cparams = MP_CSP_PARAMS_DEFAULTS;
cparams.gray = p->is_yuv && !p->is_packed_yuv && p->plane_count == 1;
cparams.input_bits = p->image_desc.component_bits;
- cparams.texture_bits = (cparams.input_bits + 7) & ~7;
+ cparams.texture_bits = p->image_desc.component_full_bits;
mp_csp_set_image_params(&cparams, &p->image_params);
mp_csp_copy_equalizer_values(&cparams, &p->video_eq);
p->user_gamma = 1.0 / (cparams.gamma * p->opts.gamma);
@@ -1484,9 +1484,9 @@ static void pass_convert_yuv(struct gl_video *p)
GLSL(color.rgb = pow(color.rgb, vec3(2.6));)
}
- // Something already took care of expansion
+ // Something already took care of expansion - disable it.
if (p->use_normalized_range)
- cparams.input_bits = cparams.texture_bits;
+ cparams.input_bits = cparams.texture_bits = 0;
// Conversion from Y'CbCr or other linear spaces to RGB
if (!p->is_rgb) {