Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. /**
  20.  * @file
  21.  * Bauer stereo-to-binaural filter
  22.  */
  23.  
  24. #include <bs2b.h>
  25.  
  26. #include "libavutil/channel_layout.h"
  27. #include "libavutil/common.h"
  28. #include "libavutil/opt.h"
  29.  
  30. #include "audio.h"
  31. #include "avfilter.h"
  32. #include "formats.h"
  33. #include "internal.h"
  34.  
  35. typedef struct Bs2bContext {
  36.     const AVClass *class;
  37.  
  38.     int profile;
  39.     int fcut;
  40.     int feed;
  41.  
  42.     t_bs2bdp bs2bp;
  43.  
  44.     void (*filter)(t_bs2bdp bs2bdp, uint8_t *sample, int n);
  45. } Bs2bContext;
  46.  
  47. #define OFFSET(x) offsetof(Bs2bContext, x)
  48. #define A AV_OPT_FLAG_AUDIO_PARAM
  49.  
  50. static const AVOption bs2b_options[] = {
  51.     { "profile", "Apply a pre-defined crossfeed level",
  52.             OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = BS2B_DEFAULT_CLEVEL }, 0, INT_MAX, A, "profile" },
  53.         { "default", "default profile", 0, AV_OPT_TYPE_CONST, { .i64 = BS2B_DEFAULT_CLEVEL }, 0, 0, A, "profile" },
  54.         { "cmoy",    "Chu Moy circuit", 0, AV_OPT_TYPE_CONST, { .i64 = BS2B_CMOY_CLEVEL    }, 0, 0, A, "profile" },
  55.         { "jmeier",  "Jan Meier circuit", 0, AV_OPT_TYPE_CONST, { .i64 = BS2B_JMEIER_CLEVEL  }, 0, 0, A, "profile" },
  56.     { "fcut", "Set cut frequency (in Hz)",
  57.             OFFSET(fcut), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, BS2B_MAXFCUT, A },
  58.     { "feed", "Set feed level (in Hz)",
  59.             OFFSET(feed), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, BS2B_MAXFEED, A },
  60.     { NULL },
  61. };
  62.  
  63. AVFILTER_DEFINE_CLASS(bs2b);
  64.  
  65. static av_cold int init(AVFilterContext *ctx)
  66. {
  67.     Bs2bContext *bs2b = ctx->priv;
  68.  
  69.     if (!(bs2b->bs2bp = bs2b_open()))
  70.         return AVERROR(ENOMEM);
  71.  
  72.     bs2b_set_level(bs2b->bs2bp, bs2b->profile);
  73.  
  74.     if (bs2b->fcut)
  75.         bs2b_set_level_fcut(bs2b->bs2bp, bs2b->fcut);
  76.  
  77.     if (bs2b->feed)
  78.         bs2b_set_level_feed(bs2b->bs2bp, bs2b->feed);
  79.  
  80.     return 0;
  81. }
  82.  
  83. static av_cold void uninit(AVFilterContext *ctx)
  84. {
  85.     Bs2bContext *bs2b = ctx->priv;
  86.  
  87.     if (bs2b->bs2bp)
  88.         bs2b_close(bs2b->bs2bp);
  89. }
  90.  
  91. static int query_formats(AVFilterContext *ctx)
  92. {
  93.     AVFilterFormats *formats = NULL;
  94.     AVFilterChannelLayouts *layouts = NULL;
  95.  
  96.     static const enum AVSampleFormat sample_fmts[] = {
  97.         AV_SAMPLE_FMT_U8,
  98.         AV_SAMPLE_FMT_S16,
  99.         AV_SAMPLE_FMT_S32,
  100.         AV_SAMPLE_FMT_FLT,
  101.         AV_SAMPLE_FMT_DBL,
  102.         AV_SAMPLE_FMT_NONE,
  103.     };
  104.     int ret;
  105.  
  106.     if (ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO) != 0)
  107.         return AVERROR(ENOMEM);
  108.     ret = ff_set_common_channel_layouts(ctx, layouts);
  109.     if (ret < 0)
  110.         return ret;
  111.  
  112.     formats = ff_make_format_list(sample_fmts);
  113.     if (!formats)
  114.         return AVERROR(ENOMEM);
  115.     ret = ff_set_common_formats(ctx, formats);
  116.     if (ret < 0)
  117.         return ret;
  118.  
  119.     formats = ff_all_samplerates();
  120.     if (!formats)
  121.         return AVERROR(ENOMEM);
  122.     return ff_set_common_samplerates(ctx, formats);
  123. }
  124.  
  125. static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
  126. {
  127.     int ret;
  128.     AVFrame *out_frame;
  129.  
  130.     Bs2bContext     *bs2b = inlink->dst->priv;
  131.     AVFilterLink *outlink = inlink->dst->outputs[0];
  132.  
  133.     if (av_frame_is_writable(frame)) {
  134.         out_frame = frame;
  135.     } else {
  136.         out_frame = ff_get_audio_buffer(inlink, frame->nb_samples);
  137.         if (!out_frame)
  138.             return AVERROR(ENOMEM);
  139.         av_frame_copy(out_frame, frame);
  140.         ret = av_frame_copy_props(out_frame, frame);
  141.         if (ret < 0) {
  142.             av_frame_free(&out_frame);
  143.             av_frame_free(&frame);
  144.             return ret;
  145.         }
  146.     }
  147.  
  148.     bs2b->filter(bs2b->bs2bp, out_frame->extended_data[0], out_frame->nb_samples);
  149.  
  150.     if (frame != out_frame)
  151.         av_frame_free(&frame);
  152.  
  153.     return ff_filter_frame(outlink, out_frame);
  154. }
  155.  
  156. static int config_output(AVFilterLink *outlink)
  157. {
  158.     AVFilterContext *ctx = outlink->src;
  159.     Bs2bContext    *bs2b = ctx->priv;
  160.     AVFilterLink *inlink = ctx->inputs[0];
  161.  
  162.     int srate = inlink->sample_rate;
  163.  
  164.     switch (inlink->format) {
  165.     case AV_SAMPLE_FMT_U8:
  166.         bs2b->filter = bs2b_cross_feed_u8;
  167.         break;
  168.     case AV_SAMPLE_FMT_S16:
  169.         bs2b->filter = (void*)bs2b_cross_feed_s16;
  170.         break;
  171.     case AV_SAMPLE_FMT_S32:
  172.         bs2b->filter = (void*)bs2b_cross_feed_s32;
  173.         break;
  174.     case AV_SAMPLE_FMT_FLT:
  175.         bs2b->filter = (void*)bs2b_cross_feed_f;
  176.         break;
  177.     case AV_SAMPLE_FMT_DBL:
  178.         bs2b->filter = (void*)bs2b_cross_feed_d;
  179.         break;
  180.     default:
  181.         return AVERROR_BUG;
  182.     }
  183.  
  184.     if ((srate < BS2B_MINSRATE) || (srate > BS2B_MAXSRATE))
  185.         return AVERROR(ENOSYS);
  186.  
  187.     bs2b_set_srate(bs2b->bs2bp, srate);
  188.  
  189.     return 0;
  190. }
  191.  
  192. static const AVFilterPad bs2b_inputs[] = {
  193.     {
  194.         .name           = "default",
  195.         .type           = AVMEDIA_TYPE_AUDIO,
  196.         .filter_frame   = filter_frame,
  197.     },
  198.     { NULL }
  199. };
  200.  
  201. static const AVFilterPad bs2b_outputs[] = {
  202.     {
  203.         .name           = "default",
  204.         .type           = AVMEDIA_TYPE_AUDIO,
  205.         .config_props   = config_output,
  206.     },
  207.     { NULL }
  208. };
  209.  
  210. AVFilter ff_af_bs2b = {
  211.     .name           = "bs2b",
  212.     .description    = NULL_IF_CONFIG_SMALL("Bauer stereo-to-binaural filter."),
  213.     .query_formats  = query_formats,
  214.     .priv_size      = sizeof(Bs2bContext),
  215.     .priv_class     = &bs2b_class,
  216.     .init           = init,
  217.     .uninit         = uninit,
  218.     .inputs         = bs2b_inputs,
  219.     .outputs        = bs2b_outputs,
  220. };
  221.