[FFmpeg-devel] [PATCH 8/8] avformat: Immersive Audio Model and Formats muxer

2023-12-14 Thread James Almer
Signed-off-by: James Almer 
---
 libavformat/Makefile  |   1 +
 libavformat/allformats.c  |   1 +
 libavformat/iamf_writer.c | 860 ++
 libavformat/iamf_writer.h |  51 +++
 libavformat/iamfenc.c | 387 +
 5 files changed, 1300 insertions(+)
 create mode 100644 libavformat/iamf_writer.c
 create mode 100644 libavformat/iamf_writer.h
 create mode 100644 libavformat/iamfenc.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index f23c22792b..581e378d95 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -259,6 +259,7 @@ 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_MUXER)+= iamfenc.o iamf_writer.o iamf.o
 OBJS-$(CONFIG_ICO_DEMUXER)   += icodec.o
 OBJS-$(CONFIG_ICO_MUXER) += icoenc.o
 OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 6e520b78a6..ce6be5f04d 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -213,6 +213,7 @@ extern const AVInputFormat  ff_hls_demuxer;
 extern const FFOutputFormat ff_hls_muxer;
 extern const AVInputFormat  ff_hnm_demuxer;
 extern const AVInputFormat  ff_iamf_demuxer;
+extern const FFOutputFormat ff_iamf_muxer;
 extern const AVInputFormat  ff_ico_demuxer;
 extern const FFOutputFormat ff_ico_muxer;
 extern const AVInputFormat  ff_idcin_demuxer;
diff --git a/libavformat/iamf_writer.c b/libavformat/iamf_writer.c
new file mode 100644
index 00..9962845049
--- /dev/null
+++ b/libavformat/iamf_writer.c
@@ -0,0 +1,860 @@
+/*
+ * Immersive Audio Model and Formats muxing helpers and structs
+ * Copyright (c) 2023 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/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/iamf.h"
+#include "libavutil/mem.h"
+#include "libavcodec/get_bits.h"
+#include "libavcodec/flac.h"
+#include "libavcodec/mpeg4audio.h"
+#include "libavcodec/put_bits.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "iamf.h"
+#include "iamf_writer.h"
+
+
+static int update_extradata(IAMFCodecConfig *codec_config)
+{
+GetBitContext gb;
+PutBitContext pb;
+int ret;
+
+switch(codec_config->codec_id) {
+case AV_CODEC_ID_OPUS:
+if (codec_config->extradata_size < 19)
+return AVERROR_INVALIDDATA;
+codec_config->extradata_size -= 8;
+memmove(codec_config->extradata, codec_config->extradata + 8, 
codec_config->extradata_size);
+AV_WB8(codec_config->extradata + 1, 2); // set channels to stereo
+break;
+case AV_CODEC_ID_FLAC: {
+uint8_t buf[13];
+
+init_put_bits(&pb, buf, sizeof(buf));
+ret = init_get_bits8(&gb, codec_config->extradata, 
codec_config->extradata_size);
+if (ret < 0)
+return ret;
+
+put_bits32(&pb, get_bits_long(&gb, 32)); // min/max blocksize
+put_bits64(&pb, 48, get_bits64(&gb, 48)); // min/max framesize
+put_bits(&pb, 20, get_bits(&gb, 20)); // samplerate
+skip_bits(&gb, 3);
+put_bits(&pb, 3, 1); // set channels to stereo
+ret = put_bits_left(&pb);
+put_bits(&pb, ret, get_bits(&gb, ret));
+flush_put_bits(&pb);
+
+memcpy(codec_config->extradata, buf, sizeof(buf));
+break;
+}
+default:
+break;
+}
+
+return 0;
+}
+
+static int fill_codec_config(IAMFContext *iamf, const AVStreamGroup *stg,
+ IAMFCodecConfig *codec_config)
+{
+const AVStream *st = stg->streams[0];
+IAMFCodecConfig **tmp;
+int j, ret = 0;
+
+codec_config->codec_id = st->codecpar->codec_id;
+codec_config->sample_rate = st->codecpar->sample_rate;
+codec_config->codec_tag = st->codecpar->codec_tag;
+codec_config->nb_samples = st->codecpar->frame_size;
+codec_config->seek_preroll = st->codecpar->seek_preroll;
+if (st->codecpar->extradata_size) {
+codec_config->extradata = av

[FFmpeg-devel] [PATCH 8/8] avformat: Immersive Audio Model and Formats muxer

2023-12-05 Thread James Almer
Signed-off-by: James Almer 
---
 libavformat/Makefile  |   1 +
 libavformat/allformats.c  |   1 +
 libavformat/iamf_writer.c | 823 ++
 libavformat/iamf_writer.h |  51 +++
 libavformat/iamfenc.c | 388 ++
 5 files changed, 1264 insertions(+)
 create mode 100644 libavformat/iamf_writer.c
 create mode 100644 libavformat/iamf_writer.h
 create mode 100644 libavformat/iamfenc.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index f23c22792b..581e378d95 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -259,6 +259,7 @@ 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_MUXER)+= iamfenc.o iamf_writer.o iamf.o
 OBJS-$(CONFIG_ICO_DEMUXER)   += icodec.o
 OBJS-$(CONFIG_ICO_MUXER) += icoenc.o
 OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 6e520b78a6..ce6be5f04d 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -213,6 +213,7 @@ extern const AVInputFormat  ff_hls_demuxer;
 extern const FFOutputFormat ff_hls_muxer;
 extern const AVInputFormat  ff_hnm_demuxer;
 extern const AVInputFormat  ff_iamf_demuxer;
+extern const FFOutputFormat ff_iamf_muxer;
 extern const AVInputFormat  ff_ico_demuxer;
 extern const FFOutputFormat ff_ico_muxer;
 extern const AVInputFormat  ff_idcin_demuxer;
diff --git a/libavformat/iamf_writer.c b/libavformat/iamf_writer.c
new file mode 100644
index 00..fc31174b53
--- /dev/null
+++ b/libavformat/iamf_writer.c
@@ -0,0 +1,823 @@
+/*
+ * Immersive Audio Model and Formats muxing helpers and structs
+ * Copyright (c) 2023 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/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/iamf.h"
+#include "libavutil/mem.h"
+#include "libavcodec/get_bits.h"
+#include "libavcodec/flac.h"
+#include "libavcodec/mpeg4audio.h"
+#include "libavcodec/put_bits.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "iamf.h"
+#include "iamf_writer.h"
+
+
+static int update_extradata(IAMFCodecConfig *codec_config)
+{
+GetBitContext gb;
+PutBitContext pb;
+int ret;
+
+switch(codec_config->codec_id) {
+case AV_CODEC_ID_OPUS:
+if (codec_config->extradata_size < 19)
+return AVERROR_INVALIDDATA;
+codec_config->extradata_size -= 8;
+memmove(codec_config->extradata, codec_config->extradata + 8, 
codec_config->extradata_size);
+AV_WB8(codec_config->extradata + 1, 2); // set channels to stereo
+break;
+case AV_CODEC_ID_FLAC: {
+uint8_t buf[13];
+
+init_put_bits(&pb, buf, sizeof(buf));
+ret = init_get_bits8(&gb, codec_config->extradata, 
codec_config->extradata_size);
+if (ret < 0)
+return ret;
+
+put_bits32(&pb, get_bits_long(&gb, 32)); // min/max blocksize
+put_bits64(&pb, 48, get_bits64(&gb, 48)); // min/max framesize
+put_bits(&pb, 20, get_bits(&gb, 20)); // samplerate
+skip_bits(&gb, 3);
+put_bits(&pb, 3, 1); // set channels to stereo
+ret = put_bits_left(&pb);
+put_bits(&pb, ret, get_bits(&gb, ret));
+flush_put_bits(&pb);
+
+memcpy(codec_config->extradata, buf, sizeof(buf));
+break;
+}
+default:
+break;
+}
+
+return 0;
+}
+
+static int fill_codec_config(IAMFContext *iamf, const AVStreamGroup *stg,
+ IAMFCodecConfig *codec_config)
+{
+const AVStream *st = stg->streams[0];
+IAMFCodecConfig **tmp;
+int j, ret = 0;
+
+codec_config->codec_id = st->codecpar->codec_id;
+codec_config->sample_rate = st->codecpar->sample_rate;
+codec_config->codec_tag = st->codecpar->codec_tag;
+codec_config->nb_samples = st->codecpar->frame_size;
+codec_config->seek_preroll = st->codecpar->seek_preroll;
+if (st->codecpar->extradata_size) {
+codec_config->extradata = a