LCOV - code coverage report
Current view: top level - libavfilter - af_crossfeed.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 61 0.0 %
Date: 2017-12-17 11:58:42 Functions: 0 3 0.0 %

          Line data    Source code
       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             : #include "libavutil/channel_layout.h"
      20             : #include "libavutil/opt.h"
      21             : #include "avfilter.h"
      22             : #include "audio.h"
      23             : #include "formats.h"
      24             : 
      25             : typedef struct CrossfeedContext {
      26             :     const AVClass *class;
      27             : 
      28             :     double range;
      29             :     double strength;
      30             :     double level_in;
      31             :     double level_out;
      32             : 
      33             :     double a0, a1, a2;
      34             :     double b0, b1, b2;
      35             : 
      36             :     double i1, i2;
      37             :     double o1, o2;
      38             : } CrossfeedContext;
      39             : 
      40           0 : static int query_formats(AVFilterContext *ctx)
      41             : {
      42           0 :     AVFilterFormats *formats = NULL;
      43           0 :     AVFilterChannelLayouts *layout = NULL;
      44             :     int ret;
      45             : 
      46           0 :     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_DBL  )) < 0 ||
      47           0 :         (ret = ff_set_common_formats         (ctx     , formats            )) < 0 ||
      48           0 :         (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO)) < 0 ||
      49           0 :         (ret = ff_set_common_channel_layouts (ctx     , layout             )) < 0 ||
      50           0 :         (ret = ff_set_common_samplerates     (ctx     , ff_all_samplerates())) < 0)
      51           0 :         return ret;
      52             : 
      53           0 :     return 0;
      54             : }
      55             : 
      56           0 : static int config_input(AVFilterLink *inlink)
      57             : {
      58           0 :     AVFilterContext *ctx = inlink->dst;
      59           0 :     CrossfeedContext *s = ctx->priv;
      60           0 :     double A = exp(s->strength * -30 / 40 * log(10.));
      61           0 :     double w0 = 2 * M_PI * (1. - s->range) * 2100 / inlink->sample_rate;
      62             :     double alpha;
      63             : 
      64           0 :     alpha = sin(w0) / 2 * sqrt(2 * (1 / 0.5 - 1) + 2);
      65             : 
      66           0 :     s->a0 =          (A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha;
      67           0 :     s->a1 =    -2 * ((A - 1) + (A + 1) * cos(w0));
      68           0 :     s->a2 =          (A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha;
      69           0 :     s->b0 =     A * ((A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha);
      70           0 :     s->b1 = 2 * A * ((A - 1) - (A + 1) * cos(w0));
      71           0 :     s->b2 =     A * ((A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha);
      72             : 
      73           0 :     s->a1 /= s->a0;
      74           0 :     s->a2 /= s->a0;
      75           0 :     s->b0 /= s->a0;
      76           0 :     s->b1 /= s->a0;
      77           0 :     s->b2 /= s->a0;
      78             : 
      79           0 :     return 0;
      80             : }
      81             : 
      82           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
      83             : {
      84           0 :     AVFilterContext *ctx = inlink->dst;
      85           0 :     AVFilterLink *outlink = ctx->outputs[0];
      86           0 :     CrossfeedContext *s = ctx->priv;
      87           0 :     const double *src = (const double *)in->data[0];
      88           0 :     const double level_in = s->level_in;
      89           0 :     const double level_out = s->level_out;
      90           0 :     const double b0 = s->b0;
      91           0 :     const double b1 = s->b1;
      92           0 :     const double b2 = s->b2;
      93           0 :     const double a1 = s->a1;
      94           0 :     const double a2 = s->a2;
      95             :     AVFrame *out;
      96             :     double *dst;
      97             :     int n;
      98             : 
      99           0 :     if (av_frame_is_writable(in)) {
     100           0 :         out = in;
     101             :     } else {
     102           0 :         out = ff_get_audio_buffer(inlink, in->nb_samples);
     103           0 :         if (!out) {
     104           0 :             av_frame_free(&in);
     105           0 :             return AVERROR(ENOMEM);
     106             :         }
     107           0 :         av_frame_copy_props(out, in);
     108             :     }
     109           0 :     dst = (double *)out->data[0];
     110             : 
     111           0 :     for (n = 0; n < out->nb_samples; n++, src += 2, dst += 2) {
     112           0 :         double mid = (src[0] + src[1]) * level_in * .5;
     113           0 :         double side = (src[0] - src[1]) * level_in * .5;
     114           0 :         double oside = side * b0 + s->i1 * b1 + s->i2 * b2 - s->o1 * a1 - s->o2 * a2;
     115             : 
     116           0 :         s->i2 = s->i1;
     117           0 :         s->i1 = side;
     118           0 :         s->o2 = s->o1;
     119           0 :         s->o1 = oside;
     120             : 
     121           0 :         dst[0] = (mid + oside) * level_out;
     122           0 :         dst[1] = (mid - oside) * level_out;
     123             :     }
     124             : 
     125           0 :     if (out != in)
     126           0 :         av_frame_free(&in);
     127           0 :     return ff_filter_frame(outlink, out);
     128             : }
     129             : 
     130             : #define OFFSET(x) offsetof(CrossfeedContext, x)
     131             : #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
     132             : 
     133             : static const AVOption crossfeed_options[] = {
     134             :     { "strength",  "set crossfeed strength",  OFFSET(strength),  AV_OPT_TYPE_DOUBLE, {.dbl=.2}, 0, 1, FLAGS },
     135             :     { "range",     "set soundstage wideness", OFFSET(range),     AV_OPT_TYPE_DOUBLE, {.dbl=.5}, 0, 1, FLAGS },
     136             :     { "level_in",  "set level in",            OFFSET(level_in),  AV_OPT_TYPE_DOUBLE, {.dbl=.9}, 0, 1, FLAGS },
     137             :     { "level_out", "set level out",           OFFSET(level_out), AV_OPT_TYPE_DOUBLE, {.dbl=1.}, 0, 1, FLAGS },
     138             :     { NULL }
     139             : };
     140             : 
     141             : AVFILTER_DEFINE_CLASS(crossfeed);
     142             : 
     143             : static const AVFilterPad inputs[] = {
     144             :     {
     145             :         .name         = "default",
     146             :         .type         = AVMEDIA_TYPE_AUDIO,
     147             :         .filter_frame = filter_frame,
     148             :         .config_props = config_input,
     149             :     },
     150             :     { NULL }
     151             : };
     152             : 
     153             : static const AVFilterPad outputs[] = {
     154             :     {
     155             :         .name = "default",
     156             :         .type = AVMEDIA_TYPE_AUDIO,
     157             :     },
     158             :     { NULL }
     159             : };
     160             : 
     161             : AVFilter ff_af_crossfeed = {
     162             :     .name           = "crossfeed",
     163             :     .description    = NULL_IF_CONFIG_SMALL("Apply headphone crossfeed filter."),
     164             :     .query_formats  = query_formats,
     165             :     .priv_size      = sizeof(CrossfeedContext),
     166             :     .priv_class     = &crossfeed_class,
     167             :     .inputs         = inputs,
     168             :     .outputs        = outputs,
     169             : };

Generated by: LCOV version 1.13