From patchwork Tue Aug 15 18:27:18 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sanchit Sinha X-Patchwork-Id: 4712 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.46.211 with SMTP id u202csp5866742vsu; Tue, 15 Aug 2017 11:27:29 -0700 (PDT) X-Received: by 10.223.133.35 with SMTP id 32mr2538890wrh.184.1502821649866; Tue, 15 Aug 2017 11:27:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1502821649; cv=none; d=google.com; s=arc-20160816; b=sdoQe5cvjyuUMcGJixRdx3qGAe5lS2qXyLFhA2gq28Xo69aixnPqg8Kwmf8JFQ2i2p HYeBEdz2zZnscZJmq8B1d9HGhsQMflzmNa1h5dTcnfko3K62LEwAYIMqNiNjQXs4ruPO zEE1xavjjuztUSsI8aoH4vHQmU10AvmdSSSgF6anNGRLp5BGN+bevXvKdtvUKK0bYLPI zXfRn6FFbt1UmnBaSWOpuKG/GYpX05WMMut6R9ShSMaAIph+k+noeOSegq4Zp+cAkR0Q UCqQ91pwtCcJzHuIOcC5UqbThWRE2Tpk7XYd4jqVGNtMw+7mAHN0YUx+FmiyaRl3F3eR ONwA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to :message-id:date:from:references:in-reply-to:mime-version :dkim-signature:delivered-to:arc-authentication-results; bh=VRuBLZOen2EbFo9CGCf6CnEwRmG4E+RgFNyV+eTNkME=; b=yBJ8Fvd1HFG3ULgo4TFlW9khAt7x7DI3ifar7kW7P99IoY5Stwk30BPuKxLAIuk+Tw R+YwX8iSDg8nr71ofNzMOYAzqX5bb2yG1gA5N7Lqe7U/k7mxRzOGAfQ03/u6xwZHLKee RBCK9nAb1m5atT6/JIoX1q9gVH/05MY7CHW1oN5bSFHDWRQ3UeHMmw2lrH7F906L5T22 LlnHZ6+49JWQoK0Mkqli7x00SjFB7lsApEvxDl9wYdQo+0+aL3+p3Pf3CpurJsID7ZDu E6C23GysIUVac4qG7JBjgASd8Fvmn6n1a8VyYW1gh8F9iBh3s19WLTmfm3+N7nfqCrK8 4V9g== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@iiitd.ac.in header.s=google header.b=kK+Sk+8m; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id a21si3514686wrc.164.2017.08.15.11.27.29; Tue, 15 Aug 2017 11:27:29 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@iiitd.ac.in header.s=google header.b=kK+Sk+8m; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5CBD3680489; Tue, 15 Aug 2017 21:27:21 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f44.google.com (mail-wm0-f44.google.com [74.125.82.44]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2B90B680352 for ; Tue, 15 Aug 2017 21:27:15 +0300 (EEST) Received: by mail-wm0-f44.google.com with SMTP id k20so25321034wmg.0 for ; Tue, 15 Aug 2017 11:27:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iiitd.ac.in; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=ki5xs9gz+LuZ0zHXQ3rhWDQuAvYEa2xbh2QaIkgNhQk=; b=kK+Sk+8mPVzYD7Ib3qk3JgyxClmtWj91c6+IqnA+hb+2XkYYEGO77JWyKeuzrnc/bc JCGJGC0koYvHTGvSjop5nk1oZJ0oqP19bclSah0LUyFL3v3btJw1KtgQZXQmi/dzuzRh DUsqKHMvDIuJlXqRaoysHVva7mQnhvLCpbb1w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=ki5xs9gz+LuZ0zHXQ3rhWDQuAvYEa2xbh2QaIkgNhQk=; b=LF/CnHliMDp3/T71RcqblWSGCFK+cwhefWWyiiNAUQeqxaTH1/3+LPaAzrEwmExpMD q0YyeQAVVWyj+HIOzCeBevXG2qR7QzwpvN1kyWqOrHPLAMulrrwu/VY/16dM8U6FvkYF V0fcVQq80VSpLGpqJFmtDO3urWkzD3J4OJU49n8KsrWhnxdkPO6pSMINtkLqsmyGlo7W HfKwfihNXvDoVpbDLU9oONR8AJ8qr3b5K9nMPpB8o1KWswfK/w6nasgjmu0WbIxFmduA WZWfj3wQal/GEdWp0fM1WzdgPP8GlFrcq5qwKH5W/THBh91XvvDLHwHfUGUWMvrrUyA6 9Itw== X-Gm-Message-State: AHYfb5jUqXC8YbhjNbWowyG6+0aLl9js++i7onwMM10CB/EXenyuD3sc TfF1TYzCqHJHfNi7L6x7hdnwZ3VPcSUP X-Received: by 10.80.135.28 with SMTP id i28mr28860974edb.162.1502821639105; Tue, 15 Aug 2017 11:27:19 -0700 (PDT) MIME-Version: 1.0 Received: by 10.80.147.228 with HTTP; Tue, 15 Aug 2017 11:27:18 -0700 (PDT) In-Reply-To: References: <57ab03c4-ca4b-a4db-4224-15c1ce9db5f1@gmail.com> <00a6a6e3-7163-ad9c-1e0c-853e830a17bb@gmail.com> From: Sanchit Sinha Date: Tue, 15 Aug 2017 23:57:18 +0530 Message-ID: To: FFmpeg development discussions and patches X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: Re: [FFmpeg-devel] [PATCH] libavfilter/af_ambisonic.c Added File for Ambisonic Filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" On Tue, Aug 15, 2017 at 4:46 PM, Paul B Mahol wrote: > Hi, > > subject of patch file is wrong. > > Why is code for rotation so limited? One should be able to rotate by > all 3 directions at once. > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > From c802c29bd9d6b141cf0d273d480f00fef97d617f Mon Sep 17 00:00:00 2001 From: Sanchit Sinha Date: Tue, 15 Aug 2017 23:55:44 +0530 Subject: [PATCH] libavfilter/af_ambisonic.c:Added File for Ambisonic Decoding Signed-off-by: Sanchit Sinha --- Changelog | 1 + libavfilter/Makefile | 1 + libavfilter/af_ambisonic.c | 732 +++++++++++++++++++++++++++++++++++++++++++++ libavfilter/allfilters.c | 1 + 4 files changed, 735 insertions(+) create mode 100644 libavfilter/af_ambisonic.c diff --git a/Changelog b/Changelog index c797d68..e09c48b 100644 --- a/Changelog +++ b/Changelog @@ -32,6 +32,7 @@ version : - unpremultiply video filter - tlut2 video filter - floodfill video filter +- Ambisonic Decoder version 3.3: - CrystalHD decoder moved to new decode API diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 06b915f..c1ca5ea 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -45,6 +45,7 @@ OBJS-$(CONFIG_AINTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_ALIMITER_FILTER) += af_alimiter.o OBJS-$(CONFIG_ALLPASS_FILTER) += af_biquads.o OBJS-$(CONFIG_ALOOP_FILTER) += f_loop.o +OBJS-$(CONFIG_AMBISONIC_FILTER) += af_ambisonic.o OBJS-$(CONFIG_AMERGE_FILTER) += af_amerge.o OBJS-$(CONFIG_AMETADATA_FILTER) += f_metadata.o OBJS-$(CONFIG_AMIX_FILTER) += af_amix.o diff --git a/libavfilter/af_ambisonic.c b/libavfilter/af_ambisonic.c new file mode 100644 index 0000000..3097268 --- /dev/null +++ b/libavfilter/af_ambisonic.c @@ -0,0 +1,732 @@ +/* + * Copyright (c) 2017 Sanchit Sinha + * 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/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "libavutil/avassert.h" +#include "audio.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include +#include + +enum FilterType { + shelf, + nearfield +}; + +enum InputFormat { + N3D , + SN3D , + FURMUL +}; + +enum Rotate { + TILT , + TUMBLE, + YAW +}; + +enum Layouts { + MONO , + STEREO , + TRIANGLE , + SQUARE , + PENTAGON , + HEXAGON , + HEPTAGON , + OCTAGON , + TETRAHEDRON , + OCTAHEDRON , + CUBE , + DODECAHEDRON, + ICOSAHEDRON +}; + +typedef struct Cache { + double i1, i2; + double o1, o2; +} Cache; + +/*Decoding matrix for 1st order files. Similar can be done for 2nd, 3rd etc*/ +static const struct { + int speakers; + float matrix[22][15]; +} ambisonic_matrix[]= { + [MONO]={ + .speakers=1, + .matrix={ + {0.22156, 0, 0, 0}, + }, + }, + [TRIANGLE]={ + .speakers=3, + .matrix={ + {0.17836, 0.32555, 0.18795, 0}, + {0.17836, 0 ,-0.37591, 0}, + {0.17836,-0.32555, 0.18795, 0}, + }, + }, + [SQUARE]={ + .speakers=4, + .matrix={ + {0.39388, 0.18690, 0.18690, 0}, + {0.39388,-0.18690, 0.18690, 0}, + {0.39388,-0.18690,-0.18690, 0}, + {0.39388, 0.18690,-0.18690, 0}, + }, + }, + [PENTAGON]={ + .speakers=5, + .matrix={ + {0.20195, 0 , 0.33420, 0}, + {0.11356, 0.2901 , 0.04186, 0}, + {0.19654,-0.07993,-0.34782, 0}, + {0.19654, 0.07993,-0.34782, 0}, + {0.19654,-0.2901 , 0.04186, 0}, + }, + }, + [HEXAGON]={ + .speakers=6, + .matrix={ + {0.26259, 0 , 0.31326, 0}, + {0.26259, 0.27129, 0.15663, 0}, + {0.26259, 0.27129, -0.15663, 0}, + {0.26259, 0 , -0.31326, 0}, + {0.26259,-0.27129, -0.15663, 0}, + {0.26259,-0.27129, 0.15663, 0}, + }, + }, + [HEPTAGON]={ + .speakers=7, + .matrix={ + {0.22501,-0.0 , 0.26846, 0}, + {0.22507, 0.20989, 0.16741, 0}, + {0.22507, 0.26180, -0.05969, 0}, + {0.22511, 0.11651, -0.24195, 0}, + {0.22511,-0.11651, -0.24195, 0}, + {0.22507,-0.26180, -0.05969, 0}, + {0.22507,-0.20989, 0.16741, 0}, + }, + }, + [OCTAGON]={ + .speakers=8, + .matrix={ + {0.19694, 0.08991, 0.21706, 0}, + {0.19694, 0.21706, 0.08991, 0}, + {0.19694, 0.21706, -0.08991, 0}, + {0.19694, 0.08991, -0.21706, 0}, + {0.19694, -0.08991, -0.21706, 0}, + {0.19694, -0.21706, -0.08991, 0}, + {0.19694, -0.21706, 0.08991, 0}, + {0.19694, -0.08991, 0.21706, 0}, + }, + }, + [OCTAHEDRON]={ + .speakers=6, + .matrix={ + {0.45832, 0.41566, 0.00000, 0.13183}, + {0.95964, 0.41566, 0.00000, -0.36696}, + {0.45832, -0.41566, 0.00000, 0.13183}, + {0.95964, -0.41566, 0.00000, -0.36696}, + {0.35449, 0.00000, 0.00000, 0.23513}, + {0.35449, 0.00000, 0.00000, 0.23513}, + }, + }, + [CUBE]={ + .speakers=8, + .matrix={ + {0.14269, 0.13909, 0.28611, 0.13909}, + {0.14269, 0.13909, -0.28611, 0.13909}, + {0.14269,-0.13909, 0.28611, 0.13909}, + {0.14269,-0.13909, -0.28611, 0.13909}, + {0.14269, 0.13909, 0.28611,-0.13909}, + {0.14269, 0.13909, -0.28611,-0.13909}, + {0.14269,-0.13909, 0.28611,-0.13909}, + {0.14269,-0.13909, -0.28611,-0.13909}, + }, + }, + [ICOSAHEDRON]={ + .speakers=12, + .matrix={ + {0.18245, -1.6727e-34, 2.0067e-17, 2.2478e-01}, + {0.18245, 5.8352e-35, 4.8797e-18, 2.2478e-01}, + {0.21854, -2.5706e-18, 1.7303e-01, 1.5296e-01}, + {0.28727, 3.0478e-01, 1.7303e-01, 1.6203e-02}, + {0.28727, -3.0478e-01, 1.7303e-01, 1.6203e-02}, + {0.39847, 1.8836e-01, 1.7303e-01, -2.0508e-01}, + {0.39847, -1.8836e-01, 1.7303e-01, -2.0508e-01}, + {0.21854, 2.5706e-18, -1.7303e-01, 1.5296e-01}, + {0.28727, 3.0478e-01, -1.7303e-01, 1.6203e-02}, + {0.28727, -3.0478e-01, -1.7303e-01, 1.6203e-02}, + {0.39847, 1.8836e-01, -1.7303e-01, -2.0508e-01}, + {0.39847, -1.8836e-01, -1.7303e-01, -2.0508e-01}, + }, + }, + [DODECAHEDRON]={ + .speakers=20, + .matrix={ + {1.7725e-01, 1.0721e-16, -3.6730e-17, 1.4416e-01}, + {1.7725e-01, 8.4733e-02, 4.8084e-19, 1.1662e-01}, + {1.7725e-01, 1.3710e-01, -3.8973e-18, 4.4547e-02}, + {1.7725e-01, 1.3710e-01, -1.9760e-18, -4.4547e-02}, + {1.7725e-01, 8.4733e-02, 3.0706e-20, -1.1662e-01}, + {1.7725e-01, -1.0415e-16, -1.5089e-19, -1.4416e-01}, + {1.7725e-01, -8.4733e-02, -1.1427e-17, 1.1662e-01}, + {1.7725e-01, -1.3710e-01, -9.4207e-18, 4.4547e-02}, + {1.7725e-01, -1.3710e-01, -5.9922e-18, -4.4547e-02}, + {1.7725e-01, -8.4733e-02, -2.4514e-18, -1.1662e-01}, + {1.7725e-01, 3.5190e-17, 1.9356e-01, 1.1452e-01}, + {1.7725e-01, 1.0891e-01, 1.9356e-01, 3.5389e-02}, + {1.7725e-01, 6.7313e-02, 1.9356e-01, -9.2648e-02}, + {1.7725e-01, -1.0891e-01, 1.9356e-01, 3.5389e-02}, + {1.7725e-01, -6.7313e-02, 1.9356e-01, -9.2648e-02}, + {1.7725e-01, 6.7313e-02, -1.9356e-01, 9.2648e-02}, + {1.7725e-01, 1.0891e-01, -1.9356e-01, -3.5389e-02}, + {1.7725e-01, -4.0103e-17, -1.9356e-01, -1.1452e-01}, + {1.7725e-01, -1.0891e-01, -1.9356e-01, -3.5389e-02}, + {1.7725e-01, -6.7313e-02, -1.9356e-01, 9.2648e-02}, + }, + }, +}; + +/*Matrix for scaling options*/ +static const struct { + float matrix[4][1]; +} scaler_matrix[]= { + [N3D]={ + .matrix={ + {1}, + {1}, + {1}, + {1}, + }, + }, + [SN3D]={ + .matrix={ + {sqrt(2*floor(sqrt(0))+1)}, + {sqrt(2*floor(sqrt(1))+1)}, + {sqrt(2*floor(sqrt(2))+1)}, + {sqrt(2*floor(sqrt(3))+1)}, + }, + }, + [FURMUL]={ + .matrix={ + {sqrt(2)}, + {sqrt(3)}, + {sqrt(3)}, + {sqrt(3)}, + }, + }, +}; + +typedef struct AmbisonicContext { + const AVClass *class; + enum FilterType filter_type; + int dimension; /*2D or 3D*/ + enum Layouts lyt; /*Output speaker layout*/ + enum InputFormat s_o; /*Scaling OPtion*/ + int nb_channels; /*No. of channels to consider while decoding*/ + int order; /*Order of ambi file*/ + int enable_shelf; /*Enable shelf filtering or not*/ + double e_nf, e_ni; /*Distances for near field filters*/ + double gain; /*Gain while shelfing*/ + double frequency; /*Freq. of shelf filter(param)*/ + double width; /*Param for shelf filter*/ + double a0, a1, a2; /*Internal param for shelf*/ + double b0, b1, b2; /*Internal param for shelf*/ + double tilt; /*Angle for tilt(x) rotation*/ + double tumble; /*Angle for tumble(y) rotation*/ + double yaw; /*Angle for yaw(z) rotation*/ + Cache *cache; /*Cache area for shelf filter*/ + float angle; /*Angle for rot.*/ + + /*Func pointer for Shelf filter*/ + void (*filter1)(struct AmbisonicContext *s, const void *ibuf, void *obuf, int len, + double *i1, double *i2, double *o1, double *o2, + double b0, double b1, double b2, double a1, double a2, double min, double max, int channelno); + + /*Func pointer for NF filter*/ + void (*filter2)(struct AmbisonicContext *s , + float **in, + float d1, float d2, + float g); + +} AmbisonicContext; + +#define OFFSET(x) offsetof(AmbisonicContext,x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption ambisonic_options[] = { + {"enable_shelf","Set if shelf filtering is required",OFFSET(enable_shelf), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS}, + {"e_s","Set if shelf filtering is required",OFFSET(enable_shelf), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS}, + {"e_nf","Set if Near Field Compensation is required/Input distance",OFFSET(e_nf), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 100.0, FLAGS}, + {"e_ni","Set if Near Field Compensation is required/Output distance",OFFSET(e_ni), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 100.0, FLAGS}, + {"output_layout","Enter Layout of output",OFFSET(lyt), AV_OPT_TYPE_INT, {.i64=SQUARE}, MONO, DODECAHEDRON, FLAGS,"lyt"}, + {"o_l","Enter Layout of output",OFFSET(lyt), AV_OPT_TYPE_INT, {.i64=SQUARE}, MONO, DODECAHEDRON, FLAGS,"lyt"}, + {"scaling_option","Set the input format (N3D, SN3D, Furse Malham)",OFFSET(s_o), AV_OPT_TYPE_INT, {.i64=N3D}, 0, 0, FLAGS, "scl"}, + {"s_o","Set the input format (N3D, SN3D, Furse Malham)",OFFSET(s_o), AV_OPT_TYPE_INT, {.i64=N3D}, N3D, FURMUL, FLAGS, "scl"}, + {"tilt","Set angle for tilt(x-axis)",OFFSET(tilt),AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, 0.0, 180.0, FLAGS}, + {"tumble","Set angle for tumble(y-axis)",OFFSET(tumble),AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, 0.0, 180.0, FLAGS}, + {"yaw","Set angle for yaw(z-axis)",OFFSET(yaw),AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, 0.0, 180.0, FLAGS}, + {"mono","Mono Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=MONO}, 0, 0, FLAGS,"lyt"}, + {"stereo","Stereo Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=STEREO}, 0, 0, FLAGS,"lyt"}, + {"triangle","Triangle Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=TRIANGLE}, 0, 0, FLAGS,"lyt"}, + {"quad","Square Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=SQUARE}, 0, 0, FLAGS,"lyt"}, + {"pentagon","Pentagonal Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=PENTAGON}, 0, 0, FLAGS,"lyt"}, + {"hexagon","Hexagonal Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=HEXAGON}, 0, 0, FLAGS,"lyt"}, + {"hepatagon","Hepatagonal Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=HEPTAGON}, 0, 0, FLAGS,"lyt"}, + {"octagon","Octagonal Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=OCTAGON}, 0, 0, FLAGS,"lyt"}, + {"octahedron","Octahedron Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=OCTAHEDRON}, 0, 0, FLAGS,"lyt"}, + {"cube","Cube Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=CUBE}, 0, 0, FLAGS,"lyt"}, + {"icosahedron","Icosahedron Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=ICOSAHEDRON}, 0, 0, FLAGS,"lyt"}, + {"dodecahedron","Dodecahedron Speaker Layout",0, AV_OPT_TYPE_CONST, {.i64=DODECAHEDRON}, 0, 0, FLAGS,"lyt"}, + {"n3d","N3D Scaling(Normalised)",0, AV_OPT_TYPE_CONST, {.i64=N3D}, 0, 0, FLAGS,"scl"}, + {"sn3d","SN3D Scaling(Semi-Normalised)",0, AV_OPT_TYPE_CONST, {.i64=SN3D}, 0, 0, FLAGS,"scl"}, + {"fm","Furse Malham Scaling",0, AV_OPT_TYPE_CONST, {.i64=FURMUL}, 0, 0, FLAGS,"scl"}, + {NULL} +}; + +static void shelf_flt( AmbisonicContext *s, + const void *input, void *output, int len, + double *in1, double *in2, + double *out1, double *out2, + double b0, double b1, double b2, + double a1, double a2, double min, double max, int channelno) +{ + + const float *ibuf = input; + float *obuf = output; + double i1 = *in1; + double i2 = *in2; + double o1 = *out1; + double o2 = *out2; + int i; + a1 = -a1; + a2 = -a2; + + switch(channelno){ + case 1: s->gain= 1.75; break; + case 2: s->gain= -1.26; break; + case 3: s->gain= -1.26; break; + default: s->gain= 1; + } + + for (i = 0; i+1 < len; i++) { + o2 = i2 * b2 + i1 * b1 + ibuf[i] * b0 + o2 * a2 + o1 * a1; + i2 = ibuf[i]; + if (o2 < min) { + obuf[i] = min; + } else if (o2 > max) { + obuf[i] = max; + } else { + obuf[i] = o2; + } + i++; + o1 = i1 * b2 + i2 * b1 + ibuf[i] * b0 + o1 * a2 + o2 * a1; + i1 = ibuf[i]; + if (o1 < min) { + obuf[i] = min; + } else if (o1 > max) { + obuf[i] = max; + } else { + obuf[i] = o1; + } + } + if (i < len) { + double o0 = ibuf[i] * b0 + i1 * b1 + i2 * b2 + o1 * a1 + o2 * a2; + i2 = i1; + i1 = ibuf[i]; + o2 = o1; + o1 = o0; + if (o0 < min) { + obuf[i] = min; + } else if (o0 > max) { + obuf[i] = max; + } else { + obuf[i] = o0; + } + } + *in1 = i1; + *in2 = i2; + *out1 = o1; + *out2 = o2; +} + +static void nearfield_flt( AmbisonicContext *s, + float **in, + float d1, float d2, + float g) +{ + float b,g1,c,d, x,y,z=0; + float *input_arr[9]; + + if(d1) d1=340.0f / (d1 * 48e3); + if(d2) d2=340.0f / (d2 * 48e3); + + b = (d1 * 0.5); + g1 = b+1; + g *= g1; + c = (2 * b) / g1; + + b = (d2 * 0.5); + g1 = b+1; + g /= g1; + d = (2 * b) / g1; + + + for(int i=0;inb_channels;i++) + { + input_arr[i]=(float*)in[i]; + } + + //forward filter + if(d1) { + for(int i=0;inb_channels;i++) { + for(int itr=0;itrnb_channels;itr++) { + x = g * input_arr[i][itr]; + y = x - (d*z) + 1e-30f; + x = y + (c*z); + z += y; + itr += d; + + input_arr[i][itr] = x; + } + } + } else { //inverse filter + for(int i=0;inb_channels;i++) { + for(int itr=0;itrnb_channels;itr++) { + x = g * input_arr[i][itr]; + x -= (d*z) + 1e-30f; + z += x; + itr += d; + + input_arr[i][itr] = x; + } + } + } +} + +static void rotate( AmbisonicContext *s, + float **in, float rotate_matrix[9][9], + float angle, + int samples) +{ + for(int j=0;jnb_channels;k++) { + for(int i=0;inb_channels;i++) { + sum+=(in[i][j]*rotate_matrix[k][i]); + } + in[k][j]=sum; + } + } +} + + +static void rotate_flt( AmbisonicContext *s, float **in, + float tilt,float tumble,float yaw, + int samples) +{ + /*Rotation matrix values for x,y,z axis*/ + float rotate_matrix_tilt[][9]= {{1, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, cos(tilt),-sin(tilt) , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, sin(tilt), cos(tilt) , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 }, + {0, 0 , 0 , 0 , cos(tilt), 0 , 0 , -sin(tilt), 0 }, + {0, 0 , 0 , 0 , 0 , cos(2*tilt) , -sqrt(3/4)*sin(2*tilt) , 0 ,-(0.5)*sin(2*tilt) }, + {0, 0 , 0 , 0 , 0 , sqrt(0.75)*sin(2*tilt), (0.25)*(1+3*cos(2*tilt)) , 0 ,-sqrt(3.0/16.0)*(1-cos(2*tilt))}, + {0, 0 , 0 , 0 , sin(tilt), 0 , 0 , cos(tilt) , 0 }, + {0, 0 , 0 , 0 , 0 , (0.5)*sin(2*tilt) , -sqrt(3/16)*(1-cos(2*tilt)) , 0 , (0.25)*(3+cos(2*tilt)) }}; + + float rotate_matrix_tumble[][9]={{1, 0, 0 ,0 ,0 ,0 , 0 ,0 ,0 }, + {0, 1, 0 ,0 ,0 ,0 , 0 ,0 ,0 }, + {0, 0, cos(tumble) ,sin(tumble) ,0 ,0 , 0 ,0 ,0 }, + {0, 0, -sin(tumble),cos(tumble) ,0 ,0 , 0 ,0 ,0 }, + {0, 0, 0 ,0 ,cos(tumble) ,-sin(tumble) , 0 ,0 ,0 }, + {0, 0, 0 ,0 ,sin(tumble) , cos(tumble) , 0 ,0 ,0 }, + {0, 0, 0 ,0 ,0 ,0 , (0.25)*(1+3*cos(2*tumble)) ,sqrt(0.75)*sin(2*tumble) ,sqrt(3.0/16.0)*(1-cos(2*tumble))}, + {0, 0, 0 ,0 ,0 ,0 ,-sqrt(0.75)*sin(2*tumble) ,cos(2*tumble) ,(0.5)*sin(2*tumble) }, + {0, 0, 0 ,0 ,0 ,0 , sqrt(3.0/16.0)*(1-cos(2*tumble)) ,-(0.5)*sin(2*tumble) ,(0.25)*(3+cos(2*tumble)) }}; + + float rotate_matrix_yaw[][9]= {{1, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, cos(yaw), 0 , sin(yaw) , 0 , 0 , 0 , 0 , 0 }, + {0, 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, -sin(yaw), 0 , cos(yaw) , 0 , 0 , 0 , 0 , 0 }, + {0, 0 , 0 , 0 , cos(2*yaw) , 0 , 0 , 0 , sin(2*yaw)}, + {0, 0 , 0 , 0 , 0 , cos(yaw) , 0 ,sin(yaw) , 0 }, + {0, 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 }, + {0, 0 , 0 , 0 , 0 , -sin(yaw) , 0 , cos(yaw) , 0 }, + {0, 0 , 0 , 0 , -sin(2*yaw) , 0 , 0 , 0 , cos(2*yaw)}}; + + if(tilt) rotate(s,in,rotate_matrix_tilt,tilt,samples); + if(tumble) rotate(s,in,rotate_matrix_tumble,tumble,samples); + if(yaw) rotate(s,in,rotate_matrix_yaw,yaw,samples); +} + +/*Utility function for matrix multiplication*/ +static float multiply(const float decode_matrix[22][15],int row, float *vars[22], + int sample_no, int nb_channels) +{ + float sum=0; + int j; + for(j=0;jpriv; + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + uint64_t temp; + int ret; + + switch(s->lyt) { + case MONO: temp=AV_CH_LAYOUT_MONO; s->dimension=2; break; + case STEREO: temp=AV_CH_LAYOUT_STEREO; s->dimension=2; break; + case TRIANGLE: temp=AV_CH_LAYOUT_SURROUND; s->dimension=2; break; + case SQUARE: temp=AV_CH_LAYOUT_4POINT0; s->dimension=2; break; + case PENTAGON: temp=AV_CH_LAYOUT_5POINT0; s->dimension=2; break; + case HEXAGON: temp=AV_CH_LAYOUT_6POINT0; s->dimension=2; break; + case HEPTAGON: temp=AV_CH_LAYOUT_7POINT0; s->dimension=2; break; + case OCTAGON: temp=AV_CH_LAYOUT_OCTAGONAL; s->dimension=2; break; + case OCTAHEDRON: temp=AV_CH_LAYOUT_6POINT0; s->dimension=2; break; + case CUBE: temp=AV_CH_LAYOUT_OCTAGONAL; s->dimension=3; break; + case ICOSAHEDRON: temp=AV_CH_LAYOUT_4POINT0; s->dimension=3; break; //Layout not yet available + case DODECAHEDRON: temp=AV_CH_LAYOUT_4POINT0; s->dimension=3; break; //Layout not yet available + default: temp=AV_CH_LAYOUT_4POINT0; s->dimension=2; + } + + /*The order of ambisonic file is calculated by floor(sqrt(no.of input channels))-1.*/ + /*This funct. is not yet in ffmpeg*/ + + s->order=1;//first order ambisonics as of now + + switch(s->dimension) { + case 2: s->nb_channels=2*s->order+1; break; + case 3: s->nb_channels=(s->order+1)*(s->order+1); break; + default: s->nb_channels=2*s->order+1; + } + + ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLTP); + if (ret) + return ret; + ret = ff_set_common_formats(ctx, formats); + if (ret) + return ret; + + ret = ff_add_channel_layout(&layouts, temp); + if (ret) + return ret; + + ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts); + if (ret) + return ret; + + layouts = NULL; + + ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_4POINT0); + if (ret) + return ret; + + ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->out_channel_layouts); + if (ret) + return ret; + + formats = ff_all_samplerates(); + if(!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AmbisonicContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + double alpha,A,w0; + s->frequency=700; + s->filter_type=shelf; + s->width=10; + A = exp(s->gain / 40 * log(10.)); + w0 = 2 * M_PI * s->frequency / inlink->sample_rate; + alpha=sin(w0) / (2 * s->frequency / s->width); + + switch (s->filter_type) { + case shelf: + s->a0 = (A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha; + s->a1 = -2 * ((A - 1) + (A + 1) * cos(w0)); + s->a2 = (A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha; + s->b0 = A * ((A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha); + s->b1 = 2 * A * ((A - 1) - (A + 1) * cos(w0)); + s->b2 = A * ((A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha); + break; + default: + av_assert0(0); + } + s->a1 /= s->a0; + s->a2 /= s->a0; + s->b0 /= s->a0; + s->b1 /= s->a0; + s->b2 /= s->a0; + + s->cache = av_realloc_f(s->cache, sizeof(Cache), inlink->channels); + if (!s->cache) + return AVERROR(ENOMEM); + + memset(s->cache, 0, sizeof(Cache) * inlink->channels); + + s->tilt =(M_PI/180.0f)*s->tilt; + s->tumble=(M_PI/180.0f)*s->tumble; + s->yaw =(M_PI/180.0f)*s->yaw; + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AmbisonicContext *s=ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out_buf; + int itr; + float *vars[9]; + float calc[22]={0}; + float *c[22]; + int i; + + out_buf = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out_buf) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out_buf, in); + + s->filter1 = shelf_flt; + + if(s->lyt==MONO) s->enable_shelf=0; /*Shelf filtering not applicable for mono*/ + if(s->enable_shelf) { + // shelf filter + // for w channel gain= 1.75 + s->filter1(s, in->extended_data[0], + out_buf->extended_data[0], in->nb_samples, + &s->cache[0].i1, &s->cache[0].i2, + &s->cache[0].o1, &s->cache[0].o2, + s->b0, s->b1, s->b2, s->a1, s->a2, -1.,1.,1); + // for x & y channel gain= -1.26 + s->filter1(s, in->extended_data[1], + out_buf->extended_data[1], in->nb_samples, + &s->cache[1].i1, &s->cache[1].i2, + &s->cache[1].o1, &s->cache[1].o2, + s->b0, s->b1, s->b2, s->a1, s->a2, -1.,1.,2); + if(s->lyt!=STEREO) + s->filter1(s, in->extended_data[2], + out_buf->extended_data[2], in->nb_samples, + &s->cache[2].i1, &s->cache[2].i2, + &s->cache[2].o1, &s->cache[2].o2, + s->b0, s->b1, s->b2, s->a1, s->a2, -1.,1.,3); + } + + s->filter2 = nearfield_flt; + if(s->e_nf && s->e_ni) { + s->filter2(s,(float **)in->extended_data,s->e_nf,s->e_ni,1.0); + } + + rotate_flt(s,(float **)in->extended_data,s->tilt,s->tumble,s->yaw,in->nb_samples); + + for(i=0;inb_channels;i++) { + vars[i]=(float*)in->extended_data[i]; + } + + for(i=0;ilyt].speakers;i++) { + c[i]=(float *)out_buf->extended_data[i]; + } + + for(itr=0;itrnb_samples;itr++) { + for(i=0;ilyt].speakers;i++) { + if(s->dimension==2) { + calc[i]=multiply(ambisonic_matrix[s->lyt].matrix,i,vars,itr,s->nb_channels); + } else { + switch(s->order) { + case 1: calc[i]=multiply(ambisonic_matrix[s->lyt].matrix,i,vars,itr,s->nb_channels); + break; + /*This will only work once we have marker for more input channels. New vals will then have to be added.*/ + case 2: calc[i]=multiply(ambisonic_matrix[s->lyt].matrix,i,vars,itr,s->nb_channels); + break; + case 3: calc[i]=multiply(ambisonic_matrix[s->lyt].matrix,i,vars,itr,s->nb_channels); + break; + } + } + } + + for(i=0;ilyt].speakers;i++) { + c[i][itr]=calc[i]; + } + + for(i=0;ilyt].speakers;i++) { + c[i][itr]*=scaler_matrix[s->s_o].matrix[0][i]; + } + } + + if (out_buf != in) + av_frame_free(&in); + return ff_filter_frame(outlink, out_buf); + +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AmbisonicContext *s = ctx->priv; + av_freep(&s->cache); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(ambisonic); + +AVFilter ff_af_ambisonic = { + .name = "ambisonic", + .description = NULL_IF_CONFIG_SMALL("An ambisonic filter"), + .query_formats = query_formats, + .priv_size = sizeof(AmbisonicContext), + .priv_class = &ambisonic_class, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, +}; \ No newline at end of file diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index e58c0d5..24ba69c 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -58,6 +58,7 @@ static void register_all(void) REGISTER_FILTER(ALIMITER, alimiter, af); REGISTER_FILTER(ALLPASS, allpass, af); REGISTER_FILTER(ALOOP, aloop, af); + REGISTER_FILTER(AMBISONIC, ambisonic, af); REGISTER_FILTER(AMERGE, amerge, af); REGISTER_FILTER(AMETADATA, ametadata, af); REGISTER_FILTER(AMIX, amix, af); -- 2.7.4