From 44f83786e057d468efee986ee865ba8c776ebe9b Mon Sep 17 00:00:00 2001
From: Lynne <dev@lynne.ee>
Date: Sun, 3 May 2020 21:17:33 +0100
Subject: [PATCH] lavc/bsf: add an Opus metadata bitstream filter

The only adjustable field is the gain. Some ripping/transcoding programs
have started to use it.
---
 libavcodec/Makefile            |  1 +
 libavcodec/bitstream_filters.c |  1 +
 libavcodec/opus_metadata_bsf.c | 72 ++++++++++++++++++++++++++++++++++
 3 files changed, 74 insertions(+)
 create mode 100644 libavcodec/opus_metadata_bsf.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 28076c2c83..cf72f55aff 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1116,6 +1116,7 @@ OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF)  += mp3_header_decompress_bsf.o \
 OBJS-$(CONFIG_MPEG2_METADATA_BSF)         += mpeg2_metadata_bsf.o
 OBJS-$(CONFIG_NOISE_BSF)                  += noise_bsf.o
 OBJS-$(CONFIG_NULL_BSF)                   += null_bsf.o
+OBJS-$(CONFIG_OPUS_METADATA_BSF)          += opus_metadata_bsf.o
 OBJS-$(CONFIG_PRORES_METADATA_BSF)        += prores_metadata_bsf.o
 OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF)       += remove_extradata_bsf.o
 OBJS-$(CONFIG_TEXT2MOVSUB_BSF)            += movsub_bsf.o
diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c
index 6b5ffe4d70..f1b24baa53 100644
--- a/libavcodec/bitstream_filters.c
+++ b/libavcodec/bitstream_filters.c
@@ -49,6 +49,7 @@ extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf;
 extern const AVBitStreamFilter ff_mov2textsub_bsf;
 extern const AVBitStreamFilter ff_noise_bsf;
 extern const AVBitStreamFilter ff_null_bsf;
+extern const AVBitStreamFilter ff_opus_metadata_bsf;
 extern const AVBitStreamFilter ff_prores_metadata_bsf;
 extern const AVBitStreamFilter ff_remove_extradata_bsf;
 extern const AVBitStreamFilter ff_text2movsub_bsf;
diff --git a/libavcodec/opus_metadata_bsf.c b/libavcodec/opus_metadata_bsf.c
new file mode 100644
index 0000000000..f0d794c1b3
--- /dev/null
+++ b/libavcodec/opus_metadata_bsf.c
@@ -0,0 +1,72 @@
+/*
+ * 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 "bsf.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+
+typedef struct OpusBSFContext {
+    const AVClass *class;
+    int64_t gain;
+} OpusBSFContext;
+
+static int opus_metadata_filter(AVBSFContext *bsfc, AVPacket *pkt)
+{
+    return ff_bsf_get_packet_ref(bsfc, pkt);
+}
+
+static int opus_metadata_init(AVBSFContext *bsfc)
+{
+    OpusBSFContext *s = bsfc->priv_data;
+
+    if (bsfc->par_out->extradata_size < 19)
+        return AVERROR_INVALIDDATA;
+
+    AV_WL16(bsfc->par_out->extradata + 16, s->gain);
+
+    return 0;
+}
+
+#define OFFSET(x) offsetof(OpusBSFContext, x)
+#define FLAGS (AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_BSF_PARAM)
+static const AVOption opus_metadata_options[] = {
+    { "gain", "Gain, actual amplification is pow(10, gain/(20.0*256))", OFFSET(gain),
+      AV_OPT_TYPE_INT, { .i64 = 0 }, -(INT16_MAX + 1), INT16_MAX, .flags = FLAGS },
+
+    { NULL },
+};
+
+static const AVClass opus_metadata_class = {
+    .class_name = "opus_metadata_bsf",
+    .item_name  = av_default_item_name,
+    .option     = opus_metadata_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+static const enum AVCodecID codec_ids[] = {
+    AV_CODEC_ID_OPUS, AV_CODEC_ID_NONE,
+};
+
+const AVBitStreamFilter ff_opus_metadata_bsf = {
+    .name           = "opus_metadata",
+    .priv_data_size = sizeof(OpusBSFContext),
+    .priv_class     = &opus_metadata_class,
+    .init           = &opus_metadata_init,
+    .filter         = &opus_metadata_filter,
+    .codec_ids      = codec_ids,
+};
-- 
2.26.2

