| 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 | 1907 | static AVStream *find_stream_by_id(AVFormatContext *s, int id, int stream_id_offset) | |
| 35 | { | ||
| 36 |
1/2✓ Branch 0 taken 5880 times.
✗ Branch 1 not taken.
|
5880 | for (int i = 0; i < s->nb_streams; i++) |
| 37 |
2/2✓ Branch 0 taken 1907 times.
✓ Branch 1 taken 3973 times.
|
5880 | if (s->streams[i]->id == id + stream_id_offset) |
| 38 | 1907 | return s->streams[i]; | |
| 39 | |||
| 40 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid stream id %d\n", id); | |
| 41 | ✗ | return NULL; | |
| 42 | } | ||
| 43 | |||
| 44 | 1907 | 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 1907 times.
|
1907 | 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 | 1907 | audio_substream_id = type - IAMF_OBU_IA_AUDIO_FRAME_ID0; | |
| 61 | |||
| 62 | 1907 | st = find_stream_by_id(s, audio_substream_id, stream_id_offset); | |
| 63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
|
1907 | if (!st) |
| 64 | ✗ | return AVERROR_INVALIDDATA; | |
| 65 | |||
| 66 | 1907 | ret = av_get_packet(pb, pkt, len); | |
| 67 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
|
1907 | if (ret < 0) |
| 68 | ✗ | return ret; | |
| 69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
|
1907 | if (ret != len) |
| 70 | ✗ | return AVERROR_INVALIDDATA; | |
| 71 | |||
| 72 |
4/4✓ Branch 0 taken 1889 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1881 times.
|
1907 | if (skip_samples || discard_padding) { |
| 73 | 26 | 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 26 times.
|
26 | if (!side_data) |
| 75 | ✗ | return AVERROR(ENOMEM); | |
| 76 | 26 | AV_WL32A(side_data, skip_samples); | |
| 77 | 26 | AV_WL32A(side_data + 4, discard_padding); | |
| 78 | } | ||
| 79 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 1757 times.
|
1907 | if (c->mix) { |
| 80 | 150 | 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 150 times.
|
150 | if (!side_data) |
| 82 | ✗ | return AVERROR(ENOMEM); | |
| 83 | 150 | memcpy(side_data, c->mix, c->mix_size); | |
| 84 | } | ||
| 85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
|
1907 | 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 124 times.
✓ Branch 1 taken 1783 times.
|
1907 | if (c->recon) { |
| 92 | 124 | 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 124 times.
|
124 | if (!side_data) |
| 94 | ✗ | return AVERROR(ENOMEM); | |
| 95 | 124 | memcpy(side_data, c->recon, c->recon_size); | |
| 96 | } | ||
| 97 | |||
| 98 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 1799 times.
|
1907 | if (st->discard == AVDISCARD_ALL) |
| 99 | 108 | pkt->flags |= AV_PKT_FLAG_DISCARD; | |
| 100 | |||
| 101 | 1907 | pkt->stream_index = st->index; | |
| 102 | 1907 | return 0; | |
| 103 | } | ||
| 104 | |||
| 105 | 90 | static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, | |
| 106 | AVIOContext *pbc, int len) | ||
| 107 | { | ||
| 108 | const IAMFAudioElement *audio_element; | ||
| 109 | const IAMFParamDefinition *param_definition; | ||
| 110 | const AVIAMFParamDefinition *param; | ||
| 111 | 90 | AVIAMFParamDefinition *out_param = NULL; | |
| 112 | FFIOContext b; | ||
| 113 | AVIOContext *pb; | ||
| 114 | uint8_t *buf; | ||
| 115 | unsigned int duration, constant_subblock_duration; | ||
| 116 | 90 | 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 | 90 | buf = av_malloc(len); | |
| 123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (!buf) |
| 124 | ✗ | return AVERROR(ENOMEM); | |
| 125 | |||
| 126 | 90 | ret = avio_read(pbc, buf, len); | |
| 127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (ret != len) { |
| 128 | ✗ | if (ret >= 0) | |
| 129 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 130 | ✗ | goto fail; | |
| 131 | } | ||
| 132 | |||
| 133 | 90 | ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); | |
| 134 | 90 | pb = &b.pub; | |
| 135 | |||
| 136 | 90 | parameter_id = ffio_read_leb(pb); | |
| 137 | 90 | param_definition = ff_iamf_get_param_definition(&c->iamf, parameter_id); | |
| 138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | 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 | 90 | audio_element = param_definition->audio_element; | |
| 146 | 90 | param = param_definition->param; | |
| 147 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 32 times.
|
90 | if (!param_definition->mode) { |
| 148 | 58 | duration = ffio_read_leb(pb); | |
| 149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | if (!duration) { |
| 150 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 151 | ✗ | goto fail; | |
| 152 | } | ||
| 153 |
1/2✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
|
58 | if (audio_element) { |
| 154 | 58 | const IAMFCodecConfig *codec_config = ff_iamf_get_codec_config(&c->iamf, audio_element->codec_config_id); | |
| 155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | 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); | |
| 157 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 158 | ✗ | goto fail; | |
| 159 | } | ||
| 160 | } | ||
| 161 | 58 | constant_subblock_duration = ffio_read_leb(pb); | |
| 162 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | if (constant_subblock_duration == 0) |
| 163 | ✗ | nb_subblocks = ffio_read_leb(pb); | |
| 164 | else { | ||
| 165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | if (constant_subblock_duration > duration) { |
| 166 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid block duration in parameter_id %u\n", parameter_id); | |
| 167 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 168 | ✗ | goto fail; | |
| 169 | } | ||
| 170 | 58 | nb_subblocks = duration / constant_subblock_duration; | |
| 171 | 58 | total_duration = duration; | |
| 172 | } | ||
| 173 | } else { | ||
| 174 | 32 | duration = param->duration; | |
| 175 | 32 | constant_subblock_duration = param->constant_subblock_duration; | |
| 176 | 32 | nb_subblocks = param->nb_subblocks; | |
| 177 | } | ||
| 178 | |||
| 179 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (nb_subblocks > duration) { |
| 180 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid duration or subblock count in parameter_id %u\n", parameter_id); | |
| 181 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 182 | ✗ | goto fail; | |
| 183 | } | ||
| 184 | |||
| 185 | 90 | out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size); | |
| 186 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (!out_param) { |
| 187 | ✗ | ret = AVERROR(ENOMEM); | |
| 188 | ✗ | goto fail; | |
| 189 | } | ||
| 190 | |||
| 191 | 90 | out_param->parameter_id = param->parameter_id; | |
| 192 | 90 | out_param->type = param->type; | |
| 193 | 90 | out_param->parameter_rate = param->parameter_rate; | |
| 194 | 90 | out_param->duration = duration; | |
| 195 | 90 | out_param->constant_subblock_duration = constant_subblock_duration; | |
| 196 | 90 | out_param->nb_subblocks = nb_subblocks; | |
| 197 | |||
| 198 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 90 times.
|
180 | for (int i = 0; i < nb_subblocks; i++) { |
| 199 | 90 | void *subblock = av_iamf_param_definition_get_subblock(out_param, i); | |
| 200 | 90 | unsigned int subblock_duration = constant_subblock_duration; | |
| 201 | |||
| 202 |
3/4✓ Branch 0 taken 58 times.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
|
90 | 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); | |
| 206 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 207 | ✗ | goto fail; | |
| 208 | } | ||
| 209 | ✗ | total_duration += subblock_duration; | |
| 210 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | } else if (i == nb_subblocks - 1) |
| 211 | 90 | subblock_duration = duration - i * constant_subblock_duration; | |
| 212 | |||
| 213 |
2/4✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
90 | switch (param->type) { |
| 214 | 58 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { | |
| 215 | 58 | AVIAMFMixGain *mix = subblock; | |
| 216 | |||
| 217 | 58 | mix->animation_type = ffio_read_leb(pb); | |
| 218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | if (mix->animation_type > AV_IAMF_ANIMATION_TYPE_BEZIER) { |
| 219 | ✗ | ret = 0; | |
| 220 | ✗ | av_free(out_param); | |
| 221 | ✗ | goto fail; | |
| 222 | } | ||
| 223 | |||
| 224 | 58 | mix->start_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); | |
| 225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | 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 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | 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 | 58 | mix->subblock_duration = subblock_duration; | |
| 232 | 58 | break; | |
| 233 | } | ||
| 234 | ✗ | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { | |
| 235 | ✗ | AVIAMFDemixingInfo *demix = subblock; | |
| 236 | |||
| 237 | ✗ | demix->dmixp_mode = avio_r8(pb) >> 5; | |
| 238 | ✗ | demix->subblock_duration = subblock_duration; | |
| 239 | ✗ | break; | |
| 240 | } | ||
| 241 | 32 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { | |
| 242 | 32 | AVIAMFReconGain *recon = subblock; | |
| 243 | const AVIAMFAudioElement *element; | ||
| 244 | |||
| 245 |
2/4✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
|
32 | av_assert0(audio_element && audio_element->celement); |
| 246 | 32 | element = audio_element->celement; | |
| 247 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 32 times.
|
96 | for (int i = 0; i < element->nb_layers; i++) { |
| 248 | 64 | const AVIAMFLayer *layer = element->layers[i]; | |
| 249 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
|
64 | if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) { |
| 250 | 32 | unsigned int recon_gain_flags = ffio_read_leb(pb); | |
| 251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | unsigned int bitcount = 7 + 5 * !!(recon_gain_flags & 0x80); |
| 252 | 32 | recon_gain_flags = (recon_gain_flags & 0x7F) | ((recon_gain_flags & 0xFF00) >> 1); | |
| 253 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 32 times.
|
256 | for (int j = 0; j < bitcount; j++) { |
| 254 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 96 times.
|
224 | if (recon_gain_flags & (1 << j)) |
| 255 | 128 | recon->recon_gain[i][j] = avio_r8(pb); | |
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
| 259 | 32 | recon->subblock_duration = subblock_duration; | |
| 260 | 32 | break; | |
| 261 | } | ||
| 262 | ✗ | default: | |
| 263 | ✗ | av_unreachable("param_definition_type should have been checked in descriptor"); | |
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | 90 | len -= avio_tell(pb); | |
| 268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | 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 |
3/6✓ Branch 0 taken 58 times.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
90 | if (!param_definition->mode && !constant_subblock_duration && total_duration != duration) { |
| 274 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid duration in parameter block\n"); | |
| 275 | ✗ | ret = AVERROR_INVALIDDATA; | |
| 276 | ✗ | goto fail; | |
| 277 | } | ||
| 278 | |||
| 279 |
2/4✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
|
90 | switch (param->type) { |
| 280 | 58 | case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: | |
| 281 | 58 | av_free(c->mix); | |
| 282 | 58 | c->mix = out_param; | |
| 283 | 58 | c->mix_size = out_param_size; | |
| 284 | 58 | break; | |
| 285 | ✗ | case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: | |
| 286 | ✗ | av_free(c->demix); | |
| 287 | ✗ | c->demix = out_param; | |
| 288 | ✗ | c->demix_size = out_param_size; | |
| 289 | ✗ | break; | |
| 290 | 32 | case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: | |
| 291 | 32 | av_free(c->recon); | |
| 292 | 32 | c->recon = out_param; | |
| 293 | 32 | c->recon_size = out_param_size; | |
| 294 | 32 | break; | |
| 295 | ✗ | default: | |
| 296 | ✗ | av_unreachable("param_definition_type should have been checked in descriptor"); | |
| 297 | } | ||
| 298 | |||
| 299 | 90 | ret = 0; | |
| 300 | 90 | fail: | |
| 301 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (ret < 0) |
| 302 | ✗ | av_free(out_param); | |
| 303 | 90 | av_free(buf); | |
| 304 | |||
| 305 | 90 | return ret; | |
| 306 | } | ||
| 307 | |||
| 308 | 1916 | int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, | |
| 309 | AVIOContext *pb, int max_size, int stream_id_offset, AVPacket *pkt) | ||
| 310 | { | ||
| 311 | 1916 | int read = 0; | |
| 312 | |||
| 313 | 90 | while (1) { | |
| 314 | 2006 | uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE] = {0}; | |
| 315 | enum IAMF_OBU_Type type; | ||
| 316 | unsigned obu_size; | ||
| 317 | unsigned skip_samples, discard_padding; | ||
| 318 | int ret, len, size, start_pos; | ||
| 319 | |||
| 320 | 2006 | ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
| 321 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2006 times.
|
2006 | if (ret < 0) |
| 322 | 1916 | return ret; | |
| 323 | 2006 | size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); | |
| 324 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1997 times.
|
2006 | if (size < 0) |
| 325 | 9 | return size; | |
| 326 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1997 times.
|
1997 | if (size != FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)) |
| 327 | ✗ | return AVERROR_INVALIDDATA; | |
| 328 | |||
| 329 | 1997 | len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, | |
| 330 | &skip_samples, &discard_padding); | ||
| 331 |
3/6✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1997 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1997 times.
|
1997 | 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 | 1997 | avio_seek(pb, -(size - start_pos), SEEK_CUR); | |
| 336 | |||
| 337 | 1997 | read += len; | |
| 338 |
3/4✓ Branch 0 taken 1907 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 1907 times.
✗ Branch 3 not taken.
|
1997 | if (type >= IAMF_OBU_IA_AUDIO_FRAME && type <= IAMF_OBU_IA_AUDIO_FRAME_ID17) { |
| 339 | 1907 | ret = audio_frame_obu(s, c, pb, pkt, obu_size, type, | |
| 340 | skip_samples, discard_padding, stream_id_offset, | ||
| 341 | type == IAMF_OBU_IA_AUDIO_FRAME); | ||
| 342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1907 times.
|
1907 | if (ret < 0) |
| 343 | ✗ | return ret; | |
| 344 | 1907 | return read; | |
| 345 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | } else if (type == IAMF_OBU_IA_PARAMETER_BLOCK) { |
| 346 | 90 | ret = parameter_block_obu(s, c, pb, obu_size); | |
| 347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | 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 | 90 | max_size -= len; | |
| 362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (max_size < 0) |
| 363 | ✗ | return AVERROR_INVALIDDATA; | |
| 364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | if (!max_size) |
| 365 | ✗ | break; | |
| 366 | } | ||
| 367 | |||
| 368 | ✗ | return read; | |
| 369 | } | ||
| 370 | |||
| 371 | 36 | void ff_iamf_read_deinit(IAMFDemuxContext *c) | |
| 372 | { | ||
| 373 | 36 | IAMFContext *const iamf = &c->iamf; | |
| 374 | |||
| 375 | 36 | ff_iamf_uninit_context(iamf); | |
| 376 | |||
| 377 | 36 | av_freep(&c->mix); | |
| 378 | 36 | c->mix_size = 0; | |
| 379 | 36 | av_freep(&c->demix); | |
| 380 | 36 | c->demix_size = 0; | |
| 381 | 36 | av_freep(&c->recon); | |
| 382 | 36 | c->recon_size = 0; | |
| 383 | 36 | } | |
| 384 |