forked from mpv-player/mpv
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: add tests for zimg RGB repacking
This tests the RGB repacker code in zimg, which deserves to be tested because it's tricky and there will be more formats. scale_test.c contains some code that can be used to test any scaler. Or at least that would be great; currently it can only test repacking of some byte-aligned-component RGB formats. It should be called repack_test.c, but I'm too lazy to change the filename now. The idea is that libswscale is used to cross-check the conversions performed by the zimg wrapper. This is why it's "OK" that scale_test.c does libswscale calls. scale_sws.c is the equivalent to scale_zimg.c, and is of course worthless (because it tests libswscale by comparing the results with libswscale), but still might help with finding bugs in scale_test.c. This borrows a sorted list of image formats from test/img_format.c, for the same reason that file sorts them. There's a slight possibility that this can be used to test vo_gpu.c too some times in the future.
- Loading branch information
wm4
committed
Nov 9, 2019
1 parent
27d88e4
commit 94d853d
Showing
10 changed files
with
349 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
0bgr using gbrp | ||
0rgb using gbrp | ||
abgr using gbrap | ||
argb using gbrap | ||
bgr0 using gbrp | ||
bgr24 using gbrp | ||
bgr48 using gbrp16 | ||
bgr48be using gbrp16 | ||
bgra using gbrap | ||
bgra64 using gbrap16 | ||
bgra64be using gbrap16 | ||
rgb0 using gbrp | ||
rgb24 using gbrp | ||
rgb48 using gbrp16 | ||
rgb48be using gbrp16 | ||
rgba using gbrap | ||
rgba64 using gbrap16 | ||
rgba64be using gbrap16 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
0bgr using gbrp | ||
0rgb using gbrp | ||
bgr0 using gbrp | ||
bgr24 using gbrp | ||
bgr48 using gbrp16 | ||
rgb0 using gbrp | ||
rgb24 using gbrp | ||
rgb48 using gbrp16 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Test scaling using libswscale. | ||
// Note: libswscale is already tested in FFmpeg. This code serves mostly to test | ||
// the functionality scale_test.h using the already tested libswscale as | ||
// reference. | ||
|
||
#include "scale_test.h" | ||
#include "video/sws_utils.h" | ||
|
||
static bool scale(void *pctx, struct mp_image *dst, struct mp_image *src) | ||
{ | ||
struct mp_sws_context *ctx = pctx; | ||
return mp_sws_scale(ctx, dst, src) >= 0; | ||
} | ||
|
||
static bool supports_fmts(void *pctx, int imgfmt_dst, int imgfmt_src) | ||
{ | ||
struct mp_sws_context *ctx = pctx; | ||
return mp_sws_supports_formats(ctx, imgfmt_dst, imgfmt_src); | ||
} | ||
|
||
static const struct scale_test_fns fns = { | ||
.scale = scale, | ||
.supports_fmts = supports_fmts, | ||
}; | ||
|
||
static void run(struct test_ctx *ctx) | ||
{ | ||
struct mp_sws_context *sws = mp_sws_alloc(NULL); | ||
|
||
struct scale_test *stest = talloc_zero(NULL, struct scale_test); | ||
stest->fns = &fns; | ||
stest->fns_priv = sws; | ||
stest->test_name = "repack_sws"; | ||
stest->ctx = ctx; | ||
|
||
repack_test_run(stest); | ||
|
||
talloc_free(stest); | ||
talloc_free(sws); | ||
} | ||
|
||
const struct unittest test_repack_sws = { | ||
.name = "repack_sws", | ||
.run = run, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
#include <libavcodec/avcodec.h> | ||
|
||
#include "scale_test.h" | ||
#include "video/image_writer.h" | ||
#include "video/sws_utils.h" | ||
|
||
static struct mp_image *gen_repack_test_img(int w, int h, int bytes, bool rgb, | ||
bool alpha) | ||
{ | ||
struct mp_regular_imgfmt planar_desc = { | ||
.component_type = MP_COMPONENT_TYPE_UINT, | ||
.component_size = bytes, | ||
.forced_csp = rgb ? MP_CSP_RGB : 0, | ||
.num_planes = alpha ? 4 : 3, | ||
.planes = { | ||
{1, {rgb ? 2 : 1}}, | ||
{1, {rgb ? 3 : 2}}, | ||
{1, {rgb ? 1 : 3}}, | ||
{1, {4}}, | ||
}, | ||
.chroma_w = 1, | ||
.chroma_h = 1, | ||
}; | ||
int mpfmt = mp_find_regular_imgfmt(&planar_desc); | ||
assert(mpfmt); | ||
struct mp_image *mpi = mp_image_alloc(mpfmt, w, h); | ||
assert(mpi); | ||
|
||
// Well, I have no idea what makes a good test image. So here's some crap. | ||
// This contains bars/tiles of solid colors. For each of R/G/B, it toggles | ||
// though 0/100% range, so 2*2*2 = 8 combinations (16 with alpha). | ||
int b_h = 16, b_w = 16; | ||
|
||
for (int y = 0; y < h; y++) { | ||
for (int p = 0; p < mpi->num_planes; p++) { | ||
void *line = mpi->planes[p] + mpi->stride[p] * (ptrdiff_t)y; | ||
|
||
for (int x = 0; x < w; x += b_w) { | ||
unsigned i = x / b_w + y / b_h * 2; | ||
int c = ((i >> p) & 1); | ||
if (bytes == 1) { | ||
c *= (1 << 8) - 1; | ||
for (int xs = x; xs < x + b_w; xs++) | ||
((uint8_t *)line)[xs] = c; | ||
} else if (bytes == 2) { | ||
c *= (1 << 16) - 1; | ||
for (int xs = x; xs < x + b_w; xs++) | ||
((uint16_t *)line)[xs] = c; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return mpi; | ||
} | ||
|
||
static void dump_image(struct scale_test *stest, const char *name, | ||
struct mp_image *img) | ||
{ | ||
char *path = mp_tprintf(4096, "%s/%s.png", stest->ctx->out_path, name); | ||
|
||
struct image_writer_opts opts = image_writer_opts_defaults; | ||
opts.format = AV_CODEC_ID_PNG; | ||
|
||
if (!write_image(img, &opts, path, stest->ctx->global, stest->ctx->log)) { | ||
MP_FATAL(stest->ctx, "Failed to write '%s'.\n", path); | ||
abort(); | ||
} | ||
} | ||
|
||
// Compare 2 images (same format and size) for exact pixel data match. | ||
// Does generally not work with formats that include undefined padding. | ||
// Does not work with non-byte aligned formats. | ||
static void assert_imgs_equal(struct scale_test *stest, FILE *f, | ||
struct mp_image *ref, struct mp_image *new) | ||
{ | ||
assert(ref->imgfmt == new->imgfmt); | ||
assert(ref->w == new->w); | ||
assert(ref->h == new->h); | ||
|
||
assert(ref->fmt.flags & MP_IMGFLAG_BYTE_ALIGNED); | ||
assert(ref->fmt.bytes[0]); | ||
|
||
for (int p = 0; p < ref->num_planes; p++) { | ||
for (int y = 0; y < ref->h; y++) { | ||
void *line_r = ref->planes[p] + ref->stride[p] * (ptrdiff_t)y; | ||
void *line_o = new->planes[p] + new->stride[p] * (ptrdiff_t)y; | ||
size_t size = ref->fmt.bytes[p] * (size_t)new->w; | ||
|
||
bool ok = memcmp(line_r, line_o, size) == 0; | ||
if (!ok) { | ||
stest->fail += 1; | ||
char *fn_a = mp_tprintf(80, "img%d_ref", stest->fail); | ||
char *fn_b = mp_tprintf(80, "img%d_new", stest->fail); | ||
fprintf(f, "Images mismatching, dumping to %s/%s\n", fn_a, fn_b); | ||
dump_image(stest, fn_a, ref); | ||
dump_image(stest, fn_b, new); | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
|
||
void repack_test_run(struct scale_test *stest) | ||
{ | ||
char *logname = mp_tprintf(80, "%s.log", stest->test_name); | ||
FILE *f = test_open_out(stest->ctx, logname); | ||
|
||
if (!stest->sws) { | ||
init_imgfmts_list(); | ||
|
||
stest->sws = mp_sws_alloc(stest); | ||
|
||
stest->img_repack_rgb8 = gen_repack_test_img(256, 128, 1, true, false); | ||
stest->img_repack_rgba8 = gen_repack_test_img(256, 128, 1, true, true); | ||
stest->img_repack_rgb16 = gen_repack_test_img(256, 128, 2, true, false); | ||
stest->img_repack_rgba16 = gen_repack_test_img(256, 128, 2, true, true); | ||
|
||
talloc_steal(stest, stest->img_repack_rgb8); | ||
talloc_steal(stest, stest->img_repack_rgba8); | ||
talloc_steal(stest, stest->img_repack_rgb16); | ||
talloc_steal(stest, stest->img_repack_rgba16); | ||
} | ||
|
||
for (int a = 0; a < num_imgfmts; a++) { | ||
int mpfmt = imgfmts[a]; | ||
struct mp_imgfmt_desc fmtdesc = mp_imgfmt_get_desc(mpfmt); | ||
if (!fmtdesc.id || !(fmtdesc.flags & MP_IMGFLAG_RGB) || | ||
!fmtdesc.component_bits || (fmtdesc.component_bits % 8) || | ||
fmtdesc.num_planes > 1) | ||
continue; | ||
|
||
struct mp_image *test_img = NULL; | ||
bool alpha = fmtdesc.flags & MP_IMGFLAG_ALPHA; | ||
bool hidepth = fmtdesc.component_bits > 8; | ||
if (alpha) { | ||
test_img = hidepth ? stest->img_repack_rgba16 : stest->img_repack_rgba8; | ||
} else { | ||
test_img = hidepth ? stest->img_repack_rgb16 : stest->img_repack_rgb8; | ||
} | ||
|
||
if (test_img->imgfmt == mpfmt) | ||
continue; | ||
|
||
if (!stest->fns->supports_fmts(stest->fns_priv, mpfmt, test_img->imgfmt)) | ||
continue; | ||
|
||
if (!mp_sws_supports_formats(stest->sws, mpfmt, test_img->imgfmt)) | ||
continue; | ||
|
||
fprintf(f, "%s using %s\n", mp_imgfmt_to_name(mpfmt), | ||
mp_imgfmt_to_name(test_img->imgfmt)); | ||
|
||
struct mp_image *dst = mp_image_alloc(mpfmt, test_img->w, test_img->h); | ||
assert(dst); | ||
|
||
// This tests packing. | ||
bool ok = stest->fns->scale(stest->fns_priv, dst, test_img); | ||
assert(ok); | ||
|
||
// Cross-check with swscale in the other direction. | ||
// (Mostly so we don't have to worry about padding.) | ||
struct mp_image *src2 = | ||
mp_image_alloc(test_img->imgfmt, test_img->w, test_img->h); | ||
assert(src2); | ||
ok = mp_sws_scale(stest->sws, src2, dst) >= 0; | ||
assert_imgs_equal(stest, f, test_img, src2); | ||
|
||
// Assume the other conversion direction also works. | ||
assert(stest->fns->supports_fmts(stest->fns_priv, test_img->imgfmt, mpfmt)); | ||
|
||
struct mp_image *back = mp_image_alloc(test_img->imgfmt, dst->w, dst->h); | ||
assert(back); | ||
|
||
// This tests unpacking. | ||
ok = stest->fns->scale(stest->fns_priv, back, dst); | ||
assert(ok); | ||
|
||
assert_imgs_equal(stest, f, test_img, back); | ||
|
||
talloc_free(back); | ||
talloc_free(src2); | ||
talloc_free(dst); | ||
} | ||
|
||
fclose(f); | ||
|
||
assert_text_files_equal(stest->ctx, logname, logname, | ||
"This can fail if FFmpeg adds or removes pixfmts."); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#pragma once | ||
|
||
#include "tests.h" | ||
#include "video/mp_image.h" | ||
|
||
struct scale_test_fns { | ||
bool (*scale)(void *ctx, struct mp_image *dst, struct mp_image *src); | ||
bool (*supports_fmts)(void *ctx, int imgfmt_dst, int imgfmt_src); | ||
}; | ||
|
||
struct scale_test { | ||
// To be filled in by user. | ||
const struct scale_test_fns *fns; | ||
void *fns_priv; | ||
const char *test_name; | ||
struct test_ctx *ctx; | ||
|
||
// Private. | ||
struct mp_image *img_repack_rgb8; | ||
struct mp_image *img_repack_rgba8; | ||
struct mp_image *img_repack_rgb16; | ||
struct mp_image *img_repack_rgba16; | ||
struct mp_sws_context *sws; | ||
int fail; | ||
}; | ||
|
||
// Test color repacking between packed formats (typically RGB). | ||
void repack_test_run(struct scale_test *stest); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#include "scale_test.h" | ||
#include "video/zimg.h" | ||
|
||
static bool scale(void *pctx, struct mp_image *dst, struct mp_image *src) | ||
{ | ||
struct mp_zimg_context *ctx = pctx; | ||
return mp_zimg_convert(ctx, dst, src); | ||
} | ||
|
||
static bool supports_fmts(void *pctx, int imgfmt_dst, int imgfmt_src) | ||
{ | ||
return mp_zimg_supports_in_format(imgfmt_src) && | ||
mp_zimg_supports_out_format(imgfmt_dst); | ||
} | ||
|
||
static const struct scale_test_fns fns = { | ||
.scale = scale, | ||
.supports_fmts = supports_fmts, | ||
}; | ||
|
||
static void run(struct test_ctx *ctx) | ||
{ | ||
struct mp_zimg_context *zimg = mp_zimg_alloc(); | ||
|
||
struct scale_test *stest = talloc_zero(NULL, struct scale_test); | ||
stest->fns = &fns; | ||
stest->fns_priv = zimg; | ||
stest->test_name = "repack_zimg"; | ||
stest->ctx = ctx; | ||
|
||
repack_test_run(stest); | ||
|
||
talloc_free(stest); | ||
talloc_free(zimg); | ||
} | ||
|
||
const struct unittest test_repack_zimg = { | ||
.name = "repack_zimg", | ||
.run = run, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.