/* Copyright (C) 2000-2003 Markus Lausser (sgop@users.sf.net) This is free software distributed under the terms of the GNU Public License. See the file COPYING for details. */ #include #include #include #include #include #include #include #include "lopster.h" #define FRAMES_FLAG 0x0001 #define BYTES_FLAG 0x0002 #define TOC_FLAG 0x0004 #define VBR_SCALE_FLAG 0x0008 unsigned int get_bits(unsigned char *buffer, int start, int no) { unsigned int res; res = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; res <<= start; res >>= (32 - no); return res; } static int ExtractI4(unsigned char *buf) { int x; /* big endian extract */ x = buf[0]; x <<= 8; x |= buf[1]; x <<= 8; x |= buf[2]; x <<= 8; x |= buf[3]; return x; } void file_parse_mp3_header(file_t * file) { FILE *fd; unsigned char buffer[4]; // header unsigned char xing[120]; int mpeg_version; int mpeg_layer; int res; int index; long totalframes; int padding; int stereo; int protection; int lsf; double bpf; static const int bs[4] = { 0, 384, 1152, 1152 }; static const int s1[4] = { 0, 48000, 144000, 144000 }; double tpf; int xing_offset; int pos; int ch; int id3; static const short br[2][4][16] = { { // mpeg 2 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0}, // {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, // {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0} // }, { // mpeg1 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, // layer I {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, // layer II {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0} // layer III } }; static const int freq[2][2][4] = { { {11025, 12000, 8000, 0}, // mpeg 2.5 {0, 0, 0, 0}, // reserved }, { {22050, 24000, 16000, 0}, // mpeg 2 {44100, 48000, 32000, 0} // mpeg 1 }, }; if ((fd = fopen(file->longname, "r")) == NULL) { // printf("could not open file for reading header [%s]\n", file->longname); return; } /* Skip ID3v2 tag at start of file - it may have false syncs in (not * according to the spec, but files out in the wild seem to have them). * If the tag is large, it's probably faster than stepping through it too. */ ch = getc(fd); id3 = 0; if (ch == 'I' && getc(fd) == 'D' && getc(fd) == '3' && getc(fd) <= 4 && getc(fd) != '\xff') { int flags = getc(fd); if ((flags & 0x0f) == 0) { int size = 0; int c; id3 = 1; for (c = 21; c >= 0; c -= 7) { ch = getc(fd); if (ch & 0x80) id3 = 0; size |= ch << c; } if (id3) fseek(fd, size + (flags & 0x10 ? 20 : 10), SEEK_SET); } } if (!id3) rewind(fd); do { do { ch = getc(fd); if (ch == EOF) { printf("could not read header [%s]\n", file->longname); goto close; } } while ((char)ch != '\xff'); ch = getc(fd); if (ch == EOF) { printf("could not read header [%s]\n", file->longname); goto close; } } while ((ch & 0xe0) != 0xe0); buffer[0] = '\xff'; buffer[1] = ch; if (fread(buffer + 2, 2, 1, fd) != 1) { printf("could not read header [%s]\n", file->longname); goto close; } // sync word index = get_bits(buffer, 11, 1); // MPEG Version mpeg_version = get_bits(buffer, 12, 1); if (mpeg_version) lsf = 0x0; // mpeg 1 else lsf = 0x1; // mpeg 2 // MPEG Layer mpeg_layer = get_bits(buffer, 13, 2); mpeg_layer = 4 - mpeg_layer; if (mpeg_layer > 3) goto close; // Protection Bit protection = get_bits(buffer, 15, 1); // Bitrate res = get_bits(buffer, 16, 4); if (res > 14) goto close; file->bitrate = br[mpeg_version][mpeg_layer][res]; // Fequency res = get_bits(buffer, 20, 2); file->frequency = freq[index][mpeg_version][res]; if ((file->bitrate == 0) || (file->frequency == 0)) { // printf("corrupted header! [%s]\n", file->longname); goto close; } // Padding Bit padding = get_bits(buffer, 22, 1); // Private Bit res = get_bits(buffer, 23, 1); // Mode res = get_bits(buffer, 24, 2); if (res == 3) stereo = 0; else stereo = 1; tpf = (double) bs[mpeg_layer] / (file->frequency << lsf); if (mpeg_version) { /* mpeg1 */ if (stereo) xing_offset = 32; else xing_offset = 17; } else { /* mpeg2 */ if (stereo) xing_offset = 17; else xing_offset = 9; } pos = ftell(fd); if ((fseek(fd, xing_offset, SEEK_CUR) == 0) && (fread(xing, 120, 1, fd) == 1) && (memcmp(xing, "Xing", 4) == 0)) { unsigned char * buf = xing + 4; int head_flags; int vbr_scale = -1; int bytes; head_flags = ExtractI4(buf); buf += 4; if (head_flags & FRAMES_FLAG) { totalframes = ExtractI4(buf); buf += 4; } else totalframes = 1; if (head_flags & BYTES_FLAG) { bytes = ExtractI4(buf); buf += 4; } else bytes = 1; if (head_flags & TOC_FLAG) { buf += 100; } if (head_flags & VBR_SCALE_FLAG) { vbr_scale = ExtractI4(buf); buf += 4; } file->bitrate = (gint) ((bytes * 8) / (tpf * totalframes * 1000)); bpf = (double) (file->size - pos) / totalframes; file->vbr = 1; } else { bpf = file->bitrate * s1[mpeg_layer] / (file->frequency << lsf); totalframes = (int) ((file->size - pos) / bpf); file->vbr = 0; } file->duration = totalframes * tpf; #ifdef SHARE_DEBUG /* printf ("mpeg %d layer %d, br %d, freq %d bpf %.1f, frames %ld, duration %d, vbr:%d\n", lsf + 1, mpeg_layer, file->bitrate, file->frequency, bpf, totalframes, file->duration, file->vbr); */ #endif #if 0 // Mode Extension res = get_bits(buffer, 26, 2); // Copyright res = get_bits(buffer, 28, 1); // Original Home res = get_bits(buffer, 29, 1); // Emphasis res = get_bits(buffer, 30, 2); #endif close: fclose(fd); }