| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 | 
							- /******************************************************************************
 
-     Copyright (C) 2014 by Ruwen Hahn <[email protected]>
 
-     This program is free software: you can redistribute it and/or modify
 
-     it under the terms of the GNU General Public License as published by
 
-     the Free Software Foundation, either version 2 of the License, or
 
-     (at your option) any later version.
 
-     This program is distributed in the hope that it will be useful,
 
-     but WITHOUT ANY WARRANTY; without even the implied warranty of
 
-     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
-     GNU General Public License for more details.
 
-     You should have received a copy of the GNU General Public License
 
-     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- ******************************************************************************/
 
- #include "video-io.h"
 
- #include "../util/bmem.h"
 
- #include "../graphics/matrix3.h"
 
- #include <assert.h>
 
- //#define LOG_MATRICES
 
- static struct {
 
- 	float range_min[3];
 
- 	float range_max[3];
 
- 	float black_levels[2][3];
 
- 	float float_range_min[3];
 
- 	float float_range_max[3];
 
- } bpp_info[9];
 
- static struct {
 
- 	enum video_colorspace const color_space;
 
- 	float const Kb, Kr;
 
- 	float matrix[OBS_COUNTOF(bpp_info)][2][16];
 
- } format_info[] = {
 
- 	{
 
- 		VIDEO_CS_601,
 
- 		0.114f,
 
- 		0.299f,
 
- 	},
 
- 	{
 
- 		VIDEO_CS_709,
 
- 		0.0722f,
 
- 		0.2126f,
 
- 	},
 
- 	{
 
- 		VIDEO_CS_2100_PQ,
 
- 		0.0593f,
 
- 		0.2627f,
 
- 	},
 
- };
 
- #define NUM_FORMATS (sizeof(format_info) / sizeof(format_info[0]))
 
- #ifdef LOG_MATRICES
 
- static void log_matrix(float const matrix[16])
 
- {
 
- 	blog(LOG_DEBUG,
 
- 	     "\n% f, % f, % f, % f"
 
- 	     "\n% f, % f, % f, % f"
 
- 	     "\n% f, % f, % f, % f"
 
- 	     "\n% f, % f, % f, % f",
 
- 	     matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5],
 
- 	     matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11],
 
- 	     matrix[12], matrix[13], matrix[14], matrix[15]);
 
- }
 
- #endif
 
- static void initialize_matrix(float const Kb, float const Kr,
 
- 			      float bit_range_max, float const range_min[3],
 
- 			      float const range_max[3],
 
- 			      float const black_levels[3], float matrix[16])
 
- {
 
- 	struct matrix3 color_matrix;
 
- 	float const yvals = range_max[0] - range_min[0];
 
- 	float const uvals = (range_max[1] - range_min[1]) / 2.f;
 
- 	float const vvals = (range_max[2] - range_min[2]) / 2.f;
 
- 	float const yscale = bit_range_max / yvals;
 
- 	float const uscale = bit_range_max / uvals;
 
- 	float const vscale = bit_range_max / vvals;
 
- 	float const Kg = (1.f - Kb - Kr);
 
- 	vec3_set(&color_matrix.x, yscale, 0.f, vscale * (1.f - Kr));
 
- 	vec3_set(&color_matrix.y, yscale, uscale * (Kb - 1.f) * Kb / Kg,
 
- 		 vscale * (Kr - 1.f) * Kr / Kg);
 
- 	vec3_set(&color_matrix.z, yscale, uscale * (1.f - Kb), 0.f);
 
- 	struct vec3 offsets, multiplied;
 
- 	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;
 
- 	matrix[1] = color_matrix.x.y;
 
- 	matrix[2] = color_matrix.x.z;
 
- 	matrix[3] = multiplied.x;
 
- 	matrix[4] = color_matrix.y.x;
 
- 	matrix[5] = color_matrix.y.y;
 
- 	matrix[6] = color_matrix.y.z;
 
- 	matrix[7] = multiplied.y;
 
- 	matrix[8] = color_matrix.z.x;
 
- 	matrix[9] = color_matrix.z.y;
 
- 	matrix[10] = color_matrix.z.z;
 
- 	matrix[11] = multiplied.z;
 
- 	matrix[12] = matrix[13] = matrix[14] = 0.;
 
- 	matrix[15] = 1.;
 
- #ifdef LOG_MATRICES
 
- 	log_matrix(matrix);
 
- #endif
 
- }
 
- static void initialize_matrices()
 
- {
 
- 	static const float full_range_min3[] = {0, 0, 0};
 
- 	float min_value = 16.f;
 
- 	float max_luma = 235.f;
 
- 	float max_chroma = 240.f;
 
- 	float range = 256.f;
 
- 	for (uint32_t bpp = 8; bpp <= 16; ++bpp) {
 
- 		const uint32_t bpp_index = bpp - 8;
 
- 		bpp_info[bpp_index].range_min[0] = min_value;
 
- 		bpp_info[bpp_index].range_min[1] = min_value;
 
- 		bpp_info[bpp_index].range_min[2] = min_value;
 
- 		bpp_info[bpp_index].range_max[0] = max_luma;
 
- 		bpp_info[bpp_index].range_max[1] = max_chroma;
 
- 		bpp_info[bpp_index].range_max[2] = max_chroma;
 
- 		const float mid_chroma = 0.5f * (min_value + max_chroma);
 
- 		bpp_info[bpp_index].black_levels[0][0] = min_value;
 
- 		bpp_info[bpp_index].black_levels[0][1] = mid_chroma;
 
- 		bpp_info[bpp_index].black_levels[0][2] = mid_chroma;
 
- 		bpp_info[bpp_index].black_levels[1][0] = 0.f;
 
- 		bpp_info[bpp_index].black_levels[1][1] = mid_chroma;
 
- 		bpp_info[bpp_index].black_levels[1][2] = mid_chroma;
 
- 		const float range_max = range - 1.f;
 
- 		bpp_info[bpp_index].float_range_min[0] = min_value / range_max;
 
- 		bpp_info[bpp_index].float_range_min[1] = min_value / range_max;
 
- 		bpp_info[bpp_index].float_range_min[2] = min_value / range_max;
 
- 		bpp_info[bpp_index].float_range_max[0] = max_luma / range_max;
 
- 		bpp_info[bpp_index].float_range_max[1] = max_chroma / range_max;
 
- 		bpp_info[bpp_index].float_range_max[2] = max_chroma / range_max;
 
- 		for (size_t i = 0; i < NUM_FORMATS; i++) {
 
- 			float full_range_max3[] = {range_max, range_max,
 
- 						   range_max};
 
- 			initialize_matrix(format_info[i].Kb, format_info[i].Kr,
 
- 					  range_max, full_range_min3,
 
- 					  full_range_max3,
 
- 					  bpp_info[bpp_index].black_levels[1],
 
- 					  format_info[i].matrix[bpp_index][1]);
 
- 			initialize_matrix(format_info[i].Kb, format_info[i].Kr,
 
- 					  range_max,
 
- 					  bpp_info[bpp_index].range_min,
 
- 					  bpp_info[bpp_index].range_max,
 
- 					  bpp_info[bpp_index].black_levels[0],
 
- 					  format_info[i].matrix[bpp_index][0]);
 
- 		}
 
- 		min_value *= 2.f;
 
- 		max_luma *= 2.f;
 
- 		max_chroma *= 2.f;
 
- 		range *= 2.f;
 
- 	}
 
- }
 
- static bool matrices_initialized = false;
 
- static const float full_min[3] = {0.0f, 0.0f, 0.0f};
 
- static const float full_max[3] = {1.0f, 1.0f, 1.0f};
 
- static bool video_format_get_parameters_for_bpc(
 
- 	enum video_colorspace color_space, enum video_range_type range,
 
- 	float matrix[16], float range_min[3], float range_max[3], uint32_t bpc)
 
- {
 
- 	if (!matrices_initialized) {
 
- 		initialize_matrices();
 
- 		matrices_initialized = true;
 
- 	}
 
- 	if ((color_space == VIDEO_CS_DEFAULT) || (color_space == VIDEO_CS_SRGB))
 
- 		color_space = VIDEO_CS_709;
 
- 	else if (color_space == VIDEO_CS_2100_HLG)
 
- 		color_space = VIDEO_CS_2100_PQ;
 
- 	if (bpc < 8)
 
- 		bpc = 8;
 
- 	if (bpc > 16)
 
- 		bpc = 16;
 
- 	const uint32_t bpc_index = bpc - 8;
 
- 	assert(bpc_index < OBS_COUNTOF(bpp_info));
 
- 	bool success = false;
 
- 	for (size_t i = 0; i < NUM_FORMATS; i++) {
 
- 		success = format_info[i].color_space == color_space;
 
- 		if (success) {
 
- 			const bool full_range = range == VIDEO_RANGE_FULL;
 
- 			memcpy(matrix,
 
- 			       format_info[i].matrix[bpc_index][full_range],
 
- 			       sizeof(float) * 16);
 
- 			if (range_min) {
 
- 				const float *src_range_min =
 
- 					full_range ? full_min
 
- 						   : bpp_info[bpc_index]
 
- 							     .float_range_min;
 
- 				memcpy(range_min, src_range_min,
 
- 				       sizeof(float) * 3);
 
- 			}
 
- 			if (range_max) {
 
- 				const float *src_range_max =
 
- 					full_range ? full_max
 
- 						   : bpp_info[bpc_index]
 
- 							     .float_range_max;
 
- 				memcpy(range_max, src_range_max,
 
- 				       sizeof(float) * 3);
 
- 			}
 
- 			break;
 
- 		}
 
- 	}
 
- 	return success;
 
- }
 
- bool video_format_get_parameters(enum video_colorspace color_space,
 
- 				 enum video_range_type range, float matrix[16],
 
- 				 float range_min[3], float range_max[3])
 
- {
 
- 	uint32_t bpc = (color_space == VIDEO_CS_2100_PQ ||
 
- 			color_space == VIDEO_CS_2100_HLG)
 
- 			       ? 10
 
- 			       : 8;
 
- 	return video_format_get_parameters_for_bpc(color_space, range, matrix,
 
- 						   range_min, range_max, bpc);
 
- }
 
- bool video_format_get_parameters_for_format(enum video_colorspace color_space,
 
- 					    enum video_range_type range,
 
- 					    enum video_format format,
 
- 					    float matrix[16],
 
- 					    float range_min[3],
 
- 					    float range_max[3])
 
- {
 
- 	uint32_t bpc;
 
- 	switch (format) {
 
- 	case VIDEO_FORMAT_I010:
 
- 	case VIDEO_FORMAT_P010:
 
- 	case VIDEO_FORMAT_I210:
 
- 	case VIDEO_FORMAT_V210:
 
- 	case VIDEO_FORMAT_R10L:
 
- 		bpc = 10;
 
- 		break;
 
- 	case VIDEO_FORMAT_I412:
 
- 	case VIDEO_FORMAT_YA2L:
 
- 		bpc = 12;
 
- 		break;
 
- 	case VIDEO_FORMAT_P216:
 
- 	case VIDEO_FORMAT_P416:
 
- 		bpc = 16;
 
- 		break;
 
- 	default:
 
- 		bpc = 8;
 
- 		break;
 
- 	}
 
- 	return video_format_get_parameters_for_bpc(color_space, range, matrix,
 
- 						   range_min, range_max, bpc);
 
- }
 
 
  |