diff --git a/docs/sphinx/reference-libobs-media-io.rst b/docs/sphinx/reference-libobs-media-io.rst index d06038aa0..6734d6123 100644 --- a/docs/sphinx/reference-libobs-media-io.rst +++ b/docs/sphinx/reference-libobs-media-io.rst @@ -39,10 +39,12 @@ Video Handler YUV color space. Can be one of the following values: - - VIDEO_CS_DEFAULT - Equivalent to VIDEO_CS_709 - - VIDEO_CS_601 - 601 color space - - VIDEO_CS_709 - 709 color space - - VIDEO_CS_SRGB - sRGB color space + - VIDEO_CS_DEFAULT - Equivalent to VIDEO_CS_709 + - VIDEO_CS_601 - Rec. 601 color space + - VIDEO_CS_709 - Rec. 709 color space + - VIDEO_CS_SRGB - sRGB color space + - VIDEO_CS_2020_PQ - Rec. 2020 color space, PQ transfer + - VIDEO_CS_2020_HLG - Rec. 2020 color space, HLG transfer --------------------- diff --git a/docs/sphinx/reference-outputs.rst b/docs/sphinx/reference-outputs.rst index b52ba160d..0b4470a3a 100644 --- a/docs/sphinx/reference-outputs.rst +++ b/docs/sphinx/reference-outputs.rst @@ -695,6 +695,24 @@ Functions used by outputs /* planar 4:4:4 */ VIDEO_FORMAT_I444, + + /* more packed uncompressed formats */ + VIDEO_FORMAT_BGR3, + + /* planar 4:2:2 */ + VIDEO_FORMAT_I422, + + /* planar 4:2:0 with alpha */ + VIDEO_FORMAT_I40A, + + /* planar 4:2:2 with alpha */ + VIDEO_FORMAT_I42A, + + /* planar 4:4:4 with alpha */ + VIDEO_FORMAT_YUVA, + + /* packed 4:4:4 with alpha */ + VIDEO_FORMAT_AYUV, }; enum video_colorspace { @@ -702,6 +720,8 @@ Functions used by outputs VIDEO_CS_601, VIDEO_CS_709, VIDEO_CS_SRGB, + VIDEO_CS_2020_PQ, + VIDEO_CS_2020_HLG, }; enum video_range_type { diff --git a/libobs/media-io/video-io.h b/libobs/media-io/video-io.h index 5cfcd2821..6e8a73022 100644 --- a/libobs/media-io/video-io.h +++ b/libobs/media-io/video-io.h @@ -75,12 +75,14 @@ enum video_colorspace { VIDEO_CS_601, VIDEO_CS_709, VIDEO_CS_SRGB, + VIDEO_CS_2020_PQ, + VIDEO_CS_2020_HLG, }; enum video_range_type { VIDEO_RANGE_DEFAULT, VIDEO_RANGE_PARTIAL, - VIDEO_RANGE_FULL + VIDEO_RANGE_FULL, }; struct video_data { @@ -176,13 +178,18 @@ static inline const char *get_video_colorspace_name(enum video_colorspace cs) switch (cs) { case VIDEO_CS_DEFAULT: case VIDEO_CS_709: - return "709"; + return "Rec. 709"; case VIDEO_CS_SRGB: return "sRGB"; - case VIDEO_CS_601:; + case VIDEO_CS_601: + return "Rec. 601"; + case VIDEO_CS_2020_PQ: + return "Rec. 2020 (PQ)"; + case VIDEO_CS_2020_HLG: + return "Rec. 2020 (HLG)"; } - return "601"; + return "Unknown"; } static inline enum video_range_type diff --git a/libobs/media-io/video-matrices.c b/libobs/media-io/video-matrices.c index c8e50e55d..f78b1e6e0 100644 --- a/libobs/media-io/video-matrices.c +++ b/libobs/media-io/video-matrices.c @@ -68,6 +68,23 @@ static struct { {1.000000f, 0.000000f, 1.581000f, -0.793600f, 1.000000f, -0.188062f, -0.469967f, 0.330305f, 1.000000f, 1.862906f, 0.000000f, -0.935106f, 0.000000f, 0.000000f, 0.000000f, 1.000000f}} +#endif + }, + {VIDEO_CS_2020_PQ, + 0.0593f, + 0.2627f, + {64, 64, 64}, + {940, 960, 960}, + {{64, 512, 512}, {0, 512, 512}}, +#ifndef COMPUTE_MATRICES + {64.0f / 1023.0f, 64.0f / 1023.0f, 64.0f / 1023.0f}, + {940.0f / 1023.0f, 960.0f / 1023.0f, 960.0f / 1023.0f}, + {{1.167808f, 0.000000f, 1.683611f, -0.915688f, 1.167808f, -0.187877f, + -0.652337f, 0.347459f, 1.167808f, 2.148072f, 0.000000f, -1.148145f, + 0.000000f, 0.000000f, 0.000000f, 1.000000f}, + {1.000000f, 0.000000f, 1.476043f, -0.738743f, 1.000000f, -0.164714f, + -0.571912f, 0.368673f, 1.000000f, 1.883241f, 0.000000f, -0.942541f, + 0.000000f, 0.000000f, 0.000000f, 1.000000f}} #endif }, }; @@ -88,8 +105,9 @@ static void log_matrix(float const matrix[16]) } static void initialize_matrix(float const Kb, float const Kr, - int const range_min[3], int const range_max[3], - int const black_levels[3], float matrix[16]) + float bit_range_max, int const range_min[3], + int const range_max[3], int const black_levels[3], + float matrix[16]) { struct matrix3 color_matrix; @@ -97,15 +115,18 @@ static void initialize_matrix(float const Kb, float const Kr, int uvals = (range_max[1] - range_min[1]) / 2; int vvals = (range_max[2] - range_min[2]) / 2; - vec3_set(&color_matrix.x, 255. / yvals, 0., 255. / vvals * (1. - Kr)); - vec3_set(&color_matrix.y, 255. / yvals, - 255. / uvals * (Kb - 1.) * Kb / (1. - Kb - Kr), - 255. / vvals * (Kr - 1.) * Kr / (1. - Kb - Kr)); - vec3_set(&color_matrix.z, 255. / yvals, 255. / uvals * (1. - Kb), 0.); + vec3_set(&color_matrix.x, bit_range_max / yvals, 0., + bit_range_max / vvals * (1.f - Kr)); + vec3_set(&color_matrix.y, bit_range_max / yvals, + bit_range_max / uvals * (Kb - 1.f) * Kb / (1.f - Kb - Kr), + bit_range_max / vvals * (Kr - 1.f) * Kr / (1.f - Kb - Kr)); + vec3_set(&color_matrix.z, bit_range_max / yvals, + bit_range_max / uvals * (1.f - Kb), 0.); struct vec3 offsets, multiplied; - vec3_set(&offsets, -black_levels[0] / 255., -black_levels[1] / 255., - -black_levels[2] / 255.); + vec3_set(&offsets, -black_levels[0] / bit_range_max, + -black_levels[1] / bit_range_max, + -black_levels[2] / bit_range_max); vec3_rotate(&multiplied, &offsets, &color_matrix); matrix[0] = color_matrix.x.x; @@ -131,16 +152,22 @@ static void initialize_matrix(float const Kb, float const Kr, static void initialize_matrices() { - static int range_min[] = {0, 0, 0}; - static int range_max[] = {255, 255, 255}; + static const int range_min[] = {0, 0, 0}; + static const int range_max_8bit[] = {255, 255, 255}; + static const int range_max_10bit[] = {1023, 1023, 1023}; for (size_t i = 0; i < NUM_FORMATS; i++) { - initialize_matrix(format_info[i].Kb, format_info[i].Kr, + const int *range_max = + (format_info[i].color_space == VIDEO_CS_2020_PQ) + ? range_max_10bit + : range_max_8bit; + float f_r_max = (float)range_max[0]; + initialize_matrix(format_info[i].Kb, format_info[i].Kr, f_r_max, range_min, range_max, format_info[i].black_levels[1], format_info[i].matrix[1]); - initialize_matrix(format_info[i].Kb, format_info[i].Kr, + initialize_matrix(format_info[i].Kb, format_info[i].Kr, f_r_max, format_info[i].range_min, format_info[i].range_max, format_info[i].black_levels[0], @@ -148,9 +175,9 @@ static void initialize_matrices() for (int j = 0; j < 3; j++) { format_info[i].float_range_min[j] = - format_info[i].range_min[j] / 255.; + format_info[i].range_min[j] / f_r_max; format_info[i].float_range_max[j] = - format_info[i].range_max[j] / 255.; + format_info[i].range_max[j] / f_r_max; } } } @@ -173,6 +200,8 @@ bool video_format_get_parameters(enum video_colorspace color_space, #endif if ((color_space == VIDEO_CS_DEFAULT) || (color_space == VIDEO_CS_SRGB)) color_space = VIDEO_CS_709; + else if (color_space == VIDEO_CS_2020_HLG) + color_space = VIDEO_CS_2020_PQ; for (size_t i = 0; i < NUM_FORMATS; i++) { if (format_info[i].color_space != color_space) diff --git a/libobs/obs.c b/libobs/obs.c index fd4efbd23..74d5c7734 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -270,6 +270,12 @@ static bool obs_init_textures(struct obs_video_info *ovi) enum gs_color_format format = GS_RGBA; enum gs_color_space space = GS_CS_SRGB; + switch (ovi->colorspace) { + case VIDEO_CS_2020_PQ: + case VIDEO_CS_2020_HLG: + format = GS_RGBA16F; + space = GS_CS_709_EXTENDED; + } video->render_texture = gs_texture_create(ovi->base_width, ovi->base_height, format, 1,