This is an automated email from the git hooks/post-receive script.
Git pushed a commit to branch release/8.0
in repository ffmpeg.
The following commit(s) were added to refs/heads/release/8.0 by this push:
new 2e803883b7 avformat/iamf: backport assorted fixes
2e803883b7 is described below
commit 2e803883b73d90b767f89b961932919772fde6fe
Author: James Almer <[email protected]>
AuthorDate: Thu Sep 10 16:40:16 2026 -0300
Commit: James Almer <[email protected]>
CommitDate: Tue Sep 15 00:20:51 2026 -0300
avformat/iamf: backport assorted fixes
Too many merge conflics to attempt individual cherry-picks.
Signed-off-by: James Almer <[email protected]>
---
libavformat/iamf_parse.c | 84 ++++++++++++++++++++++++++++++++++++++++++-----
libavformat/iamf_reader.c | 32 ++++++++++++++++--
libavformat/iamf_writer.c | 27 +++++++++++----
3 files changed, 126 insertions(+), 17 deletions(-)
diff --git a/libavformat/iamf_parse.c b/libavformat/iamf_parse.c
index 29b8acd351..87f13069e6 100644
--- a/libavformat/iamf_parse.c
+++ b/libavformat/iamf_parse.c
@@ -406,6 +406,7 @@ static int scalable_channel_layout_config(void *s,
AVIOContext *pb,
int substream_count, coupled_substream_count;
int expanded_loudspeaker_layout = -1;
int ret, byte = avio_r8(pb);
+ int channels;
layer = av_iamf_audio_element_add_layer(audio_element->element);
if (!layer)
@@ -418,7 +419,8 @@ static int scalable_channel_layout_config(void *s,
AVIOContext *pb,
substream_count = avio_r8(pb);
coupled_substream_count = avio_r8(pb);
- if (substream_count + k > audio_element->nb_substreams)
+ if (!substream_count || coupled_substream_count > substream_count ||
+ substream_count + k > audio_element->nb_substreams)
return AVERROR_INVALIDDATA;
audio_element->layers[i].substream_count = substream_count;
@@ -428,8 +430,14 @@ static int scalable_channel_layout_config(void *s,
AVIOContext *pb,
layer->output_gain = av_make_q(sign_extend(avio_rb16(pb), 16), 1
<< 8);
}
- if (!i && loudspeaker_layout == 15)
+ if (loudspeaker_layout == 15) {
+ if (i) {
+ av_log(s, AV_LOG_ERROR, "expanded_loudspeaker_layout set with
more than one layer in Audio Element #%d\n",
+ audio_element->audio_element_id);
+ return AVERROR_INVALIDDATA;
+ }
expanded_loudspeaker_layout = avio_r8(pb);
+ }
if (expanded_loudspeaker_layout >= 0 && expanded_loudspeaker_layout <
13) {
av_channel_layout_copy(&ch_layout,
&ff_iamf_expanded_scalable_ch_layouts[expanded_loudspeaker_layout]);
} else if (loudspeaker_layout < 10) {
@@ -451,7 +459,13 @@ static int scalable_channel_layout_config(void *s,
AVIOContext *pb,
return AVERROR_PATCHWELCOME;
}
- if (i && ch_layout.nb_channels <=
audio_element->element->layers[i-1]->ch_layout.nb_channels)
+ channels = ch_layout.nb_channels;
+ if (i) {
+ if (ch_layout.nb_channels <=
audio_element->element->layers[i-1]->ch_layout.nb_channels)
+ return AVERROR_INVALIDDATA;
+ channels -=
audio_element->element->layers[i-1]->ch_layout.nb_channels;
+ }
+ if (channels != substream_count + coupled_substream_count)
return AVERROR_INVALIDDATA;
for (int j = 0; j < substream_count; j++) {
@@ -489,6 +503,9 @@ static int scalable_channel_layout_config(void *s,
AVIOContext *pb,
}
}
+ if (n != ch_layout.nb_channels)
+ return AVERROR_INVALIDDATA;
+
ret = av_channel_layout_retype(&layer->ch_layout,
AV_CHANNEL_ORDER_NATIVE, 0);
if (ret < 0 && ret != AVERROR(ENOSYS))
return ret;
@@ -590,6 +607,7 @@ static int ambisonics_config(void *s, AVIOContext *pb,
static int param_parse(void *s, IAMFContext *c, AVIOContext *pb,
unsigned int type,
const IAMFAudioElement *audio_element,
+ const IAMFCodecConfig *codec_config,
AVIAMFParamDefinition **out_param_definition)
{
IAMFParamDefinition *param_definition = NULL;
@@ -612,17 +630,29 @@ static int param_parse(void *s, IAMFContext *c,
AVIOContext *pb,
if (mode == 0) {
duration = ffio_read_leb(pb);
- if (!duration)
+ if (!duration || duration > av_rescale(codec_config->nb_samples,
+ codec_config->sample_rate,
parameter_rate)) {
+ av_log(s, AV_LOG_ERROR, "Invalid block duration in parameter_id
%u\n", parameter_id);
return AVERROR_INVALIDDATA;
+ }
constant_subblock_duration = ffio_read_leb(pb);
if (constant_subblock_duration == 0)
nb_subblocks = ffio_read_leb(pb);
else {
+ if (constant_subblock_duration > duration) {
+ av_log(s, AV_LOG_ERROR, "Invalid block duration in
parameter_id %u\n", parameter_id);
+ return AVERROR_INVALIDDATA;
+ }
nb_subblocks = duration / constant_subblock_duration;
total_duration = duration;
}
}
+ if (nb_subblocks > duration) {
+ av_log(s, AV_LOG_ERROR, "Invalid duration or subblock count in
parameter_id %u\n", parameter_id);
+ return AVERROR_INVALIDDATA;
+ }
+
param = av_iamf_param_definition_alloc(type, nb_subblocks, ¶m_size);
if (!param)
return AVERROR(ENOMEM);
@@ -633,6 +663,11 @@ static int param_parse(void *s, IAMFContext *c,
AVIOContext *pb,
if (constant_subblock_duration == 0) {
subblock_duration = ffio_read_leb(pb);
+ if (subblock_duration > duration - total_duration) {
+ av_log(s, AV_LOG_ERROR, "Invalid subblock durations in
parameter_id %u\n", parameter_id);
+ av_free(param);
+ return AVERROR_INVALIDDATA;
+ }
total_duration += subblock_duration;
} else if (i == nb_subblocks - 1)
subblock_duration = duration - i * constant_subblock_duration;
@@ -859,13 +894,17 @@ static int audio_element_obu(void *s, IAMFContext *c,
AVIOContext *pb, int len)
ret = AVERROR_INVALIDDATA;
goto fail;
}
- ret = param_parse(s, c, pbc, type, audio_element,
&element->demixing_info);
+ ret = param_parse(s, c, pbc, type,
+ audio_element, codec_config,
+ &element->demixing_info);
} else if (type == AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN) {
if (element->recon_gain_info) {
ret = AVERROR_INVALIDDATA;
goto fail;
}
- ret = param_parse(s, c, pbc, type, audio_element,
&element->recon_gain_info);
+ ret = param_parse(s, c, pbc, type,
+ audio_element, codec_config,
+ &element->recon_gain_info);
} else {
unsigned param_definition_size = ffio_read_leb(pbc);
avio_skip(pbc, param_definition_size);
@@ -920,6 +959,7 @@ static int label_string(AVIOContext *pb, char **label)
static int mix_presentation_obu(void *s, IAMFContext *c, AVIOContext *pb, int
len)
{
AVIAMFMixPresentation *mix;
+ const IAMFCodecConfig *codec_config = NULL;
IAMFMixPresentation **tmp, *mix_presentation = NULL;
FFIOContext b;
AVIOContext *pbc;
@@ -969,6 +1009,11 @@ static int mix_presentation_obu(void *s, IAMFContext *c,
AVIOContext *pb, int le
mix_presentation->cmix = mix;
mix_presentation->count_label = ffio_read_leb(pbc);
+ if (mix_presentation->count_label > len - avio_tell(pbc)) {
+ mix_presentation->count_label = 0;
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
mix_presentation->language_label = av_calloc(mix_presentation->count_label,
sizeof(*mix_presentation->language_label));
if (!mix_presentation->language_label) {
@@ -995,6 +1040,12 @@ static int mix_presentation_obu(void *s, IAMFContext *c,
AVIOContext *pb, int le
}
nb_submixes = ffio_read_leb(pbc);
+ if (!nb_submixes) {
+ av_log(s, AV_LOG_ERROR, "Mix presentation %u has no submixes\n",
mix_presentation_id);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
for (int i = 0; i < nb_submixes; i++) {
AVIAMFSubmix *sub_mix;
unsigned nb_elements, nb_layouts;
@@ -1006,9 +1057,17 @@ static int mix_presentation_obu(void *s, IAMFContext *c,
AVIOContext *pb, int le
}
nb_elements = ffio_read_leb(pbc);
+ if (!nb_elements) {
+ av_log(s, AV_LOG_ERROR, "Submix %d from Mix presentation %u has no
audio elements\n",
+ i, mix_presentation_id);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
for (int j = 0; j < nb_elements; j++) {
AVIAMFSubmixElement *submix_element;
IAMFAudioElement *audio_element = NULL;
+ const IAMFCodecConfig *config = NULL;
unsigned int rendering_config_extension_size;
submix_element = av_iamf_submix_add_element(sub_mix);
@@ -1031,6 +1090,7 @@ static int mix_presentation_obu(void *s, IAMFContext *c,
AVIOContext *pb, int le
ret = AVERROR_INVALIDDATA;
goto fail;
}
+ config = ff_iamf_get_codec_config(c,
audio_element->codec_config_id);
for (int k = 0; k < mix_presentation->count_label; k++) {
char *annotation = NULL;
@@ -1049,14 +1109,22 @@ static int mix_presentation_obu(void *s, IAMFContext
*c, AVIOContext *pb, int le
avio_skip(pbc, rendering_config_extension_size);
ret = param_parse(s, c, pbc, AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN,
- NULL,
+ audio_element, config,
&submix_element->element_mix_config);
if (ret < 0)
goto fail;
submix_element->default_mix_gain =
av_make_q(sign_extend(avio_rb16(pbc), 16), 1 << 8);
+
+ if (!codec_config || (config->nb_samples >
+ av_rescale(codec_config->nb_samples,
+ codec_config->sample_rate,
+ config->sample_rate)))
+ codec_config = config;
}
- ret = param_parse(s, c, pbc, AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN,
NULL, &sub_mix->output_mix_config);
+ ret = param_parse(s, c, pbc, AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN,
+ NULL, codec_config,
+ &sub_mix->output_mix_config);
if (ret < 0)
goto fail;
sub_mix->default_mix_gain = av_make_q(sign_extend(avio_rb16(pbc), 16),
1 << 8);
diff --git a/libavformat/iamf_reader.c b/libavformat/iamf_reader.c
index 2098f264aa..eab49a8fc0 100644
--- a/libavformat/iamf_reader.c
+++ b/libavformat/iamf_reader.c
@@ -105,6 +105,7 @@ static int audio_frame_obu(AVFormatContext *s, const
IAMFDemuxContext *c,
static int parameter_block_obu(AVFormatContext *s, IAMFDemuxContext *c,
AVIOContext *pbc, int len)
{
+ const IAMFAudioElement *audio_element;
const IAMFParamDefinition *param_definition;
const AVIAMFParamDefinition *param;
AVIAMFParamDefinition *out_param = NULL;
@@ -141,6 +142,7 @@ static int parameter_block_obu(AVFormatContext *s,
IAMFDemuxContext *c,
goto fail;
}
+ audio_element = param_definition->audio_element;
param = param_definition->param;
if (!param_definition->mode) {
duration = ffio_read_leb(pb);
@@ -148,10 +150,23 @@ static int parameter_block_obu(AVFormatContext *s,
IAMFDemuxContext *c,
ret = AVERROR_INVALIDDATA;
goto fail;
}
+ if (audio_element) {
+ const IAMFCodecConfig *codec_config =
ff_iamf_get_codec_config(&c->iamf, audio_element->codec_config_id);
+ if (duration > av_rescale(codec_config->nb_samples,
codec_config->sample_rate, param->parameter_rate)) {
+ av_log(s, AV_LOG_ERROR, "Invalid block duration in
parameter_id %u\n", parameter_id);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ }
constant_subblock_duration = ffio_read_leb(pb);
if (constant_subblock_duration == 0)
nb_subblocks = ffio_read_leb(pb);
else {
+ if (constant_subblock_duration > duration) {
+ av_log(s, AV_LOG_ERROR, "Invalid block duration in
parameter_id %u\n", parameter_id);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
nb_subblocks = duration / constant_subblock_duration;
total_duration = duration;
}
@@ -161,6 +176,12 @@ static int parameter_block_obu(AVFormatContext *s,
IAMFDemuxContext *c,
nb_subblocks = param->nb_subblocks;
}
+ if (nb_subblocks > duration) {
+ av_log(s, AV_LOG_ERROR, "Invalid duration or subblock count in
parameter_id %u\n", parameter_id);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+
out_param = av_iamf_param_definition_alloc(param->type, nb_subblocks,
&out_param_size);
if (!out_param) {
ret = AVERROR(ENOMEM);
@@ -180,6 +201,11 @@ static int parameter_block_obu(AVFormatContext *s,
IAMFDemuxContext *c,
if (!param_definition->mode && !constant_subblock_duration) {
subblock_duration = ffio_read_leb(pb);
+ if (duration - total_duration > subblock_duration) {
+ av_log(s, AV_LOG_ERROR, "Invalid subblock durations in
parameter_id %u\n", parameter_id);
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
total_duration += subblock_duration;
} else if (i == nb_subblocks - 1)
subblock_duration = duration - i * constant_subblock_duration;
@@ -214,10 +240,10 @@ static int parameter_block_obu(AVFormatContext *s,
IAMFDemuxContext *c,
}
case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: {
AVIAMFReconGain *recon = subblock;
- const IAMFAudioElement *audio_element =
param_definition->audio_element;
- const AVIAMFAudioElement *element = audio_element->celement;
+ const AVIAMFAudioElement *element;
- av_assert0(audio_element && element);
+ av_assert0(audio_element && audio_element->celement);
+ element = audio_element->celement;
for (int i = 0; i < element->nb_layers; i++) {
const AVIAMFLayer *layer = element->layers[i];
if (layer->flags & AV_IAMF_LAYER_FLAG_RECON_GAIN) {
diff --git a/libavformat/iamf_writer.c b/libavformat/iamf_writer.c
index 4b2bd87004..dcd8dcfa19 100644
--- a/libavformat/iamf_writer.c
+++ b/libavformat/iamf_writer.c
@@ -100,12 +100,18 @@ static int populate_audio_roll_distance(IAMFCodecConfig
*codec_config)
}
static int fill_codec_config(IAMFContext *iamf, const AVStreamGroup *stg,
- IAMFCodecConfig *codec_config)
+ IAMFCodecConfig *codec_config, void *log_ctx)
{
const AVStream *st = stg->streams[0];
IAMFCodecConfig **tmp;
int j, ret = 0;
+ if (!st->codecpar->frame_size) {
+ av_log(log_ctx, AV_LOG_ERROR, "frame_size is unset for stream id %d\n",
+ st->id);
+ return AVERROR(EINVAL);
+ }
+
codec_config->codec_id = st->codecpar->codec_id;
codec_config->codec_tag = st->codecpar->codec_tag;
switch (codec_config->codec_id) {
@@ -308,7 +314,7 @@ int ff_iamf_add_audio_element(IAMFContext *iamf, const
AVStreamGroup *stg, void
if (!codec_config)
return AVERROR(ENOMEM);
- ret = fill_codec_config(iamf, stg, codec_config);
+ ret = fill_codec_config(iamf, stg, codec_config, log_ctx);
if (ret < 0) {
av_free(codec_config);
return ret;
@@ -733,8 +739,16 @@ static int iamf_write_audio_element(const IAMFContext
*iamf,
int layout = 0, expanded_layout = 0;
get_loudspeaker_layout(element->layers[0], &layout, &expanded_layout);
/* When the loudspeaker_layout = 15, the type
PARAMETER_DEFINITION_DEMIXING SHALL NOT be present. */
- if (layout == 15)
+ if (layout == 15) {
param_definition_types &= ~AV_IAMF_PARAMETER_DEFINITION_DEMIXING;
+ /* expanded_loudspeaker_layout SHALL only be present when
num_layers = 1 and loudspeaker_layout is set to 15 */
+ if (element->nb_layers > 1) {
+ av_log(log_ctx, AV_LOG_ERROR, "expanded_loudspeaker_layout
present when using more than one layer in "
+ "Stream Group #%u\n",
+ audio_element->audio_element_id);
+ return AVERROR(EINVAL);
+ }
+ }
/* When the loudspeaker_layout of the (non-)scalable channel audio
(i.e., num_layers = 1) is less than or equal to 3.1.2ch,
* (i.e., Mono, Stereo, or 3.1.2ch), the type
PARAMETER_DEFINITION_DEMIXING SHALL NOT be present. */
else if (element->nb_layers == 1 && (layout == 0 || layout == 1 ||
layout == 8))
@@ -1222,9 +1236,10 @@ int ff_iamf_write_audio_frame(const IAMFContext *iamf,
AVIOContext *pb,
if (codec_config->codec_id == AV_CODEC_ID_OPUS) {
// IAMF's num_samples_to_trim_at_start is the same as Opus's pre-skip.
- skip_samples = pkt->dts < 0
- ? av_rescale(-pkt->dts, 48000, pkt->time_base.den)
- : 0;
+ if (!skip_samples)
+ skip_samples = pkt->dts < 0
+ ? av_rescale(-pkt->dts, 48000, pkt->time_base.den)
+ : 0;
discard_padding = av_rescale(discard_padding, 48000,
pkt->time_base.den);
}
--
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]