[FFmpeg-devel] [PATCH 2/3] lavfi/ebur128: add metadata injection. - volnorm.patch (0/1)
Jan Ehrhardt
phpdev at ehrhardt.nl
Wed May 1 22:10:54 CEST 2013
Hi,
I am picking up this 'old' discussion, because I saw none of the
one-pass normalization proposals had made its way to FFmpeg yet. Unless
I am very mistaken all current methods are two pass: first analyze the
volume level and then normalize the sound level. Correct me if I am
wrong.
Nicolas George in gmane.comp.video.ffmpeg.devel (Sat, 16 Mar 2013
12:36:40 +0100):
>Le quintidi 25 ventôse, an CCXXI, Jan Ehrhardt a écrit :
>> Actually it is useful for volume normalization, in those cases where the
>> overall sound level is either too low or too high. I have used Clément's
>> first patch set for over 2 weeks now on about 200 videofiles with an
>> average duration of 1 hour. It worked exactly as what we expected:
>> lowering the sound level of a few recordings and increasing the volume
>> of most recordings.
>
>It will work if the volume of the whole movie is approximately constant, but
>not at all if you have, for example, a very loud opening and then a quieter
>program.
http://permalink.gmane.org/gmane.comp.video.ffmpeg.devel/159978 was
Clément's first attempt. It is working quite well for us and replaced
the (one pass) -af volnorm filter in MEncoder with only a few flaws.
>Of course, no normalization system can deal with quick changes of volume,
>but with this example, it will take the integrated loudness more than one
>minute to digest the 25 seconds of loud beginning. That is too much.
We experienced this flaw only with a test video and (as far as I know)
with none of the 750 one-hour videos our users transcoded. But I did not
look at all of them...
In the test video the first three normalization frames had a loudness
(I) of -70:
t: 0.0999792 M:-120.7 S:-120.7 I: -70.0 LUFS LRA: 0.0 LU
t: 0.199979 M:-120.7 S:-120.7 I: -70.0 LUFS LRA: 0.0 LU
t: 0.299979 M:-120.7 S:-120.7 I: -70.0 LUFS LRA: 0.0 LU
t: 0.399979 M: -20.7 S:-120.7 I: -20.7 LUFS LRA: 0.0 LU
Our FFmpeg tried to adjust the volume three times with +47dB (70-23),
apparently enough to lead to all kinds of buffer overflows. The result:
a one hour video with a measured I of 10.0 (the maximum).
So I went looking for ways to maximize the adjustment. My first working
example looked like this:
loudness = av_strtod(e->value, NULL);
new_volume = fmax(-20,fmin(20,(-23 - loudness)));
set_fixed_volume(vol, pow(10, new_volume / 20));
The idea: maximize the adjustment within the range -20 up to +20
(measured from the -23 target). This solved the buffer overflow
problems, but had the issue Nicolas George predicted. After the three
initial frames the volume went up to -2 and it took about 30 seconds to
return to -17. An unwanted sound spike at the beginning of the video.
The question arose: how to minimize the adjustments at the beginning of
a video? I went back to f_ebur128.c and inserted another variable to the
metadata: the pts. I could use the pts in af_volume.c to maximize the
change in loudness during the initial seconds. My arbitrary choice:
allow -1/+1 after the first second, -2/+2 after the second second,
-20/+20 after 20 seconds or any longer duration. Of course, it is
possible to lengthen the initial duration to, say, a minute and lower
the maximum adjustment to -10/+10. But the idea is clear. Essential part
of the patch:
if (vol->metadata) {
double loudness, new_volume, pts, timestamp, mx;
AVDictionaryEntry *t, *e;
t = av_dict_get(buf->metadata, "lavfi.r128.pts", NULL, 0);
mx = 20;
if (t) {
pts = av_strtod(t->value, NULL);
timestamp = pts / 48000; /* assume 48kHz */
mx = fmin(mx, timestamp);
}
e = av_dict_get(buf->metadata, vol->metadata, NULL, 0);
if (e) {
loudness = av_strtod(e->value, NULL);
new_volume = fmax(-mx,fmin(mx,(-23 - loudness)));
set_fixed_volume(vol, pow(10, new_volume / 20));
}
}
The mx variable defines the min/max adjustment. By setting an absolute
maximum of 20 and by dividing the pts by 48k, I got the described setup
of -1/+1 per second.
Complete patch attached (if my nntp client handles it correctly).
Applied to yesterdays FFmpeg.
Jan
PS. I also made some changes to the av_log messages: hide them normally,
but show them with -loglevel verbose.
More information about the ffmpeg-devel
mailing list