This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 9a71d6a6407478898c8e7cb497e034b0ee83fdf0 Author: Jun Zhao <[email protected]> AuthorDate: Sat Sep 12 12:39:45 2026 +0800 Commit: Jun Zhao <[email protected]> CommitDate: Mon Sep 14 12:44:07 2026 +0000 fate: add ASTC LDR/HDR round-trip and container tests Add self-contained FATE coverage for ASTC LDR, HDR, profile mismatch, 3D-block, and ASTC/KTX container paths. Exercise both KTX color profiles and inspect the generated KTX enum and single-mipmap header fields directly so the test does not rely solely on FFmpeg's matching demuxer. Cover the KTX linear default as well: the linear GL internal format says nothing about the endpoint formats the blocks use, so a linear texture carrying HDR endpoints has to decode like an explicit -dec_profile hdr-ldr-a request instead of coming back as the magenta mismatch colour. Declare the lavfi, filter, codec, muxer, and demuxer dependencies used by each test, and keep generated negative-test files in the FATE cleanup set. The HDR test hashes frames converted to the explicitly little-endian gbrapf32le, so its bytewise output does not depend on the host endianness. Signed-off-by: Jun Zhao <[email protected]> --- tests/Makefile | 1 + tests/api/Makefile | 1 + tests/api/api-astc-profile-test.c | 307 +++++++++++++++++++++++++++++++ tests/fate/api.mak | 4 + tests/fate/astc.mak | 157 ++++++++++++++++ tests/ref/fate/api-astc-profile | 11 ++ tests/ref/fate/astc-3d | 8 + tests/ref/fate/astc-hdr | 8 + tests/ref/fate/astc-hdr-native | 8 + tests/ref/fate/astc-hdr-profile-mismatch | 8 + tests/ref/fate/astc-ktx | 8 + tests/ref/fate/astc-ktx-header | 6 + tests/ref/fate/astc-ktx-linear-hdr | 2 + tests/ref/fate/astc-ldr | 8 + 14 files changed, 537 insertions(+) diff --git a/tests/Makefile b/tests/Makefile index 43c34ee253..bd83c8df91 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -185,6 +185,7 @@ include $(SRC_PATH)/tests/fate/dvvideo.mak include $(SRC_PATH)/tests/fate/ea.mak include $(SRC_PATH)/tests/fate/exif.mak include $(SRC_PATH)/tests/fate/enc_external.mak +include $(SRC_PATH)/tests/fate/astc.mak # Must be included after lavf-video.mak include $(SRC_PATH)/tests/fate/ffmpeg.mak include $(SRC_PATH)/tests/fate/ffprobe.mak diff --git a/tests/api/Makefile b/tests/api/Makefile index a590fe49fe..953325f89d 100644 --- a/tests/api/Makefile +++ b/tests/api/Makefile @@ -1,3 +1,4 @@ +APITESTPROGS-$(call ALLYES, LIBASTCENC_ENCODER LIBASTCENC_DECODER) += api-astc-profile APITESTPROGS-$(call ENCDEC, FLAC, FLAC) += api-flac APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264 APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264-slice diff --git a/tests/api/api-astc-profile-test.c b/tests/api/api-astc-profile-test.c new file mode 100644 index 0000000000..cea54f0b59 --- /dev/null +++ b/tests/api/api-astc-profile-test.c @@ -0,0 +1,307 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * ASTC profile test. + * + * Encodes a constant-colour image through AVCodecContext.profile, the path a + * command line cannot reach because the encoder's private "profile" option + * takes precedence there, and prints the profile the encoder resolved + * together with the decoded result. The interesting part is an out-of-range + * (HDR) alpha: only AV_PROFILE_ASTC_HDR can carry it, so a request that is + * silently substituted for another profile shows up as a decoded value of 1.0 + * instead of 2.5. + * + * The decoded values are constant-colour blocks, so they are exact and do not + * depend on the astcenc version the way a compressed-payload hash would. + */ + +#include <stdio.h> + +#include "libavcodec/avcodec.h" +#include "libavcodec/defs.h" +#include "libavutil/common.h" +#include "libavutil/error.h" +#include "libavutil/intfloat.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" + +#define SIZE 16 + +/* The names of the packed float formats carry a host endianness suffix, so + * print the canonical name instead to keep the reference endian-independent. */ +static const char *fmt_label(enum AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_RGBA: return "rgba"; + case AV_PIX_FMT_RGBAF32: return "rgbaf32"; + case AV_PIX_FMT_RGBAF16: return "rgbaf16"; + default: return "unexpected"; + } +} + +/* Convert an IEEE-754 binary16 value held in a native uint16_t to a float. + * The decoder output is native-endian, so going through a float keeps the + * printed value independent of the host byte order. */ +static float half_to_float(uint16_t h) +{ + uint32_t sign = (uint32_t)(h & 0x8000u) << 16; + uint32_t exp = (h & 0x7C00u) >> 10; + uint32_t mant = h & 0x03FFu; + uint32_t f; + + if (exp == 0x1F) { /* infinity or NaN */ + f = 0x7F800000u | (mant << 13); + } else if (exp == 0) { /* zero or subnormal */ + if (!mant) + return av_int2float(sign); + exp = 1; + while (!(mant & 0x0400u)) { + mant <<= 1; + exp--; + } + mant &= 0x03FFu; + f = ((uint32_t)(exp + 112) << 23) | (mant << 13); + } else { + f = ((exp + 112) << 23) | (mant << 13); + } + + return av_int2float(f | sign); +} + +static int fill_frame(const AVFrame *frame) +{ + int y, x; + + for (y = 0; y < frame->height; y++) { + if (frame->format == AV_PIX_FMT_RGBA) { + uint8_t *row = frame->data[0] + (size_t)y * frame->linesize[0]; + for (x = 0; x < frame->width; x++) { + row[4 * x + 0] = 0x80; + row[4 * x + 1] = 0x80; + row[4 * x + 2] = 0x80; + row[4 * x + 3] = 0xff; + } + } else if (frame->format == AV_PIX_FMT_RGBAF32) { + float *row = (float *)(frame->data[0] + (size_t)y * frame->linesize[0]); + for (x = 0; x < frame->width; x++) { + row[4 * x + 0] = 2.5f; + row[4 * x + 1] = 2.5f; + row[4 * x + 2] = 2.5f; + row[4 * x + 3] = 2.5f; + } + } else { + return AVERROR(EINVAL); + } + } + + return 0; +} + +static void print_texel(const AVFrame *frame) +{ + const uint8_t *rgba; + const uint16_t *half; + + if (frame->format == AV_PIX_FMT_RGBA) { + rgba = frame->data[0]; + printf("decoded %s: 0x%02x 0x%02x 0x%02x 0x%02x", + fmt_label(frame->format), + rgba[0], rgba[1], rgba[2], rgba[3]); + } else if (frame->format == AV_PIX_FMT_RGBAF16) { + half = (const uint16_t *)frame->data[0]; + printf("decoded %s: %.3f %.3f %.3f %.3f", + fmt_label(frame->format), + half_to_float(half[0]), half_to_float(half[1]), + half_to_float(half[2]), half_to_float(half[3])); + } else { + printf("decoded %s: unexpected format", + fmt_label(frame->format)); + } +} + +static int run_case(const AVCodec *enc, const AVCodec *dec, + int req_profile, enum AVPixelFormat pix_fmt, + const char *priv_profile, int dec_profile) +{ + AVCodecContext *enc_ctx = NULL, *dec_ctx = NULL; + AVDictionary *opts = NULL; + AVFrame *in_frame = NULL, *out_frame = NULL; + AVPacket *pkt = NULL; + int ret; + + printf("requested profile %d", req_profile); + if (priv_profile) + printf(", private profile %s", priv_profile); + printf(", input %s -> ", fmt_label(pix_fmt)); + + enc_ctx = avcodec_alloc_context3(enc); + if (!enc_ctx) + return AVERROR(ENOMEM); + enc_ctx->width = SIZE; + enc_ctx->height = SIZE; + enc_ctx->time_base = (AVRational){ 1, 1 }; + enc_ctx->pix_fmt = pix_fmt; + enc_ctx->profile = req_profile; + if (priv_profile) + av_dict_set(&opts, "profile", priv_profile, 0); + + ret = avcodec_open2(enc_ctx, enc, &opts); + av_dict_free(&opts); + if (ret < 0) { + /* Record the actual result; FATE checks it against the reference. */ + printf("open failed: %s\n", av_err2str(ret)); + ret = 0; + goto fail; + } + printf("resolved profile %d, ", enc_ctx->profile); + + in_frame = av_frame_alloc(); + if (!in_frame) { + ret = AVERROR(ENOMEM); + goto fail; + } + in_frame->format = pix_fmt; + in_frame->width = SIZE; + in_frame->height = SIZE; + ret = av_frame_get_buffer(in_frame, 0); + if (ret < 0) + goto fail; + ret = fill_frame(in_frame); + if (ret < 0) + goto fail; + + pkt = av_packet_alloc(); + if (!pkt) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = avcodec_send_frame(enc_ctx, in_frame); + if (ret < 0) + goto fail; + ret = avcodec_receive_packet(enc_ctx, pkt); + if (ret < 0) + goto fail; + + /* The decoder needs the .astc header the encoder published as extradata, + * and the profile the container would have recorded. */ + dec_ctx = avcodec_alloc_context3(dec); + if (!dec_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + dec_ctx->profile = dec_profile; + if (enc_ctx->extradata_size) { + dec_ctx->extradata = av_mallocz(enc_ctx->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dec_ctx->extradata) { + ret = AVERROR(ENOMEM); + goto fail; + } + memcpy(dec_ctx->extradata, enc_ctx->extradata, enc_ctx->extradata_size); + dec_ctx->extradata_size = enc_ctx->extradata_size; + } + ret = avcodec_open2(dec_ctx, dec, NULL); + if (ret < 0) { + printf("decoder open failed: %s (UNEXPECTED)\n", av_err2str(ret)); + goto fail; + } + + out_frame = av_frame_alloc(); + if (!out_frame) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = avcodec_send_packet(dec_ctx, pkt); + if (ret < 0) { + printf("send packet failed: %s (UNEXPECTED)\n", av_err2str(ret)); + goto fail; + } + ret = avcodec_receive_frame(dec_ctx, out_frame); + if (ret < 0) { + printf("receive frame failed: %s (UNEXPECTED)\n", av_err2str(ret)); + goto fail; + } + + print_texel(out_frame); + printf("\n"); + ret = 0; + +fail: + av_frame_free(&in_frame); + av_frame_free(&out_frame); + av_packet_free(&pkt); + avcodec_free_context(&dec_ctx); + avcodec_free_context(&enc_ctx); + return ret; +} + +int main(void) +{ + const AVCodec *enc, *dec; + int ret, i; + + struct { + int req_profile; + enum AVPixelFormat pix_fmt; + const char *priv_profile; + int dec_profile; + } cases[] = { + /* AV_PROFILE_UNKNOWN keeps the documented default. */ + { AV_PROFILE_UNKNOWN, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_UNKNOWN }, + { AV_PROFILE_ASTC_LDR_SRGB, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_ASTC_LDR_SRGB }, + { AV_PROFILE_ASTC_LDR, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_ASTC_LDR }, + /* An HDR profile cannot be driven by 8-bit input. */ + { AV_PROFILE_ASTC_HDR_RGB_LDR_A, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_ASTC_HDR_RGB_LDR_A }, + { AV_PROFILE_ASTC_HDR, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_ASTC_HDR }, + /* LINEAR_ANY is stream metadata, not an encoding profile. */ + { AV_PROFILE_ASTC_LINEAR_ANY, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_ASTC_LINEAR_ANY }, + /* Only full HDR keeps an out-of-range alpha; hdr-ldr-a clamps it. */ + { AV_PROFILE_ASTC_HDR, AV_PIX_FMT_RGBAF32, NULL, AV_PROFILE_ASTC_HDR }, + { AV_PROFILE_ASTC_HDR_RGB_LDR_A, AV_PIX_FMT_RGBAF32, NULL, AV_PROFILE_ASTC_HDR_RGB_LDR_A }, + /* LDR input is auto-promoted, so it loses the HDR alpha as well. */ + { AV_PROFILE_ASTC_LDR, AV_PIX_FMT_RGBAF32, NULL, AV_PROFILE_ASTC_HDR_RGB_LDR_A }, + /* An explicit private option overrides the public field. */ + { AV_PROFILE_ASTC_HDR, AV_PIX_FMT_RGBAF32, "hdr-ldr-a", AV_PROFILE_ASTC_HDR_RGB_LDR_A }, + /* Same payload decoded as a linear texture: LINEAR_ANY samples it + * with HDR precision, so the output is half-float. */ + { AV_PROFILE_ASTC_LDR_SRGB, AV_PIX_FMT_RGBA, NULL, AV_PROFILE_ASTC_LINEAR_ANY }, + }; + + enc = avcodec_find_encoder(AV_CODEC_ID_ASTC); + if (!enc) { + av_log(NULL, AV_LOG_ERROR, "Can't find encoder\n"); + return 1; + } + dec = avcodec_find_decoder(AV_CODEC_ID_ASTC); + if (!dec) { + av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n"); + return 1; + } + + for (i = 0; i < FF_ARRAY_ELEMS(cases); i++) { + ret = run_case(enc, dec, cases[i].req_profile, cases[i].pix_fmt, + cases[i].priv_profile, cases[i].dec_profile); + if (ret < 0) + return 1; + } + + return 0; +} diff --git a/tests/fate/api.mak b/tests/fate/api.mak index 4c0f51c4fc..a740db1f0a 100644 --- a/tests/fate/api.mak +++ b/tests/fate/api.mak @@ -1,3 +1,7 @@ +FATE_API_LIBAVCODEC-$(call ALLYES, LIBASTCENC_ENCODER LIBASTCENC_DECODER) += fate-api-astc-profile +fate-api-astc-profile: $(APITESTSDIR)/api-astc-profile-test$(EXESUF) +fate-api-astc-profile: CMD = run $(APITESTSDIR)/api-astc-profile-test$(EXESUF) + FATE_API_LIBAVCODEC-$(call ENCDEC, FLAC, FLAC) += fate-api-flac fate-api-flac: $(APITESTSDIR)/api-flac-test$(EXESUF) fate-api-flac: CMD = run $(APITESTSDIR)/api-flac-test$(EXESUF) diff --git a/tests/fate/astc.mak b/tests/fate/astc.mak new file mode 100644 index 0000000000..665043e56a --- /dev/null +++ b/tests/fate/astc.mak @@ -0,0 +1,157 @@ +# ASTC (Adaptive Scalable Texture Compression) codec + container tests. +# +# Input is the self-generated "testsrc" lavfi source. astcenc compression is +# fully deterministic, so encode -> container -> decode can be locked down with +# framecrc/md5 with no external sample files required. +# +# The codec is single-image, but the lavfi sources are *infinite*, so every +# test caps the encode to a single frame with -frames:v 1 (otherwise the encode +# step would never reach EOF and the test would hang). +# +# testsrc is native rgb24, so no pixel-format conversion is needed under +# FATE's -noauto_conversion_filters. For the HDR path the graph explicitly +# requests format=gbrapf32: swscale cannot convert *to* packed half/float +# (rgbaf16/rgbaf32) but it CAN produce planar float (gbrapf32), which the +# encoder also accepts as HDR input and auto-promotes to HDR_RGB_LDR_A. + +# LDR round-trip through the raw .astc container. +FATE_ASTC-$(call TRANSCODE, LIBASTCENC, ASTC, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER) += fate-astc-ldr +fate-astc-ldr: CMD = transcode lavfi "testsrc=size=128x128" astc \ + "-c:v libastcenc -block_size 8x8 -frames:v 1" "" "" "" "" "" + +# LDR round-trip through the KTX 1.0 container (HDR output is not implemented +# by the KTX muxer, see the negative test below). The linear GL enum only fixes +# the colour space, so the decoder samples a linear texture with HDR precision +# by default; -dec_profile ldr pins this test to the 8-bit LDR path. +FATE_ASTC-$(call TRANSCODE, LIBASTCENC, KTX, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER) += fate-astc-ktx +fate-astc-ktx: CMD = transcode lavfi "testsrc=size=128x128" ktx \ + "-c:v libastcenc -block_size 8x8 -profile:v ldr -frames:v 1 -srgb 0" "" "" "" "-dec_profile ldr" "" + +# Check the KTX enum and single-level header fields directly rather than only +# through the FFmpeg KTX demuxer, which could mirror the muxer's mistake. +FATE_ASTC-$(call ENCMUX, LIBASTCENC, KTX, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER FILE_PROTOCOL) += fate-astc-ktx-header +fate-astc-ktx-header: CMD = \ + cleanfiles="$${cleanfiles} $${outfile}.linear.ktx $${outfile}.srgb.ktx"; \ + linear="$$(target_path "$${outfile}.linear.ktx")"; \ + srgb="$$(target_path "$${outfile}.srgb.ktx")"; \ + read_le32() { \ + od -An -tx1 -j "$$2" -N 4 "$$1" | tr -d "[:space:]"; \ + }; \ + ffmpeg -f lavfi -i "testsrc=size=16x16" -frames:v 1 -c:v libastcenc -block_size 8x8 -profile:v ldr -srgb 0 \ + -f ktx -y "$$linear" && \ + ffmpeg -f lavfi -i "testsrc=size=16x16" -frames:v 1 -c:v libastcenc -block_size 8x8 -profile:v ldr-srgb -srgb 1 \ + -f ktx -y "$$srgb" && \ + printf "linear glInternalFormat: " && read_le32 "$${outfile}.linear.ktx" 28 && printf "\n" && \ + printf "linear faces: " && read_le32 "$${outfile}.linear.ktx" 52 && printf "\n" && \ + printf "linear mipmap levels: " && read_le32 "$${outfile}.linear.ktx" 56 && printf "\n" && \ + printf "srgb glInternalFormat: " && read_le32 "$${outfile}.srgb.ktx" 28 && printf "\n" && \ + printf "srgb faces: " && read_le32 "$${outfile}.srgb.ktx" 52 && printf "\n" && \ + printf "srgb mipmap levels: " && read_le32 "$${outfile}.srgb.ktx" 56 && printf "\n" + +# The KTX linear GL enum fixes the colour space but not the endpoint format, so a +# linear texture may hold HDR endpoints and must be sampled with HDR precision by +# default: inferring LDR from the enum makes astcenc return its magenta +# profile-mismatch colour for the RGB=2.5 payload used here. Decoding without +# -dec_profile has to match an explicit -dec_profile hdr-ldr-a decode (which +# yields 2.5, 2.5, 2.5, 1.0) and differ from an explicit LDR decode. +# +# The KTX file is produced by remuxing the .astc stream: a raw .astc carries no +# profile, so the KTX muxer writes the linear format the test needs. +FATE_ASTC-$(call ENCMUX, LIBASTCENC, KTX, LAVFI_INDEV WRAPPED_AVFRAME_DECODER \ + TESTSRC2_FILTER FORMAT_FILTER SCALE_FILTER GEQ_FILTER \ + FILE_PROTOCOL RAWVIDEO_MUXER RAWVIDEO_ENCODER \ + LIBASTCENC_DECODER \ + ASTC_MUXER ASTC_DEMUXER KTX_DEMUXER) += fate-astc-ktx-linear-hdr +fate-astc-ktx-linear-hdr: CMD = \ + cleanfiles="$${cleanfiles} $${outfile}.astc $${outfile}.ktx $${outfile}.raw $${outfile}.hdr.raw $${outfile}.ldr.raw"; \ + enc="$$(target_path "$${outfile}.astc")"; \ + ktx="$$(target_path "$${outfile}.ktx")"; \ + ffmpeg -f lavfi -i "testsrc2=size=64x64,format=gbrapf32,geq=r=2.5:g=2.5:b=2.5:a=1" \ + -frames:v 1 -c:v libastcenc -block_size 8x8 -profile:v hdr-ldr-a \ + -f astc -y "$$enc" && \ + ffmpeg -i "$$enc" -c copy -srgb linear -f ktx -y "$$ktx" && \ + ffmpeg -i "$$ktx" -frames:v 1 -f rawvideo -y "$$(target_path "$${outfile}.raw")" && \ + ffmpeg -dec_profile hdr-ldr-a -i "$$ktx" -frames:v 1 -f rawvideo \ + -y "$$(target_path "$${outfile}.hdr.raw")" && \ + ffmpeg -dec_profile ldr -i "$$ktx" -frames:v 1 -f rawvideo \ + -y "$$(target_path "$${outfile}.ldr.raw")" && \ + printf "linear KTX default decode vs explicit hdr-ldr-a: " && \ + { cmp -s "$${outfile}.raw" "$${outfile}.hdr.raw" && echo "identical" || echo "DIFFERENT"; } && \ + printf "linear KTX default decode vs explicit ldr: " && \ + { cmp -s "$${outfile}.raw" "$${outfile}.ldr.raw" && echo "identical" || echo "different"; } + +# HDR round-trip: float/half input auto-promotes the profile to +# HDR_RGB_LDR_A; the decoder receives the profile through -dec_profile and +# emits rgbaf16 (no 8-bit clamp). Verifies the HDR encode/decode chain end to end. +# +# Note: swscale cannot convert *to* packed half/float (rgbaf16/rgbaf32), +# but it CAN produce planar float (gbrapf32le), which the encoder also accepts +# as a valid HDR input. testsrc -> gbrapf32 exercises the float path. +# +# The decoded rgbaf16 frames are converted to the explicitly little-endian +# gbrapf32le before hashing, so the bytewise FATE output does not depend on +# the endianness of the host that runs the test. FATE disables automatic +# filter insertion, so the scaler is named explicitly. That conversion clamps +# to [0, 1] while this source's HDR decode overshoots above it, so the hash +# locks the bitstream, the output precision and the in-range values; the +# region above 1.0 is locked by fate-astc-hdr-native below. +FATE_ASTC-$(call TRANSCODE, LIBASTCENC, ASTC, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER FORMAT_FILTER SCALE_FILTER) += fate-astc-hdr +fate-astc-hdr: CMD = transcode lavfi "testsrc=size=128x128,format=gbrapf32" astc \ + "-c:v libastcenc -block_size 8x8 -frames:v 1" "-vf scale,format=gbrapf32le" "" "" "-dec_profile hdr-ldr-a" "" + +# The value hash above cannot see the HDR region: it hashes through a +# conversion that clamps to [0, 1], while this source decodes to values up to +# 4.0. Hash the decoder's native rgbaf16 output instead, on little-endian +# hosts, where native order is already defined. A big-endian host would hash +# the same samples in the other byte order, so the test is limited to the +# little-endian case rather than becoming endian dependent. +ifneq ($(HAVE_BIGENDIAN),yes) +FATE_ASTC-$(call TRANSCODE, LIBASTCENC, ASTC, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER FORMAT_FILTER SCALE_FILTER) += fate-astc-hdr-native +fate-astc-hdr-native: CMD = transcode lavfi "testsrc=size=128x128,format=gbrapf32" astc \ + "-c:v libastcenc -block_size 8x8 -frames:v 1" "" "" "" "-dec_profile hdr-ldr-a" "" +endif + +# HDR profile mismatch: ASTC bitstreams do not carry a profile field, so if +# the decoder is asked to decode HDR-encoded endpoints with the (default) +# LDR profile, astcenc's endpoint unpacking intentionally returns a fixed +# magenta error color (0xFF, 0x00, 0xFF) rather than garbage or a decode +# failure -- this is astcenc's own defined behavior for a profile mismatch, +# confirmed against the astcenc reference CLI decoding the same bitstream +# with the wrong profile flag. Locking down the magenta output as a +# regression test ensures our decoder keeps propagating this signal instead +# of silently misinterpreting HDR data as LDR. +# +# The source pixel value (2.5) is genuinely out of the LDR [0,1] range so +# the encoder is forced to use HDR endpoint formats; decoding those with +# the LDR profile is what triggers the magenta error path. +FATE_ASTC-$(call TRANSCODE, LIBASTCENC, ASTC, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC2_FILTER FORMAT_FILTER SCALE_FILTER GEQ_FILTER) += fate-astc-hdr-profile-mismatch +fate-astc-hdr-profile-mismatch: CMD = transcode lavfi \ + "testsrc2=size=64x64,format=gbrapf32,geq=r=2.5:g=2.5:b=2.5:a=1" astc \ + "-c:v libastcenc -block_size 8x8 -profile:v hdr-ldr-a -frames:v 1" "" "" "" "" "" + +# 3D block round-trip: a 3D block size (4x4x4) compresses a 2D image using +# three-dimensional partition patterns. The block_z value is carried in the +# .astc header and mirrored by the decoder. +FATE_ASTC-$(call TRANSCODE, LIBASTCENC, ASTC, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER) += fate-astc-3d +fate-astc-3d: CMD = transcode lavfi "testsrc=size=64x64" astc \ + "-c:v libastcenc -block_size 4x4x4 -frames:v 1" "" "" "" "" "" + +# Negative test: writing HDR to KTX is not implemented, so feeding HDR +# (float/half) input to the .ktx muxer must be rejected with AVERROR(EINVAL) +# and the specific "Writing HDR ASTC to KTX 1.0 is not supported" message. +# The command asserts the non-zero exit status, and CMP = grep asserts the +# diagnostic. +FATE_ASTC-$(call ENCMUX, LIBASTCENC, KTX, LAVFI_INDEV WRAPPED_AVFRAME_DECODER TESTSRC_FILTER FORMAT_FILTER SCALE_FILTER FILE_PROTOCOL) += fate-astc-ktx-hdr-reject +fate-astc-ktx-hdr-reject: CMP = grep +fate-astc-ktx-hdr-reject: REF = Writing HDR ASTC to KTX 1.0 is not supported +fate-astc-ktx-hdr-reject: CMD = \ + cleanfiles="$${cleanfiles} $${outfile}.ktx"; \ + ffmpeg -y -f lavfi -i "testsrc=size=128x128,format=gbrapf32" \ + -threads 1 -c:v libastcenc -block_size 8x8 -frames:v 1 \ + -f ktx "$$(target_path "$${outfile}.ktx")" ; \ + test $$? -ne 0 + +FATE_ASTC += $(FATE_ASTC-yes) +fate-astc: $(FATE_ASTC-yes) + +FATE_FFMPEG += $(FATE_ASTC) diff --git a/tests/ref/fate/api-astc-profile b/tests/ref/fate/api-astc-profile new file mode 100644 index 0000000000..818f1bccf8 --- /dev/null +++ b/tests/ref/fate/api-astc-profile @@ -0,0 +1,11 @@ +requested profile -99, input rgba -> resolved profile 1, decoded rgba: 0x80 0x80 0x80 0xff +requested profile 1, input rgba -> resolved profile 1, decoded rgba: 0x80 0x80 0x80 0xff +requested profile 2, input rgba -> resolved profile 2, decoded rgba: 0x80 0x80 0x80 0xff +requested profile 3, input rgba -> open failed: Invalid argument +requested profile 4, input rgba -> open failed: Invalid argument +requested profile 5, input rgba -> open failed: Invalid argument +requested profile 4, input rgbaf32 -> resolved profile 4, decoded rgbaf16: 2.500 2.500 2.500 2.500 +requested profile 3, input rgbaf32 -> resolved profile 3, decoded rgbaf16: 2.500 2.500 2.500 1.000 +requested profile 2, input rgbaf32 -> resolved profile 3, decoded rgbaf16: 2.500 2.500 2.500 1.000 +requested profile 4, private profile hdr-ldr-a, input rgbaf32 -> resolved profile 3, decoded rgbaf16: 2.500 2.500 2.500 1.000 +requested profile 1, input rgba -> resolved profile 1, decoded rgbaf16: 0.502 0.502 0.502 1.000 diff --git a/tests/ref/fate/astc-3d b/tests/ref/fate/astc-3d new file mode 100644 index 0000000000..fd2efb7ca3 --- /dev/null +++ b/tests/ref/fate/astc-3d @@ -0,0 +1,8 @@ +992ecc2713a9ca3e4f9a2a838ce91a7f *tests/data/fate/astc-3d.astc +4112 tests/data/fate/astc-3d.astc +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x64 +#sar 0: 0/1 +0, 0, 0, 1, 16384, 0x8e695e67 diff --git a/tests/ref/fate/astc-hdr b/tests/ref/fate/astc-hdr new file mode 100644 index 0000000000..1aea2bbcdd --- /dev/null +++ b/tests/ref/fate/astc-hdr @@ -0,0 +1,8 @@ +bf52e531c5700cd2039de30c0cdb7a22 *tests/data/fate/astc-hdr.astc +4112 tests/data/fate/astc-hdr.astc +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x128 +#sar 0: 0/1 +0, 0, 0, 1, 262144, 0xca65d360 diff --git a/tests/ref/fate/astc-hdr-native b/tests/ref/fate/astc-hdr-native new file mode 100644 index 0000000000..e770d8df9f --- /dev/null +++ b/tests/ref/fate/astc-hdr-native @@ -0,0 +1,8 @@ +bf52e531c5700cd2039de30c0cdb7a22 *tests/data/fate/astc-hdr-native.astc +4112 tests/data/fate/astc-hdr-native.astc +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x128 +#sar 0: 0/1 +0, 0, 0, 1, 131072, 0x55277a51 diff --git a/tests/ref/fate/astc-hdr-profile-mismatch b/tests/ref/fate/astc-hdr-profile-mismatch new file mode 100644 index 0000000000..754aadb05a --- /dev/null +++ b/tests/ref/fate/astc-hdr-profile-mismatch @@ -0,0 +1,8 @@ +4e488750dca715be36407f4ca18c0bed *tests/data/fate/astc-hdr-profile-mismatch.astc +1040 tests/data/fate/astc-hdr-profile-mismatch.astc +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x64 +#sar 0: 0/1 +0, 0, 0, 1, 16384, 0x9c27d2c1 diff --git a/tests/ref/fate/astc-ktx b/tests/ref/fate/astc-ktx new file mode 100644 index 0000000000..21dcdd8f1a --- /dev/null +++ b/tests/ref/fate/astc-ktx @@ -0,0 +1,8 @@ +fe8511ba3b5ed0aab64f4b5c47271bc1 *tests/data/fate/astc-ktx.ktx +4192 tests/data/fate/astc-ktx.ktx +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x128 +#sar 0: 0/1 +0, 0, 0, 1, 65536, 0xd37f6262 diff --git a/tests/ref/fate/astc-ktx-header b/tests/ref/fate/astc-ktx-header new file mode 100644 index 0000000000..2d3edeabc9 --- /dev/null +++ b/tests/ref/fate/astc-ktx-header @@ -0,0 +1,6 @@ +linear glInternalFormat: b7930000 +linear faces: 01000000 +linear mipmap levels: 01000000 +srgb glInternalFormat: d7930000 +srgb faces: 01000000 +srgb mipmap levels: 01000000 diff --git a/tests/ref/fate/astc-ktx-linear-hdr b/tests/ref/fate/astc-ktx-linear-hdr new file mode 100644 index 0000000000..f17d9d35a3 --- /dev/null +++ b/tests/ref/fate/astc-ktx-linear-hdr @@ -0,0 +1,2 @@ +linear KTX default decode vs explicit hdr-ldr-a: identical +linear KTX default decode vs explicit ldr: different diff --git a/tests/ref/fate/astc-ldr b/tests/ref/fate/astc-ldr new file mode 100644 index 0000000000..34e1054217 --- /dev/null +++ b/tests/ref/fate/astc-ldr @@ -0,0 +1,8 @@ +fa51c1a57dca4983debf4cc6b3a2c53b *tests/data/fate/astc-ldr.astc +4112 tests/data/fate/astc-ldr.astc +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x128 +#sar 0: 0/1 +0, 0, 0, 1, 65536, 0x08d2628c -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
