LCOV - code coverage report
Current view: top level - src/libavfilter - af_earwax.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 35 39 89.7 %
Date: 2017-06-24 07:01:58 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2011 Mina Nagy Zaki
       3             :  * Copyright (c) 2000 Edward Beingessner And Sundry Contributors.
       4             :  * This source code is freely redistributable and may be used for any purpose.
       5             :  * This copyright notice must be maintained.  Edward Beingessner And Sundry
       6             :  * Contributors are not responsible for the consequences of using this
       7             :  * software.
       8             :  *
       9             :  * This file is part of FFmpeg.
      10             :  *
      11             :  * FFmpeg is free software; you can redistribute it and/or
      12             :  * modify it under the terms of the GNU Lesser General Public
      13             :  * License as published by the Free Software Foundation; either
      14             :  * version 2.1 of the License, or (at your option) any later version.
      15             :  *
      16             :  * FFmpeg is distributed in the hope that it will be useful,
      17             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      19             :  * Lesser General Public License for more details.
      20             :  *
      21             :  * You should have received a copy of the GNU Lesser General Public
      22             :  * License along with FFmpeg; if not, write to the Free Software
      23             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      24             :  */
      25             : 
      26             : /**
      27             :  * @file
      28             :  * Stereo Widening Effect. Adds audio cues to move stereo image in
      29             :  * front of the listener. Adapted from the libsox earwax effect.
      30             :  */
      31             : 
      32             : #include "libavutil/channel_layout.h"
      33             : #include "avfilter.h"
      34             : #include "audio.h"
      35             : #include "formats.h"
      36             : 
      37             : #define NUMTAPS 64
      38             : 
      39             : static const int8_t filt[NUMTAPS] = {
      40             : /* 30°  330° */
      41             :     4,   -6,     /* 32 tap stereo FIR filter. */
      42             :     4,  -11,     /* One side filters as if the */
      43             :    -1,   -5,     /* signal was from 30 degrees */
      44             :     3,    3,     /* from the ear, the other as */
      45             :    -2,    5,     /* if 330 degrees. */
      46             :    -5,    0,
      47             :     9,    1,
      48             :     6,    3,     /*                         Input                         */
      49             :    -4,   -1,     /*                   Left         Right                  */
      50             :    -5,   -3,     /*                __________   __________                */
      51             :    -2,   -5,     /*               |          | |          |               */
      52             :    -7,    1,     /*           .---|  Hh,0(f) | |  Hh,0(f) |---.           */
      53             :     6,   -7,     /*          /    |__________| |__________|    \          */
      54             :    30,  -29,     /*         /                \ /                \         */
      55             :    12,   -3,     /*        /                  X                  \        */
      56             :   -11,    4,     /*       /                  / \                  \       */
      57             :    -3,    7,     /*  ____V_____   __________V   V__________   _____V____  */
      58             :   -20,   23,     /* |          | |          |   |          | |          | */
      59             :     2,    0,     /* | Hh,30(f) | | Hh,330(f)|   | Hh,330(f)| | Hh,30(f) | */
      60             :     1,   -6,     /* |__________| |__________|   |__________| |__________| */
      61             :   -14,   -5,     /*      \     ___      /           \      ___     /      */
      62             :    15,  -18,     /*       \   /   \    /    _____    \    /   \   /       */
      63             :     6,    7,     /*        `->| + |<--'    /     \    `-->| + |<-'        */
      64             :    15,  -10,     /*           \___/      _/       \_      \___/           */
      65             :   -14,   22,     /*               \     / \       / \     /               */
      66             :    -7,   -2,     /*                `--->| |       | |<---'                */
      67             :    -4,    9,     /*                     \_/       \_/                     */
      68             :     6,  -12,     /*                                                       */
      69             :     6,   -6,     /*                       Headphones                      */
      70             :     0,  -11,
      71             :     0,   -5,
      72             :     4,    0};
      73             : 
      74             : typedef struct EarwaxContext {
      75             :     int16_t taps[NUMTAPS * 2];
      76             : } EarwaxContext;
      77             : 
      78           1 : static int query_formats(AVFilterContext *ctx)
      79             : {
      80             :     static const int sample_rates[] = { 44100, -1 };
      81             :     int ret;
      82             : 
      83           1 :     AVFilterFormats *formats = NULL;
      84           1 :     AVFilterChannelLayouts *layout = NULL;
      85             : 
      86           2 :     if ((ret = ff_add_format                 (&formats, AV_SAMPLE_FMT_S16                 )) < 0 ||
      87           2 :         (ret = ff_set_common_formats         (ctx     , formats                           )) < 0 ||
      88           1 :         (ret = ff_add_channel_layout         (&layout , AV_CH_LAYOUT_STEREO               )) < 0 ||
      89           2 :         (ret = ff_set_common_channel_layouts (ctx     , layout                            )) < 0 ||
      90           1 :         (ret = ff_set_common_samplerates     (ctx     , ff_make_format_list(sample_rates) )) < 0)
      91           0 :         return ret;
      92             : 
      93           1 :     return 0;
      94             : }
      95             : 
      96             : //FIXME: replace with DSPContext.scalarproduct_int16
      97          40 : static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, int16_t *out)
      98             : {
      99             :     int32_t sample;
     100             :     int16_t j;
     101             : 
     102       41040 :     while (in < endin) {
     103       40960 :         sample = 0;
     104     2662400 :         for (j = 0; j < NUMTAPS; j++)
     105     2621440 :             sample += in[j] * filt[j];
     106       40960 :         *out = av_clip_int16(sample >> 6);
     107       40960 :         out++;
     108       40960 :         in++;
     109             :     }
     110             : 
     111          40 :     return out;
     112             : }
     113             : 
     114          20 : static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     115             : {
     116          20 :     AVFilterLink *outlink = inlink->dst->outputs[0];
     117             :     int16_t *taps, *endin, *in, *out;
     118          20 :     AVFrame *outsamples = ff_get_audio_buffer(inlink, insamples->nb_samples);
     119             :     int len;
     120             : 
     121          20 :     if (!outsamples) {
     122           0 :         av_frame_free(&insamples);
     123           0 :         return AVERROR(ENOMEM);
     124             :     }
     125          20 :     av_frame_copy_props(outsamples, insamples);
     126             : 
     127          20 :     taps  = ((EarwaxContext *)inlink->dst->priv)->taps;
     128          20 :     out   = (int16_t *)outsamples->data[0];
     129          20 :     in    = (int16_t *)insamples ->data[0];
     130             : 
     131          20 :     len = FFMIN(NUMTAPS, 2*insamples->nb_samples);
     132             :     // copy part of new input and process with saved input
     133          20 :     memcpy(taps+NUMTAPS, in, len * sizeof(*taps));
     134          20 :     out   = scalarproduct(taps, taps + len, out);
     135             : 
     136             :     // process current input
     137          20 :     if (2*insamples->nb_samples >= NUMTAPS ){
     138          20 :         endin = in + insamples->nb_samples * 2 - NUMTAPS;
     139          20 :         scalarproduct(in, endin, out);
     140             : 
     141             :         // save part of input for next round
     142          20 :         memcpy(taps, endin, NUMTAPS * sizeof(*taps));
     143             :     } else
     144           0 :         memmove(taps, taps + 2*insamples->nb_samples, NUMTAPS * sizeof(*taps));
     145             : 
     146          20 :     av_frame_free(&insamples);
     147          20 :     return ff_filter_frame(outlink, outsamples);
     148             : }
     149             : 
     150             : static const AVFilterPad earwax_inputs[] = {
     151             :     {
     152             :         .name         = "default",
     153             :         .type         = AVMEDIA_TYPE_AUDIO,
     154             :         .filter_frame = filter_frame,
     155             :     },
     156             :     { NULL }
     157             : };
     158             : 
     159             : static const AVFilterPad earwax_outputs[] = {
     160             :     {
     161             :         .name = "default",
     162             :         .type = AVMEDIA_TYPE_AUDIO,
     163             :     },
     164             :     { NULL }
     165             : };
     166             : 
     167             : AVFilter ff_af_earwax = {
     168             :     .name           = "earwax",
     169             :     .description    = NULL_IF_CONFIG_SMALL("Widen the stereo image."),
     170             :     .query_formats  = query_formats,
     171             :     .priv_size      = sizeof(EarwaxContext),
     172             :     .inputs         = earwax_inputs,
     173             :     .outputs        = earwax_outputs,
     174             : };

Generated by: LCOV version 1.13