PR #25023 opened by Graham Vosloo (GrahamV) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25023 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25023.patch
# Summary of changes Two fixes for the DXV3 decoder, found while comparing its output with files written by Resolume Alley 7.28.1. Each commit adds FATE tests with small clips made by Alley. 1. avcodec/dxv: fix opcode limit for heights that are not multiples of 16 YCG6 and YG10 frames are padded to a multiple of 16 in both dimensions, and the opcode streams cover the padded area. The decoder computed the limit on the number of opcodes from the unpadded size, so files such as 1920x1080 failed to decode. The limit is now computed from the padded dimensions. 2. avcodec/dxv: do not unpremultiply DXT5 textures of DXV3 Alley stores straight (non-premultiplied) alpha in DXT5 textures of DXV3 and writes the colour unchanged, but the decoder treated them as premultiplied and divided the colour by the alpha. The older headerless flavour of the format is left as it was. Tested with `make fate` on AArch64 (macOS). Beyond FATE, the patched decoder was run over 102 files made by Alley (about 386,000 frames) without errors, and Normal Quality frames are unchanged. ```fate-samples dxv/dxv3-hqna-padded.mov dxv/dxv3-hqwa-padded.mov dxv/dxv3-nqwa-alpha.mov ```# Summary of changes >From fcd7732bdb865a9b741b8fc5ec809a8271abf22f Mon Sep 17 00:00:00 2001 From: Graham Vosloo <[email protected]> Date: Sun, 11 Oct 2026 13:28:10 -0400 Subject: [PATCH 1/2] avcodec/dxv: fix opcode limit for heights that are not multiples of 16 Resolume pads the textures of a frame to multiples of 16 pixels in both directions, and the YCG6 and YG10 formats can have one opcode for every block of the padded textures. The decoder only aligns the height to 4 and derives the maximum number of opcodes from that, so a 1920x1080 frame whose opcodes cover the 1088 padded lines is rejected as invalid as soon as nearly all of its blocks need an opcode, which happens with noisy or highly detailed content. Compute the limits from the padded dimensions instead. The textures themselves are still decoded up to the coded height only. Add tests with clips of 128x72 pixels made by Resolume Alley, which could not be decoded. Assisted-by: Claude Opus 5.5 Signed-off-by: Graham Vosloo <[email protected]> --- libavcodec/dxv.c | 12 ++++++++---- tests/fate/video.mak | 6 ++++++ tests/ref/fate/dxv3-ycg6-padded | 7 +++++++ tests/ref/fate/dxv3-yg10-padded | 7 +++++++ 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 tests/ref/fate/dxv3-ycg6-padded create mode 100644 tests/ref/fate/dxv3-yg10-padded diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index bae46cdee0..894308cc18 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -992,16 +992,20 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, memset(ctx->tex_data + old_size, 0, ctx->tex_data_size - old_size); if (avctx->pix_fmt != AV_PIX_FMT_RGBA) { + /* Resolume pads its textures to multiples of 16 pixels, and there + * can be one opcode for every block of the padded textures. */ + const int padded_size = FFALIGN(avctx->coded_width, 16) * + FFALIGN(avctx->coded_height, 16); int i; ctx->ctex_size = avctx->coded_width / 2 / ctexdsp_ctx.raw_ratio * avctx->coded_height / 2 / TEXTURE_BLOCK_H * ctexdsp_ctx.tex_ratio; - ctx->op_size[0] = avctx->coded_width * avctx->coded_height / 16; - ctx->op_size[1] = avctx->coded_width * avctx->coded_height / 32; - ctx->op_size[2] = avctx->coded_width * avctx->coded_height / 32; - ctx->op_size[3] = avctx->coded_width * avctx->coded_height / 16; + ctx->op_size[0] = padded_size / 16; + ctx->op_size[1] = padded_size / 32; + ctx->op_size[2] = padded_size / 32; + ctx->op_size[3] = padded_size / 16; old_size = ctx->ctex_data_size; ptr = av_fast_realloc(ctx->ctex_data, &ctx->ctex_data_size, ctx->ctex_size + AV_INPUT_BUFFER_PADDING_SIZE); diff --git a/tests/fate/video.mak b/tests/fate/video.mak index fa7b202052..e5811b7016 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -158,6 +158,12 @@ fate-dxv3-ycg6: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-hqna.mov FATE_DXV += fate-dxv3-yg10 fate-dxv3-yg10: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-hqwa.mov +FATE_DXV += fate-dxv3-ycg6-padded +fate-dxv3-ycg6-padded: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-hqna-padded.mov + +FATE_DXV += fate-dxv3-yg10-padded +fate-dxv3-yg10-padded: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-hqwa-padded.mov + FATE_VIDEO-$(call FRAMECRC, MOV, DXV) += $(FATE_DXV) fate-dxv: $(FATE_DXV) diff --git a/tests/ref/fate/dxv3-ycg6-padded b/tests/ref/fate/dxv3-ycg6-padded new file mode 100644 index 0000000000..8004ff9ab3 --- /dev/null +++ b/tests/ref/fate/dxv3-ycg6-padded @@ -0,0 +1,7 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x72 +#sar 0: 0/1 +0, 0, 0, 1, 13824, 0x7e856094 +0, 1, 1, 1, 13824, 0x1a73e899 diff --git a/tests/ref/fate/dxv3-yg10-padded b/tests/ref/fate/dxv3-yg10-padded new file mode 100644 index 0000000000..b31d3bfa11 --- /dev/null +++ b/tests/ref/fate/dxv3-yg10-padded @@ -0,0 +1,7 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x72 +#sar 0: 0/1 +0, 0, 0, 1, 23040, 0xdd903eb0 +0, 1, 1, 1, 23040, 0x4c7cc6b5 -- 2.52.0 >From 54a905b49979fb660a070ae36dd79b494d4a16fc Mon Sep 17 00:00:00 2001 From: Graham Vosloo <[email protected]> Date: Sun, 11 Oct 2026 13:28:10 -0400 Subject: [PATCH 2/2] avcodec/dxv: do not unpremultiply DXT5 textures of DXV3 The decoder assumed that the color of DXV3 DXT5 textures is premultiplied by alpha, and divided it by alpha. Resolume's encoder does not premultiply anything though: Resolume Alley 7.28.1 writes the color of a source with straight alpha into the texture unchanged, as can be seen by converting the same source with its "Normal Quality No Alpha" and "Normal Quality With Alpha" presets and comparing the textures. Dividing by alpha then blows the colors out wherever alpha is not 255. The YG10 format, which also has alpha, was already output as is. The FATE sample is fully opaque, so its reference does not change. The older, headerless DXT5 flavour is left alone as there is no encoder at hand to check it against. Add a test with a clip made by Resolume Alley whose alpha is not constant. Assisted-by: Claude Opus 5.5 Signed-off-by: Graham Vosloo <[email protected]> --- libavcodec/dxv.c | 5 +++-- tests/fate/video.mak | 3 +++ tests/ref/fate/dxv3-dxt5-alpha | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/ref/fate/dxv3-dxt5-alpha diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index 894308cc18..0b4b107d0e 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -879,8 +879,9 @@ static int dxv_decode(AVCodecContext *avctx, AVFrame *frame, break; case DXV_FMT_DXT5: decompress_tex = dxv_decompress_dxt5; - /* DXV misnomers DXT5, alpha is premultiplied so use DXT4 instead */ - texdsp_ctx.tex_funct = ctx->texdsp.dxt4_block; + /* Resolume stores the color of its input as is, whether its alpha + * is straight or premultiplied, so do not alter it either. */ + texdsp_ctx.tex_funct = ctx->texdsp.dxt5_block; texdsp_ctx.tex_ratio = 16; texdsp_ctx.raw_ratio = 16; msgcomp = "DXTR5"; diff --git a/tests/fate/video.mak b/tests/fate/video.mak index e5811b7016..c6c0d419ba 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -164,6 +164,9 @@ fate-dxv3-ycg6-padded: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-hqna-padded. FATE_DXV += fate-dxv3-yg10-padded fate-dxv3-yg10-padded: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-hqwa-padded.mov +FATE_DXV += fate-dxv3-dxt5-alpha +fate-dxv3-dxt5-alpha: CMD = framecrc -i $(TARGET_SAMPLES)/dxv/dxv3-nqwa-alpha.mov + FATE_VIDEO-$(call FRAMECRC, MOV, DXV) += $(FATE_DXV) fate-dxv: $(FATE_DXV) diff --git a/tests/ref/fate/dxv3-dxt5-alpha b/tests/ref/fate/dxv3-dxt5-alpha new file mode 100644 index 0000000000..bb4c72a720 --- /dev/null +++ b/tests/ref/fate/dxv3-dxt5-alpha @@ -0,0 +1,7 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x64 +#sar 0: 0/1 +0, 0, 0, 1, 32768, 0xaf2dca4e +0, 1, 1, 1, 32768, 0x9a90a39c -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
