This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit d4b9b94ccb43a4f84a0748f2965e700fbcc6b54b Author: Niklas Haas <[email protected]> AuthorDate: Sat Jun 20 11:21:51 2026 +0200 Commit: Niklas Haas <[email protected]> CommitDate: Sat Jun 20 14:08:49 2026 +0000 swscale/format: add support for AV_PIX_FMT_PAL8 This is handled using the new SWS_RW_PALETTE read op mode. We need to be a bit careful to use the correct pixfmt descriptor downstream, because the descriptor for PAL8 itself merely describes the *index*, rather than the actual data values. Accomplish this by introducing a new function to map the palette format to the resulting pixel format after applying the palette (explicitly documented as AV_PIX_FMT_RGB32). +pal8 16x16 -> rgb24 16x16: + [ u8 +++X] SWS_OP_READ : 4 elem(s) palette >> 0 + min: {0 0 0 _}, max: {255 255 255 _} + [ u8 +++X] SWS_OP_SWIZZLE : 2103 + min: {0 0 0 _}, max: {255 255 255 _} + [ u8 XXXX] SWS_OP_WRITE : 3 elem(s) packed >> 0 + (X = unused, z = byteswapped, + = exact, 0 = zero) + translated micro-ops: + u8_read_palette_xyzw + u8_permute_xz_zx + u8_write_packed_xyz ... Sponsored-by: Sovereign Tech Fund Signed-off-by: Niklas Haas <[email protected]> --- libswscale/format.c | 61 +++++++++++++++++++++++++++++++++------------ libswscale/uops_macros.h | 6 +++-- tests/ref/fate/sws-ops-list | 2 +- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/libswscale/format.c b/libswscale/format.c index 48eee12696..a424bb2cfc 100644 --- a/libswscale/format.c +++ b/libswscale/format.c @@ -681,10 +681,24 @@ void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src) #if CONFIG_UNSTABLE +/** + * Returns the underlying descriptor for fake formats like PAL8 whose + * descriptors alone do not fully describe the pixel data. + */ +static inline const AVPixFmtDescriptor *fmt_desc_decoded(enum AVPixelFormat fmt) +{ + if (fmt == AV_PIX_FMT_PAL8) + return av_pix_fmt_desc_get(AV_PIX_FMT_RGB32); + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + av_assert0(!(desc->flags & AV_PIX_FMT_FLAG_PAL)); + return desc; +} + /* Returns the type suitable for a pixel after fully decoding/unpacking it */ static SwsPixelType fmt_pixel_type(enum AVPixelFormat fmt) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt); const int bits = FFALIGN(desc->comp[0].depth, 8); if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { switch (bits) { @@ -824,6 +838,18 @@ static FmtInfo fmt_info_irregular(enum AVPixelFormat fmt) case AV_PIX_FMT_XV48LE: case AV_PIX_FMT_XV48BE: return PACKED_FMT(UYVA, 4); + + /* Miscellaneous irregular formats */ + case AV_PIX_FMT_PAL8: + return (FmtInfo) { + .rw = { .elems = 4, .mode = SWS_RW_PALETTE }, + /* PAL8 is explicitly defined as endian-dependent */ + #if AV_HAVE_BIGENDIAN + .swizzle = ARGB, + #else + .swizzle = BGRA, + #endif + }; } return (FmtInfo) {0}; @@ -965,8 +991,9 @@ static void swizzle_inv(SwsSwizzleOp *swiz) */ static SwsClearOp fmt_clear(const SwsFormat *fmt) { - const bool has_chroma = fmt->desc->nb_components >= 3; - const bool has_alpha = fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA; + const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format); + const bool has_chroma = desc->nb_components >= 3; + const bool has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA; SwsClearOp c = {0}; if (!has_chroma) { @@ -990,7 +1017,7 @@ static SwsClearOp fmt_clear(const SwsFormat *fmt) int ff_sws_decode_pixfmt(SwsOpList *ops, const SwsFormat *fmt) { - const AVPixFmtDescriptor *desc = fmt->desc; + const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format); SwsPixelType pixel_type, raw_type; SwsReadWriteOp rw_op; SwsSwizzleOp swizzle; @@ -1079,7 +1106,7 @@ int ff_sws_decode_pixfmt(SwsOpList *ops, const SwsFormat *fmt) int ff_sws_encode_pixfmt(SwsOpList *ops, const SwsFormat *fmt) { - const AVPixFmtDescriptor *desc = fmt->desc; + const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format); SwsPixelType pixel_type, raw_type; SwsReadWriteOp rw_op; SwsSwizzleOp swizzle; @@ -1162,23 +1189,24 @@ static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) { Q0, Q0, Q0, Q1, Q0 }, }}; - const int depth0 = fmt->desc->comp[0].depth; - const int depth1 = fmt->desc->comp[1].depth; - const int depth2 = fmt->desc->comp[2].depth; - const int depth3 = fmt->desc->comp[3].depth; + const AVPixFmtDescriptor *desc = fmt_desc_decoded(fmt->format); + const int depth0 = desc->comp[0].depth; + const int depth1 = desc->comp[1].depth; + const int depth2 = desc->comp[2].depth; + const int depth3 = desc->comp[3].depth; - if (fmt->desc->flags & AV_PIX_FMT_FLAG_FLOAT) + if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) return c; /* floats are directly output as-is */ av_assert0(depth0 < 32 && depth1 < 32 && depth2 < 32 && depth3 < 32); - if (fmt->csp == AVCOL_SPC_RGB || (fmt->desc->flags & AV_PIX_FMT_FLAG_XYZ)) { + if (fmt->csp == AVCOL_SPC_RGB || (desc->flags & AV_PIX_FMT_FLAG_XYZ)) { c.m[0][0] = Q((1 << depth0) - 1); c.m[1][1] = Q((1 << depth1) - 1); c.m[2][2] = Q((1 << depth2) - 1); } else if (fmt->range == AVCOL_RANGE_JPEG) { /* Full range YUV */ c.m[0][0] = Q((1 << depth0) - 1); - if (fmt->desc->nb_components >= 3) { + if (desc->nb_components >= 3) { /* This follows the ITU-R convention, which is slightly different * from the JFIF convention. */ c.m[1][1] = Q((1 << depth1) - 1); @@ -1192,7 +1220,7 @@ static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) *incomplete = true; c.m[0][0] = Q(219 << (depth0 - 8)); c.m[0][4] = Q( 16 << (depth0 - 8)); - if (fmt->desc->nb_components >= 3) { + if (desc->nb_components >= 3) { c.m[1][1] = Q(224 << (depth1 - 8)); c.m[2][2] = Q(224 << (depth2 - 8)); c.m[1][4] = Q(128 << (depth1 - 8)); @@ -1200,8 +1228,8 @@ static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) } } - if (fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA) { - const bool is_ya = fmt->desc->nb_components == 2; + if (desc->flags & AV_PIX_FMT_FLAG_ALPHA) { + const bool is_ya = desc->nb_components == 2; c.m[3][3] = Q((1 << (is_ya ? depth1 : depth3)) - 1); } @@ -1351,7 +1379,8 @@ static int fmt_dither(SwsContext *ctx, SwsOpList *ops, dither.y_offset[i] = offsets_16x16[i]; } - if (src->desc->nb_components < 3 && bpc >= 8) { + const AVPixFmtDescriptor *src_desc = fmt_desc_decoded(src->format); + if (src_desc->nb_components < 3 && bpc >= 8) { /** * For high-bit-depth sources without chroma, use same matrix * offset for all color channels. This prevents introducing color diff --git a/libswscale/uops_macros.h b/libswscale/uops_macros.h index 9166a72850..2c88870a66 100644 --- a/libswscale/uops_macros.h +++ b/libswscale/uops_macros.h @@ -75,8 +75,10 @@ MACRO(__VA_ARGS__, u8_read_bit_x , SWS_PIXEL_U8 , SWS_UOP_READ_BIT , 0x1) #define SWS_FOR_STRUCT_U8_READ_BIT(MACRO, ...) \ MACRO(__VA_ARGS__, u8_read_bit_x , .type = SWS_PIXEL_U8 , .uop = SWS_UOP_READ_BIT , .mask = 0x1) -#define SWS_FOR_U8_READ_PALETTE(MACRO, ...) -#define SWS_FOR_STRUCT_U8_READ_PALETTE(MACRO, ...) +#define SWS_FOR_U8_READ_PALETTE(MACRO, ...) \ + MACRO(__VA_ARGS__, u8_read_palette_xyzw , SWS_PIXEL_U8 , SWS_UOP_READ_PALETTE , 0xf) +#define SWS_FOR_STRUCT_U8_READ_PALETTE(MACRO, ...) \ + MACRO(__VA_ARGS__, u8_read_palette_xyzw , .type = SWS_PIXEL_U8 , .uop = SWS_UOP_READ_PALETTE , .mask = 0xf) #define SWS_FOR_U8_WRITE_PLANAR(MACRO, ...) \ MACRO(__VA_ARGS__, u8_write_planar_x , SWS_PIXEL_U8 , SWS_UOP_WRITE_PLANAR , 0x1) \ MACRO(__VA_ARGS__, u8_write_planar_xy , SWS_PIXEL_U8 , SWS_UOP_WRITE_PLANAR , 0x3) \ diff --git a/tests/ref/fate/sws-ops-list b/tests/ref/fate/sws-ops-list index d47e674bec..f5ed4c676d 100644 --- a/tests/ref/fate/sws-ops-list +++ b/tests/ref/fate/sws-ops-list @@ -1 +1 @@ -a5779f7e6e5f6a56d8150261343369ac +31a9d8a35355bed66e8c64dda5246828 _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
