feat(video): use unified color conversion matrix generator (#4387)
This commit is contained in:
parent
eb72930a8e
commit
cdb7e2b813
5 changed files with 54 additions and 92 deletions
|
|
@ -330,7 +330,7 @@ namespace cuda {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sws_t::apply_colorspace(const video::sunshine_colorspace_t &colorspace) {
|
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");
|
CU_CHECK_IGNORE(cudaMemcpy(color_matrix.get(), color_p, sizeof(video::color_t), cudaMemcpyHostToDevice), "Couldn't copy color matrix to cuda");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -698,7 +698,7 @@ namespace egl {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sws_t::apply_colorspace(const video::sunshine_colorspace_t &colorspace) {
|
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[] {
|
std::string_view members[] {
|
||||||
util::view(color_p->color_vec_y),
|
util::view(color_p->color_vec_y),
|
||||||
|
|
@ -811,7 +811,7 @@ namespace egl {
|
||||||
gl::ctx.UseProgram(sws.program[1].handle());
|
gl::ctx.UseProgram(sws.program[1].handle());
|
||||||
gl::ctx.Uniform1fv(loc_width_i, 1, &width_i);
|
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<const char *, std::string_view> members[] {
|
std::pair<const char *, std::string_view> members[] {
|
||||||
std::make_pair("color_vec_y", util::view(color_p->color_vec_y)),
|
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)),
|
std::make_pair("color_vec_u", util::view(color_p->color_vec_u)),
|
||||||
|
|
|
||||||
|
|
@ -457,12 +457,12 @@ namespace platf::dxgi {
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_colorspace(const ::video::sunshine_colorspace_t &colorspace) {
|
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 ||
|
if (format == DXGI_FORMAT_AYUV ||
|
||||||
format == DXGI_FORMAT_R16_UINT ||
|
format == DXGI_FORMAT_R16_UINT ||
|
||||||
format == DXGI_FORMAT_Y410) {
|
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) {
|
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.";
|
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) {
|
if (!default_color_vectors) {
|
||||||
BOOST_LOG(error) << "Missing color vectors for Rec. 601"sv;
|
BOOST_LOG(error) << "Missing color vectors for Rec. 601"sv;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
||||||
|
|
@ -120,66 +120,9 @@ namespace video {
|
||||||
return avcodec_colorspace;
|
return avcodec_colorspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace) {
|
const color_t *color_vectors_from_colorspace(const sunshine_colorspace_t &colorspace, bool unorm_output) {
|
||||||
return color_vectors_from_colorspace(colorspace.colorspace, colorspace.full_range);
|
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
|
||||||
|
|
||||||
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 {
|
|
||||||
double Kr, Kb;
|
double Kr, Kb;
|
||||||
switch (colorspace.colorspace) {
|
switch (colorspace.colorspace) {
|
||||||
case colorspace_e::rec601:
|
case colorspace_e::rec601:
|
||||||
|
|
@ -202,7 +145,7 @@ namespace video {
|
||||||
double y_mult, y_add;
|
double y_mult, y_add;
|
||||||
double uv_mult, uv_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) {
|
if (colorspace.full_range) {
|
||||||
y_mult = (1 << colorspace.bit_depth) - 1;
|
y_mult = (1 << colorspace.bit_depth) - 1;
|
||||||
y_add = 0;
|
y_add = 0;
|
||||||
|
|
@ -215,9 +158,17 @@ namespace video {
|
||||||
uv_add = (1 << (colorspace.bit_depth - 8)) * 128;
|
uv_add = (1 << (colorspace.bit_depth - 8)) * 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For rounding
|
if (unorm_output) {
|
||||||
y_add += 0.5;
|
const double unorm_range = (1 << colorspace.bit_depth) - 1;
|
||||||
uv_add += 0.5;
|
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;
|
color_t color_vectors;
|
||||||
|
|
||||||
|
|
@ -246,18 +197,31 @@ namespace video {
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr color_t colors[] = {
|
static constexpr color_t colors[] = {
|
||||||
generate_color_vectors({colorspace_e::rec601, false, 8}),
|
generate_color_vectors({colorspace_e::rec601, false, 8}, false),
|
||||||
generate_color_vectors({colorspace_e::rec601, true, 8}),
|
generate_color_vectors({colorspace_e::rec601, true, 8}, false),
|
||||||
generate_color_vectors({colorspace_e::rec601, false, 10}),
|
generate_color_vectors({colorspace_e::rec601, false, 10}, false),
|
||||||
generate_color_vectors({colorspace_e::rec601, true, 10}),
|
generate_color_vectors({colorspace_e::rec601, true, 10}, false),
|
||||||
generate_color_vectors({colorspace_e::rec709, false, 8}),
|
generate_color_vectors({colorspace_e::rec709, false, 8}, false),
|
||||||
generate_color_vectors({colorspace_e::rec709, true, 8}),
|
generate_color_vectors({colorspace_e::rec709, true, 8}, false),
|
||||||
generate_color_vectors({colorspace_e::rec709, false, 10}),
|
generate_color_vectors({colorspace_e::rec709, false, 10}, false),
|
||||||
generate_color_vectors({colorspace_e::rec709, true, 10}),
|
generate_color_vectors({colorspace_e::rec709, true, 10}, false),
|
||||||
generate_color_vectors({colorspace_e::bt2020, false, 8}),
|
generate_color_vectors({colorspace_e::bt2020, false, 8}, false),
|
||||||
generate_color_vectors({colorspace_e::bt2020, true, 8}),
|
generate_color_vectors({colorspace_e::bt2020, true, 8}, false),
|
||||||
generate_color_vectors({colorspace_e::bt2020, false, 10}),
|
generate_color_vectors({colorspace_e::bt2020, false, 10}, false),
|
||||||
generate_color_vectors({colorspace_e::bt2020, true, 10}),
|
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;
|
const color_t *result = nullptr;
|
||||||
|
|
@ -282,6 +246,9 @@ namespace video {
|
||||||
if (colorspace.full_range) {
|
if (colorspace.full_range) {
|
||||||
result += 1;
|
result += 1;
|
||||||
}
|
}
|
||||||
|
if (unorm_output) {
|
||||||
|
result += 12;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,20 +48,15 @@ namespace video {
|
||||||
float range_uv[2];
|
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.
|
* @brief Get static RGB->YUV color conversion matrix.
|
||||||
* Returned vectors are used to perform RGB->YUV conversion.
|
* This matrix expects RGB input in UNORM (0.0 to 1.0) range and doesn't perform any
|
||||||
* Unlike its predecessor, color vectors will produce output in `UINT` range, not `UNORM` range.
|
* gamut mapping or gamma correction.
|
||||||
* Input is still in `UNORM` range. Returned vectors won't modify color primaries and color
|
|
||||||
* transfer function.
|
|
||||||
* @param colorspace Targeted YUV colorspace.
|
* @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.
|
* @return `const color_t*` that contains RGB->YUV transformation vectors.
|
||||||
* Components `range_y` and `range_uv` are there for backwards compatibility
|
* Components `range_y` and `range_uv` are there for backwards compatibility
|
||||||
* and can be ignored in the computation.
|
* 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
|
} // namespace video
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue