[FFmpeg-devel] [PATCH 2/2] lavfi: Add libspatialaudio filter
Marvin Scholz
epirat07 at gmail.com
Mon Nov 25 12:43:09 EET 2024
---
configure | 5 +
libavfilter/Makefile | 1 +
libavfilter/af_libspatialaudio.cpp | 294 ++++++++++++++++++++++++
libavfilter/af_libspatialaudio_c.c | 199 ++++++++++++++++
libavfilter/af_libspatialaudio_common.h | 47 ++++
libavfilter/allfilters.c | 1 +
6 files changed, 547 insertions(+)
create mode 100644 libavfilter/af_libspatialaudio.cpp
create mode 100644 libavfilter/af_libspatialaudio_c.c
create mode 100644 libavfilter/af_libspatialaudio_common.h
diff --git a/configure b/configure
index ff26aa2da7..30b3a35d64 100755
--- a/configure
+++ b/configure
@@ -274,6 +274,7 @@ External library support:
--enable-libsmbclient enable Samba protocol via libsmbclient [no]
--enable-libsnappy enable Snappy compression, needed for hap encoding [no]
--enable-libsoxr enable Include libsoxr resampling [no]
+ --enable-libspatialaudio enable ambisonics/binaural renderer support via libspatialaudio [no]
--enable-libspeex enable Speex de/encoding via libspeex [no]
--enable-libsrt enable Haivision SRT protocol via libsrt [no]
--enable-libssh enable SFTP protocol via libssh [no]
@@ -1991,6 +1992,7 @@ EXTERNAL_LIBRARY_LIST="
libsnappy
libsoxr
libspeex
+ libspatialaudio
libsrt
libssh
libsvtav1
@@ -3994,6 +3996,8 @@ signature_filter_deps="gpl avcodec avformat"
smartblur_filter_deps="gpl swscale"
sobel_opencl_filter_deps="opencl"
sofalizer_filter_deps="libmysofa"
+libspatialaudio_filter_deps="libspatialaudio"
+libspatialaudio_filter_extralibs="-lstdc++"
spp_filter_deps="gpl avcodec"
spp_filter_select="idctdsp fdctdsp me_cmp pixblockdsp"
sr_filter_deps="avformat swscale"
@@ -7043,6 +7047,7 @@ enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnap
enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr
enabled libssh && require_pkg_config libssh "libssh >= 0.6.0" libssh/sftp.h sftp_init
enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init
+enabled libspatialaudio && require_pkg_config_cxx libspatialaudio "spatialaudio >= 0.3.1" spatialaudio/Ambisonics.h "CAmbisonicDecoder"
enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket
enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle
enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 4d9681768b..f47d8a9912 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -154,6 +154,7 @@ OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o
OBJS-$(CONFIG_LOUDNORM_FILTER) += af_loudnorm.o ebur128.o
OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o
OBJS-$(CONFIG_LOWSHELF_FILTER) += af_biquads.o
+OBJS-$(CONFIG_LIBSPATIALAUDIO_FILTER) += af_libspatialaudio_c.o af_libspatialaudio.o
OBJS-$(CONFIG_LV2_FILTER) += af_lv2.o
OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o
OBJS-$(CONFIG_PAN_FILTER) += af_pan.o
diff --git a/libavfilter/af_libspatialaudio.cpp b/libavfilter/af_libspatialaudio.cpp
new file mode 100644
index 0000000000..593cf5400b
--- /dev/null
+++ b/libavfilter/af_libspatialaudio.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2024 Marvin Scholz
+ * Copyright (C) 2017 VLC authors and VideoLAN
+ *
+ * Authors: Marvin Scholz <epirat07 at gmail.com>
+ *
+ * Heavily inspired from VLC media players' spatialaudio.cpp
+ * Authors: Adrien Maglo <magsoft at videolan.org>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ */
+
+extern "C" {
+ #include "libavutil/avassert.h"
+ #include "libavutil/mem.h"
+ #include "avfilter.h"
+ #include "filters.h"
+ #include "libavfilter/af_libspatialaudio_common.h"
+}
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+#include <map>
+
+#include <spatialaudio/Ambisonics.h>
+#include <spatialaudio/SpeakersBinauralizer.h>
+
+struct SpatialaudioContext
+{
+ SpatialaudioContext() {}
+
+ ~SpatialaudioContext() {}
+
+ enum SpatialaudioMode
+ {
+ AMBISONICS_DECODER = 0, // Ambisonics decoding
+ AMBISONICS_BINAURAL_DECODER, // Ambisonics decoding to binaural
+ };
+
+ void *logctx;
+
+ SpatialaudioMode mode;
+
+ CAmbisonicBinauralizer binauralDecoder;
+ SpeakersBinauralizer binauralizer;
+ CAmbisonicDecoder speakerDecoder;
+ CAmbisonicProcessor processor;
+ CAmbisonicZoomer zoomer;
+
+ std::string hrtfPath;
+
+ // Ambisonic order
+ unsigned ambisonicOrder;
+ // Non-diegetic channels
+ unsigned nondiegeticChCount;
+
+ unsigned inChCount;
+ unsigned outChCount;
+
+ /* View point */
+ struct {
+ float theta;
+ float phi;
+ float roll;
+ float zoom;
+ } viewpoint;
+
+};
+
+// Speaker positions according to Rec. ITU-R BS.2051-3
+static const std::map<enum AVChannel, PolarPoint> speakerPositions = {
+ { AV_CHAN_FRONT_LEFT, { DegreesToRadians(+30), 0.f, 1.0f } },
+ { AV_CHAN_FRONT_RIGHT, { DegreesToRadians(-30), 0.f, 1.0f } },
+ { AV_CHAN_SIDE_LEFT, { DegreesToRadians(+110), 0.f, 1.0f } },
+ { AV_CHAN_SIDE_RIGHT, { DegreesToRadians(-110), 0.f, 1.0f } },
+ { AV_CHAN_BACK_LEFT, { DegreesToRadians(+145), 0.f, 1.0f } },
+ { AV_CHAN_BACK_RIGHT, { DegreesToRadians(-145), 0.f, 1.0f } },
+ { AV_CHAN_BACK_CENTER, { DegreesToRadians(+0), 0.f, 1.0f } },
+ { AV_CHAN_FRONT_CENTER, { DegreesToRadians(+0), 0.f, 1.0f } },
+ { AV_CHAN_LOW_FREQUENCY, { DegreesToRadians(+0), 0.f, 0.5f } },
+};
+
+// L/R channels
+// This list must be ordered so that the left channels is always followed by the right channel!
+static const std::vector<enum AVChannel> stereoChannels = {
+ AV_CHAN_FRONT_LEFT,
+ AV_CHAN_FRONT_RIGHT,
+
+ AV_CHAN_SIDE_LEFT,
+ AV_CHAN_SIDE_RIGHT,
+
+ AV_CHAN_BACK_LEFT,
+ AV_CHAN_BACK_RIGHT,
+};
+
+int spatialaudio_context_create(struct SpatialaudioContext **spctx, void *logctx)
+{
+ void *storage = av_malloc(sizeof(SpatialaudioContext));
+ if (!storage)
+ return AVERROR(ENOMEM);
+
+ *spctx = new(storage) SpatialaudioContext();
+ (*spctx)->logctx = logctx;
+ return 0;
+}
+
+void spatialaudio_context_set_viewpoint(struct SpatialaudioContext *spctx, float yaw, float pitch, float roll, float fov)
+{
+ spctx->viewpoint.theta = -DegreesToRadians(yaw);
+ spctx->viewpoint.phi = DegreesToRadians(pitch);
+ spctx->viewpoint.roll = DegreesToRadians(roll);
+
+ if (fov >= FOV_DEGREES_DEFAULT)
+ spctx->viewpoint.zoom = 0.f; // no unzoom as it does not really make sense.
+ else
+ spctx->viewpoint.zoom = (FOV_DEGREES_DEFAULT - fov) / (FOV_DEGREES_DEFAULT - FOV_DEGREES_MIN);
+}
+
+void spatialaudio_context_set_hrtf_path(struct SpatialaudioContext *spctx, const char *hrtf_path)
+{
+ spctx->hrtfPath = (hrtf_path) ? hrtf_path : "";
+}
+
+int spatialaudio_context_configure_input(struct SpatialaudioContext *spctx, const AVChannelLayout *in_layout)
+{
+ spctx->inChCount = in_layout->nb_channels;
+
+ if (in_layout->order == AV_CHANNEL_ORDER_AMBISONIC) {
+ int order = av_channel_layout_ambisonic_order(in_layout);
+ if (order < 0 || order > AMB_MAX_ORDER) {
+ av_log(spctx->logctx, AV_LOG_ERROR, "unsupported/invalid ambisonic order\n");
+ return AVERROR(EINVAL);
+ }
+ spctx->ambisonicOrder = order;
+ spctx->nondiegeticChCount = spctx->inChCount - (spctx->ambisonicOrder + 1) * (spctx->ambisonicOrder + 1);
+
+ av_log(spctx->logctx, AV_LOG_VERBOSE, "channels: %d, ambisonic order: %d, non-diegetic channels: %d\n",
+ spctx->inChCount, spctx->ambisonicOrder, spctx->nondiegeticChCount);
+
+ if (spctx->nondiegeticChCount > 0 &&
+ (spctx->nondiegeticChCount != 2 ||
+ av_channel_layout_subset(in_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
+ {
+ av_log(spctx->logctx, AV_LOG_ERROR, "Invalid amount of non-diegetic channels: %d\n", spctx->nondiegeticChCount);
+ return AVERROR(EINVAL);
+ }
+ } else {
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+int spatialaudio_context_configure_output(struct SpatialaudioContext *spctx, const AVChannelLayout *out_layout, int samplerate)
+{
+ static constexpr auto binaural_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_BINAURAL;
+ spctx->outChCount = out_layout->nb_channels;
+
+ if (spctx->outChCount == 2 &&
+ !av_channel_layout_compare(out_layout, &binaural_layout))
+ {
+ spctx->mode = SpatialaudioContext::AMBISONICS_BINAURAL_DECODER;
+ if (spctx->hrtfPath.empty()) {
+ av_log(spctx->logctx, AV_LOG_ERROR, "HRTF file path needs to be provided for binaural rendering\n");
+ return AVERROR(EINVAL);
+ }
+
+ unsigned tailLength = 0;
+ if (!spctx->binauralDecoder.Configure(spctx->ambisonicOrder, true, samplerate,
+ AMB_BLOCK_TIME_LEN, tailLength, spctx->hrtfPath))
+ {
+ av_log(spctx->logctx, AV_LOG_ERROR, "Failure creating binaural ambisonic decoder\n");
+ return AVERROR(EINVAL);
+ }
+ } else {
+ if (spctx->outChCount == 1 ||
+ !spctx->speakerDecoder.Configure(spctx->ambisonicOrder, true, AMB_BLOCK_TIME_LEN,
+ kAmblib_CustomSpeakerSetUp, spctx->outChCount))
+ {
+ av_log(spctx->logctx, AV_LOG_ERROR, "Failure creating the ambisonics decoder\n");
+ return AVERROR(EINVAL);
+ }
+
+ for (size_t idx = 0; idx < spctx->outChCount; idx++) {
+ char name[32];
+ enum AVChannel channel = av_channel_layout_channel_from_index(out_layout, idx);
+ av_channel_name(name, sizeof(name), channel);
+
+ PolarPoint point = {};
+ auto it = speakerPositions.find(channel);
+ if (it != speakerPositions.end()) {
+ point = it->second;
+ av_log(spctx->logctx, AV_LOG_VERBOSE, "Setting point for channel '%s':\t Azi.: %.2f, Elev.: %.2f, Dist.: %.2f\n",
+ name, point.fAzimuth, point.fElevation, point.fDistance);
+ } else {
+ av_log(spctx->logctx, AV_LOG_WARNING, "No position information for channel '%s', assuming Azi.: %.2f, Elev.: %.2f, Dist.: %.2f\n",
+ name, point.fAzimuth, point.fElevation, point.fDistance);
+ }
+
+ spctx->speakerDecoder.SetPosition(idx, point);
+ }
+ }
+
+ if (!spctx->processor.Configure(spctx->ambisonicOrder, true, AMB_BLOCK_TIME_LEN, 0))
+ {
+ av_log(spctx->logctx, AV_LOG_ERROR, "Failure creating the ambisonics processor\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ if (!spctx->zoomer.Configure(spctx->ambisonicOrder, true, AMB_BLOCK_TIME_LEN, 0))
+ {
+ av_log(spctx->logctx, AV_LOG_ERROR, "Failure creating the ambisonics zoomer\n");
+ return AVERROR_EXTERNAL;
+ }
+
+ return 0;
+}
+
+// Mix in the non-diegetic (headlocked) channels into the output
+static void add_nondiegetic_channels(struct SpatialaudioContext *spctx, AVFrame *in, AVFrame *out)
+{
+ const AVChannelLayout *out_layout = &out->ch_layout;
+
+ // The non-diegetic channels are at the end
+ unsigned nondiegeticChStart = spctx->inChCount - spctx->nondiegeticChCount;
+
+ for (size_t idx = 0; idx < spctx->outChCount; idx++) {
+ enum AVChannel channel = av_channel_layout_channel_from_index(out_layout, idx);
+
+ auto it = std::find(stereoChannels.cbegin(), stereoChannels.cend(), channel);
+ if (it == stereoChannels.cend())
+ continue;
+
+ ptrdiff_t pos = std::distance(stereoChannels.cbegin(), it);
+
+ // This is either 0 for left or 1 for right
+ unsigned lr = !((pos + 1) % 2);
+
+ float *in_plane = ((float **)in->extended_data)[nondiegeticChStart + lr];
+ float *out_plane = ((float **)out->extended_data)[idx];
+
+ for (size_t i = 0; i < out->nb_samples; i++)
+ out_plane[i] = out_plane[i] / 2.f + in_plane[i] / 2.f;
+ }
+}
+
+int spatialaudio_context_process(struct SpatialaudioContext *spctx, AVFrame *in, AVFrame *out)
+{
+ CBFormat inData;
+ inData.Configure(spctx->ambisonicOrder, true, in->nb_samples);
+
+ av_assert2(in->ch_layout.nb_channels >= spctx->inChCount - spctx->nondiegeticChCount);
+ for (unsigned i = 0; i < spctx->inChCount - spctx->nondiegeticChCount; ++i)
+ inData.InsertStream((float *)in->extended_data[i], i, in->nb_samples);
+
+ Orientation ori(spctx->viewpoint.theta, spctx->viewpoint.phi, spctx->viewpoint.roll);
+ spctx->processor.SetOrientation(ori);
+ spctx->processor.Refresh();
+ spctx->processor.Process(&inData, inData.GetSampleCount());
+
+ spctx->zoomer.SetZoom(spctx->viewpoint.zoom);
+ spctx->zoomer.Refresh();
+ spctx->zoomer.Process(&inData, inData.GetSampleCount());
+
+ if (spctx->mode == SpatialaudioContext::AMBISONICS_BINAURAL_DECODER)
+ spctx->binauralDecoder.Process(&inData, (float **)out->extended_data, out->nb_samples);
+ else
+ spctx->speakerDecoder.Process(&inData, out->nb_samples, (float **)out->extended_data);
+
+ if (spctx->nondiegeticChCount > 0)
+ add_nondiegetic_channels(spctx, in, out);
+
+ return 0;
+}
+
+void spatialaudio_context_destroy(struct SpatialaudioContext **spctx)
+{
+ if (*spctx)
+ (*spctx)->~SpatialaudioContext();
+ av_freep(spctx);
+}
diff --git a/libavfilter/af_libspatialaudio_c.c b/libavfilter/af_libspatialaudio_c.c
new file mode 100644
index 0000000000..a21079c3a7
--- /dev/null
+++ b/libavfilter/af_libspatialaudio_c.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2024 Marvin Scholz
+ *
+ * Authors: Marvin Scholz <epirat07 at gmail.com>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ */
+
+#include "libavutil/mem.h"
+#include "libavutil/tx.h"
+#include "libavutil/avstring.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/intmath.h"
+#include "libavutil/opt.h"
+#include "avfilter.h"
+#include "filters.h"
+#include "formats.h"
+#include "audio.h"
+
+#include "libavfilter/af_libspatialaudio_common.h"
+
+struct SpatialaudioContextC {
+ const AVClass *class;
+ struct SpatialaudioContext *spctx;
+
+ // The output channel layout to mix to
+ AVChannelLayout output_layout;
+
+ float fov;
+ float roll;
+ float pitch;
+ float yaw;
+
+ // Path of the HRTF file (only used for binaural rendering)
+ char *hrtf_path;
+};
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+ AVFilterContext *ctx = inlink->dst;
+ AVFilterLink *outlink = ctx->outputs[0];
+ struct SpatialaudioContextC *s = ctx->priv;
+ AVFrame *out;
+ int ret;
+
+ out = ff_get_audio_buffer(outlink, in->nb_samples);
+ if (!out) {
+ av_frame_free(&in);
+ return AVERROR(ENOMEM);
+ }
+ av_frame_copy_props(out, in);
+
+ ret = spatialaudio_context_process(s->spctx, in, out);
+
+ av_frame_free(&in);
+ return (ret < 0) ? ret : ff_filter_frame(outlink, out);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ struct SpatialaudioContextC *s = ctx->priv;
+ spatialaudio_context_destroy(&s->spctx);
+}
+
+static av_cold int init(AVFilterContext *ctx)
+{
+ struct SpatialaudioContextC *s = ctx->priv;
+ int ret = spatialaudio_context_create(&s->spctx, ctx);
+ if (ret < 0)
+ return ret;
+
+ spatialaudio_context_set_viewpoint(s->spctx, s->yaw, s->pitch, s->roll, s->fov);
+ spatialaudio_context_set_hrtf_path(s->spctx, s->hrtf_path);
+ return 0;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+ int ret;
+ AVFilterContext *ctx = inlink->dst;
+ struct SpatialaudioContextC *s = ctx->priv;
+ FilterLink *ff_inlink = ff_filter_link(inlink);
+
+ ret = spatialaudio_context_configure_input(s->spctx, &inlink->ch_layout);
+ if (ret < 0)
+ return ret;
+
+ ff_inlink->min_samples = ff_inlink->max_samples = AMB_BLOCK_TIME_LEN;
+ return 0;
+}
+
+static int config_output(AVFilterLink *outlink)
+{
+ int ret;
+ AVFilterContext *ctx = outlink->src;
+ struct SpatialaudioContextC *s = ctx->priv;
+
+ ret = spatialaudio_context_configure_output(s->spctx, &outlink->ch_layout, outlink->sample_rate);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int query_formats(const AVFilterContext *ctx,
+ AVFilterFormatsConfig **cfg_in,
+ AVFilterFormatsConfig **cfg_out)
+{
+ int ret;
+ struct SpatialaudioContextC *s = ctx->priv;
+ AVFilterChannelLayouts *channel_layouts = NULL;
+
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_FLTP,
+ AV_SAMPLE_FMT_NONE
+ };
+
+ ret = ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, sample_fmts);
+ if (ret < 0)
+ return ret;
+
+ ret = ff_add_channel_layout(&channel_layouts, &s->output_layout);
+ if (ret < 0)
+ return ret;
+
+ ret = ff_channel_layouts_ref(channel_layouts, &cfg_out[0]->channel_layouts);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+#define OFFSET(x) offsetof(struct SpatialaudioContextC, x)
+#define FLAGS (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM)
+
+static const AVOption libspatialaudio_options[] = {
+ { "channel_layout", "Output channel layout", OFFSET(output_layout),
+ AV_OPT_TYPE_CHLAYOUT, { .str = "stereo" }, .flags = FLAGS },
+
+ { "fov", "FoV in the soundsphere", OFFSET(fov),
+ AV_OPT_TYPE_FLOAT, { .dbl = FOV_DEGREES_DEFAULT }, FOV_DEGREES_MIN, FOV_DEGREES_MAX, .flags = FLAGS },
+
+ { "roll", "Roll to apply to the position in the soundsphere",OFFSET(roll),
+ AV_OPT_TYPE_FLOAT, { .dbl = 0.f }, -180.f, 180.f, .flags = FLAGS },
+
+ { "pitch","Pitch to apply to the position in the soundsphere",OFFSET(pitch),
+ AV_OPT_TYPE_FLOAT, { .dbl = 0.f }, -180.f, 180.f, .flags = FLAGS },
+
+ { "yaw", "Yaw to apply to the position in the soundsphere", OFFSET(yaw),
+ AV_OPT_TYPE_FLOAT, { .dbl = 0.f }, -180.f, 180.f, .flags = FLAGS },
+
+ { "hrtf_path", "Path to the HRTF file to use for binauralization", OFFSET(hrtf_path),
+ AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
+
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(libspatialaudio);
+
+static const AVFilterPad inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_input,
+ .filter_frame = filter_frame,
+ },
+};
+
+static const AVFilterPad outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .config_props = config_output,
+ },
+};
+
+const AVFilter ff_af_libspatialaudio = {
+ .name = "libspatialaudio",
+ .description = NULL_IF_CONFIG_SMALL("Spatial audio rendering using libspatialaudio"),
+ .priv_size = sizeof(struct SpatialaudioContextC),
+ .priv_class = &libspatialaudio_class,
+ .init = init,
+ .uninit = uninit,
+ FILTER_INPUTS(inputs),
+ FILTER_OUTPUTS(outputs),
+ FILTER_QUERY_FUNC2(query_formats),
+};
diff --git a/libavfilter/af_libspatialaudio_common.h b/libavfilter/af_libspatialaudio_common.h
new file mode 100644
index 0000000000..a07b05d940
--- /dev/null
+++ b/libavfilter/af_libspatialaudio_common.h
@@ -0,0 +1,47 @@
+/*
+* Copyright (C) 2024 Marvin Scholz
+ *
+ * Authors: Marvin Scholz <epirat07 at gmail.com>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ */
+#include "avfilter.h"
+
+#ifdef __cplusplus
+#define SPATIALEXTERNC extern "C"
+#else
+#define SPATIALEXTERNC
+#endif
+
+#define AMB_BLOCK_TIME_LEN 1024
+#define AMB_MAX_ORDER 3
+
+#define FOV_DEGREES_MIN 20.f
+#define FOV_DEGREES_MAX 150.f
+#define FOV_DEGREES_DEFAULT 80.f
+
+struct SpatialaudioContext;
+
+SPATIALEXTERNC int spatialaudio_context_create(struct SpatialaudioContext **spctx, void *logctx);
+
+SPATIALEXTERNC void spatialaudio_context_set_viewpoint(struct SpatialaudioContext *spctx, float yaw, float pitch, float roll, float fov);
+SPATIALEXTERNC void spatialaudio_context_set_hrtf_path(struct SpatialaudioContext *spctx, const char *hrtf_path);
+
+SPATIALEXTERNC int spatialaudio_context_configure_input(struct SpatialaudioContext *spctx, const AVChannelLayout *out_layout);
+SPATIALEXTERNC int spatialaudio_context_configure_output(struct SpatialaudioContext *spctx, const AVChannelLayout *out_layout, int samplerate);
+
+SPATIALEXTERNC int spatialaudio_context_process(struct SpatialaudioContext *spctx, AVFrame *in, AVFrame *out);
+
+SPATIALEXTERNC void spatialaudio_context_destroy(struct SpatialaudioContext **spctx);
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 9819f0f95b..a2ef33fc30 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -136,6 +136,7 @@ extern const AVFilter ff_af_highpass;
extern const AVFilter ff_af_highshelf;
extern const AVFilter ff_af_join;
extern const AVFilter ff_af_ladspa;
+extern const AVFilter ff_af_libspatialaudio;
extern const AVFilter ff_af_loudnorm;
extern const AVFilter ff_af_lowpass;
extern const AVFilter ff_af_lowshelf;
--
2.39.5 (Apple Git-154)
More information about the ffmpeg-devel
mailing list