/****************************************************************************** Copyright (C) 2014 by Ruwen Hahn 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 . ******************************************************************************/ #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_SRGB)) color_space = VIDEO_CS_709; 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; }