FFmpeg
iamfenc.c
Go to the documentation of this file.
1 /*
2  * IAMF muxer
3  * Copyright (c) 2023 James Almer
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 <stdint.h>
23 
24 #include "avformat.h"
25 #include "iamf.h"
26 #include "iamf_writer.h"
27 #include "internal.h"
28 #include "mux.h"
29 
30 typedef struct IAMFMuxContext {
32 
35 
38 
40 {
41  IAMFMuxContext *const c = s->priv_data;
42  IAMFContext *const iamf = &c->iamf;
43  int nb_audio_elements = 0, nb_mix_presentations = 0;
44  int ret;
45 
46  for (int i = 0; i < s->nb_streams; i++) {
47  if (s->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
48  (s->streams[i]->codecpar->codec_tag != MKTAG('m','p','4','a') &&
49  s->streams[i]->codecpar->codec_tag != MKTAG('O','p','u','s') &&
50  s->streams[i]->codecpar->codec_tag != MKTAG('f','L','a','C') &&
51  s->streams[i]->codecpar->codec_tag != MKTAG('i','p','c','m'))) {
52  av_log(s, AV_LOG_ERROR, "Unsupported codec id %s\n",
53  avcodec_get_name(s->streams[i]->codecpar->codec_id));
54  return AVERROR(EINVAL);
55  }
56 
57  if (s->streams[i]->codecpar->ch_layout.nb_channels > 2) {
58  av_log(s, AV_LOG_ERROR, "Unsupported channel layout on stream #%d\n", i);
59  return AVERROR(EINVAL);
60  }
61 
62  for (int j = 0; j < i; j++) {
63  if (s->streams[i]->id == s->streams[j]->id) {
64  av_log(s, AV_LOG_ERROR, "Duplicated stream id %d\n", s->streams[j]->id);
65  return AVERROR(EINVAL);
66  }
67  }
68  }
69 
70  if (s->nb_stream_groups <= 1) {
71  av_log(s, AV_LOG_ERROR, "There must be at least two stream groups\n");
72  return AVERROR(EINVAL);
73  }
74 
75  for (int i = 0; i < s->nb_stream_groups; i++) {
76  const AVStreamGroup *stg = s->stream_groups[i];
77 
79  nb_audio_elements++;
81  nb_mix_presentations++;
82  }
83  if ((nb_audio_elements < 1 || nb_audio_elements > 2) || nb_mix_presentations < 1) {
84  av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
85  "one IAMF_MIX_PRESENTATION stream groups\n");
86  return AVERROR(EINVAL);
87  }
88 
89  for (int i = 0; i < s->nb_stream_groups; i++) {
90  const AVStreamGroup *stg = s->stream_groups[i];
92  continue;
93 
94  ret = ff_iamf_add_audio_element(iamf, stg, s);
95  if (ret < 0)
96  return ret;
97  }
98 
99  for (int i = 0; i < s->nb_stream_groups; i++) {
100  const AVStreamGroup *stg = s->stream_groups[i];
102  continue;
103 
104  ret = ff_iamf_add_mix_presentation(iamf, stg, s);
105  if (ret < 0)
106  return ret;
107  }
108 
109  c->first_stream_id = s->streams[0]->id;
110 
111  return 0;
112 }
113 
115 {
116  IAMFMuxContext *const c = s->priv_data;
117  IAMFContext *const iamf = &c->iamf;
118  int ret;
119 
120  c->descriptors_offset = avio_tell(s->pb);
121  ret = ff_iamf_write_descriptors(iamf, s->pb, s);
122  if (ret < 0)
123  return ret;
124 
125  c->first_stream_id = s->streams[0]->id;
126 
127  return 0;
128 }
129 
131 {
132  IAMFMuxContext *const c = s->priv_data;
133  AVStream *st = s->streams[pkt->stream_index];
134  int ret = 0;
135 
136  if (st->id == c->first_stream_id)
137  ret = ff_iamf_write_parameter_blocks(&c->iamf, s->pb, pkt, s);
138  if (!ret)
139  ret = ff_iamf_write_audio_frame(&c->iamf, s->pb, st->id, pkt);
140  if (!ret && !pkt->size)
141  c->update_extradata = 1;
142 
143  return ret;
144 }
145 
147 {
148  const IAMFMuxContext *const c = s->priv_data;
149  const IAMFContext *const iamf = &c->iamf;
150  int64_t pos;
151  int ret;
152 
153  if (!c->update_extradata || !(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
154  return 0;
155 
156  pos = avio_tell(s->pb);
157  avio_seek(s->pb, c->descriptors_offset, SEEK_SET);
158  ret = ff_iamf_write_descriptors(iamf, s->pb, s);
159  if (ret < 0)
160  return ret;
161 
162  avio_seek(s->pb, pos, SEEK_SET);
163 
164  return 0;
165 }
166 
168 {
169  IAMFMuxContext *const c = s->priv_data;
170  IAMFContext *const iamf = &c->iamf;
171 
173 }
174 
175 static const AVCodecTag iamf_codec_tags[] = {
176  { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
177  { AV_CODEC_ID_FLAC, MKTAG('f','L','a','C') },
178  { AV_CODEC_ID_OPUS, MKTAG('O','p','u','s') },
179  { AV_CODEC_ID_PCM_S16LE, MKTAG('i','p','c','m') },
180  { AV_CODEC_ID_PCM_S16BE, MKTAG('i','p','c','m') },
181  { AV_CODEC_ID_PCM_S24LE, MKTAG('i','p','c','m') },
182  { AV_CODEC_ID_PCM_S24BE, MKTAG('i','p','c','m') },
183  { AV_CODEC_ID_PCM_S32LE, MKTAG('i','p','c','m') },
184  { AV_CODEC_ID_PCM_S32BE, MKTAG('i','p','c','m') },
185  { AV_CODEC_ID_NONE, MKTAG('i','p','c','m') }
186 };
187 
189  .p.name = "iamf",
190  .p.long_name = NULL_IF_CONFIG_SMALL("Raw Immersive Audio Model and Formats"),
191  .p.extensions = "iamf",
192  .priv_data_size = sizeof(IAMFMuxContext),
193  .p.audio_codec = AV_CODEC_ID_OPUS,
194  .init = iamf_init,
195  .deinit = iamf_deinit,
196  .write_header = iamf_write_header,
197  .write_packet = iamf_write_packet,
198  .write_trailer = iamf_write_trailer,
199  .p.codec_tag = (const AVCodecTag* const []){ iamf_codec_tags, NULL },
201 };
AV_CODEC_ID_PCM_S16LE
@ AV_CODEC_ID_PCM_S16LE
Definition: codec_id.h:334
iamf_write_header
static int iamf_write_header(AVFormatContext *s)
Definition: iamfenc.c:114
IAMFMuxContext::descriptors_offset
int64_t descriptors_offset
Definition: iamfenc.c:33
AVOutputFormat::name
const char * name
Definition: avformat.h:510
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
AVFMT_NOTIMESTAMPS
#define AVFMT_NOTIMESTAMPS
Format does not need / have any timestamps.
Definition: avformat.h:479
int64_t
long long int64_t
Definition: coverity.c:34
AV_CODEC_ID_FLAC
@ AV_CODEC_ID_FLAC
Definition: codec_id.h:458
FFOutputFormat::p
AVOutputFormat p
The public AVOutputFormat.
Definition: mux.h:65
AV_CODEC_ID_PCM_S16BE
@ AV_CODEC_ID_PCM_S16BE
Definition: codec_id.h:335
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
IAMFMuxContext::update_extradata
int update_extradata
Definition: iamfenc.c:34
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
iamf_write_packet
static int iamf_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: iamfenc.c:130
AVCodecTag
Definition: internal.h:42
AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION
@ AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION
Definition: avformat.h:1126
ff_iamf_add_audio_element
int ff_iamf_add_audio_element(IAMFContext *iamf, const AVStreamGroup *stg, void *log_ctx)
Definition: iamf_writer.c:203
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVFormatContext
Format I/O context.
Definition: avformat.h:1300
internal.h
NULL
#define NULL
Definition: coverity.c:32
FFOutputFormat
Definition: mux.h:61
ff_iamf_add_mix_presentation
int ff_iamf_add_mix_presentation(IAMFContext *iamf, const AVStreamGroup *stg, void *log_ctx)
Definition: iamf_writer.c:369
IAMFMuxContext
Definition: iamfenc.c:30
IAMFMuxContext::first_stream_id
int first_stream_id
Definition: iamfenc.c:36
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: codec_id.h:448
AV_CODEC_ID_PCM_S24LE
@ AV_CODEC_ID_PCM_S24LE
Definition: codec_id.h:346
AVPacket::size
int size
Definition: packet.h:540
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
ff_iamf_uninit_context
void ff_iamf_uninit_context(IAMFContext *c)
Definition: iamf.c:99
ff_iamf_write_parameter_blocks
int ff_iamf_write_parameter_blocks(const IAMFContext *iamf, AVIOContext *pb, const AVPacket *pkt, void *log_ctx)
Definition: iamf_writer.c:1027
AV_CODEC_ID_OPUS
@ AV_CODEC_ID_OPUS
Definition: codec_id.h:506
IAMFContext
Definition: iamf.h:128
AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
@ AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT
Definition: avformat.h:1125
avcodec_get_name
const char * avcodec_get_name(enum AVCodecID id)
Get the name of a codec.
Definition: utils.c:409
AVFMT_GLOBALHEADER
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:478
AV_CODEC_ID_NONE
@ AV_CODEC_ID_NONE
Definition: codec_id.h:50
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
iamf_write_trailer
static int iamf_write_trailer(AVFormatContext *s)
Definition: iamfenc.c:146
AV_CODEC_ID_PCM_S32BE
@ AV_CODEC_ID_PCM_S32BE
Definition: codec_id.h:343
ff_iamf_write_audio_frame
int ff_iamf_write_audio_frame(const IAMFContext *iamf, AVIOContext *pb, unsigned audio_substream_id, const AVPacket *pkt)
Definition: iamf_writer.c:1077
ff_iamf_write_descriptors
int ff_iamf_write_descriptors(const IAMFContext *iamf, AVIOContext *pb, void *log_ctx)
Definition: iamf_writer.c:869
AVStream::id
int id
Format-specific stream ID.
Definition: avformat.h:760
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:748
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:231
pos
unsigned int pos
Definition: spdifenc.c:414
avformat.h
ff_iamf_muxer
const FFOutputFormat ff_iamf_muxer
Definition: iamfenc.c:188
AVStreamGroup
Definition: avformat.h:1134
iamf_deinit
static void iamf_deinit(AVFormatContext *s)
Definition: iamfenc.c:167
iamf_codec_tags
static const AVCodecTag iamf_codec_tags[]
Definition: iamfenc.c:175
AVIO_SEEKABLE_NORMAL
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition: avio.h:41
AVPacket::stream_index
int stream_index
Definition: packet.h:541
AV_CODEC_ID_PCM_S32LE
@ AV_CODEC_ID_PCM_S32LE
Definition: codec_id.h:342
AVStreamGroup::type
enum AVStreamGroupParamsType type
Group type.
Definition: avformat.h:1161
iamf_init
static int iamf_init(AVFormatContext *s)
Definition: iamfenc.c:39
AVPacket
This structure stores compressed data.
Definition: packet.h:516
iamf.h
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
MKTAG
#define MKTAG(a, b, c, d)
Definition: macros.h:55
AV_CODEC_ID_PCM_S24BE
@ AV_CODEC_ID_PCM_S24BE
Definition: codec_id.h:347
IAMFMuxContext::iamf
IAMFContext iamf
Definition: iamfenc.c:31
iamf_writer.h
mux.h