FFmpeg
Loading...
Searching...
No Matches
api-astc-profile-test.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19/*
20 * ASTC profile test.
21 *
22 * Encodes a constant-colour image through AVCodecContext.profile, the path a
23 * command line cannot reach because the encoder's private "profile" option
24 * takes precedence there, and prints the profile the encoder resolved
25 * together with the decoded result. The interesting part is an out-of-range
26 * (HDR) alpha: only AV_PROFILE_ASTC_HDR can carry it, so a request that is
27 * silently substituted for another profile shows up as a decoded value of 1.0
28 * instead of 2.5.
29 *
30 * The decoded values are constant-colour blocks, so they are exact and do not
31 * depend on the astcenc version the way a compressed-payload hash would.
32 */
33
34#include <stdio.h>
35
36#include "libavcodec/avcodec.h"
37#include "libavcodec/defs.h"
38#include "libavutil/common.h"
39#include "libavutil/error.h"
40#include "libavutil/intfloat.h"
41#include "libavutil/mem.h"
42#include "libavutil/pixdesc.h"
43
44#define SIZE 16
45
46/* The names of the packed float formats carry a host endianness suffix, so
47 * print the canonical name instead to keep the reference endian-independent. */
48static const char *fmt_label(enum AVPixelFormat pix_fmt)
49{
50 switch (pix_fmt) {
51 case AV_PIX_FMT_RGBA: return "rgba";
52 case AV_PIX_FMT_RGBAF32: return "rgbaf32";
53 case AV_PIX_FMT_RGBAF16: return "rgbaf16";
54 default: return "unexpected";
55 }
56}
57
58/* Convert an IEEE-754 binary16 value held in a native uint16_t to a float.
59 * The decoder output is native-endian, so going through a float keeps the
60 * printed value independent of the host byte order. */
61static float half_to_float(uint16_t h)
62{
63 uint32_t sign = (uint32_t)(h & 0x8000u) << 16;
64 uint32_t exp = (h & 0x7C00u) >> 10;
65 uint32_t mant = h & 0x03FFu;
66 uint32_t f;
67
68 if (exp == 0x1F) { /* infinity or NaN */
69 f = 0x7F800000u | (mant << 13);
70 } else if (exp == 0) { /* zero or subnormal */
71 if (!mant)
72 return av_int2float(sign);
73 exp = 1;
74 while (!(mant & 0x0400u)) {
75 mant <<= 1;
76 exp--;
77 }
78 mant &= 0x03FFu;
79 f = ((uint32_t)(exp + 112) << 23) | (mant << 13);
80 } else {
81 f = ((exp + 112) << 23) | (mant << 13);
82 }
83
84 return av_int2float(f | sign);
85}
86
87static int fill_frame(const AVFrame *frame)
88{
89 int y, x;
90
91 for (y = 0; y < frame->height; y++) {
92 if (frame->format == AV_PIX_FMT_RGBA) {
93 uint8_t *row = frame->data[0] + (size_t)y * frame->linesize[0];
94 for (x = 0; x < frame->width; x++) {
95 row[4 * x + 0] = 0x80;
96 row[4 * x + 1] = 0x80;
97 row[4 * x + 2] = 0x80;
98 row[4 * x + 3] = 0xff;
99 }
100 } else if (frame->format == AV_PIX_FMT_RGBAF32) {
101 float *row = (float *)(frame->data[0] + (size_t)y * frame->linesize[0]);
102 for (x = 0; x < frame->width; x++) {
103 row[4 * x + 0] = 2.5f;
104 row[4 * x + 1] = 2.5f;
105 row[4 * x + 2] = 2.5f;
106 row[4 * x + 3] = 2.5f;
107 }
108 } else {
109 return AVERROR(EINVAL);
110 }
111 }
112
113 return 0;
114}
115
116static void print_texel(const AVFrame *frame)
117{
118 const uint8_t *rgba;
119 const uint16_t *half;
120
121 if (frame->format == AV_PIX_FMT_RGBA) {
122 rgba = frame->data[0];
123 printf("decoded %s: 0x%02x 0x%02x 0x%02x 0x%02x",
124 fmt_label(frame->format),
125 rgba[0], rgba[1], rgba[2], rgba[3]);
126 } else if (frame->format == AV_PIX_FMT_RGBAF16) {
127 half = (const uint16_t *)frame->data[0];
128 printf("decoded %s: %.3f %.3f %.3f %.3f",
129 fmt_label(frame->format),
132 } else {
133 printf("decoded %s: unexpected format",
134 fmt_label(frame->format));
135 }
136}
137
138static int run_case(const AVCodec *enc, const AVCodec *dec,
139 int req_profile, enum AVPixelFormat pix_fmt,
140 const char *priv_profile, int dec_profile)
141{
142 AVCodecContext *enc_ctx = NULL, *dec_ctx = NULL;
144 AVFrame *in_frame = NULL, *out_frame = NULL;
145 AVPacket *pkt = NULL;
146 int ret;
147
148 printf("requested profile %d", req_profile);
149 if (priv_profile)
150 printf(", private profile %s", priv_profile);
151 printf(", input %s -> ", fmt_label(pix_fmt));
152
153 enc_ctx = avcodec_alloc_context3(enc);
154 if (!enc_ctx)
155 return AVERROR(ENOMEM);
156 enc_ctx->width = SIZE;
157 enc_ctx->height = SIZE;
158 enc_ctx->time_base = (AVRational){ 1, 1 };
159 enc_ctx->pix_fmt = pix_fmt;
160 enc_ctx->profile = req_profile;
161 if (priv_profile)
162 av_dict_set(&opts, "profile", priv_profile, 0);
163
164 ret = avcodec_open2(enc_ctx, enc, &opts);
166 if (ret < 0) {
167 /* Record the actual result; FATE checks it against the reference. */
168 printf("open failed: %s\n", av_err2str(ret));
169 ret = 0;
170 goto fail;
171 }
172 printf("resolved profile %d, ", enc_ctx->profile);
173
174 in_frame = av_frame_alloc();
175 if (!in_frame) {
176 ret = AVERROR(ENOMEM);
177 goto fail;
178 }
179 in_frame->format = pix_fmt;
180 in_frame->width = SIZE;
181 in_frame->height = SIZE;
182 ret = av_frame_get_buffer(in_frame, 0);
183 if (ret < 0)
184 goto fail;
185 ret = fill_frame(in_frame);
186 if (ret < 0)
187 goto fail;
188
190 if (!pkt) {
191 ret = AVERROR(ENOMEM);
192 goto fail;
193 }
194
195 ret = avcodec_send_frame(enc_ctx, in_frame);
196 if (ret < 0)
197 goto fail;
198 ret = avcodec_receive_packet(enc_ctx, pkt);
199 if (ret < 0)
200 goto fail;
201
202 /* The decoder needs the .astc header the encoder published as extradata,
203 * and the profile the container would have recorded. */
205 if (!dec_ctx) {
206 ret = AVERROR(ENOMEM);
207 goto fail;
208 }
209 dec_ctx->profile = dec_profile;
210 if (enc_ctx->extradata_size) {
211 dec_ctx->extradata = av_mallocz(enc_ctx->extradata_size +
213 if (!dec_ctx->extradata) {
214 ret = AVERROR(ENOMEM);
215 goto fail;
216 }
217 memcpy(dec_ctx->extradata, enc_ctx->extradata, enc_ctx->extradata_size);
218 dec_ctx->extradata_size = enc_ctx->extradata_size;
219 }
220 ret = avcodec_open2(dec_ctx, dec, NULL);
221 if (ret < 0) {
222 printf("decoder open failed: %s (UNEXPECTED)\n", av_err2str(ret));
223 goto fail;
224 }
225
226 out_frame = av_frame_alloc();
227 if (!out_frame) {
228 ret = AVERROR(ENOMEM);
229 goto fail;
230 }
231
233 if (ret < 0) {
234 printf("send packet failed: %s (UNEXPECTED)\n", av_err2str(ret));
235 goto fail;
236 }
237 ret = avcodec_receive_frame(dec_ctx, out_frame);
238 if (ret < 0) {
239 printf("receive frame failed: %s (UNEXPECTED)\n", av_err2str(ret));
240 goto fail;
241 }
242
243 print_texel(out_frame);
244 printf("\n");
245 ret = 0;
246
247fail:
248 av_frame_free(&in_frame);
249 av_frame_free(&out_frame);
252 avcodec_free_context(&enc_ctx);
253 return ret;
254}
255
256int main(void)
257{
258 const AVCodec *enc, *dec;
259 int ret, i;
260
261 struct {
262 int req_profile;
264 const char *priv_profile;
265 int dec_profile;
266 } cases[] = {
267 /* AV_PROFILE_UNKNOWN keeps the documented default. */
271 /* An HDR profile cannot be driven by 8-bit input. */
274 /* LINEAR_ANY is stream metadata, not an encoding profile. */
276 /* Only full HDR keeps an out-of-range alpha; hdr-ldr-a clamps it. */
279 /* LDR input is auto-promoted, so it loses the HDR alpha as well. */
281 /* An explicit private option overrides the public field. */
283 /* Same payload decoded as a linear texture: LINEAR_ANY samples it
284 * with HDR precision, so the output is half-float. */
286 };
287
289 if (!enc) {
290 av_log(NULL, AV_LOG_ERROR, "Can't find encoder\n");
291 return 1;
292 }
294 if (!dec) {
295 av_log(NULL, AV_LOG_ERROR, "Can't find decoder\n");
296 return 1;
297 }
298
299 for (i = 0; i < FF_ARRAY_ELEMS(cases); i++) {
300 ret = run_case(enc, dec, cases[i].req_profile, cases[i].pix_fmt,
301 cases[i].priv_profile, cases[i].dec_profile);
302 if (ret < 0)
303 return 1;
304 }
305
306 return 0;
307}
static int run_case(const AVCodec *enc, const AVCodec *dec, int req_profile, enum AVPixelFormat pix_fmt, const char *priv_profile, int dec_profile)
int main(void)
static void print_texel(const AVFrame *frame)
static const char * fmt_label(enum AVPixelFormat pix_fmt)
static float half_to_float(uint16_t h)
static int fill_frame(const AVFrame *frame)
static AVDictionary * opts
Libavcodec external API header.
#define SIZE
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define f(width, name)
Definition cbs_vp8.c:236
common internal and external API header
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
static AVCodecContext * dec_ctx
Misc types and constants that do not belong anywhere else.
#define AV_PROFILE_UNKNOWN
Definition defs.h:65
#define AV_PROFILE_ASTC_LDR
Linear LDR.
Definition defs.h:81
#define AV_PROFILE_ASTC_HDR
HDR RGB and alpha.
Definition defs.h:83
#define AV_PROFILE_ASTC_HDR_RGB_LDR_A
HDR RGB with LDR alpha.
Definition defs.h:82
#define AV_PROFILE_ASTC_LDR_SRGB
sRGB LDR.
Definition defs.h:80
#define AV_PROFILE_ASTC_LINEAR_ANY
Definition defs.h:87
static AVPacket * pkt
static enum AVPixelFormat pix_fmt
static AVFrame * frame
error code definitions
int8_t exp
Definition eval.c:76
#define fail
Definition test.h:479
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
Definition avcodec.c:144
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition options.c:149
const AVCodec * avcodec_find_decoder(enum AVCodecID id)
Find a registered decoder with a matching codec ID.
Definition allcodecs.c:993
const AVCodec * avcodec_find_encoder(enum AVCodecID id)
Find a registered encoder with a matching codec ID.
Definition allcodecs.c:988
void avcodec_free_context(AVCodecContext **avctx)
Free the codec context and everything associated with it and write NULL to the provided pointer.
Definition options.c:164
@ AV_CODEC_ID_ASTC
Definition codec_id.h:327
int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
Alias for avcodec_receive_frame_flags(avctx, frame, 0).
Definition avcodec.c:720
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
Supply raw packet data as input to a decoder.
Definition decode.c:730
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
Read encoded data from the encoder.
Definition encode.c:578
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition defs.h:40
int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
Supply a raw video or audio frame to the encoder.
Definition encode.c:545
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition packet.c:63
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
int av_frame_get_buffer(AVFrame *frame, int align)
Allocate new buffer(s) for audio or video data.
Definition frame.c:206
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
static av_always_inline float av_int2float(uint32_t i)
Reinterpret a 32-bit integer as a float.
Definition intfloat.h:40
Memory handling functions.
static uint8_t half(int a, int b)
Definition mobiclip.c:540
#define AV_PIX_FMT_RGBAF32
Definition pixfmt.h:633
#define AV_PIX_FMT_RGBAF16
Definition pixfmt.h:630
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition pixfmt.h:100
#define FF_ARRAY_ELEMS(a)
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
int profile
profile
Definition avcodec.h:1641
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition avcodec.h:547
uint8_t * extradata
Out-of-band global headers that may be used by some codecs.
Definition avcodec.h:526
int extradata_size
Definition avcodec.h:527
AVCodec.
Definition codec.h:175
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int width
Definition frame.h:544
int height
Definition frame.h:544
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
#define av_mallocz(s)
#define av_log(a,...)