Line | Branch | Exec | Source |
---|---|---|---|
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" | ||
23 | #include "libavutil/intreadwrite.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 | |||
34 | 697 | static AVStream *find_stream_by_id(AVFormatContext *s, int id, int stream_id_offset) | |
35 | { | ||
36 |
1/2✓ Branch 0 taken 2507 times.
✗ Branch 1 not taken.
|
2507 | for (int i = 0; i < s->nb_streams; i++) |
37 |
2/2✓ Branch 0 taken 697 times.
✓ Branch 1 taken 1810 times.
|
2507 | if (s->streams[i]->id == id + stream_id_offset) |
38 | 697 | return s->streams[i]; | |
39 | |||
40 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid stream id %d\n", id); | |
41 | ✗ | return NULL; | |
42 | } | ||
43 | |||
44 | 697 | static int audio_frame_obu(AVFormatContext *s, const IAMFDemuxContext *c, | |
45 | AVIOContext *pb, AVPacket *pkt, | ||
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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
|
697 | 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 | 697 | audio_substream_id = type - IAMF_OBU_IA_AUDIO_FRAME_ID0; | |
61 | |||
62 | 697 | st = find_stream_by_id(s, audio_substream_id, stream_id_offset); | |
63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
|
697 | if (!st) |
64 | ✗ | return AVERROR_INVALIDDATA; | |
65 | |||
66 | 697 | ret = av_get_packet(pb, pkt, len); | |
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
|
697 | if (ret < 0) |
68 | ✗ | return ret; | |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
|
697 | if (ret != len) |
70 | ✗ | return AVERROR_INVALIDDATA; | |
71 | |||
72 |
4/4✓ Branch 0 taken 683 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 679 times.
|
697 | if (skip_samples || discard_padding) { |
73 | 18 | uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); | |
74 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (!side_data) |
75 | ✗ | return AVERROR(ENOMEM); | |
76 | 18 | AV_WL32A(side_data, skip_samples); | |
77 | 18 | AV_WL32A(side_data + 4, discard_padding); | |
78 | } | ||
79 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 555 times.
|
697 | if (c->mix) { |
80 | 142 | uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, c->mix_size); | |
81 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | if (!side_data) |
82 | ✗ | return AVERROR(ENOMEM); | |
83 | 142 | memcpy(side_data, c->mix, c->mix_size); | |
84 | } | ||
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
|
697 | 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 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 581 times.
|
697 | if (c->recon) { |
92 | 116 | uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM, c->recon_size); | |
93 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
|
116 | if (!side_data) |
94 | ✗ | return AVERROR(ENOMEM); | |
95 | 116 | memcpy(side_data, c->recon, c->recon_size); | |
96 | } | ||
97 | |||
98 | 697 | pkt->stream_index = st->index; | |
99 | 697 | return 0; | |
100 | } | ||
101 | |||
102 | 86 | static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, | |
103 | AVIOContext *pbc, int len) | ||
104 | { | ||
105 | const IAMFParamDefinition *param_definition; | ||
106 | const AVIAMFParamDefinition *param; | ||
107 | 86 | AVIAMFParamDefinition *out_param = NULL; | |
108 | FFIOContext b; | ||
109 | AVIOContext *pb; | ||
110 | uint8_t *buf; | ||
111 | unsigned int duration, constant_subblock_duration; | ||
112 | 86 | unsigned int total_duration = 0; | |
113 | unsigned int nb_subblocks; | ||
114 | unsigned int parameter_id; | ||
115 | size_t out_param_size; | ||
116 | int ret; | ||
117 | |||
118 | 86 | buf = av_malloc(len); | |
119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (!buf) |
120 | ✗ | return AVERROR(ENOMEM); | |
121 | |||
122 | 86 | ret = avio_read(pbc, buf, len); | |
123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (ret != len) { |
124 | ✗ | if (ret >= 0) | |
125 | ✗ | ret = AVERROR_INVALIDDATA; | |
126 | ✗ | goto fail; | |
127 | } | ||
128 | |||
129 | 86 | ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); | |
130 | 86 | pb = &b.pub; | |
131 | |||
132 | 86 | parameter_id = ffio_read_leb(pb); | |
133 | 86 | param_definition = ff_iamf_get_param_definition(&c->iamf, parameter_id); | |
134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (!param_definition) { |
135 | ✗ | av_log(s, AV_LOG_VERBOSE, "Non existant parameter_id %d referenced in a parameter block. Ignoring\n", | |
136 | parameter_id); | ||
137 | ✗ | ret = 0; | |
138 | ✗ | goto fail; | |
139 | } | ||
140 | |||
141 | 86 | param = param_definition->param; | |
142 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 30 times.
|
86 | if (!param_definition->mode) { |
143 | 56 | duration = ffio_read_leb(pb); | |
144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | if (!duration) { |
145 | ✗ | ret = AVERROR_INVALIDDATA; | |
146 | ✗ | goto fail; | |
147 | } | ||
148 | 56 | constant_subblock_duration = ffio_read_leb(pb); | |
149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | if (constant_subblock_duration == 0) |
150 | ✗ | nb_subblocks = ffio_read_leb(pb); | |
151 | else { | ||
152 | 56 | nb_subblocks = duration / constant_subblock_duration; | |
153 | 56 | total_duration = duration; | |
154 | } | ||
155 | } else { | ||
156 | 30 | duration = param->duration; | |
157 | 30 | constant_subblock_duration = param->constant_subblock_duration; | |
158 | 30 | nb_subblocks = param->nb_subblocks; | |
159 | } | ||
160 | |||
161 | 86 | out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size); | |
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (!out_param) { |
163 | ✗ | ret = AVERROR(ENOMEM); | |
164 | ✗ | goto fail; | |
165 | } | ||
166 | |||
167 | 86 | out_param->parameter_id = param->parameter_id; | |
168 | 86 | out_param->type = param->type; | |
169 | 86 | out_param->parameter_rate = param->parameter_rate; | |
170 | 86 | out_param->duration = duration; | |
171 | 86 | out_param->constant_subblock_duration = constant_subblock_duration; | |
172 | 86 | out_param->nb_subblocks = nb_subblocks; | |
173 | |||
174 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 86 times.
|
172 | for (int i = 0; i < nb_subblocks; i++) { |
175 | 86 | void *subblock = av_iamf_param_definition_get_subblock(out_param, i); | |
176 | 86 | unsigned int subblock_duration = constant_subblock_duration; | |
177 | |||
178 |
3/4✓ Branch 0 taken 56 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
|
86 | if (!param_definition->mode && !constant_subblock_duration) { |
179 | ✗ | subblock_duration = ffio_read_leb(pb); | |
180 | ✗ | total_duration += subblock_duration; | |
181 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | } else if (i == nb_subblocks - 1) |
182 | 86 | subblock_duration = duration - i * constant_subblock_duration; | |
183 | |||
184 |
2/4✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
86 | switch (param->type) { |
185 | 56 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { | |
186 | 56 | AVIAMFMixGain *mix = subblock; | |
187 | |||
188 | 56 | mix->animation_type = ffio_read_leb(pb); | |
189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | if (mix->animation_type > AV_IAMF_ANIMATION_TYPE_BEZIER) { |
190 | ✗ | ret = 0; | |
191 | ✗ | av_free(out_param); | |
192 | ✗ | goto fail; | |
193 | } | ||
194 | |||
195 | 56 | mix->start_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); | |
196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | if (mix->animation_type >= AV_IAMF_ANIMATION_TYPE_LINEAR) |
197 | ✗ | mix->end_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); | |
198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | if (mix->animation_type == AV_IAMF_ANIMATION_TYPE_BEZIER) { |
199 | ✗ | mix->control_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); | |
200 | ✗ | mix->control_point_relative_time = av_make_q(avio_r8(pb), 1 << 8); | |
201 | } | ||
202 | 56 | mix->subblock_duration = subblock_duration; | |
203 | 56 | break; | |
204 | } | ||
205 | ✗ | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { | |
206 | ✗ | AVIAMFDemixingInfo *demix = subblock; | |
207 | |||
208 | ✗ | demix->dmixp_mode = avio_r8(pb) >> 5; | |
209 | ✗ | demix->subblock_duration = subblock_duration; | |
210 | ✗ | break; | |
211 | } | ||
212 | 30 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { | |
213 | 30 | AVIAMFReconGain *recon = subblock; | |
214 | 30 | const IAMFAudioElement *audio_element = param_definition->audio_element; | |
215 | 30 | const AVIAMFAudioElement *element = audio_element->celement; | |
216 | |||
217 |
2/4✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
|
30 | av_assert0(audio_element && element); |
218 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 30 times.
|
90 | for (int i = 0; i < element->nb_layers; i++) { |
219 | 60 | const AVIAMFLayer *layer = element->layers[i]; | |
220 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
|
60 | if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) { |
221 | 30 | unsigned int recon_gain_flags = ffio_read_leb(pb); | |
222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | unsigned int bitcount = 7 + 5 * !!(recon_gain_flags & 0x80); |
223 | 30 | recon_gain_flags = (recon_gain_flags & 0x7F) | ((recon_gain_flags & 0xFF00) >> 1); | |
224 |
2/2✓ Branch 0 taken 210 times.
✓ Branch 1 taken 30 times.
|
240 | for (int j = 0; j < bitcount; j++) { |
225 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 90 times.
|
210 | if (recon_gain_flags & (1 << j)) |
226 | 120 | recon->recon_gain[i][j] = avio_r8(pb); | |
227 | } | ||
228 | } | ||
229 | } | ||
230 | 30 | recon->subblock_duration = subblock_duration; | |
231 | 30 | break; | |
232 | } | ||
233 | ✗ | default: | |
234 | ✗ | av_assert0(0); | |
235 | } | ||
236 | } | ||
237 | |||
238 | 86 | len -= avio_tell(pb); | |
239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (len) { |
240 | ✗ | int level = (s->error_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING; | |
241 | ✗ | av_log(s, level, "Underread in parameter_block_obu. %d bytes left at the end\n", len); | |
242 | } | ||
243 | |||
244 |
3/6✓ Branch 0 taken 56 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
86 | if (!param_definition->mode && !constant_subblock_duration && total_duration != duration) { |
245 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid duration in parameter block\n"); | |
246 | ✗ | ret = AVERROR_INVALIDDATA; | |
247 | ✗ | goto fail; | |
248 | } | ||
249 | |||
250 |
2/4✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
86 | switch (param->type) { |
251 | 56 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: | |
252 | 56 | av_free(c->mix); | |
253 | 56 | c->mix = out_param; | |
254 | 56 | c->mix_size = out_param_size; | |
255 | 56 | break; | |
256 | ✗ | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: | |
257 | ✗ | av_free(c->demix); | |
258 | ✗ | c->demix = out_param; | |
259 | ✗ | c->demix_size = out_param_size; | |
260 | ✗ | break; | |
261 | 30 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: | |
262 | 30 | av_free(c->recon); | |
263 | 30 | c->recon = out_param; | |
264 | 30 | c->recon_size = out_param_size; | |
265 | 30 | break; | |
266 | ✗ | default: | |
267 | ✗ | av_assert0(0); | |
268 | } | ||
269 | |||
270 | 86 | ret = 0; | |
271 | 86 | fail: | |
272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (ret < 0) |
273 | ✗ | av_free(out_param); | |
274 | 86 | av_free(buf); | |
275 | |||
276 | 86 | return ret; | |
277 | } | ||
278 | |||
279 | 704 | int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, | |
280 | AVIOContext *pb, int max_size, int stream_id_offset, AVPacket *pkt) | ||
281 | { | ||
282 | 704 | int read = 0; | |
283 | |||
284 | 86 | while (1) { | |
285 | 790 | uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE] = {0}; | |
286 | enum IAMF_OBU_Type type; | ||
287 | unsigned obu_size; | ||
288 | unsigned skip_samples, discard_padding; | ||
289 | int ret, len, size, start_pos; | ||
290 | |||
291 | 790 | ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 790 times.
|
790 | if (ret < 0) |
293 | 704 | return ret; | |
294 | 790 | size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
295 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 783 times.
|
790 | if (size < 0) |
296 | 7 | return size; | |
297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 783 times.
|
783 | if (size != FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)) |
298 | ✗ | return AVERROR_INVALIDDATA; | |
299 | |||
300 | 783 | len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, | |
301 | &skip_samples, &discard_padding); | ||
302 |
3/6✓ Branch 0 taken 783 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 783 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 783 times.
|
783 | if (len < 0 || obu_size > max_size || len > INT_MAX - read) { |
303 | ✗ | av_log(s, AV_LOG_ERROR, "Failed to read obu\n"); | |
304 | ✗ | return len < 0 ? len : AVERROR_INVALIDDATA; | |
305 | } | ||
306 | 783 | avio_seek(pb, -(size - start_pos), SEEK_CUR); | |
307 | |||
308 | 783 | read += len; | |
309 |
3/4✓ Branch 0 taken 697 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 697 times.
✗ Branch 3 not taken.
|
783 | if (type >= IAMF_OBU_IA_AUDIO_FRAME && type <= IAMF_OBU_IA_AUDIO_FRAME_ID17) { |
310 | 697 | ret = audio_frame_obu(s, c, pb, pkt, obu_size, type, | |
311 | skip_samples, discard_padding, stream_id_offset, | ||
312 | type == IAMF_OBU_IA_AUDIO_FRAME); | ||
313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
|
697 | if (ret < 0) |
314 | ✗ | return ret; | |
315 | 697 | return read; | |
316 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | } else if (type == IAMF_OBU_IA_PARAMETER_BLOCK) { |
317 | 86 | ret = parameter_block_obu(s, c, pb, obu_size); | |
318 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (ret < 0) |
319 | ✗ | return ret; | |
320 | ✗ | } else if (type == IAMF_OBU_IA_TEMPORAL_DELIMITER) { | |
321 | ✗ | av_freep(&c->mix); | |
322 | ✗ | c->mix_size = 0; | |
323 | ✗ | av_freep(&c->demix); | |
324 | ✗ | c->demix_size = 0; | |
325 | ✗ | av_freep(&c->recon); | |
326 | ✗ | c->recon_size = 0; | |
327 | } else { | ||
328 | ✗ | int64_t offset = avio_skip(pb, obu_size); | |
329 | ✗ | if (offset < 0) | |
330 | ✗ | return offset; | |
331 | } | ||
332 | 86 | max_size -= len; | |
333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (max_size < 0) |
334 | ✗ | return AVERROR_INVALIDDATA; | |
335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
|
86 | if (!max_size) |
336 | ✗ | break; | |
337 | } | ||
338 | |||
339 | ✗ | return read; | |
340 | } | ||
341 | |||
342 | 27 | void ff_iamf_read_deinit(IAMFDemuxContext *c) | |
343 | { | ||
344 | 27 | IAMFContext *const iamf = &c->iamf; | |
345 | |||
346 | 27 | ff_iamf_uninit_context(iamf); | |
347 | |||
348 | 27 | av_freep(&c->mix); | |
349 | 27 | c->mix_size = 0; | |
350 | 27 | av_freep(&c->demix); | |
351 | 27 | c->demix_size = 0; | |
352 | 27 | av_freep(&c->recon); | |
353 | 27 | c->recon_size = 0; | |
354 | 27 | } | |
355 |