summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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) {