diff options
author | Jens Arnold <amiconn@rockbox.org> | 2005-09-10 12:28:16 +0000 |
---|---|---|
committer | Jens Arnold <amiconn@rockbox.org> | 2005-09-10 12:28:16 +0000 |
commit | ec9b202a921996945ebd42a7edba1326754d7737 (patch) | |
tree | f88c7d9ee1ff94c3a5cefdba0d30c78b84e72d62 | |
parent | 1996dca15a495c09986cefc02086e03a53244f3a (diff) | |
download | rockbox-ec9b202a921996945ebd42a7edba1326754d7737.tar.gz rockbox-ec9b202a921996945ebd42a7edba1326754d7737.zip |
Reworked handling of MPEG audio frame & file info: * Fixed frame size calculation for layer 1 (all versions) and layer 2 (V2/V2.5). * Exact frame time (expressed as a fraction) for way more precise playtime calculation at 44100/22050/11025Hz sample frequency. * Exact playtime<->position conversion for CBR also used for resume position. * More compact code, long policy.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7505 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/bookmark.c | 2 | ||||
-rw-r--r-- | apps/playback.c | 10 | ||||
-rw-r--r-- | apps/screens.c | 2 | ||||
-rw-r--r-- | apps/settings.h | 4 | ||||
-rw-r--r-- | apps/wps-display.c | 4 | ||||
-rw-r--r-- | firmware/export/id3.h | 38 | ||||
-rw-r--r-- | firmware/export/mp3data.h | 26 | ||||
-rw-r--r-- | firmware/id3.c | 8 | ||||
-rw-r--r-- | firmware/mp3data.c | 187 | ||||
-rw-r--r-- | firmware/mpeg.c | 12 |
10 files changed, 136 insertions, 157 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c index c157d01662..593bfe98cb 100644 --- a/apps/bookmark.c +++ b/apps/bookmark.c | |||
@@ -389,7 +389,7 @@ static char* create_bookmark() | |||
389 | 389 | ||
390 | /* create the bookmark */ | 390 | /* create the bookmark */ |
391 | snprintf(global_bookmark, sizeof(global_bookmark), | 391 | snprintf(global_bookmark, sizeof(global_bookmark), |
392 | "%d;%d;%d;%d;%d;%d;%d;%s;%s", | 392 | "%d;%ld;%d;%d;%ld;%d;%d;%s;%s", |
393 | resume_index, | 393 | resume_index, |
394 | id3->offset, | 394 | id3->offset, |
395 | playlist_get_seed(NULL), | 395 | playlist_get_seed(NULL), |
diff --git a/apps/playback.c b/apps/playback.c index 6fd63d5a0f..1677e3138b 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -2008,7 +2008,7 @@ static void mp3_set_elapsed(struct mp3entry* id3) | |||
2008 | /* find wich percent we're at */ | 2008 | /* find wich percent we're at */ |
2009 | for (i=0; i<100; i++ ) | 2009 | for (i=0; i<100; i++ ) |
2010 | { | 2010 | { |
2011 | if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) ) | 2011 | if ( id3->offset < id3->toc[i] * (id3->filesize / 256) ) |
2012 | { | 2012 | { |
2013 | break; | 2013 | break; |
2014 | } | 2014 | } |
@@ -2048,8 +2048,8 @@ static void mp3_set_elapsed(struct mp3entry* id3) | |||
2048 | } | 2048 | } |
2049 | } | 2049 | } |
2050 | else | 2050 | else |
2051 | /* constant bitrate == simple frame calculation */ | 2051 | /* constant bitrate, use exact calculation */ |
2052 | id3->elapsed = id3->offset / id3->bpf * id3->tpf; | 2052 | id3->elapsed = id3->offset / (id3->bitrate / 8); |
2053 | } | 2053 | } |
2054 | 2054 | ||
2055 | /* Copied from mpeg.c. Should be moved somewhere else. */ | 2055 | /* Copied from mpeg.c. Should be moved somewhere else. */ |
@@ -2092,8 +2092,8 @@ int mp3_get_file_pos(void) | |||
2092 | (id3->elapsed / 1000); | 2092 | (id3->elapsed / 1000); |
2093 | } | 2093 | } |
2094 | } | 2094 | } |
2095 | else if (id3->bpf && id3->tpf) | 2095 | else if (id3->bitrate) |
2096 | pos = (id3->elapsed/id3->tpf)*id3->bpf; | 2096 | pos = id3->elapsed * (id3->bitrate / 8); |
2097 | else | 2097 | else |
2098 | { | 2098 | { |
2099 | return -1; | 2099 | return -1; |
diff --git a/apps/screens.c b/apps/screens.c index 10e1cdd188..bba5b279e2 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -1398,7 +1398,7 @@ bool browse_id3(void) | |||
1398 | id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) ""); | 1398 | id3->vbr ? str(LANG_ID3_VBR) : (const unsigned char*) ""); |
1399 | line = draw_id3_item(line, top, LANG_ID3_BITRATE, buf); | 1399 | line = draw_id3_item(line, top, LANG_ID3_BITRATE, buf); |
1400 | 1400 | ||
1401 | snprintf(buf, sizeof(buf), "%d Hz", id3->frequency); | 1401 | snprintf(buf, sizeof(buf), "%ld Hz", id3->frequency); |
1402 | line = draw_id3_item(line, top, LANG_ID3_FRECUENCY, buf); | 1402 | line = draw_id3_item(line, top, LANG_ID3_FRECUENCY, buf); |
1403 | 1403 | ||
1404 | #if CONFIG_CODEC == SWCODEC | 1404 | #if CONFIG_CODEC == SWCODEC |
diff --git a/apps/settings.h b/apps/settings.h index 1c1e664b90..327b79a7ee 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -215,13 +215,13 @@ struct user_settings | |||
215 | #ifdef HAVE_SPDIF_POWER | 215 | #ifdef HAVE_SPDIF_POWER |
216 | bool spdif_enable; /* S/PDIF power on/off */ | 216 | bool spdif_enable; /* S/PDIF power on/off */ |
217 | #endif | 217 | #endif |
218 | 218 | ||
219 | /* resume settings */ | 219 | /* resume settings */ |
220 | 220 | ||
221 | bool resume; /* resume option: 0=off, 1=on */ | 221 | bool resume; /* resume option: 0=off, 1=on */ |
222 | int resume_index; /* index in playlist (-1 for no active resume) */ | 222 | int resume_index; /* index in playlist (-1 for no active resume) */ |
223 | int resume_first_index; /* index of first track in playlist */ | 223 | int resume_first_index; /* index of first track in playlist */ |
224 | int resume_offset; /* byte offset in mp3 file */ | 224 | unsigned long resume_offset; /* byte offset in mp3 file */ |
225 | int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted | 225 | int resume_seed; /* shuffle seed (-1=no resume shuffle 0=sorted |
226 | >0=shuffled) */ | 226 | >0=shuffled) */ |
227 | 227 | ||
diff --git a/apps/wps-display.c b/apps/wps-display.c index 1794e53549..3c3cc98ed4 100644 --- a/apps/wps-display.c +++ b/apps/wps-display.c | |||
@@ -598,7 +598,7 @@ static char* get_tag(struct mp3entry* cid3, | |||
598 | return buf; | 598 | return buf; |
599 | 599 | ||
600 | case 'f': /* File Frequency */ | 600 | case 'f': /* File Frequency */ |
601 | snprintf(buf, buf_size, "%d", id3->frequency); | 601 | snprintf(buf, buf_size, "%ld", id3->frequency); |
602 | return buf; | 602 | return buf; |
603 | 603 | ||
604 | case 'p': /* File Path */ | 604 | case 'p': /* File Path */ |
@@ -626,7 +626,7 @@ static char* get_tag(struct mp3entry* cid3, | |||
626 | } | 626 | } |
627 | 627 | ||
628 | case 's': /* File Size (in kilobytes) */ | 628 | case 's': /* File Size (in kilobytes) */ |
629 | snprintf(buf, buf_size, "%d", id3->filesize / 1024); | 629 | snprintf(buf, buf_size, "%ld", id3->filesize / 1024); |
630 | return buf; | 630 | return buf; |
631 | 631 | ||
632 | case 'c': /* File Codec */ | 632 | case 'c': /* File Codec */ |
diff --git a/firmware/export/id3.h b/firmware/export/id3.h index 6c6507159a..47a084d67a 100644 --- a/firmware/export/id3.h +++ b/firmware/export/id3.h | |||
@@ -61,39 +61,37 @@ struct mp3entry { | |||
61 | unsigned char genre; | 61 | unsigned char genre; |
62 | unsigned int codectype; | 62 | unsigned int codectype; |
63 | unsigned int bitrate; | 63 | unsigned int bitrate; |
64 | unsigned int frequency; | 64 | unsigned long frequency; |
65 | unsigned int id3v2len; | 65 | unsigned long id3v2len; |
66 | unsigned int id3v1len; | 66 | unsigned long id3v1len; |
67 | unsigned int first_frame_offset; /* Byte offset to first real MP3 frame. | 67 | unsigned long first_frame_offset; /* Byte offset to first real MP3 frame. |
68 | Used for skipping leading garbage to | 68 | Used for skipping leading garbage to |
69 | avoid gaps between tracks. */ | 69 | avoid gaps between tracks. */ |
70 | unsigned int vbr_header_pos; | 70 | unsigned long vbr_header_pos; |
71 | unsigned int filesize; /* in bytes */ | 71 | unsigned long filesize; /* without headers; in bytes */ |
72 | unsigned int length; /* song length */ | 72 | unsigned long length; /* song length in ms */ |
73 | unsigned int elapsed; /* ms played */ | 73 | unsigned long elapsed; /* ms played */ |
74 | 74 | ||
75 | int lead_trim; /* Number of samples to skip at the beginning */ | 75 | int lead_trim; /* Number of samples to skip at the beginning */ |
76 | int tail_trim; /* Number of samples to remove from the end */ | 76 | int tail_trim; /* Number of samples to remove from the end */ |
77 | 77 | ||
78 | /* Added for Vorbis */ | 78 | /* Added for Vorbis */ |
79 | unsigned long samples; /* number of samples in track */ | 79 | unsigned long samples; /* number of samples in track */ |
80 | 80 | ||
81 | /* MP3 stream specific info */ | 81 | /* MP3 stream specific info */ |
82 | long bpf; /* bytes per frame */ | 82 | unsigned long frame_count; /* number of frames in the file (if VBR) */ |
83 | long tpf; /* time per frame */ | ||
84 | long frame_count; /* number of frames in the file (if VBR) */ | ||
85 | 83 | ||
86 | /* Xing VBR fields */ | 84 | /* Xing VBR fields */ |
87 | bool vbr; | 85 | bool vbr; |
88 | bool has_toc; /* True if there is a VBR header in the file */ | 86 | bool has_toc; /* True if there is a VBR header in the file */ |
89 | unsigned char toc[100];/* table of contents */ | 87 | unsigned char toc[100]; /* table of contents */ |
90 | 88 | ||
91 | /* these following two fields are used for local buffering */ | 89 | /* these following two fields are used for local buffering */ |
92 | char id3v2buf[300]; | 90 | char id3v2buf[300]; |
93 | char id3v1buf[3][32]; | 91 | char id3v1buf[3][32]; |
94 | 92 | ||
95 | /* resume related */ | 93 | /* resume related */ |
96 | int offset; /* bytes played */ | 94 | unsigned long offset; /* bytes played */ |
97 | int index; /* playlist index */ | 95 | int index; /* playlist index */ |
98 | 96 | ||
99 | /* FileEntry fields */ | 97 | /* FileEntry fields */ |
diff --git a/firmware/export/mp3data.h b/firmware/export/mp3data.h index db1a93b8d6..3961664815 100644 --- a/firmware/export/mp3data.h +++ b/firmware/export/mp3data.h | |||
@@ -20,9 +20,9 @@ | |||
20 | #ifndef _MP3DATA_H_ | 20 | #ifndef _MP3DATA_H_ |
21 | #define _MP3DATA_H_ | 21 | #define _MP3DATA_H_ |
22 | 22 | ||
23 | #define MPEG_VERSION2_5 0 | 23 | #define MPEG_VERSION1 0 |
24 | #define MPEG_VERSION1 1 | 24 | #define MPEG_VERSION2 1 |
25 | #define MPEG_VERSION2 2 | 25 | #define MPEG_VERSION2_5 2 |
26 | 26 | ||
27 | struct mp3info { | 27 | struct mp3info { |
28 | /* Standard MP3 frame header fields */ | 28 | /* Standard MP3 frame header fields */ |
@@ -30,23 +30,25 @@ struct mp3info { | |||
30 | int layer; | 30 | int layer; |
31 | bool protection; | 31 | bool protection; |
32 | int bitrate; | 32 | int bitrate; |
33 | int frequency; | 33 | long frequency; |
34 | int padding; | 34 | int padding; |
35 | int channel_mode; | 35 | int channel_mode; |
36 | int mode_extension; | 36 | int mode_extension; |
37 | int emphasis; | 37 | int emphasis; |
38 | int frame_size; /* Frame size in bytes */ | 38 | int frame_size; /* Frame size in bytes */ |
39 | int frame_time; /* Frame duration in milliseconds */ | 39 | int frame_samples; /* Samples per frame */ |
40 | int ft_num; /* Numerator of frametime in milliseconds */ | ||
41 | int ft_den; /* Denominator of frametime in milliseconds */ | ||
40 | 42 | ||
41 | bool is_vbr; /* True if the file is VBR */ | 43 | bool is_vbr; /* True if the file is VBR */ |
42 | bool has_toc; /* True if there is a VBR header in the file */ | 44 | bool has_toc; /* True if there is a VBR header in the file */ |
43 | bool is_xing_vbr; /* True if the VBR header is of Xing type */ | 45 | bool is_xing_vbr; /* True if the VBR header is of Xing type */ |
44 | bool is_vbri_vbr; /* True if the VBR header is of VBRI type */ | 46 | bool is_vbri_vbr; /* True if the VBR header is of VBRI type */ |
45 | unsigned char toc[100]; | 47 | unsigned char toc[100]; |
46 | long frame_count; /* Number of frames in the file (if VBR) */ | 48 | unsigned long frame_count; /* Number of frames in the file (if VBR) */ |
47 | long byte_count; /* File size in bytes */ | 49 | unsigned long byte_count; /* File size in bytes */ |
48 | long file_time; /* Length of the whole file in milliseconds */ | 50 | unsigned long file_time; /* Length of the whole file in milliseconds */ |
49 | int vbr_header_pos; | 51 | unsigned long vbr_header_pos; |
50 | int enc_delay; /* Encoder delay, fetched from LAME header */ | 52 | int enc_delay; /* Encoder delay, fetched from LAME header */ |
51 | int enc_padding; /* Padded samples added to last frame. LAME header */ | 53 | int enc_padding; /* Padded samples added to last frame. LAME header */ |
52 | }; | 54 | }; |
diff --git a/firmware/id3.c b/firmware/id3.c index f1aa821fba..dfbcb9699d 100644 --- a/firmware/id3.c +++ b/firmware/id3.c | |||
@@ -863,10 +863,10 @@ static int getid3v2len(int fd) | |||
863 | */ | 863 | */ |
864 | static int getsonglength(int fd, struct mp3entry *entry) | 864 | static int getsonglength(int fd, struct mp3entry *entry) |
865 | { | 865 | { |
866 | unsigned int filetime = 0; | 866 | unsigned long filetime = 0; |
867 | struct mp3info info; | 867 | struct mp3info info; |
868 | int bytecount; | 868 | long bytecount; |
869 | 869 | ||
870 | /* Start searching after ID3v2 header */ | 870 | /* Start searching after ID3v2 header */ |
871 | if(-1 == lseek(fd, entry->id3v2len, SEEK_SET)) | 871 | if(-1 == lseek(fd, entry->id3v2len, SEEK_SET)) |
872 | return 0; | 872 | return 0; |
@@ -912,8 +912,6 @@ static int getsonglength(int fd, struct mp3entry *entry) | |||
912 | * always multiples of 8, and it avoids overflows. */ | 912 | * always multiples of 8, and it avoids overflows. */ |
913 | } | 913 | } |
914 | 914 | ||
915 | entry->tpf = info.frame_time; | ||
916 | entry->bpf = info.frame_size; | ||
917 | entry->frame_count = info.frame_count; | 915 | entry->frame_count = info.frame_count; |
918 | 916 | ||
919 | entry->vbr = info.is_vbr; | 917 | entry->vbr = info.is_vbr; |
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 @@ | |||
31 | #include <stdlib.h> | 31 | #include <stdlib.h> |
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <stdbool.h> | 33 | #include <stdbool.h> |
34 | #include <limits.h> | ||
34 | #include "debug.h" | 35 | #include "debug.h" |
35 | #include "logf.h" | 36 | #include "logf.h" |
36 | #include "mp3data.h" | 37 | #include "mp3data.h" |
@@ -39,7 +40,7 @@ | |||
39 | 40 | ||
40 | #define DEBUG_VERBOSE | 41 | #define DEBUG_VERBOSE |
41 | 42 | ||
42 | #define BYTES2INT(b1,b2,b3,b4) (((long)(b1 & 0xFF) << (3*8)) | \ | 43 | #define BYTES2INT(b1,b2,b3,b4) (((long)(b1 & 0xFF) << (3*8)) | \ |
43 | ((long)(b2 & 0xFF) << (2*8)) | \ | 44 | ((long)(b2 & 0xFF) << (2*8)) | \ |
44 | ((long)(b3 & 0xFF) << (1*8)) | \ | 45 | ((long)(b3 & 0xFF) << (1*8)) | \ |
45 | ((long)(b4 & 0xFF) << (0*8))) | 46 | ((long)(b4 & 0xFF) << (0*8))) |
@@ -58,37 +59,34 @@ | |||
58 | #define ORIGINAL_MASK (1L << 2) | 59 | #define ORIGINAL_MASK (1L << 2) |
59 | #define EMPHASIS_MASK 3L | 60 | #define EMPHASIS_MASK 3L |
60 | 61 | ||
61 | /* Table of bitrates for MP3 files, all values in kilo. | 62 | /* MPEG Version table, sorted by version index */ |
62 | * Indexed by version, layer and value of bit 15-12 in header. | 63 | static const signed char version_table[4] = { |
63 | */ | 64 | MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1 |
64 | const int bitrate_table[2][3][16] = | ||
65 | { | ||
66 | { | ||
67 | {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, | ||
68 | {0,32,48,56, 64,80, 96, 112,128,160,192,224,256,320,384,0}, | ||
69 | {0,32,40,48, 56,64, 80, 96, 112,128,160,192,224,256,320,0} | ||
70 | }, | ||
71 | { | ||
72 | {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0}, | ||
73 | {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0}, | ||
74 | {0, 8,16,24,32,40,48, 56, 64, 80, 96,112,128,144,160,0} | ||
75 | } | ||
76 | }; | 65 | }; |
77 | 66 | ||
78 | /* Table of samples per frame for MP3 files. | 67 | /* Bitrate table for mpeg audio, indexed by row index and birate index */ |
79 | * Indexed by layer. Multiplied with 1000. | 68 | static const short bitrates[5][16] = { |
80 | */ | 69 | {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */ |
81 | const long bs[3] = {384000, 1152000, 1152000}; | 70 | {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */ |
71 | {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */ | ||
72 | {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */ | ||
73 | {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */ | ||
74 | }; | ||
82 | 75 | ||
83 | /* Table of sample frequency for MP3 files. | 76 | /* Bitrate pointer table, indexed by version and layer */ |
84 | * Indexed by version and layer. | 77 | static const short *bitrate_table[3][3] = |
85 | */ | 78 | { |
79 | {bitrates[0], bitrates[1], bitrates[2]}, | ||
80 | {bitrates[3], bitrates[4], bitrates[4]}, | ||
81 | {bitrates[3], bitrates[4], bitrates[4]} | ||
82 | }; | ||
86 | 83 | ||
87 | const int freqtab[][4] = | 84 | /* Sampling frequency table, indexed by version and frequency index */ |
85 | static const long freq_table[3][3] = | ||
88 | { | 86 | { |
89 | {11025, 12000, 8000, 0}, /* MPEG version 2.5 */ | 87 | {44100, 48000, 32000}, /* MPEG Version 1 */ |
90 | {44100, 48000, 32000, 0}, /* MPEG Version 1 */ | 88 | {22050, 24000, 16000}, /* MPEG version 2 */ |
91 | {22050, 24000, 16000, 0}, /* MPEG version 2 */ | 89 | {11025, 12000, 8000}, /* MPEG version 2.5 */ |
92 | }; | 90 | }; |
93 | 91 | ||
94 | /* check if 'head' is a valid mp3 frame header */ | 92 | /* check if 'head' is a valid mp3 frame header */ |
@@ -117,97 +115,77 @@ static bool is_mp3frameheader(unsigned long head) | |||
117 | 115 | ||
118 | static bool mp3headerinfo(struct mp3info *info, unsigned long header) | 116 | static bool mp3headerinfo(struct mp3info *info, unsigned long header) |
119 | { | 117 | { |
120 | int bittable = 0; | 118 | int bitindex, freqindex; |
121 | int bitindex; | 119 | |
122 | int freqindex; | ||
123 | |||
124 | /* MPEG Audio Version */ | 120 | /* MPEG Audio Version */ |
125 | switch((header & VERSION_MASK) >> 19) { | 121 | info->version = version_table[(header & VERSION_MASK) >> 19]; |
126 | case 0: | 122 | if (info->version < 0) |
127 | /* MPEG version 2.5 is not an official standard */ | ||
128 | info->version = MPEG_VERSION2_5; | ||
129 | bittable = MPEG_VERSION2 - 1; /* use the V2 bit rate table */ | ||
130 | break; | ||
131 | |||
132 | case 1: | ||
133 | return false; | 123 | return false; |
134 | 124 | ||
135 | case 2: | 125 | /* Layer */ |
136 | /* MPEG version 2 (ISO/IEC 13818-3) */ | 126 | info->layer = 3 - ((header & LAYER_MASK) >> 17); |
137 | info->version = MPEG_VERSION2; | 127 | if (info->layer == 3) |
138 | bittable = MPEG_VERSION2 - 1; | ||
139 | break; | ||
140 | |||
141 | case 3: | ||
142 | /* MPEG version 1 (ISO/IEC 11172-3) */ | ||
143 | info->version = MPEG_VERSION1; | ||
144 | bittable = MPEG_VERSION1 - 1; | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | switch((header & LAYER_MASK) >> 17) { | ||
149 | case 0: | ||
150 | return false; | 128 | return false; |
151 | case 1: | ||
152 | info->layer = 2; | ||
153 | break; | ||
154 | case 2: | ||
155 | info->layer = 1; | ||
156 | break; | ||
157 | case 3: | ||
158 | info->layer = 0; | ||
159 | break; | ||
160 | } | ||
161 | 129 | ||
162 | info->protection = (header & PROTECTION_MASK)?true:false; | 130 | info->protection = (header & PROTECTION_MASK) ? true : false; |
163 | 131 | ||
164 | /* Bitrate */ | 132 | /* Bitrate */ |
165 | bitindex = (header & 0xf000) >> 12; | 133 | bitindex = (header & BITRATE_MASK) >> 12; |
166 | info->bitrate = bitrate_table[bittable][info->layer][bitindex]; | 134 | info->bitrate = bitrate_table[info->version][info->layer][bitindex]; |
167 | if(info->bitrate == 0) | 135 | if(info->bitrate == 0) |
168 | return false; | 136 | return false; |
169 | 137 | ||
170 | /* Sampling frequency */ | 138 | /* Sampling frequency */ |
171 | freqindex = (header & 0x0C00) >> 10; | 139 | freqindex = (header & SAMPLERATE_MASK) >> 10; |
172 | info->frequency = freqtab[info->version][freqindex]; | 140 | if (freqindex == 3) |
173 | if(info->frequency == 0) | ||
174 | return false; | 141 | return false; |
142 | info->frequency = freq_table[info->version][freqindex]; | ||
175 | 143 | ||
176 | info->padding = (header & 0x0200)?1:0; | 144 | info->padding = (header & PADDING_MASK) ? 1 : 0; |
177 | 145 | ||
178 | /* Calculate number of bytes, calculation depends on layer */ | 146 | /* Calculate number of bytes, calculation depends on layer */ |
179 | switch(info->layer) { | 147 | if (info->layer == 0) { |
180 | case 0: | 148 | info->frame_samples = 384; |
181 | info->frame_size = info->bitrate * 48000; | 149 | info->frame_size = (12000 * info->bitrate / info->frequency |
182 | info->frame_size /= | 150 | + info->padding) * 4; |
183 | freqtab[info->version][freqindex] << bittable; | 151 | } |
184 | break; | 152 | else { |
185 | case 1: | 153 | if ((info->version > MPEG_VERSION1) && (info->layer == 2)) |
186 | case 2: | 154 | info->frame_samples = 576; |
187 | info->frame_size = info->bitrate * 144000; | 155 | else |
188 | info->frame_size /= | 156 | info->frame_samples = 1152; |
189 | freqtab[info->version][freqindex] << bittable; | 157 | info->frame_size = (1000/8) * info->frame_samples * info->bitrate |
190 | break; | 158 | / info->frequency + info->padding; |
191 | default: | ||
192 | info->frame_size = 1; | ||
193 | } | 159 | } |
194 | 160 | ||
195 | info->frame_size += info->padding; | 161 | /* Frametime fraction calculation. |
196 | 162 | This fraction is reduced as far as possible. */ | |
197 | /* Calculate time per frame */ | 163 | if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */ |
198 | info->frame_time = bs[info->layer] / | 164 | /* integer number of milliseconds, denominator == 1 */ |
199 | (freqtab[info->version][freqindex] << bittable); | 165 | info->ft_num = 1000 * info->frame_samples / info->frequency; |
166 | info->ft_den = 1; | ||
167 | } | ||
168 | else { /* 44.1/22.05/11.025 kHz */ | ||
169 | if (info->layer == 0) { | ||
170 | info->ft_num = 147000 * 384 / info->frequency; | ||
171 | info->ft_den = 147; | ||
172 | } | ||
173 | else { | ||
174 | info->ft_num = 49000 * info->frame_samples / info->frequency; | ||
175 | info->ft_den = 49; | ||
176 | } | ||
177 | } | ||
200 | 178 | ||
201 | info->channel_mode = (header & 0xc0) >> 6; | 179 | info->channel_mode = (header & CHANNELMODE_MASK) >> 6; |
202 | info->mode_extension = (header & 0x30) >> 4; | 180 | info->mode_extension = (header & MODE_EXT_MASK) >> 4; |
203 | info->emphasis = header & 3; | 181 | info->emphasis = header & EMPHASIS_MASK; |
204 | 182 | ||
205 | #ifdef DEBUG_VERBOSE | 183 | #ifdef DEBUG_VERBOSE |
206 | DEBUGF( "Header: %08x, Ver %d, lay %d, bitr %d, freq %d, " | 184 | DEBUGF( "Header: %08x, Ver %d, lay %d, bitr %d, freq %ld, " |
207 | "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d\n", | 185 | "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d/%d\n", |
208 | header, info->version, info->layer+1, info->bitrate, | 186 | header, info->version, info->layer+1, info->bitrate, |
209 | info->frequency, info->channel_mode, info->mode_extension, | 187 | info->frequency, info->channel_mode, info->mode_extension, |
210 | info->emphasis, info->frame_size, info->frame_time); | 188 | info->emphasis, info->frame_size, info->ft_num, info->ft_den); |
211 | #endif | 189 | #endif |
212 | return true; | 190 | return true; |
213 | } | 191 | } |
@@ -252,7 +230,7 @@ static unsigned long __find_next_frame(int fd, long *offset, long max_offset, | |||
252 | if(*offset) | 230 | if(*offset) |
253 | DEBUGF("Warning: skipping %d bytes of garbage\n", *offset); | 231 | DEBUGF("Warning: skipping %d bytes of garbage\n", *offset); |
254 | #endif | 232 | #endif |
255 | 233 | ||
256 | return header; | 234 | return header; |
257 | } | 235 | } |
258 | 236 | ||
@@ -380,9 +358,6 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
380 | 358 | ||
381 | memset(info, 0, sizeof(struct mp3info)); | 359 | memset(info, 0, sizeof(struct mp3info)); |
382 | /* These two are needed for proper LAME gapless MP3 playback */ | 360 | /* These two are needed for proper LAME gapless MP3 playback */ |
383 | /* TODO: These can be found in a LAME Info header as well, but currently | ||
384 | they are only looked for in a Xing header. Xing and Info headers have | ||
385 | the exact same format, but Info headers are used for CBR files. */ | ||
386 | info->enc_delay = -1; | 361 | info->enc_delay = -1; |
387 | info->enc_padding = -1; | 362 | info->enc_padding = -1; |
388 | if(!mp3headerinfo(info, header)) | 363 | if(!mp3headerinfo(info, header)) |
@@ -435,7 +410,10 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
435 | { | 410 | { |
436 | info->frame_count = BYTES2INT(vbrheader[i], vbrheader[i+1], | 411 | info->frame_count = BYTES2INT(vbrheader[i], vbrheader[i+1], |
437 | vbrheader[i+2], vbrheader[i+3]); | 412 | vbrheader[i+2], vbrheader[i+3]); |
438 | info->file_time = info->frame_count * info->frame_time; | 413 | if (info->frame_count <= ULONG_MAX / info->ft_num) |
414 | info->file_time = info->frame_count * info->ft_num / info->ft_den; | ||
415 | else | ||
416 | info->file_time = info->frame_count / info->ft_den * info->ft_num; | ||
439 | i += 4; | 417 | i += 4; |
440 | } | 418 | } |
441 | 419 | ||
@@ -510,7 +488,10 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
510 | vbrheader[12], vbrheader[13]); | 488 | vbrheader[12], vbrheader[13]); |
511 | info->frame_count = BYTES2INT(vbrheader[14], vbrheader[15], | 489 | info->frame_count = BYTES2INT(vbrheader[14], vbrheader[15], |
512 | vbrheader[16], vbrheader[17]); | 490 | vbrheader[16], vbrheader[17]); |
513 | info->file_time = info->frame_count * info->frame_time; | 491 | if (info->frame_count <= ULONG_MAX / info->ft_num) |
492 | info->file_time = info->frame_count * info->ft_num / info->ft_den; | ||
493 | else | ||
494 | info->file_time = info->frame_count / info->ft_den * info->ft_num; | ||
514 | info->bitrate = info->byte_count * 8 / info->file_time; | 495 | info->bitrate = info->byte_count * 8 / info->file_time; |
515 | 496 | ||
516 | /* We don't parse the TOC, since we don't yet know how to (FIXME) */ | 497 | /* We don't parse the TOC, since we don't yet know how to (FIXME) */ |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index ff74cf96a8..8d2d13b6ee 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -348,7 +348,7 @@ static void set_elapsed(struct mp3entry* id3) | |||
348 | /* find wich percent we're at */ | 348 | /* find wich percent we're at */ |
349 | for (i=0; i<100; i++ ) | 349 | for (i=0; i<100; i++ ) |
350 | { | 350 | { |
351 | if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) ) | 351 | if ( id3->offset < id3->toc[i] * (id3->filesize / 256) ) |
352 | { | 352 | { |
353 | break; | 353 | break; |
354 | } | 354 | } |
@@ -388,8 +388,8 @@ static void set_elapsed(struct mp3entry* id3) | |||
388 | } | 388 | } |
389 | } | 389 | } |
390 | else | 390 | else |
391 | /* constant bitrate == simple frame calculation */ | 391 | /* constant bitrate, use exact calculation */ |
392 | id3->elapsed = id3->offset / id3->bpf * id3->tpf; | 392 | id3->elapsed = id3->offset / (id3->bitrate / 8); |
393 | } | 393 | } |
394 | 394 | ||
395 | int audio_get_file_pos(void) | 395 | int audio_get_file_pos(void) |
@@ -405,7 +405,7 @@ int audio_get_file_pos(void) | |||
405 | unsigned int percent, remainder; | 405 | unsigned int percent, remainder; |
406 | int curtoc, nexttoc, plen; | 406 | int curtoc, nexttoc, plen; |
407 | 407 | ||
408 | percent = (id3->elapsed*100)/id3->length; | 408 | percent = (id3->elapsed*100)/id3->length; |
409 | if (percent > 99) | 409 | if (percent > 99) |
410 | percent = 99; | 410 | percent = 99; |
411 | 411 | ||
@@ -431,8 +431,8 @@ int audio_get_file_pos(void) | |||
431 | (id3->elapsed / 1000); | 431 | (id3->elapsed / 1000); |
432 | } | 432 | } |
433 | } | 433 | } |
434 | else if (id3->bpf && id3->tpf) | 434 | else if (id3->bitrate) |
435 | pos = (id3->elapsed/id3->tpf)*id3->bpf; | 435 | pos = id3->elapsed * (id3->bitrate / 8); |
436 | else | 436 | else |
437 | { | 437 | { |
438 | return -1; | 438 | return -1; |