Also contains the following changes to the library: - add ff_ prefix to functions - remove cplusplus defines. - add FF_ prefix to contants and some structs - remove true peak calculation feature, since it uses its own resampler, and af_loudnorm does not need it. - remove version info and some fprintf(stderr) functions - convert to use av_malloc - always use histogram mode for LRA calculation, otherwise LRA data is slowly consuming memory making af_loudnorm unfit for 24/7 operation. It also uses a BSD style linked list implementation which is probably not available on all platforms. So let's just remove the classic mode which not uses histogram. - add ff_thread_once for calculating static histogram tables - convert some functions to void which cannot fail - remove intrinsics and some unused headers - add support for planar audio - remove channel / sample rate changer function, in ffmpeg usually we simply alloc a new context - convert some static variables to defines - declare static histogram variables as aligned - convert some initalizations to mallocz - add window size parameter to init function and remove window size setter function - convert return codes to AVERROR - fix indentation Signed-off-by: Marton Balint <cus@passwd.hu>tags/n3.3
@@ -3,6 +3,7 @@ releases are sorted from youngest to oldest. | |||||
version <next>: | version <next>: | ||||
- CrystalHD decoder moved to new decode API | - CrystalHD decoder moved to new decode API | ||||
- add internal ebur128 library, remove external libebur128 dependency | |||||
version 3.2: | version 3.2: | ||||
- libopenmpt demuxer | - libopenmpt demuxer | ||||
@@ -222,8 +222,6 @@ External library support: | |||||
--enable-libcdio enable audio CD grabbing with libcdio [no] | --enable-libcdio enable audio CD grabbing with libcdio [no] | ||||
--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 | --enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 | ||||
and libraw1394 [no] | and libraw1394 [no] | ||||
--enable-libebur128 enable libebur128 for EBU R128 measurement, | |||||
needed for loudnorm filter [no] | |||||
--enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] | --enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] | ||||
--enable-libflite enable flite (voice synthesis) support via libflite [no] | --enable-libflite enable flite (voice synthesis) support via libflite [no] | ||||
--enable-libfontconfig enable libfontconfig, useful for drawtext filter [no] | --enable-libfontconfig enable libfontconfig, useful for drawtext filter [no] | ||||
@@ -1491,7 +1489,6 @@ EXTERNAL_LIBRARY_LIST=" | |||||
libcdio | libcdio | ||||
libcelt | libcelt | ||||
libdc1394 | libdc1394 | ||||
libebur128 | |||||
libfdk_aac | libfdk_aac | ||||
libflite | libflite | ||||
libfontconfig | libfontconfig | ||||
@@ -3052,7 +3049,6 @@ hqdn3d_filter_deps="gpl" | |||||
interlace_filter_deps="gpl" | interlace_filter_deps="gpl" | ||||
kerndeint_filter_deps="gpl" | kerndeint_filter_deps="gpl" | ||||
ladspa_filter_deps="ladspa dlopen" | ladspa_filter_deps="ladspa dlopen" | ||||
loudnorm_filter_deps="libebur128" | |||||
mcdeint_filter_deps="avcodec gpl" | mcdeint_filter_deps="avcodec gpl" | ||||
movie_filter_deps="avcodec avformat" | movie_filter_deps="avcodec avformat" | ||||
mpdecimate_filter_deps="gpl" | mpdecimate_filter_deps="gpl" | ||||
@@ -5689,7 +5685,6 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && | |||||
{ check_lib celt/celt.h celt_decoder_create_custom -lcelt0 || | { check_lib celt/celt.h celt_decoder_create_custom -lcelt0 || | ||||
die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } | die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } | ||||
enabled libcaca && require_pkg_config caca caca.h caca_create_canvas | enabled libcaca && require_pkg_config caca caca.h caca_create_canvas | ||||
enabled libebur128 && require ebur128 ebur128.h ebur128_relative_threshold -lebur128 | |||||
enabled libfdk_aac && { use_pkg_config fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || | enabled libfdk_aac && { use_pkg_config fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || | ||||
{ require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac && | { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac && | ||||
warn "using libfdk without pkg-config"; } } | warn "using libfdk without pkg-config"; } } | ||||
@@ -2921,9 +2921,6 @@ EBU R128 loudness normalization. Includes both dynamic and linear normalization | |||||
Support for both single pass (livestreams, files) and double pass (files) modes. | Support for both single pass (livestreams, files) and double pass (files) modes. | ||||
This algorithm can target IL, LRA, and maximum true peak. | This algorithm can target IL, LRA, and maximum true peak. | ||||
To enable compilation of this filter you need to configure FFmpeg with | |||||
@code{--enable-libebur128}. | |||||
The filter accepts the following options: | The filter accepts the following options: | ||||
@table @option | @table @option | ||||
@@ -93,7 +93,7 @@ OBJS-$(CONFIG_HDCD_FILTER) += af_hdcd.o | |||||
OBJS-$(CONFIG_HIGHPASS_FILTER) += af_biquads.o | OBJS-$(CONFIG_HIGHPASS_FILTER) += af_biquads.o | ||||
OBJS-$(CONFIG_JOIN_FILTER) += af_join.o | OBJS-$(CONFIG_JOIN_FILTER) += af_join.o | ||||
OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o | OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o | ||||
OBJS-$(CONFIG_LOUDNORM_FILTER) += af_loudnorm.o | |||||
OBJS-$(CONFIG_LOUDNORM_FILTER) += af_loudnorm.o ebur128.o | |||||
OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o | OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o | ||||
OBJS-$(CONFIG_PAN_FILTER) += af_pan.o | OBJS-$(CONFIG_PAN_FILTER) += af_pan.o | ||||
OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o | OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o | ||||
@@ -24,7 +24,7 @@ | |||||
#include "avfilter.h" | #include "avfilter.h" | ||||
#include "internal.h" | #include "internal.h" | ||||
#include "audio.h" | #include "audio.h" | ||||
#include <ebur128.h> | |||||
#include "ebur128.h" | |||||
enum FrameType { | enum FrameType { | ||||
FIRST_FRAME, | FIRST_FRAME, | ||||
@@ -91,8 +91,8 @@ typedef struct LoudNormContext { | |||||
int prev_nb_samples; | int prev_nb_samples; | ||||
int channels; | int channels; | ||||
ebur128_state *r128_in; | |||||
ebur128_state *r128_out; | |||||
FFEBUR128State *r128_in; | |||||
FFEBUR128State *r128_out; | |||||
} LoudNormContext; | } LoudNormContext; | ||||
#define OFFSET(x) offsetof(LoudNormContext, x) | #define OFFSET(x) offsetof(LoudNormContext, x) | ||||
@@ -437,15 +437,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
buf = s->buf; | buf = s->buf; | ||||
limiter_buf = s->limiter_buf; | limiter_buf = s->limiter_buf; | ||||
ebur128_add_frames_double(s->r128_in, src, in->nb_samples); | |||||
ff_ebur128_add_frames_double(s->r128_in, src, in->nb_samples); | |||||
if (s->frame_type == FIRST_FRAME && in->nb_samples < frame_size(inlink->sample_rate, 3000)) { | if (s->frame_type == FIRST_FRAME && in->nb_samples < frame_size(inlink->sample_rate, 3000)) { | ||||
double offset, offset_tp, true_peak; | double offset, offset_tp, true_peak; | ||||
ebur128_loudness_global(s->r128_in, &global); | |||||
ff_ebur128_loudness_global(s->r128_in, &global); | |||||
for (c = 0; c < inlink->channels; c++) { | for (c = 0; c < inlink->channels; c++) { | ||||
double tmp; | double tmp; | ||||
ebur128_sample_peak(s->r128_in, c, &tmp); | |||||
ff_ebur128_sample_peak(s->r128_in, c, &tmp); | |||||
if (c == 0 || tmp > true_peak) | if (c == 0 || tmp > true_peak) | ||||
true_peak = tmp; | true_peak = tmp; | ||||
} | } | ||||
@@ -467,7 +467,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
s->buf_index += inlink->channels; | s->buf_index += inlink->channels; | ||||
} | } | ||||
ebur128_loudness_shortterm(s->r128_in, &shortterm); | |||||
ff_ebur128_loudness_shortterm(s->r128_in, &shortterm); | |||||
if (shortterm < s->measured_thresh) { | if (shortterm < s->measured_thresh) { | ||||
s->above_threshold = 0; | s->above_threshold = 0; | ||||
@@ -497,7 +497,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
subframe_length = frame_size(inlink->sample_rate, 100); | subframe_length = frame_size(inlink->sample_rate, 100); | ||||
true_peak_limiter(s, dst, subframe_length, inlink->channels); | true_peak_limiter(s, dst, subframe_length, inlink->channels); | ||||
ebur128_add_frames_double(s->r128_out, dst, subframe_length); | |||||
ff_ebur128_add_frames_double(s->r128_out, dst, subframe_length); | |||||
s->pts += | s->pts += | ||||
out->nb_samples = | out->nb_samples = | ||||
@@ -536,12 +536,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
s->limiter_buf_index = s->limiter_buf_index + subframe_length < s->limiter_buf_size ? s->limiter_buf_index + subframe_length : s->limiter_buf_index + subframe_length - s->limiter_buf_size; | s->limiter_buf_index = s->limiter_buf_index + subframe_length < s->limiter_buf_size ? s->limiter_buf_index + subframe_length : s->limiter_buf_index + subframe_length - s->limiter_buf_size; | ||||
true_peak_limiter(s, dst, in->nb_samples, inlink->channels); | true_peak_limiter(s, dst, in->nb_samples, inlink->channels); | ||||
ebur128_add_frames_double(s->r128_out, dst, in->nb_samples); | |||||
ff_ebur128_add_frames_double(s->r128_out, dst, in->nb_samples); | |||||
ebur128_loudness_range(s->r128_in, &lra); | |||||
ebur128_loudness_global(s->r128_in, &global); | |||||
ebur128_loudness_shortterm(s->r128_in, &shortterm); | |||||
ebur128_relative_threshold(s->r128_in, &relative_threshold); | |||||
ff_ebur128_loudness_range(s->r128_in, &lra); | |||||
ff_ebur128_loudness_global(s->r128_in, &global); | |||||
ff_ebur128_loudness_shortterm(s->r128_in, &shortterm); | |||||
ff_ebur128_relative_threshold(s->r128_in, &relative_threshold); | |||||
if (s->above_threshold == 0) { | if (s->above_threshold == 0) { | ||||
double shortterm_out; | double shortterm_out; | ||||
@@ -549,7 +549,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
if (shortterm > s->measured_thresh) | if (shortterm > s->measured_thresh) | ||||
s->prev_delta *= 1.0058; | s->prev_delta *= 1.0058; | ||||
ebur128_loudness_shortterm(s->r128_out, &shortterm_out); | |||||
ff_ebur128_loudness_shortterm(s->r128_out, &shortterm_out); | |||||
if (shortterm_out >= s->target_i) | if (shortterm_out >= s->target_i) | ||||
s->above_threshold = 1; | s->above_threshold = 1; | ||||
} | } | ||||
@@ -611,7 +611,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
} | } | ||||
dst = (double *)out->data[0]; | dst = (double *)out->data[0]; | ||||
ebur128_add_frames_double(s->r128_out, dst, in->nb_samples); | |||||
ff_ebur128_add_frames_double(s->r128_out, dst, in->nb_samples); | |||||
break; | break; | ||||
case LINEAR_MODE: | case LINEAR_MODE: | ||||
@@ -624,7 +624,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) | |||||
} | } | ||||
dst = (double *)out->data[0]; | dst = (double *)out->data[0]; | ||||
ebur128_add_frames_double(s->r128_out, dst, in->nb_samples); | |||||
ff_ebur128_add_frames_double(s->r128_out, dst, in->nb_samples); | |||||
s->pts += in->nb_samples; | s->pts += in->nb_samples; | ||||
break; | break; | ||||
} | } | ||||
@@ -725,17 +725,17 @@ static int config_input(AVFilterLink *inlink) | |||||
AVFilterContext *ctx = inlink->dst; | AVFilterContext *ctx = inlink->dst; | ||||
LoudNormContext *s = ctx->priv; | LoudNormContext *s = ctx->priv; | ||||
s->r128_in = ebur128_init(inlink->channels, inlink->sample_rate, EBUR128_MODE_I | EBUR128_MODE_S | EBUR128_MODE_LRA | EBUR128_MODE_SAMPLE_PEAK); | |||||
s->r128_in = ff_ebur128_init(inlink->channels, inlink->sample_rate, 0, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK); | |||||
if (!s->r128_in) | if (!s->r128_in) | ||||
return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
s->r128_out = ebur128_init(inlink->channels, inlink->sample_rate, EBUR128_MODE_I | EBUR128_MODE_S | EBUR128_MODE_LRA | EBUR128_MODE_SAMPLE_PEAK); | |||||
s->r128_out = ff_ebur128_init(inlink->channels, inlink->sample_rate, 0, FF_EBUR128_MODE_I | FF_EBUR128_MODE_S | FF_EBUR128_MODE_LRA | FF_EBUR128_MODE_SAMPLE_PEAK); | |||||
if (!s->r128_out) | if (!s->r128_out) | ||||
return AVERROR(ENOMEM); | return AVERROR(ENOMEM); | ||||
if (inlink->channels == 1 && s->dual_mono) { | if (inlink->channels == 1 && s->dual_mono) { | ||||
ebur128_set_channel(s->r128_in, 0, EBUR128_DUAL_MONO); | |||||
ebur128_set_channel(s->r128_out, 0, EBUR128_DUAL_MONO); | |||||
ff_ebur128_set_channel(s->r128_in, 0, FF_EBUR128_DUAL_MONO); | |||||
ff_ebur128_set_channel(s->r128_out, 0, FF_EBUR128_DUAL_MONO); | |||||
} | } | ||||
s->buf_size = frame_size(inlink->sample_rate, 3000) * inlink->channels; | s->buf_size = frame_size(inlink->sample_rate, 3000) * inlink->channels; | ||||
@@ -799,22 +799,22 @@ static av_cold void uninit(AVFilterContext *ctx) | |||||
if (!s->r128_in || !s->r128_out) | if (!s->r128_in || !s->r128_out) | ||||
goto end; | goto end; | ||||
ebur128_loudness_range(s->r128_in, &lra_in); | |||||
ebur128_loudness_global(s->r128_in, &i_in); | |||||
ebur128_relative_threshold(s->r128_in, &thresh_in); | |||||
ff_ebur128_loudness_range(s->r128_in, &lra_in); | |||||
ff_ebur128_loudness_global(s->r128_in, &i_in); | |||||
ff_ebur128_relative_threshold(s->r128_in, &thresh_in); | |||||
for (c = 0; c < s->channels; c++) { | for (c = 0; c < s->channels; c++) { | ||||
double tmp; | double tmp; | ||||
ebur128_sample_peak(s->r128_in, c, &tmp); | |||||
ff_ebur128_sample_peak(s->r128_in, c, &tmp); | |||||
if ((c == 0) || (tmp > tp_in)) | if ((c == 0) || (tmp > tp_in)) | ||||
tp_in = tmp; | tp_in = tmp; | ||||
} | } | ||||
ebur128_loudness_range(s->r128_out, &lra_out); | |||||
ebur128_loudness_global(s->r128_out, &i_out); | |||||
ebur128_relative_threshold(s->r128_out, &thresh_out); | |||||
ff_ebur128_loudness_range(s->r128_out, &lra_out); | |||||
ff_ebur128_loudness_global(s->r128_out, &i_out); | |||||
ff_ebur128_relative_threshold(s->r128_out, &thresh_out); | |||||
for (c = 0; c < s->channels; c++) { | for (c = 0; c < s->channels; c++) { | ||||
double tmp; | double tmp; | ||||
ebur128_sample_peak(s->r128_out, c, &tmp); | |||||
ff_ebur128_sample_peak(s->r128_out, c, &tmp); | |||||
if ((c == 0) || (tmp > tp_out)) | if ((c == 0) || (tmp > tp_out)) | ||||
tp_out = tmp; | tp_out = tmp; | ||||
} | } | ||||
@@ -881,9 +881,9 @@ static av_cold void uninit(AVFilterContext *ctx) | |||||
end: | end: | ||||
if (s->r128_in) | if (s->r128_in) | ||||
ebur128_destroy(&s->r128_in); | |||||
ff_ebur128_destroy(&s->r128_in); | |||||
if (s->r128_out) | if (s->r128_out) | ||||
ebur128_destroy(&s->r128_out); | |||||
ff_ebur128_destroy(&s->r128_out); | |||||
av_freep(&s->limiter_buf); | av_freep(&s->limiter_buf); | ||||
av_freep(&s->prev_smp); | av_freep(&s->prev_smp); | ||||
av_freep(&s->buf); | av_freep(&s->buf); | ||||
@@ -0,0 +1,784 @@ | |||||
/* | |||||
* Copyright (c) 2011 Jan KokemĂĽller | |||||
* | |||||
* This file is part of FFmpeg. | |||||
* | |||||
* FFmpeg is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2.1 of the License, or (at your option) any later version. | |||||
* | |||||
* FFmpeg is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with FFmpeg; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
* | |||||
* This file is based on libebur128 which is available at | |||||
* https://github.com/jiixyj/libebur128/ | |||||
* | |||||
* Libebur128 has the following copyright: | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in | |||||
* all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||||
* THE SOFTWARE. | |||||
*/ | |||||
#include "ebur128.h" | |||||
#include <float.h> | |||||
#include <limits.h> | |||||
#include <math.h> /* You may have to define _USE_MATH_DEFINES if you use MSVC */ | |||||
#include "libavutil/common.h" | |||||
#include "libavutil/mem.h" | |||||
#include "libavutil/thread.h" | |||||
#define CHECK_ERROR(condition, errorcode, goto_point) \ | |||||
if ((condition)) { \ | |||||
errcode = (errorcode); \ | |||||
goto goto_point; \ | |||||
} | |||||
#define ALMOST_ZERO 0.000001 | |||||
#define RELATIVE_GATE (-10.0) | |||||
#define RELATIVE_GATE_FACTOR pow(10.0, RELATIVE_GATE / 10.0) | |||||
#define MINUS_20DB pow(10.0, -20.0 / 10.0) | |||||
struct FFEBUR128StateInternal { | |||||
/** Filtered audio data (used as ring buffer). */ | |||||
double *audio_data; | |||||
/** Size of audio_data array. */ | |||||
size_t audio_data_frames; | |||||
/** Current index for audio_data. */ | |||||
size_t audio_data_index; | |||||
/** How many frames are needed for a gating block. Will correspond to 400ms | |||||
* of audio at initialization, and 100ms after the first block (75% overlap | |||||
* as specified in the 2011 revision of BS1770). */ | |||||
unsigned long needed_frames; | |||||
/** The channel map. Has as many elements as there are channels. */ | |||||
int *channel_map; | |||||
/** How many samples fit in 100ms (rounded). */ | |||||
unsigned long samples_in_100ms; | |||||
/** BS.1770 filter coefficients (nominator). */ | |||||
double b[5]; | |||||
/** BS.1770 filter coefficients (denominator). */ | |||||
double a[5]; | |||||
/** BS.1770 filter state. */ | |||||
double v[5][5]; | |||||
/** Histograms, used to calculate LRA. */ | |||||
unsigned long *block_energy_histogram; | |||||
unsigned long *short_term_block_energy_histogram; | |||||
/** Keeps track of when a new short term block is needed. */ | |||||
size_t short_term_frame_counter; | |||||
/** Maximum sample peak, one per channel */ | |||||
double *sample_peak; | |||||
/** The maximum window duration in ms. */ | |||||
unsigned long window; | |||||
/** Data pointer array for interleaved data */ | |||||
void **data_ptrs; | |||||
}; | |||||
static AVOnce histogram_init = AV_ONCE_INIT; | |||||
static DECLARE_ALIGNED(32, double, histogram_energies)[1000]; | |||||
static DECLARE_ALIGNED(32, double, histogram_energy_boundaries)[1001]; | |||||
static void ebur128_init_filter(FFEBUR128State * st) | |||||
{ | |||||
int i, j; | |||||
double f0 = 1681.974450955533; | |||||
double G = 3.999843853973347; | |||||
double Q = 0.7071752369554196; | |||||
double K = tan(M_PI * f0 / (double) st->samplerate); | |||||
double Vh = pow(10.0, G / 20.0); | |||||
double Vb = pow(Vh, 0.4996667741545416); | |||||
double pb[3] = { 0.0, 0.0, 0.0 }; | |||||
double pa[3] = { 1.0, 0.0, 0.0 }; | |||||
double rb[3] = { 1.0, -2.0, 1.0 }; | |||||
double ra[3] = { 1.0, 0.0, 0.0 }; | |||||
double a0 = 1.0 + K / Q + K * K; | |||||
pb[0] = (Vh + Vb * K / Q + K * K) / a0; | |||||
pb[1] = 2.0 * (K * K - Vh) / a0; | |||||
pb[2] = (Vh - Vb * K / Q + K * K) / a0; | |||||
pa[1] = 2.0 * (K * K - 1.0) / a0; | |||||
pa[2] = (1.0 - K / Q + K * K) / a0; | |||||
f0 = 38.13547087602444; | |||||
Q = 0.5003270373238773; | |||||
K = tan(M_PI * f0 / (double) st->samplerate); | |||||
ra[1] = 2.0 * (K * K - 1.0) / (1.0 + K / Q + K * K); | |||||
ra[2] = (1.0 - K / Q + K * K) / (1.0 + K / Q + K * K); | |||||
st->d->b[0] = pb[0] * rb[0]; | |||||
st->d->b[1] = pb[0] * rb[1] + pb[1] * rb[0]; | |||||
st->d->b[2] = pb[0] * rb[2] + pb[1] * rb[1] + pb[2] * rb[0]; | |||||
st->d->b[3] = pb[1] * rb[2] + pb[2] * rb[1]; | |||||
st->d->b[4] = pb[2] * rb[2]; | |||||
st->d->a[0] = pa[0] * ra[0]; | |||||
st->d->a[1] = pa[0] * ra[1] + pa[1] * ra[0]; | |||||
st->d->a[2] = pa[0] * ra[2] + pa[1] * ra[1] + pa[2] * ra[0]; | |||||
st->d->a[3] = pa[1] * ra[2] + pa[2] * ra[1]; | |||||
st->d->a[4] = pa[2] * ra[2]; | |||||
for (i = 0; i < 5; ++i) { | |||||
for (j = 0; j < 5; ++j) { | |||||
st->d->v[i][j] = 0.0; | |||||
} | |||||
} | |||||
} | |||||
static int ebur128_init_channel_map(FFEBUR128State * st) | |||||
{ | |||||
size_t i; | |||||
st->d->channel_map = | |||||
(int *) av_malloc_array(st->channels, sizeof(int)); | |||||
if (!st->d->channel_map) | |||||
return AVERROR(ENOMEM); | |||||
if (st->channels == 4) { | |||||
st->d->channel_map[0] = FF_EBUR128_LEFT; | |||||
st->d->channel_map[1] = FF_EBUR128_RIGHT; | |||||
st->d->channel_map[2] = FF_EBUR128_LEFT_SURROUND; | |||||
st->d->channel_map[3] = FF_EBUR128_RIGHT_SURROUND; | |||||
} else if (st->channels == 5) { | |||||
st->d->channel_map[0] = FF_EBUR128_LEFT; | |||||
st->d->channel_map[1] = FF_EBUR128_RIGHT; | |||||
st->d->channel_map[2] = FF_EBUR128_CENTER; | |||||
st->d->channel_map[3] = FF_EBUR128_LEFT_SURROUND; | |||||
st->d->channel_map[4] = FF_EBUR128_RIGHT_SURROUND; | |||||
} else { | |||||
for (i = 0; i < st->channels; ++i) { | |||||
switch (i) { | |||||
case 0: | |||||
st->d->channel_map[i] = FF_EBUR128_LEFT; | |||||
break; | |||||
case 1: | |||||
st->d->channel_map[i] = FF_EBUR128_RIGHT; | |||||
break; | |||||
case 2: | |||||
st->d->channel_map[i] = FF_EBUR128_CENTER; | |||||
break; | |||||
case 3: | |||||
st->d->channel_map[i] = FF_EBUR128_UNUSED; | |||||
break; | |||||
case 4: | |||||
st->d->channel_map[i] = FF_EBUR128_LEFT_SURROUND; | |||||
break; | |||||
case 5: | |||||
st->d->channel_map[i] = FF_EBUR128_RIGHT_SURROUND; | |||||
break; | |||||
default: | |||||
st->d->channel_map[i] = FF_EBUR128_UNUSED; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
static inline void init_histogram(void) | |||||
{ | |||||
int i; | |||||
/* initialize static constants */ | |||||
histogram_energy_boundaries[0] = pow(10.0, (-70.0 + 0.691) / 10.0); | |||||
for (i = 0; i < 1000; ++i) { | |||||
histogram_energies[i] = | |||||
pow(10.0, ((double) i / 10.0 - 69.95 + 0.691) / 10.0); | |||||
} | |||||
for (i = 1; i < 1001; ++i) { | |||||
histogram_energy_boundaries[i] = | |||||
pow(10.0, ((double) i / 10.0 - 70.0 + 0.691) / 10.0); | |||||
} | |||||
} | |||||
FFEBUR128State *ff_ebur128_init(unsigned int channels, | |||||
unsigned long samplerate, | |||||
unsigned long window, int mode) | |||||
{ | |||||
int errcode; | |||||
FFEBUR128State *st; | |||||
st = (FFEBUR128State *) av_malloc(sizeof(FFEBUR128State)); | |||||
CHECK_ERROR(!st, 0, exit) | |||||
st->d = (struct FFEBUR128StateInternal *) | |||||
av_malloc(sizeof(struct FFEBUR128StateInternal)); | |||||
CHECK_ERROR(!st->d, 0, free_state) | |||||
st->channels = channels; | |||||
errcode = ebur128_init_channel_map(st); | |||||
CHECK_ERROR(errcode, 0, free_internal) | |||||
st->d->sample_peak = | |||||
(double *) av_mallocz_array(channels, sizeof(double)); | |||||
CHECK_ERROR(!st->d->sample_peak, 0, free_channel_map) | |||||
st->samplerate = samplerate; | |||||
st->d->samples_in_100ms = (st->samplerate + 5) / 10; | |||||
st->mode = mode; | |||||
if ((mode & FF_EBUR128_MODE_S) == FF_EBUR128_MODE_S) { | |||||
st->d->window = FFMAX(window, 3000); | |||||
} else if ((mode & FF_EBUR128_MODE_M) == FF_EBUR128_MODE_M) { | |||||
st->d->window = FFMAX(window, 400); | |||||
} else { | |||||
goto free_sample_peak; | |||||
} | |||||
st->d->audio_data_frames = st->samplerate * st->d->window / 1000; | |||||
if (st->d->audio_data_frames % st->d->samples_in_100ms) { | |||||
/* round up to multiple of samples_in_100ms */ | |||||
st->d->audio_data_frames = st->d->audio_data_frames | |||||
+ st->d->samples_in_100ms | |||||
- (st->d->audio_data_frames % st->d->samples_in_100ms); | |||||
} | |||||
st->d->audio_data = | |||||
(double *) av_mallocz_array(st->d->audio_data_frames, | |||||
st->channels * sizeof(double)); | |||||
CHECK_ERROR(!st->d->audio_data, 0, free_sample_peak) | |||||
ebur128_init_filter(st); | |||||
st->d->block_energy_histogram = | |||||
av_mallocz(1000 * sizeof(unsigned long)); | |||||
CHECK_ERROR(!st->d->block_energy_histogram, 0, free_audio_data) | |||||
st->d->short_term_block_energy_histogram = | |||||
av_mallocz(1000 * sizeof(unsigned long)); | |||||
CHECK_ERROR(!st->d->short_term_block_energy_histogram, 0, | |||||
free_block_energy_histogram) | |||||
st->d->short_term_frame_counter = 0; | |||||
/* the first block needs 400ms of audio data */ | |||||
st->d->needed_frames = st->d->samples_in_100ms * 4; | |||||
/* start at the beginning of the buffer */ | |||||
st->d->audio_data_index = 0; | |||||
if (ff_thread_once(&histogram_init, &init_histogram) != 0) | |||||
goto free_short_term_block_energy_histogram; | |||||
st->d->data_ptrs = av_malloc_array(channels, sizeof(void *)); | |||||
CHECK_ERROR(!st->d->data_ptrs, 0, | |||||
free_short_term_block_energy_histogram); | |||||
return st; | |||||
free_short_term_block_energy_histogram: | |||||
av_free(st->d->short_term_block_energy_histogram); | |||||
free_block_energy_histogram: | |||||
av_free(st->d->block_energy_histogram); | |||||
free_audio_data: | |||||
av_free(st->d->audio_data); | |||||
free_sample_peak: | |||||
av_free(st->d->sample_peak); | |||||
free_channel_map: | |||||
av_free(st->d->channel_map); | |||||
free_internal: | |||||
av_free(st->d); | |||||
free_state: | |||||
av_free(st); | |||||
exit: | |||||
return NULL; | |||||
} | |||||
void ff_ebur128_destroy(FFEBUR128State ** st) | |||||
{ | |||||
av_free((*st)->d->block_energy_histogram); | |||||
av_free((*st)->d->short_term_block_energy_histogram); | |||||
av_free((*st)->d->audio_data); | |||||
av_free((*st)->d->channel_map); | |||||
av_free((*st)->d->sample_peak); | |||||
av_free((*st)->d->data_ptrs); | |||||
av_free((*st)->d); | |||||
av_free(*st); | |||||
*st = NULL; | |||||
} | |||||
#define EBUR128_FILTER(type, min_scale, max_scale) \ | |||||
static void ebur128_filter_##type(FFEBUR128State* st, const type** srcs, \ | |||||
size_t src_index, size_t frames, \ | |||||
int stride) { \ | |||||
static double scaling_factor = -((double) min_scale) > (double) max_scale ? \ | |||||
-((double) min_scale) : (double) max_scale; \ | |||||
double* audio_data = st->d->audio_data + st->d->audio_data_index; \ | |||||
size_t i, c; \ | |||||
\ | |||||
if ((st->mode & FF_EBUR128_MODE_SAMPLE_PEAK) == FF_EBUR128_MODE_SAMPLE_PEAK) { \ | |||||
for (c = 0; c < st->channels; ++c) { \ | |||||
double max = 0.0; \ | |||||
for (i = 0; i < frames; ++i) { \ | |||||
type v = srcs[c][src_index + i * stride]; \ | |||||
if (v > max) { \ | |||||
max = v; \ | |||||
} else if (-v > max) { \ | |||||
max = -1.0 * v; \ | |||||
} \ | |||||
} \ | |||||
max /= scaling_factor; \ | |||||
if (max > st->d->sample_peak[c]) st->d->sample_peak[c] = max; \ | |||||
} \ | |||||
} \ | |||||
for (c = 0; c < st->channels; ++c) { \ | |||||
int ci = st->d->channel_map[c] - 1; \ | |||||
if (ci < 0) continue; \ | |||||
else if (ci == FF_EBUR128_DUAL_MONO - 1) ci = 0; /*dual mono */ \ | |||||
for (i = 0; i < frames; ++i) { \ | |||||
st->d->v[ci][0] = (double) (srcs[c][src_index + i * stride] / scaling_factor) \ | |||||
- st->d->a[1] * st->d->v[ci][1] \ | |||||
- st->d->a[2] * st->d->v[ci][2] \ | |||||
- st->d->a[3] * st->d->v[ci][3] \ | |||||
- st->d->a[4] * st->d->v[ci][4]; \ | |||||
audio_data[i * st->channels + c] = \ | |||||
st->d->b[0] * st->d->v[ci][0] \ | |||||
+ st->d->b[1] * st->d->v[ci][1] \ | |||||
+ st->d->b[2] * st->d->v[ci][2] \ | |||||
+ st->d->b[3] * st->d->v[ci][3] \ | |||||
+ st->d->b[4] * st->d->v[ci][4]; \ | |||||
st->d->v[ci][4] = st->d->v[ci][3]; \ | |||||
st->d->v[ci][3] = st->d->v[ci][2]; \ | |||||
st->d->v[ci][2] = st->d->v[ci][1]; \ | |||||
st->d->v[ci][1] = st->d->v[ci][0]; \ | |||||
} \ | |||||
st->d->v[ci][4] = fabs(st->d->v[ci][4]) < DBL_MIN ? 0.0 : st->d->v[ci][4]; \ | |||||
st->d->v[ci][3] = fabs(st->d->v[ci][3]) < DBL_MIN ? 0.0 : st->d->v[ci][3]; \ | |||||
st->d->v[ci][2] = fabs(st->d->v[ci][2]) < DBL_MIN ? 0.0 : st->d->v[ci][2]; \ | |||||
st->d->v[ci][1] = fabs(st->d->v[ci][1]) < DBL_MIN ? 0.0 : st->d->v[ci][1]; \ | |||||
} \ | |||||
} | |||||
EBUR128_FILTER(short, SHRT_MIN, SHRT_MAX) | |||||
EBUR128_FILTER(int, INT_MIN, INT_MAX) | |||||
EBUR128_FILTER(float, -1.0f, 1.0f) EBUR128_FILTER(double, -1.0, 1.0) | |||||
static double ebur128_energy_to_loudness(double energy) | |||||
{ | |||||
return 10 * (log(energy) / log(10.0)) - 0.691; | |||||
} | |||||
static size_t find_histogram_index(double energy) | |||||
{ | |||||
size_t index_min = 0; | |||||
size_t index_max = 1000; | |||||
size_t index_mid; | |||||
do { | |||||
index_mid = (index_min + index_max) / 2; | |||||
if (energy >= histogram_energy_boundaries[index_mid]) { | |||||
index_min = index_mid; | |||||
} else { | |||||
index_max = index_mid; | |||||
} | |||||
} while (index_max - index_min != 1); | |||||
return index_min; | |||||
} | |||||
static void ebur128_calc_gating_block(FFEBUR128State * st, | |||||
size_t frames_per_block, | |||||
double *optional_output) | |||||
{ | |||||
size_t i, c; | |||||
double sum = 0.0; | |||||
double channel_sum; | |||||
for (c = 0; c < st->channels; ++c) { | |||||
if (st->d->channel_map[c] == FF_EBUR128_UNUSED) | |||||
continue; | |||||
channel_sum = 0.0; | |||||
if (st->d->audio_data_index < frames_per_block * st->channels) { | |||||
for (i = 0; i < st->d->audio_data_index / st->channels; ++i) { | |||||
channel_sum += st->d->audio_data[i * st->channels + c] * | |||||
st->d->audio_data[i * st->channels + c]; | |||||
} | |||||
for (i = st->d->audio_data_frames - | |||||
(frames_per_block - | |||||
st->d->audio_data_index / st->channels); | |||||
i < st->d->audio_data_frames; ++i) { | |||||
channel_sum += st->d->audio_data[i * st->channels + c] * | |||||
st->d->audio_data[i * st->channels + c]; | |||||
} | |||||
} else { | |||||
for (i = | |||||
st->d->audio_data_index / st->channels - frames_per_block; | |||||
i < st->d->audio_data_index / st->channels; ++i) { | |||||
channel_sum += | |||||
st->d->audio_data[i * st->channels + | |||||
c] * st->d->audio_data[i * | |||||
st->channels + | |||||
c]; | |||||
} | |||||
} | |||||
if (st->d->channel_map[c] == FF_EBUR128_Mp110 || | |||||
st->d->channel_map[c] == FF_EBUR128_Mm110 || | |||||
st->d->channel_map[c] == FF_EBUR128_Mp060 || | |||||
st->d->channel_map[c] == FF_EBUR128_Mm060 || | |||||
st->d->channel_map[c] == FF_EBUR128_Mp090 || | |||||
st->d->channel_map[c] == FF_EBUR128_Mm090) { | |||||
channel_sum *= 1.41; | |||||
} else if (st->d->channel_map[c] == FF_EBUR128_DUAL_MONO) { | |||||
channel_sum *= 2.0; | |||||
} | |||||
sum += channel_sum; | |||||
} | |||||
sum /= (double) frames_per_block; | |||||
if (optional_output) { | |||||
*optional_output = sum; | |||||
} else if (sum >= histogram_energy_boundaries[0]) { | |||||
++st->d->block_energy_histogram[find_histogram_index(sum)]; | |||||
} | |||||
} | |||||
int ff_ebur128_set_channel(FFEBUR128State * st, | |||||
unsigned int channel_number, int value) | |||||
{ | |||||
if (channel_number >= st->channels) { | |||||
return 1; | |||||
} | |||||
if (value == FF_EBUR128_DUAL_MONO && | |||||
(st->channels != 1 || channel_number != 0)) { | |||||
return 1; | |||||
} | |||||
st->d->channel_map[channel_number] = value; | |||||
return 0; | |||||
} | |||||
static int ebur128_energy_shortterm(FFEBUR128State * st, double *out); | |||||
#define FF_EBUR128_ADD_FRAMES_PLANAR(type) \ | |||||
void ff_ebur128_add_frames_planar_##type(FFEBUR128State* st, const type** srcs, \ | |||||
size_t frames, int stride) { \ | |||||
size_t src_index = 0; \ | |||||
while (frames > 0) { \ | |||||
if (frames >= st->d->needed_frames) { \ | |||||
ebur128_filter_##type(st, srcs, src_index, st->d->needed_frames, stride); \ | |||||
src_index += st->d->needed_frames * stride; \ | |||||
frames -= st->d->needed_frames; \ | |||||
st->d->audio_data_index += st->d->needed_frames * st->channels; \ | |||||
/* calculate the new gating block */ \ | |||||
if ((st->mode & FF_EBUR128_MODE_I) == FF_EBUR128_MODE_I) { \ | |||||
ebur128_calc_gating_block(st, st->d->samples_in_100ms * 4, NULL); \ | |||||
} \ | |||||
if ((st->mode & FF_EBUR128_MODE_LRA) == FF_EBUR128_MODE_LRA) { \ | |||||
st->d->short_term_frame_counter += st->d->needed_frames; \ | |||||
if (st->d->short_term_frame_counter == st->d->samples_in_100ms * 30) { \ | |||||
double st_energy; \ | |||||
ebur128_energy_shortterm(st, &st_energy); \ | |||||
if (st_energy >= histogram_energy_boundaries[0]) { \ | |||||
++st->d->short_term_block_energy_histogram[ \ | |||||
find_histogram_index(st_energy)]; \ | |||||
} \ | |||||
st->d->short_term_frame_counter = st->d->samples_in_100ms * 20; \ | |||||
} \ | |||||
} \ | |||||
/* 100ms are needed for all blocks besides the first one */ \ | |||||
st->d->needed_frames = st->d->samples_in_100ms; \ | |||||
/* reset audio_data_index when buffer full */ \ | |||||
if (st->d->audio_data_index == st->d->audio_data_frames * st->channels) { \ | |||||
st->d->audio_data_index = 0; \ | |||||
} \ | |||||
} else { \ | |||||
ebur128_filter_##type(st, srcs, src_index, frames, stride); \ | |||||
st->d->audio_data_index += frames * st->channels; \ | |||||
if ((st->mode & FF_EBUR128_MODE_LRA) == FF_EBUR128_MODE_LRA) { \ | |||||
st->d->short_term_frame_counter += frames; \ | |||||
} \ | |||||
st->d->needed_frames -= frames; \ | |||||
frames = 0; \ | |||||
} \ | |||||
} \ | |||||
} | |||||
FF_EBUR128_ADD_FRAMES_PLANAR(short) | |||||
FF_EBUR128_ADD_FRAMES_PLANAR(int) | |||||
FF_EBUR128_ADD_FRAMES_PLANAR(float) | |||||
FF_EBUR128_ADD_FRAMES_PLANAR(double) | |||||
#define FF_EBUR128_ADD_FRAMES(type) \ | |||||
void ff_ebur128_add_frames_##type(FFEBUR128State* st, const type* src, \ | |||||
size_t frames) { \ | |||||
int i; \ | |||||
const type **buf = (const type**)st->d->data_ptrs; \ | |||||
for (i = 0; i < st->channels; i++) \ | |||||
buf[i] = src + i; \ | |||||
ff_ebur128_add_frames_planar_##type(st, buf, frames, st->channels); \ | |||||
} | |||||
FF_EBUR128_ADD_FRAMES(short) | |||||
FF_EBUR128_ADD_FRAMES(int) | |||||
FF_EBUR128_ADD_FRAMES(float) | |||||
FF_EBUR128_ADD_FRAMES(double) | |||||
static int ebur128_calc_relative_threshold(FFEBUR128State * st, | |||||
size_t * above_thresh_counter, | |||||
double *relative_threshold) | |||||
{ | |||||
size_t i; | |||||
*relative_threshold = 0.0; | |||||
*above_thresh_counter = 0; | |||||
for (i = 0; i < 1000; ++i) { | |||||
*relative_threshold += st->d->block_energy_histogram[i] * | |||||
histogram_energies[i]; | |||||
*above_thresh_counter += st->d->block_energy_histogram[i]; | |||||
} | |||||
if (*above_thresh_counter != 0) { | |||||
*relative_threshold /= (double) *above_thresh_counter; | |||||
*relative_threshold *= RELATIVE_GATE_FACTOR; | |||||
} | |||||
return 0; | |||||
} | |||||
static int ebur128_gated_loudness(FFEBUR128State ** sts, size_t size, | |||||
double *out) | |||||
{ | |||||
double gated_loudness = 0.0; | |||||
double relative_threshold; | |||||
size_t above_thresh_counter; | |||||
size_t i, j, start_index; | |||||
for (i = 0; i < size; i++) { | |||||
if (sts[i] | |||||
&& (sts[i]->mode & FF_EBUR128_MODE_I) != FF_EBUR128_MODE_I) { | |||||
return AVERROR(EINVAL); | |||||
} | |||||
} | |||||
for (i = 0; i < size; i++) { | |||||
if (!sts[i]) | |||||
continue; | |||||
ebur128_calc_relative_threshold(sts[i], &above_thresh_counter, | |||||
&relative_threshold); | |||||
} | |||||
if (!above_thresh_counter) { | |||||
*out = -HUGE_VAL; | |||||
return 0; | |||||
} | |||||
above_thresh_counter = 0; | |||||
if (relative_threshold < histogram_energy_boundaries[0]) { | |||||
start_index = 0; | |||||
} else { | |||||
start_index = find_histogram_index(relative_threshold); | |||||
if (relative_threshold > histogram_energies[start_index]) { | |||||
++start_index; | |||||
} | |||||
} | |||||
for (i = 0; i < size; i++) { | |||||
if (!sts[i]) | |||||
continue; | |||||
for (j = start_index; j < 1000; ++j) { | |||||
gated_loudness += sts[i]->d->block_energy_histogram[j] * | |||||
histogram_energies[j]; | |||||
above_thresh_counter += sts[i]->d->block_energy_histogram[j]; | |||||
} | |||||
} | |||||
if (!above_thresh_counter) { | |||||
*out = -HUGE_VAL; | |||||
return 0; | |||||
} | |||||
gated_loudness /= (double) above_thresh_counter; | |||||
*out = ebur128_energy_to_loudness(gated_loudness); | |||||
return 0; | |||||
} | |||||
int ff_ebur128_relative_threshold(FFEBUR128State * st, double *out) | |||||
{ | |||||
double relative_threshold; | |||||
size_t above_thresh_counter; | |||||
if (st && (st->mode & FF_EBUR128_MODE_I) != FF_EBUR128_MODE_I) | |||||
return AVERROR(EINVAL); | |||||
ebur128_calc_relative_threshold(st, &above_thresh_counter, | |||||
&relative_threshold); | |||||
if (!above_thresh_counter) { | |||||
*out = -70.0; | |||||
return 0; | |||||
} | |||||
*out = ebur128_energy_to_loudness(relative_threshold); | |||||
return 0; | |||||
} | |||||
int ff_ebur128_loudness_global(FFEBUR128State * st, double *out) | |||||
{ | |||||
return ebur128_gated_loudness(&st, 1, out); | |||||
} | |||||
int ff_ebur128_loudness_global_multiple(FFEBUR128State ** sts, size_t size, | |||||
double *out) | |||||
{ | |||||
return ebur128_gated_loudness(sts, size, out); | |||||
} | |||||
static int ebur128_energy_in_interval(FFEBUR128State * st, | |||||
size_t interval_frames, double *out) | |||||
{ | |||||
if (interval_frames > st->d->audio_data_frames) { | |||||
return AVERROR(EINVAL); | |||||
} | |||||
ebur128_calc_gating_block(st, interval_frames, out); | |||||
return 0; | |||||
} | |||||
static int ebur128_energy_shortterm(FFEBUR128State * st, double *out) | |||||
{ | |||||
return ebur128_energy_in_interval(st, st->d->samples_in_100ms * 30, | |||||
out); | |||||
} | |||||
int ff_ebur128_loudness_momentary(FFEBUR128State * st, double *out) | |||||
{ | |||||
double energy; | |||||
int error = ebur128_energy_in_interval(st, st->d->samples_in_100ms * 4, | |||||
&energy); | |||||
if (error) { | |||||
return error; | |||||
} else if (energy <= 0.0) { | |||||
*out = -HUGE_VAL; | |||||
return 0; | |||||
} | |||||
*out = ebur128_energy_to_loudness(energy); | |||||
return 0; | |||||
} | |||||
int ff_ebur128_loudness_shortterm(FFEBUR128State * st, double *out) | |||||
{ | |||||
double energy; | |||||
int error = ebur128_energy_shortterm(st, &energy); | |||||
if (error) { | |||||
return error; | |||||
} else if (energy <= 0.0) { | |||||
*out = -HUGE_VAL; | |||||
return 0; | |||||
} | |||||
*out = ebur128_energy_to_loudness(energy); | |||||
return 0; | |||||
} | |||||
int ff_ebur128_loudness_window(FFEBUR128State * st, | |||||
unsigned long window, double *out) | |||||
{ | |||||
double energy; | |||||
size_t interval_frames = st->samplerate * window / 1000; | |||||
int error = ebur128_energy_in_interval(st, interval_frames, &energy); | |||||
if (error) { | |||||
return error; | |||||
} else if (energy <= 0.0) { | |||||
*out = -HUGE_VAL; | |||||
return 0; | |||||
} | |||||
*out = ebur128_energy_to_loudness(energy); | |||||
return 0; | |||||
} | |||||
/* EBU - TECH 3342 */ | |||||
int ff_ebur128_loudness_range_multiple(FFEBUR128State ** sts, size_t size, | |||||
double *out) | |||||
{ | |||||
size_t i, j; | |||||
size_t stl_size; | |||||
double stl_power, stl_integrated; | |||||
/* High and low percentile energy */ | |||||
double h_en, l_en; | |||||
unsigned long hist[1000] = { 0 }; | |||||
size_t percentile_low, percentile_high; | |||||
size_t index; | |||||
for (i = 0; i < size; ++i) { | |||||
if (sts[i]) { | |||||
if ((sts[i]->mode & FF_EBUR128_MODE_LRA) != | |||||
FF_EBUR128_MODE_LRA) { | |||||
return AVERROR(EINVAL); | |||||
} | |||||
} | |||||
} | |||||
stl_size = 0; | |||||
stl_power = 0.0; | |||||
for (i = 0; i < size; ++i) { | |||||
if (!sts[i]) | |||||
continue; | |||||
for (j = 0; j < 1000; ++j) { | |||||
hist[j] += sts[i]->d->short_term_block_energy_histogram[j]; | |||||
stl_size += sts[i]->d->short_term_block_energy_histogram[j]; | |||||
stl_power += sts[i]->d->short_term_block_energy_histogram[j] | |||||
* histogram_energies[j]; | |||||
} | |||||
} | |||||
if (!stl_size) { | |||||
*out = 0.0; | |||||
return 0; | |||||
} | |||||
stl_power /= stl_size; | |||||
stl_integrated = MINUS_20DB * stl_power; | |||||
if (stl_integrated < histogram_energy_boundaries[0]) { | |||||
index = 0; | |||||
} else { | |||||
index = find_histogram_index(stl_integrated); | |||||
if (stl_integrated > histogram_energies[index]) { | |||||
++index; | |||||
} | |||||
} | |||||
stl_size = 0; | |||||
for (j = index; j < 1000; ++j) { | |||||
stl_size += hist[j]; | |||||
} | |||||
if (!stl_size) { | |||||
*out = 0.0; | |||||
return 0; | |||||
} | |||||
percentile_low = (size_t) ((stl_size - 1) * 0.1 + 0.5); | |||||
percentile_high = (size_t) ((stl_size - 1) * 0.95 + 0.5); | |||||
stl_size = 0; | |||||
j = index; | |||||
while (stl_size <= percentile_low) { | |||||
stl_size += hist[j++]; | |||||
} | |||||
l_en = histogram_energies[j - 1]; | |||||
while (stl_size <= percentile_high) { | |||||
stl_size += hist[j++]; | |||||
} | |||||
h_en = histogram_energies[j - 1]; | |||||
*out = | |||||
ebur128_energy_to_loudness(h_en) - | |||||
ebur128_energy_to_loudness(l_en); | |||||
return 0; | |||||
} | |||||
int ff_ebur128_loudness_range(FFEBUR128State * st, double *out) | |||||
{ | |||||
return ff_ebur128_loudness_range_multiple(&st, 1, out); | |||||
} | |||||
int ff_ebur128_sample_peak(FFEBUR128State * st, | |||||
unsigned int channel_number, double *out) | |||||
{ | |||||
if ((st->mode & FF_EBUR128_MODE_SAMPLE_PEAK) != | |||||
FF_EBUR128_MODE_SAMPLE_PEAK) { | |||||
return AVERROR(EINVAL); | |||||
} else if (channel_number >= st->channels) { | |||||
return AVERROR(EINVAL); | |||||
} | |||||
*out = st->d->sample_peak[channel_number]; | |||||
return 0; | |||||
} |
@@ -0,0 +1,296 @@ | |||||
/* | |||||
* Copyright (c) 2011 Jan KokemĂĽller | |||||
* | |||||
* This file is part of FFmpeg. | |||||
* | |||||
* FFmpeg is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 2.1 of the License, or (at your option) any later version. | |||||
* | |||||
* FFmpeg is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public | |||||
* License along with FFmpeg; if not, write to the Free Software | |||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
* | |||||
* This file is based on libebur128 which is available at | |||||
* https://github.com/jiixyj/libebur128/ | |||||
* | |||||
*/ | |||||
#ifndef AVFILTER_EBUR128_H | |||||
#define AVFILTER_EBUR128_H | |||||
/** \file ebur128.h | |||||
* \brief libebur128 - a library for loudness measurement according to | |||||
* the EBU R128 standard. | |||||
*/ | |||||
#include <stddef.h> /* for size_t */ | |||||
/** \enum channel | |||||
* Use these values when setting the channel map with ebur128_set_channel(). | |||||
* See definitions in ITU R-REC-BS 1770-4 | |||||
*/ | |||||
enum channel { | |||||
FF_EBUR128_UNUSED = 0, /**< unused channel (for example LFE channel) */ | |||||
FF_EBUR128_LEFT, | |||||
FF_EBUR128_Mp030 = 1, /**< itu M+030 */ | |||||
FF_EBUR128_RIGHT, | |||||
FF_EBUR128_Mm030 = 2, /**< itu M-030 */ | |||||
FF_EBUR128_CENTER, | |||||
FF_EBUR128_Mp000 = 3, /**< itu M+000 */ | |||||
FF_EBUR128_LEFT_SURROUND, | |||||
FF_EBUR128_Mp110 = 4, /**< itu M+110 */ | |||||
FF_EBUR128_RIGHT_SURROUND, | |||||
FF_EBUR128_Mm110 = 5, /**< itu M-110 */ | |||||
FF_EBUR128_DUAL_MONO, /**< a channel that is counted twice */ | |||||
FF_EBUR128_MpSC, /**< itu M+SC */ | |||||
FF_EBUR128_MmSC, /**< itu M-SC */ | |||||
FF_EBUR128_Mp060, /**< itu M+060 */ | |||||
FF_EBUR128_Mm060, /**< itu M-060 */ | |||||
FF_EBUR128_Mp090, /**< itu M+090 */ | |||||
FF_EBUR128_Mm090, /**< itu M-090 */ | |||||
FF_EBUR128_Mp135, /**< itu M+135 */ | |||||
FF_EBUR128_Mm135, /**< itu M-135 */ | |||||
FF_EBUR128_Mp180, /**< itu M+180 */ | |||||
FF_EBUR128_Up000, /**< itu U+000 */ | |||||
FF_EBUR128_Up030, /**< itu U+030 */ | |||||
FF_EBUR128_Um030, /**< itu U-030 */ | |||||
FF_EBUR128_Up045, /**< itu U+045 */ | |||||
FF_EBUR128_Um045, /**< itu U-030 */ | |||||
FF_EBUR128_Up090, /**< itu U+090 */ | |||||
FF_EBUR128_Um090, /**< itu U-090 */ | |||||
FF_EBUR128_Up110, /**< itu U+110 */ | |||||
FF_EBUR128_Um110, /**< itu U-110 */ | |||||
FF_EBUR128_Up135, /**< itu U+135 */ | |||||
FF_EBUR128_Um135, /**< itu U-135 */ | |||||
FF_EBUR128_Up180, /**< itu U+180 */ | |||||
FF_EBUR128_Tp000, /**< itu T+000 */ | |||||
FF_EBUR128_Bp000, /**< itu B+000 */ | |||||
FF_EBUR128_Bp045, /**< itu B+045 */ | |||||
FF_EBUR128_Bm045 /**< itu B-045 */ | |||||
}; | |||||
/** \enum mode | |||||
* Use these values in ebur128_init (or'ed). Try to use the lowest possible | |||||
* modes that suit your needs, as performance will be better. | |||||
*/ | |||||
enum mode { | |||||
/** can call ebur128_loudness_momentary */ | |||||
FF_EBUR128_MODE_M = (1 << 0), | |||||
/** can call ebur128_loudness_shortterm */ | |||||
FF_EBUR128_MODE_S = (1 << 1) | FF_EBUR128_MODE_M, | |||||
/** can call ebur128_loudness_global_* and ebur128_relative_threshold */ | |||||
FF_EBUR128_MODE_I = (1 << 2) | FF_EBUR128_MODE_M, | |||||
/** can call ebur128_loudness_range */ | |||||
FF_EBUR128_MODE_LRA = (1 << 3) | FF_EBUR128_MODE_S, | |||||
/** can call ebur128_sample_peak */ | |||||
FF_EBUR128_MODE_SAMPLE_PEAK = (1 << 4) | FF_EBUR128_MODE_M, | |||||
}; | |||||
/** forward declaration of FFEBUR128StateInternal */ | |||||
struct FFEBUR128StateInternal; | |||||
/** \brief Contains information about the state of a loudness measurement. | |||||
* | |||||
* You should not need to modify this struct directly. | |||||
*/ | |||||
typedef struct { | |||||
int mode; /**< The current mode. */ | |||||
unsigned int channels; /**< The number of channels. */ | |||||
unsigned long samplerate; /**< The sample rate. */ | |||||
struct FFEBUR128StateInternal *d; /**< Internal state. */ | |||||
} FFEBUR128State; | |||||
/** \brief Initialize library state. | |||||
* | |||||
* @param channels the number of channels. | |||||
* @param samplerate the sample rate. | |||||
* @param window set the maximum window size in ms, set to 0 for auto. | |||||
* @param mode see the mode enum for possible values. | |||||
* @return an initialized library state. | |||||
*/ | |||||
FFEBUR128State *ff_ebur128_init(unsigned int channels, | |||||
unsigned long samplerate, | |||||
unsigned long window, int mode); | |||||
/** \brief Destroy library state. | |||||
* | |||||
* @param st pointer to a library state. | |||||
*/ | |||||
void ff_ebur128_destroy(FFEBUR128State ** st); | |||||
/** \brief Set channel type. | |||||
* | |||||
* The default is: | |||||
* - 0 -> FF_EBUR128_LEFT | |||||
* - 1 -> FF_EBUR128_RIGHT | |||||
* - 2 -> FF_EBUR128_CENTER | |||||
* - 3 -> FF_EBUR128_UNUSED | |||||
* - 4 -> FF_EBUR128_LEFT_SURROUND | |||||
* - 5 -> FF_EBUR128_RIGHT_SURROUND | |||||
* | |||||
* @param st library state. | |||||
* @param channel_number zero based channel index. | |||||
* @param value channel type from the "channel" enum. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if invalid channel index. | |||||
*/ | |||||
int ff_ebur128_set_channel(FFEBUR128State * st, | |||||
unsigned int channel_number, int value); | |||||
/** \brief Add frames to be processed. | |||||
* | |||||
* @param st library state. | |||||
* @param src array of source frames. Channels must be interleaved. | |||||
* @param frames number of frames. Not number of samples! | |||||
*/ | |||||
void ff_ebur128_add_frames_short(FFEBUR128State * st, | |||||
const short *src, size_t frames); | |||||
/** \brief See \ref ebur128_add_frames_short */ | |||||
void ff_ebur128_add_frames_int(FFEBUR128State * st, | |||||
const int *src, size_t frames); | |||||
/** \brief See \ref ebur128_add_frames_short */ | |||||
void ff_ebur128_add_frames_float(FFEBUR128State * st, | |||||
const float *src, size_t frames); | |||||
/** \brief See \ref ebur128_add_frames_short */ | |||||
void ff_ebur128_add_frames_double(FFEBUR128State * st, | |||||
const double *src, size_t frames); | |||||
/** \brief Add frames to be processed. | |||||
* | |||||
* @param st library state. | |||||
* @param srcs array of source frame channel data pointers | |||||
* @param frames number of frames. Not number of samples! | |||||
* @param stride number of samples to skip to for the next sample of the same channel | |||||
*/ | |||||
void ff_ebur128_add_frames_planar_short(FFEBUR128State * st, | |||||
const short **srcs, | |||||
size_t frames, int stride); | |||||
/** \brief See \ref ebur128_add_frames_planar_short */ | |||||
void ff_ebur128_add_frames_planar_int(FFEBUR128State * st, | |||||
const int **srcs, | |||||
size_t frames, int stride); | |||||
/** \brief See \ref ebur128_add_frames_planar_short */ | |||||
void ff_ebur128_add_frames_planar_float(FFEBUR128State * st, | |||||
const float **srcs, | |||||
size_t frames, int stride); | |||||
/** \brief See \ref ebur128_add_frames_planar_short */ | |||||
void ff_ebur128_add_frames_planar_double(FFEBUR128State * st, | |||||
const double **srcs, | |||||
size_t frames, int stride); | |||||
/** \brief Get global integrated loudness in LUFS. | |||||
* | |||||
* @param st library state. | |||||
* @param out integrated loudness in LUFS. -HUGE_VAL if result is negative | |||||
* infinity. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_I" has not been set. | |||||
*/ | |||||
int ff_ebur128_loudness_global(FFEBUR128State * st, double *out); | |||||
/** \brief Get global integrated loudness in LUFS across multiple instances. | |||||
* | |||||
* @param sts array of library states. | |||||
* @param size length of sts | |||||
* @param out integrated loudness in LUFS. -HUGE_VAL if result is negative | |||||
* infinity. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_I" has not been set. | |||||
*/ | |||||
int ff_ebur128_loudness_global_multiple(FFEBUR128State ** sts, | |||||
size_t size, double *out); | |||||
/** \brief Get momentary loudness (last 400ms) in LUFS. | |||||
* | |||||
* @param st library state. | |||||
* @param out momentary loudness in LUFS. -HUGE_VAL if result is negative | |||||
* infinity. | |||||
* @return | |||||
* - 0 on success. | |||||
*/ | |||||
int ff_ebur128_loudness_momentary(FFEBUR128State * st, double *out); | |||||
/** \brief Get short-term loudness (last 3s) in LUFS. | |||||
* | |||||
* @param st library state. | |||||
* @param out short-term loudness in LUFS. -HUGE_VAL if result is negative | |||||
* infinity. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_S" has not been set. | |||||
*/ | |||||
int ff_ebur128_loudness_shortterm(FFEBUR128State * st, double *out); | |||||
/** \brief Get loudness of the specified window in LUFS. | |||||
* | |||||
* window must not be larger than the current window set in st. | |||||
* | |||||
* @param st library state. | |||||
* @param window window in ms to calculate loudness. | |||||
* @param out loudness in LUFS. -HUGE_VAL if result is negative infinity. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if window larger than current window in st. | |||||
*/ | |||||
int ff_ebur128_loudness_window(FFEBUR128State * st, | |||||
unsigned long window, double *out); | |||||
/** \brief Get loudness range (LRA) of programme in LU. | |||||
* | |||||
* Calculates loudness range according to EBU 3342. | |||||
* | |||||
* @param st library state. | |||||
* @param out loudness range (LRA) in LU. Will not be changed in case of | |||||
* error. AVERROR(EINVAL) will be returned in this case. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_LRA" has not been set. | |||||
*/ | |||||
int ff_ebur128_loudness_range(FFEBUR128State * st, double *out); | |||||
/** \brief Get loudness range (LRA) in LU across multiple instances. | |||||
* | |||||
* Calculates loudness range according to EBU 3342. | |||||
* | |||||
* @param sts array of library states. | |||||
* @param size length of sts | |||||
* @param out loudness range (LRA) in LU. Will not be changed in case of | |||||
* error. AVERROR(EINVAL) will be returned in this case. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_LRA" has not been set. | |||||
*/ | |||||
int ff_ebur128_loudness_range_multiple(FFEBUR128State ** sts, | |||||
size_t size, double *out); | |||||
/** \brief Get maximum sample peak of selected channel in float format. | |||||
* | |||||
* @param st library state | |||||
* @param channel_number channel to analyse | |||||
* @param out maximum sample peak in float format (1.0 is 0 dBFS) | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_SAMPLE_PEAK" has not been set. | |||||
* - AVERROR(EINVAL) if invalid channel index. | |||||
*/ | |||||
int ff_ebur128_sample_peak(FFEBUR128State * st, | |||||
unsigned int channel_number, double *out); | |||||
/** \brief Get relative threshold in LUFS. | |||||
* | |||||
* @param st library state | |||||
* @param out relative threshold in LUFS. | |||||
* @return | |||||
* - 0 on success. | |||||
* - AVERROR(EINVAL) if mode "FF_EBUR128_MODE_I" has not been set. | |||||
*/ | |||||
int ff_ebur128_relative_threshold(FFEBUR128State * st, double *out); | |||||
#endif /* AVFILTER_EBUR128_H */ |
@@ -30,7 +30,7 @@ | |||||
#include "libavutil/version.h" | #include "libavutil/version.h" | ||||
#define LIBAVFILTER_VERSION_MAJOR 6 | #define LIBAVFILTER_VERSION_MAJOR 6 | ||||
#define LIBAVFILTER_VERSION_MINOR 66 | |||||
#define LIBAVFILTER_VERSION_MINOR 67 | |||||
#define LIBAVFILTER_VERSION_MICRO 100 | #define LIBAVFILTER_VERSION_MICRO 100 | ||||
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ | #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ | ||||