LCOV - code coverage report
Current view: top level - src/libavfilter - avf_aphasemeter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 64 121 52.9 %
Date: 2017-06-22 08:51:55 Functions: 6 7 85.7 %

          Line data    Source code
       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 do_video;
      41             :     int w, h;
      42             :     AVRational frame_rate;
      43             :     int contrast[4];
      44             :     uint8_t *mpc_str;
      45             :     uint8_t mpc[4];
      46             :     int draw_median_phase;
      47             : } AudioPhaseMeterContext;
      48             : 
      49             : #define OFFSET(x) offsetof(AudioPhaseMeterContext, x)
      50             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      51             : 
      52             : static const AVOption aphasemeter_options[] = {
      53             :     { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS },
      54             :     { "r",    "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS },
      55             :     { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="800x400"}, 0, 0, FLAGS },
      56             :     { "s",    "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="800x400"}, 0, 0, FLAGS },
      57             :     { "rc", "set red contrast",   OFFSET(contrast[0]), AV_OPT_TYPE_INT, {.i64=2}, 0, 255, FLAGS },
      58             :     { "gc", "set green contrast", OFFSET(contrast[1]), AV_OPT_TYPE_INT, {.i64=7}, 0, 255, FLAGS },
      59             :     { "bc", "set blue contrast",  OFFSET(contrast[2]), AV_OPT_TYPE_INT, {.i64=1}, 0, 255, FLAGS },
      60             :     { "mpc", "set median phase color", OFFSET(mpc_str), AV_OPT_TYPE_STRING, {.str = "none"}, 0, 0, FLAGS },
      61             :     { "video", "set video output", OFFSET(do_video), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
      62             :     { NULL }
      63             : };
      64             : 
      65             : AVFILTER_DEFINE_CLASS(aphasemeter);
      66             : 
      67           2 : static int query_formats(AVFilterContext *ctx)
      68             : {
      69           2 :     AudioPhaseMeterContext *s = ctx->priv;
      70           2 :     AVFilterFormats *formats = NULL;
      71           2 :     AVFilterChannelLayouts *layout = NULL;
      72           2 :     AVFilterLink *inlink = ctx->inputs[0];
      73           2 :     AVFilterLink *outlink = ctx->outputs[0];
      74             :     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE };
      75             :     static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE };
      76             :     int ret;
      77             : 
      78           2 :     formats = ff_make_format_list(sample_fmts);
      79           4 :     if ((ret = ff_formats_ref         (formats, &inlink->out_formats        )) < 0 ||
      80           4 :         (ret = ff_formats_ref         (formats, &outlink->in_formats        )) < 0 ||
      81           2 :         (ret = ff_add_channel_layout  (&layout, AV_CH_LAYOUT_STEREO         )) < 0 ||
      82           4 :         (ret = ff_channel_layouts_ref (layout , &inlink->out_channel_layouts)) < 0 ||
      83           2 :         (ret = ff_channel_layouts_ref (layout , &outlink->in_channel_layouts)) < 0)
      84           0 :         return ret;
      85             : 
      86           2 :     formats = ff_all_samplerates();
      87           4 :     if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0 ||
      88           2 :         (ret = ff_formats_ref(formats, &outlink->in_samplerates)) < 0)
      89           0 :         return ret;
      90             : 
      91           2 :     if (s->do_video) {
      92           0 :         AVFilterLink *outlink = ctx->outputs[1];
      93             : 
      94           0 :         formats = ff_make_format_list(pix_fmts);
      95           0 :         if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0)
      96           0 :             return ret;
      97             :     }
      98             : 
      99           2 :     return 0;
     100             : }
     101             : 
     102           2 : static int config_input(AVFilterLink *inlink)
     103             : {
     104           2 :     AVFilterContext *ctx = inlink->dst;
     105           2 :     AudioPhaseMeterContext *s = ctx->priv;
     106             :     int nb_samples;
     107             : 
     108           2 :     if (s->do_video) {
     109           0 :         nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5);
     110           0 :         inlink->partial_buf_size =
     111           0 :         inlink->min_samples =
     112           0 :         inlink->max_samples = nb_samples;
     113             :     }
     114             : 
     115           2 :     return 0;
     116             : }
     117             : 
     118           0 : static int config_video_output(AVFilterLink *outlink)
     119             : {
     120           0 :     AVFilterContext *ctx = outlink->src;
     121           0 :     AudioPhaseMeterContext *s = ctx->priv;
     122             : 
     123           0 :     outlink->w = s->w;
     124           0 :     outlink->h = s->h;
     125           0 :     outlink->sample_aspect_ratio = (AVRational){1,1};
     126           0 :     outlink->frame_rate = s->frame_rate;
     127             : 
     128           0 :     if (!strcmp(s->mpc_str, "none"))
     129           0 :         s->draw_median_phase = 0;
     130           0 :     else if (av_parse_color(s->mpc, s->mpc_str, -1, ctx) >= 0)
     131           0 :         s->draw_median_phase = 1;
     132             :     else
     133           0 :         return AVERROR(EINVAL);
     134             : 
     135           0 :     return 0;
     136             : }
     137             : 
     138       96000 : static inline int get_x(float phase, int w)
     139             : {
     140       96000 :   return (phase + 1.) / 2. * (w - 1);
     141             : }
     142             : 
     143          58 : static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     144             : {
     145          58 :     AVFilterContext *ctx = inlink->dst;
     146          58 :     AudioPhaseMeterContext *s = ctx->priv;
     147          58 :     AVFilterLink *outlink = s->do_video ? ctx->outputs[1] : NULL;
     148          58 :     AVFilterLink *aoutlink = ctx->outputs[0];
     149             :     AVDictionary **metadata;
     150          58 :     const int rc = s->contrast[0];
     151          58 :     const int gc = s->contrast[1];
     152          58 :     const int bc = s->contrast[2];
     153          58 :     float fphase = 0;
     154             :     AVFrame *out;
     155             :     uint8_t *dst;
     156             :     int i;
     157             : 
     158          58 :     if (s->do_video && (!s->out || s->out->width  != outlink->w ||
     159           0 :                                    s->out->height != outlink->h)) {
     160           0 :         av_frame_free(&s->out);
     161           0 :         s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     162           0 :         if (!s->out) {
     163           0 :             av_frame_free(&in);
     164           0 :             return AVERROR(ENOMEM);
     165             :         }
     166             : 
     167           0 :         out = s->out;
     168           0 :         for (i = 0; i < outlink->h; i++)
     169           0 :             memset(out->data[0] + i * out->linesize[0], 0, outlink->w * 4);
     170          58 :     } else if (s->do_video) {
     171           0 :         out = s->out;
     172           0 :         for (i = outlink->h - 1; i >= 10; i--)
     173           0 :             memmove(out->data[0] + (i  ) * out->linesize[0],
     174           0 :                     out->data[0] + (i-1) * out->linesize[0],
     175           0 :                     outlink->w * 4);
     176           0 :         for (i = 0; i < outlink->w; i++)
     177           0 :             AV_WL32(out->data[0] + i * 4, 0);
     178             :     }
     179             : 
     180       96058 :     for (i = 0; i < in->nb_samples; i++) {
     181       96000 :         const float *src = (float *)in->data[0] + i * 2;
     182       96000 :         const float f = src[0] * src[1] / (src[0]*src[0] + src[1] * src[1]) * 2;
     183       96000 :         const float phase = isnan(f) ? 1 : f;
     184       96000 :         const int x = get_x(phase, s->w);
     185             : 
     186       96000 :         if (s->do_video) {
     187           0 :             dst = out->data[0] + x * 4;
     188           0 :             dst[0] = FFMIN(255, dst[0] + rc);
     189           0 :             dst[1] = FFMIN(255, dst[1] + gc);
     190           0 :             dst[2] = FFMIN(255, dst[2] + bc);
     191           0 :             dst[3] = 255;
     192             :         }
     193       96000 :         fphase += phase;
     194             :     }
     195          58 :     fphase /= in->nb_samples;
     196             : 
     197          58 :     if (s->do_video) {
     198           0 :         if (s->draw_median_phase) {
     199           0 :             dst = out->data[0] + get_x(fphase, s->w) * 4;
     200           0 :             AV_WL32(dst, AV_RL32(s->mpc));
     201             :         }
     202             : 
     203           0 :         for (i = 1; i < 10 && i < outlink->h; i++)
     204           0 :             memcpy(out->data[0] + i * out->linesize[0], out->data[0], outlink->w * 4);
     205             :     }
     206             : 
     207          58 :     metadata = &in->metadata;
     208          58 :     if (metadata) {
     209             :         uint8_t value[128];
     210             : 
     211          58 :         snprintf(value, sizeof(value), "%f", fphase);
     212          58 :         av_dict_set(metadata, "lavfi.aphasemeter.phase", value, 0);
     213             :     }
     214             : 
     215          58 :     if (s->do_video) {
     216           0 :         s->out->pts = in->pts;
     217           0 :         ff_filter_frame(outlink, av_frame_clone(s->out));
     218             :     }
     219          58 :     return ff_filter_frame(aoutlink, in);
     220             : }
     221             : 
     222           2 : static av_cold void uninit(AVFilterContext *ctx)
     223             : {
     224           2 :     AudioPhaseMeterContext *s = ctx->priv;
     225             :     int i;
     226             : 
     227           2 :     av_frame_free(&s->out);
     228           4 :     for (i = 0; i < ctx->nb_outputs; i++)
     229           2 :         av_freep(&ctx->output_pads[i].name);
     230           2 : }
     231             : 
     232           2 : static av_cold int init(AVFilterContext *ctx)
     233             : {
     234           2 :     AudioPhaseMeterContext *s = ctx->priv;
     235             :     AVFilterPad pad;
     236             : 
     237           2 :     pad = (AVFilterPad){
     238           2 :         .name         = av_strdup("out0"),
     239             :         .type         = AVMEDIA_TYPE_AUDIO,
     240             :     };
     241           2 :     if (!pad.name)
     242           0 :         return AVERROR(ENOMEM);
     243           2 :     ff_insert_outpad(ctx, 0, &pad);
     244             : 
     245           2 :     if (s->do_video) {
     246           0 :         pad = (AVFilterPad){
     247           0 :             .name         = av_strdup("out1"),
     248             :             .type         = AVMEDIA_TYPE_VIDEO,
     249             :             .config_props = config_video_output,
     250             :         };
     251           0 :         if (!pad.name)
     252           0 :             return AVERROR(ENOMEM);
     253           0 :         ff_insert_outpad(ctx, 1, &pad);
     254             :     }
     255             : 
     256           2 :     return 0;
     257             : }
     258             : 
     259             : static const AVFilterPad inputs[] = {
     260             :     {
     261             :         .name         = "default",
     262             :         .type         = AVMEDIA_TYPE_AUDIO,
     263             :         .config_props = config_input,
     264             :         .filter_frame = filter_frame,
     265             :     },
     266             :     { NULL }
     267             : };
     268             : 
     269             : AVFilter ff_avf_aphasemeter = {
     270             :     .name          = "aphasemeter",
     271             :     .description   = NULL_IF_CONFIG_SMALL("Convert input audio to phase meter video output."),
     272             :     .init          = init,
     273             :     .uninit        = uninit,
     274             :     .query_formats = query_formats,
     275             :     .priv_size     = sizeof(AudioPhaseMeterContext),
     276             :     .inputs        = inputs,
     277             :     .outputs       = NULL,
     278             :     .priv_class    = &aphasemeter_class,
     279             :     .flags         = AVFILTER_FLAG_DYNAMIC_OUTPUTS,
     280             : };

Generated by: LCOV version 1.13