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 | 703 | static AVStream *find_stream_by_id(AVFormatContext *s, int id) | |
35 | { | ||
36 |
1/2✓ Branch 0 taken 2524 times.
✗ Branch 1 not taken.
|
2524 | for (int i = 0; i < s->nb_streams; i++) |
37 |
2/2✓ Branch 0 taken 703 times.
✓ Branch 1 taken 1821 times.
|
2524 | if (s->streams[i]->id == id) |
38 | 703 | return s->streams[i]; | |
39 | |||
40 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid stream id %d\n", id); | |
41 | ✗ | return NULL; | |
42 | } | ||
43 | |||
44 | 703 | 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 id_in_bitstream) | ||
49 | { | ||
50 | AVStream *st; | ||
51 | int ret, audio_substream_id; | ||
52 | |||
53 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 703 times.
|
703 | 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 | 703 | audio_substream_id = type - IAMF_OBU_IA_AUDIO_FRAME_ID0; | |
61 | |||
62 | 703 | st = find_stream_by_id(s, audio_substream_id); | |
63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 703 times.
|
703 | if (!st) |
64 | ✗ | return AVERROR_INVALIDDATA; | |
65 | |||
66 | 703 | ret = av_get_packet(pb, pkt, len); | |
67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 703 times.
|
703 | if (ret < 0) |
68 | ✗ | return ret; | |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 703 times.
|
703 | if (ret != len) |
70 | ✗ | return AVERROR_INVALIDDATA; | |
71 | |||
72 |
4/4✓ Branch 0 taken 689 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 685 times.
|
703 | 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 148 times.
✓ Branch 1 taken 555 times.
|
703 | if (c->mix) { |
80 | 148 | 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 148 times.
|
148 | if (!side_data) |
82 | ✗ | return AVERROR(ENOMEM); | |
83 | 148 | memcpy(side_data, c->mix, c->mix_size); | |
84 | } | ||
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 703 times.
|
703 | 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 122 times.
✓ Branch 1 taken 581 times.
|
703 | if (c->recon) { |
92 | 122 | 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 122 times.
|
122 | if (!side_data) |
94 | ✗ | return AVERROR(ENOMEM); | |
95 | 122 | memcpy(side_data, c->recon, c->recon_size); | |
96 | } | ||
97 | |||
98 | 703 | pkt->stream_index = st->index; | |
99 | 703 | return 0; | |
100 | } | ||
101 | |||
102 | 88 | 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 | 88 | AVIAMFParamDefinition *out_param = NULL; | |
108 | FFIOContext b; | ||
109 | AVIOContext *pb; | ||
110 | uint8_t *buf; | ||
111 | unsigned int duration, constant_subblock_duration; | ||
112 | 88 | 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 | 88 | buf = av_malloc(len); | |
119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (!buf) |
120 | ✗ | return AVERROR(ENOMEM); | |
121 | |||
122 | 88 | ret = avio_read(pbc, buf, len); | |
123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (ret != len) { |
124 | ✗ | if (ret >= 0) | |
125 | ✗ | ret = AVERROR_INVALIDDATA; | |
126 | ✗ | goto fail; | |
127 | } | ||
128 | |||
129 | 88 | ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); | |
130 | 88 | pb = &b.pub; | |
131 | |||
132 | 88 | parameter_id = ffio_read_leb(pb); | |
133 | 88 | param_definition = ff_iamf_get_param_definition(&c->iamf, parameter_id); | |
134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | 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 | 88 | param = param_definition->param; | |
142 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 31 times.
|
88 | if (!param_definition->mode) { |
143 | 57 | duration = ffio_read_leb(pb); | |
144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (!duration) { |
145 | ✗ | ret = AVERROR_INVALIDDATA; | |
146 | ✗ | goto fail; | |
147 | } | ||
148 | 57 | constant_subblock_duration = ffio_read_leb(pb); | |
149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (constant_subblock_duration == 0) |
150 | ✗ | nb_subblocks = ffio_read_leb(pb); | |
151 | else { | ||
152 | 57 | nb_subblocks = duration / constant_subblock_duration; | |
153 | 57 | total_duration = duration; | |
154 | } | ||
155 | } else { | ||
156 | 31 | duration = param->duration; | |
157 | 31 | constant_subblock_duration = param->constant_subblock_duration; | |
158 | 31 | nb_subblocks = param->nb_subblocks; | |
159 | } | ||
160 | |||
161 | 88 | out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size); | |
162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (!out_param) { |
163 | ✗ | ret = AVERROR(ENOMEM); | |
164 | ✗ | goto fail; | |
165 | } | ||
166 | |||
167 | 88 | out_param->parameter_id = param->parameter_id; | |
168 | 88 | out_param->type = param->type; | |
169 | 88 | out_param->parameter_rate = param->parameter_rate; | |
170 | 88 | out_param->duration = duration; | |
171 | 88 | out_param->constant_subblock_duration = constant_subblock_duration; | |
172 | 88 | out_param->nb_subblocks = nb_subblocks; | |
173 | |||
174 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 88 times.
|
176 | for (int i = 0; i < nb_subblocks; i++) { |
175 | 88 | void *subblock = av_iamf_param_definition_get_subblock(out_param, i); | |
176 | 88 | unsigned int subblock_duration = constant_subblock_duration; | |
177 | |||
178 |
3/4✓ Branch 0 taken 57 times.
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57 times.
|
88 | 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 88 times.
✗ Branch 1 not taken.
|
88 | } else if (i == nb_subblocks - 1) |
182 | 88 | subblock_duration = duration - i * constant_subblock_duration; | |
183 | |||
184 |
2/4✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
88 | switch (param->type) { |
185 | 57 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { | |
186 | 57 | AVIAMFMixGain *mix = subblock; | |
187 | |||
188 | 57 | mix->animation_type = ffio_read_leb(pb); | |
189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (mix->animation_type > AV_IAMF_ANIMATION_TYPE_BEZIER) { |
190 | ✗ | ret = 0; | |
191 | ✗ | av_free(out_param); | |
192 | ✗ | goto fail; | |
193 | } | ||
194 | |||
195 | 57 | 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 57 times.
|
57 | 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 57 times.
|
57 | 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 | 57 | mix->subblock_duration = subblock_duration; | |
203 | 57 | 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 | 31 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { | |
213 | 31 | AVIAMFReconGain *recon = subblock; | |
214 | 31 | const IAMFAudioElement *audio_element = param_definition->audio_element; | |
215 | 31 | const AVIAMFAudioElement *element = audio_element->celement; | |
216 | |||
217 |
2/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
|
31 | av_assert0(audio_element && element); |
218 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 31 times.
|
93 | for (int i = 0; i < element->nb_layers; i++) { |
219 | 62 | const AVIAMFLayer *layer = element->layers[i]; | |
220 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
|
62 | if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) { |
221 | 31 | unsigned int recon_gain_flags = ffio_read_leb(pb); | |
222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
|
31 | unsigned int bitcount = 7 + 5 * !!(recon_gain_flags & 0x80); |
223 | 31 | recon_gain_flags = (recon_gain_flags & 0x7F) | ((recon_gain_flags & 0xFF00) >> 1); | |
224 |
2/2✓ Branch 0 taken 217 times.
✓ Branch 1 taken 31 times.
|
248 | for (int j = 0; j < bitcount; j++) { |
225 |
2/2✓ Branch 0 taken 124 times.
✓ Branch 1 taken 93 times.
|
217 | if (recon_gain_flags & (1 << j)) |
226 | 124 | recon->recon_gain[i][j] = avio_r8(pb); | |
227 | } | ||
228 | } | ||
229 | } | ||
230 | 31 | recon->subblock_duration = subblock_duration; | |
231 | 31 | break; | |
232 | } | ||
233 | ✗ | default: | |
234 | ✗ | av_assert0(0); | |
235 | } | ||
236 | } | ||
237 | |||
238 | 88 | len -= avio_tell(pb); | |
239 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | 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 57 times.
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
88 | 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 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
88 | switch (param->type) { |
251 | 57 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: | |
252 | 57 | av_free(c->mix); | |
253 | 57 | c->mix = out_param; | |
254 | 57 | c->mix_size = out_param_size; | |
255 | 57 | 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 | 31 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: | |
262 | 31 | av_free(c->recon); | |
263 | 31 | c->recon = out_param; | |
264 | 31 | c->recon_size = out_param_size; | |
265 | 31 | break; | |
266 | ✗ | default: | |
267 | ✗ | av_assert0(0); | |
268 | } | ||
269 | |||
270 | 88 | ret = 0; | |
271 | 88 | fail: | |
272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (ret < 0) |
273 | ✗ | av_free(out_param); | |
274 | 88 | av_free(buf); | |
275 | |||
276 | 88 | return ret; | |
277 | } | ||
278 | |||
279 | 710 | int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, | |
280 | AVIOContext *pb, int max_size, AVPacket *pkt) | ||
281 | { | ||
282 | 710 | int read = 0; | |
283 | |||
284 | 88 | while (1) { | |
285 | uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; | ||
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 | 798 | ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 798 times.
|
798 | if (ret < 0) |
293 | 710 | return ret; | |
294 | 798 | size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
295 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 791 times.
|
798 | if (size < 0) |
296 | 7 | return size; | |
297 | |||
298 | 791 | len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, | |
299 | &skip_samples, &discard_padding); | ||
300 |
3/6✓ Branch 0 taken 791 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 791 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 791 times.
|
791 | if (len < 0 || obu_size > max_size || len > INT_MAX - read) { |
301 | ✗ | av_log(s, AV_LOG_ERROR, "Failed to read obu\n"); | |
302 | ✗ | return len < 0 ? len : AVERROR_INVALIDDATA; | |
303 | } | ||
304 | 791 | avio_seek(pb, -(size - start_pos), SEEK_CUR); | |
305 | |||
306 | 791 | read += len; | |
307 |
3/4✓ Branch 0 taken 703 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 703 times.
✗ Branch 3 not taken.
|
791 | if (type >= IAMF_OBU_IA_AUDIO_FRAME && type <= IAMF_OBU_IA_AUDIO_FRAME_ID17) { |
308 | 703 | ret = audio_frame_obu(s, c, pb, pkt, obu_size, type, | |
309 | skip_samples, discard_padding, | ||
310 | type == IAMF_OBU_IA_AUDIO_FRAME); | ||
311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 703 times.
|
703 | if (ret < 0) |
312 | ✗ | return ret; | |
313 | 703 | return read; | |
314 |
1/2✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
|
88 | } else if (type == IAMF_OBU_IA_PARAMETER_BLOCK) { |
315 | 88 | ret = parameter_block_obu(s, c, pb, obu_size); | |
316 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (ret < 0) |
317 | ✗ | return ret; | |
318 | ✗ | } else if (type == IAMF_OBU_IA_TEMPORAL_DELIMITER) { | |
319 | ✗ | av_freep(&c->mix); | |
320 | ✗ | c->mix_size = 0; | |
321 | ✗ | av_freep(&c->demix); | |
322 | ✗ | c->demix_size = 0; | |
323 | ✗ | av_freep(&c->recon); | |
324 | ✗ | c->recon_size = 0; | |
325 | } else { | ||
326 | ✗ | int64_t offset = avio_skip(pb, obu_size); | |
327 | ✗ | if (offset < 0) | |
328 | ✗ | return offset; | |
329 | } | ||
330 | 88 | max_size -= len; | |
331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (max_size < 0) |
332 | ✗ | return AVERROR_INVALIDDATA; | |
333 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (!max_size) |
334 | ✗ | break; | |
335 | } | ||
336 | |||
337 | ✗ | return read; | |
338 | } | ||
339 | |||
340 | 27 | void ff_iamf_read_deinit(IAMFDemuxContext *c) | |
341 | { | ||
342 | 27 | IAMFContext *const iamf = &c->iamf; | |
343 | |||
344 | 27 | ff_iamf_uninit_context(iamf); | |
345 | |||
346 | 27 | av_freep(&c->mix); | |
347 | 27 | c->mix_size = 0; | |
348 | 27 | av_freep(&c->demix); | |
349 | 27 | c->demix_size = 0; | |
350 | 27 | av_freep(&c->recon); | |
351 | 27 | c->recon_size = 0; | |
352 | 27 | } | |
353 |