2 * Copyright (c) 2012 Stefano Sabatini
4 * This file is part of FFmpeg.
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.
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.
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
23 * audio to video multimedia filter
26 #include "config_components.h"
28 #include "libavutil/avassert.h"
29 #include "libavutil/avstring.h"
30 #include "libavutil/channel_layout.h"
31 #include "libavutil/intreadwrite.h"
32 #include "libavutil/mem.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/parseutils.h"
57 enum ShowWavesDrawMode
{
63 enum ShowWavesFilterMode
{
71 struct frame_node
*next
;
74 typedef struct ShowWavesContext
{
80 int16_t *buf_idy
; /* y coordinate of previous sample for each channel */
82 int history_nb_samples
;
87 int mode
; ///< ShowWavesMode
88 int scale
; ///< ShowWavesScale
89 int draw_mode
; ///< ShowWavesDrawMode
94 int (*get_h
)(int16_t sample
, int height
);
95 void (*draw_sample
)(uint8_t *buf
, int height
, int linesize
,
96 int16_t *prev_y
, const uint8_t color
[4], int h
);
100 struct frame_node
*audio_frames
;
101 struct frame_node
*last_frame
;
102 int64_t total_samples
;
103 int64_t *sum
; /* abs sum of the samples per channel */
106 #define OFFSET(x) offsetof(ShowWavesContext, x)
107 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
109 static const AVOption showwaves_options
[] = {
110 { "size", "set video size", OFFSET(w
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= "600x240"}, 0, 0, FLAGS
},
111 { "s", "set video size", OFFSET(w
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= "600x240"}, 0, 0, FLAGS
},
112 { "mode", "select display mode", OFFSET(mode
), AV_OPT_TYPE_INT
, {.i64
=MODE_POINT
}, 0, MODE_NB
-1, .flags
=FLAGS
, .unit
="mode"},
113 { "point", "draw a point for each sample", 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_POINT
}, .flags
=FLAGS
, .unit
="mode"},
114 { "line", "draw a line for each sample", 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_LINE
}, .flags
=FLAGS
, .unit
="mode"},
115 { "p2p", "draw a line between samples", 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_P2P
}, .flags
=FLAGS
, .unit
="mode"},
116 { "cline", "draw a centered line for each sample", 0, AV_OPT_TYPE_CONST
, {.i64
=MODE_CENTERED_LINE
}, .flags
=FLAGS
, .unit
="mode"},
117 { "n", "set how many samples to show in the same point", OFFSET(n
), AV_OPT_TYPE_RATIONAL
, {.i64
= 0}, 0, INT_MAX
, FLAGS
},
118 { "rate", "set video rate", OFFSET(rate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, INT_MAX
, FLAGS
},
119 { "r", "set video rate", OFFSET(rate
), AV_OPT_TYPE_VIDEO_RATE
, {.str
= "25"}, 0, INT_MAX
, FLAGS
},
120 { "split_channels", "draw channels separately", OFFSET(split_channels
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, FLAGS
},
121 { "colors", "set channels colors", OFFSET(colors
), AV_OPT_TYPE_STRING
, {.str
= "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS
},
122 { "scale", "set amplitude scale", OFFSET(scale
), AV_OPT_TYPE_INT
, {.i64
= 0 }, 0, SCALE_NB
-1, FLAGS
, .unit
="scale" },
123 { "lin", "linear", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_LIN
}, .flags
=FLAGS
, .unit
="scale"},
124 { "log", "logarithmic", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_LOG
}, .flags
=FLAGS
, .unit
="scale"},
125 { "sqrt", "square root", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_SQRT
}, .flags
=FLAGS
, .unit
="scale"},
126 { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_CBRT
}, .flags
=FLAGS
, .unit
="scale"},
127 { "draw", "set draw mode", OFFSET(draw_mode
), AV_OPT_TYPE_INT
, {.i64
= DRAW_SCALE
}, 0, DRAW_NB
-1, FLAGS
, .unit
="draw" },
128 { "scale", "scale pixel values for each drawn sample", 0, AV_OPT_TYPE_CONST
, {.i64
=DRAW_SCALE
}, .flags
=FLAGS
, .unit
="draw"},
129 { "full", "draw every pixel for sample directly", 0, AV_OPT_TYPE_CONST
, {.i64
=DRAW_FULL
}, .flags
=FLAGS
, .unit
="draw"},
133 AVFILTER_DEFINE_CLASS(showwaves
);
135 static av_cold
void uninit(AVFilterContext
*ctx
)
137 ShowWavesContext
*showwaves
= ctx
->priv
;
139 av_frame_free(&showwaves
->outpicref
);
140 av_freep(&showwaves
->buf_idy
);
141 av_freep(&showwaves
->history
);
142 av_freep(&showwaves
->fg
);
144 if (showwaves
->single_pic
) {
145 struct frame_node
*node
= showwaves
->audio_frames
;
147 struct frame_node
*tmp
= node
;
150 av_frame_free(&tmp
->frame
);
153 av_freep(&showwaves
->sum
);
154 showwaves
->last_frame
= NULL
;
158 static int query_formats(const AVFilterContext
*ctx
,
159 AVFilterFormatsConfig
**cfg_in
,
160 AVFilterFormatsConfig
**cfg_out
)
162 AVFilterFormats
*formats
= NULL
;
163 static const enum AVSampleFormat sample_fmts
[] = { AV_SAMPLE_FMT_S16
, AV_SAMPLE_FMT_NONE
};
164 static const enum AVPixelFormat pix_fmts
[] = { AV_PIX_FMT_RGBA
, AV_PIX_FMT_GRAY8
, AV_PIX_FMT_NONE
};
167 /* set input audio formats */
168 formats
= ff_make_format_list(sample_fmts
);
169 if ((ret
= ff_formats_ref(formats
, &cfg_in
[0]->formats
)) < 0)
172 /* set output video format */
173 formats
= ff_make_format_list(pix_fmts
);
174 if ((ret
= ff_formats_ref(formats
, &cfg_out
[0]->formats
)) < 0)
180 static int get_lin_h(int16_t sample
, int height
)
182 return height
/2 - av_rescale(sample
, height
/2, INT16_MAX
);
185 static int get_lin_h2(int16_t sample
, int height
)
187 return av_rescale(FFABS(sample
), height
, INT16_MAX
);
190 static int get_log_h(int16_t sample
, int height
)
192 return height
/2 - FFSIGN(sample
) * (log10(1 + FFABS(sample
)) * (height
/2) / log10(1 + INT16_MAX
));
195 static int get_log_h2(int16_t sample
, int height
)
197 return log10(1 + FFABS(sample
)) * height
/ log10(1 + INT16_MAX
);
200 static int get_sqrt_h(int16_t sample
, int height
)
202 return height
/2 - FFSIGN(sample
) * (sqrt(FFABS(sample
)) * (height
/2) / sqrt(INT16_MAX
));
205 static int get_sqrt_h2(int16_t sample
, int height
)
207 return sqrt(FFABS(sample
)) * height
/ sqrt(INT16_MAX
);
210 static int get_cbrt_h(int16_t sample
, int height
)
212 return height
/2 - FFSIGN(sample
) * (cbrt(FFABS(sample
)) * (height
/2) / cbrt(INT16_MAX
));
215 static int get_cbrt_h2(int16_t sample
, int height
)
217 return cbrt(FFABS(sample
)) * height
/ cbrt(INT16_MAX
);
220 static void draw_sample_point_rgba_scale(uint8_t *buf
, int height
, int linesize
,
222 const uint8_t color
[4], int h
)
224 if (h
>= 0 && h
< height
) {
225 buf
[h
* linesize
+ 0] += color
[0];
226 buf
[h
* linesize
+ 1] += color
[1];
227 buf
[h
* linesize
+ 2] += color
[2];
228 buf
[h
* linesize
+ 3] += color
[3];
232 static void draw_sample_point_rgba_full(uint8_t *buf
, int height
, int linesize
,
234 const uint8_t color
[4], int h
)
236 uint32_t clr
= AV_RN32(color
);
237 if (h
>= 0 && h
< height
)
238 AV_WN32(buf
+ h
* linesize
, clr
);
241 static void draw_sample_line_rgba_scale(uint8_t *buf
, int height
, int linesize
,
243 const uint8_t color
[4], int h
)
245 int start
= height
/2;
246 int end
= av_clip(h
, 0, height
-1);
249 FFSWAP(int16_t, start
, end
);
250 bufk
= buf
+ start
* linesize
;
251 for (int k
= start
; k
< end
; k
++, bufk
+= linesize
) {
259 static void draw_sample_line_rgba_full(uint8_t *buf
, int height
, int linesize
,
261 const uint8_t color
[4], int h
)
263 int start
= height
/2;
264 int end
= av_clip(h
, 0, height
-1);
265 uint32_t clr
= AV_RN32(color
);
268 FFSWAP(int16_t, start
, end
);
269 bufk
= buf
+ start
* linesize
;
270 for (int k
= start
; k
< end
; k
++, bufk
+= linesize
)
274 static void draw_sample_p2p_rgba_scale(uint8_t *buf
, int height
, int linesize
,
276 const uint8_t color
[4], int h
)
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
) {
286 int end
= av_clip(h
, 0, height
-1);
288 FFSWAP(int16_t, start
, end
);
289 bufk
= buf
+ (start
+ 1) * linesize
;
290 for (int k
= start
+ 1; k
< end
; k
++, bufk
+= linesize
) {
301 static void draw_sample_p2p_rgba_full(uint8_t *buf
, int height
, int linesize
,
303 const uint8_t color
[4], int h
)
305 uint32_t clr
= AV_RN32(color
);
306 if (h
>= 0 && h
< height
) {
307 AV_WN32(buf
+ h
* linesize
, clr
);
308 if (*prev_y
&& h
!= *prev_y
) {
311 int end
= av_clip(h
, 0, height
-1);
313 FFSWAP(int16_t, start
, end
);
314 bufk
= buf
+ (start
+ 1) * linesize
;
315 for (int k
= start
+ 1; k
< end
; k
++, bufk
+= linesize
)
322 static void draw_sample_cline_rgba_scale(uint8_t *buf
, int height
, int linesize
,
324 const uint8_t color
[4], int h
)
326 const int start
= (height
- h
) / 2;
327 const int end
= start
+ h
;
328 uint8_t *bufk
= buf
+ start
* linesize
;
329 for (int k
= start
; k
< end
; k
++, bufk
+= linesize
) {
337 static void draw_sample_cline_rgba_full(uint8_t *buf
, int height
, int linesize
,
339 const uint8_t color
[4], int h
)
341 uint32_t clr
= AV_RN32(color
);
342 const int start
= (height
- h
) / 2;
343 const int end
= start
+ h
;
344 uint8_t *bufk
= buf
+ start
* linesize
;
345 for (int k
= start
; k
< end
; k
++, bufk
+= linesize
)
349 static void draw_sample_point_gray(uint8_t *buf
, int height
, int linesize
,
351 const uint8_t color
[4], int h
)
353 if (h
>= 0 && h
< height
)
354 buf
[h
* linesize
] += color
[0];
357 static void draw_sample_line_gray(uint8_t *buf
, int height
, int linesize
,
359 const uint8_t color
[4], int h
)
362 int start
= height
/2;
363 int end
= av_clip(h
, 0, height
-1);
365 FFSWAP(int16_t, start
, end
);
366 for (k
= start
; k
< end
; k
++)
367 buf
[k
* linesize
] += color
[0];
370 static void draw_sample_p2p_gray(uint8_t *buf
, int height
, int linesize
,
372 const uint8_t color
[4], int h
)
375 if (h
>= 0 && h
< height
) {
376 buf
[h
* linesize
] += color
[0];
377 if (*prev_y
&& h
!= *prev_y
) {
379 int end
= av_clip(h
, 0, height
-1);
381 FFSWAP(int16_t, start
, end
);
382 for (k
= start
+ 1; k
< end
; k
++)
383 buf
[k
* linesize
] += color
[0];
389 static void draw_sample_cline_gray(uint8_t *buf
, int height
, int linesize
,
391 const uint8_t color
[4], int h
)
394 const int start
= (height
- h
) / 2;
395 const int end
= start
+ h
;
396 for (k
= start
; k
< end
; k
++)
397 buf
[k
* linesize
] += color
[0];
400 static int config_output(AVFilterLink
*outlink
)
402 FilterLink
*l
= ff_filter_link(outlink
);
403 AVFilterContext
*ctx
= outlink
->src
;
404 AVFilterLink
*inlink
= ctx
->inputs
[0];
405 ShowWavesContext
*showwaves
= ctx
->priv
;
406 int nb_channels
= inlink
->ch_layout
.nb_channels
;
407 char *colors
, *saveptr
= NULL
;
411 showwaves
->q
= av_make_q(0, 1);
412 showwaves
->c
= av_make_q(0, 1);
414 if (showwaves
->single_pic
) {
415 showwaves
->n
= av_make_q(1, 1);
416 l
->frame_rate
= av_make_q(1, 1);
418 if (!showwaves
->n
.num
|| !showwaves
->n
.den
) {
419 showwaves
->n
= av_mul_q(av_make_q(inlink
->sample_rate
,
420 showwaves
->w
), av_inv_q(showwaves
->rate
));
421 l
->frame_rate
= showwaves
->rate
;
423 l
->frame_rate
= av_div_q(av_make_q(inlink
->sample_rate
, showwaves
->w
), showwaves
->n
);
427 showwaves
->buf_idx
= 0;
428 if (!FF_ALLOCZ_TYPED_ARRAY(showwaves
->buf_idy
, nb_channels
)) {
429 av_log(ctx
, AV_LOG_ERROR
, "Could not allocate showwaves buffer\n");
430 return AVERROR(ENOMEM
);
433 showwaves
->history_nb_samples
= av_rescale(showwaves
->w
* nb_channels
* 2,
434 showwaves
->n
.num
, showwaves
->n
.den
);
435 if (showwaves
->history_nb_samples
<= 0)
436 return AVERROR(EINVAL
);
437 showwaves
->history
= av_calloc(showwaves
->history_nb_samples
,
438 sizeof(*showwaves
->history
));
439 if (!showwaves
->history
)
440 return AVERROR(ENOMEM
);
442 outlink
->time_base
= av_inv_q(l
->frame_rate
);
443 outlink
->w
= showwaves
->w
;
444 outlink
->h
= showwaves
->h
;
445 outlink
->sample_aspect_ratio
= (AVRational
){1,1};
447 av_log(ctx
, AV_LOG_VERBOSE
, "s:%dx%d r:%f n:%f\n",
448 showwaves
->w
, showwaves
->h
, av_q2d(l
->frame_rate
), av_q2d(showwaves
->n
));
450 switch (outlink
->format
) {
451 case AV_PIX_FMT_GRAY8
:
452 switch (showwaves
->mode
) {
453 case MODE_POINT
: showwaves
->draw_sample
= draw_sample_point_gray
; break;
454 case MODE_LINE
: showwaves
->draw_sample
= draw_sample_line_gray
; break;
455 case MODE_P2P
: showwaves
->draw_sample
= draw_sample_p2p_gray
; break;
456 case MODE_CENTERED_LINE
: showwaves
->draw_sample
= draw_sample_cline_gray
; break;
460 showwaves
->pixstep
= 1;
462 case AV_PIX_FMT_RGBA
:
463 switch (showwaves
->mode
) {
464 case MODE_POINT
: showwaves
->draw_sample
= showwaves
->draw_mode
== DRAW_SCALE
? draw_sample_point_rgba_scale
: draw_sample_point_rgba_full
; break;
465 case MODE_LINE
: showwaves
->draw_sample
= showwaves
->draw_mode
== DRAW_SCALE
? draw_sample_line_rgba_scale
: draw_sample_line_rgba_full
; break;
466 case MODE_P2P
: showwaves
->draw_sample
= showwaves
->draw_mode
== DRAW_SCALE
? draw_sample_p2p_rgba_scale
: draw_sample_p2p_rgba_full
; break;
467 case MODE_CENTERED_LINE
: showwaves
->draw_sample
= showwaves
->draw_mode
== DRAW_SCALE
? draw_sample_cline_rgba_scale
: draw_sample_cline_rgba_full
; break;
471 showwaves
->pixstep
= 4;
475 switch (showwaves
->scale
) {
477 switch (showwaves
->mode
) {
480 case MODE_P2P
: showwaves
->get_h
= get_lin_h
; break;
481 case MODE_CENTERED_LINE
: showwaves
->get_h
= get_lin_h2
; break;
487 switch (showwaves
->mode
) {
490 case MODE_P2P
: showwaves
->get_h
= get_log_h
; break;
491 case MODE_CENTERED_LINE
: showwaves
->get_h
= get_log_h2
; break;
497 switch (showwaves
->mode
) {
500 case MODE_P2P
: showwaves
->get_h
= get_sqrt_h
; break;
501 case MODE_CENTERED_LINE
: showwaves
->get_h
= get_sqrt_h2
; break;
507 switch (showwaves
->mode
) {
510 case MODE_P2P
: showwaves
->get_h
= get_cbrt_h
; break;
511 case MODE_CENTERED_LINE
: showwaves
->get_h
= get_cbrt_h2
; break;
518 showwaves
->fg
= av_malloc_array(nb_channels
, 4 * sizeof(*showwaves
->fg
));
520 return AVERROR(ENOMEM
);
522 colors
= av_strdup(showwaves
->colors
);
524 return AVERROR(ENOMEM
);
526 if (showwaves
->draw_mode
== DRAW_SCALE
) {
527 /* multiplication factor, pre-computed to avoid in-loop divisions */
528 x
= (showwaves
->n
.den
* 255) / ((showwaves
->split_channels
? 1 : nb_channels
) * showwaves
->n
.num
);
532 if (outlink
->format
== AV_PIX_FMT_RGBA
) {
533 uint8_t fg
[4] = { 0xff, 0xff, 0xff, 0xff };
535 for (ch
= 0; ch
< nb_channels
; ch
++) {
538 color
= av_strtok(ch
== 0 ? colors
: NULL
, " |", &saveptr
);
540 av_parse_color(fg
, color
, -1, ctx
);
541 showwaves
->fg
[4*ch
+ 0] = fg
[0] * x
/ 255.;
542 showwaves
->fg
[4*ch
+ 1] = fg
[1] * x
/ 255.;
543 showwaves
->fg
[4*ch
+ 2] = fg
[2] * x
/ 255.;
544 showwaves
->fg
[4*ch
+ 3] = fg
[3] * x
/ 255.;
547 for (ch
= 0; ch
< nb_channels
; ch
++)
548 showwaves
->fg
[4 * ch
+ 0] = x
;
555 inline static int push_frame(AVFilterLink
*outlink
, int i
, int64_t pts
)
557 AVFilterContext
*ctx
= outlink
->src
;
558 AVFilterLink
*inlink
= ctx
->inputs
[0];
559 ShowWavesContext
*showwaves
= outlink
->src
->priv
;
560 int nb_channels
= inlink
->ch_layout
.nb_channels
;
563 showwaves
->outpicref
->duration
= 1;
564 showwaves
->outpicref
->pts
= av_rescale_q(pts
+ i
,
568 ret
= ff_filter_frame(outlink
, showwaves
->outpicref
);
569 showwaves
->outpicref
= NULL
;
570 showwaves
->buf_idx
= 0;
571 for (int i
= 0; i
< nb_channels
; i
++)
572 showwaves
->buf_idy
[i
] = 0;
576 static int push_single_pic(AVFilterLink
*outlink
)
578 AVFilterContext
*ctx
= outlink
->src
;
579 AVFilterLink
*inlink
= ctx
->inputs
[0];
580 ShowWavesContext
*showwaves
= ctx
->priv
;
581 int64_t n
= 0, column_max_samples
= showwaves
->total_samples
/ outlink
->w
;
582 int64_t remaining_samples
= showwaves
->total_samples
- (column_max_samples
* outlink
->w
);
583 int64_t last_column_samples
= column_max_samples
+ remaining_samples
;
584 AVFrame
*out
= showwaves
->outpicref
;
585 struct frame_node
*node
;
586 const int nb_channels
= inlink
->ch_layout
.nb_channels
;
587 const int ch_height
= showwaves
->split_channels
? outlink
->h
/ nb_channels
: outlink
->h
;
588 const int linesize
= out
->linesize
[0];
589 const int pixstep
= showwaves
->pixstep
;
591 int64_t *sum
= showwaves
->sum
;
593 if (column_max_samples
== 0) {
594 av_log(ctx
, AV_LOG_ERROR
, "Too few samples\n");
595 return AVERROR(EINVAL
);
598 av_log(ctx
, AV_LOG_DEBUG
, "Create frame averaging %"PRId64
" samples per column\n", column_max_samples
);
600 memset(sum
, 0, nb_channels
* sizeof(*sum
));
602 for (node
= showwaves
->audio_frames
; node
; node
= node
->next
) {
604 const AVFrame
*frame
= node
->frame
;
605 const int16_t *p
= (const int16_t *)frame
->data
[0];
607 for (i
= 0; i
< frame
->nb_samples
; i
++) {
608 int64_t max_samples
= col
== outlink
->w
- 1 ? last_column_samples
: column_max_samples
;
611 switch (showwaves
->filter_mode
) {
613 for (ch
= 0; ch
< nb_channels
; ch
++)
614 sum
[ch
] += abs(p
[ch
+ i
*nb_channels
]);
617 for (ch
= 0; ch
< nb_channels
; ch
++)
618 sum
[ch
] = FFMAX(sum
[ch
], abs(p
[ch
+ i
*nb_channels
]));
623 if (n
== max_samples
) {
624 for (ch
= 0; ch
< nb_channels
; ch
++) {
625 int16_t sample
= sum
[ch
] / (showwaves
->filter_mode
== FILTER_AVERAGE
? max_samples
: 1);
626 uint8_t *buf
= out
->data
[0] + col
* pixstep
;
629 if (showwaves
->split_channels
)
630 buf
+= ch
*ch_height
*linesize
;
631 av_assert0(col
< outlink
->w
);
632 h
= showwaves
->get_h(sample
, ch_height
);
633 showwaves
->draw_sample(buf
, ch_height
, linesize
, &showwaves
->buf_idy
[ch
], &showwaves
->fg
[ch
* 4], h
);
642 return push_frame(outlink
, 0, 0);
646 static int request_frame(AVFilterLink
*outlink
)
648 ShowWavesContext
*showwaves
= outlink
->src
->priv
;
649 AVFilterLink
*inlink
= outlink
->src
->inputs
[0];
652 ret
= ff_request_frame(inlink
);
653 if (ret
== AVERROR_EOF
&& showwaves
->outpicref
) {
654 push_single_pic(outlink
);
660 static int alloc_out_frame(ShowWavesContext
*showwaves
,
661 AVFilterLink
*outlink
)
663 if (!showwaves
->outpicref
) {
664 AVFrame
*out
= showwaves
->outpicref
=
665 ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
667 return AVERROR(ENOMEM
);
668 out
->width
= outlink
->w
;
669 out
->height
= outlink
->h
;
670 for (int j
= 0; j
< outlink
->h
; j
++)
671 memset(out
->data
[0] + j
*out
->linesize
[0], 0, outlink
->w
* showwaves
->pixstep
);
676 static av_cold
int init(AVFilterContext
*ctx
)
678 ShowWavesContext
*showwaves
= ctx
->priv
;
680 if (!strcmp(ctx
->filter
->name
, "showwavespic")) {
681 showwaves
->single_pic
= 1;
682 showwaves
->mode
= MODE_CENTERED_LINE
;
688 #if CONFIG_SHOWWAVES_FILTER
690 static int showwaves_filter_frame(AVFilterLink
*inlink
, AVFrame
*insamples
)
692 AVFilterContext
*ctx
= inlink
->dst
;
693 AVFilterLink
*outlink
= ctx
->outputs
[0];
694 ShowWavesContext
*showwaves
= ctx
->priv
;
695 const int nb_samples
= insamples
->nb_samples
;
696 AVFrame
*outpicref
= showwaves
->outpicref
;
697 const int16_t *p
= (const int16_t *)insamples
->data
[0];
698 int16_t *history
= showwaves
->history
;
699 const int nb_channels
= inlink
->ch_layout
.nb_channels
;
700 int i
, j
, ret
= 0, linesize
;
701 const int pixstep
= showwaves
->pixstep
;
702 const int ch_height
= showwaves
->split_channels
? outlink
->h
/ nb_channels
: outlink
->h
;
703 const int history_nb_samples
= showwaves
->history_nb_samples
;
704 const int split_channels
= showwaves
->split_channels
;
705 const AVRational i_n
= av_inv_q(showwaves
->n
);
706 const AVRational u_q
= av_make_q(1, 1);
707 const AVRational z_q
= av_make_q(0, 1);
708 int16_t *buf_idy
= showwaves
->buf_idy
;
709 int idx
= showwaves
->history_index
;
710 int buf_idx
= showwaves
->buf_idx
;
711 const uint8_t *fg
= showwaves
->fg
;
712 const int w
= showwaves
->w
;
715 for (int n
= 0; n
< nb_samples
* nb_channels
; n
++) {
716 history
[idx
++] = p
[n
];
717 if (idx
>= history_nb_samples
)
720 showwaves
->history_index
= idx
;
722 ret
= alloc_out_frame(showwaves
, outlink
);
725 outpicref
= showwaves
->outpicref
;
726 linesize
= outpicref
->linesize
[0];
728 /* draw data in the buffer */
729 dst
= outpicref
->data
[0];
730 for (i
= 0; i
< history_nb_samples
; i
++) {
731 for (j
= 0; j
< nb_channels
; j
++) {
732 uint8_t *buf
= dst
+ buf_idx
* pixstep
;
736 buf
+= j
*ch_height
*linesize
;
737 h
= showwaves
->get_h(history
[idx
++], ch_height
);
738 if (idx
>= history_nb_samples
)
740 showwaves
->draw_sample(buf
, ch_height
, linesize
,
741 &buf_idy
[j
], &fg
[j
* 4], h
);
744 showwaves
->c
= av_add_q(showwaves
->c
, i_n
);
745 if (av_cmp_q(showwaves
->c
, u_q
) >= 0) {
753 showwaves
->buf_idx
= buf_idx
;
755 if ((ret
= push_frame(outlink
, history_nb_samples
- i
- 1, insamples
->pts
)) < 0)
757 outpicref
= showwaves
->outpicref
;
759 av_frame_free(&insamples
);
763 static int activate(AVFilterContext
*ctx
)
765 AVFilterLink
*inlink
= ctx
->inputs
[0];
766 AVFilterLink
*outlink
= ctx
->outputs
[0];
767 ShowWavesContext
*showwaves
= ctx
->priv
;
773 FF_FILTER_FORWARD_STATUS_BACK(outlink
, inlink
);
775 q
= av_add_q(showwaves
->q
, av_mul_q(av_make_q(outlink
->w
, 1), showwaves
->n
));
776 nb_samples
= (q
.num
+ (q
.den
/ 2)) / q
.den
;
777 ret
= ff_inlink_consume_samples(inlink
, nb_samples
, nb_samples
, &in
);
781 showwaves
->q
= av_sub_q(q
, av_make_q(nb_samples
, 1));
782 return showwaves_filter_frame(inlink
, in
);
785 FF_FILTER_FORWARD_STATUS(inlink
, outlink
);
786 FF_FILTER_FORWARD_WANTED(outlink
, inlink
);
788 return FFERROR_NOT_READY
;
791 static const AVFilterPad showwaves_outputs
[] = {
794 .type
= AVMEDIA_TYPE_VIDEO
,
795 .config_props
= config_output
,
799 const FFFilter ff_avf_showwaves
= {
800 .p
.name
= "showwaves",
801 .p
.description
= NULL_IF_CONFIG_SMALL("Convert input audio to a video output."),
802 .p
.priv_class
= &showwaves_class
,
805 .priv_size
= sizeof(ShowWavesContext
),
806 FILTER_INPUTS(ff_audio_default_filterpad
),
807 .activate
= activate
,
808 FILTER_OUTPUTS(showwaves_outputs
),
809 FILTER_QUERY_FUNC2(query_formats
),
812 #endif // CONFIG_SHOWWAVES_FILTER
814 #if CONFIG_SHOWWAVESPIC_FILTER
816 #define OFFSET(x) offsetof(ShowWavesContext, x)
817 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
819 static const AVOption showwavespic_options
[] = {
820 { "size", "set video size", OFFSET(w
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= "600x240"}, 0, 0, FLAGS
},
821 { "s", "set video size", OFFSET(w
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
= "600x240"}, 0, 0, FLAGS
},
822 { "split_channels", "draw channels separately", OFFSET(split_channels
), AV_OPT_TYPE_BOOL
, {.i64
= 0}, 0, 1, FLAGS
},
823 { "colors", "set channels colors", OFFSET(colors
), AV_OPT_TYPE_STRING
, {.str
= "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS
},
824 { "scale", "set amplitude scale", OFFSET(scale
), AV_OPT_TYPE_INT
, {.i64
= 0 }, 0, SCALE_NB
-1, FLAGS
, .unit
="scale" },
825 { "lin", "linear", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_LIN
}, .flags
=FLAGS
, .unit
="scale"},
826 { "log", "logarithmic", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_LOG
}, .flags
=FLAGS
, .unit
="scale"},
827 { "sqrt", "square root", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_SQRT
}, .flags
=FLAGS
, .unit
="scale"},
828 { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST
, {.i64
=SCALE_CBRT
}, .flags
=FLAGS
, .unit
="scale"},
829 { "draw", "set draw mode", OFFSET(draw_mode
), AV_OPT_TYPE_INT
, {.i64
= DRAW_SCALE
}, 0, DRAW_NB
-1, FLAGS
, .unit
="draw" },
830 { "scale", "scale pixel values for each drawn sample", 0, AV_OPT_TYPE_CONST
, {.i64
=DRAW_SCALE
}, .flags
=FLAGS
, .unit
="draw"},
831 { "full", "draw every pixel for sample directly", 0, AV_OPT_TYPE_CONST
, {.i64
=DRAW_FULL
}, .flags
=FLAGS
, .unit
="draw"},
832 { "filter", "set filter mode", OFFSET(filter_mode
), AV_OPT_TYPE_INT
, {.i64
= FILTER_AVERAGE
}, 0, FILTER_NB
-1, FLAGS
, .unit
="filter" },
833 { "average", "use average samples", 0, AV_OPT_TYPE_CONST
, {.i64
=FILTER_AVERAGE
}, .flags
=FLAGS
, .unit
="filter"},
834 { "peak", "use peak samples", 0, AV_OPT_TYPE_CONST
, {.i64
=FILTER_PEAK
}, .flags
=FLAGS
, .unit
="filter"},
838 AVFILTER_DEFINE_CLASS(showwavespic
);
840 static int showwavespic_config_input(AVFilterLink
*inlink
)
842 AVFilterContext
*ctx
= inlink
->dst
;
843 ShowWavesContext
*showwaves
= ctx
->priv
;
845 if (showwaves
->single_pic
) {
846 showwaves
->sum
= av_calloc(inlink
->ch_layout
.nb_channels
, sizeof(*showwaves
->sum
));
848 return AVERROR(ENOMEM
);
854 static int showwavespic_filter_frame(AVFilterLink
*inlink
, AVFrame
*insamples
)
856 AVFilterContext
*ctx
= inlink
->dst
;
857 AVFilterLink
*outlink
= ctx
->outputs
[0];
858 ShowWavesContext
*showwaves
= ctx
->priv
;
861 if (showwaves
->single_pic
) {
862 struct frame_node
*f
;
864 ret
= alloc_out_frame(showwaves
, outlink
);
868 /* queue the audio frame */
869 f
= av_malloc(sizeof(*f
));
871 ret
= AVERROR(ENOMEM
);
874 f
->frame
= insamples
;
876 if (!showwaves
->last_frame
) {
877 showwaves
->audio_frames
=
878 showwaves
->last_frame
= f
;
880 showwaves
->last_frame
->next
= f
;
881 showwaves
->last_frame
= f
;
883 showwaves
->total_samples
+= insamples
->nb_samples
;
889 av_frame_free(&insamples
);
893 static const AVFilterPad showwavespic_inputs
[] = {
896 .type
= AVMEDIA_TYPE_AUDIO
,
897 .config_props
= showwavespic_config_input
,
898 .filter_frame
= showwavespic_filter_frame
,
902 static const AVFilterPad showwavespic_outputs
[] = {
905 .type
= AVMEDIA_TYPE_VIDEO
,
906 .config_props
= config_output
,
907 .request_frame
= request_frame
,
911 const FFFilter ff_avf_showwavespic
= {
912 .p
.name
= "showwavespic",
913 .p
.description
= NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."),
914 .p
.priv_class
= &showwavespic_class
,
917 .priv_size
= sizeof(ShowWavesContext
),
918 FILTER_INPUTS(showwavespic_inputs
),
919 FILTER_OUTPUTS(showwavespic_outputs
),
920 FILTER_QUERY_FUNC2(query_formats
),
923 #endif // CONFIG_SHOWWAVESPIC_FILTER