2 * Copyright (c) 2009 Rob Sykes <robs@users.sourceforge.net>
3 * Copyright (c) 2013 Paul B Mahol
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/opt.h"
29 typedef struct ChannelStats
{
31 double sigma_x
, sigma_x2
;
32 double avg_sigma_x2
, min_sigma_x2
, max_sigma_x2
;
34 double min_run
, max_run
;
35 double min_runs
, max_runs
;
36 uint64_t min_count
, max_count
;
42 ChannelStats
*chstats
;
49 #define OFFSET(x) offsetof(AudioStatsContext, x)
50 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
52 static const AVOption astats_options
[] = {
53 { "length", "set the window length", OFFSET(time_constant
), AV_OPT_TYPE_DOUBLE
, {.dbl
=.05}, .01, 10, FLAGS
},
57 AVFILTER_DEFINE_CLASS(astats
);
59 static int query_formats(AVFilterContext
*ctx
)
61 AVFilterFormats
*formats
;
62 AVFilterChannelLayouts
*layouts
;
63 static const enum AVSampleFormat sample_fmts
[] = {
64 AV_SAMPLE_FMT_DBL
, AV_SAMPLE_FMT_DBLP
,
68 layouts
= ff_all_channel_layouts();
70 return AVERROR(ENOMEM
);
71 ff_set_common_channel_layouts(ctx
, layouts
);
73 formats
= ff_make_format_list(sample_fmts
);
75 return AVERROR(ENOMEM
);
76 ff_set_common_formats(ctx
, formats
);
78 formats
= ff_all_samplerates();
80 return AVERROR(ENOMEM
);
81 ff_set_common_samplerates(ctx
, formats
);
86 static int config_output(AVFilterLink
*outlink
)
88 AudioStatsContext
*s
= outlink
->src
->priv
;
91 s
->chstats
= av_calloc(sizeof(*s
->chstats
), outlink
->channels
);
93 return AVERROR(ENOMEM
);
94 s
->nb_channels
= outlink
->channels
;
95 s
->mult
= exp((-1 / s
->time_constant
/ outlink
->sample_rate
));
96 s
->tc_samples
= 5 * s
->time_constant
* outlink
->sample_rate
+ .5;
98 for (c
= 0; c
< s
->nb_channels
; c
++) {
99 ChannelStats
*p
= &s
->chstats
[c
];
101 p
->min
= p
->min_sigma_x2
= DBL_MAX
;
102 p
->max
= p
->max_sigma_x2
= DBL_MIN
;
108 static inline void update_stat(AudioStatsContext
*s
, ChannelStats
*p
, double d
)
115 } else if (d
== p
->min
) {
117 p
->min_run
= d
== p
->last
? p
->min_run
+ 1 : 1;
118 } else if (p
->last
== p
->min
) {
119 p
->min_runs
+= p
->min_run
* p
->min_run
;
127 } else if (d
== p
->max
) {
129 p
->max_run
= d
== p
->last
? p
->max_run
+ 1 : 1;
130 } else if (p
->last
== p
->max
) {
131 p
->max_runs
+= p
->max_run
* p
->max_run
;
135 p
->sigma_x2
+= d
* d
;
136 p
->avg_sigma_x2
= p
->avg_sigma_x2
* s
->mult
+ (1.0 - s
->mult
) * d
* d
;
139 if (p
->nb_samples
>= s
->tc_samples
) {
140 p
->max_sigma_x2
= FFMAX(p
->max_sigma_x2
, p
->avg_sigma_x2
);
141 p
->min_sigma_x2
= FFMIN(p
->min_sigma_x2
, p
->avg_sigma_x2
);
146 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*buf
)
148 AudioStatsContext
*s
= inlink
->dst
->priv
;
149 const int channels
= s
->nb_channels
;
153 switch (inlink
->format
) {
154 case AV_SAMPLE_FMT_DBLP
:
155 for (c
= 0; c
< channels
; c
++) {
156 ChannelStats
*p
= &s
->chstats
[c
];
157 src
= (const double *)buf
->extended_data
[c
];
159 for (i
= 0; i
< buf
->nb_samples
; i
++, src
++)
160 update_stat(s
, p
, *src
);
163 case AV_SAMPLE_FMT_DBL
:
164 src
= (const double *)buf
->extended_data
[0];
166 for (i
= 0; i
< buf
->nb_samples
; i
++) {
167 for (c
= 0; c
< channels
; c
++, src
++)
168 update_stat(s
, &s
->chstats
[c
], *src
);
173 return ff_filter_frame(inlink
->dst
->outputs
[0], buf
);
176 #define LINEAR_TO_DB(x) (log10(x) * 20)
178 static void print_stats(AVFilterContext
*ctx
)
180 AudioStatsContext
*s
= ctx
->priv
;
181 uint64_t min_count
= 0, max_count
= 0, nb_samples
= 0;
182 double min_runs
= 0, max_runs
= 0,
183 min
= DBL_MAX
, max
= DBL_MIN
,
187 min_sigma_x2
= DBL_MAX
,
188 max_sigma_x2
= DBL_MIN
;
191 for (c
= 0; c
< s
->nb_channels
; c
++) {
192 ChannelStats
*p
= &s
->chstats
[c
];
194 if (p
->nb_samples
< s
->tc_samples
)
195 p
->min_sigma_x2
= p
->max_sigma_x2
= p
->sigma_x2
/ p
->nb_samples
;
197 min
= FFMIN(min
, p
->min
);
198 max
= FFMAX(max
, p
->max
);
199 min_sigma_x2
= FFMIN(min_sigma_x2
, p
->min_sigma_x2
);
200 max_sigma_x2
= FFMAX(max_sigma_x2
, p
->max_sigma_x2
);
201 sigma_x
+= p
->sigma_x
;
202 sigma_x2
+= p
->sigma_x2
;
203 min_count
+= p
->min_count
;
204 max_count
+= p
->max_count
;
205 min_runs
+= p
->min_runs
;
206 max_runs
+= p
->max_runs
;
207 nb_samples
+= p
->nb_samples
;
208 if (fabs(p
->sigma_x
) > fabs(max_sigma_x
))
209 max_sigma_x
= p
->sigma_x
;
211 av_log(ctx
, AV_LOG_INFO
, "Channel: %d\n", c
+ 1);
212 av_log(ctx
, AV_LOG_INFO
, "DC offset: %f\n", p
->sigma_x
/ p
->nb_samples
);
213 av_log(ctx
, AV_LOG_INFO
, "Min level: %f\n", p
->min
);
214 av_log(ctx
, AV_LOG_INFO
, "Max level: %f\n", p
->max
);
215 av_log(ctx
, AV_LOG_INFO
, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-p
->min
, p
->max
)));
216 av_log(ctx
, AV_LOG_INFO
, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(p
->sigma_x2
/ p
->nb_samples
)));
217 av_log(ctx
, AV_LOG_INFO
, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(p
->max_sigma_x2
)));
218 if (p
->min_sigma_x2
!= 1)
219 av_log(ctx
, AV_LOG_INFO
, "RMS trough dB: %f\n",LINEAR_TO_DB(sqrt(p
->min_sigma_x2
)));
220 av_log(ctx
, AV_LOG_INFO
, "Crest factor: %f\n", p
->sigma_x2
? FFMAX(-p
->min
, p
->max
) / sqrt(p
->sigma_x2
/ p
->nb_samples
) : 1);
221 av_log(ctx
, AV_LOG_INFO
, "Flat factor: %f\n", LINEAR_TO_DB((p
->min_runs
+ p
->max_runs
) / (p
->min_count
+ p
->max_count
)));
222 av_log(ctx
, AV_LOG_INFO
, "Peak count: %"PRId64
"\n", p
->min_count
+ p
->max_count
);
225 av_log(ctx
, AV_LOG_INFO
, "Overall\n");
226 av_log(ctx
, AV_LOG_INFO
, "DC offset: %f\n", max_sigma_x
/ (nb_samples
/ s
->nb_channels
));
227 av_log(ctx
, AV_LOG_INFO
, "Min level: %f\n", min
);
228 av_log(ctx
, AV_LOG_INFO
, "Max level: %f\n", max
);
229 av_log(ctx
, AV_LOG_INFO
, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-min
, max
)));
230 av_log(ctx
, AV_LOG_INFO
, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(sigma_x2
/ nb_samples
)));
231 av_log(ctx
, AV_LOG_INFO
, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(max_sigma_x2
)));
232 if (min_sigma_x2
!= 1)
233 av_log(ctx
, AV_LOG_INFO
, "RMS trough dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2
)));
234 av_log(ctx
, AV_LOG_INFO
, "Flat factor: %f\n", LINEAR_TO_DB((min_runs
+ max_runs
) / (min_count
+ max_count
)));
235 av_log(ctx
, AV_LOG_INFO
, "Peak count: %f\n", (min_count
+ max_count
) / (double)s
->nb_channels
);
236 av_log(ctx
, AV_LOG_INFO
, "Number of samples: %"PRId64
"\n", nb_samples
/ s
->nb_channels
);
239 static av_cold
void uninit(AVFilterContext
*ctx
)
241 AudioStatsContext
*s
= ctx
->priv
;
244 av_freep(&s
->chstats
);
247 static const AVFilterPad astats_inputs
[] = {
250 .type
= AVMEDIA_TYPE_AUDIO
,
251 .filter_frame
= filter_frame
,
256 static const AVFilterPad astats_outputs
[] = {
259 .type
= AVMEDIA_TYPE_AUDIO
,
260 .config_props
= config_output
,
265 AVFilter ff_af_astats
= {
267 .description
= NULL_IF_CONFIG_SMALL("Show time domain statistics about audio frames."),
268 .query_formats
= query_formats
,
269 .priv_size
= sizeof(AudioStatsContext
),
270 .priv_class
= &astats_class
,
272 .inputs
= astats_inputs
,
273 .outputs
= astats_outputs
,