summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2020-04-13 20:05:38 +0200
committerwm4 <wm4@nowhere>2020-04-13 20:05:38 +0200
commitafedaf3b61287b43b5ee4123b94b1ffcd7a506d4 (patch)
tree4312e68d06b006c29903f2dcb7f38a84628716fc /video
parent30855638df313fd2d13739107c2ed39935a52eb3 (diff)
downloadmpv-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.c112
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))