mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-01-01 03:18:32 +00:00
182 lines
5.7 KiB
C++
182 lines
5.7 KiB
C++
#include "video_colorspace.h"
|
|
|
|
#include "logging.h"
|
|
#include "video.h"
|
|
|
|
extern "C" {
|
|
#include <libswscale/swscale.h>
|
|
}
|
|
|
|
namespace video {
|
|
|
|
bool
|
|
colorspace_is_hdr(const sunshine_colorspace_t &colorspace) {
|
|
return colorspace.colorspace == colorspace_e::bt2020;
|
|
}
|
|
|
|
sunshine_colorspace_t
|
|
colorspace_from_client_config(const config_t &config, bool hdr_display) {
|
|
sunshine_colorspace_t colorspace;
|
|
|
|
/* See video::config_t declaration for details */
|
|
|
|
if (config.dynamicRange > 0 && hdr_display) {
|
|
// Rec. 2020 with ST 2084 perceptual quantizer
|
|
colorspace.colorspace = colorspace_e::bt2020;
|
|
}
|
|
else {
|
|
switch (config.encoderCscMode >> 1) {
|
|
case 0:
|
|
// Rec. 601
|
|
colorspace.colorspace = colorspace_e::rec601;
|
|
break;
|
|
|
|
case 1:
|
|
// Rec. 709
|
|
colorspace.colorspace = colorspace_e::rec709;
|
|
break;
|
|
|
|
case 2:
|
|
// Rec. 2020
|
|
colorspace.colorspace = colorspace_e::bt2020sdr;
|
|
break;
|
|
|
|
default:
|
|
BOOST_LOG(error) << "Unknown video colorspace in csc, falling back to Rec. 709";
|
|
colorspace.colorspace = colorspace_e::rec709;
|
|
break;
|
|
}
|
|
}
|
|
|
|
colorspace.full_range = (config.encoderCscMode & 0x1);
|
|
|
|
switch (config.dynamicRange) {
|
|
case 0:
|
|
colorspace.bit_depth = 8;
|
|
break;
|
|
|
|
case 1:
|
|
colorspace.bit_depth = 10;
|
|
break;
|
|
|
|
default:
|
|
BOOST_LOG(error) << "Unknown dynamicRange value, falling back to 10-bit color depth";
|
|
colorspace.bit_depth = 10;
|
|
break;
|
|
}
|
|
|
|
if (colorspace.colorspace == colorspace_e::bt2020sdr && colorspace.bit_depth != 10) {
|
|
BOOST_LOG(error) << "BT.2020 SDR colorspace expects 10-bit color depth, falling back to Rec. 709";
|
|
colorspace.colorspace = colorspace_e::rec709;
|
|
}
|
|
|
|
return colorspace;
|
|
}
|
|
|
|
avcodec_colorspace_t
|
|
avcodec_colorspace_from_sunshine_colorspace(const sunshine_colorspace_t &sunshine_colorspace) {
|
|
avcodec_colorspace_t avcodec_colorspace;
|
|
|
|
switch (sunshine_colorspace.colorspace) {
|
|
case colorspace_e::rec601:
|
|
// Rec. 601
|
|
avcodec_colorspace.primaries = AVCOL_PRI_SMPTE170M;
|
|
avcodec_colorspace.transfer_function = AVCOL_TRC_SMPTE170M;
|
|
avcodec_colorspace.matrix = AVCOL_SPC_SMPTE170M;
|
|
avcodec_colorspace.software_format = SWS_CS_SMPTE170M;
|
|
break;
|
|
|
|
case colorspace_e::rec709:
|
|
// Rec. 709
|
|
avcodec_colorspace.primaries = AVCOL_PRI_BT709;
|
|
avcodec_colorspace.transfer_function = AVCOL_TRC_BT709;
|
|
avcodec_colorspace.matrix = AVCOL_SPC_BT709;
|
|
avcodec_colorspace.software_format = SWS_CS_ITU709;
|
|
break;
|
|
|
|
case colorspace_e::bt2020sdr:
|
|
// Rec. 2020
|
|
avcodec_colorspace.primaries = AVCOL_PRI_BT2020;
|
|
assert(sunshine_colorspace.bit_depth == 10);
|
|
avcodec_colorspace.transfer_function = AVCOL_TRC_BT2020_10;
|
|
avcodec_colorspace.matrix = AVCOL_SPC_BT2020_NCL;
|
|
avcodec_colorspace.software_format = SWS_CS_BT2020;
|
|
break;
|
|
|
|
case colorspace_e::bt2020:
|
|
// Rec. 2020 with ST 2084 perceptual quantizer
|
|
avcodec_colorspace.primaries = AVCOL_PRI_BT2020;
|
|
assert(sunshine_colorspace.bit_depth == 10);
|
|
avcodec_colorspace.transfer_function = AVCOL_TRC_SMPTE2084;
|
|
avcodec_colorspace.matrix = AVCOL_SPC_BT2020_NCL;
|
|
avcodec_colorspace.software_format = SWS_CS_BT2020;
|
|
break;
|
|
}
|
|
|
|
avcodec_colorspace.range = sunshine_colorspace.full_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
|
|
|
|
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;
|
|
}
|
|
|
|
} // namespace video
|