0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02:00

csputils: add missing gamma support

We have MP_CSP_TRC defined, but it wasn't being used by practically
anything. This commit adds missing conversion logic, adds it to
mp_image, and moves the auto-guessing logic to where it should be, in
mp_image_params_guess_csp (and out of vo_opengl).

Note that this also fixes a minor bug: csp_prim was not being copied
between mp_image structs if the format was not YUV in both cases, but
this is wrong - the primaries are always relevant.
This commit is contained in:
Niklas Haas 2015-02-28 00:59:09 +01:00
parent 076b3d1385
commit fbacd5de31
5 changed files with 58 additions and 24 deletions

View File

@ -65,6 +65,13 @@ const char *const mp_csp_prim_names[MP_CSP_PRIM_COUNT] = {
"BT.470 M", "BT.470 M",
}; };
const char *const mp_csp_trc_names[MP_CSP_TRC_COUNT] = {
"Autoselect",
"BT.1886 (SD, HD, UHD)",
"sRGB (IEC 61966-2-1)",
"Linear light",
};
const char *const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = { const char *const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = {
"brightness", "brightness",
"contrast", "contrast",
@ -142,6 +149,21 @@ enum mp_csp_prim avcol_pri_to_mp_csp_prim(int avpri)
} }
} }
enum mp_csp_trc avcol_trc_to_mp_csp_trc(int avtrc)
{
switch (avtrc) {
case AVCOL_TRC_BT709:
case AVCOL_TRC_SMPTE170M:
case AVCOL_TRC_SMPTE240M:
case AVCOL_TRC_BT1361_ECG:
case AVCOL_TRC_BT2020_10:
case AVCOL_TRC_BT2020_12: return MP_CSP_TRC_BT_1886;
case AVCOL_TRC_IEC61966_2_1: return MP_CSP_TRC_SRGB;
case AVCOL_TRC_LINEAR: return MP_CSP_TRC_LINEAR;
default: return MP_CSP_TRC_AUTO;
}
}
int mp_csp_to_avcol_spc(enum mp_csp colorspace) int mp_csp_to_avcol_spc(enum mp_csp colorspace)
{ {
switch (colorspace) { switch (colorspace) {
@ -181,6 +203,17 @@ int mp_csp_prim_to_avcol_pri(enum mp_csp_prim prim)
} }
} }
int mp_csp_trc_to_avcol_trc(enum mp_csp_trc trc)
{
switch (trc) {
// We just call it BT.1886 since we're decoding, but it's still BT.709
case MP_CSP_TRC_BT_1886: return AVCOL_TRC_BT709;
case MP_CSP_TRC_SRGB: return AVCOL_TRC_IEC61966_2_1;
case MP_CSP_TRC_LINEAR: return AVCOL_TRC_LINEAR;
default: return AVCOL_TRC_UNSPECIFIED;
}
}
enum mp_csp mp_csp_guess_colorspace(int width, int height) enum mp_csp mp_csp_guess_colorspace(int width, int height)
{ {
return width >= 1280 || height > 576 ? MP_CSP_BT_709 : MP_CSP_BT_601; return width >= 1280 || height > 576 ? MP_CSP_BT_709 : MP_CSP_BT_601;

View File

@ -68,16 +68,20 @@ enum mp_csp_prim {
MP_CSP_PRIM_COUNT MP_CSP_PRIM_COUNT
}; };
enum mp_csp_trc {
MP_CSP_TRC_NONE,
MP_CSP_TRC_BT_1886,
MP_CSP_TRC_SRGB,
MP_CSP_TRC_LINEAR
};
// Any enum mp_csp_prim value is a valid index (except MP_CSP_PRIM_COUNT) // Any enum mp_csp_prim value is a valid index (except MP_CSP_PRIM_COUNT)
extern const char *const mp_csp_prim_names[MP_CSP_PRIM_COUNT]; extern const char *const mp_csp_prim_names[MP_CSP_PRIM_COUNT];
enum mp_csp_trc {
MP_CSP_TRC_AUTO,
MP_CSP_TRC_BT_1886,
MP_CSP_TRC_SRGB,
MP_CSP_TRC_LINEAR,
MP_CSP_TRC_COUNT
};
// Any enum mp_csp_trc value is a valid index (except MP_CSP_TRC_COUNT)
extern const char *const mp_csp_trc_names[MP_CSP_TRC_COUNT];
// These constants are based on the ICC specification (Table 23) and match // These constants are based on the ICC specification (Table 23) and match
// up with the API of LittleCMS, which treats them as integers. // up with the API of LittleCMS, which treats them as integers.
enum mp_render_intent { enum mp_render_intent {
@ -205,6 +209,8 @@ int mp_csp_levels_to_avcol_range(enum mp_csp_levels range);
int mp_csp_prim_to_avcol_pri(enum mp_csp_prim prim); int mp_csp_prim_to_avcol_pri(enum mp_csp_prim prim);
int mp_csp_trc_to_avcol_trc(enum mp_csp_trc trc);
enum mp_csp mp_csp_guess_colorspace(int width, int height); enum mp_csp mp_csp_guess_colorspace(int width, int height);
enum mp_csp_prim mp_csp_guess_primaries(int width, int height); enum mp_csp_prim mp_csp_guess_primaries(int width, int height);

View File

@ -368,10 +368,11 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src)
dst->params.d_w = src->params.d_w; dst->params.d_w = src->params.d_w;
dst->params.d_h = src->params.d_h; dst->params.d_h = src->params.d_h;
} }
dst->params.primaries = src->params.primaries;
dst->params.gamma = src->params.gamma;
if ((dst->flags & MP_IMGFLAG_YUV) == (src->flags & MP_IMGFLAG_YUV)) { if ((dst->flags & MP_IMGFLAG_YUV) == (src->flags & MP_IMGFLAG_YUV)) {
dst->params.colorspace = src->params.colorspace; dst->params.colorspace = src->params.colorspace;
dst->params.colorlevels = src->params.colorlevels; dst->params.colorlevels = src->params.colorlevels;
dst->params.primaries = src->params.primaries;
dst->params.chroma_location = src->params.chroma_location; dst->params.chroma_location = src->params.chroma_location;
dst->params.outputlevels = src->params.outputlevels; dst->params.outputlevels = src->params.outputlevels;
} }
@ -516,6 +517,7 @@ bool mp_image_params_equal(const struct mp_image_params *p1,
p1->colorlevels == p2->colorlevels && p1->colorlevels == p2->colorlevels &&
p1->outputlevels == p2->outputlevels && p1->outputlevels == p2->outputlevels &&
p1->primaries == p2->primaries && p1->primaries == p2->primaries &&
p1->gamma == p2->gamma &&
p1->chroma_location == p2->chroma_location && p1->chroma_location == p2->chroma_location &&
p1->rotate == p2->rotate && p1->rotate == p2->rotate &&
p1->stereo_in == p2->stereo_in && p1->stereo_in == p2->stereo_in &&
@ -578,6 +580,8 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
params->primaries = mp_csp_guess_primaries(params->w, params->h); params->primaries = mp_csp_guess_primaries(params->w, params->h);
} }
} }
if (params->gamma == MP_CSP_TRC_AUTO)
params->gamma = MP_CSP_TRC_BT_1886;
} else if (fmt.flags & MP_IMGFLAG_RGB) { } else if (fmt.flags & MP_IMGFLAG_RGB) {
params->colorspace = MP_CSP_RGB; params->colorspace = MP_CSP_RGB;
params->colorlevels = MP_CSP_LEVELS_PC; params->colorlevels = MP_CSP_LEVELS_PC;
@ -589,6 +593,8 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
// Note: sRGB primaries = BT.709 primaries // Note: sRGB primaries = BT.709 primaries
if (params->primaries == MP_CSP_PRIM_AUTO) if (params->primaries == MP_CSP_PRIM_AUTO)
params->primaries = MP_CSP_PRIM_BT_709; params->primaries = MP_CSP_PRIM_BT_709;
if (params->gamma == MP_CSP_TRC_AUTO)
params->gamma = MP_CSP_TRC_SRGB;
} else if (fmt.flags & MP_IMGFLAG_XYZ) { } else if (fmt.flags & MP_IMGFLAG_XYZ) {
params->colorspace = MP_CSP_XYZ; params->colorspace = MP_CSP_XYZ;
params->colorlevels = MP_CSP_LEVELS_PC; params->colorlevels = MP_CSP_LEVELS_PC;
@ -603,11 +609,14 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
// tagged with. // tagged with.
if (params->primaries == MP_CSP_PRIM_AUTO) if (params->primaries == MP_CSP_PRIM_AUTO)
params->primaries = MP_CSP_PRIM_BT_709; params->primaries = MP_CSP_PRIM_BT_709;
if (params->gamma = MP_CSP_TRC_AUTO)
params->gamma = MP_CSP_TRC_LINEAR;
} else { } else {
// We have no clue. // We have no clue.
params->colorspace = MP_CSP_AUTO; params->colorspace = MP_CSP_AUTO;
params->colorlevels = MP_CSP_LEVELS_AUTO; params->colorlevels = MP_CSP_LEVELS_AUTO;
params->primaries = MP_CSP_PRIM_AUTO; params->primaries = MP_CSP_PRIM_AUTO;
params->gamma = MP_CSP_TRC_AUTO;
} }
} }

View File

@ -48,6 +48,7 @@ struct mp_image_params {
enum mp_csp colorspace; enum mp_csp colorspace;
enum mp_csp_levels colorlevels; enum mp_csp_levels colorlevels;
enum mp_csp_prim primaries; enum mp_csp_prim primaries;
enum mp_csp_trc gamma;
enum mp_chroma_location chroma_location; enum mp_chroma_location chroma_location;
// The image should be converted to these levels. Unlike colorlevels, it // The image should be converted to these levels. Unlike colorlevels, it
// does not describe the current state of the image. (Somewhat similar to // does not describe the current state of the image. (Somewhat similar to

View File

@ -937,8 +937,7 @@ static void compile_shaders(struct gl_video *p)
bool use_input_gamma = p->input_gamma != 1.0; bool use_input_gamma = p->input_gamma != 1.0;
bool use_conv_gamma = p->conv_gamma != 1.0; bool use_conv_gamma = p->conv_gamma != 1.0;
bool use_const_luma = p->image_params.colorspace == MP_CSP_BT_2020_C; bool use_const_luma = p->image_params.colorspace == MP_CSP_BT_2020_C;
enum mp_csp_trc gamma_fun = p->image_params.gamma;
enum mp_csp_trc gamma_fun = MP_CSP_TRC_NONE;
// If either color correction option (3dlut or srgb) is enabled, or if // If either color correction option (3dlut or srgb) is enabled, or if
// sigmoidal upscaling is requested, or if the source is linear XYZ, we // sigmoidal upscaling is requested, or if the source is linear XYZ, we
@ -946,20 +945,6 @@ static void compile_shaders(struct gl_video *p)
bool use_linear_light = p->opts.linear_scaling || p->opts.sigmoid_upscaling bool use_linear_light = p->opts.linear_scaling || p->opts.sigmoid_upscaling
|| use_cms || is_xyz; || use_cms || is_xyz;
if (use_linear_light) {
// We use the color level range to distinguish between PC
// content like images, which are most likely sRGB, and TV content
// like movies, which are most likely BT.1886. XYZ input is always
// treated as linear.
if (is_xyz) {
gamma_fun = MP_CSP_TRC_LINEAR;
} else if (p->image_params.colorlevels == MP_CSP_LEVELS_PC) {
gamma_fun = MP_CSP_TRC_SRGB;
} else {
gamma_fun = MP_CSP_TRC_BT_1886;
}
}
// The inverse of the above transformation is normally handled by // The inverse of the above transformation is normally handled by
// the CMS cases, but if CMS is disabled we need to go back manually // the CMS cases, but if CMS is disabled we need to go back manually
bool use_inv_bt1886 = false; bool use_inv_bt1886 = false;