1 /*
2 * mp3stat - scan mp3 for time and other bitrate info built with some code
3 * from mp3check.
4 * Copyright (c) 2002 by Ed Sweetman <safemode@comcast.net>
5 * mp3check - check mp3 file for consistency and print infos
6 * Copyright (C) 1998 by Johannes Overmann <overmann@iname.com>
7 */
8 #include <unistd.h>
9 #include <sys/stat.h>
10 #include <sys/mman.h>
11 #include <fcntl.h>
12 #include <string>
13
14 #include "mp3stat.h"
15
16 using namespace std;
17
18 int mp3::min_valid = 6;
19 int mp3::FREEFORMAT = 0;
20 int mp3::FORBIDDEN = -1;
21 uint mp3::CONST_MASK = 0xffffffff;
22 int mp3::layer_tab[4] = { 0, 3, 2, 1 };
23 int mp3::bitrate1_tab[16][3] = {
24 {FREEFORMAT, FREEFORMAT, FREEFORMAT},
25 {32, 32, 32},
26 {64, 48, 40},
27 {96, 56, 48},
28 {128, 64, 56},
29 {160, 80, 64},
30 {192, 96, 80},
31 {224, 112, 96},
32 {256, 128, 112},
33 {288, 160, 128},
34 {320, 192, 160},
35 {352, 224, 192},
36 {384, 256, 224},
37 {416, 320, 256},
38 {448, 384, 320},
39 {FORBIDDEN, FORBIDDEN, FORBIDDEN}
40 };
41 int mp3::bitrate2_tab[16][3] = {
42 {FREEFORMAT, FREEFORMAT, FREEFORMAT},
43 {32, 8, 8},
44 {48, 16, 16},
45 {56, 24, 24},
46 {64, 32, 32},
47 {80, 40, 40},
48 {96, 48, 48},
49 {112, 56, 56},
50 {128, 64, 64},
51 {144, 80, 80},
52 {160, 96, 96},
53 {176, 112, 112},
54 {192, 128, 128},
55 {224, 144, 144},
56 {256, 160, 160},
57 {FORBIDDEN, FORBIDDEN, FORBIDDEN}
58 };
59 double mp3::sampd1_tab[4] = { 44.1, 48.0, 32.0, 0.0 };
60 int mp3::samp_1_tab[4] = { 44100, 48000, 32000, 50000 };
61 double mp3::sampd2_tab[4] = { 22.05, 24.0, 16.0, 0.0 };
62 int mp3::samp_2_tab[4] = { 22050, 24000, 16000, 50000 };
63
64 // get header from pointer
65 mp3::Header
get_header(const uchar * p)66 mp3::get_header (const uchar * p)
67 {
68 Header h;
69 uchar *q = (uchar *) & h;
70 q[0] = p[3];
71 q[1] = p[2];
72 q[2] = p[1];
73 q[3] = p[0];
74 return h;
75 }
76
77 // set header to pointer
78 void
set_header(uchar * p,Header h)79 mp3::set_header (uchar * p, Header h)
80 {
81 uchar *q = (uchar *) & h;
82 p[0] = q[3];
83 p[1] = q[2];
84 p[2] = q[1];
85 p[3] = q[0];
86 }
87
88 // return length of frame in bytes
89 int
frame_length(Header h)90 mp3::frame_length (Header h)
91 {
92 if (h.ID) {
93 return ((((h.layer () == 1) ? 48000 : 144000) * h.bitrate ()) /
94 h.samp_int_rate ()) + h.padding_bit;
95 } else {
96 return ((((h.layer () == 1) ? 24000 : 72000) * h.bitrate ()) /
97 h.samp_int_rate ()) + h.padding_bit;
98 }
99 }
100
101 //Detects the next valid header
102 int
find_next_header(const uchar * p,int len,int min_valid)103 mp3::find_next_header (const uchar * p, int len, int min_valid)
104 {
105 int i;
106 const uchar *q = p;
107 const uchar *t;
108 int rest, k, l;
109 Header h, h2;
110 for (i = 0; i < len - 3; i++, q++) {
111 if (*q == 255) {
112 h = get_header (q);
113 l = frame_length (h);
114 if (h.isValid () && (l >= 21)) {
115 t = q + l;
116 rest = len - i - l;
117 for (k = 1; (k < min_valid) && (rest >= 4); k++) {
118 h2 = get_header (t);
119 if (!h2.isValid ())
120 break;
121 if (!h2.sameConstant (h))
122 break;
123 l = frame_length (h2);
124 if (l < 21)
125 break;
126 t += l;
127 rest -= l;
128 }
129 if (k == min_valid)
130 return i;
131 }
132 }
133 }
134 return -1; // not found
135 }
136
137 // Major function ...scans mp3 and gathers info as it does it
138 void
scan_mp3(uchar * p,int len,statistic * mp3info2)139 mp3::scan_mp3 (uchar * p, int len, statistic * mp3info2)
140 {
141 int start = find_next_header (p, len, min_valid);
142 int rest = len;
143 int l, s;
144
145 if (start >= 0) {
146 // check whole file
147 rest -= start;
148 p += start;
149 Header head = get_header (p);
150 l = frame_length (head);
151 p += l;
152 rest -= l;
153 start += l;
154 while (rest >= 4) {
155 Header h = get_header (p);
156 mp3info2->addBit(h.bitrate());
157 if (!(h.isValid () && (frame_length (h) >= 21))) {
158 // invalid header, search for next valid header
159 s = find_next_header (p, rest, min_valid);
160 if (s < 0)
161 break; // error: junk at eof
162 // skips invalid bytes
163 p += s;
164 rest -= s;
165 start += s;
166 } else {
167 head = h;
168 // skip to next frame
169 l = frame_length (h);
170 p += l;
171 rest -= l;
172 start += l;
173 }
174 }
175 }
176 }
177
178 // mmaps mp3 calls scan_mp3 which returns filled status structure mp3info
179 void
statfile(statistic * mp3info2)180 mp3::statfile (statistic * mp3info2)
181 {
182 //create stat accessor
183 struct stat buf;
184 int len;
185 int fd;
186 uchar *p;
187 uchar *free_p;
188 stat (mp3info2->getName().c_str(), &buf);
189 len = buf.st_size;
190 mp3info2->setSize((double) len / 1024);
191 // open file
192 fd = open (mp3info2->getName().c_str(), O_RDONLY);
193 if (fd == -1) {
194 return;
195 }
196 // mmap file
197 p = (uchar *) mmap (0, len, PROT_READ, MAP_SHARED, fd, 0);
198 free_p = p; //this should be left here, scan_mp3 is modifying p
199 if (p == (uchar *) - 1) {
200 return;
201 }
202 scan_mp3 (p, len, mp3info2);
203 // unmap file and close
204 if (munmap ((char *) free_p, len)) {
205 return;
206 }
207 close (fd);
208 }
209
createi()210 extern "C" input* createi() {
211 return new mp3;
212 }
213
destroyi(input * tempIn)214 extern "C" void destroyi(input* tempIn) {
215 delete tempIn;
216 }
217