inputPlugins/mp3_plugin: parse LAME tags for ReplayGain info
Parse ReplayGain info in LAME tags and use it if no ID3v2 ReplayGain tags are found. This is currently a bit unsafe, as apparently some LAME tags have bogus ReplayGain values. But I'm finding a lot of MP3s with valid LAME tags that fail the LAME tag CRC check. So until I figure out why that's happening, it's an unreliable method for checking if the LAME tag is valid. A big thanks to tmz for writing the original patch. git-svn-id: https://svn.musicpd.org/mpd/trunk@6798 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
5e1deab05f
commit
fe4b16ed96
@ -41,17 +41,17 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#define FRAMES_CUSHION 2000
|
#define FRAMES_CUSHION 2000
|
||||||
|
|
||||||
#define READ_BUFFER_SIZE 40960
|
#define READ_BUFFER_SIZE 40960
|
||||||
|
|
||||||
#define DECODE_SKIP -3
|
#define DECODE_SKIP -3
|
||||||
#define DECODE_BREAK -2
|
#define DECODE_BREAK -2
|
||||||
#define DECODE_CONT -1
|
#define DECODE_CONT -1
|
||||||
#define DECODE_OK 0
|
#define DECODE_OK 0
|
||||||
|
|
||||||
#define MUTEFRAME_SKIP 1
|
#define MUTEFRAME_SKIP 1
|
||||||
#define MUTEFRAME_SEEK 2
|
#define MUTEFRAME_SEEK 2
|
||||||
|
|
||||||
/* the number of samples of silence the decoder inserts at start */
|
/* the number of samples of silence the decoder inserts at start */
|
||||||
#define DECODERDELAY 529
|
#define DECODERDELAY 529
|
||||||
@ -498,16 +498,20 @@ enum {
|
|||||||
XING_SCALE = 0x00000008L
|
XING_SCALE = 0x00000008L
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct version {
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
};
|
||||||
|
|
||||||
struct lame {
|
struct lame {
|
||||||
char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */
|
char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */
|
||||||
#if 0
|
struct version version; /* struct containing just the version */
|
||||||
/* See related comment in parse_lame() */
|
float peak; /* replaygain peak */
|
||||||
float peak; /* replaygain peak */
|
float trackGain; /* replaygain track gain */
|
||||||
float trackGain; /* replaygain track gain */
|
float albumGain; /* replaygain album gain */
|
||||||
float albumGain; /* replaygain album gain */
|
int encoderDelay; /* # of added samples at start of mp3 */
|
||||||
#endif
|
int encoderPadding; /* # of added samples at end of mp3 */
|
||||||
int encoderDelay; /* # of added samples at start of mp3 */
|
int crc; /* CRC of the first 190 bytes of this frame */
|
||||||
int encoderPadding; /* # of added samples at end of mp3 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int parse_xing(struct xing *xing, struct mad_bitptr *ptr, int *oldbitlen)
|
static int parse_xing(struct xing *xing, struct mad_bitptr *ptr, int *oldbitlen)
|
||||||
@ -585,52 +589,94 @@ fail:
|
|||||||
|
|
||||||
static int parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
|
static int parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
|
||||||
{
|
{
|
||||||
|
int adj = 0;
|
||||||
|
int name;
|
||||||
|
int orig;
|
||||||
|
int sign;
|
||||||
|
int gain;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Unlike the xing header, the lame tag has a fixed length. Fail if
|
/* Unlike the xing header, the lame tag has a fixed length. Fail if
|
||||||
* not all 36 bytes (288 bits) are there. */
|
* not all 36 bytes (288 bits) are there. */
|
||||||
if (*bitlen < 288) return 0;
|
if (*bitlen < 288)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < 9; i++) lame->encoder[i] = (char)mad_bit_read(ptr, 8);
|
for (i = 0; i < 9; i++)
|
||||||
|
lame->encoder[i] = (char)mad_bit_read(ptr, 8);
|
||||||
lame->encoder[9] = '\0';
|
lame->encoder[9] = '\0';
|
||||||
|
|
||||||
|
*bitlen -= 72;
|
||||||
|
|
||||||
/* This is technically incorrect, since the encoder might not be lame.
|
/* This is technically incorrect, since the encoder might not be lame.
|
||||||
* But there's no other way to determine if this is a lame tag, and we
|
* But there's no other way to determine if this is a lame tag, and we
|
||||||
* wouldn't want to go reading a tag that's not there. */
|
* wouldn't want to go reading a tag that's not there. */
|
||||||
if (strncmp(lame->encoder, "LAME", 4) != 0) return 0;
|
if (strncmp(lame->encoder, "LAME", 4) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sscanf(lame->encoder+4, "%u.%u",
|
||||||
|
&lame->version.major, &lame->version.minor) != 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
DEBUG("detected LAME version %i.%i (\"%s\")\n",
|
||||||
|
lame->version.major, lame->version.minor, lame->encoder);
|
||||||
|
|
||||||
|
/* The reference volume was changed from the 83dB used in the
|
||||||
|
* ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older
|
||||||
|
* versions, since everyone else uses 89dB instead of 83dB.
|
||||||
|
* Unfortunately, lame didn't differentiate between 3.95 and 3.95.1, so
|
||||||
|
* it's impossible to make the proper adjustment for 3.95.
|
||||||
|
* Fortunately, 3.95 was only out for about a day before 3.95.1 was
|
||||||
|
* released. -- tmz */
|
||||||
|
if (lame->version.major < 3 ||
|
||||||
|
(lame->version.major == 3 && lame->version.minor < 95))
|
||||||
|
adj = 6;
|
||||||
|
|
||||||
|
mad_bit_read(ptr, 16);
|
||||||
|
|
||||||
|
lame->peak = mad_f_todouble(mad_bit_read(ptr, 32) << 5); /* peak */
|
||||||
|
DEBUG("LAME peak found: %f\n", lame->peak);
|
||||||
|
|
||||||
|
lame->trackGain = 0;
|
||||||
|
name = mad_bit_read(ptr, 3); /* gain name */
|
||||||
|
orig = mad_bit_read(ptr, 3); /* gain originator */
|
||||||
|
sign = mad_bit_read(ptr, 1); /* sign bit */
|
||||||
|
gain = mad_bit_read(ptr, 9); /* gain*10 */
|
||||||
|
if (gain && name == 1 && orig != 0) {
|
||||||
|
lame->trackGain = ((sign ? -gain : gain) / 10.0) + adj;
|
||||||
|
DEBUG("LAME track gain found: %f\n", lame->trackGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tmz reports that this isn't currently written by any version of lame
|
||||||
|
* (as of 3.97). Since we have no way of testing it, don't use it.
|
||||||
|
* Wouldn't want to go blowing someone's ears just because we read it
|
||||||
|
* wrong. :P -- jat */
|
||||||
|
lame->albumGain = 0;
|
||||||
#if 0
|
#if 0
|
||||||
/* Apparently lame versions <3.97b1 do not calculate replaygain. I'm
|
name = mad_bit_read(ptr, 3); /* gain name */
|
||||||
* using lame 3.97b2, and while it does calculate replaygain, it's
|
orig = mad_bit_read(ptr, 3); /* gain originator */
|
||||||
* setting the values to 0. Using --replaygain-(fast|accurate) doesn't
|
sign = mad_bit_read(ptr, 1); /* sign bit */
|
||||||
* make any difference. Leaving this code unused until we have a way
|
gain = mad_bit_read(ptr, 9); /* gain*10 */
|
||||||
* of testing it. -- jat */
|
if (gain && name == 2 && orig != 0) {
|
||||||
|
lame->albumGain = ((sign ? -gain : gain) / 10.0) + adj;
|
||||||
mad_bit_read(ptr, 16);
|
DEBUG("LAME album gain found: %f\n", lame->trackGain);
|
||||||
|
}
|
||||||
mad_bit_read(ptr, 32); /* peak */
|
|
||||||
|
|
||||||
mad_bit_read(ptr, 6); /* header */
|
|
||||||
bits = mad_bit_read(ptr, 1); /* sign bit */
|
|
||||||
lame->trackGain = mad_bit_read(ptr, 9); /* gain*10 */
|
|
||||||
lame->trackGain = (bits ? -lame->trackGain : lame->trackGain) / 10;
|
|
||||||
|
|
||||||
mad_bit_read(ptr, 6); /* header */
|
|
||||||
bits = mad_bit_read(ptr, 1); /* sign bit */
|
|
||||||
lame->albumGain = mad_bit_read(ptr, 9); /* gain*10 */
|
|
||||||
lame->albumGain = (bits ? -lame->albumGain : lame->albumGain) / 10;
|
|
||||||
|
|
||||||
mad_bit_read(ptr, 16);
|
|
||||||
#else
|
#else
|
||||||
mad_bit_read(ptr, 96);
|
mad_bit_read(ptr, 16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mad_bit_read(ptr, 16);
|
||||||
|
|
||||||
lame->encoderDelay = mad_bit_read(ptr, 12);
|
lame->encoderDelay = mad_bit_read(ptr, 12);
|
||||||
lame->encoderPadding = mad_bit_read(ptr, 12);
|
lame->encoderPadding = mad_bit_read(ptr, 12);
|
||||||
|
|
||||||
mad_bit_read(ptr, 96);
|
DEBUG("encoder delay is %i, encoder padding is %i\n",
|
||||||
|
lame->encoderDelay, lame->encoderPadding);
|
||||||
|
|
||||||
*bitlen -= 288;
|
mad_bit_read(ptr, 80);
|
||||||
|
|
||||||
|
lame->crc = mad_bit_read(ptr, 16);
|
||||||
|
|
||||||
|
*bitlen -= 216;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -694,18 +740,30 @@ static int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
|
|||||||
data->foundXing = 1;
|
data->foundXing = 1;
|
||||||
data->muteFrame = MUTEFRAME_SKIP;
|
data->muteFrame = MUTEFRAME_SKIP;
|
||||||
|
|
||||||
if (gaplessPlaybackEnabled && data->inStream->seekable &&
|
|
||||||
parse_lame(&lame, &ptr, &bitlen)) {
|
|
||||||
data->dropSamplesAtStart = lame.encoderDelay + DECODERDELAY;
|
|
||||||
data->dropSamplesAtEnd = lame.encoderPadding;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((xing.flags & XING_FRAMES) && xing.frames) {
|
if ((xing.flags & XING_FRAMES) && xing.frames) {
|
||||||
mad_timer_t duration = data->frame.header.duration;
|
mad_timer_t duration = data->frame.header.duration;
|
||||||
mad_timer_multiply(&duration, xing.frames);
|
mad_timer_multiply(&duration, xing.frames);
|
||||||
data->totalTime = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000;
|
data->totalTime = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000;
|
||||||
data->maxFrames = xing.frames;
|
data->maxFrames = xing.frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parse_lame(&lame, &ptr, &bitlen)) {
|
||||||
|
if (gaplessPlaybackEnabled &&
|
||||||
|
data->inStream->seekable) {
|
||||||
|
data->dropSamplesAtStart = lame.encoderDelay +
|
||||||
|
DECODERDELAY;
|
||||||
|
data->dropSamplesAtEnd = lame.encoderPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Album gain isn't currently used. See comment in
|
||||||
|
* parse_lame() for details. -- jat */
|
||||||
|
if (replayGainInfo && !*replayGainInfo &&
|
||||||
|
lame.trackGain) {
|
||||||
|
*replayGainInfo = newReplayGainInfo();
|
||||||
|
(*replayGainInfo)->trackGain = lame.trackGain;
|
||||||
|
(*replayGainInfo)->trackPeak = lame.peak;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data->maxFrames) return -1;
|
if (!data->maxFrames) return -1;
|
||||||
|
Loading…
Reference in New Issue
Block a user