From 7832204c99e78d021b6fbe1a6f996cc5c89fb054 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 13 Apr 2020 20:42:34 +0200 Subject: zimg: add support for 1 bit per pixel formats Again worthless, slow, and only for libswscale parity. With this, we support all formats libswscale supports, except bayer input, and rgb4/bgr4 output. We even support some formats libswscale doesn't. It's possible that the zimg wrapper isn't always as fast as libswscale. But there is optimization potential: the inner repack loops are self-contained enough that they could be reasonably be implemented in assembler (probably), and doing everything slice-wise should reduce the overhead of the separate pack/unpack stages. --- test/ref/zimg_formats.txt | 4 ++-- video/zimg.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/test/ref/zimg_formats.txt b/test/ref/zimg_formats.txt index ef5b650a3f..26d260a70e 100644 --- a/test/ref/zimg_formats.txt +++ b/test/ref/zimg_formats.txt @@ -74,8 +74,8 @@ grayf32be Zin Zout SWSin SWSout | mediacodec | mmal | - monob SWSin SWSout | - monow SWSin SWSout | + monob Zin Zout SWSin SWSout | + monow Zin Zout SWSin SWSout | nv12 Zin Zout SWSin SWSout | nv16 Zin Zout | nv20 Zin Zout | diff --git a/video/zimg.c b/video/zimg.c index 951cf2c907..cd68495831 100644 --- a/video/zimg.c +++ b/video/zimg.c @@ -90,6 +90,8 @@ struct mp_zimg_repack { // Output bit depth. If 0, use format defaults. (Used by some packets. This // is simpler than defining fringe planar RGB formats for each depth.) int override_depth; + // Hammer it into using ZIMG_COLOR_GREY. + bool override_gray; // Endian-swap (done before/after actual repacker). int endian_size; // 0=no swapping, 2/4=word byte size to swap @@ -561,6 +563,40 @@ static int fringe_rgb_repack(void *user, unsigned i, unsigned x0, unsigned x1) return 0; } +static int bitmap_repack(void *user, unsigned i, unsigned x0, unsigned x1) +{ + struct mp_zimg_repack *r = user; + + // Supposedly zimg aligns this at least on 64 byte boundaries. Simplifies a + // lot for us. + assert(!(x0 & 7)); + + uint8_t *p1 = + r->mpi->planes[0] + r->mpi->stride[0] * (ptrdiff_t)(i - r->mpi_y0); + uint8_t *p2 = + r->tmp->planes[0] + r->tmp->stride[0] * (ptrdiff_t)(i & r->zmask[0]); + + uint8_t swap = r->comp_size ? 0xFF : 0; + if (r->pack) { + for (int x = x0; x < x1; x += 8) { + uint8_t d = 0; + int max_b = MPMIN(8, x1 - x); + for (int b = 0; b < max_b; b++) + d |= (!!p2[x + b]) << (7 - b); + p1[x / 8] = d ^ swap; + } + } else { + for (int x = x0; x < x1; x += 8) { + uint8_t d = p1[x / 8] ^ swap; + int max_b = MPMIN(8, x1 - x); + for (int b = 0; b < max_b; b++) + p2[x + b] = !!(d & (1 << (7 - b))); + } + } + + return 0; +} + static int unpack_pal(void *user, unsigned i, unsigned x0, unsigned x1) { struct mp_zimg_repack *r = user; @@ -966,6 +1002,16 @@ static void setup_misc_packer(struct mp_zimg_repack *r) return; r->zimgfmt = grap_fmt; r->repack = unpack_pal; + } else { + enum AVPixelFormat avfmt = imgfmt2pixfmt(r->zimgfmt); + if (avfmt == AV_PIX_FMT_MONOWHITE || avfmt == AV_PIX_FMT_MONOBLACK) { + r->zimgfmt = IMGFMT_Y8; + r->repack = bitmap_repack; + r->override_depth = 1; + r->override_gray = true; + r->comp_size = avfmt == AV_PIX_FMT_MONOWHITE; // abuse to pass a flag + return; + } } } @@ -1169,6 +1215,12 @@ static bool setup_format_ne(zimg_image_format *zfmt, struct mp_zimg_repack *r, zfmt->color_primaries = mp_to_z_prim(fmt.color.primaries); zfmt->chroma_location = mp_to_z_chroma(fmt.chroma_location); + if (r->override_gray) { + zfmt->color_family = ZIMG_COLOR_GREY; + zfmt->pixel_range = ZIMG_RANGE_FULL; + zfmt->matrix_coefficients = ZIMG_MATRIX_BT470_BG; + } + if (ctx && ctx->opts.fast) { // mpv's default for RGB output slows down zimg significantly. if (zfmt->transfer_characteristics == ZIMG_TRANSFER_IEC_61966_2_1 && -- cgit v1.2.3