1 /*
2  * mp3plot - Bitrate analysis tool
3  *
4  * Copyright (C) 2007, 2009 Toni Corvera
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 // $Id: frame.cc 1347 2009-06-22 15:53:15Z toni $
22 
23 #include <iostream>
24 #include <cassert>
25 #include <cstring> // memcmp
26 
27 #include "../mp3_config.h" // btoh32
28 #include "frame.h"
29 
30 // References:
31 // [[HA1]] Frame Size, Calc bitrate, length, vbr/cbr etc..
32 //         <http://www.hydrogenaudio.org/forums/index.php?showtopic=52216>
33 // [[HA2]] Is this a MP3 Frame header
34 //         <http://www.hydrogenaudio.org/forums/index.php?showtopic=43172>
35 
36 using std::ifstream;
37 using std::string;
38 using std::ios;
39 using std::cout;
40 
41 namespace {
42     // These are used to avoid showing a warning for each frame tainting the results
43     int unsupported_frequency = 0;
44     int bad_bitrate = 0;
45     int freeform_bitrate = 0;
46     int mpeg25 = 0;
47 }
48 
49 namespace mp3plot {
50 
51 namespace mp3 {
52 
53     using net_outlyer::btoh32;
54 
55 // -- MP3 Frame --
56 
read(ifstream & in)57 void frame::read(ifstream & in) throw (e_error) {
58     using std::cerr;
59     using std::endl;
60 
61     uint8_t sync_header[4];
62     in.read(CHARR(sync_header), 4);
63     if (!in.good()) {
64         throw e_read_failure();
65     }
66 
67     // The sync part is 12 bits, starting on byte-boundary
68     // ((11 bits for the non-standard MPEG 2.5) set to 1
69     if (sync_header[0] != 0xff || (sync_header[1]&0xf0)!=0xf0) {
70        throw e_read_failure("Invalid frame start.", EX_DATAERR);
71     }
72 
73     assert( in.tellg() >= 4 );
74     start = -4;
75     start += in.tellg(); // compiler complains if done in one operation
76 
77     // MPEG Version
78     {
79         // 2nd byte: xxxY Yxxx
80         uint8_t version_field = (sync_header[1] & 0x18) >> 3;
81         mpeg_version = mpeg_version_t(version_field);
82         // TODO: My MPEG2.5 sample doesn't seem to match this, might be a sync issue
83         if (MPEG2_5 == mpeg_version && 0 == mpeg25) {
84             // FIXME: Add support
85             cerr << "WARNING: MPEG 2.5 extensions detected. Information *WILL* be innacurate." << endl;
86             ++mpeg25;
87         }
88 
89         // 2nd byte: xxxx xYYx
90         uint8_t layer_field = (sync_header[1] & 0x06) >> 1;
91         mpeg_layer = mpeg_layer_t(layer_field);
92 
93         // 2nd byte: xxxx xxxY
94         // This works in reverse, 1 means NO CRC
95         crc = 1 != (sync_header[1] & 0x01);
96 
97         // 3rd byte: YYYY xxxx
98         bitrate_index = ( (sync_header[2] & 0xf0) >> 4 );
99         assert( bitrate_index < 0x10 );
100         bitrate_ = bitrate_translator::get(bitrate_index, mpeg_version, mpeg_layer);
101 
102         // 3rd byte: xxxx YYxx
103         uint8_t freq_field = (sync_header[2] & 0x0c) >> 2;
104         switch (freq_field) { // FIXME: The table is different for MPEG-2
105             case 0: freq=44100; break;
106             case 1: freq=48000; break;
107             case 2: freq=32000; break;
108             case 3: freq=0; break; // reserved
109             default:
110                     assert( false );
111                     freq=-1;
112             ;
113         }
114 
115         // Adjust according to MPEG version
116         if (MPEG2_5 == mpeg_version) {
117             freq /= 4;
118         }
119         else if (MPEG2 == mpeg_version) {
120             freq /= 2;
121         }
122 
123         // 3rd byte: xxxx xxYx
124         has_padding = 0 != (sync_header[2] & 0x02);
125 
126         // 3rd byte: xxxx xxxY
127         // Private bit, can be safely discarded
128 
129         // 4th byte: YYxx xxxx
130         channel_mode = static_cast<channel_mode_t>( (sync_header[3] & 0xc0)>>6 );
131 
132         if (bitrate_ == 0) {
133             if (0 == freeform_bitrate) {
134                 cerr << "WARNING: Free-format or corrupted bitstream detected.\n"
135                         "\tInformation might be innacurate." << endl;
136             }
137             ++freeform_bitrate;
138         }
139         else if (bitrate_ == bitrate_translator::bad_bitrate()) {
140             if (0 == bad_bitrate) {
141                 cerr << "WARNING: Illegal value found in the bitrate field.\n"
142                         "\tThis is usually a sign of a corrupted file.\n"
143                         "\tInformation might be innacurate." << endl;
144             }
145             ++bad_bitrate;
146         }
147 
148 #if 0 // FIXME: This breaks the frame detection. Why?
149         if (crc) {
150             // CRC is stored as 16bits immediately following the header
151             in.seekg(2, ios::cur);
152         }
153 #endif
154         // TODO: parse the other fields
155     }
156 }
157 
skip_data(ifstream & in)158 void frame::skip_data(ifstream & in) throw (e_read_failure) {
159     using std::cerr;
160     using std::endl;
161 
162     uint16_t f = freq;
163 
164     if (f == 0) {
165         f = 44100;
166         if (0 == unsupported_frequency) {
167             cerr << "WARNING: Unsupported frequency found, using a sane default.\n"
168                     "\tInformation might be innacurate.\n"
169                     "\tThis warning won't be reported again." << endl;
170         }
171         ++unsupported_frequency;
172     }
173 
174     // Per PRE not allowed
175     assert( bitrate_translator::bad_bitrate() != bitrate_ );
176     if (bitrate_translator::bad_bitrate() == bitrate_) {
177         throw e_read_failure("Attempted to read a frame with bad bitrate");
178     }
179 
180     // Ditto
181     assert( 0 != bitrate_ );
182     if (0 == bitrate_) {
183         throw e_read_failure("Attempted to read a freeform bitstream frame");
184     }
185 
186 
187     const uint16_t factor = get_sample_size() / 8;
188     assert( factor==48 || factor == 72 || factor == 144 );
189 
190     uint32_t framelen = int(factor * (bitrate_ * 1000) / f ) -4;
191     if (has_padding) {
192         // In layer I padding is 4 bytes (that's why the formula is usually given as
193         // '(12 * br / freq + pad) * 4')
194         if (mpeg_layer == LAYER_I) {
195             framelen += 4;
196         }
197         else {
198             ++framelen;
199         }
200     }
201 
202     in.seekg(framelen, ios::cur);
203 }
204 
205 // See [[HA1]], [[HA2]]
206 // static
get_sample_size(mpeg_version_t v,mpeg_layer_t l)207 uint16_t frame::get_sample_size(mpeg_version_t v, mpeg_layer_t l) {
208     // Layer I (MPEG 1 and 2) has 384 samples per frame,
209     // MPEG-1 Layer II and III and MPEG-2 Layer 2 have 1152 samples per frame
210     // MPEG-2 Layer II has 576 samples per frame
211 
212     if (l == LAYER_I) {
213         // MPEG-1/2 Layer I
214         return 384;
215     }
216     if (l == LAYER_III && v == MPEG2) {
217         // MPEG-2 LSF Layer III
218         return 576;
219     }
220     // MPEG-1 Layers II and III, MPEG-2 Layer II
221     return 1152;
222 }
223 
read(ifstream & in)224 void frame_first::read(ifstream & in) throw (e_error) {
225     frame::read(in);
226 
227     using std::cerr;
228 
229     // POST ]-> At end of frame header (4th byte, [3])
230 
231     check_vbr(in);
232     if (!info.is_vbr) {
233         // Note even CBR files can have some VBR due to bit reservoir
234         cerr << "This appears to be a CBR file" << std::endl;
235     }
236 
237     // POST ]-> At 41th frame byte ([40]) || !is_vbr
238 
239     { // TODO: Is this right?
240         in.seekg(3, std::ios_base::cur);
241         in.read(CHARR(&flags), 1);
242     }
243 
244     info.has_filesize = (0 != (flags & FL_FILESIZE));
245     info.has_numframes = (0 != (flags & FL_NUMFRAMES));
246     info.has_toc = (0 != (flags & FL_TOC));
247     info.has_vbr_scale = (0 != (flags & FL_VBR_SCALE));
248 
249     // POST ]-> At 45th frame byte ([44])
250     {
251         if (info.has_numframes) {
252             in.read(CHARR(&info.num_frames), 4);
253             // XXX: is this ok in all arches?
254             info.num_frames = btoh32(info.num_frames);
255         }
256         else {
257             in.seekg(4, ios::cur);
258         }
259 
260         if (info.has_filesize) {
261             in.read(CHARR(&info.file_size), 4);
262             info.file_size = btoh32(info.file_size);
263         }
264         else {
265             in.seekg(4, ios::cur);
266         }
267 
268         // FIXME: Do something with the TOC ?
269         in.seekg(99, ios::cur);
270         // FIXME: Do something with VBR Scale ?
271         in.seekg(4, ios::cur);
272     }
273 }
274 
check_vbr(ifstream & in)275 void frame_first::check_vbr(ifstream & in) throw (e_read_failure) {
276     // PRE ]-> At 4th byte [3]
277 
278     const int BLOCK=36;
279     uint8_t buffer[BLOCK];
280     in.read(CHARR(buffer), BLOCK);
281 
282     int offset=-1;
283     while (!info.is_vbr && ++offset < (BLOCK-3)) {
284         uint8_t * ptr = & (buffer[offset]);
285 
286         if (0 == memcmp(ptr, "Xing", 4)) {
287             info.is_vbr = true;
288             xing_offset = offset + 4; // We started after the first four bytes
289         }
290     }
291     // FIXME: do validity check of offset
292     // // <http://www.multiweb.cz/twoinches/MP3inside.htm>
293     // 36		"Xing" for MPEG1 and CHANNEL != mono (most used)
294     // 21		"Xing" for MPEG1 and CHANNEL == mono
295     // 21		"Xing" for MPEG2 and CHANNEL != mono
296     // 13		"Xing" for MPEG2 and CHANNEL == mono
297 
298     if (!info.is_vbr) { // Return to the CBR frame start
299         in.seekg( -40, std::ios_base::cur );
300     }
301 }
302 
operator <<(std::ostream & os,const frame & f)303 std::ostream & operator<<(std::ostream & os, const frame & f) {
304     string ver, layer, chanmode;
305 
306     switch (f.mpeg_version) {
307         case MPEG1: ver="MPEG v1"; break;
308         case MPEG2: ver="MPEG v2"; break;
309         case MPEG2_5: ver="MPEG v2.5"; break;
310         default: ver="undefined";
311     }
312     switch (f.mpeg_layer) {
313         case LAYER_III: layer="Layer III"; break;
314         case LAYER_II: layer="Layer II"; break;
315         case LAYER_I: layer="Layer I"; break;
316         default: layer="undefined";
317     }
318     switch (f.channel_mode) {
319         case STEREO: chanmode="Stereo"; break;
320         case JOINT_STEREO: chanmode="Joint Stereo"; break;
321         case DUAL_MONO: chanmode="Dual Mono"; break;
322         case MONO: chanmode="Mono"; break;
323         default: chanmode="undefined"; break;
324     }
325 
326     os << "MPEG Version: " << ver << "\n";
327     os << "MPEG Layer: " << layer << "\n";
328     os << "Has CRC: " << (f.crc?"Yes":"No") << "\n";
329     // TODO: Do something on VBR files, this is always 128 and has no meaning AFAIK
330     os << "Nominal bitrate: " << f.bitrate_ << " kbps\n";
331     os << "Sampling rate: " << f.freq << " Hz\n";
332     os << "Channel mode: " << chanmode << "\n";
333 
334     return os;
335 }
336 
337 } // namespace mp3
338 
339 } // namespace mp3plot
340 
341 // vim:set ts=4 et ai:
342 
343