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).
This commit is contained in:
wm4 2020-04-13 20:05:38 +02:00
parent 30855638df
commit afedaf3b61
2 changed files with 116 additions and 6 deletions

View File

@ -107,7 +107,7 @@
rgba Zin Zout SWSin SWSout |
rgba64 Zin Zout SWSin SWSout |
rgba64be Zin Zout SWSin SWSout |
uyvy422 SWSin SWSout |
uyvy422 Zin Zout SWSin SWSout |
uyyvyy411 |
vaapi |
vaapi_idct |
@ -119,8 +119,8 @@
xvmc |
xyz12 Zin Zout SWSin SWSout |
xyz12be Zin Zout SWSin SWSout |
y210 SWSin |
y210be |
y210 Zin Zout SWSin |
y210be Zin Zout |
ya16 Zin Zout SWSin SWSout |
ya16be Zin Zout SWSin SWSout |
ya8 Zin Zout SWSin SWSout |
@ -194,5 +194,5 @@
yuvj411p Zin Zout SWSin SWSout |
yuvj422p Zin Zout SWSin SWSout |
yuvj440p Zin Zout SWSin SWSout |
yuyv422 SWSin SWSout |
yvyu422 SWSin SWSout |
yuyv422 Zin Zout SWSin SWSout |
yvyu422 Zin Zout SWSin SWSout |

View File

@ -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))