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]

Reply via email to