diff options
author | wm4 <wm4@nowhere> | 2020-04-13 20:05:38 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2020-04-13 20:05:38 +0200 |
commit | afedaf3b61287b43b5ee4123b94b1ffcd7a506d4 (patch) | |
tree | 4312e68d06b006c29903f2dcb7f38a84628716fc /video | |
parent | 30855638df313fd2d13739107c2ed39935a52eb3 (diff) | |
download | mpv-afedaf3b61287b43b5ee4123b94b1ffcd7a506d4.tar.bz2 mpv-afedaf3b61287b43b5ee4123b94b1ffcd7a506d4.tar.xz |
zimg: add packed YUV bullshit
Just lazily tested.
The comment on AV_PIX_FMT_Y210LE seems to be wrong. It claims it's "like
YUYV422", bit it seems more like YVYU422, at last the way libswscale
input treats it. Maybe Intel pays its developers too much?
The repacker inner lop is probably rather inefficient. In theory we
could optimize it by reading the packed pixels as words, doing the
component reshuffling using compile time values etc., but I'd rather
keep the code size small. It's already bad enough that we have to
support 16 bit per component variants, just because this one Intel guy
couldn't keep it in his pants. In general, I can't be bothered to spend
time on optimizing it; I'm only doing this for fun (i.e. masochistic
obligation).
Diffstat (limited to 'video')
-rw-r--r-- | video/zimg.c | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/video/zimg.c b/video/zimg.c index 1a0c4e3b0b..951cf2c907 100644 --- a/video/zimg.c +++ b/video/zimg.c @@ -101,8 +101,9 @@ struct mp_zimg_repack { // unpack: p1 is src, p2 is dst void (*packed_repack_scanline)(void *p1, void *p2[], int x0, int x1); - // Fringe RGB. + // Fringe RGB/YUV. uint8_t comp_size; + uint8_t *comp_map; uint8_t comp_shifts[3]; uint8_t *comp_lut; // 256 * 3 @@ -585,6 +586,75 @@ static int unpack_pal(void *user, unsigned i, unsigned x0, unsigned x1) return 0; } +struct fringe_yuv422_repacker { + // To avoid making a mess of IMGFMT_*, we use av formats directly. + enum AVPixelFormat avfmt; + // In bits (depth/8 rounded up gives byte size) + int8_t depth; + // Word index of each sample: {y0, y1, cr, cb} + uint8_t comp[4]; + bool be; +}; + +static const struct fringe_yuv422_repacker fringe_yuv422_repackers[] = { + {AV_PIX_FMT_YUYV422, 8, {0, 2, 3, 1}}, + {AV_PIX_FMT_UYVY422, 8, {1, 3, 2, 0}}, + {AV_PIX_FMT_YVYU422, 8, {0, 2, 1, 3}}, + {AV_PIX_FMT_Y210LE, 10, {0, 2, 1, 3}}, + {AV_PIX_FMT_Y210BE, 10, {0, 2, 1, 3}, .be = true}, +}; + +#define PA_P422(name, comp_t) \ + static void name(void *dst, void *src[], int x0, int x1, uint8_t *c) { \ + for (int x = x0; x < x1; x += 2) { \ + ((comp_t *)dst)[x * 2 + c[0]] = ((comp_t *)src[0])[x + 0]; \ + ((comp_t *)dst)[x * 2 + c[1]] = ((comp_t *)src[0])[x + 1]; \ + ((comp_t *)dst)[x * 2 + c[2]] = ((comp_t *)src[1])[x >> 1]; \ + ((comp_t *)dst)[x * 2 + c[3]] = ((comp_t *)src[2])[x >> 1]; \ + } \ + } + + +#define UN_P422(name, comp_t) \ + static void name(void *src, void *dst[], int x0, int x1, uint8_t *c) { \ + for (int x = x0; x < x1; x += 2) { \ + ((comp_t *)dst[0])[x + 0] = ((comp_t *)src)[x * 2 + c[0]]; \ + ((comp_t *)dst[0])[x + 1] = ((comp_t *)src)[x * 2 + c[1]]; \ + ((comp_t *)dst[1])[x >> 1] = ((comp_t *)src)[x * 2 + c[2]]; \ + ((comp_t *)dst[2])[x >> 1] = ((comp_t *)src)[x * 2 + c[3]]; \ + } \ + } + +PA_P422(pa_p422_8, uint8_t) +PA_P422(pa_p422_16, uint16_t) +UN_P422(un_p422_8, uint8_t) +UN_P422(un_p422_16, uint16_t) + +static int fringe_yuv422_repack(void *user, unsigned i, unsigned x0, unsigned x1) +{ + struct mp_zimg_repack *r = user; + + void *p1 = r->mpi->planes[0] + r->mpi->stride[0] * (ptrdiff_t)(i - r->mpi_y0); + + void *p2[4] = {0}; + for (int p = 0; p < r->num_planes; p++) { + p2[p] = r->tmp->planes[p] + + r->tmp->stride[p] * (ptrdiff_t)(i & r->zmask[p]); + } + + assert(r->comp_size == 1 || r->comp_size == 2); + + void (*repack)(void *p1, void *p2[], int x0, int x1, uint8_t *c) = NULL; + if (r->pack) { + repack = r->comp_size == 1 ? pa_p422_8 : pa_p422_16; + } else { + repack = r->comp_size == 1 ? un_p422_8 : un_p422_16; + } + repack(p1, p2, x0, x1, r->comp_map); + + return 0; +} + static int repack_nv(void *user, unsigned i, unsigned x0, unsigned x1) { struct mp_zimg_repack *r = user; @@ -758,6 +828,44 @@ static void setup_fringe_rgb_packer(struct mp_zimg_repack *r, } } +static void setup_fringe_yuv422_packer(struct mp_zimg_repack *r) +{ + enum AVPixelFormat avfmt = imgfmt2pixfmt(r->zimgfmt); + + const struct fringe_yuv422_repacker *fmt = NULL; + for (int n = 0; n < MP_ARRAY_SIZE(fringe_yuv422_repackers); n++) { + if (fringe_yuv422_repackers[n].avfmt == avfmt) { + fmt = &fringe_yuv422_repackers[n]; + break; + } + } + + if (!fmt) + return; + + r->comp_size = (fmt->depth + 7) / 8; + assert(r->comp_size == 1 || r->comp_size == 2); + + struct mp_regular_imgfmt yuvfmt = { + .component_type = MP_COMPONENT_TYPE_UINT, + // NB: same problem with P010 and not clearing padding. + .component_size = r->comp_size, + .num_planes = 3, + .planes = { {1, {1}}, {1, {2}}, {1, {3}} }, + .chroma_w = 2, + .chroma_h = 1, + }; + r->zimgfmt = mp_find_regular_imgfmt(&yuvfmt); + r->repack = fringe_yuv422_repack; + r->comp_map = (uint8_t *)fmt->comp; + + if (fmt->be) { + assert(r->comp_size == 2); + r->endian_size = 2; + r->endian_items[0] = 4; + } +} + static void setup_nv_packer(struct mp_zimg_repack *r) { struct mp_regular_imgfmt desc; @@ -954,6 +1062,8 @@ static bool setup_format_ne(zimg_image_format *zfmt, struct mp_zimg_repack *r, setup_regular_rgb_packer(r); if (!r->repack) setup_fringe_rgb_packer(r, ctx); + if (!r->repack) + setup_fringe_yuv422_packer(r); struct mp_regular_imgfmt desc; if (!mp_get_regular_imgfmt(&desc, r->zimgfmt)) |