color.c: generalize the macros

do not assume just BT.709 coefficients
This commit is contained in:
Martin Pulec
2024-09-27 12:43:17 +02:00
parent 7168c8763b
commit 16cfc6a3e2
2 changed files with 60 additions and 46 deletions

View File

@@ -42,53 +42,63 @@
#include "types.h" // for depth
#define KG_709 KG(KR_709,KB_709)
#define D (2.*(KR_709+KG_709))
#define E (2.*(1.-KR_709))
#define D(kr, kb) (2. * ((kr) + KG(kr, kb)))
#define E(kr) (2. * (1. - (kr)))
#define Y_R(out_depth) \
((comp_type_t) (((KR_709 * Y_LIMIT(out_depth)) * (1 << COMP_BASE)) + \
#define Y_R(out_depth, kr, kb) \
((comp_type_t) (((kr * Y_LIMIT(out_depth)) * (1 << COMP_BASE)) + C_EPS))
#define Y_G(out_depth, kr, kb) \
((comp_type_t) (((KG(kr, kb) * Y_LIMIT(out_depth)) * \
(1 << COMP_BASE)) + \
C_EPS))
#define Y_G(out_depth) \
((comp_type_t) (((KG_709 * Y_LIMIT(out_depth)) * (1 << COMP_BASE)) + \
#define Y_B(out_depth, kr, kb) \
((comp_type_t) ((((kb) * Y_LIMIT(out_depth)) * (1 << COMP_BASE)) + \
C_EPS))
#define Y_B(out_depth) \
((comp_type_t) (((KB_709 * Y_LIMIT(out_depth)) * (1 << COMP_BASE)) + \
#define CB_R(out_depth, kr, kb) \
((comp_type_t) (((-(kr) / D(kr, kb) * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - \
C_EPS))
#define CB_G(out_depth, kr, kb) \
((comp_type_t) (((-KG(kr, kb) / D(kr, kb) * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - \
C_EPS))
#define CB_B(out_depth, kr, kb) \
((comp_type_t) ((((1 - (kb)) / D(kr, kb) * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) + \
C_EPS))
#define CR_R(out_depth, kr, kb) \
((comp_type_t) ((((1 - (kr)) / E(kr) * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - \
C_EPS))
#define CR_G(out_depth, kr, kb) \
((comp_type_t) (((-KG(kr, kb) / E(kr) * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - \
C_EPS))
#define CR_B(out_depth, kr, kb) \
((comp_type_t) (((-(kb) / E(kr) * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) + \
C_EPS))
#define CB_R(out_depth) \
((comp_type_t) (((-KR_709 / D * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - C_EPS))
#define CB_G(out_depth) \
((comp_type_t) (((-KG_709 / D * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - C_EPS))
#define CB_B(out_depth) \
((comp_type_t) ((((1 - KB_709) / D * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) + C_EPS))
#define CR_R(out_depth) \
((comp_type_t) ((((1 - KR_709) / E * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - C_EPS))
#define CR_G(out_depth) \
((comp_type_t) (((-KG_709 / E * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) - C_EPS))
#define CR_B(out_depth) \
((comp_type_t) (((-KB_709 / E * CBCR_LIMIT(out_depth)) * \
(1 << COMP_BASE)) + C_EPS))
#define COEFFS(depth) \
#define COEFFS(depth, kr, kb) \
{ \
Y_R(depth), Y_G(depth), Y_B(depth),\
CB_R(depth), CB_G(depth), CB_B(depth),\
CR_R(depth), CR_G(depth), CR_B(depth),\
Y_R(depth, kr, kb), Y_G(depth, kr, kb), Y_B(depth, kr, kb),\
CB_R(depth, kr, kb), CB_G(depth, kr, kb), CB_B(depth, kr, kb),\
CR_R(depth, kr, kb), CR_G(depth, kr, kb), CR_B(depth, kr, kb),\
\
SCALED(R_CR(depth, KR_709, KB_709)), \
SCALED(G_CB(depth, KR_709, KB_709)), \
SCALED(G_CR(depth, KR_709, KB_709)), \
SCALED(B_CB(depth, KR_709, KB_709)), \
SCALED(R_CR(depth, kr, kb)), \
SCALED(G_CB(depth, kr, kb)), \
SCALED(G_CR(depth, kr, kb)), \
SCALED(B_CB(depth, kr, kb)), \
}
#define COEFFS_709(depth) COEFFS(depth, KR_709, KB_709)
/**
* @brief returns color coefficient for RGB<-YCbCr conversion
*
* Using BT.709 by default.
*
*
* @note
* It is suggested to copy the result to a struct (not using the returned ptr
* directly) when passing to RGB_TO_*() or YCBCR_TO_*(). The compiler may not
@@ -99,10 +109,10 @@
const struct color_coeffs *
get_color_coeffs(int ycbcr_bit_depth)
{
static const struct color_coeffs col_cfs_8 = COEFFS(DEPTH8);
static const struct color_coeffs col_cfs_10 = COEFFS(DEPTH10);
static const struct color_coeffs col_cfs_12 = COEFFS(DEPTH12);
static const struct color_coeffs col_cfs_16 = COEFFS(DEPTH16);
static const struct color_coeffs col_cfs_8 = COEFFS_709(DEPTH8);
static const struct color_coeffs col_cfs_10 = COEFFS_709(DEPTH10);
static const struct color_coeffs col_cfs_12 = COEFFS_709(DEPTH12);
static const struct color_coeffs col_cfs_16 = COEFFS_709(DEPTH16);
switch ((enum depth) ycbcr_bit_depth) {
case DEPTH8:
return &col_cfs_8;

View File

@@ -47,20 +47,25 @@
#include "utils/macros.h" // CLAMP
/* @brief Color space coedfficients - RGB full range to YCbCr bt. 709 limited range
/**
* @file
* @brief Color space coedfficients and limits
*
* RGB should use SDI full range [1<<(depth-8)..255<<(depth-8)-1], see [limits]
* RGB should use SDI full range [1<<(depth-8)..255<<(depth-8)-1], YCbCr
* limited, see [limits].
*
* The coefficients are scaled by 1<<COMP_BASE.
*
* limited footroom is (1<<(limited_depth - 4)), headroom 235*(limited_depth-8)
* /luma/, 240*(limited_depth-8)/255 /chroma/; full-range limits
* [2^(depth-8)..255*2^(depth-8)-1] (excludes vals with 0x00 and 0xFF MSB).
*
* Scaled by 1<<COMP_BASE, footroom 16/255, headroom 235/255 (luma), 240/255 (chroma); limits [2^(depth-8)..255*2^(depth-8)-1]
* matrix Y = [ 0.182586, 0.614231, 0.062007; -0.100643, -0.338572, 0.4392157; 0.4392157, -0.398942, -0.040274 ]
* * [coefficients]: https://gist.github.com/yohhoy/dafa5a47dade85d8b40625261af3776a "Rec. 709 coefficients"
* * [limits]: https://tech.ebu.ch/docs/r/r103.pdf "SDI limits"
*
* @ingroup lavc_video_conversions
*
* @todo
* Use this transformations in all conversions.
* @{
*/
typedef int32_t comp_type_t; // int32_t provides much better performance than int_fast32_t
#define COMP_BASE (sizeof(comp_type_t) == 4 ? 14 : 18) // computation will be less precise when comp_type_t is 32 bit
@@ -136,7 +141,6 @@ static_assert(sizeof(comp_type_t) * 8 >= COMP_BASE + 18, "comp_type_t not wide e
((alpha_mask) | (CLAMP_FULL((r), (depth)) << (rshift) | \
CLAMP_FULL((g), (depth)) << (gshift) | \
CLAMP_FULL((b), (depth)) << (bshift)))
/// @}
#define MK_MONOCHROME(val) \
FORMAT_RGBA((val), (val), (val), 0, 8, 16, 0xFF000000, 8)