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