Files
Jun Zhao 7afd90fa95 lavf: add ASTC and KTX 1.0 muxers/demuxers
Add single-image ASTC and KTX 1.0 muxers and demuxers for the
libastcenc codec. Validate the KTX layout, ASTC dimensions, color profile,
and compressed payload boundaries before exposing a packet to the decoder.

Map the KTX 1.0 2D linear and sRGB ASTC formats to the corresponding
libastcenc profiles, and reject unsupported HDR, 3D, array, cubemap, and
mipmap layouts instead of producing ambiguous image streams.

The KTX demuxer turns the KTXorientation key into display metadata, and the
KTX muxer writes the key back, so a stream copied from a flipped texture
keeps its row order. Its srgb option follows the encoder's color profile by
default, and an explicit value that contradicts a known profile is rejected
instead of silently relabelling the texture.

Signed-off-by: Jun Zhao <barryjzhao@tencent.com>
2026-09-14 12:44:07 +00:00

87 lines
2.7 KiB
C

/*
* ASTC muxer (.astc container)
* Copyright (c) 2026 Jun Zhao
*
* 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
*/
/**
* @file
* ASTC (Adaptive Scalable Texture Compression) muxer.
*
* The .astc container is a 16-byte header followed by the raw ASTC
* bitstream. The header is taken verbatim from the encoder's extradata
* (which it publishes in .astc form).
*/
#include "avformat.h"
#include "avio.h"
#include "mux.h"
#define ASTC_HEADER_SIZE 16
typedef struct ASTCMuxerContext {
int wrote_image;
} ASTCMuxerContext;
static int astc_write_header(AVFormatContext *s)
{
AVStream *st = s->streams[0];
if (st->codecpar->extradata_size < ASTC_HEADER_SIZE) {
av_log(s, AV_LOG_ERROR, ".astc muxer requires 16-byte extradata "
"(block size / dimensions) from the encoder.\n");
return AVERROR(EINVAL);
}
avio_write(s->pb, st->codecpar->extradata, ASTC_HEADER_SIZE);
return 0;
}
static int astc_write_packet(AVFormatContext *s, AVPacket *pkt)
{
ASTCMuxerContext *ctx = s->priv_data;
/* The container holds a single image; FF_OFMT_FLAG_MAX_ONE_OF_EACH only
* limits the number of streams, so packets must be rejected here. */
if (ctx->wrote_image) {
av_log(s, AV_LOG_ERROR,
".astc muxer supports a single image per file.\n");
return AVERROR(EINVAL);
}
ctx->wrote_image = 1;
avio_write(s->pb, pkt->data, pkt->size);
return 0;
}
const FFOutputFormat ff_astc_muxer = {
.p.name = "astc",
.p.long_name = NULL_IF_CONFIG_SMALL("ASTC (Adaptive Scalable Texture Compression)"),
.p.mime_type = "image/astc",
.p.extensions = "astc",
.p.audio_codec = AV_CODEC_ID_NONE,
.p.video_codec = AV_CODEC_ID_ASTC,
.p.subtitle_codec = AV_CODEC_ID_NONE,
.flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH |
FF_OFMT_FLAG_ONLY_DEFAULT_CODECS,
.priv_data_size = sizeof(ASTCMuxerContext),
.write_header = astc_write_header,
.write_packet = astc_write_packet,
.p.flags = AVFMT_NOTIMESTAMPS,
};