mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-18 13:35:13 +00:00
avutil/tests/color_utils: add tests for av_csp_itu_eotf
This commit is contained in:
parent
06f084468e
commit
7b73ea501d
@ -20,12 +20,35 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/csp.h"
|
||||
#include "libavutil/macros.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
#include "libavutil/pixfmt.h"
|
||||
|
||||
static inline int fuzzy_equal(double a, double b)
|
||||
{
|
||||
const double epsilon = fmax(fmax(fabs(a), fabs(b)), 1.0) * 1e-7;
|
||||
return fabs(a - b) <= epsilon;
|
||||
}
|
||||
|
||||
#define TEST_EOTF(func, input, ref) do \
|
||||
{ \
|
||||
const double _b[3] = { (ref)[0], (ref)[1], (ref)[2] }; \
|
||||
double _a[3] = { (input)[0], (input)[1], (input)[2] }; \
|
||||
func(Lw, Lb, _a); \
|
||||
for (int _i = 0; _i < 3; _i++) { \
|
||||
if (!fuzzy_equal(_a[_i], _b[_i])) { \
|
||||
printf("FAIL: trc=%s %s(%g, %g, %s) != %s\n" \
|
||||
" expected {%g, %g, %g}, got {%g, %g, %g}\n", \
|
||||
trc_name, #func, Lw, Lb, #input, #ref, \
|
||||
_b[0], _b[1], _b[2], _a[0], _a[1], _a[2]); \
|
||||
return 1; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static const double test_data[] = {
|
||||
@ -53,4 +76,91 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (enum AVColorTransferCharacteristic trc = 0; trc < AVCOL_TRC_NB; trc++) {
|
||||
av_csp_eotf_function eotf = av_csp_itu_eotf(trc);
|
||||
av_csp_eotf_function eotf_inv = av_csp_itu_eotf_inv(trc);
|
||||
const char *trc_name = av_color_transfer_name(trc);
|
||||
if (!eotf)
|
||||
continue;
|
||||
|
||||
if (trc == AVCOL_TRC_SMPTE2084) {
|
||||
/* This one is equivalent to the TRC already tested above */
|
||||
continue;
|
||||
} else if (trc == AVCOL_TRC_SMPTE428) {
|
||||
/* Test vectors from SMPTE RP-431-2 */
|
||||
const struct { double E_xyz[3]; double luma; } tests[] = {
|
||||
#define XYZ(X, Y, Z) { X / 4095.0, Y / 4095.0, Z / 4095.0 }
|
||||
{ XYZ( 379, 396, 389), 0.14 },
|
||||
{ XYZ( 759, 792, 778), 0.75 },
|
||||
{ XYZ(1138, 1188, 1167), 2.12 },
|
||||
{ XYZ(1518, 1584, 1556), 4.45 },
|
||||
{ XYZ(1897, 1980, 1945), 7.94 },
|
||||
{ XYZ(2276, 2376, 2334), 12.74 },
|
||||
{ XYZ(2656, 2772, 2723), 19.01 },
|
||||
{ XYZ(3035, 3168, 3112), 26.89 },
|
||||
{ XYZ(3415, 3564, 3501), 36.52 },
|
||||
{ XYZ(3794, 3960, 3890), 48.02 },
|
||||
};
|
||||
/* DCI reference display */
|
||||
const double luminance = 48.00;
|
||||
const double contrast = 2000;
|
||||
/* Solve for Lw - Lb = luminance, Lw / Lb = contrast */
|
||||
const double Lb = luminance / (contrast - 1);
|
||||
const double Lw = Lb + luminance;
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(tests); i++) {
|
||||
double L_xyz[3];
|
||||
memcpy(L_xyz, tests[i].E_xyz, sizeof(L_xyz));
|
||||
eotf(Lw, Lb, L_xyz);
|
||||
printf("trc=%s EOTF(%g, %g, {%g, %g, %g}) = {%g, %g %g}, expected Y=%f\n",
|
||||
trc_name, Lw, Lb,
|
||||
tests[i].E_xyz[0], tests[i].E_xyz[1], tests[i].E_xyz[2],
|
||||
L_xyz[0], L_xyz[1], L_xyz[2], tests[i].luma);
|
||||
|
||||
if (fabs(L_xyz[1] - tests[i].luma) > 0.01) {
|
||||
printf(" FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Normal, display-relative RGB curve */
|
||||
static const double black_points[] = { 0.0, 1e-6, 0.1, 1.5 };
|
||||
static const double white_points[] = { 50.0, 100.0, 203.0, 1000.0, 10000.0 };
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(black_points); i++) {
|
||||
for (int j = 0; j < FF_ARRAY_ELEMS(white_points); j++) {
|
||||
const double Lb = black_points[i];
|
||||
const double Lw = white_points[j];
|
||||
const double all0[3] = { 0.0, 0.0, 0.0 };
|
||||
const double all1[3] = { 1.0, 1.0, 1.0 };
|
||||
const double black[3] = { Lb, Lb, Lb };
|
||||
const double white[3] = { Lw, Lw, Lw };
|
||||
double L_prev;
|
||||
|
||||
TEST_EOTF(eotf, all0, black);
|
||||
TEST_EOTF(eotf, all1, white);
|
||||
TEST_EOTF(eotf_inv, black, all0);
|
||||
TEST_EOTF(eotf_inv, white, all1);
|
||||
|
||||
/* Test round-trip on grayscale ramp */
|
||||
for (double x = 0.0; x < 1.0; x += 0.1) {
|
||||
const double E[3] = { x, x, x };
|
||||
double L[3] = { x, x, x };
|
||||
eotf(Lw, Lb, L);
|
||||
|
||||
printf("trc=%s EOTF(%g, %g, {%g}) = {%g}\n",
|
||||
trc_name, Lw, Lb, E[1], L[1]);
|
||||
TEST_EOTF(eotf_inv, L, E);
|
||||
|
||||
if (x > 0.0 && L[1] <= L_prev) {
|
||||
printf(" FAIL: non-monotonic!\n");
|
||||
return 1;
|
||||
}
|
||||
L_prev = L[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user