Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2015 Paul B Mahol
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. /**
  22.  * @file
  23.  * audio to video multimedia aphasemeter filter
  24.  */
  25.  
  26. #include "libavutil/avassert.h"
  27. #include "libavutil/channel_layout.h"
  28. #include "libavutil/intreadwrite.h"
  29. #include "libavutil/opt.h"
  30. #include "libavutil/parseutils.h"
  31. #include "avfilter.h"
  32. #include "formats.h"
  33. #include "audio.h"
  34. #include "video.h"
  35. #include "internal.h"
  36.  
  37. typedef struct AudioPhaseMeterContext {
  38.     const AVClass *class;
  39.     AVFrame *out;
  40.     int w, h;
  41.     AVRational frame_rate;
  42.     int contrast[4];
  43.     uint8_t *mpc_str;
  44.     uint8_t mpc[4];
  45.     int draw_median_phase;
  46. } AudioPhaseMeterContext;
  47.  
  48. #define OFFSET(x) offsetof(AudioPhaseMeterContext, x)
  49. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  50.  
  51. static const AVOption aphasemeter_options[] = {
  52.     { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS },
  53.     { "r",    "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS },
  54.     { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="800x400"}, 0, 0, FLAGS },
  55.     { "s",    "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="800x400"}, 0, 0, FLAGS },
  56.     { "rc", "set red contrast",   OFFSET(contrast[0]), AV_OPT_TYPE_INT, {.i64=2}, 0, 255, FLAGS },
  57.     { "gc", "set green contrast", OFFSET(contrast[1]), AV_OPT_TYPE_INT, {.i64=7}, 0, 255, FLAGS },
  58.     { "bc", "set blue contrast",  OFFSET(contrast[2]), AV_OPT_TYPE_INT, {.i64=1}, 0, 255, FLAGS },
  59.     { "mpc", "set median phase color", OFFSET(mpc_str), AV_OPT_TYPE_STRING, {.str = "none"}, 0, 0, FLAGS },
  60.     { NULL }
  61. };
  62.  
  63. AVFILTER_DEFINE_CLASS(aphasemeter);
  64.  
  65. static int query_formats(AVFilterContext *ctx)
  66. {
  67.     AVFilterFormats *formats = NULL;
  68.     AVFilterChannelLayouts *layout = NULL;
  69.     AVFilterLink *inlink = ctx->inputs[0];
  70.     AVFilterLink *outlink = ctx->outputs[0];
  71.     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE };
  72.     static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE };
  73.  
  74.     formats = ff_make_format_list(sample_fmts);
  75.     if (!formats)
  76.         return AVERROR(ENOMEM);
  77.     ff_formats_ref(formats, &inlink->out_formats);
  78.  
  79.     ff_add_channel_layout(&layout, AV_CH_LAYOUT_STEREO);
  80.     ff_channel_layouts_ref(layout, &inlink->out_channel_layouts);
  81.  
  82.     formats = ff_all_samplerates();
  83.     if (!formats)
  84.         return AVERROR(ENOMEM);
  85.     ff_formats_ref(formats, &inlink->out_samplerates);
  86.  
  87.     formats = ff_make_format_list(pix_fmts);
  88.     if (!formats)
  89.         return AVERROR(ENOMEM);
  90.     ff_formats_ref(formats, &outlink->in_formats);
  91.  
  92.     return 0;
  93. }
  94.  
  95. static int config_input(AVFilterLink *inlink)
  96. {
  97.     AVFilterContext *ctx = inlink->dst;
  98.     AudioPhaseMeterContext *s = ctx->priv;
  99.     int nb_samples;
  100.  
  101.     nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5);
  102.     inlink->partial_buf_size =
  103.     inlink->min_samples =
  104.     inlink->max_samples = nb_samples;
  105.  
  106.     return 0;
  107. }
  108.  
  109. static int config_output(AVFilterLink *outlink)
  110. {
  111.     AVFilterContext *ctx = outlink->src;
  112.     AudioPhaseMeterContext *s = ctx->priv;
  113.  
  114.     outlink->w = s->w;
  115.     outlink->h = s->h;
  116.     outlink->sample_aspect_ratio = (AVRational){1,1};
  117.     outlink->frame_rate = s->frame_rate;
  118.  
  119.     if (!strcmp(s->mpc_str, "none"))
  120.         s->draw_median_phase = 0;
  121.     else if (av_parse_color(s->mpc, s->mpc_str, -1, ctx) >= 0)
  122.         s->draw_median_phase = 1;
  123.     else
  124.         return AVERROR(EINVAL);
  125.  
  126.     return 0;
  127. }
  128.  
  129. static inline int get_x(float phase, int w)
  130. {
  131.   return (phase + 1.) / 2. * (w - 1);
  132. }
  133.  
  134. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  135. {
  136.     AVFilterContext *ctx = inlink->dst;
  137.     AVFilterLink *outlink = ctx->outputs[0];
  138.     AudioPhaseMeterContext *s = ctx->priv;
  139.     AVDictionary **metadata;
  140.     const int rc = s->contrast[0];
  141.     const int gc = s->contrast[1];
  142.     const int bc = s->contrast[2];
  143.     float fphase = 0;
  144.     AVFrame *out;
  145.     uint8_t *dst;
  146.     int i;
  147.  
  148.     if (!s->out || s->out->width  != outlink->w ||
  149.                    s->out->height != outlink->h) {
  150.         av_frame_free(&s->out);
  151.         s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  152.         if (!s->out) {
  153.             av_frame_free(&in);
  154.             return AVERROR(ENOMEM);
  155.         }
  156.  
  157.         out = s->out;
  158.         for (i = 0; i < outlink->h; i++)
  159.             memset(out->data[0] + i * out->linesize[0], 0, outlink->w * 4);
  160.     } else {
  161.         out = s->out;
  162.         for (i = outlink->h - 1; i >= 10; i--)
  163.             memmove(out->data[0] + (i  ) * out->linesize[0],
  164.                     out->data[0] + (i-1) * out->linesize[0],
  165.                     outlink->w * 4);
  166.         for (i = 0; i < outlink->w; i++)
  167.             AV_WL32(out->data[0] + i * 4, 0);
  168.     }
  169.     s->out->pts = in->pts;
  170.  
  171.     for (i = 0; i < in->nb_samples; i++) {
  172.         const float *src = (float *)in->data[0] + i * 2;
  173.         const float f = src[0] * src[1] / (src[0]*src[0] + src[1] * src[1]) * 2;
  174.         const float phase = isnan(f) ? 1 : f;
  175.         const int x = get_x(phase, s->w);
  176.  
  177.         dst = out->data[0] + x * 4;
  178.         dst[0] = FFMIN(255, dst[0] + rc);
  179.         dst[1] = FFMIN(255, dst[1] + gc);
  180.         dst[2] = FFMIN(255, dst[2] + bc);
  181.         dst[3] = 255;
  182.         fphase += phase;
  183.     }
  184.     fphase /= in->nb_samples;
  185.  
  186.     if (s->draw_median_phase) {
  187.         dst = out->data[0] + get_x(fphase, s->w) * 4;
  188.         AV_WL32(dst, AV_RL32(s->mpc));
  189.     }
  190.  
  191.     for (i = 1; i < 10 && i < outlink->h; i++)
  192.         memcpy(out->data[0] + i * out->linesize[0], out->data[0], outlink->w * 4);
  193.  
  194.     metadata = avpriv_frame_get_metadatap(out);
  195.     if (metadata) {
  196.         uint8_t value[128];
  197.  
  198.         snprintf(value, sizeof(value), "%f", fphase);
  199.         av_dict_set(metadata, "lavfi.aphasemeter.phase", value, 0);
  200.     }
  201.  
  202.     av_frame_free(&in);
  203.     return ff_filter_frame(outlink, av_frame_clone(s->out));
  204. }
  205.  
  206. static av_cold void uninit(AVFilterContext *ctx)
  207. {
  208.     AudioPhaseMeterContext *s = ctx->priv;
  209.  
  210.     av_frame_free(&s->out);
  211. }
  212.  
  213. static const AVFilterPad inputs[] = {
  214.     {
  215.         .name         = "default",
  216.         .type         = AVMEDIA_TYPE_AUDIO,
  217.         .config_props = config_input,
  218.         .filter_frame = filter_frame,
  219.     },
  220.     { NULL }
  221. };
  222.  
  223. static const AVFilterPad outputs[] = {
  224.     {
  225.         .name         = "default",
  226.         .type         = AVMEDIA_TYPE_VIDEO,
  227.         .config_props = config_output,
  228.     },
  229.     { NULL }
  230. };
  231.  
  232. AVFilter ff_avf_aphasemeter = {
  233.     .name          = "aphasemeter",
  234.     .description   = NULL_IF_CONFIG_SMALL("Convert input audio to phase meter video output."),
  235.     .uninit        = uninit,
  236.     .query_formats = query_formats,
  237.     .priv_size     = sizeof(AudioPhaseMeterContext),
  238.     .inputs        = inputs,
  239.     .outputs       = outputs,
  240.     .priv_class    = &aphasemeter_class,
  241. };
  242.