diff --git a/player/command.c b/player/command.c index caca0c32ec..85f453e0ef 100644 --- a/player/command.c +++ b/player/command.c @@ -2569,13 +2569,13 @@ static int property_imgparams(struct mp_image_params p, int action, void *arg) {"aspect", SUB_PROP_FLOAT(d_w / (double)d_h)}, {"par", SUB_PROP_FLOAT(p.p_w / (double)p.p_h)}, {"colormatrix", - SUB_PROP_STR(m_opt_choice_str(mp_csp_names, p.colorspace))}, + SUB_PROP_STR(m_opt_choice_str(mp_csp_names, p.color.space))}, {"colorlevels", - SUB_PROP_STR(m_opt_choice_str(mp_csp_levels_names, p.colorlevels))}, + SUB_PROP_STR(m_opt_choice_str(mp_csp_levels_names, p.color.levels))}, {"primaries", - SUB_PROP_STR(m_opt_choice_str(mp_csp_prim_names, p.primaries))}, + SUB_PROP_STR(m_opt_choice_str(mp_csp_prim_names, p.color.primaries))}, {"gamma", - SUB_PROP_STR(m_opt_choice_str(mp_csp_trc_names, p.gamma))}, + SUB_PROP_STR(m_opt_choice_str(mp_csp_trc_names, p.color.gamma))}, {"chroma-location", SUB_PROP_STR(m_opt_choice_str(mp_chroma_names, p.chroma_location))}, {"stereo-in", diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index 5356a8fa99..b79810ce9a 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -193,8 +193,7 @@ static void scale_sb_rgba(struct sub_bitmap *sb, struct mp_image *dst_format, mp_image_swscale(sbisrc2, &sbisrc, SWS_BILINEAR); unpremultiply_and_split_BGR32(sbisrc2, sba); - sbi->params.colorspace = dst_format->params.colorspace; - sbi->params.colorlevels = dst_format->params.colorlevels; + sbi->params.color = dst_format->params.color; mp_image_swscale(sbi, sbisrc2, SWS_BILINEAR); talloc_free(sbisrc2); @@ -367,8 +366,8 @@ static struct part *get_cache(struct mp_draw_sub_cache *cache, if (part) { if (part->change_id != sbs->change_id || part->imgfmt != format->imgfmt - || part->colorspace != format->params.colorspace - || part->levels != format->params.colorlevels) + || part->colorspace != format->params.color.space + || part->levels != format->params.color.levels) { talloc_free(part); part = NULL; @@ -380,8 +379,8 @@ static struct part *get_cache(struct mp_draw_sub_cache *cache, .change_id = sbs->change_id, .num_imgs = sbs->num_parts, .imgfmt = format->imgfmt, - .levels = format->params.colorlevels, - .colorspace = format->params.colorspace, + .levels = format->params.color.levels, + .colorspace = format->params.color.space, }; part->imgs = talloc_zero_array(part, struct sub_cache, part->num_imgs); @@ -436,10 +435,8 @@ static struct mp_image *chroma_up(struct mp_draw_sub_cache *cache, int imgfmt, // The temp image is always YUV, but src not necessarily. // Reduce amount of conversions in YUV case (upsampling/shifting only) - if (src->fmt.flags & MP_IMGFLAG_YUV) { - temp->params.colorspace = src->params.colorspace; - temp->params.colorlevels = src->params.colorlevels; - } + if (src->fmt.flags & MP_IMGFLAG_YUV) + temp->params.color = src->params.color; if (src->imgfmt == IMGFMT_420P) { assert(imgfmt == IMGFMT_444P); diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 7abeea9eeb..34a49c1501 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -733,15 +733,17 @@ static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts) struct mp_image_params params = ctx->video_params; if (force_601) { - params.colorspace = MP_CSP_BT_709; - params.colorlevels = MP_CSP_LEVELS_TV; + params.color = (struct mp_colorspace){ + .space = MP_CSP_BT_709, + .levels = MP_CSP_LEVELS_TV, + }; } - if (csp == params.colorspace && levels == params.colorlevels) + if (csp == params.color.space && levels == params.color.levels) return; - bool basic_conv = params.colorspace == MP_CSP_BT_709 && - params.colorlevels == MP_CSP_LEVELS_TV && + bool basic_conv = params.color.space == MP_CSP_BT_709 && + params.color.levels == MP_CSP_LEVELS_TV && csp == MP_CSP_BT_601 && levels == MP_CSP_LEVELS_TV; @@ -749,8 +751,8 @@ static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts) if (opts->ass_vsfilter_color_compat == 1 && !basic_conv) return; - if (params.colorspace != ctx->last_params.colorspace || - params.colorlevels != ctx->last_params.colorlevels) + if (params.color.space != ctx->last_params.color.space || + params.color.levels != ctx->last_params.color.levels) { int msgl = basic_conv ? MSGL_V : MSGL_WARN; ctx->last_params = params; @@ -758,22 +760,21 @@ static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts) "RGB -> %s %s -> %s %s -> RGB\n", m_opt_choice_str(mp_csp_names, csp), m_opt_choice_str(mp_csp_levels_names, levels), - m_opt_choice_str(mp_csp_names, params.colorspace), - m_opt_choice_str(mp_csp_names, params.colorlevels)); + m_opt_choice_str(mp_csp_names, params.color.space), + m_opt_choice_str(mp_csp_names, params.color.levels)); } // Conversion that VSFilter would use struct mp_csp_params vs_params = MP_CSP_PARAMS_DEFAULTS; - vs_params.colorspace = csp; - vs_params.levels_in = levels; + vs_params.color.space = csp; + vs_params.color.levels = levels; struct mp_cmat vs_yuv2rgb, vs_rgb2yuv; mp_get_csp_matrix(&vs_params, &vs_yuv2rgb); mp_invert_cmat(&vs_rgb2yuv, &vs_yuv2rgb); // Proper conversion to RGB struct mp_csp_params rgb_params = MP_CSP_PARAMS_DEFAULTS; - rgb_params.colorspace = params.colorspace; - rgb_params.levels_in = params.colorlevels; + rgb_params.color = params.color; struct mp_cmat vs2rgb; mp_get_csp_matrix(&rgb_params, &vs2rgb); diff --git a/video/csputils.c b/video/csputils.c index d419152e2c..4c9cfbeebd 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -581,7 +581,7 @@ void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest static void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, enum mp_render_intent intent, struct mp_cmat *m) { - struct mp_csp_primaries prim = mp_get_csp_primaries(params->primaries); + struct mp_csp_primaries prim = mp_get_csp_primaries(params->color.primaries); float brightness = params->brightness; mp_get_rgb2xyz_matrix(prim, m->m); mp_invert_matrix3x3(m->m); @@ -658,10 +658,10 @@ static void luma_coeffs(struct mp_cmat *mat, float lr, float lg, float lb) // get the coefficients of the yuv -> rgb conversion matrix void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m) { - int colorspace = params->colorspace; + enum mp_csp colorspace = params->color.space; if (colorspace <= MP_CSP_AUTO || colorspace >= MP_CSP_COUNT) colorspace = MP_CSP_BT_601; - int levels_in = params->levels_in; + enum mp_csp_levels levels_in = params->color.levels; if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT) levels_in = MP_CSP_LEVELS_TV; @@ -772,9 +772,16 @@ void mp_csp_set_image_params(struct mp_csp_params *params, { struct mp_image_params p = *imgparams; mp_image_params_guess_csp(&p); // ensure consistency - params->colorspace = p.colorspace; - params->levels_in = p.colorlevels; - params->primaries = p.primaries; + params->color = p.color; +} + +bool mp_colorspace_equal(struct mp_colorspace c1, struct mp_colorspace c2) +{ + return c1.space == c2.space && + c1.levels == c2.levels && + c1.primaries == c2.primaries && + c1.gamma == c2.gamma && + c1.peak == c2.peak; } // Copy settings from eq into params. diff --git a/video/csputils.h b/video/csputils.h index 274b548381..0743f2bee5 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -116,11 +116,17 @@ extern const struct m_opt_choice_alternatives mp_stereo3d_names[]; #define MP_STEREO3D_NAME_DEF(x, def) \ (MP_STEREO3D_NAME(x) ? MP_STEREO3D_NAME(x) : (def)) -struct mp_csp_params { - enum mp_csp colorspace; - enum mp_csp_levels levels_in; // encoded video - enum mp_csp_levels levels_out; // output device +struct mp_colorspace { + enum mp_csp space; + enum mp_csp_levels levels; enum mp_csp_prim primaries; + enum mp_csp_trc gamma; + float peak; // 0 = auto/unknown +}; + +struct mp_csp_params { + struct mp_colorspace color; // input colorspace + enum mp_csp_levels levels_out; // output device float brightness; float contrast; float hue; @@ -134,9 +140,8 @@ struct mp_csp_params { }; #define MP_CSP_PARAMS_DEFAULTS { \ - .colorspace = MP_CSP_BT_601, \ - .levels_in = MP_CSP_LEVELS_TV, \ - .primaries = MP_CSP_PRIM_AUTO, \ + .color = { .space = MP_CSP_BT_601, \ + .levels = MP_CSP_LEVELS_TV }, \ .levels_out = MP_CSP_LEVELS_PC, \ .brightness = 0, .contrast = 1, .hue = 0, .saturation = 1, \ .gamma = 1, .texture_bits = 8, .input_bits = 8} @@ -145,6 +150,8 @@ struct mp_image_params; void mp_csp_set_image_params(struct mp_csp_params *params, const struct mp_image_params *imgparams); +bool mp_colorspace_equal(struct mp_colorspace c1, struct mp_colorspace c2); + enum mp_chroma_location { MP_CHROMA_AUTO, MP_CHROMA_LEFT, // mpeg2/4, h264 diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index be6aceb662..62fc4ff280 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -578,10 +578,12 @@ static void update_image_params(struct dec_video *vd, AVFrame *frame, .h = frame->height, .p_w = frame->sample_aspect_ratio.num, .p_h = frame->sample_aspect_ratio.den, - .colorspace = avcol_spc_to_mp_csp(ctx->avctx->colorspace), - .colorlevels = avcol_range_to_mp_csp_levels(ctx->avctx->color_range), - .primaries = avcol_pri_to_mp_csp_prim(ctx->avctx->color_primaries), - .gamma = avcol_trc_to_mp_csp_trc(ctx->avctx->color_trc), + .color = { + .space = avcol_spc_to_mp_csp(ctx->avctx->colorspace), + .levels = avcol_range_to_mp_csp_levels(ctx->avctx->color_range), + .primaries = avcol_pri_to_mp_csp_prim(ctx->avctx->color_primaries), + .gamma = avcol_trc_to_mp_csp_trc(ctx->avctx->color_trc), + }, .chroma_location = avchroma_location_to_mp(ctx->avctx->chroma_sample_location), .rotate = vd->codec->rotate, diff --git a/video/filter/vf_d3d11vpp.c b/video/filter/vf_d3d11vpp.c index a0aa0edae2..658aec25b8 100644 --- a/video/filter/vf_d3d11vpp.c +++ b/video/filter/vf_d3d11vpp.c @@ -211,21 +211,21 @@ static int recreate_video_proc(struct vf_instance *vf) FALSE, 0); D3D11_VIDEO_PROCESSOR_COLOR_SPACE csp = { - .YCbCr_Matrix = p->params.colorspace != MP_CSP_BT_601, - .Nominal_Range = p->params.colorlevels == MP_CSP_LEVELS_TV ? 1 : 2, + .YCbCr_Matrix = p->params.color.space != MP_CSP_BT_601, + .Nominal_Range = p->params.color.levels == MP_CSP_LEVELS_TV ? 1 : 2, }; ID3D11VideoContext_VideoProcessorSetStreamColorSpace(p->video_ctx, p->video_proc, 0, &csp); if (p->out_rgb) { - if (p->params.colorspace != MP_CSP_BT_601 && - p->params.colorspace != MP_CSP_BT_709) + if (p->params.color.space != MP_CSP_BT_601 && + p->params.color.space != MP_CSP_BT_709) { MP_WARN(vf, "Unsupported video colorspace (%s/%s). Consider " "disabling hardware decoding, or using " "--hwdec=d3d11va-copy to get correct output.\n", - m_opt_choice_str(mp_csp_names, p->params.colorspace), - m_opt_choice_str(mp_csp_levels_names, p->params.colorlevels)); + m_opt_choice_str(mp_csp_names, p->params.color.space), + m_opt_choice_str(mp_csp_levels_names, p->params.color.levels)); } } else { ID3D11VideoContext_VideoProcessorSetOutputColorSpace(p->video_ctx, diff --git a/video/filter/vf_format.c b/video/filter/vf_format.c index 109fda4053..36388e6288 100644 --- a/video/filter/vf_format.c +++ b/video/filter/vf_format.c @@ -88,15 +88,15 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in, if (p->outfmt) out->imgfmt = p->outfmt; if (p->colormatrix) - out->colorspace = p->colormatrix; + out->color.space = p->colormatrix; if (p->colorlevels) - out->colorlevels = p->colorlevels; + out->color.levels = p->colorlevels; if (p->primaries) - out->primaries = p->primaries; + out->color.primaries = p->primaries; if (p->gamma) - out->gamma = p->gamma; + out->color.gamma = p->gamma; if (p->peak) - out->peak = p->peak; + out->color.peak = p->peak; if (p->chroma_location) out->chroma_location = p->chroma_location; if (p->stereo_in) diff --git a/video/filter/vf_scale.c b/video/filter/vf_scale.c index 518ff41beb..0b233e7098 100644 --- a/video/filter/vf_scale.c +++ b/video/filter/vf_scale.c @@ -166,8 +166,8 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in, struct mp_imgfmt_desc d_fmt = mp_imgfmt_get_desc(out->imgfmt); // keep colorspace settings if the data stays in yuv if (!(s_fmt.flags & MP_IMGFLAG_YUV) || !(d_fmt.flags & MP_IMGFLAG_YUV)) { - out->colorspace = MP_CSP_AUTO; - out->colorlevels = MP_CSP_LEVELS_AUTO; + out->color.space = MP_CSP_AUTO; + out->color.levels = MP_CSP_LEVELS_AUTO; } mp_image_params_guess_csp(out); diff --git a/video/filter/vf_vapoursynth.c b/video/filter/vf_vapoursynth.c index 5592e032e4..625d539dc4 100644 --- a/video/filter/vf_vapoursynth.c +++ b/video/filter/vf_vapoursynth.c @@ -143,13 +143,13 @@ static void copy_mp_to_vs_frame_props_map(struct vf_priv_s *p, VSMap *map, struct mp_image_params *params = &img->params; p->vsapi->propSetInt(map, "_SARNum", params->p_w, 0); p->vsapi->propSetInt(map, "_SARDen", params->p_h, 0); - if (params->colorlevels) { + if (params->color.levels) { p->vsapi->propSetInt(map, "_ColorRange", - params->colorlevels == MP_CSP_LEVELS_TV, 0); + params->color.levels == MP_CSP_LEVELS_TV, 0); } // The docs explicitly say it uses libavcodec values. p->vsapi->propSetInt(map, "_ColorSpace", - mp_csp_to_avcol_spc(params->colorspace), 0); + mp_csp_to_avcol_spc(params->color.space), 0); if (params->chroma_location) { p->vsapi->propSetInt(map, "_ChromaLocation", params->chroma_location == MP_CHROMA_CENTER, 0); diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c index 0365b55fb3..b24f886241 100644 --- a/video/filter/vf_vavpp.c +++ b/video/filter/vf_vavpp.c @@ -168,7 +168,7 @@ static struct mp_image *render(struct vf_instance *vf) mp_image_set_size(img, in->w, in->h); mp_image_copy_attributes(img, in); - unsigned int flags = va_get_colorspace_flag(p->params.colorspace); + unsigned int flags = va_get_colorspace_flag(p->params.color.space); if (!mp_refqueue_is_interlaced(p->queue)) { flags |= VA_FRAME_PICTURE; } else if (mp_refqueue_is_top_field(p->queue)) { diff --git a/video/image_writer.c b/video/image_writer.c index 5ba89c8167..6b2f0f9a92 100644 --- a/video/image_writer.c +++ b/video/image_writer.c @@ -133,8 +133,8 @@ static bool write_lavc(struct image_writer_ctx *ctx, mp_image_t *image, FILE *fp pic->width = avctx->width; pic->height = avctx->height; if (ctx->opts->tag_csp) { - pic->color_primaries = mp_csp_prim_to_avcol_pri(image->params.primaries); - pic->color_trc = mp_csp_trc_to_avcol_trc(image->params.gamma); + pic->color_primaries = mp_csp_prim_to_avcol_pri(image->params.color.primaries); + pic->color_trc = mp_csp_trc_to_avcol_trc(image->params.color.gamma); } #if HAVE_AVCODEC_NEW_CODEC_API diff --git a/video/mp_image.c b/video/mp_image.c index 0b46f947bc..286e40bf62 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -393,11 +393,12 @@ void mp_image_copy_attributes(struct mp_image *dst, struct mp_image *src) dst->params.p_w = src->params.p_w; dst->params.p_h = src->params.p_h; } - dst->params.primaries = src->params.primaries; - dst->params.gamma = src->params.gamma; + dst->params.color.primaries = src->params.color.primaries; + dst->params.color.gamma = src->params.color.gamma; + dst->params.color.peak = src->params.color.peak; if ((dst->fmt.flags & MP_IMGFLAG_YUV) == (src->fmt.flags & MP_IMGFLAG_YUV)) { - dst->params.colorspace = src->params.colorspace; - dst->params.colorlevels = src->params.colorlevels; + dst->params.color.space = src->params.color.space; + dst->params.color.levels = src->params.color.levels; dst->params.chroma_location = src->params.chroma_location; } mp_image_params_guess_csp(&dst->params); // ensure colorspace consistency @@ -512,8 +513,8 @@ char *mp_image_params_to_str_buf(char *b, size_t bs, if (p->hw_subfmt) mp_snprintf_cat(b, bs, "[%llu]", (unsigned long long)(p->hw_subfmt)); mp_snprintf_cat(b, bs, " %s/%s", - m_opt_choice_str(mp_csp_names, p->colorspace), - m_opt_choice_str(mp_csp_levels_names, p->colorlevels)); + m_opt_choice_str(mp_csp_names, p->color.space), + m_opt_choice_str(mp_csp_levels_names, p->color.levels)); mp_snprintf_cat(b, bs, " CL=%s", m_opt_choice_str(mp_chroma_names, p->chroma_location)); if (p->rotate) @@ -564,11 +565,7 @@ bool mp_image_params_equal(const struct mp_image_params *p1, p1->hw_subfmt == p2->hw_subfmt && p1->w == p2->w && p1->h == p2->h && p1->p_w == p2->p_w && p1->p_h == p2->p_h && - p1->colorspace == p2->colorspace && - p1->colorlevels == p2->colorlevels && - p1->primaries == p2->primaries && - p1->gamma == p2->gamma && - p1->peak == p2->peak && + mp_colorspace_equal(p1->color, p2->color) && p1->chroma_location == p2->chroma_location && p1->rotate == p2->rotate && p1->stereo_in == p2->stereo_in && @@ -598,56 +595,56 @@ void mp_image_params_guess_csp(struct mp_image_params *params) if (!fmt.id) return; if (fmt.flags & MP_IMGFLAG_YUV) { - if (params->colorspace != MP_CSP_BT_601 && - params->colorspace != MP_CSP_BT_709 && - params->colorspace != MP_CSP_BT_2020_NC && - params->colorspace != MP_CSP_BT_2020_C && - params->colorspace != MP_CSP_SMPTE_240M && - params->colorspace != MP_CSP_YCGCO) + if (params->color.space != MP_CSP_BT_601 && + params->color.space != MP_CSP_BT_709 && + params->color.space != MP_CSP_BT_2020_NC && + params->color.space != MP_CSP_BT_2020_C && + params->color.space != MP_CSP_SMPTE_240M && + params->color.space != MP_CSP_YCGCO) { // Makes no sense, so guess instead // YCGCO should be separate, but libavcodec disagrees - params->colorspace = MP_CSP_AUTO; + params->color.space = MP_CSP_AUTO; } - if (params->colorspace == MP_CSP_AUTO) - params->colorspace = mp_csp_guess_colorspace(params->w, params->h); - if (params->colorlevels == MP_CSP_LEVELS_AUTO) { - if (params->gamma == MP_CSP_TRC_V_LOG) { - params->colorlevels = MP_CSP_LEVELS_PC; + if (params->color.space == MP_CSP_AUTO) + params->color.space = mp_csp_guess_colorspace(params->w, params->h); + if (params->color.levels == MP_CSP_LEVELS_AUTO) { + if (params->color.gamma == MP_CSP_TRC_V_LOG) { + params->color.levels = MP_CSP_LEVELS_PC; } else { - params->colorlevels = MP_CSP_LEVELS_TV; + params->color.levels = MP_CSP_LEVELS_TV; } } - if (params->primaries == MP_CSP_PRIM_AUTO) { + if (params->color.primaries == MP_CSP_PRIM_AUTO) { // Guess based on the colormatrix as a first priority - if (params->colorspace == MP_CSP_BT_2020_NC || - params->colorspace == MP_CSP_BT_2020_C) { - params->primaries = MP_CSP_PRIM_BT_2020; - } else if (params->colorspace == MP_CSP_BT_709) { - params->primaries = MP_CSP_PRIM_BT_709; + if (params->color.space == MP_CSP_BT_2020_NC || + params->color.space == MP_CSP_BT_2020_C) { + params->color.primaries = MP_CSP_PRIM_BT_2020; + } else if (params->color.space == MP_CSP_BT_709) { + params->color.primaries = MP_CSP_PRIM_BT_709; } else { // Ambiguous colormatrix for BT.601, guess based on res - params->primaries = mp_csp_guess_primaries(params->w, params->h); + params->color.primaries = mp_csp_guess_primaries(params->w, params->h); } } - if (params->gamma == MP_CSP_TRC_AUTO) - params->gamma = MP_CSP_TRC_BT_1886; + if (params->color.gamma == MP_CSP_TRC_AUTO) + params->color.gamma = MP_CSP_TRC_BT_1886; } else if (fmt.flags & MP_IMGFLAG_RGB) { - params->colorspace = MP_CSP_RGB; - params->colorlevels = MP_CSP_LEVELS_PC; + params->color.space = MP_CSP_RGB; + params->color.levels = MP_CSP_LEVELS_PC; // The majority of RGB content is either sRGB or (rarely) some other // color space which we don't even handle, like AdobeRGB or // ProPhotoRGB. The only reasonable thing we can do is assume it's // sRGB and hope for the best, which should usually just work out fine. // 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; + if (params->color.primaries == MP_CSP_PRIM_AUTO) + params->color.primaries = MP_CSP_PRIM_BT_709; + if (params->color.gamma == MP_CSP_TRC_AUTO) + params->color.gamma = MP_CSP_TRC_SRGB; } else if (fmt.flags & MP_IMGFLAG_XYZ) { - params->colorspace = MP_CSP_XYZ; - params->colorlevels = MP_CSP_LEVELS_PC; + params->color.space = MP_CSP_XYZ; + params->color.levels = MP_CSP_LEVELS_PC; // The default XYZ matrix converts it to BT.709 color space // since that's the most likely scenario. Proper VOs should ignore @@ -657,22 +654,22 @@ void mp_image_params_guess_csp(struct mp_image_params *params) // gamut for VOs which *do* use the specialized XYZ matrix but don't // know any better output gamut other than whatever the source is // 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; + if (params->color.primaries == MP_CSP_PRIM_AUTO) + params->color.primaries = MP_CSP_PRIM_BT_709; + if (params->color.gamma == MP_CSP_TRC_AUTO) + params->color.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; + params->color.space = MP_CSP_AUTO; + params->color.levels = MP_CSP_LEVELS_AUTO; + params->color.primaries = MP_CSP_PRIM_AUTO; + params->color.gamma = MP_CSP_TRC_AUTO; } - // Guess the reference peak (independent of the colorspace) - if (params->gamma == MP_CSP_TRC_SMPTE_ST2084) { - if (!params->peak) - params->peak = 10000; // As per the spec + // Guess the nominal peak (independent of the colorspace) + if (params->color.gamma == MP_CSP_TRC_SMPTE_ST2084) { + if (!params->color.peak) + params->color.peak = 10000; // As per the spec } } @@ -729,8 +726,8 @@ static void mp_image_copy_fields_to_av_frame(struct AVFrame *dst, if (src->fields & MP_IMGFIELD_REPEAT_FIRST) dst->repeat_pict = 1; - dst->colorspace = mp_csp_to_avcol_spc(src->params.colorspace); - dst->color_range = mp_csp_levels_to_avcol_range(src->params.colorlevels); + dst->colorspace = mp_csp_to_avcol_spc(src->params.color.space); + dst->color_range = mp_csp_levels_to_avcol_range(src->params.color.levels); } // Create a new mp_image reference to av_frame. diff --git a/video/mp_image.h b/video/mp_image.h index 18d25968c0..dfbe4ee0ba 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -43,11 +43,7 @@ struct mp_image_params { // (will use the HW API's format identifiers) int w, h; // image dimensions int p_w, p_h; // define pixel aspect ratio (undefined: 0/0) - enum mp_csp colorspace; - enum mp_csp_levels colorlevels; - enum mp_csp_prim primaries; - enum mp_csp_trc gamma; - float peak; // 0 = auto/unknown + struct mp_colorspace color; enum mp_chroma_location chroma_location; // The image should be rotated clockwise (0-359 degrees). int rotate; diff --git a/video/out/opengl/hwdec_vaglx.c b/video/out/opengl/hwdec_vaglx.c index 2e3017c193..0400604067 100644 --- a/video/out/opengl/hwdec_vaglx.c +++ b/video/out/opengl/hwdec_vaglx.c @@ -185,7 +185,7 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, 0, 0, hw_image->w, hw_image->h, 0, 0, hw_image->w, hw_image->h, NULL, 0, - va_get_colorspace_flag(hw_image->params.colorspace)); + va_get_colorspace_flag(hw_image->params.color.space)); CHECK_VA_STATUS(p, "vaPutSurface()"); va_unlock(p->ctx); diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 6c7646bef4..59dd64cb65 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -729,7 +729,7 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg, // The existing code assumes we just have a single tex multiplier for // all of the planes. This may change in the future - float tex_mul = 1.0 / mp_get_csp_mul(p->image_params.colorspace, + float tex_mul = 1.0 / mp_get_csp_mul(p->image_params.color.space, p->image_desc.component_bits, p->image_desc.component_full_bits); @@ -793,7 +793,7 @@ static void init_video(struct gl_video *p) mp_image_params_guess_csp(&p->image_params); int eq_caps = MP_CSP_EQ_CAPS_GAMMA; - if (p->image_params.colorspace != MP_CSP_BT_2020_C) + if (p->image_params.color.space != MP_CSP_BT_2020_C) eq_caps |= MP_CSP_EQ_CAPS_COLORMATRIX; if (p->image_desc.flags & MP_IMGFLAG_XYZ) eq_caps |= MP_CSP_EQ_CAPS_BRIGHTNESS; @@ -1985,7 +1985,7 @@ static void pass_convert_yuv(struct gl_video *p) GLSLF("color = color.%s;\n", p->color_swizzle); // Pre-colormatrix input gamma correction - if (cparams.colorspace == MP_CSP_XYZ) + if (cparams.color.space == MP_CSP_XYZ) GLSL(color.rgb = pow(color.rgb, vec3(2.6));) // linear light // We always explicitly normalize the range in pass_read_video @@ -2000,7 +2000,7 @@ static void pass_convert_yuv(struct gl_video *p) GLSL(color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;) - if (p->image_params.colorspace == MP_CSP_BT_2020_C) { + if (p->image_params.color.space == MP_CSP_BT_2020_C) { // Conversion for C'rcY'cC'bc via the BT.2020 CL system: // C'bc = (B'-Y'c) / 1.9404 | C'bc <= 0 // = (B'-Y'c) / 1.5816 | C'bc > 0 @@ -2111,7 +2111,7 @@ static void pass_scale_main(struct gl_video *p) // Pre-conversion, like linear light/sigmoidization GLSLF("// scaler pre-conversion\n"); if (p->use_linear) { - pass_linearize(p->sc, p->image_params.gamma); + pass_linearize(p->sc, p->image_params.color.gamma); pass_opt_hook_point(p, "LINEAR", NULL); } @@ -2171,8 +2171,8 @@ static void pass_colormanage(struct gl_video *p, float peak_src, if (p->use_lut_3d) { // The 3DLUT is always generated against the original source space - enum mp_csp_prim prim_orig = p->image_params.primaries; - enum mp_csp_trc trc_orig = p->image_params.gamma; + enum mp_csp_prim prim_orig = p->image_params.color.primaries; + enum mp_csp_trc trc_orig = p->image_params.color.gamma; // One exception: HDR is not implemented by LittleCMS for technical // limitation reasons, so we use a gamma 2.2 input curve here instead. @@ -2196,14 +2196,14 @@ static void pass_colormanage(struct gl_video *p, float peak_src, // this as the default output color space. prim_dst = MP_CSP_PRIM_BT_709; - if (p->image_params.primaries == MP_CSP_PRIM_BT_601_525 || - p->image_params.primaries == MP_CSP_PRIM_BT_601_625) + if (p->image_params.color.primaries == MP_CSP_PRIM_BT_601_525 || + p->image_params.color.primaries == MP_CSP_PRIM_BT_601_625) { // Since we auto-pick BT.601 and BT.709 based on the dimensions, // combined with the fact that they're very similar to begin with, // and to avoid confusing the average user, just don't adapt BT.601 // content automatically at all. - prim_dst = p->image_params.primaries; + prim_dst = p->image_params.color.primaries; } } @@ -2213,7 +2213,7 @@ static void pass_colormanage(struct gl_video *p, float peak_src, // altogether by default. The only exceptions to this rule apply to // very unusual TRCs, which even hardcode technoluddites would probably // not enjoy viewing unaltered. - trc_dst = p->image_params.gamma; + trc_dst = p->image_params.color.gamma; // Avoid outputting linear light or HDR content "by default". For these // just pick gamma 2.2 as a default, since it's a good estimate for @@ -2225,7 +2225,7 @@ static void pass_colormanage(struct gl_video *p, float peak_src, if (!peak_src) { // If the source has no information known, it's display-referred // (and should be treated relative to the specified desired peak_dst) - peak_src = peak_dst * mp_csp_trc_rel_peak(p->image_params.gamma); + peak_src = peak_dst * mp_csp_trc_rel_peak(p->image_params.color.gamma); } // All operations from here on require linear light as a starting point, @@ -2513,7 +2513,7 @@ static void pass_render_frame(struct gl_video *p) rect.mt *= scale[1]; rect.mb *= scale[1]; // We should always blend subtitles in non-linear light if (p->use_linear) { - pass_delinearize(p->sc, p->image_params.gamma); + pass_delinearize(p->sc, p->image_params.color.gamma); p->use_linear = false; } finish_pass_fbo(p, &p->blend_subs_fbo, p->texture_w, p->texture_h, @@ -2542,8 +2542,8 @@ static void pass_draw_to_screen(struct gl_video *p, int fbo) GLSL(color.rgb = pow(color.rgb, vec3(user_gamma));) } - pass_colormanage(p, p->image_params.peak, p->image_params.primaries, - p->use_linear ? MP_CSP_TRC_LINEAR : p->image_params.gamma); + pass_colormanage(p, p->image_params.color.peak, p->image_params.color.primaries, + p->use_linear ? MP_CSP_TRC_LINEAR : p->image_params.color.gamma); // Draw checkerboard pattern to indicate transparency if (p->has_alpha && p->opts.alpha_mode == ALPHA_BLEND_TILES) { diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c index 7003bd17bd..1721136f8b 100644 --- a/video/out/vo_lavc.c +++ b/video/out/vo_lavc.c @@ -155,8 +155,8 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) vc->codec->height = height; vc->codec->pix_fmt = pix_fmt; - encode_lavc_set_csp(vo->encode_lavc_ctx, vc->codec, params->colorspace); - encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->codec, params->colorlevels); + encode_lavc_set_csp(vo->encode_lavc_ctx, vc->codec, params->color.space); + encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->codec, params->color.levels); if (encode_lavc_open_codec(vo->encode_lavc_ctx, vc->codec) < 0) goto error; diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index 08b9b11fe0..095308f9b5 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -305,8 +305,10 @@ static int control(struct vo *vo, uint32_t request, void *data) struct mp_image *screen = gl_read_window_contents(p->gl); // set image parameters according to the display, if possible if (screen) { - screen->params.primaries = p->renderer_opts->target_prim; - screen->params.gamma = p->renderer_opts->target_trc; + screen->params.color = (struct mp_colorspace) { + .primaries = p->renderer_opts->target_prim, + .gamma = p->renderer_opts->target_trc, + }; if (p->glctx->flip_v) mp_image_vflip(screen); } diff --git a/video/out/vo_rpi.c b/video/out/vo_rpi.c index cd37362a30..947e63037e 100644 --- a/video/out/vo_rpi.c +++ b/video/out/vo_rpi.c @@ -529,7 +529,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) input->format->es->video.height = MP_ALIGN_UP(params->h, ALIGN_H); input->format->es->video.crop = (MMAL_RECT_T){0, 0, params->w, params->h}; input->format->es->video.par = (MMAL_RATIONAL_T){params->p_w, params->p_h}; - input->format->es->video.color_space = map_csp(params->colorspace); + input->format->es->video.color_space = map_csp(params->color.space); if (mmal_port_format_commit(input)) return -1; diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 8380771e27..11bb469b24 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -225,7 +225,7 @@ static bool render_to_screen(struct priv *p, struct mp_image *mpi) } } - int flags = va_get_colorspace_flag(p->image_params.colorspace) | + int flags = va_get_colorspace_flag(p->image_params.color.space) | p->scaling | VA_FRAME_PICTURE; status = vaPutSurface(p->display, surface, diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c index a5a4728085..f450eb2df9 100644 --- a/video/out/vo_xv.c +++ b/video/out/vo_xv.c @@ -518,7 +518,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params) ctx->current_buf = 0; ctx->current_ip_buf = 0; - int is_709 = params->colorspace == MP_CSP_BT_709; + int is_709 = params->color.space == MP_CSP_BT_709; xv_set_eq(vo, ctx->xv_port, "bt_709", is_709 * 200 - 100); read_xv_csp(vo); @@ -661,7 +661,7 @@ static struct mp_image get_xv_buffer(struct vo *vo, int buf_index) if (vo->params) { struct mp_image_params params = *vo->params; if (ctx->cached_csp) - params.colorspace = ctx->cached_csp; + params.color.space = ctx->cached_csp; mp_image_set_attributes(&img, ¶ms); } diff --git a/video/sws_utils.c b/video/sws_utils.c index ce44c67eeb..45918b19d1 100644 --- a/video/sws_utils.c +++ b/video/sws_utils.c @@ -192,11 +192,11 @@ int mp_sws_reinit(struct mp_sws_context *ctx) return -1; } - int s_csp = mp_csp_to_sws_colorspace(src->colorspace); - int s_range = src->colorlevels == MP_CSP_LEVELS_PC; + int s_csp = mp_csp_to_sws_colorspace(src->color.space); + int s_range = src->color.levels == MP_CSP_LEVELS_PC; - int d_csp = mp_csp_to_sws_colorspace(dst->colorspace); - int d_range = dst->colorlevels == MP_CSP_LEVELS_PC; + int d_csp = mp_csp_to_sws_colorspace(dst->color.space); + int d_range = dst->color.levels == MP_CSP_LEVELS_PC; // Work around libswscale bug #1852 (fixed in ffmpeg commit 8edf9b1fa): // setting range flags for RGB gives random bogus results.