FFmpeg
Loading...
Searching...
No Matches
iamf_reader.c
Go to the documentation of this file.
1/*
2 * Immersive Audio Model and Formats demuxing utils
3 * Copyright (c) 2024 James Almer <jamrial@gmail.com>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "libavutil/avassert.h"
24#include "libavutil/log.h"
25#include "libavutil/mem.h"
26#include "libavcodec/mathops.h"
27#include "libavcodec/packet.h"
28#include "avformat.h"
29#include "avio_internal.h"
30#include "iamf.h"
31#include "iamf_parse.h"
32#include "iamf_reader.h"
33
34static AVStream *find_stream_by_id(AVFormatContext *s, int id, int stream_id_offset)
35{
36 for (int i = 0; i < s->nb_streams; i++)
37 if (s->streams[i]->id == id + stream_id_offset)
38 return s->streams[i];
39
40 av_log(s, AV_LOG_ERROR, "Invalid stream id %d\n", id);
41 return NULL;
42}
43
46 int len, enum IAMF_OBU_Type type,
47 unsigned skip_samples, unsigned discard_padding,
48 int stream_id_offset, int id_in_bitstream)
49{
50 AVStream *st;
51 int ret, audio_substream_id;
52
53 if (id_in_bitstream) {
54 unsigned explicit_audio_substream_id;
55 int64_t pos = avio_tell(pb);
56 explicit_audio_substream_id = ffio_read_leb(pb);
57 len -= avio_tell(pb) - pos;
58 audio_substream_id = explicit_audio_substream_id;
59 } else
60 audio_substream_id = type - IAMF_OBU_IA_AUDIO_FRAME_ID0;
61
62 st = find_stream_by_id(s, audio_substream_id, stream_id_offset);
63 if (!st)
65
66 ret = av_get_packet(pb, pkt, len);
67 if (ret < 0)
68 return ret;
69 if (ret != len)
71
72 if (skip_samples || discard_padding) {
73 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
74 if (!side_data)
75 return AVERROR(ENOMEM);
76 AV_WL32A(side_data, skip_samples);
77 AV_WL32A(side_data + 4, discard_padding);
78 }
79 if (c->mix) {
80 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, c->mix_size);
81 if (!side_data)
82 return AVERROR(ENOMEM);
83 memcpy(side_data, c->mix, c->mix_size);
84 }
85 if (c->demix) {
86 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM, c->demix_size);
87 if (!side_data)
88 return AVERROR(ENOMEM);
89 memcpy(side_data, c->demix, c->demix_size);
90 }
91 if (c->recon) {
92 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM, c->recon_size);
93 if (!side_data)
94 return AVERROR(ENOMEM);
95 memcpy(side_data, c->recon, c->recon_size);
96 }
97
98 if (st->discard == AVDISCARD_ALL)
99 pkt->flags |= AV_PKT_FLAG_DISCARD;
100
101 pkt->stream_index = st->index;
102 return 0;
103}
104
106 AVIOContext *pbc, int len)
107{
108 const IAMFAudioElement *audio_element;
110 const AVIAMFParamDefinition *param;
111 AVIAMFParamDefinition *out_param = NULL;
113 AVIOContext *pb;
114 uint8_t *buf;
115 unsigned int duration, constant_subblock_duration;
116 unsigned int total_duration = 0;
117 unsigned int nb_subblocks;
118 unsigned int parameter_id;
119 size_t out_param_size;
120 int ret;
121
122 buf = av_malloc(len);
123 if (!buf)
124 return AVERROR(ENOMEM);
125
126 ret = avio_read(pbc, buf, len);
127 if (ret != len) {
128 if (ret >= 0)
130 goto fail;
131 }
132
133 ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL);
134 pb = &b.pub;
135
136 parameter_id = ffio_read_leb(pb);
137 param_definition = ff_iamf_get_param_definition(&c->iamf, parameter_id);
138 if (!param_definition) {
139 av_log(s, AV_LOG_VERBOSE, "Non existent parameter_id %d referenced in a parameter block. Ignoring\n",
140 parameter_id);
141 ret = 0;
142 goto fail;
143 }
144
145 audio_element = param_definition->audio_element;
146 param = param_definition->param;
147 if (!param_definition->mode) {
149 if (!duration) {
151 goto fail;
152 }
153 if (audio_element) {
154 const IAMFCodecConfig *codec_config = ff_iamf_get_codec_config(&c->iamf, audio_element->codec_config_id);
155 if (duration > av_rescale(codec_config->nb_samples, codec_config->sample_rate, param->parameter_rate)) {
156 av_log(s, AV_LOG_ERROR, "Invalid block duration in parameter_id %u\n", parameter_id);
158 goto fail;
159 }
160 }
161 constant_subblock_duration = ffio_read_leb(pb);
162 if (constant_subblock_duration == 0)
163 nb_subblocks = ffio_read_leb(pb);
164 else {
165 if (constant_subblock_duration > duration) {
166 av_log(s, AV_LOG_ERROR, "Invalid block duration in parameter_id %u\n", parameter_id);
168 goto fail;
169 }
170 nb_subblocks = duration / constant_subblock_duration;
171 total_duration = duration;
172 }
173 } else {
174 duration = param->duration;
175 constant_subblock_duration = param->constant_subblock_duration;
176 nb_subblocks = param->nb_subblocks;
177 }
178
179 if (nb_subblocks > duration) {
180 av_log(s, AV_LOG_ERROR, "Invalid duration or subblock count in parameter_id %u\n", parameter_id);
182 goto fail;
183 }
184
185 out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size);
186 if (!out_param) {
187 ret = AVERROR(ENOMEM);
188 goto fail;
189 }
190
191 out_param->parameter_id = param->parameter_id;
192 out_param->type = param->type;
193 out_param->parameter_rate = param->parameter_rate;
194 out_param->duration = duration;
195 out_param->constant_subblock_duration = constant_subblock_duration;
196 out_param->nb_subblocks = nb_subblocks;
197
198 for (int i = 0; i < nb_subblocks; i++) {
199 void *subblock = av_iamf_param_definition_get_subblock(out_param, i);
200 unsigned int subblock_duration = constant_subblock_duration;
201
202 if (!param_definition->mode && !constant_subblock_duration) {
203 subblock_duration = ffio_read_leb(pb);
204 if (duration - total_duration > subblock_duration) {
205 av_log(s, AV_LOG_ERROR, "Invalid subblock durations in parameter_id %u\n", parameter_id);
207 goto fail;
208 }
209 total_duration += subblock_duration;
210 } else if (i == nb_subblocks - 1)
211 subblock_duration = duration - i * constant_subblock_duration;
212
213 switch (param->type) {
215 AVIAMFMixGain *mix = subblock;
216
217 mix->animation_type = ffio_read_leb(pb);
218 if (mix->animation_type > AV_IAMF_ANIMATION_TYPE_BEZIER) {
219 ret = 0;
220 av_free(out_param);
221 goto fail;
222 }
223
224 mix->start_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8);
225 if (mix->animation_type >= AV_IAMF_ANIMATION_TYPE_LINEAR)
226 mix->end_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8);
227 if (mix->animation_type == AV_IAMF_ANIMATION_TYPE_BEZIER) {
228 mix->control_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8);
229 mix->control_point_relative_time = av_make_q(avio_r8(pb), 1 << 8);
230 }
231 mix->subblock_duration = subblock_duration;
232 break;
233 }
235 AVIAMFDemixingInfo *demix = subblock;
236
237 demix->dmixp_mode = avio_r8(pb) >> 5;
238 demix->subblock_duration = subblock_duration;
239 break;
240 }
242 AVIAMFReconGain *recon = subblock;
243 const AVIAMFAudioElement *element;
244
245 av_assert0(audio_element && audio_element->celement);
246 element = audio_element->celement;
247 for (int i = 0; i < element->nb_layers; i++) {
248 const AVIAMFLayer *layer = element->layers[i];
250 unsigned int recon_gain_flags = ffio_read_leb(pb);
251 unsigned int bitcount = 7 + 5 * !!(recon_gain_flags & 0x80);
252 recon_gain_flags = (recon_gain_flags & 0x7F) | ((recon_gain_flags & 0xFF00) >> 1);
253 for (int j = 0; j < bitcount; j++) {
254 if (recon_gain_flags & (1 << j))
255 recon->recon_gain[i][j] = avio_r8(pb);
256 }
257 }
258 }
259 recon->subblock_duration = subblock_duration;
260 break;
261 }
262 default:
263 av_unreachable("param_definition_type should have been checked in descriptor");
264 }
265 }
266
267 len -= avio_tell(pb);
268 if (len) {
269 int level = (s->error_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING;
270 av_log(s, level, "Underread in parameter_block_obu. %d bytes left at the end\n", len);
271 }
272
273 if (!param_definition->mode && !constant_subblock_duration && total_duration != duration) {
274 av_log(s, AV_LOG_ERROR, "Invalid duration in parameter block\n");
276 goto fail;
277 }
278
279 switch (param->type) {
281 av_free(c->mix);
282 c->mix = out_param;
283 c->mix_size = out_param_size;
284 break;
286 av_free(c->demix);
287 c->demix = out_param;
288 c->demix_size = out_param_size;
289 break;
291 av_free(c->recon);
292 c->recon = out_param;
293 c->recon_size = out_param_size;
294 break;
295 default:
296 av_unreachable("param_definition_type should have been checked in descriptor");
297 }
298
299 ret = 0;
300fail:
301 if (ret < 0)
302 av_free(out_param);
303 av_free(buf);
304
305 return ret;
306}
307
309 AVIOContext *pb, int max_size, int stream_id_offset, AVPacket *pkt)
310{
311 int read = 0;
312
313 while (1) {
315 enum IAMF_OBU_Type type;
316 unsigned obu_size;
317 unsigned skip_samples, discard_padding;
318 int ret, len, size, start_pos;
319
321 if (ret < 0)
322 return ret;
324 if (size < 0)
325 return size;
326 if (size != FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size))
327 return AVERROR_INVALIDDATA;
328
329 len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type,
330 &skip_samples, &discard_padding);
331 if (len < 0 || obu_size > max_size || len > INT_MAX - read) {
332 av_log(s, AV_LOG_ERROR, "Failed to read obu\n");
333 return len < 0 ? len : AVERROR_INVALIDDATA;
334 }
335 avio_seek(pb, -(size - start_pos), SEEK_CUR);
336
337 read += len;
339 ret = audio_frame_obu(s, c, pb, pkt, obu_size, type,
340 skip_samples, discard_padding, stream_id_offset,
342 if (ret < 0)
343 return ret;
344 return read;
345 } else if (type == IAMF_OBU_IA_PARAMETER_BLOCK) {
346 ret = parameter_block_obu(s, c, pb, obu_size);
347 if (ret < 0)
348 return ret;
349 } else if (type == IAMF_OBU_IA_TEMPORAL_DELIMITER) {
350 av_freep(&c->mix);
351 c->mix_size = 0;
352 av_freep(&c->demix);
353 c->demix_size = 0;
354 av_freep(&c->recon);
355 c->recon_size = 0;
356 } else {
357 int64_t offset = avio_skip(pb, obu_size);
358 if (offset < 0)
359 return offset;
360 }
361 max_size -= len;
362 if (max_size < 0)
363 return AVERROR_INVALIDDATA;
364 if (!max_size)
365 break;
366 }
367
368 return read;
369}
370
372{
373 IAMFContext *const iamf = &c->iamf;
374
376
377 av_freep(&c->mix);
378 c->mix_size = 0;
379 av_freep(&c->demix);
380 c->demix_size = 0;
381 av_freep(&c->recon);
382 c->recon_size = 0;
383}
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
Main libavformat public API header.
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
Allocate and read the payload of a packet and initialize its fields with default values.
Definition utils.c:98
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition aviobuf.c:236
unsigned int avio_rb16(AVIOContext *s)
Definition aviobuf.c:749
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition avio.h:494
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition aviobuf.c:321
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition aviobuf.c:615
int avio_r8(AVIOContext *s)
Definition aviobuf.c:606
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition aviobuf.c:1026
void ffio_init_context(FFIOContext *s, unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, const uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Definition aviobuf.c:50
unsigned int ffio_read_leb(AVIOContext *s)
Read a unsigned integer coded as a variable number of up to eight little-endian bytes,...
Definition aviobuf.c:930
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define AV_EF_EXPLODE
abort decoding on minor error detection
Definition defs.h:51
static AVPacket * pkt
static int64_t duration
Definition ffplay.c:330
#define fail
Definition test.h:479
#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
@ AVDISCARD_ALL
discard all
Definition defs.h:232
@ AV_PKT_DATA_SKIP_SAMPLES
Recommends skipping the specified number of samples.
Definition packet.h:153
@ AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM
IAMF Recon Gain Info Parameter Data associated with the audio frame.
Definition packet.h:320
@ AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM
IAMF Demixing Info Parameter Data associated with the audio frame.
Definition packet.h:312
@ AV_PKT_DATA_IAMF_MIX_GAIN_PARAM
IAMF Mix Gain Parameter Data associated with the audio frame.
Definition packet.h:304
#define AV_PKT_FLAG_DISCARD
Flag is used to discard packets which are required to maintain valid decoder state but are not requir...
Definition packet.h:657
uint8_t * av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, size_t size)
Allocate new information of a packet.
Definition packet.c:231
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
#define AV_IAMF_LAYER_FLAG_RECON_GAIN
Recon gain information for the layer is present in AVIAMFReconGain.
Definition iamf.h:280
static av_always_inline void * av_iamf_param_definition_get_subblock(const AVIAMFParamDefinition *par, unsigned int idx)
Get the subblock at the specified idx.
Definition iamf.h:260
AVIAMFParamDefinition * av_iamf_param_definition_alloc(enum AVIAMFParamDefinitionType type, unsigned int nb_subblocks, size_t *out_size)
Allocates memory for AVIAMFParamDefinition, plus an array of nb_subblocks amount of subblocks of the ...
Definition iamf.c:159
@ AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN
Subblocks are of struct type AVIAMFReconGain.
Definition iamf.h:181
@ AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN
Subblocks are of struct type AVIAMFMixGain.
Definition iamf.h:173
@ AV_IAMF_PARAMETER_DEFINITION_DEMIXING
Subblocks are of struct type AVIAMFDemixingInfo.
Definition iamf.h:177
@ AV_IAMF_ANIMATION_TYPE_BEZIER
Definition iamf.h:69
@ AV_IAMF_ANIMATION_TYPE_LINEAR
Definition iamf.h:68
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
cl_device_type type
int ff_iamf_parse_obu_header(const uint8_t *buf, int buf_size, unsigned *obu_size, int *start_pos, enum IAMF_OBU_Type *type, unsigned *skip_samples, unsigned *discard_padding)
static int audio_frame_obu(AVFormatContext *s, const IAMFDemuxContext *c, AVIOContext *pb, AVPacket *pkt, int len, enum IAMF_OBU_Type type, unsigned skip_samples, unsigned discard_padding, int stream_id_offset, int id_in_bitstream)
Definition iamf_reader.c:44
static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, AVIOContext *pbc, int len)
int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, AVIOContext *pb, int max_size, int stream_id_offset, AVPacket *pkt)
static AVStream * find_stream_by_id(AVFormatContext *s, int id, int stream_id_offset)
Definition iamf_reader.c:34
void ff_iamf_read_deinit(IAMFDemuxContext *c)
static int param_definition(const IAMFContext *iamf, const IAMFParamDefinition *param_def, AVIOContext *dyn_bc, void *log_ctx)
#define b
Definition input.c:43
#define AV_WL32A(p, v)
unsigned offset
Definition libaomenc.c:763
static int mix(int c0, int c1)
Definition 4xm.c:717
void ff_iamf_uninit_context(IAMFContext *c)
Definition iamf.c:172
static IAMFParamDefinition * ff_iamf_get_param_definition(const IAMFContext *iamf, unsigned int parameter_id)
Definition iamf.h:185
#define MAX_IAMF_OBU_HEADER_SIZE
Definition iamf.h:34
static IAMFCodecConfig * ff_iamf_get_codec_config(const IAMFContext *c, unsigned int codec_config_id)
Definition iamf.h:172
IAMF_OBU_Type
Definition iamf.h:37
@ IAMF_OBU_IA_AUDIO_FRAME
Definition iamf.h:43
@ IAMF_OBU_IA_PARAMETER_BLOCK
Definition iamf.h:41
@ IAMF_OBU_IA_TEMPORAL_DELIMITER
Definition iamf.h:42
@ IAMF_OBU_IA_AUDIO_FRAME_ID17
Definition iamf.h:61
@ IAMF_OBU_IA_AUDIO_FRAME_ID0
Definition iamf.h:44
#define FFMIN(a, b)
Definition macros.h:49
static av_const int sign_extend(int val, unsigned bits)
Definition mathops.h:135
Memory handling functions.
#define av_malloc(s)
Definition ops_static.c:52
static const uint8_t header[24]
Definition sdr2.c:68
unsigned int pos
Definition spdifenc.c:431
Format I/O context.
Definition avformat.h:1333
Information on how to combine one or more audio streams, as defined in section 3.6 of IAMF.
Definition iamf.h:359
AVIAMFLayer ** layers
Definition iamf.h:362
unsigned int nb_layers
Number of layers, or channel groups, in the Audio Element.
Definition iamf.h:371
Demixing Info Parameter Data as defined in section 3.8.2 of IAMF.
Definition iamf.h:128
unsigned int dmixp_mode
Pre-defined combination of demixing parameters.
Definition iamf.h:140
unsigned int subblock_duration
Duration for the given subblock, in units of 1 / parameter_rate.
Definition iamf.h:136
A layer defining a Channel Layout in the Audio Element.
Definition iamf.h:294
unsigned int flags
A bitmask which may contain a combination of AV_IAMF_LAYER_FLAG_* flags.
Definition iamf.h:302
Mix Gain Parameter Data as defined in section 3.8.1 of IAMF.
Definition iamf.h:77
Parameters as defined in section 3.6.1 of IAMF.
Definition iamf.h:193
unsigned int parameter_rate
Sample rate for the parameter substream.
Definition iamf.h:222
unsigned int duration
The accumulated duration of all blocks in this parameter definition, in units of 1 / parameter_rate.
Definition iamf.h:231
unsigned int constant_subblock_duration
The duration of every subblock in the case where all subblocks, with the optional exception of the la...
Definition iamf.h:238
unsigned int parameter_id
Identifier for the parameter substream.
Definition iamf.h:218
enum AVIAMFParamDefinitionType type
Parameters type.
Definition iamf.h:213
unsigned int nb_subblocks
Number of subblocks in the array.
Definition iamf.h:208
Recon Gain Info Parameter Data as defined in section 3.8.3 of IAMF.
Definition iamf.h:148
unsigned int subblock_duration
Duration for the given subblock, in units of 1 / parameter_rate.
Definition iamf.h:156
uint8_t recon_gain[6][12]
Array of gain values to be applied to each channel for each layer defined in the Audio Element refere...
Definition iamf.h:166
Bytestream IO Context.
Definition avio.h:160
This structure stores compressed data.
Definition packet.h:580
Stream structure.
Definition avformat.h:766
enum AVDiscard discard
Selects which packets can be discarded at will and do not need to be demuxed.
Definition avformat.h:837
int index
stream index in AVFormatContext
Definition avformat.h:772
unsigned int codec_config_id
Definition iamf.h:101
const AVIAMFAudioElement * celement
Definition iamf.h:90
int sample_rate
Definition iamf.h:72
unsigned nb_samples
Definition iamf.h:70
uint8_t level
Definition svq3.c:208
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
int size
int len
static double c[64]