f53df7da64
Code submissions have continually suffered from formatting inconsistencies that constantly have to be addressed. Using clang-format simplifies this by making code formatting more consistent, and allows automation of the code formatting so that maintainers can focus more on the code itself instead of code formatting.
205 lines
6.1 KiB
C
205 lines
6.1 KiB
C
/******************************************************************************
|
|
Copyright (C) 2014 by Ruwen Hahn <palana@stunned.de>
|
|
|
|
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 "../util/bmem.h"
|
|
#include "video-io.h"
|
|
|
|
//#define COMPUTE_MATRICES
|
|
|
|
#ifdef COMPUTE_MATRICES
|
|
#include "../graphics/matrix3.h"
|
|
#endif
|
|
|
|
static struct {
|
|
enum video_colorspace const color_space;
|
|
float const Kb, Kr;
|
|
int const range_min[3];
|
|
int const range_max[3];
|
|
int const black_levels[2][3];
|
|
|
|
float float_range_min[3];
|
|
float float_range_max[3];
|
|
float matrix[2][16];
|
|
|
|
} format_info[] = {
|
|
{VIDEO_CS_601,
|
|
0.114f,
|
|
0.299f,
|
|
{16, 16, 16},
|
|
{235, 240, 240},
|
|
{{16, 128, 128}, {0, 128, 128}},
|
|
#ifndef COMPUTE_MATRICES
|
|
{16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
|
|
{235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
|
|
{{1.164384f, 0.000000f, 1.596027f, -0.874202f, 1.164384f, -0.391762f,
|
|
-0.812968f, 0.531668f, 1.164384f, 2.017232f, 0.000000f, -1.085631f,
|
|
0.000000f, 0.000000f, 0.000000f, 1.000000f},
|
|
{1.000000f, 0.000000f, 1.407520f, -0.706520f, 1.000000f, -0.345491f,
|
|
-0.716948f, 0.533303f, 1.000000f, 1.778976f, 0.000000f, -0.892976f,
|
|
0.000000f, 0.000000f, 0.000000f, 1.000000f}}
|
|
#endif
|
|
},
|
|
{VIDEO_CS_709,
|
|
0.0722f,
|
|
0.2126f,
|
|
{16, 16, 16},
|
|
{235, 240, 240},
|
|
{{16, 128, 128}, {0, 128, 128}},
|
|
#ifndef COMPUTE_MATRICES
|
|
{16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f},
|
|
{235.0f / 255.0f, 240.0f / 255.0f, 240.0f / 255.0f},
|
|
{{1.164384f, 0.000000f, 1.792741f, -0.972945f, 1.164384f, -0.213249f,
|
|
-0.532909f, 0.301483f, 1.164384f, 2.112402f, 0.000000f, -1.133402f,
|
|
0.000000f, 0.000000f, 0.000000f, 1.000000f},
|
|
{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
|
|
},
|
|
};
|
|
|
|
#define NUM_FORMATS (sizeof(format_info) / sizeof(format_info[0]))
|
|
|
|
#ifdef COMPUTE_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]);
|
|
}
|
|
|
|
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])
|
|
{
|
|
struct matrix3 color_matrix;
|
|
|
|
int yvals = range_max[0] - range_min[0];
|
|
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.);
|
|
|
|
struct vec3 offsets, multiplied;
|
|
vec3_set(&offsets, -black_levels[0] / 255., -black_levels[1] / 255.,
|
|
-black_levels[2] / 255.);
|
|
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.;
|
|
|
|
log_matrix(matrix);
|
|
}
|
|
|
|
static void initialize_matrices()
|
|
{
|
|
static int range_min[] = {0, 0, 0};
|
|
static int range_max[] = {255, 255, 255};
|
|
|
|
for (size_t i = 0; i < NUM_FORMATS; i++) {
|
|
initialize_matrix(format_info[i].Kb, format_info[i].Kr,
|
|
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,
|
|
format_info[i].range_min,
|
|
format_info[i].range_max,
|
|
format_info[i].black_levels[0],
|
|
format_info[i].matrix[0]);
|
|
|
|
for (int j = 0; j < 3; j++) {
|
|
format_info[i].float_range_min[j] =
|
|
format_info[i].range_min[j] / 255.;
|
|
format_info[i].float_range_max[j] =
|
|
format_info[i].range_max[j] / 255.;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool matrices_initialized = false;
|
|
#endif
|
|
|
|
static const float full_min[3] = {0.0f, 0.0f, 0.0f};
|
|
static const float full_max[3] = {1.0f, 1.0f, 1.0f};
|
|
|
|
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])
|
|
{
|
|
#ifdef COMPUTE_MATRICES
|
|
if (!matrices_initialized) {
|
|
initialize_matrices();
|
|
matrices_initialized = true;
|
|
}
|
|
#endif
|
|
if (color_space == VIDEO_CS_DEFAULT)
|
|
color_space = VIDEO_CS_601;
|
|
|
|
for (size_t i = 0; i < NUM_FORMATS; i++) {
|
|
if (format_info[i].color_space != color_space)
|
|
continue;
|
|
|
|
int full_range = range == VIDEO_RANGE_FULL ? 1 : 0;
|
|
memcpy(matrix, format_info[i].matrix[full_range],
|
|
sizeof(float) * 16);
|
|
|
|
if (range == VIDEO_RANGE_FULL) {
|
|
if (range_min)
|
|
memcpy(range_min, full_min, sizeof(float) * 3);
|
|
if (range_max)
|
|
memcpy(range_max, full_max, sizeof(float) * 3);
|
|
return true;
|
|
}
|
|
|
|
if (range_min)
|
|
memcpy(range_min, format_info[i].float_range_min,
|
|
sizeof(float) * 3);
|
|
|
|
if (range_max)
|
|
memcpy(range_max, format_info[i].float_range_max,
|
|
sizeof(float) * 3);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|