From c7266ad60f3dc43e8f2fc22620f20ae9764586db Mon Sep 17 00:00:00 2001 From: James Almer Date: Thu, 15 Feb 2024 19:12:40 -0300 Subject: [PATCH] avformat/iamfdec: further split into shareable modules Signed-off-by: James Almer --- configure | 2 + libavformat/Makefile | 3 +- libavformat/iamf_reader.c | 356 ++++++++++++++++++++++++++++++++++++++ libavformat/iamf_reader.h | 49 ++++++ libavformat/iamfdec.c | 339 ++---------------------------------- 5 files changed, 423 insertions(+), 326 deletions(-) create mode 100644 libavformat/iamf_reader.c create mode 100644 libavformat/iamf_reader.h diff --git a/configure b/configure index 021d30855d..6d1df83d50 100755 --- a/configure +++ b/configure @@ -2516,6 +2516,7 @@ CONFIG_EXTRA=" huffman huffyuvdsp huffyuvencdsp + iamfdec idctdsp iirfilter inflate_wrapper @@ -3534,6 +3535,7 @@ gxf_muxer_select="pcm_rechunk_bsf" hds_muxer_select="flv_muxer" hls_demuxer_select="adts_header ac3_parser mov_demuxer mpegts_demuxer" hls_muxer_select="mov_muxer mpegts_muxer" +iamf_demuxer_select="iamfdec" image2_alias_pix_demuxer_select="image2_demuxer" image2_brender_pix_demuxer_select="image2_demuxer" imf_demuxer_deps="libxml2" diff --git a/libavformat/Makefile b/libavformat/Makefile index 9e8e7c9cb8..3b83f5a685 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -35,6 +35,7 @@ OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o # subsystems OBJS-$(CONFIG_ISO_MEDIA) += isom.o +OBJS-$(CONFIG_IAMFDEC) += iamf_reader.o iamf_parse.o iamf.o OBJS-$(CONFIG_NETWORK) += network.o OBJS-$(CONFIG_RIFFDEC) += riffdec.o OBJS-$(CONFIG_RIFFENC) += riffenc.o @@ -258,7 +259,7 @@ OBJS-$(CONFIG_EVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o hls_sample_encryption.o OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o avc.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o -OBJS-$(CONFIG_IAMF_DEMUXER) += iamfdec.o iamf_parse.o iamf.o +OBJS-$(CONFIG_IAMF_DEMUXER) += iamfdec.o OBJS-$(CONFIG_IAMF_MUXER) += iamfenc.o iamf_writer.o iamf.o OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_ICO_MUXER) += icoenc.o diff --git a/libavformat/iamf_reader.c b/libavformat/iamf_reader.c new file mode 100644 index 0000000000..f63bd94b61 --- /dev/null +++ b/libavformat/iamf_reader.c @@ -0,0 +1,356 @@ +/* + * Immersive Audio Model and Formats demuxing utils + * Copyright (c) 2024 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavcodec/mathops.h" +#include "libavcodec/packet.h" +#include "avformat.h" +#include "avio_internal.h" +#include "iamf.h" +#include "iamf_parse.h" +#include "iamf_reader.h" + +static AVStream *find_stream_by_id(AVFormatContext *s, int id) +{ + for (int i = 0; i < s->nb_streams; i++) + if (s->streams[i]->id == id) + return s->streams[i]; + + av_log(s, AV_LOG_ERROR, "Invalid stream id %d\n", id); + return NULL; +} + +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 id_in_bitstream) +{ + AVStream *st; + int ret, audio_substream_id; + + if (id_in_bitstream) { + unsigned explicit_audio_substream_id; + int64_t pos = avio_tell(pb); + explicit_audio_substream_id = ffio_read_leb(pb); + len -= avio_tell(pb) - pos; + audio_substream_id = explicit_audio_substream_id; + } else + audio_substream_id = type - IAMF_OBU_IA_AUDIO_FRAME_ID0; + + st = find_stream_by_id(s, audio_substream_id); + if (!st) + return AVERROR_INVALIDDATA; + + ret = av_get_packet(pb, pkt, len); + if (ret < 0) + return ret; + if (ret != len) + return AVERROR_INVALIDDATA; + + if (skip_samples || discard_padding) { + uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); + if (!side_data) + return AVERROR(ENOMEM); + AV_WL32(side_data, skip_samples); + AV_WL32(side_data + 4, discard_padding); + } + if (c->mix) { + uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, c->mix_size); + if (!side_data) + return AVERROR(ENOMEM); + memcpy(side_data, c->mix, c->mix_size); + } + if (c->demix) { + uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM, c->demix_size); + if (!side_data) + return AVERROR(ENOMEM); + memcpy(side_data, c->demix, c->demix_size); + } + if (c->recon) { + uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM, c->recon_size); + if (!side_data) + return AVERROR(ENOMEM); + memcpy(side_data, c->recon, c->recon_size); + } + + pkt->stream_index = st->index; + return 0; +} + +static const IAMFParamDefinition *get_param_definition(AVFormatContext *s, + const IAMFDemuxContext *c, + unsigned int parameter_id) +{ + const IAMFContext *const iamf = &c->iamf; + const IAMFParamDefinition *param_definition = NULL; + + for (int i = 0; i < iamf->nb_param_definitions; i++) + if (iamf->param_definitions[i]->param->parameter_id == parameter_id) { + param_definition = iamf->param_definitions[i]; + break; + } + + return param_definition; +} + +static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c, + AVIOContext *pbc, int len) +{ + const IAMFParamDefinition *param_definition; + const AVIAMFParamDefinition *param; + AVIAMFParamDefinition *out_param = NULL; + FFIOContext b; + AVIOContext *pb; + uint8_t *buf; + unsigned int duration, constant_subblock_duration; + unsigned int nb_subblocks; + unsigned int parameter_id; + size_t out_param_size; + int ret; + + buf = av_malloc(len); + if (!buf) + return AVERROR(ENOMEM); + + ret = avio_read(pbc, buf, len); + if (ret != len) { + if (ret >= 0) + ret = AVERROR_INVALIDDATA; + goto fail; + } + + ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); + pb = &b.pub; + + parameter_id = ffio_read_leb(pb); + param_definition = get_param_definition(s, c, parameter_id); + if (!param_definition) { + av_log(s, AV_LOG_VERBOSE, "Non existant parameter_id %d referenced in a parameter block. Ignoring\n", + parameter_id); + ret = 0; + goto fail; + } + + param = param_definition->param; + if (!param_definition->mode) { + duration = ffio_read_leb(pb); + if (!duration) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + constant_subblock_duration = ffio_read_leb(pb); + if (constant_subblock_duration == 0) + nb_subblocks = ffio_read_leb(pb); + else + nb_subblocks = duration / constant_subblock_duration; + } else { + duration = param->duration; + constant_subblock_duration = param->constant_subblock_duration; + nb_subblocks = param->nb_subblocks; + } + + out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size); + if (!out_param) { + ret = AVERROR(ENOMEM); + goto fail; + } + + out_param->parameter_id = param->parameter_id; + out_param->type = param->type; + out_param->parameter_rate = param->parameter_rate; + out_param->duration = duration; + out_param->constant_subblock_duration = constant_subblock_duration; + out_param->nb_subblocks = nb_subblocks; + + for (int i = 0; i < nb_subblocks; i++) { + void *subblock = av_iamf_param_definition_get_subblock(out_param, i); + unsigned int subblock_duration = constant_subblock_duration; + + if (!param_definition->mode && !constant_subblock_duration) + subblock_duration = ffio_read_leb(pb); + + switch (param->type) { + case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { + AVIAMFMixGain *mix = subblock; + + mix->animation_type = ffio_read_leb(pb); + if (mix->animation_type > AV_IAMF_ANIMATION_TYPE_BEZIER) { + ret = 0; + av_free(out_param); + goto fail; + } + + mix->start_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); + if (mix->animation_type >= AV_IAMF_ANIMATION_TYPE_LINEAR) + mix->end_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); + if (mix->animation_type == AV_IAMF_ANIMATION_TYPE_BEZIER) { + mix->control_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); + mix->control_point_relative_time = av_make_q(avio_r8(pb), 1 << 8); + } + mix->subblock_duration = subblock_duration; + break; + } + case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { + AVIAMFDemixingInfo *demix = subblock; + + demix->dmixp_mode = avio_r8(pb) >> 5; + demix->subblock_duration = subblock_duration; + break; + } + case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { + AVIAMFReconGain *recon = subblock; + const IAMFAudioElement *audio_element = param_definition->audio_element; + const AVIAMFAudioElement *element = audio_element->celement; + + av_assert0(audio_element && element); + for (int i = 0; i < element->nb_layers; i++) { + const AVIAMFLayer *layer = element->layers[i]; + if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) { + unsigned int recon_gain_flags = ffio_read_leb(pb); + unsigned int bitcount = 7 + 5 * !!(recon_gain_flags & 0x80); + recon_gain_flags = (recon_gain_flags & 0x7F) | ((recon_gain_flags & 0xFF00) >> 1); + for (int j = 0; j < bitcount; j++) { + if (recon_gain_flags & (1 << j)) + recon->recon_gain[i][j] = avio_r8(pb); + } + } + } + recon->subblock_duration = subblock_duration; + break; + } + default: + av_assert0(0); + } + } + + len -= avio_tell(pb); + if (len) { + int level = (s->error_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING; + av_log(s, level, "Underread in parameter_block_obu. %d bytes left at the end\n", len); + } + + switch (param->type) { + case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: + av_free(c->mix); + c->mix = out_param; + c->mix_size = out_param_size; + break; + case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: + av_free(c->demix); + c->demix = out_param; + c->demix_size = out_param_size; + break; + case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: + av_free(c->recon); + c->recon = out_param; + c->recon_size = out_param_size; + break; + default: + av_assert0(0); + } + + ret = 0; +fail: + if (ret < 0) + av_free(out_param); + av_free(buf); + + return ret; +} + +int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, + AVIOContext *pb, int max_size, AVPacket *pkt) +{ + int read = 0; + + while (1) { + uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; + enum IAMF_OBU_Type type; + unsigned obu_size; + unsigned skip_samples, discard_padding; + int ret, len, size, start_pos; + + if ((ret = ffio_ensure_seekback(pb, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size))) < 0) + return ret; + size = avio_read(pb, header, FFMIN(MAX_IAMF_OBU_HEADER_SIZE, max_size)); + if (size < 0) + return size; + + len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, + &skip_samples, &discard_padding); + if (len < 0 || obu_size > max_size) { + av_log(s, AV_LOG_ERROR, "Failed to read obu\n"); + return len; + } + avio_seek(pb, -(size - start_pos), SEEK_CUR); + + read += len; + if (type >= IAMF_OBU_IA_AUDIO_FRAME && type <= IAMF_OBU_IA_AUDIO_FRAME_ID17) { + ret = audio_frame_obu(s, c, pb, pkt, obu_size, type, + skip_samples, discard_padding, + type == IAMF_OBU_IA_AUDIO_FRAME); + if (ret < 0) + return ret; + return read; + } else if (type == IAMF_OBU_IA_PARAMETER_BLOCK) { + ret = parameter_block_obu(s, c, pb, obu_size); + if (ret < 0) + return ret; + } else if (type == IAMF_OBU_IA_TEMPORAL_DELIMITER) { + av_freep(&c->mix); + c->mix_size = 0; + av_freep(&c->demix); + c->demix_size = 0; + av_freep(&c->recon); + c->recon_size = 0; + } else { + int64_t offset = avio_skip(pb, obu_size); + if (offset < 0) { + ret = offset; + break; + } + } + max_size -= len; + if (max_size < 0) + return AVERROR_INVALIDDATA; + if (!max_size) + break; + } + + return read; +} + +void ff_iamf_read_deinit(IAMFDemuxContext *c) +{ + IAMFContext *const iamf = &c->iamf; + + ff_iamf_uninit_context(iamf); + + av_freep(&c->mix); + c->mix_size = 0; + av_freep(&c->demix); + c->demix_size = 0; + av_freep(&c->recon); + c->recon_size = 0; +} diff --git a/libavformat/iamf_reader.h b/libavformat/iamf_reader.h new file mode 100644 index 0000000000..ecb92d485a --- /dev/null +++ b/libavformat/iamf_reader.h @@ -0,0 +1,49 @@ +/* + * Immersive Audio Model and Formats demuxing utils + * Copyright (c) 2024 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_IAMF_READER_H +#define AVFORMAT_IAMF_READER_H + +#include + +#include "libavcodec/packet.h" +#include "avformat.h" +#include "avio.h" +#include "iamf.h" + +typedef struct IAMFDemuxContext { + IAMFContext iamf; + + // Packet side data + AVIAMFParamDefinition *mix; + size_t mix_size; + AVIAMFParamDefinition *demix; + size_t demix_size; + AVIAMFParamDefinition *recon; + size_t recon_size; +} IAMFDemuxContext; + +int ff_iamf_read_packet(AVFormatContext *s, IAMFDemuxContext *c, + AVIOContext *pb, int max_size, AVPacket *pkt); + +void ff_iamf_read_deinit(IAMFDemuxContext *c); + +#endif /* AVFORMAT_IAMF_READER_H */ diff --git a/libavformat/iamfdec.c b/libavformat/iamfdec.c index 9b3f4c7429..de4d502f5a 100644 --- a/libavformat/iamfdec.c +++ b/libavformat/iamfdec.c @@ -20,329 +20,13 @@ */ #include "libavutil/avassert.h" -#include "libavutil/iamf.h" #include "libavutil/intreadwrite.h" -#include "libavutil/log.h" -#include "libavcodec/mathops.h" #include "avformat.h" -#include "avio_internal.h" #include "iamf.h" +#include "iamf_reader.h" #include "iamf_parse.h" #include "internal.h" -typedef struct IAMFDemuxContext { - IAMFContext iamf; - - // Packet side data - AVIAMFParamDefinition *mix; - size_t mix_size; - AVIAMFParamDefinition *demix; - size_t demix_size; - AVIAMFParamDefinition *recon; - size_t recon_size; -} IAMFDemuxContext; - -static AVStream *find_stream_by_id(AVFormatContext *s, int id) -{ - for (int i = 0; i < s->nb_streams; i++) - if (s->streams[i]->id == id) - return s->streams[i]; - - av_log(s, AV_LOG_ERROR, "Invalid stream id %d\n", id); - return NULL; -} - -static int audio_frame_obu(AVFormatContext *s, AVPacket *pkt, int len, - enum IAMF_OBU_Type type, - unsigned skip_samples, unsigned discard_padding, - int id_in_bitstream) -{ - const IAMFDemuxContext *const c = s->priv_data; - AVStream *st; - int ret, audio_substream_id; - - if (id_in_bitstream) { - unsigned explicit_audio_substream_id; - int64_t pos = avio_tell(s->pb); - explicit_audio_substream_id = ffio_read_leb(s->pb); - len -= avio_tell(s->pb) - pos; - audio_substream_id = explicit_audio_substream_id; - } else - audio_substream_id = type - IAMF_OBU_IA_AUDIO_FRAME_ID0; - - st = find_stream_by_id(s, audio_substream_id); - if (!st) - return AVERROR_INVALIDDATA; - - ret = av_get_packet(s->pb, pkt, len); - if (ret < 0) - return ret; - if (ret != len) - return AVERROR_INVALIDDATA; - - if (skip_samples || discard_padding) { - uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); - if (!side_data) - return AVERROR(ENOMEM); - AV_WL32(side_data, skip_samples); - AV_WL32(side_data + 4, discard_padding); - } - if (c->mix) { - uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, c->mix_size); - if (!side_data) - return AVERROR(ENOMEM); - memcpy(side_data, c->mix, c->mix_size); - } - if (c->demix) { - uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM, c->demix_size); - if (!side_data) - return AVERROR(ENOMEM); - memcpy(side_data, c->demix, c->demix_size); - } - if (c->recon) { - uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM, c->recon_size); - if (!side_data) - return AVERROR(ENOMEM); - memcpy(side_data, c->recon, c->recon_size); - } - - pkt->stream_index = st->index; - return 0; -} - -static const IAMFParamDefinition *get_param_definition(AVFormatContext *s, unsigned int parameter_id) -{ - const IAMFDemuxContext *const c = s->priv_data; - const IAMFContext *const iamf = &c->iamf; - const IAMFParamDefinition *param_definition = NULL; - - for (int i = 0; i < iamf->nb_param_definitions; i++) - if (iamf->param_definitions[i]->param->parameter_id == parameter_id) { - param_definition = iamf->param_definitions[i]; - break; - } - - return param_definition; -} - -static int parameter_block_obu(AVFormatContext *s, int len) -{ - IAMFDemuxContext *const c = s->priv_data; - const IAMFParamDefinition *param_definition; - const AVIAMFParamDefinition *param; - AVIAMFParamDefinition *out_param = NULL; - FFIOContext b; - AVIOContext *pb; - uint8_t *buf; - unsigned int duration, constant_subblock_duration; - unsigned int nb_subblocks; - unsigned int parameter_id; - size_t out_param_size; - int ret; - - buf = av_malloc(len); - if (!buf) - return AVERROR(ENOMEM); - - ret = avio_read(s->pb, buf, len); - if (ret != len) { - if (ret >= 0) - ret = AVERROR_INVALIDDATA; - goto fail; - } - - ffio_init_context(&b, buf, len, 0, NULL, NULL, NULL, NULL); - pb = &b.pub; - - parameter_id = ffio_read_leb(pb); - param_definition = get_param_definition(s, parameter_id); - if (!param_definition) { - av_log(s, AV_LOG_VERBOSE, "Non existant parameter_id %d referenced in a parameter block. Ignoring\n", - parameter_id); - ret = 0; - goto fail; - } - - param = param_definition->param; - if (!param_definition->mode) { - duration = ffio_read_leb(pb); - if (!duration) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - constant_subblock_duration = ffio_read_leb(pb); - if (constant_subblock_duration == 0) - nb_subblocks = ffio_read_leb(pb); - else - nb_subblocks = duration / constant_subblock_duration; - } else { - duration = param->duration; - constant_subblock_duration = param->constant_subblock_duration; - nb_subblocks = param->nb_subblocks; - } - - out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks, &out_param_size); - if (!out_param) { - ret = AVERROR(ENOMEM); - goto fail; - } - - out_param->parameter_id = param->parameter_id; - out_param->type = param->type; - out_param->parameter_rate = param->parameter_rate; - out_param->duration = duration; - out_param->constant_subblock_duration = constant_subblock_duration; - out_param->nb_subblocks = nb_subblocks; - - for (int i = 0; i < nb_subblocks; i++) { - void *subblock = av_iamf_param_definition_get_subblock(out_param, i); - unsigned int subblock_duration = constant_subblock_duration; - - if (!param_definition->mode && !constant_subblock_duration) - subblock_duration = ffio_read_leb(pb); - - switch (param->type) { - case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: { - AVIAMFMixGain *mix = subblock; - - mix->animation_type = ffio_read_leb(pb); - if (mix->animation_type > AV_IAMF_ANIMATION_TYPE_BEZIER) { - ret = 0; - av_free(out_param); - goto fail; - } - - mix->start_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); - if (mix->animation_type >= AV_IAMF_ANIMATION_TYPE_LINEAR) - mix->end_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); - if (mix->animation_type == AV_IAMF_ANIMATION_TYPE_BEZIER) { - mix->control_point_value = av_make_q(sign_extend(avio_rb16(pb), 16), 1 << 8); - mix->control_point_relative_time = av_make_q(avio_r8(pb), 1 << 8); - } - mix->subblock_duration = subblock_duration; - break; - } - case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: { - AVIAMFDemixingInfo *demix = subblock; - - demix->dmixp_mode = avio_r8(pb) >> 5; - demix->subblock_duration = subblock_duration; - break; - } - case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: { - AVIAMFReconGain *recon = subblock; - const IAMFAudioElement *audio_element = param_definition->audio_element; - const AVIAMFAudioElement *element = audio_element->celement; - - av_assert0(audio_element && element); - for (int i = 0; i < element->nb_layers; i++) { - const AVIAMFLayer *layer = element->layers[i]; - if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) { - unsigned int recon_gain_flags = ffio_read_leb(pb); - unsigned int bitcount = 7 + 5 * !!(recon_gain_flags & 0x80); - recon_gain_flags = (recon_gain_flags & 0x7F) | ((recon_gain_flags & 0xFF00) >> 1); - for (int j = 0; j < bitcount; j++) { - if (recon_gain_flags & (1 << j)) - recon->recon_gain[i][j] = avio_r8(pb); - } - } - } - recon->subblock_duration = subblock_duration; - break; - } - default: - av_assert0(0); - } - } - - len -= avio_tell(pb); - if (len) { - int level = (s->error_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING; - av_log(s, level, "Underread in parameter_block_obu. %d bytes left at the end\n", len); - } - - switch (param->type) { - case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: - av_free(c->mix); - c->mix = out_param; - c->mix_size = out_param_size; - break; - case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: - av_free(c->demix); - c->demix = out_param; - c->demix_size = out_param_size; - break; - case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: - av_free(c->recon); - c->recon = out_param; - c->recon_size = out_param_size; - break; - default: - av_assert0(0); - } - - ret = 0; -fail: - if (ret < 0) - av_free(out_param); - av_free(buf); - - return ret; -} - -static int iamf_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - IAMFDemuxContext *const c = s->priv_data; - uint8_t header[MAX_IAMF_OBU_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; - unsigned obu_size; - int ret; - - while (1) { - enum IAMF_OBU_Type type; - unsigned skip_samples, discard_padding; - int len, size, start_pos; - - if ((ret = ffio_ensure_seekback(s->pb, MAX_IAMF_OBU_HEADER_SIZE)) < 0) - return ret; - size = avio_read(s->pb, header, MAX_IAMF_OBU_HEADER_SIZE); - if (size < 0) - return size; - - len = ff_iamf_parse_obu_header(header, size, &obu_size, &start_pos, &type, - &skip_samples, &discard_padding); - if (len < 0) { - av_log(s, AV_LOG_ERROR, "Failed to read obu\n"); - return len; - } - avio_seek(s->pb, -(size - start_pos), SEEK_CUR); - - if (type >= IAMF_OBU_IA_AUDIO_FRAME && type <= IAMF_OBU_IA_AUDIO_FRAME_ID17) - return audio_frame_obu(s, pkt, obu_size, type, - skip_samples, discard_padding, - type == IAMF_OBU_IA_AUDIO_FRAME); - else if (type == IAMF_OBU_IA_PARAMETER_BLOCK) { - ret = parameter_block_obu(s, obu_size); - if (ret < 0) - return ret; - } else if (type == IAMF_OBU_IA_TEMPORAL_DELIMITER) { - av_freep(&c->mix); - c->mix_size = 0; - av_freep(&c->demix); - c->demix_size = 0; - av_freep(&c->recon); - c->recon_size = 0; - } else { - int64_t offset = avio_skip(s->pb, obu_size); - if (offset < 0) { - ret = offset; - break; - } - } - } - - return ret; -} - //return < 0 if we need more data static int get_score(const uint8_t *buf, int buf_size, enum IAMF_OBU_Type type, int *seq) { @@ -468,18 +152,23 @@ static int iamf_read_header(AVFormatContext *s) return 0; } +static int iamf_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + IAMFDemuxContext *const c = s->priv_data; + int ret; + + ret = ff_iamf_read_packet(s, c, s->pb, INT_MAX, pkt); + if (ret < 0) + return ret; + + return 0; +} + static int iamf_read_close(AVFormatContext *s) { IAMFDemuxContext *const c = s->priv_data; - ff_iamf_uninit_context(&c->iamf); - - av_freep(&c->mix); - c->mix_size = 0; - av_freep(&c->demix); - c->demix_size = 0; - av_freep(&c->recon); - c->recon_size = 0; + ff_iamf_read_deinit(c); return 0; }