1 /******************************************************************************
2     Copyright (C) 2014 by Ruwen Hahn <palana@stunned.de>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 #include "../util/bmem.h"
19 #include "video-io.h"
20 
21 //#define COMPUTE_MATRICES
22 
23 #ifdef COMPUTE_MATRICES
24 #include "../graphics/matrix3.h"
25 #endif
26 
27 static struct {
28 	enum video_colorspace const color_space;
29 	float const Kb, Kr;
30 	int const range_min[3];
31 	int const range_max[3];
32 	int const black_levels[2][3];
33 
34 	float float_range_min[3];
35 	float float_range_max[3];
36 	float matrix[2][16];
37 
38 } format_info[] = {
39 	{VIDEO_CS_601,
40 	 0.114f,
41 	 0.299f,
42 	 {16, 16, 16},
43 	 {235, 240, 240},
44 	 {{16, 128, 128}, {0, 128, 128}},
45 #ifndef COMPUTE_MATRICES
46 	 {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
47 	 {235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
48 	 {{1.164384f, 0.000000f, 1.596027f, -0.874202f, 1.164384f, -0.391762f,
49 	   -0.812968f, 0.531668f, 1.164384f, 2.017232f, 0.000000f, -1.085631f,
50 	   0.000000f, 0.000000f, 0.000000f, 1.000000f},
51 	  {1.000000f, 0.000000f, 1.407520f, -0.706520f, 1.000000f, -0.345491f,
52 	   -0.716948f, 0.533303f, 1.000000f, 1.778976f, 0.000000f, -0.892976f,
53 	   0.000000f, 0.000000f, 0.000000f, 1.000000f}}
54 #endif
55 	},
56 	{VIDEO_CS_709,
57 	 0.0722f,
58 	 0.2126f,
59 	 {16, 16, 16},
60 	 {235, 240, 240},
61 	 {{16, 128, 128}, {0, 128, 128}},
62 #ifndef COMPUTE_MATRICES
63 	 {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
64 	 {235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
65 	 {{1.164384f, 0.000000f, 1.792741f, -0.972945f, 1.164384f, -0.213249f,
66 	   -0.532909f, 0.301483f, 1.164384f, 2.112402f, 0.000000f, -1.133402f,
67 	   0.000000f, 0.000000f, 0.000000f, 1.000000f},
68 	  {1.000000f, 0.000000f, 1.581000f, -0.793600f, 1.000000f, -0.188062f,
69 	   -0.469967f, 0.330305f, 1.000000f, 1.862906f, 0.000000f, -0.935106f,
70 	   0.000000f, 0.000000f, 0.000000f, 1.000000f}}
71 #endif
72 	},
73 };
74 
75 #define NUM_FORMATS (sizeof(format_info) / sizeof(format_info[0]))
76 
77 #ifdef COMPUTE_MATRICES
log_matrix(float const matrix[16])78 static void log_matrix(float const matrix[16])
79 {
80 	blog(LOG_DEBUG,
81 	     "\n% f, % f, % f, % f"
82 	     "\n% f, % f, % f, % f"
83 	     "\n% f, % f, % f, % f"
84 	     "\n% f, % f, % f, % f",
85 	     matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5],
86 	     matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11],
87 	     matrix[12], matrix[13], matrix[14], matrix[15]);
88 }
89 
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])90 static void initialize_matrix(float const Kb, float const Kr,
91 			      int const range_min[3], int const range_max[3],
92 			      int const black_levels[3], float matrix[16])
93 {
94 	struct matrix3 color_matrix;
95 
96 	int yvals = range_max[0] - range_min[0];
97 	int uvals = (range_max[1] - range_min[1]) / 2;
98 	int vvals = (range_max[2] - range_min[2]) / 2;
99 
100 	vec3_set(&color_matrix.x, 255. / yvals, 0., 255. / vvals * (1. - Kr));
101 	vec3_set(&color_matrix.y, 255. / yvals,
102 		 255. / uvals * (Kb - 1.) * Kb / (1. - Kb - Kr),
103 		 255. / vvals * (Kr - 1.) * Kr / (1. - Kb - Kr));
104 	vec3_set(&color_matrix.z, 255. / yvals, 255. / uvals * (1. - Kb), 0.);
105 
106 	struct vec3 offsets, multiplied;
107 	vec3_set(&offsets, -black_levels[0] / 255., -black_levels[1] / 255.,
108 		 -black_levels[2] / 255.);
109 	vec3_rotate(&multiplied, &offsets, &color_matrix);
110 
111 	matrix[0] = color_matrix.x.x;
112 	matrix[1] = color_matrix.x.y;
113 	matrix[2] = color_matrix.x.z;
114 	matrix[3] = multiplied.x;
115 
116 	matrix[4] = color_matrix.y.x;
117 	matrix[5] = color_matrix.y.y;
118 	matrix[6] = color_matrix.y.z;
119 	matrix[7] = multiplied.y;
120 
121 	matrix[8] = color_matrix.z.x;
122 	matrix[9] = color_matrix.z.y;
123 	matrix[10] = color_matrix.z.z;
124 	matrix[11] = multiplied.z;
125 
126 	matrix[12] = matrix[13] = matrix[14] = 0.;
127 	matrix[15] = 1.;
128 
129 	log_matrix(matrix);
130 }
131 
initialize_matrices()132 static void initialize_matrices()
133 {
134 	static int range_min[] = {0, 0, 0};
135 	static int range_max[] = {255, 255, 255};
136 
137 	for (size_t i = 0; i < NUM_FORMATS; i++) {
138 		initialize_matrix(format_info[i].Kb, format_info[i].Kr,
139 				  range_min, range_max,
140 				  format_info[i].black_levels[1],
141 				  format_info[i].matrix[1]);
142 
143 		initialize_matrix(format_info[i].Kb, format_info[i].Kr,
144 				  format_info[i].range_min,
145 				  format_info[i].range_max,
146 				  format_info[i].black_levels[0],
147 				  format_info[i].matrix[0]);
148 
149 		for (int j = 0; j < 3; j++) {
150 			format_info[i].float_range_min[j] =
151 				format_info[i].range_min[j] / 255.;
152 			format_info[i].float_range_max[j] =
153 				format_info[i].range_max[j] / 255.;
154 		}
155 	}
156 }
157 
158 static bool matrices_initialized = false;
159 #endif
160 
161 static const float full_min[3] = {0.0f, 0.0f, 0.0f};
162 static const float full_max[3] = {1.0f, 1.0f, 1.0f};
163 
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])164 bool video_format_get_parameters(enum video_colorspace color_space,
165 				 enum video_range_type range, float matrix[16],
166 				 float range_min[3], float range_max[3])
167 {
168 #ifdef COMPUTE_MATRICES
169 	if (!matrices_initialized) {
170 		initialize_matrices();
171 		matrices_initialized = true;
172 	}
173 #endif
174 	if ((color_space == VIDEO_CS_DEFAULT) || (color_space == VIDEO_CS_SRGB))
175 		color_space = VIDEO_CS_709;
176 
177 	for (size_t i = 0; i < NUM_FORMATS; i++) {
178 		if (format_info[i].color_space != color_space)
179 			continue;
180 
181 		int full_range = range == VIDEO_RANGE_FULL ? 1 : 0;
182 		memcpy(matrix, format_info[i].matrix[full_range],
183 		       sizeof(float) * 16);
184 
185 		if (range == VIDEO_RANGE_FULL) {
186 			if (range_min)
187 				memcpy(range_min, full_min, sizeof(float) * 3);
188 			if (range_max)
189 				memcpy(range_max, full_max, sizeof(float) * 3);
190 			return true;
191 		}
192 
193 		if (range_min)
194 			memcpy(range_min, format_info[i].float_range_min,
195 			       sizeof(float) * 3);
196 
197 		if (range_max)
198 			memcpy(range_max, format_info[i].float_range_max,
199 			       sizeof(float) * 3);
200 
201 		return true;
202 	}
203 	return false;
204 }
205