[FFmpeg-devel] [PATCH] swscale/unscaled: add pal8 -> gbr(a)p special converter
Niklas Haas
ffmpeg at haasn.xyz
Fri Dec 20 12:58:59 EET 2024
On Thu, 19 Dec 2024 22:34:05 -0300 James Almer <jamrial at gmail.com> wrote:
> On 12/18/2024 11:24 AM, Niklas Haas wrote:
> > From: Niklas Haas <git at haasn.dev>
> >
> > Fixes: ticket #9520
> > Signed-off-by: Niklas Haas <git at haasn.dev>
> > Sponsored-by: Sovereign Tech Fund
> > ---
> > libswscale/swscale.c | 2 +
> > libswscale/swscale_unscaled.c | 81 ++++++++++++++++++++++++++++++++++-
> > 2 files changed, 81 insertions(+), 2 deletions(-)
> >
> > diff --git a/libswscale/swscale.c b/libswscale/swscale.c
> > index 96634acfd6..bd5b6370db 100644
> > --- a/libswscale/swscale.c
> > +++ b/libswscale/swscale.c
> > @@ -910,6 +910,8 @@ void ff_update_palette(SwsInternal *c, const uint32_t *pal)
> > case AV_PIX_FMT_BGR32_1:
> > #if HAVE_BIGENDIAN
> > case AV_PIX_FMT_BGR24:
> > + case AV_PIX_FMT_BGRP:
> > + case AV_PIX_FMT_BGRAP:
>
> These don't exist. And GBRP/GBRAP would need c->pal_rgb to be ordered in
> a different way.
Simply fixing BGRP -> GBRP should make it work; in theory.
>
> > #endif
> > c->pal_rgb[i]= a + (r<<8) + (g<<16) + ((unsigned)b<<24);
> > break;
> > diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c
> > index c7ad6b014a..973ffe0299 100644
> > --- a/libswscale/swscale_unscaled.c
> > +++ b/libswscale/swscale_unscaled.c
> > @@ -509,6 +509,34 @@ static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels,
> > }
> > }
> >
> > +static void gray8aToPlanar8(const uint8_t *src, uint8_t *dstG, uint8_t *dstB,
> > + uint8_t *dstR, uint8_t *dstA, int num_pixels,
> > + const uint8_t *palette)
> > +{
> > + for (int i = 0; i < num_pixels; i++) {
> > + const uint8_t *rgb = &palette[src[i << 1] * 4];
> > + dstB[i] = rgb[0];
> > + dstG[i] = rgb[1];
> > + dstR[i] = rgb[2];
> > + if (dstA)
> > + dstA[i] = src[(i << 1) + 1];
> > + }
> > +}
> > +
> > +static void pal8ToPlanar8(const uint8_t *src, uint8_t *dstG, uint8_t *dstB,
> > + uint8_t *dstR, uint8_t *dstA, int num_pixels,
> > + const uint8_t *palette)
> > +{
> > + for (int i = 0; i < num_pixels; i++) {
> > + const uint8_t *rgba = &palette[src[i] * 4];
>
> Does this work in both big and little endian? c->pal_rgb is uint32_t,
> and ff_update_palette() sets it in a native endian way.
Yes. For little endian, we hit the default branch:
c->pal_rgb[i]= b + (g<<8) + (r<<16) + ((unsigned)a<<24);
And this is also the order that pal8ToPlanar8 accesses the values in. But in
retrospect, I find this a bit confusing. I'll change it to use GBRA order
instead, matching the plane order.
> > + dstB[i] = rgba[0];
> > + dstG[i] = rgba[1];
> > + dstR[i] = rgba[2];
> > + if (dstA)
> > + dstA[i] = rgba[3];
> > + }
> > +}
> > +
> > static int bswap_16bpc(SwsInternal *c, const uint8_t *const src[],
> > const int srcStride[], int srcSliceY, int srcSliceH,
> > uint8_t *const dst[], const int dstStride[])
> > @@ -610,6 +638,45 @@ static int palToRgbWrapper(SwsInternal *c, const uint8_t *const src[], const int
> > return srcSliceH;
> > }
> >
> > +static int palToGbrpWrapper(SwsInternal *c, const uint8_t *const src[],
> > + const int srcStride[], int srcSliceY, int srcSliceH,
> > + uint8_t *const dst[], const int dstStride[])
> > +{
> > + const enum AVPixelFormat srcFormat = c->opts.src_format;
> > + const enum AVPixelFormat dstFormat = c->opts.dst_format;
> > + void (*conv)(const uint8_t *src, uint8_t *dstG, uint8_t *dstB, uint8_t *dstR,
> > + uint8_t *dstA, int num_pixels, const uint8_t *palette) = NULL;
> > +
> > + const int num_planes = isALPHA(dstFormat) ? 4 : 3;
> > + const uint8_t *srcPtr = src[0];
> > + uint8_t *dstPtr[4] = {0};
> > + for (int i = 0; i < num_planes; i++)
> > + dstPtr[i] = dst[i] + dstStride[i] * srcSliceY;
> > +
> > + if (srcFormat == AV_PIX_FMT_YA8) {
> > + switch (dstFormat) {
> > + case AV_PIX_FMT_GBRP: conv = gray8aToPlanar8; break;
> > + case AV_PIX_FMT_GBRAP: conv = gray8aToPlanar8; break;
> > + }
> > + } else if (usePal(srcFormat)) {
> > + switch (dstFormat) {
> > + case AV_PIX_FMT_GBRP: conv = pal8ToPlanar8; break;
> > + case AV_PIX_FMT_GBRAP: conv = pal8ToPlanar8; break;
> > + }
> > + }
> > +
> > + av_assert1(conv);
> > + for (int y = 0; y < srcSliceH; y++) {
> > + conv(srcPtr, dstPtr[0], dstPtr[1], dstPtr[2], dstPtr[3], c->opts.src_w,
> > + (uint8_t *) c->pal_rgb);
> > + srcPtr += srcStride[0];
> > + for (int i = 0; i < num_planes; i++)
> > + dstPtr[i] += dstStride[i];
> > + }
> > +
> > + return srcSliceH;
> > +}
> > +
> > static void packed16togbra16(const uint8_t *src, int srcStride,
> > uint16_t *dst[], const int dstStride[], int srcSliceH,
> > int src_alpha, int swap, int shift, int width)
> > @@ -2529,8 +2596,18 @@ void ff_get_unscaled_swscale(SwsInternal *c)
> > IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAPF32))
> > c->convert_unscaled = bswap_32bpc;
> >
> > - if (usePal(srcFormat) && isByteRGB(dstFormat))
> > - c->convert_unscaled = palToRgbWrapper;
> > + if (usePal(srcFormat)) {
> > + switch (dstFormat) {
> > + case AV_PIX_FMT_GBRP:
> > + case AV_PIX_FMT_GBRAP:
> > + c->convert_unscaled = palToGbrpWrapper;
> > + break;
> > + default:
> > + if (isByteRGB(dstFormat))
> > + c->convert_unscaled = palToRgbWrapper;
> > + break;
> > + }
> > + }
> >
> > if (srcFormat == AV_PIX_FMT_YUV422P) {
> > if (dstFormat == AV_PIX_FMT_YUYV422)
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
More information about the ffmpeg-devel
mailing list