fixed mp3 identification, skip ID3s

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5287 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
François Revol
2003-11-08 20:26:29 +00:00
parent f929e15217
commit ccd79dfdce
2 changed files with 72 additions and 10 deletions
@@ -13,6 +13,16 @@
#define TRACE ((void)0)
#endif
/* see
* http://www.multiweb.cz/twoinches/MP3inside.htm
*
*/
/* minimal ID3 stuff
* see http://www.id3.org/id3v2.3.0.txt
*/
#define ID3_HEADER_SIZE 10
// bit_rate_table[mpeg_version_index][layer_index][bitrate_index]
static const int bit_rate_table[4][4][16] =
{
@@ -241,10 +251,28 @@ mp3Reader::GetNextChunk(void *cookie,
return result;
}
ssize_t
mp3Reader::ID3Size(uint8 *buffer, size_t len)
{
if (len < ID3_HEADER_SIZE)
return B_BAD_VALUE;
if ((buffer[0] == 'I') && /* magic */
(buffer[1] == 'D') &&
(buffer[2] == '3') &&
(buffer[3] != 0xff) && (buffer[4] != 0xff) && /* version */
/* flags */
(!(buffer[6] & 0x80)) && (!(buffer[7] & 0x80)) && /* the MSB in each byte in size is 0, to avoid */
(!(buffer[8] & 0x80)) && (!(buffer[9] & 0x80))) { /* making a buggy mpeg header */
return ((buffer[6] << 21)|(buffer[7] << 14)|(buffer[8] << 7)|(buffer[9])) + 10;
}
return B_ENTRY_NOT_FOUND;
}
bool
mp3Reader::IsMp3File()
{
// To detect an mp3 file, we seek into the middle,
// //! To detect an mp3 file, we seek into the middle,
// To detect an mp3 file, we first check for an ID3,
// and search for a valid sequence of 3 frame headers.
// A mp3 frame has a maximum length of 2881 bytes, we
// load a block of 16kB and use it to search.
@@ -253,7 +281,29 @@ mp3Reader::IsMp3File()
int64 offset;
int32 size;
uint8 buf[search_size];
ssize_t id3size;
offset = 0;
size = (search_size > fFileSize)?fFileSize:search_size;
TRACE("searching for mp3 frame headers or ID3 at %Ld in %ld bytes\n", offset, size);
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("mp3ReaderPlugin::IsMp3File reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
id3size = ID3Size(buf, size);
if (id3size > 0) {
TRACE("found ID3, size %ld, skipping...\n", id3size);
offset += id3size;
size = (search_size+offset > fFileSize)?(fFileSize-offset):(search_size);
TRACE("searching for mp3 frame headers or ID3 at %Ld in %ld bytes\n", offset, size);
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("mp3ReaderPlugin::IsMp3File reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
}
#if 0
size = search_size;
offset = fFileSize / 2 - search_size / 2;
if (size > fFileSize) {
@@ -267,9 +317,12 @@ mp3Reader::IsMp3File()
TRACE("mp3ReaderPlugin::IsMp3File reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
#endif
for (int32 pos = 0; pos < (size - 8); pos++) {
int length1, length2, length3;
//TRACE("---- checking for frame at %Ld\n", offset + pos);
length1 = GetFrameLength(&buf[pos]);
if (length1 < 0 || (pos + length1 + 4) > size)
continue;
@@ -290,20 +343,27 @@ mp3Reader::IsMp3File()
int
mp3Reader::GetFrameLength(void *header)
{
if (((uint8 *)header)[0] != 0xff)
uint8 *h = (uint8 *)header;
if (h[0] != 0xff)
return -1;
if (((uint8 *)header)[1] & 0xe0 != 0xe)
if ((h[1] & 0xe0) != 0xe0)
return -1;
int mpeg_version_index = (((uint8 *)header)[1] >> 3) & 0x03;
int layer_index = (((uint8 *)header)[1] >> 1) & 0x03;
int bitrate_index = (((uint8 *)header)[2] >> 4) & 0x0f;
int sampling_rate_index = (((uint8 *)header)[2] >> 2) & 0x03;
int padding = (((uint8 *)header)[2] >> 1) & 0x01;
int mpeg_version_index = (h[1] >> 3) & 0x03;
int layer_index = (h[1] >> 1) & 0x03;
int no_crc = (h[1] & 0x01);
/* VBR files seem to use CRC in info frames, probably to make the
* decoder discard them with a wrong CRC...
*/
int bitrate_index = (h[2] >> 4) & 0x0f;
int sampling_rate_index = (h[2] >> 2) & 0x03;
int padding = (h[2] >> 1) & 0x01;
/* no interested in the other bits */
int bitrate = bit_rate_table[mpeg_version_index][layer_index][bitrate_index];
int samplingrate = sampling_rate_table[mpeg_version_index][sampling_rate_index];
if (!bitrate || !samplingrate)
return -1;
@@ -313,9 +373,10 @@ mp3Reader::GetFrameLength(void *header)
else // layer 2 & 3
length = ((144 * 1000 * bitrate) / samplingrate) + padding;
TRACE("%s %s, bit rate %d, sampling rate %d, padding %d, frame length %d\n",
TRACE("%s %s, %s crc, bit rate %d, sampling rate %d, padding %d, frame length %d\n",
mpeg_version_index == 0 ? "mpeg 2.5" : (mpeg_version_index == 2 ? "mpeg 2" : "mpeg 1"),
layer_index == 3 ? "layer 1" : (layer_index == 2 ? "layer 2" : "layer 3"),
no_crc?"no":"has",
bitrate, samplingrate, padding, length);
return length;
@@ -32,6 +32,7 @@ public:
BPositionIO *Source() { return fSeekableSource; }
private:
ssize_t ID3Size(uint8 *buffer, size_t len);
bool IsMp3File();
int GetFrameLength(void *header);