libobs: Add video_format_get_parameters_for_format
Video matrix is slightly different based on the number of bits per channel, so derive from video_format for convenience.master
parent
9903d73f36
commit
94fa6d064b
|
@ -131,6 +131,19 @@ Video Handler
|
|||
|
||||
---------------------
|
||||
|
||||
.. function:: 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 min_range[3], float max_range[3])
|
||||
|
||||
Converts a color space/range to matrix/min/max values for a given video format.
|
||||
|
||||
:param color_space: Color space to convert
|
||||
:param range: Color range to convert
|
||||
:param format: Video format
|
||||
:param matrix: Pointer to the matrix
|
||||
:param min_range: Pointer to get the minimum range value
|
||||
:param max_range: Pointer to get the maximum range value
|
||||
|
||||
---------------------
|
||||
|
||||
.. function:: bool video_output_connect(video_t *video, const struct video_scale_info *conversion, void (*callback)(void *param, struct video_data *frame), void *param)
|
||||
|
||||
Connects a raw video callback to the video output handler.
|
||||
|
|
|
@ -250,6 +250,10 @@ EXPORT bool video_format_get_parameters(enum video_colorspace color_space,
|
|||
enum video_range_type range,
|
||||
float matrix[16], float min_range[3],
|
||||
float max_range[3]);
|
||||
EXPORT 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 min_range[3],
|
||||
float max_range[3]);
|
||||
|
||||
#define VIDEO_OUTPUT_SUCCESS 0
|
||||
#define VIDEO_OUTPUT_INVALIDPARAM -1
|
||||
|
|
|
@ -15,83 +15,49 @@
|
|||
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 "../util/bmem.h"
|
||||
#include "../graphics/matrix3.h"
|
||||
#endif
|
||||
|
||||
#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;
|
||||
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];
|
||||
|
||||
float matrix[OBS_COUNTOF(bpp_info)][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_601,
|
||||
0.114f,
|
||||
0.299f,
|
||||
},
|
||||
{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
|
||||
{
|
||||
VIDEO_CS_709,
|
||||
0.0722f,
|
||||
0.2126f,
|
||||
},
|
||||
{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
|
||||
{
|
||||
VIDEO_CS_2020_PQ,
|
||||
0.0593f,
|
||||
0.2627f,
|
||||
},
|
||||
};
|
||||
|
||||
#define NUM_FORMATS (sizeof(format_info) / sizeof(format_info[0]))
|
||||
|
||||
#ifdef COMPUTE_MATRICES
|
||||
#ifdef LOG_MATRICES
|
||||
static void log_matrix(float const matrix[16])
|
||||
{
|
||||
blog(LOG_DEBUG,
|
||||
|
@ -103,25 +69,29 @@ static void log_matrix(float const matrix[16])
|
|||
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, int const range_min[3],
|
||||
int const range_max[3], int const black_levels[3],
|
||||
float matrix[16])
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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.);
|
||||
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,
|
||||
|
@ -147,87 +117,156 @@ static void initialize_matrix(float const Kb, float const Kr,
|
|||
matrix[12] = matrix[13] = matrix[14] = 0.;
|
||||
matrix[15] = 1.;
|
||||
|
||||
#ifdef LOG_MATRICES
|
||||
log_matrix(matrix);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void initialize_matrices()
|
||||
{
|
||||
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};
|
||||
static const float full_range_min3[] = {0, 0, 0};
|
||||
|
||||
for (size_t i = 0; i < NUM_FORMATS; i++) {
|
||||
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]);
|
||||
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;
|
||||
|
||||
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],
|
||||
format_info[i].matrix[0]);
|
||||
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]);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
format_info[i].float_range_min[j] =
|
||||
format_info[i].range_min[j] / f_r_max;
|
||||
format_info[i].float_range_max[j] =
|
||||
format_info[i].range_max[j] / f_r_max;
|
||||
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;
|
||||
#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])
|
||||
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)
|
||||
{
|
||||
#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;
|
||||
else if (color_space == VIDEO_CS_2020_HLG)
|
||||
color_space = VIDEO_CS_2020_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++) {
|
||||
if (format_info[i].color_space != color_space)
|
||||
continue;
|
||||
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);
|
||||
|
||||
int full_range = range == VIDEO_RANGE_FULL ? 1 : 0;
|
||||
memcpy(matrix, format_info[i].matrix[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 == 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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 = 8;
|
||||
switch (color_space) {
|
||||
case VIDEO_CS_2020_PQ:
|
||||
case VIDEO_CS_2020_HLG:
|
||||
bpc = 10;
|
||||
}
|
||||
|
||||
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 = 8;
|
||||
switch (format) {
|
||||
case VIDEO_FORMAT_I010:
|
||||
case VIDEO_FORMAT_P010:
|
||||
bpc = 10;
|
||||
}
|
||||
|
||||
return video_format_get_parameters_for_bpc(color_space, range, matrix,
|
||||
range_min, range_max, bpc);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue