From fbacd5de31de964f7cd562304ab1c9b4a0d76015 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sat, 28 Feb 2015 00:59:09 +0100 Subject: 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. --- video/csputils.c | 33 +++++++++++++++++++++++++++++++++ video/csputils.h | 14 ++++++++++---- video/mp_image.c | 11 ++++++++++- video/mp_image.h | 1 + video/out/gl_video.c | 17 +---------------- 5 files changed, 55 insertions(+), 21 deletions(-) (limited to 'video') diff --git a/video/csputils.c b/video/csputils.c index 90eec39d36..cbd9734819 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -65,6 +65,13 @@ const char *const mp_csp_prim_names[MP_CSP_PRIM_COUNT] = { "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] = { "brightness", "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) { 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) { return width >= 1280 || height > 576 ? MP_CSP_BT_709 : MP_CSP_BT_601; diff --git a/video/csputils.h b/video/csputils.h index b6d17c1815..b84a4a3544 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -68,15 +68,19 @@ enum mp_csp_prim { 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]; + enum mp_csp_trc { - MP_CSP_TRC_NONE, + MP_CSP_TRC_AUTO, MP_CSP_TRC_BT_1886, MP_CSP_TRC_SRGB, - MP_CSP_TRC_LINEAR + MP_CSP_TRC_LINEAR, + MP_CSP_TRC_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]; +// 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 // up with the API of LittleCMS, which treats them as integers. @@ -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_trc_to_avcol_trc(enum mp_csp_trc trc); + enum mp_csp mp_csp_guess_colorspace(int width, int height); enum mp_csp_prim mp_csp_guess_primaries(int width, int height); diff --git a/video/mp_image.c b/video/mp_image.c index 44f5ab903c..64476a6d99 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -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_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)) { dst->params.colorspace = src->params.colorspace; dst->params.colorlevels = src->params.colorlevels; - dst->params.primaries = src->params.primaries; dst->params.chroma_location = src->params.chroma_location; 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->outputlevels == p2->outputlevels && p1->primaries == p2->primaries && + p1->gamma == p2->gamma && p1->chroma_location == p2->chroma_location && p1->rotate == p2->rotate && 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); } } + if (params->gamma == MP_CSP_TRC_AUTO) + params->gamma = MP_CSP_TRC_BT_1886; } else if (fmt.flags & MP_IMGFLAG_RGB) { params->colorspace = MP_CSP_RGB; 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 if (params->primaries == MP_CSP_PRIM_AUTO) 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) { params->colorspace = MP_CSP_XYZ; params->colorlevels = MP_CSP_LEVELS_PC; @@ -603,11 +609,14 @@ void mp_image_params_guess_csp(struct mp_image_params *params) // tagged with. if (params->primaries == MP_CSP_PRIM_AUTO) params->primaries = MP_CSP_PRIM_BT_709; + if (params->gamma = MP_CSP_TRC_AUTO) + params->gamma = MP_CSP_TRC_LINEAR; } else { // We have no clue. params->colorspace = MP_CSP_AUTO; params->colorlevels = MP_CSP_LEVELS_AUTO; params->primaries = MP_CSP_PRIM_AUTO; + params->gamma = MP_CSP_TRC_AUTO; } } diff --git a/video/mp_image.h b/video/mp_image.h index 5263249987..3017ef46eb 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -48,6 +48,7 @@ struct mp_image_params { enum mp_csp colorspace; enum mp_csp_levels colorlevels; enum mp_csp_prim primaries; + enum mp_csp_trc gamma; enum mp_chroma_location chroma_location; // The image should be converted to these levels. Unlike colorlevels, it // does not describe the current state of the image. (Somewhat similar to diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 23b19b3125..9c8a64365d 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -937,8 +937,7 @@ static void compile_shaders(struct gl_video *p) bool use_input_gamma = p->input_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; - - enum mp_csp_trc gamma_fun = MP_CSP_TRC_NONE; + enum mp_csp_trc gamma_fun = p->image_params.gamma; // If either color correction option (3dlut or srgb) is enabled, or if // 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 || 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 CMS cases, but if CMS is disabled we need to go back manually bool use_inv_bt1886 = false; -- cgit v1.2.3