LCOV - code coverage report
Current view: top level - src/libavfilter - avf_showwaves.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 345 0.0 %
Date: 2017-04-23 07:57:23 Functions: 0 27 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012 Stefano Sabatini
       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 filter
      24             :  */
      25             : 
      26             : #include "libavutil/avassert.h"
      27             : #include "libavutil/avstring.h"
      28             : #include "libavutil/channel_layout.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             : enum ShowWavesMode {
      38             :     MODE_POINT,
      39             :     MODE_LINE,
      40             :     MODE_P2P,
      41             :     MODE_CENTERED_LINE,
      42             :     MODE_NB,
      43             : };
      44             : 
      45             : enum ShowWavesScale {
      46             :     SCALE_LIN,
      47             :     SCALE_LOG,
      48             :     SCALE_SQRT,
      49             :     SCALE_CBRT,
      50             :     SCALE_NB,
      51             : };
      52             : 
      53             : struct frame_node {
      54             :     AVFrame *frame;
      55             :     struct frame_node *next;
      56             : };
      57             : 
      58             : typedef struct {
      59             :     const AVClass *class;
      60             :     int w, h;
      61             :     AVRational rate;
      62             :     char *colors;
      63             :     int buf_idx;
      64             :     int16_t *buf_idy;    /* y coordinate of previous sample for each channel */
      65             :     AVFrame *outpicref;
      66             :     int n;
      67             :     int pixstep;
      68             :     int sample_count_mod;
      69             :     int mode;                   ///< ShowWavesMode
      70             :     int scale;                  ///< ShowWavesScale
      71             :     int split_channels;
      72             :     uint8_t *fg;
      73             : 
      74             :     int (*get_h)(int16_t sample, int height);
      75             :     void (*draw_sample)(uint8_t *buf, int height, int linesize,
      76             :                         int16_t *prev_y, const uint8_t color[4], int h);
      77             : 
      78             :     /* single picture */
      79             :     int single_pic;
      80             :     struct frame_node *audio_frames;
      81             :     struct frame_node *last_frame;
      82             :     int64_t total_samples;
      83             :     int64_t *sum; /* abs sum of the samples per channel */
      84             : } ShowWavesContext;
      85             : 
      86             : #define OFFSET(x) offsetof(ShowWavesContext, x)
      87             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      88             : 
      89             : static const AVOption showwaves_options[] = {
      90             :     { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
      91             :     { "s",    "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
      92             :     { "mode", "select display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_POINT}, 0, MODE_NB-1, FLAGS, "mode"},
      93             :         { "point", "draw a point for each sample",         0, AV_OPT_TYPE_CONST, {.i64=MODE_POINT},         .flags=FLAGS, .unit="mode"},
      94             :         { "line",  "draw a line for each sample",          0, AV_OPT_TYPE_CONST, {.i64=MODE_LINE},          .flags=FLAGS, .unit="mode"},
      95             :         { "p2p",   "draw a line between samples",          0, AV_OPT_TYPE_CONST, {.i64=MODE_P2P},           .flags=FLAGS, .unit="mode"},
      96             :         { "cline", "draw a centered line for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_CENTERED_LINE}, .flags=FLAGS, .unit="mode"},
      97             :     { "n",    "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
      98             :     { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS },
      99             :     { "r",    "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, FLAGS },
     100             :     { "split_channels", "draw channels separately", OFFSET(split_channels), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
     101             :     { "colors", "set channels colors", OFFSET(colors), AV_OPT_TYPE_STRING, {.str = "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS },
     102             :     { "scale", "set amplitude scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, SCALE_NB-1, FLAGS, .unit="scale" },
     103             :         { "lin", "linear",         0, AV_OPT_TYPE_CONST, {.i64=SCALE_LIN}, .flags=FLAGS, .unit="scale"},
     104             :         { "log", "logarithmic",    0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"},
     105             :         { "sqrt", "square root",   0, AV_OPT_TYPE_CONST, {.i64=SCALE_SQRT}, .flags=FLAGS, .unit="scale"},
     106             :         { "cbrt", "cubic root",    0, AV_OPT_TYPE_CONST, {.i64=SCALE_CBRT}, .flags=FLAGS, .unit="scale"},
     107             :     { NULL }
     108             : };
     109             : 
     110             : AVFILTER_DEFINE_CLASS(showwaves);
     111             : 
     112           0 : static av_cold void uninit(AVFilterContext *ctx)
     113             : {
     114           0 :     ShowWavesContext *showwaves = ctx->priv;
     115             : 
     116           0 :     av_frame_free(&showwaves->outpicref);
     117           0 :     av_freep(&showwaves->buf_idy);
     118           0 :     av_freep(&showwaves->fg);
     119             : 
     120           0 :     if (showwaves->single_pic) {
     121           0 :         struct frame_node *node = showwaves->audio_frames;
     122           0 :         while (node) {
     123           0 :             struct frame_node *tmp = node;
     124             : 
     125           0 :             node = node->next;
     126           0 :             av_frame_free(&tmp->frame);
     127           0 :             av_freep(&tmp);
     128             :         }
     129           0 :         av_freep(&showwaves->sum);
     130           0 :         showwaves->last_frame = NULL;
     131             :     }
     132           0 : }
     133             : 
     134           0 : static int query_formats(AVFilterContext *ctx)
     135             : {
     136           0 :     AVFilterFormats *formats = NULL;
     137           0 :     AVFilterChannelLayouts *layouts = NULL;
     138           0 :     AVFilterLink *inlink = ctx->inputs[0];
     139           0 :     AVFilterLink *outlink = ctx->outputs[0];
     140             :     static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE };
     141             :     static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE };
     142             :     int ret;
     143             : 
     144             :     /* set input audio formats */
     145           0 :     formats = ff_make_format_list(sample_fmts);
     146           0 :     if ((ret = ff_formats_ref(formats, &inlink->out_formats)) < 0)
     147           0 :         return ret;
     148             : 
     149           0 :     layouts = ff_all_channel_layouts();
     150           0 :     if ((ret = ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts)) < 0)
     151           0 :         return ret;
     152             : 
     153           0 :     formats = ff_all_samplerates();
     154           0 :     if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0)
     155           0 :         return ret;
     156             : 
     157             :     /* set output video format */
     158           0 :     formats = ff_make_format_list(pix_fmts);
     159           0 :     if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0)
     160           0 :         return ret;
     161             : 
     162           0 :     return 0;
     163             : }
     164             : 
     165           0 : static int get_lin_h(int16_t sample, int height)
     166             : {
     167           0 :     return height/2 - av_rescale(sample, height/2, INT16_MAX);
     168             : }
     169             : 
     170           0 : static int get_lin_h2(int16_t sample, int height)
     171             : {
     172           0 :     return av_rescale(FFABS(sample), height, INT16_MAX);
     173             : }
     174             : 
     175           0 : static int get_log_h(int16_t sample, int height)
     176             : {
     177           0 :     return height/2 - FFSIGN(sample) * (log10(1 + FFABS(sample)) * (height/2) / log10(1 + INT16_MAX));
     178             : }
     179             : 
     180           0 : static int get_log_h2(int16_t sample, int height)
     181             : {
     182           0 :     return log10(1 + FFABS(sample)) * height / log10(1 + INT16_MAX);
     183             : }
     184             : 
     185           0 : static int get_sqrt_h(int16_t sample, int height)
     186             : {
     187           0 :     return height/2 - FFSIGN(sample) * (sqrt(FFABS(sample)) * (height/2) / sqrt(INT16_MAX));
     188             : }
     189             : 
     190           0 : static int get_sqrt_h2(int16_t sample, int height)
     191             : {
     192           0 :     return sqrt(FFABS(sample)) * height / sqrt(INT16_MAX);
     193             : }
     194             : 
     195           0 : static int get_cbrt_h(int16_t sample, int height)
     196             : {
     197           0 :     return height/2 - FFSIGN(sample) * (cbrt(FFABS(sample)) * (height/2) / cbrt(INT16_MAX));
     198             : }
     199             : 
     200           0 : static int get_cbrt_h2(int16_t sample, int height)
     201             : {
     202           0 :     return cbrt(FFABS(sample)) * height / cbrt(INT16_MAX);
     203             : }
     204             : 
     205           0 : static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize,
     206             :                                    int16_t *prev_y,
     207             :                                    const uint8_t color[4], int h)
     208             : {
     209           0 :     if (h >= 0 && h < height) {
     210           0 :         buf[h * linesize + 0] += color[0];
     211           0 :         buf[h * linesize + 1] += color[1];
     212           0 :         buf[h * linesize + 2] += color[2];
     213           0 :         buf[h * linesize + 3] += color[3];
     214             :     }
     215           0 : }
     216             : 
     217           0 : static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize,
     218             :                                   int16_t *prev_y,
     219             :                                   const uint8_t color[4], int h)
     220             : {
     221             :     int k;
     222           0 :     int start   = height/2;
     223           0 :     int end     = av_clip(h, 0, height-1);
     224           0 :     if (start > end)
     225           0 :         FFSWAP(int16_t, start, end);
     226           0 :     for (k = start; k < end; k++) {
     227           0 :         buf[k * linesize + 0] += color[0];
     228           0 :         buf[k * linesize + 1] += color[1];
     229           0 :         buf[k * linesize + 2] += color[2];
     230           0 :         buf[k * linesize + 3] += color[3];
     231             :     }
     232           0 : }
     233             : 
     234           0 : static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize,
     235             :                                  int16_t *prev_y,
     236             :                                  const uint8_t color[4], int h)
     237             : {
     238             :     int k;
     239           0 :     if (h >= 0 && h < height) {
     240           0 :         buf[h * linesize + 0] += color[0];
     241           0 :         buf[h * linesize + 1] += color[1];
     242           0 :         buf[h * linesize + 2] += color[2];
     243           0 :         buf[h * linesize + 3] += color[3];
     244           0 :         if (*prev_y && h != *prev_y) {
     245           0 :             int start = *prev_y;
     246           0 :             int end = av_clip(h, 0, height-1);
     247           0 :             if (start > end)
     248           0 :                 FFSWAP(int16_t, start, end);
     249           0 :             for (k = start + 1; k < end; k++) {
     250           0 :                 buf[k * linesize + 0] += color[0];
     251           0 :                 buf[k * linesize + 1] += color[1];
     252           0 :                 buf[k * linesize + 2] += color[2];
     253           0 :                 buf[k * linesize + 3] += color[3];
     254             :             }
     255             :         }
     256             :     }
     257           0 :     *prev_y = h;
     258           0 : }
     259             : 
     260           0 : static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize,
     261             :                                    int16_t *prev_y,
     262             :                                    const uint8_t color[4], int h)
     263             : {
     264             :     int k;
     265           0 :     const int start = (height - h) / 2;
     266           0 :     const int end   = start + h;
     267           0 :     for (k = start; k < end; k++) {
     268           0 :         buf[k * linesize + 0] += color[0];
     269           0 :         buf[k * linesize + 1] += color[1];
     270           0 :         buf[k * linesize + 2] += color[2];
     271           0 :         buf[k * linesize + 3] += color[3];
     272             :     }
     273           0 : }
     274             : 
     275           0 : static void draw_sample_point_gray(uint8_t *buf, int height, int linesize,
     276             :                                    int16_t *prev_y,
     277             :                                    const uint8_t color[4], int h)
     278             : {
     279           0 :     if (h >= 0 && h < height)
     280           0 :         buf[h * linesize] += color[0];
     281           0 : }
     282             : 
     283           0 : static void draw_sample_line_gray(uint8_t *buf, int height, int linesize,
     284             :                                   int16_t *prev_y,
     285             :                                   const uint8_t color[4], int h)
     286             : {
     287             :     int k;
     288           0 :     int start   = height/2;
     289           0 :     int end     = av_clip(h, 0, height-1);
     290           0 :     if (start > end)
     291           0 :         FFSWAP(int16_t, start, end);
     292           0 :     for (k = start; k < end; k++)
     293           0 :         buf[k * linesize] += color[0];
     294           0 : }
     295             : 
     296           0 : static void draw_sample_p2p_gray(uint8_t *buf, int height, int linesize,
     297             :                                  int16_t *prev_y,
     298             :                                  const uint8_t color[4], int h)
     299             : {
     300             :     int k;
     301           0 :     if (h >= 0 && h < height) {
     302           0 :         buf[h * linesize] += color[0];
     303           0 :         if (*prev_y && h != *prev_y) {
     304           0 :             int start = *prev_y;
     305           0 :             int end = av_clip(h, 0, height-1);
     306           0 :             if (start > end)
     307           0 :                 FFSWAP(int16_t, start, end);
     308           0 :             for (k = start + 1; k < end; k++)
     309           0 :                 buf[k * linesize] += color[0];
     310             :         }
     311             :     }
     312           0 :     *prev_y = h;
     313           0 : }
     314             : 
     315           0 : static void draw_sample_cline_gray(uint8_t *buf, int height, int linesize,
     316             :                                    int16_t *prev_y,
     317             :                                    const uint8_t color[4], int h)
     318             : {
     319             :     int k;
     320           0 :     const int start = (height - h) / 2;
     321           0 :     const int end   = start + h;
     322           0 :     for (k = start; k < end; k++)
     323           0 :         buf[k * linesize] += color[0];
     324           0 : }
     325             : 
     326           0 : static int config_output(AVFilterLink *outlink)
     327             : {
     328           0 :     AVFilterContext *ctx = outlink->src;
     329           0 :     AVFilterLink *inlink = ctx->inputs[0];
     330           0 :     ShowWavesContext *showwaves = ctx->priv;
     331           0 :     int nb_channels = inlink->channels;
     332           0 :     char *colors, *saveptr = NULL;
     333             :     uint8_t x;
     334             :     int ch;
     335             : 
     336           0 :     if (showwaves->single_pic)
     337           0 :         showwaves->n = 1;
     338             : 
     339           0 :     if (!showwaves->n)
     340           0 :         showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5);
     341             : 
     342           0 :     showwaves->buf_idx = 0;
     343           0 :     if (!(showwaves->buf_idy = av_mallocz_array(nb_channels, sizeof(*showwaves->buf_idy)))) {
     344           0 :         av_log(ctx, AV_LOG_ERROR, "Could not allocate showwaves buffer\n");
     345           0 :         return AVERROR(ENOMEM);
     346             :     }
     347           0 :     outlink->w = showwaves->w;
     348           0 :     outlink->h = showwaves->h;
     349           0 :     outlink->sample_aspect_ratio = (AVRational){1,1};
     350             : 
     351           0 :     outlink->frame_rate = av_div_q((AVRational){inlink->sample_rate,showwaves->n},
     352           0 :                                    (AVRational){showwaves->w,1});
     353             : 
     354           0 :     av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%d\n",
     355             :            showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n);
     356             : 
     357           0 :     switch (outlink->format) {
     358             :     case AV_PIX_FMT_GRAY8:
     359           0 :         switch (showwaves->mode) {
     360           0 :         case MODE_POINT:         showwaves->draw_sample = draw_sample_point_gray; break;
     361           0 :         case MODE_LINE:          showwaves->draw_sample = draw_sample_line_gray;  break;
     362           0 :         case MODE_P2P:           showwaves->draw_sample = draw_sample_p2p_gray;   break;
     363           0 :         case MODE_CENTERED_LINE: showwaves->draw_sample = draw_sample_cline_gray; break;
     364             :         default:
     365           0 :             return AVERROR_BUG;
     366             :         }
     367           0 :         showwaves->pixstep = 1;
     368           0 :         break;
     369             :     case AV_PIX_FMT_RGBA:
     370           0 :         switch (showwaves->mode) {
     371           0 :         case MODE_POINT:         showwaves->draw_sample = draw_sample_point_rgba; break;
     372           0 :         case MODE_LINE:          showwaves->draw_sample = draw_sample_line_rgba;  break;
     373           0 :         case MODE_P2P:           showwaves->draw_sample = draw_sample_p2p_rgba;   break;
     374           0 :         case MODE_CENTERED_LINE: showwaves->draw_sample = draw_sample_cline_rgba; break;
     375             :         default:
     376           0 :             return AVERROR_BUG;
     377             :         }
     378           0 :         showwaves->pixstep = 4;
     379           0 :         break;
     380             :     }
     381             : 
     382           0 :     switch (showwaves->scale) {
     383             :     case SCALE_LIN:
     384           0 :         switch (showwaves->mode) {
     385             :         case MODE_POINT:
     386             :         case MODE_LINE:
     387           0 :         case MODE_P2P:           showwaves->get_h = get_lin_h;  break;
     388           0 :         case MODE_CENTERED_LINE: showwaves->get_h = get_lin_h2; break;
     389             :         default:
     390           0 :             return AVERROR_BUG;
     391             :         }
     392           0 :         break;
     393             :     case SCALE_LOG:
     394           0 :         switch (showwaves->mode) {
     395             :         case MODE_POINT:
     396             :         case MODE_LINE:
     397           0 :         case MODE_P2P:           showwaves->get_h = get_log_h;  break;
     398           0 :         case MODE_CENTERED_LINE: showwaves->get_h = get_log_h2; break;
     399             :         default:
     400           0 :             return AVERROR_BUG;
     401             :         }
     402           0 :         break;
     403             :     case SCALE_SQRT:
     404           0 :         switch (showwaves->mode) {
     405             :         case MODE_POINT:
     406             :         case MODE_LINE:
     407           0 :         case MODE_P2P:           showwaves->get_h = get_sqrt_h;  break;
     408           0 :         case MODE_CENTERED_LINE: showwaves->get_h = get_sqrt_h2; break;
     409             :         default:
     410           0 :             return AVERROR_BUG;
     411             :         }
     412           0 :         break;
     413             :     case SCALE_CBRT:
     414           0 :         switch (showwaves->mode) {
     415             :         case MODE_POINT:
     416             :         case MODE_LINE:
     417           0 :         case MODE_P2P:           showwaves->get_h = get_cbrt_h;  break;
     418           0 :         case MODE_CENTERED_LINE: showwaves->get_h = get_cbrt_h2; break;
     419             :         default:
     420           0 :             return AVERROR_BUG;
     421             :         }
     422           0 :         break;
     423             :     }
     424             : 
     425           0 :     showwaves->fg = av_malloc_array(nb_channels, 4 * sizeof(*showwaves->fg));
     426           0 :     if (!showwaves->fg)
     427           0 :         return AVERROR(ENOMEM);
     428             : 
     429           0 :     colors = av_strdup(showwaves->colors);
     430           0 :     if (!colors)
     431           0 :         return AVERROR(ENOMEM);
     432             : 
     433             :     /* multiplication factor, pre-computed to avoid in-loop divisions */
     434           0 :     x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n);
     435           0 :     if (outlink->format == AV_PIX_FMT_RGBA) {
     436           0 :         uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff };
     437             : 
     438           0 :         for (ch = 0; ch < nb_channels; ch++) {
     439             :             char *color;
     440             : 
     441           0 :             color = av_strtok(ch == 0 ? colors : NULL, " |", &saveptr);
     442           0 :             if (color)
     443           0 :                 av_parse_color(fg, color, -1, ctx);
     444           0 :             showwaves->fg[4*ch + 0] = fg[0] * x / 255.;
     445           0 :             showwaves->fg[4*ch + 1] = fg[1] * x / 255.;
     446           0 :             showwaves->fg[4*ch + 2] = fg[2] * x / 255.;
     447           0 :             showwaves->fg[4*ch + 3] = fg[3] * x / 255.;
     448             :         }
     449             :     } else {
     450           0 :         for (ch = 0; ch < nb_channels; ch++)
     451           0 :             showwaves->fg[4 * ch + 0] = x;
     452             :     }
     453           0 :     av_free(colors);
     454             : 
     455           0 :     return 0;
     456             : }
     457             : 
     458           0 : inline static int push_frame(AVFilterLink *outlink)
     459             : {
     460           0 :     AVFilterContext *ctx = outlink->src;
     461           0 :     AVFilterLink *inlink = ctx->inputs[0];
     462           0 :     ShowWavesContext *showwaves = outlink->src->priv;
     463           0 :     int nb_channels = inlink->channels;
     464             :     int ret, i;
     465             : 
     466           0 :     ret = ff_filter_frame(outlink, showwaves->outpicref);
     467           0 :     showwaves->outpicref = NULL;
     468           0 :     showwaves->buf_idx = 0;
     469           0 :     for (i = 0; i < nb_channels; i++)
     470           0 :         showwaves->buf_idy[i] = 0;
     471           0 :     return ret;
     472             : }
     473             : 
     474           0 : static int push_single_pic(AVFilterLink *outlink)
     475             : {
     476           0 :     AVFilterContext *ctx = outlink->src;
     477           0 :     AVFilterLink *inlink = ctx->inputs[0];
     478           0 :     ShowWavesContext *showwaves = ctx->priv;
     479           0 :     int64_t n = 0, max_samples = showwaves->total_samples / outlink->w;
     480           0 :     AVFrame *out = showwaves->outpicref;
     481             :     struct frame_node *node;
     482           0 :     const int nb_channels = inlink->channels;
     483           0 :     const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h;
     484           0 :     const int linesize = out->linesize[0];
     485           0 :     const int pixstep = showwaves->pixstep;
     486           0 :     int col = 0;
     487           0 :     int64_t *sum = showwaves->sum;
     488             : 
     489           0 :     if (max_samples == 0) {
     490           0 :         av_log(ctx, AV_LOG_ERROR, "Too few samples\n");
     491           0 :         return AVERROR(EINVAL);
     492             :     }
     493             : 
     494           0 :     av_log(ctx, AV_LOG_DEBUG, "Create frame averaging %"PRId64" samples per column\n", max_samples);
     495             : 
     496           0 :     memset(sum, 0, nb_channels);
     497             : 
     498           0 :     for (node = showwaves->audio_frames; node; node = node->next) {
     499             :         int i;
     500           0 :         const AVFrame *frame = node->frame;
     501           0 :         const int16_t *p = (const int16_t *)frame->data[0];
     502             : 
     503           0 :         for (i = 0; i < frame->nb_samples; i++) {
     504             :             int ch;
     505             : 
     506           0 :             for (ch = 0; ch < nb_channels; ch++)
     507           0 :                 sum[ch] += abs(p[ch + i*nb_channels]) << 1;
     508           0 :             if (n++ == max_samples) {
     509           0 :                 for (ch = 0; ch < nb_channels; ch++) {
     510           0 :                     int16_t sample = sum[ch] / max_samples;
     511           0 :                     uint8_t *buf = out->data[0] + col * pixstep;
     512             :                     int h;
     513             : 
     514           0 :                     if (showwaves->split_channels)
     515           0 :                         buf += ch*ch_height*linesize;
     516           0 :                     av_assert0(col < outlink->w);
     517           0 :                     h = showwaves->get_h(sample, ch_height);
     518           0 :                     showwaves->draw_sample(buf, ch_height, linesize, &showwaves->buf_idy[ch], &showwaves->fg[ch * 4], h);
     519           0 :                     sum[ch] = 0;
     520             :                 }
     521           0 :                 col++;
     522           0 :                 n = 0;
     523             :             }
     524             :         }
     525             :     }
     526             : 
     527           0 :     return push_frame(outlink);
     528             : }
     529             : 
     530             : 
     531           0 : static int request_frame(AVFilterLink *outlink)
     532             : {
     533           0 :     ShowWavesContext *showwaves = outlink->src->priv;
     534           0 :     AVFilterLink *inlink = outlink->src->inputs[0];
     535             :     int ret;
     536             : 
     537           0 :     ret = ff_request_frame(inlink);
     538           0 :     if (ret == AVERROR_EOF && showwaves->outpicref) {
     539           0 :         if (showwaves->single_pic)
     540           0 :             push_single_pic(outlink);
     541             :         else
     542           0 :             push_frame(outlink);
     543             :     }
     544             : 
     545           0 :     return ret;
     546             : }
     547             : 
     548           0 : static int alloc_out_frame(ShowWavesContext *showwaves, const int16_t *p,
     549             :                            const AVFilterLink *inlink, AVFilterLink *outlink,
     550             :                            const AVFrame *in)
     551             : {
     552           0 :     if (!showwaves->outpicref) {
     553             :         int j;
     554           0 :         AVFrame *out = showwaves->outpicref =
     555           0 :             ff_get_video_buffer(outlink, outlink->w, outlink->h);
     556           0 :         if (!out)
     557           0 :             return AVERROR(ENOMEM);
     558           0 :         out->width  = outlink->w;
     559           0 :         out->height = outlink->h;
     560           0 :         out->pts = in->pts + av_rescale_q((p - (int16_t *)in->data[0]) / inlink->channels,
     561             :                                           av_make_q(1, inlink->sample_rate),
     562             :                                           outlink->time_base);
     563           0 :         for (j = 0; j < outlink->h; j++)
     564           0 :             memset(out->data[0] + j*out->linesize[0], 0, outlink->w * showwaves->pixstep);
     565             :     }
     566           0 :     return 0;
     567             : }
     568             : 
     569           0 : static av_cold int init(AVFilterContext *ctx)
     570             : {
     571           0 :     ShowWavesContext *showwaves = ctx->priv;
     572             : 
     573           0 :     if (!strcmp(ctx->filter->name, "showwavespic")) {
     574           0 :         showwaves->single_pic = 1;
     575           0 :         showwaves->mode = MODE_CENTERED_LINE;
     576             :     }
     577             : 
     578           0 :     return 0;
     579             : }
     580             : 
     581             : #if CONFIG_SHOWWAVES_FILTER
     582             : 
     583           0 : static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     584             : {
     585           0 :     AVFilterContext *ctx = inlink->dst;
     586           0 :     AVFilterLink *outlink = ctx->outputs[0];
     587           0 :     ShowWavesContext *showwaves = ctx->priv;
     588           0 :     const int nb_samples = insamples->nb_samples;
     589           0 :     AVFrame *outpicref = showwaves->outpicref;
     590           0 :     int16_t *p = (int16_t *)insamples->data[0];
     591           0 :     int nb_channels = inlink->channels;
     592           0 :     int i, j, ret = 0;
     593           0 :     const int pixstep = showwaves->pixstep;
     594           0 :     const int n = showwaves->n;
     595           0 :     const int ch_height = showwaves->split_channels ? outlink->h / nb_channels : outlink->h;
     596             : 
     597             :     /* draw data in the buffer */
     598           0 :     for (i = 0; i < nb_samples; i++) {
     599             : 
     600           0 :         ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples);
     601           0 :         if (ret < 0)
     602           0 :             goto end;
     603           0 :         outpicref = showwaves->outpicref;
     604             : 
     605           0 :         for (j = 0; j < nb_channels; j++) {
     606           0 :             uint8_t *buf = outpicref->data[0] + showwaves->buf_idx * pixstep;
     607           0 :             const int linesize = outpicref->linesize[0];
     608             :             int h;
     609             : 
     610           0 :             if (showwaves->split_channels)
     611           0 :                 buf += j*ch_height*linesize;
     612           0 :             h = showwaves->get_h(*p++, ch_height);
     613           0 :             showwaves->draw_sample(buf, ch_height, linesize,
     614           0 :                                    &showwaves->buf_idy[j], &showwaves->fg[j * 4], h);
     615             :         }
     616             : 
     617           0 :         showwaves->sample_count_mod++;
     618           0 :         if (showwaves->sample_count_mod == n) {
     619           0 :             showwaves->sample_count_mod = 0;
     620           0 :             showwaves->buf_idx++;
     621             :         }
     622           0 :         if (showwaves->buf_idx == showwaves->w)
     623           0 :             if ((ret = push_frame(outlink)) < 0)
     624           0 :                 break;
     625           0 :         outpicref = showwaves->outpicref;
     626             :     }
     627             : 
     628             : end:
     629           0 :     av_frame_free(&insamples);
     630           0 :     return ret;
     631             : }
     632             : 
     633             : static const AVFilterPad showwaves_inputs[] = {
     634             :     {
     635             :         .name         = "default",
     636             :         .type         = AVMEDIA_TYPE_AUDIO,
     637             :         .filter_frame = showwaves_filter_frame,
     638             :     },
     639             :     { NULL }
     640             : };
     641             : 
     642             : static const AVFilterPad showwaves_outputs[] = {
     643             :     {
     644             :         .name          = "default",
     645             :         .type          = AVMEDIA_TYPE_VIDEO,
     646             :         .config_props  = config_output,
     647             :         .request_frame = request_frame,
     648             :     },
     649             :     { NULL }
     650             : };
     651             : 
     652             : AVFilter ff_avf_showwaves = {
     653             :     .name          = "showwaves",
     654             :     .description   = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."),
     655             :     .init          = init,
     656             :     .uninit        = uninit,
     657             :     .query_formats = query_formats,
     658             :     .priv_size     = sizeof(ShowWavesContext),
     659             :     .inputs        = showwaves_inputs,
     660             :     .outputs       = showwaves_outputs,
     661             :     .priv_class    = &showwaves_class,
     662             : };
     663             : 
     664             : #endif // CONFIG_SHOWWAVES_FILTER
     665             : 
     666             : #if CONFIG_SHOWWAVESPIC_FILTER
     667             : 
     668             : #define OFFSET(x) offsetof(ShowWavesContext, x)
     669             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
     670             : 
     671             : static const AVOption showwavespic_options[] = {
     672             :     { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
     673             :     { "s",    "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
     674             :     { "split_channels", "draw channels separately", OFFSET(split_channels), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
     675             :     { "colors", "set channels colors", OFFSET(colors), AV_OPT_TYPE_STRING, {.str = "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS },
     676             :     { "scale", "set amplitude scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, SCALE_NB-1, FLAGS, .unit="scale" },
     677             :         { "lin", "linear",         0, AV_OPT_TYPE_CONST, {.i64=SCALE_LIN}, .flags=FLAGS, .unit="scale"},
     678             :         { "log", "logarithmic",    0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"},
     679             :         { "sqrt", "square root",   0, AV_OPT_TYPE_CONST, {.i64=SCALE_SQRT}, .flags=FLAGS, .unit="scale"},
     680             :         { "cbrt", "cubic root",    0, AV_OPT_TYPE_CONST, {.i64=SCALE_CBRT}, .flags=FLAGS, .unit="scale"},
     681             :     { NULL }
     682             : };
     683             : 
     684             : AVFILTER_DEFINE_CLASS(showwavespic);
     685             : 
     686           0 : static int showwavespic_config_input(AVFilterLink *inlink)
     687             : {
     688           0 :     AVFilterContext *ctx = inlink->dst;
     689           0 :     ShowWavesContext *showwaves = ctx->priv;
     690             : 
     691           0 :     if (showwaves->single_pic) {
     692           0 :         showwaves->sum = av_mallocz_array(inlink->channels, sizeof(*showwaves->sum));
     693           0 :         if (!showwaves->sum)
     694           0 :             return AVERROR(ENOMEM);
     695             :     }
     696             : 
     697           0 :     return 0;
     698             : }
     699             : 
     700           0 : static int showwavespic_filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     701             : {
     702           0 :     AVFilterContext *ctx = inlink->dst;
     703           0 :     AVFilterLink *outlink = ctx->outputs[0];
     704           0 :     ShowWavesContext *showwaves = ctx->priv;
     705           0 :     int16_t *p = (int16_t *)insamples->data[0];
     706           0 :     int ret = 0;
     707             : 
     708           0 :     if (showwaves->single_pic) {
     709             :         struct frame_node *f;
     710             : 
     711           0 :         ret = alloc_out_frame(showwaves, p, inlink, outlink, insamples);
     712           0 :         if (ret < 0)
     713           0 :             goto end;
     714             : 
     715             :         /* queue the audio frame */
     716           0 :         f = av_malloc(sizeof(*f));
     717           0 :         if (!f) {
     718           0 :             ret = AVERROR(ENOMEM);
     719           0 :             goto end;
     720             :         }
     721           0 :         f->frame = insamples;
     722           0 :         f->next = NULL;
     723           0 :         if (!showwaves->last_frame) {
     724           0 :             showwaves->audio_frames =
     725           0 :             showwaves->last_frame   = f;
     726             :         } else {
     727           0 :             showwaves->last_frame->next = f;
     728           0 :             showwaves->last_frame = f;
     729             :         }
     730           0 :         showwaves->total_samples += insamples->nb_samples;
     731             : 
     732           0 :         return 0;
     733             :     }
     734             : 
     735             : end:
     736           0 :     av_frame_free(&insamples);
     737           0 :     return ret;
     738             : }
     739             : 
     740             : static const AVFilterPad showwavespic_inputs[] = {
     741             :     {
     742             :         .name         = "default",
     743             :         .type         = AVMEDIA_TYPE_AUDIO,
     744             :         .config_props = showwavespic_config_input,
     745             :         .filter_frame = showwavespic_filter_frame,
     746             :     },
     747             :     { NULL }
     748             : };
     749             : 
     750             : static const AVFilterPad showwavespic_outputs[] = {
     751             :     {
     752             :         .name          = "default",
     753             :         .type          = AVMEDIA_TYPE_VIDEO,
     754             :         .config_props  = config_output,
     755             :         .request_frame = request_frame,
     756             :     },
     757             :     { NULL }
     758             : };
     759             : 
     760             : AVFilter ff_avf_showwavespic = {
     761             :     .name          = "showwavespic",
     762             :     .description   = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."),
     763             :     .init          = init,
     764             :     .uninit        = uninit,
     765             :     .query_formats = query_formats,
     766             :     .priv_size     = sizeof(ShowWavesContext),
     767             :     .inputs        = showwavespic_inputs,
     768             :     .outputs       = showwavespic_outputs,
     769             :     .priv_class    = &showwavespic_class,
     770             : };
     771             : 
     772             : #endif // CONFIG_SHOWWAVESPIC_FILTER

Generated by: LCOV version 1.13