diff options
Diffstat (limited to 'firmware/mp3data.c')
-rw-r--r-- | firmware/mp3data.c | 187 |
1 files changed, 84 insertions, 103 deletions
diff --git a/firmware/mp3data.c b/firmware/mp3data.c index 6f4c560578..c2d4cd2c37 100644 --- a/firmware/mp3data.c +++ b/firmware/mp3data.c @@ -31,6 +31,7 @@ #include <stdlib.h> #include <string.h> #include <stdbool.h> +#include <limits.h> #include "debug.h" #include "logf.h" #include "mp3data.h" @@ -39,7 +40,7 @@ #define DEBUG_VERBOSE -#define BYTES2INT(b1,b2,b3,b4) (((long)(b1 & 0xFF) << (3*8)) | \ +#define BYTES2INT(b1,b2,b3,b4) (((long)(b1 & 0xFF) << (3*8)) | \ ((long)(b2 & 0xFF) << (2*8)) | \ ((long)(b3 & 0xFF) << (1*8)) | \ ((long)(b4 & 0xFF) << (0*8))) @@ -58,37 +59,34 @@ #define ORIGINAL_MASK (1L << 2) #define EMPHASIS_MASK 3L -/* Table of bitrates for MP3 files, all values in kilo. - * Indexed by version, layer and value of bit 15-12 in header. - */ -const int bitrate_table[2][3][16] = -{ - { - {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, - {0,32,48,56, 64,80, 96, 112,128,160,192,224,256,320,384,0}, - {0,32,40,48, 56,64, 80, 96, 112,128,160,192,224,256,320,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} - } +/* MPEG Version table, sorted by version index */ +static const signed char version_table[4] = { + MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1 }; -/* Table of samples per frame for MP3 files. - * Indexed by layer. Multiplied with 1000. - */ -const long bs[3] = {384000, 1152000, 1152000}; +/* Bitrate table for mpeg audio, indexed by row index and birate index */ +static const short bitrates[5][16] = { + {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */ + {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */ + {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */ + {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */ + {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */ +}; -/* Table of sample frequency for MP3 files. - * Indexed by version and layer. - */ +/* Bitrate pointer table, indexed by version and layer */ +static const short *bitrate_table[3][3] = +{ + {bitrates[0], bitrates[1], bitrates[2]}, + {bitrates[3], bitrates[4], bitrates[4]}, + {bitrates[3], bitrates[4], bitrates[4]} +}; -const int freqtab[][4] = +/* Sampling frequency table, indexed by version and frequency index */ +static const long freq_table[3][3] = { - {11025, 12000, 8000, 0}, /* MPEG version 2.5 */ - {44100, 48000, 32000, 0}, /* MPEG Version 1 */ - {22050, 24000, 16000, 0}, /* MPEG version 2 */ + {44100, 48000, 32000}, /* MPEG Version 1 */ + {22050, 24000, 16000}, /* MPEG version 2 */ + {11025, 12000, 8000}, /* MPEG version 2.5 */ }; /* check if 'head' is a valid mp3 frame header */ @@ -117,97 +115,77 @@ static bool is_mp3frameheader(unsigned long head) static bool mp3headerinfo(struct mp3info *info, unsigned long header) { - int bittable = 0; - int bitindex; - int freqindex; - + int bitindex, freqindex; + /* MPEG Audio Version */ - switch((header & VERSION_MASK) >> 19) { - case 0: - /* MPEG version 2.5 is not an official standard */ - info->version = MPEG_VERSION2_5; - bittable = MPEG_VERSION2 - 1; /* use the V2 bit rate table */ - break; - - case 1: + info->version = version_table[(header & VERSION_MASK) >> 19]; + if (info->version < 0) return false; - case 2: - /* MPEG version 2 (ISO/IEC 13818-3) */ - info->version = MPEG_VERSION2; - bittable = MPEG_VERSION2 - 1; - break; - - case 3: - /* MPEG version 1 (ISO/IEC 11172-3) */ - info->version = MPEG_VERSION1; - bittable = MPEG_VERSION1 - 1; - break; - } - - switch((header & LAYER_MASK) >> 17) { - case 0: + /* Layer */ + info->layer = 3 - ((header & LAYER_MASK) >> 17); + if (info->layer == 3) return false; - case 1: - info->layer = 2; - break; - case 2: - info->layer = 1; - break; - case 3: - info->layer = 0; - break; - } - info->protection = (header & PROTECTION_MASK)?true:false; + info->protection = (header & PROTECTION_MASK) ? true : false; /* Bitrate */ - bitindex = (header & 0xf000) >> 12; - info->bitrate = bitrate_table[bittable][info->layer][bitindex]; + bitindex = (header & BITRATE_MASK) >> 12; + info->bitrate = bitrate_table[info->version][info->layer][bitindex]; if(info->bitrate == 0) return false; - + /* Sampling frequency */ - freqindex = (header & 0x0C00) >> 10; - info->frequency = freqtab[info->version][freqindex]; - if(info->frequency == 0) + freqindex = (header & SAMPLERATE_MASK) >> 10; + if (freqindex == 3) return false; + info->frequency = freq_table[info->version][freqindex]; - info->padding = (header & 0x0200)?1:0; + info->padding = (header & PADDING_MASK) ? 1 : 0; /* Calculate number of bytes, calculation depends on layer */ - switch(info->layer) { - case 0: - info->frame_size = info->bitrate * 48000; - info->frame_size /= - freqtab[info->version][freqindex] << bittable; - break; - case 1: - case 2: - info->frame_size = info->bitrate * 144000; - info->frame_size /= - freqtab[info->version][freqindex] << bittable; - break; - default: - info->frame_size = 1; + if (info->layer == 0) { + info->frame_samples = 384; + info->frame_size = (12000 * info->bitrate / info->frequency + + info->padding) * 4; + } + else { + if ((info->version > MPEG_VERSION1) && (info->layer == 2)) + info->frame_samples = 576; + else + info->frame_samples = 1152; + info->frame_size = (1000/8) * info->frame_samples * info->bitrate + / info->frequency + info->padding; } - info->frame_size += info->padding; - - /* Calculate time per frame */ - info->frame_time = bs[info->layer] / - (freqtab[info->version][freqindex] << bittable); + /* Frametime fraction calculation. + This fraction is reduced as far as possible. */ + if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */ + /* integer number of milliseconds, denominator == 1 */ + info->ft_num = 1000 * info->frame_samples / info->frequency; + info->ft_den = 1; + } + else { /* 44.1/22.05/11.025 kHz */ + if (info->layer == 0) { + info->ft_num = 147000 * 384 / info->frequency; + info->ft_den = 147; + } + else { + info->ft_num = 49000 * info->frame_samples / info->frequency; + info->ft_den = 49; + } + } - info->channel_mode = (header & 0xc0) >> 6; - info->mode_extension = (header & 0x30) >> 4; - info->emphasis = header & 3; + info->channel_mode = (header & CHANNELMODE_MASK) >> 6; + info->mode_extension = (header & MODE_EXT_MASK) >> 4; + info->emphasis = header & EMPHASIS_MASK; #ifdef DEBUG_VERBOSE - DEBUGF( "Header: %08x, Ver %d, lay %d, bitr %d, freq %d, " - "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d\n", + DEBUGF( "Header: %08x, Ver %d, lay %d, bitr %d, freq %ld, " + "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d/%d\n", header, info->version, info->layer+1, info->bitrate, info->frequency, info->channel_mode, info->mode_extension, - info->emphasis, info->frame_size, info->frame_time); + info->emphasis, info->frame_size, info->ft_num, info->ft_den); #endif return true; } @@ -252,7 +230,7 @@ static unsigned long __find_next_frame(int fd, long *offset, long max_offset, if(*offset) DEBUGF("Warning: skipping %d bytes of garbage\n", *offset); #endif - + return header; } @@ -380,9 +358,6 @@ int get_mp3file_info(int fd, struct mp3info *info) memset(info, 0, sizeof(struct mp3info)); /* These two are needed for proper LAME gapless MP3 playback */ - /* TODO: These can be found in a LAME Info header as well, but currently - they are only looked for in a Xing header. Xing and Info headers have - the exact same format, but Info headers are used for CBR files. */ info->enc_delay = -1; info->enc_padding = -1; if(!mp3headerinfo(info, header)) @@ -435,7 +410,10 @@ int get_mp3file_info(int fd, struct mp3info *info) { info->frame_count = BYTES2INT(vbrheader[i], vbrheader[i+1], vbrheader[i+2], vbrheader[i+3]); - info->file_time = info->frame_count * info->frame_time; + if (info->frame_count <= ULONG_MAX / info->ft_num) + info->file_time = info->frame_count * info->ft_num / info->ft_den; + else + info->file_time = info->frame_count / info->ft_den * info->ft_num; i += 4; } @@ -510,7 +488,10 @@ int get_mp3file_info(int fd, struct mp3info *info) vbrheader[12], vbrheader[13]); info->frame_count = BYTES2INT(vbrheader[14], vbrheader[15], vbrheader[16], vbrheader[17]); - info->file_time = info->frame_count * info->frame_time; + if (info->frame_count <= ULONG_MAX / info->ft_num) + info->file_time = info->frame_count * info->ft_num / info->ft_den; + else + info->file_time = info->frame_count / info->ft_den * info->ft_num; info->bitrate = info->byte_count * 8 / info->file_time; /* We don't parse the TOC, since we don't yet know how to (FIXME) */ |