mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
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>
This commit is contained in:
parent
25b6837f7c
commit
8542f9c4f1
@ -13,6 +13,10 @@ libavutil: 2013-12-xx
|
|||||||
|
|
||||||
API changes, most recent first:
|
API changes, most recent first:
|
||||||
|
|
||||||
|
2014-04-xx - xxxxxxx - lavu 53.10.0 - replaygain.h
|
||||||
|
Full scale for peak values is now 100000 (instead of UINT32_MAX) and values
|
||||||
|
may overflow.
|
||||||
|
|
||||||
2014-04-xx - xxxxxxx - lavu 53.09.0 - log.h
|
2014-04-xx - xxxxxxx - lavu 53.09.0 - log.h
|
||||||
Add AV_LOG(c) macro to have 256 color debug messages.
|
Add AV_LOG(c) macro to have 256 color debug messages.
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
#include "replaygain.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;
|
char *fraction;
|
||||||
int scale = 10000;
|
int scale = 10000;
|
||||||
@ -43,15 +43,15 @@ static int32_t parse_gain(const char *gain)
|
|||||||
int sign = 1;
|
int sign = 1;
|
||||||
int db;
|
int db;
|
||||||
|
|
||||||
if (!gain)
|
if (!value)
|
||||||
return INT32_MIN;
|
return min;
|
||||||
|
|
||||||
gain += strspn(gain, " \t");
|
value += strspn(value, " \t");
|
||||||
|
|
||||||
if (*gain == '-')
|
if (*value == '-')
|
||||||
sign = -1;
|
sign = -1;
|
||||||
|
|
||||||
db = strtol(gain, &fraction, 0);
|
db = strtol(value, &fraction, 0);
|
||||||
if (*fraction++ == '.') {
|
if (*fraction++ == '.') {
|
||||||
while (av_isdigit(*fraction) && scale) {
|
while (av_isdigit(*fraction) && scale) {
|
||||||
mb += scale * (*fraction - '0');
|
mb += scale * (*fraction - '0');
|
||||||
@ -61,43 +61,11 @@ static int32_t parse_gain(const char *gain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (abs(db) > (INT32_MAX - mb) / 100000)
|
if (abs(db) > (INT32_MAX - mb) / 100000)
|
||||||
return INT32_MIN;
|
return min;
|
||||||
|
|
||||||
return db * 100000 + sign * mb;
|
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,
|
static int replaygain_export(AVStream *st,
|
||||||
const uint8_t *track_gain, const uint8_t *track_peak,
|
const uint8_t *track_gain, const uint8_t *track_peak,
|
||||||
const uint8_t *album_gain, const uint8_t *album_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;
|
int32_t tg, ag;
|
||||||
uint32_t tp, ap;
|
uint32_t tp, ap;
|
||||||
|
|
||||||
tg = parse_gain(track_gain);
|
tg = parse_value(track_gain, INT32_MIN);
|
||||||
ag = parse_gain(album_gain);
|
ag = parse_value(album_gain, INT32_MIN);
|
||||||
tp = parse_peak(track_peak);
|
tp = parse_value(track_peak, 0);
|
||||||
ap = parse_peak(album_peak);
|
ap = parse_value(album_peak, 0);
|
||||||
|
|
||||||
if (tg == INT32_MIN && ag == INT32_MIN)
|
if (tg == INT32_MIN && ag == INT32_MIN)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -34,8 +34,8 @@ typedef struct AVReplayGain {
|
|||||||
*/
|
*/
|
||||||
int32_t track_gain;
|
int32_t track_gain;
|
||||||
/**
|
/**
|
||||||
* Peak track amplitude, with UINT32_MAX representing full scale. 0 when
|
* Peak track amplitude, with 100000 representing full scale (but values
|
||||||
* unknown.
|
* may overflow). 0 when unknown.
|
||||||
*/
|
*/
|
||||||
uint32_t track_peak;
|
uint32_t track_peak;
|
||||||
/**
|
/**
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#define LIBAVUTIL_VERSION_MAJOR 53
|
#define LIBAVUTIL_VERSION_MAJOR 53
|
||||||
#define LIBAVUTIL_VERSION_MINOR 9
|
#define LIBAVUTIL_VERSION_MINOR 10
|
||||||
#define LIBAVUTIL_VERSION_MICRO 0
|
#define LIBAVUTIL_VERSION_MICRO 0
|
||||||
|
|
||||||
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
|
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
|
||||||
|
Loading…
Reference in New Issue
Block a user