Showing the changes to libavfilter (2 of 3 files). Show all
Unified · Split
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #include "audio.h" | 26 | #include "audio.h" |
| 27 | #include "avfilter.h" | 27 | #include "avfilter.h" |
| 28 | #include "filters.h" | 28 | #include "filters.h" |
| 29 | #include "formats.h" | ||
| 29 | #include "internal.h" | 30 | #include "internal.h" |
| 30 | 31 | ||
| 31 | enum OutModes { | 32 | enum OutModes { |
| @@ -45,6 +46,7 @@ typedef struct AudioNLMSContext { · 13 unmodified lines | |||
| 45 | float eps; | 46 | float eps; |
| 46 | float leakage; | 47 | float leakage; |
| 47 | int output_mode; | 48 | int output_mode; |
| 49 | int precision; | ||
| 48 | 50 | ||
| 49 | int kernel_size; | 51 | int kernel_size; |
| 50 | AVFrame *offset; | 52 | AVFrame *offset; |
| @@ -56,6 +58,8 @@ typedef struct AudioNLMSContext { · 5 unmodified lines | |||
| 56 | 58 | ||
| 57 | int anlmf; | 59 | int anlmf; |
| 58 | 60 | ||
| 61 | int (*filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); | ||
| 62 | |||
| 59 | AVFloatDSPContext *fdsp; | 63 | AVFloatDSPContext *fdsp; |
| 60 | } AudioNLMSContext; | 64 | } AudioNLMSContext; |
| 61 | 65 | ||
| @@ -74,93 +78,32 @@ static const AVOption anlms_options[] = { · 12 unmodified lines | |||
| 74 | { "o", "output", 0, AV_OPT_TYPE_CONST, {.i64=OUT_MODE}, 0, 0, AT, "mode" }, | 78 | { "o", "output", 0, AV_OPT_TYPE_CONST, {.i64=OUT_MODE}, 0, 0, AT, "mode" }, |
| 75 | { "n", "noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_MODE}, 0, 0, AT, "mode" }, | 79 | { "n", "noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_MODE}, 0, 0, AT, "mode" }, |
| 76 | { "e", "error", 0, AV_OPT_TYPE_CONST, {.i64=ERROR_MODE}, 0, 0, AT, "mode" }, | 80 | { "e", "error", 0, AV_OPT_TYPE_CONST, {.i64=ERROR_MODE}, 0, 0, AT, "mode" }, |
| 81 | { "precision", "set processing precision", OFFSET(precision), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, A, "precision" }, | ||
| 82 | { "auto", "set auto processing precision", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, "precision" }, | ||
| 83 | { "float", "set single-floating point processing precision", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, "precision" }, | ||
| 84 | { "double","set double-floating point processing precision", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, A, "precision" }, | ||
| 77 | { NULL } | 85 | { NULL } |
| 78 | }; | 86 | }; |
| 79 | 87 | ||
| 80 | AVFILTER_DEFINE_CLASS_EXT(anlms, "anlm(f|s)", anlms_options); | 88 | AVFILTER_DEFINE_CLASS_EXT(anlms, "anlm(f|s)", anlms_options); |
| 81 | 89 | ||
| 82 | static float fir_sample(AudioNLMSContext *s, float sample, float *delay, | 90 | static int query_formats(AVFilterContext *ctx) |
| 83 | float *coeffs, float *tmp, int *offset) | ||
| 84 | { | 91 | { |
| 85 | const int order = s->order; | 92 | AudioNLMSContext *s = ctx->priv; |
| 86 | float output; | 93 | static const enum AVSampleFormat sample_fmts[3][3] = { |
| 87 | 94 | { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, | |
| 88 | delay[*offset] = sample; | 95 | { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, |
| 89 | 96 | { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }, | |
| 90 | memcpy(tmp, coeffs + order - *offset, order * sizeof(float)); | 97 | }; |
| 91 | 98 | int ret; | |
| 92 | output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size); | ||
| 93 | |||
| 94 | if (--(*offset) < 0) | ||
| 95 | *offset = order - 1; | ||
| 96 | |||
| 97 | return output; | ||
| 98 | } | ||
| 99 | |||
| 100 | static float process_sample(AudioNLMSContext *s, float input, float desired, | ||
| 101 | float *delay, float *coeffs, float *tmp, int *offsetp) | ||
| 102 | { | ||
| 103 | const int order = s->order; | ||
| 104 | const float leakage = s->leakage; | ||
| 105 | const float mu = s->mu; | ||
| 106 | const float a = 1.f - leakage; | ||
| 107 | float sum, output, e, norm, b; | ||
| 108 | int offset = *offsetp; | ||
| 109 | |||
| 110 | delay[offset + order] = input; | ||
| 111 | |||
| 112 | output = fir_sample(s, input, delay, coeffs, tmp, offsetp); | ||
| 113 | e = desired - output; | ||
| 114 | |||
| 115 | sum = s->fdsp->scalarproduct_float(delay, delay, s->kernel_size); | ||
| 116 | |||
| 117 | norm = s->eps + sum; | ||
| 118 | b = mu * e / norm; | ||
| 119 | if (s->anlmf) | ||
| 120 | b *= e * e; | ||
| 121 | |||
| 122 | memcpy(tmp, delay + offset, order * sizeof(float)); | ||
| 123 | |||
| 124 | s->fdsp->vector_fmul_scalar(coeffs, coeffs, a, s->kernel_size); | ||
| 125 | 99 | ||
| 126 | s->fdsp->vector_fmac_scalar(coeffs, tmp, b, s->kernel_size); | 100 | if ((ret = ff_set_common_all_channel_counts(ctx)) < 0) |
| 101 | return ret; | ||
| 127 | 102 | ||
| 128 | memcpy(coeffs + order, coeffs, order * sizeof(float)); | 103 | if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0) |
| 104 | return ret; | ||
| 129 | 105 | ||
| 130 | switch (s->output_mode) { | 106 | return ff_set_common_all_samplerates(ctx); |
| 131 | case IN_MODE: output = input; break; | ||
| 132 | case DESIRED_MODE: output = desired; break; | ||
| 133 | case OUT_MODE: output = desired - output; break; | ||
| 134 | case NOISE_MODE: output = input - output; break; | ||
| 135 | case ERROR_MODE: break; | ||
| 136 | } | ||
| 137 | return output; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int process_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | ||
| 141 | { | ||
| 142 | AudioNLMSContext *s = ctx->priv; | ||
| 143 | AVFrame *out = arg; | ||
| 144 | const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs; | ||
| 145 | const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs; | ||
| 146 | |||
| 147 | for (int c = start; c < end; c++) { | ||
| 148 | const float *input = (const float *)s->frame[0]->extended_data[c]; | ||
| 149 | const float *desired = (const float *)s->frame[1]->extended_data[c]; | ||
| 150 | float *delay = (float *)s->delay->extended_data[c]; | ||
| 151 | float *coeffs = (float *)s->coeffs->extended_data[c]; | ||
| 152 | float *tmp = (float *)s->tmp->extended_data[c]; | ||
| 153 | int *offset = (int *)s->offset->extended_data[c]; | ||
| 154 | float *output = (float *)out->extended_data[c]; | ||
| 155 | |||
| 156 | for (int n = 0; n < out->nb_samples; n++) { | ||
| 157 | output[n] = process_sample(s, input[n], desired[n], delay, coeffs, tmp, offset); | ||
| 158 | if (ctx->is_disabled) | ||
| 159 | output[n] = input[n]; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | 107 | } |
| 165 | 108 | ||
| 166 | static int activate(AVFilterContext *ctx) | 109 | static int activate(AVFilterContext *ctx) |
| @@ -195,7 +138,7 @@ static int activate(AVFilterContext *ctx) · 28 unmodified lines | |||
| 195 | return AVERROR(ENOMEM); | 138 | return AVERROR(ENOMEM); |
| 196 | } | 139 | } |
| 197 | 140 | ||
| 198 | ff_filter_execute(ctx, process_channels, out, NULL, | 141 | ff_filter_execute(ctx, s->filter_channels, out, NULL, |
| 199 | FFMIN(ctx->outputs[0]->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx))); | 142 | FFMIN(ctx->outputs[0]->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx))); |
| 200 | 143 | ||
| 201 | out->pts = s->frame[0]->pts; | 144 | out->pts = s->frame[0]->pts; |
| @@ -228,6 +171,13 @@ static int activate(AVFilterContext *ctx) · 26 unmodified lines | |||
| 228 | return 0; | 171 | return 0; |
| 229 | } | 172 | } |
| 230 | 173 | ||
| 174 | #define DEPTH 32 | ||
| 175 | #include "anlms_template.c" | ||
| 176 | |||
| 177 | #undef DEPTH | ||
| 178 | #define DEPTH 64 | ||
| 179 | #include "anlms_template.c" | ||
| 180 | |||
| 231 | static int config_output(AVFilterLink *outlink) | 181 | static int config_output(AVFilterLink *outlink) |
| 232 | { | 182 | { |
| 233 | AVFilterContext *ctx = outlink->src; | 183 | AVFilterContext *ctx = outlink->src; |
| @@ -247,6 +197,15 @@ static int config_output(AVFilterLink *outlink) · 13 unmodified lines | |||
| 247 | if (!s->delay || !s->coeffs || !s->offset || !s->tmp) | 197 | if (!s->delay || !s->coeffs || !s->offset || !s->tmp) |
| 248 | return AVERROR(ENOMEM); | 198 | return AVERROR(ENOMEM); |
| 249 | 199 | ||
| 200 | switch (outlink->format) { | ||
| 201 | case AV_SAMPLE_FMT_DBLP: | ||
| 202 | s->filter_channels = filter_channels_double; | ||
| 203 | break; | ||
| 204 | case AV_SAMPLE_FMT_FLTP: | ||
| 205 | s->filter_channels = filter_channels_float; | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | |||
| 250 | return 0; | 209 | return 0; |
| 251 | } | 210 | } |
| 252 | 211 | ||
| @@ -317,7 +276,7 @@ const AVFilter ff_af_anlmf = { · 64 unmodified lines | |||
| 317 | .activate = activate, | 276 | .activate = activate, |
| 318 | FILTER_INPUTS(inputs), | 277 | FILTER_INPUTS(inputs), |
| 319 | FILTER_OUTPUTS(outputs), | 278 | FILTER_OUTPUTS(outputs), |
| 320 | FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP), | 279 | FILTER_QUERY_FUNC(query_formats), |
| 321 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | | 280 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | |
| 322 | AVFILTER_FLAG_SLICE_THREADS, | 281 | AVFILTER_FLAG_SLICE_THREADS, |
| 323 | .process_command = ff_filter_process_command, | 282 | .process_command = ff_filter_process_command, |
| @@ -0,0 +1,141 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #undef ONE | ||
| 20 | #undef ftype | ||
| 21 | #undef SAMPLE_FORMAT | ||
| 22 | #if DEPTH == 32 | ||
| 23 | #define SAMPLE_FORMAT float | ||
| 24 | #define ftype float | ||
| 25 | #define ONE 1.f | ||
| 26 | #else | ||
| 27 | #define SAMPLE_FORMAT double | ||
| 28 | #define ftype double | ||
| 29 | #define ONE 1.0 | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #define fn3(a,b) a##_##b | ||
| 33 | #define fn2(a,b) fn3(a,b) | ||
| 34 | #define fn(a) fn2(a, SAMPLE_FORMAT) | ||
| 35 | |||
| 36 | #if DEPTH == 64 | ||
| 37 | static double scalarproduct_double(const double *v1, const double *v2, int len) | ||
| 38 | { | ||
| 39 | double p = 0.0; | ||
| 40 | |||
| 41 | for (int i = 0; i < len; i++) | ||
| 42 | p += v1[i] * v2[i]; | ||
| 43 | |||
| 44 | return p; | ||
| 45 | } | ||
| 46 | #endif | ||
| 47 | |||
| 48 | static ftype fn(fir_sample)(AudioNLMSContext *s, ftype sample, ftype *delay, | ||
| 49 | ftype *coeffs, ftype *tmp, int *offset) | ||
| 50 | { | ||
| 51 | const int order = s->order; | ||
| 52 | ftype output; | ||
| 53 | |||
| 54 | delay[*offset] = sample; | ||
| 55 | |||
| 56 | memcpy(tmp, coeffs + order - *offset, order * sizeof(ftype)); | ||
| 57 | |||
| 58 | #if DEPTH == 32 | ||
| 59 | output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size); | ||
| 60 | #else | ||
| 61 | output = scalarproduct_double(delay, tmp, s->kernel_size); | ||
| 62 | #endif | ||
| 63 | |||
| 64 | if (--(*offset) < 0) | ||
| 65 | *offset = order - 1; | ||
| 66 | |||
| 67 | return output; | ||
| 68 | } | ||
| 69 | |||
| 70 | static ftype fn(process_sample)(AudioNLMSContext *s, ftype input, ftype desired, | ||
| 71 | ftype *delay, ftype *coeffs, ftype *tmp, int *offsetp) | ||
| 72 | { | ||
| 73 | const int order = s->order; | ||
| 74 | const ftype leakage = s->leakage; | ||
| 75 | const ftype mu = s->mu; | ||
| 76 | const ftype a = ONE - leakage; | ||
| 77 | ftype sum, output, e, norm, b; | ||
| 78 | int offset = *offsetp; | ||
| 79 | |||
| 80 | delay[offset + order] = input; | ||
| 81 | |||
| 82 | output = fn(fir_sample)(s, input, delay, coeffs, tmp, offsetp); | ||
| 83 | e = desired - output; | ||
| 84 | |||
| 85 | #if DEPTH == 32 | ||
| 86 | sum = s->fdsp->scalarproduct_float(delay, delay, s->kernel_size); | ||
| 87 | #else | ||
| 88 | sum = scalarproduct_double(delay, delay, s->kernel_size); | ||
| 89 | #endif | ||
| 90 | norm = s->eps + sum; | ||
| 91 | b = mu * e / norm; | ||
| 92 | if (s->anlmf) | ||
| 93 | b *= e * e; | ||
| 94 | |||
| 95 | memcpy(tmp, delay + offset, order * sizeof(ftype)); | ||
| 96 | |||
| 97 | #if DEPTH == 32 | ||
| 98 | s->fdsp->vector_fmul_scalar(coeffs, coeffs, a, s->kernel_size); | ||
| 99 | s->fdsp->vector_fmac_scalar(coeffs, tmp, b, s->kernel_size); | ||
| 100 | #else | ||
| 101 | s->fdsp->vector_dmul_scalar(coeffs, coeffs, a, s->kernel_size); | ||
| 102 | s->fdsp->vector_dmac_scalar(coeffs, tmp, b, s->kernel_size); | ||
| 103 | #endif | ||
| 104 | |||
| 105 | memcpy(coeffs + order, coeffs, order * sizeof(ftype)); | ||
| 106 | |||
| 107 | switch (s->output_mode) { | ||
| 108 | case IN_MODE: output = input; break; | ||
| 109 | case DESIRED_MODE: output = desired; break; | ||
| 110 | case OUT_MODE: output = desired - output; break; | ||
| 111 | case NOISE_MODE: output = input - output; break; | ||
| 112 | case ERROR_MODE: break; | ||
| 113 | } | ||
| 114 | return output; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int fn(filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) | ||
| 118 | { | ||
| 119 | AudioNLMSContext *s = ctx->priv; | ||
| 120 | AVFrame *out = arg; | ||
| 121 | const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs; | ||
| 122 | const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs; | ||
| 123 | |||
| 124 | for (int c = start; c < end; c++) { | ||
| 125 | const ftype *input = (const ftype *)s->frame[0]->extended_data[c]; | ||
| 126 | const ftype *desired = (const ftype *)s->frame[1]->extended_data[c]; | ||
| 127 | ftype *delay = (ftype *)s->delay->extended_data[c]; | ||
| 128 | ftype *coeffs = (ftype *)s->coeffs->extended_data[c]; | ||
| 129 | ftype *tmp = (ftype *)s->tmp->extended_data[c]; | ||
| 130 | int *offset = (int *)s->offset->extended_data[c]; | ||
| 131 | ftype *output = (ftype *)out->extended_data[c]; | ||
| 132 | |||
| 133 | for (int n = 0; n < out->nb_samples; n++) { | ||
| 134 | output[n] = fn(process_sample)(s, input[n], desired[n], delay, coeffs, tmp, offset); | ||
| 135 | if (ctx->is_disabled) | ||
| 136 | output[n] = input[n]; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||