diff options
author | Alessandro Ghedini <alessandro@ghedini.me> | 2014-04-04 11:50:44 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2014-04-04 17:40:19 +0200 |
commit | 8542f9c4f17125d483c40c0c5723842f1c982f81 (patch) | |
tree | 3981a5b0ca00cd6e3d3f47725dc7e3ff1050c9bd /libavformat | |
parent | 25b6837f7cacd691b19cbc12b9dad1ce84a318a1 (diff) | |
download | ffmpeg-8542f9c4f17125d483c40c0c5723842f1c982f81.tar.gz |
replaygain: correctly parse peak values
According to the ReplayGain spec, the peak amplitude may overflow and may result
in peak amplitude values greater than 1.0 with psychoacoustically coded audio,
such as MP3. Fully compliant decoders must allow peak overflows.
Additionally, having peak values in the 0<->UINT32_MAX scale makes it more
difficult for applications to actually use the peak values (e.g. when
implementing clipping prevention) since values have to be rescaled down.
This patch corrects the peak parsing by removing the rescaling of the decoded
values between 0 and UINT32_MAX and the 1.0 upper limit.
Signed-off-by: Anton Khirnov <anton@khirnov.net>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/replaygain.c | 54 |
1 files changed, 11 insertions, 43 deletions
diff --git a/libavformat/replaygain.c b/libavformat/replaygain.c index 6983601491..c123a63985 100644 --- a/libavformat/replaygain.c +++ b/libavformat/replaygain.c @@ -35,7 +35,7 @@ #include "avformat.h" #include "replaygain.h" -static int32_t parse_gain(const char *gain) +static int32_t parse_value(const char *value, int32_t min) { char *fraction; int scale = 10000; @@ -43,15 +43,15 @@ static int32_t parse_gain(const char *gain) int sign = 1; int db; - if (!gain) - return INT32_MIN; + if (!value) + return min; - gain += strspn(gain, " \t"); + value += strspn(value, " \t"); - if (*gain == '-') + if (*value == '-') sign = -1; - db = strtol(gain, &fraction, 0); + db = strtol(value, &fraction, 0); if (*fraction++ == '.') { while (av_isdigit(*fraction) && scale) { mb += scale * (*fraction - '0'); @@ -61,43 +61,11 @@ static int32_t parse_gain(const char *gain) } if (abs(db) > (INT32_MAX - mb) / 100000) - return INT32_MIN; + return min; return db * 100000 + sign * mb; } -static uint32_t parse_peak(const uint8_t *peak) -{ - int64_t val = 0; - int64_t scale = 1; - - if (!peak) - return 0; - - peak += strspn(peak, " \t"); - - if (peak[0] == '1' && peak[1] == '.') - return UINT32_MAX; - else if (!(peak[0] == '0' && peak[1] == '.')) - return 0; - - peak += 2; - - while (av_isdigit(*peak)) { - int digit = *peak - '0'; - - if (scale > INT64_MAX / 10) - break; - - val = 10 * val + digit; - scale *= 10; - - peak++; - } - - return av_rescale(val, UINT32_MAX, scale); -} - static int replaygain_export(AVStream *st, const uint8_t *track_gain, const uint8_t *track_peak, const uint8_t *album_gain, const uint8_t *album_peak) @@ -108,10 +76,10 @@ static int replaygain_export(AVStream *st, int32_t tg, ag; uint32_t tp, ap; - tg = parse_gain(track_gain); - ag = parse_gain(album_gain); - tp = parse_peak(track_peak); - ap = parse_peak(album_peak); + tg = parse_value(track_gain, INT32_MIN); + ag = parse_value(album_gain, INT32_MIN); + tp = parse_value(track_peak, 0); + ap = parse_value(album_peak, 0); if (tg == INT32_MIN && ag == INT32_MIN) return 0; |