diff --git a/src/platform/linux/cuda.cu b/src/platform/linux/cuda.cu index 6d288ef8..e48dc3a0 100644 --- a/src/platform/linux/cuda.cu +++ b/src/platform/linux/cuda.cu @@ -330,7 +330,7 @@ namespace cuda { } void sws_t::apply_colorspace(const video::sunshine_colorspace_t &colorspace) { - auto color_p = video::color_vectors_from_colorspace(colorspace); + auto color_p = video::color_vectors_from_colorspace(colorspace, true); CU_CHECK_IGNORE(cudaMemcpy(color_matrix.get(), color_p, sizeof(video::color_t), cudaMemcpyHostToDevice), "Couldn't copy color matrix to cuda"); } diff --git a/src/platform/linux/graphics.cpp b/src/platform/linux/graphics.cpp index 245addb6..96cf95d1 100644 --- a/src/platform/linux/graphics.cpp +++ b/src/platform/linux/graphics.cpp @@ -698,7 +698,7 @@ namespace egl { } void sws_t::apply_colorspace(const video::sunshine_colorspace_t &colorspace) { - auto color_p = video::color_vectors_from_colorspace(colorspace); + auto color_p = video::color_vectors_from_colorspace(colorspace, true); std::string_view members[] { util::view(color_p->color_vec_y), @@ -811,7 +811,7 @@ namespace egl { gl::ctx.UseProgram(sws.program[1].handle()); gl::ctx.Uniform1fv(loc_width_i, 1, &width_i); - auto color_p = video::color_vectors_from_colorspace(video::colorspace_e::rec601, false); + auto color_p = video::color_vectors_from_colorspace({video::colorspace_e::rec601, false, 8}, true); std::pair members[] { std::make_pair("color_vec_y", util::view(color_p->color_vec_y)), std::make_pair("color_vec_u", util::view(color_p->color_vec_u)), diff --git a/src/platform/windows/display_vram.cpp b/src/platform/windows/display_vram.cpp index b537e6e6..cf6b4c43 100644 --- a/src/platform/windows/display_vram.cpp +++ b/src/platform/windows/display_vram.cpp @@ -457,12 +457,12 @@ namespace platf::dxgi { } void apply_colorspace(const ::video::sunshine_colorspace_t &colorspace) { - auto color_vectors = ::video::color_vectors_from_colorspace(colorspace); + auto color_vectors = ::video::color_vectors_from_colorspace(colorspace, true); if (format == DXGI_FORMAT_AYUV || format == DXGI_FORMAT_R16_UINT || format == DXGI_FORMAT_Y410) { - color_vectors = ::video::new_color_vectors_from_colorspace(colorspace); + color_vectors = ::video::color_vectors_from_colorspace(colorspace, false); } if (!color_vectors) { @@ -775,7 +775,7 @@ namespace platf::dxgi { BOOST_LOG(warning) << "Failed to increase encoding GPU thread priority. Please run application as administrator for optimal performance."; } - auto default_color_vectors = ::video::color_vectors_from_colorspace(::video::colorspace_e::rec601, false); + auto default_color_vectors = ::video::color_vectors_from_colorspace({::video::colorspace_e::rec601, false, 8}, true); if (!default_color_vectors) { BOOST_LOG(error) << "Missing color vectors for Rec. 601"sv; return -1; diff --git a/src/video_colorspace.cpp b/src/video_colorspace.cpp index 24522235..674c053a 100644 --- a/src/video_colorspace.cpp +++ b/src/video_colorspace.cpp @@ -120,66 +120,9 @@ namespace video { return avcodec_colorspace; } - const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace) { - return color_vectors_from_colorspace(colorspace.colorspace, colorspace.full_range); - } - - const color_t *color_vectors_from_colorspace(colorspace_e colorspace, bool full_range) { - using float2 = float[2]; - auto make_color_matrix = [](float Cr, float Cb, const float2 &range_Y, const float2 &range_UV) -> color_t { - float Cg = 1.0f - Cr - Cb; - - float Cr_i = 1.0f - Cr; - float Cb_i = 1.0f - Cb; - - float shift_y = range_Y[0] / 255.0f; - float shift_uv = range_UV[0] / 255.0f; - - float scale_y = (range_Y[1] - range_Y[0]) / 255.0f; - float scale_uv = (range_UV[1] - range_UV[0]) / 255.0f; - return { - {Cr, Cg, Cb, 0.0f}, - {-(Cr * 0.5f / Cb_i), -(Cg * 0.5f / Cb_i), 0.5f, 0.5f}, - {0.5f, -(Cg * 0.5f / Cr_i), -(Cb * 0.5f / Cr_i), 0.5f}, - {scale_y, shift_y}, - {scale_uv, shift_uv}, - }; - }; - - static const color_t colors[] { - make_color_matrix(0.299f, 0.114f, {16.0f, 235.0f}, {16.0f, 240.0f}), // BT601 MPEG - make_color_matrix(0.299f, 0.114f, {0.0f, 255.0f}, {0.0f, 255.0f}), // BT601 JPEG - make_color_matrix(0.2126f, 0.0722f, {16.0f, 235.0f}, {16.0f, 240.0f}), // BT709 MPEG - make_color_matrix(0.2126f, 0.0722f, {0.0f, 255.0f}, {0.0f, 255.0f}), // BT709 JPEG - make_color_matrix(0.2627f, 0.0593f, {16.0f, 235.0f}, {16.0f, 240.0f}), // BT2020 MPEG - make_color_matrix(0.2627f, 0.0593f, {0.0f, 255.0f}, {0.0f, 255.0f}), // BT2020 JPEG - }; - - const color_t *result = nullptr; - - switch (colorspace) { - case colorspace_e::rec601: - default: - result = &colors[0]; - break; - case colorspace_e::rec709: - result = &colors[2]; - break; - case colorspace_e::bt2020: - case colorspace_e::bt2020sdr: - result = &colors[4]; - break; - }; - - if (full_range) { - result++; - } - - return result; - } - - const color_t *new_color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace) { - constexpr auto generate_color_vectors = [](const sunshine_colorspace_t &colorspace) -> color_t { + const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace, bool unorm_output) { + constexpr auto generate_color_vectors = [](const sunshine_colorspace_t &colorspace, bool unorm_output) -> color_t { + // "Table 4 – Interpretation of matrix coefficients (MatrixCoefficients) value" section of ITU-T H.273 double Kr, Kb; switch (colorspace.colorspace) { case colorspace_e::rec601: @@ -202,7 +145,7 @@ namespace video { double y_mult, y_add; double uv_mult, uv_add; - // "Matrix coefficients" section of ITU-T H.273 + // "8.3 Matrix coefficients" section of ITU-T H.273 if (colorspace.full_range) { y_mult = (1 << colorspace.bit_depth) - 1; y_add = 0; @@ -215,9 +158,17 @@ namespace video { uv_add = (1 << (colorspace.bit_depth - 8)) * 128; } - // For rounding - y_add += 0.5; - uv_add += 0.5; + if (unorm_output) { + const double unorm_range = (1 << colorspace.bit_depth) - 1; + y_mult /= unorm_range; + y_add /= unorm_range; + uv_mult /= unorm_range; + uv_add /= unorm_range; + } else { + // For rounding + y_add += 0.5f; + uv_add += 0.5f; + } color_t color_vectors; @@ -246,18 +197,31 @@ namespace video { }; static constexpr color_t colors[] = { - generate_color_vectors({colorspace_e::rec601, false, 8}), - generate_color_vectors({colorspace_e::rec601, true, 8}), - generate_color_vectors({colorspace_e::rec601, false, 10}), - generate_color_vectors({colorspace_e::rec601, true, 10}), - generate_color_vectors({colorspace_e::rec709, false, 8}), - generate_color_vectors({colorspace_e::rec709, true, 8}), - generate_color_vectors({colorspace_e::rec709, false, 10}), - generate_color_vectors({colorspace_e::rec709, true, 10}), - generate_color_vectors({colorspace_e::bt2020, false, 8}), - generate_color_vectors({colorspace_e::bt2020, true, 8}), - generate_color_vectors({colorspace_e::bt2020, false, 10}), - generate_color_vectors({colorspace_e::bt2020, true, 10}), + generate_color_vectors({colorspace_e::rec601, false, 8}, false), + generate_color_vectors({colorspace_e::rec601, true, 8}, false), + generate_color_vectors({colorspace_e::rec601, false, 10}, false), + generate_color_vectors({colorspace_e::rec601, true, 10}, false), + generate_color_vectors({colorspace_e::rec709, false, 8}, false), + generate_color_vectors({colorspace_e::rec709, true, 8}, false), + generate_color_vectors({colorspace_e::rec709, false, 10}, false), + generate_color_vectors({colorspace_e::rec709, true, 10}, false), + generate_color_vectors({colorspace_e::bt2020, false, 8}, false), + generate_color_vectors({colorspace_e::bt2020, true, 8}, false), + generate_color_vectors({colorspace_e::bt2020, false, 10}, false), + generate_color_vectors({colorspace_e::bt2020, true, 10}, false), + + generate_color_vectors({colorspace_e::rec601, false, 8}, true), + generate_color_vectors({colorspace_e::rec601, true, 8}, true), + generate_color_vectors({colorspace_e::rec601, false, 10}, true), + generate_color_vectors({colorspace_e::rec601, true, 10}, true), + generate_color_vectors({colorspace_e::rec709, false, 8}, true), + generate_color_vectors({colorspace_e::rec709, true, 8}, true), + generate_color_vectors({colorspace_e::rec709, false, 10}, true), + generate_color_vectors({colorspace_e::rec709, true, 10}, true), + generate_color_vectors({colorspace_e::bt2020, false, 8}, true), + generate_color_vectors({colorspace_e::bt2020, true, 8}, true), + generate_color_vectors({colorspace_e::bt2020, false, 10}, true), + generate_color_vectors({colorspace_e::bt2020, true, 10}, true), }; const color_t *result = nullptr; @@ -282,6 +246,9 @@ namespace video { if (colorspace.full_range) { result += 1; } + if (unorm_output) { + result += 12; + } return result; } diff --git a/src/video_colorspace.h b/src/video_colorspace.h index eaa6c019..db0e1107 100644 --- a/src/video_colorspace.h +++ b/src/video_colorspace.h @@ -48,20 +48,15 @@ namespace video { float range_uv[2]; }; - const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace); - - const color_t *color_vectors_from_colorspace(colorspace_e colorspace, bool full_range); - /** - * @brief New version of `color_vectors_from_colorspace()` function that better adheres to the standards. - * Returned vectors are used to perform RGB->YUV conversion. - * Unlike its predecessor, color vectors will produce output in `UINT` range, not `UNORM` range. - * Input is still in `UNORM` range. Returned vectors won't modify color primaries and color - * transfer function. + * @brief Get static RGB->YUV color conversion matrix. + * This matrix expects RGB input in UNORM (0.0 to 1.0) range and doesn't perform any + * gamut mapping or gamma correction. * @param colorspace Targeted YUV colorspace. + * @param unorm_output Whether the matrix should produce output in UNORM or UINT range. * @return `const color_t*` that contains RGB->YUV transformation vectors. * Components `range_y` and `range_uv` are there for backwards compatibility * and can be ignored in the computation. */ - const color_t *new_color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace); + const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace, bool unorm_output); } // namespace video