id3lib  3.8.3
mp3_parse.cpp
Go to the documentation of this file.
1 // -*- C++ -*-
2 // $Id: mp3_parse.cpp,v 1.6 2002/11/02 17:48:51 t1mpy Exp $
3 
4 // id3lib: a C++ library for creating and manipulating id3v1/v2 tags
5 // Copyright 2002, Thijmen Klok (thijmen@id3lib.org)
6 
7 // This library is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU Library General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or (at your
10 // option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU Library General Public License
18 // along with this library; if not, write to the Free Software Foundation,
19 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 
21 // The id3lib authors encourage improvements and optimisations to be sent to
22 // the id3lib coordinator. Please see the README file for details on where to
23 // send such submissions. See the AUTHORS file for a list of people who have
24 // contributed to id3lib. See the ChangeLog file for a list of changes to
25 // id3lib. These files are distributed with id3lib at
26 // http://download.sourceforge.net/id3lib/
27 
28 #include "mp3_header.h"
29 
30 #define FRAMES_FLAG 0x0001
31 #define BYTES_FLAG 0x0002
32 #define TOC_FLAG 0x0004
33 #define SCALE_FLAG 0x0008
34 
35 static int ExtractI4(unsigned char *buf)
36 {
37  int x;
38  // big endian extract
39 
40  x = buf[0];
41  x <<= 8;
42  x |= buf[1];
43  x <<= 8;
44  x |= buf[2];
45  x <<= 8;
46  x |= buf[3];
47 
48  return x;
49 }
50 
51 uint32 fto_nearest_i(float f)
52 {
53  uint32 i;
54 
55  i = (uint32)f;
56  if (i < f)
57  {
58  f -= i;
59  if (f >= 0.5)
60  return i+1;
61  else
62  return i;
63  }
64  else
65  return i;
66 }
67 
68 uint16 calcCRC(char *pFrame, size_t audiodatasize)
69 {
70  size_t icounter;
71  int tmpchar, crcmask, tmpi;
72  uint16 crc = 0xffff;
73 
74  for (icounter = 2; icounter < audiodatasize; ++icounter)
75  {
76  if (icounter != 4 && icounter != 5) //skip the 2 chars of the crc itself
77  {
78  crcmask = 1 << 8;
79  tmpchar = pFrame[icounter];
80  while (crcmask >>= 1)
81  {
82  tmpi = crc & 0x8000;
83  crc <<= 1;
84  if (!tmpi ^ !(tmpchar & crcmask))
85  crc ^= 0x8005;
86  }
87  }
88  }
89  crc &= 0xffff;
90  return crc;
91 }
92 
94 {
95  if (_mp3_header_output != NULL)
96  delete _mp3_header_output;
97  _mp3_header_output = NULL;
98 }
99 
100 using namespace dami;
101 
102 bool Mp3Info::Parse(ID3_Reader& reader, size_t mp3size)
103 {
104  MP3_BitRates _mp3_bitrates[2][3][16] =
105  {
106  {
107  { //MPEG 1, LAYER I
124  },
125  { //MPEG 1, LAYER II
142  },
143  { //MPEG 1, LAYER III
160  }
161  },
162  {
163  { //MPEG 2 or 2.5, LAYER I
180  },
181  { //MPEG 2 or 2.5, LAYER II
198  },
199  { //MPEG 2 or 2.5, LAYER III
216  }
217  }
218  };
219 
220  Mp3_Frequencies _mp3_frequencies[4][4] =
221  {
226  };
227 
228  _mp3_header_internal *_tmpheader;
229 
230  const size_t HEADERSIZE = 4;//
231  char buf[HEADERSIZE+1]; //+1 to hold the \0 char
232  ID3_Reader::pos_type beg = reader.getCur() ;
233  ID3_Reader::pos_type end = beg + HEADERSIZE ;
234  reader.setCur(beg);
235  int bitrate_index;
236 
237  _mp3_header_output->layer = MPEGLAYER_FALSE;
238  _mp3_header_output->version = MPEGVERSION_FALSE;
239  _mp3_header_output->bitrate = MP3BITRATE_FALSE;
240  _mp3_header_output->channelmode = MP3CHANNELMODE_FALSE;
241  _mp3_header_output->modeext = MP3MODEEXT_FALSE;
242  _mp3_header_output->emphasis = MP3EMPHASIS_FALSE;
243  _mp3_header_output->crc = MP3CRC_MISMATCH;
244  _mp3_header_output->frequency = 0;
245  _mp3_header_output->framesize = 0;
246  _mp3_header_output->frames = 0;
247  _mp3_header_output->time = 0;
248  _mp3_header_output->vbr_bitrate = 0;
249 
250  reader.readChars(buf, HEADERSIZE);
251  buf[HEADERSIZE]='\0';
252  // copy the pointer to the struct
253 
254  if (((buf[0] & 0xFF) != 0xFF) || ((buf[1] & 0xE0) != 0xE0)) //first 11 bits should be 1
255  {
256  this->Clean();
257  return false;
258  }
259 
260  _tmpheader = reinterpret_cast<_mp3_header_internal *>(buf);
261 
262  bitrate_index = 0;
263  switch (_tmpheader->id)
264  {
265  case 3:
266  _mp3_header_output->version = MPEGVERSION_1;
267  bitrate_index = 0;
268  break;
269  case 2:
270  _mp3_header_output->version = MPEGVERSION_2;
271  bitrate_index = 1;
272  break;
273  case 1:
274  this->Clean();
275  return false; //wouldn't know how to handle it
276  break;
277  case 0:
278  _mp3_header_output->version = MPEGVERSION_2_5;
279  bitrate_index = 1;
280  break;
281  default:
282  this->Clean();
283  return false;
284  break;
285  };
286 
287  switch (_tmpheader->layer)
288  {
289  case 3:
290  _mp3_header_output->layer = MPEGLAYER_I;
291  break;
292  case 2:
293  _mp3_header_output->layer = MPEGLAYER_II;
294  break;
295  case 1:
296  _mp3_header_output->layer = MPEGLAYER_III;
297  break;
298  case 0:
299  this->Clean();
300  return false; //wouldn't know how to handle it
301  break;
302  default:
303  this->Clean();
304  return false; //how can two unsigned bits be something else??
305  break;
306  };
307 
308  // mpegversion, layer and bitrate are all valid
309  _mp3_header_output->bitrate = _mp3_bitrates[bitrate_index][3-_tmpheader->layer][_tmpheader->bitrate_index];
310  if (_mp3_header_output->bitrate == MP3BITRATE_FALSE)
311  {
312  this->Clean();
313  return false;
314  }
315  _mp3_header_output->frequency = _mp3_frequencies[_tmpheader->id][_tmpheader->frequency];
316  if (_mp3_header_output->frequency == MP3FREQUENCIES_Reserved)
317  {
318  this->Clean();
319  return false;
320  }
321 
322  _mp3_header_output->privatebit = (bool)_tmpheader->private_bit;
323  _mp3_header_output->copyrighted = (bool)_tmpheader->copyright;
324  _mp3_header_output->original = (bool)_tmpheader->original;
325  _mp3_header_output->crc = (Mp3_Crc)!(bool)_tmpheader->protection_bit;
326 
327  switch (_tmpheader->mode)
328  {
329  case 3:
330  _mp3_header_output->channelmode = MP3CHANNELMODE_SINGLE_CHANNEL;
331  break;
332  case 2:
333  _mp3_header_output->channelmode = MP3CHANNELMODE_DUAL_CHANNEL;
334  break;
335  case 1:
336  _mp3_header_output->channelmode = MP3CHANNELMODE_JOINT_STEREO;
337  break;
338  case 0:
339  _mp3_header_output->channelmode = MP3CHANNELMODE_STEREO;
340  break;
341  default:
342  this->Clean();
343  return false; //wouldn't know how to handle it
344  break;
345  }
346 
347  if (_mp3_header_output->channelmode == MP3CHANNELMODE_JOINT_STEREO)
348  {
349  // these have a different meaning for different layers, better give them a generic name in the enum
350  switch (_tmpheader->mode_ext)
351  {
352  case 3:
353  _mp3_header_output->modeext = MP3MODEEXT_3;
354  break;
355  case 2:
356  _mp3_header_output->modeext = MP3MODEEXT_2;
357  break;
358  case 1:
359  _mp3_header_output->modeext = MP3MODEEXT_1;
360  break;
361  case 0:
362  _mp3_header_output->modeext = MP3MODEEXT_0;
363  break;
364  default:
365  this->Clean();
366  return false; //wouldn't know how to handle it
367  break;
368  }
369  }
370  else //it's valid to have a valid false one in this case, since it's only used with joint stereo
371  _mp3_header_output->modeext = MP3MODEEXT_FALSE;
372 
373  switch (_tmpheader->emphasis)
374  {
375  case 3:
376  _mp3_header_output->emphasis = MP3EMPHASIS_CCIT_J17;
377  break;
378  case 2:
379  _mp3_header_output->emphasis = MP3EMPHASIS_Reserved;
380  break;
381  case 1:
382  _mp3_header_output->emphasis = MP3EMPHASIS_50_15MS;
383  break;
384  case 0:
385  _mp3_header_output->emphasis = MP3EMPHASIS_NONE;
386  break;
387  default:
388  this->Clean();
389  return false; //wouldn't know how to handle it
390  break;
391  }
392 
393 //http://www.mp3-tech.org/programmer/frame_header.html
394  if (_mp3_header_output->bitrate != MP3BITRATE_NONE && _mp3_header_output->frequency > 0)
395  {
396 
397  switch(_mp3_header_output->layer)
398  {
399  case MPEGLAYER_I: // Layer 1
400  _mp3_header_output->framesize = 4 * (12 * _mp3_header_output->bitrate / _mp3_header_output->frequency + (_tmpheader->padding_bit ? 1 : 0));
401  break;
402  case MPEGLAYER_II: // Layer 2
403  _mp3_header_output->framesize = 144 * _mp3_header_output->bitrate / _mp3_header_output->frequency + (_tmpheader->padding_bit ? 1 : 0);
404  break;
405  case MPEGLAYER_III: // Layer 3
406  if(_mp3_header_output->version == MPEGVERSION_2_5)
407  _mp3_header_output->framesize = 144 * _mp3_header_output->bitrate / _mp3_header_output->frequency + (_tmpheader->padding_bit ? 1 : 0); //Mpeg1
408  else
409  _mp3_header_output->framesize = 72000 * _mp3_header_output->bitrate / _mp3_header_output->frequency + (_tmpheader->padding_bit ? 1 : 0); //Mpeg2 + Mpeg2.5
410  break;
411  }
412 // if (_mp3_header_output->layer == MPEGLAYER_I)
413 // _mp3_header_output->framesize = fto_nearest_i((float)((48 * (float)_mp3_header_output->bitrate) / _mp3_header_output->frequency)) + (_tmpheader->padding_bit ? 4 : 0);
414 // else
415 // _mp3_header_output->framesize = fto_nearest_i((float)((144 * (float)_mp3_header_output->bitrate) / _mp3_header_output->frequency)) + (_tmpheader->padding_bit ? 1 : 0);
416  }
417  else
418  _mp3_header_output->framesize = 0; //unable to determine
419 
420  const size_t CRCSIZE = 2;
421  size_t sideinfo_len;
422 
423  if (_mp3_header_output->version == MPEGVERSION_1) /* MPEG 1 */
424  sideinfo_len = (_mp3_header_output->channelmode == MP3CHANNELMODE_SINGLE_CHANNEL) ? 4 + 17 : 4 + 32;
425  else /* MPEG 2 */
426  sideinfo_len = (_mp3_header_output->channelmode == MP3CHANNELMODE_SINGLE_CHANNEL) ? 4 + 9 : 4 + 17;
427 
428  int vbr_header_offest = beg + sideinfo_len;
429  int vbr_frames = 0;
430 
431  sideinfo_len += 2; // add two for the crc itself
432 
433  if ((_mp3_header_output->crc == MP3CRC_OK) && mp3size < sideinfo_len)
434  _mp3_header_output->crc = MP3CRC_ERROR_SIZE;
435 
436  if (_mp3_header_output->crc == MP3CRC_OK)
437  {
438  char audiodata[38 + 1]; //+1 to hold the 0 char
439  uint16 crc16;
440  uint16 crcstored;
441 
442  _mp3_header_output->crc = MP3CRC_MISMATCH; //as a starting point, we assume the worst
443 
444  reader.setCur(beg);
445 
446  reader.readChars(audiodata, sideinfo_len);
447  audiodata[sideinfo_len] = '\0';
448 
449  crc16 = calcCRC(audiodata, sideinfo_len);
450 
451  beg = end;
452  end = beg + CRCSIZE;
453 
454  reader.setCur(beg);
455  crcstored = (uint16)io::readBENumber(reader, CRCSIZE);
456 
457  // a mismatch doesn't mean the file is unusable
458  // it has just some bits in the wrong place
459  if (crcstored == crc16)
460  _mp3_header_output->crc = MP3CRC_OK;
461  }
462 
463  // read xing/vbr header if present
464  // derived from code in vbrheadersdk.zip
465  // from http://www.xingtech.com/developer/mp3/
466 
467  const size_t VBR_HEADER_MIN_SIZE = 8; // "xing" + flags are fixed
468  const size_t VBR_HEADER_MAX_SIZE = 116; // frames, bytes, toc and scale are optional
469 
470  if (mp3size >= vbr_header_offest + VBR_HEADER_MIN_SIZE)
471  {
472  char vbrheaderdata[VBR_HEADER_MAX_SIZE+1]; //+1 to hold the 0 char
473  unsigned char *pvbrdata = (unsigned char *)vbrheaderdata;
474  int vbr_filesize = 0;
475  int vbr_scale = 0;
476  int vbr_flags = 0;
477 
478  // get fixed part of vbr header
479  // and check if valid
480 
481  beg = vbr_header_offest;
482  reader.setCur(beg);
483  reader.readChars(vbrheaderdata, VBR_HEADER_MIN_SIZE);
484  vbrheaderdata[VBR_HEADER_MIN_SIZE] = '\0';
485 
486  if (pvbrdata[0] == 'X' &&
487  pvbrdata[1] == 'i' &&
488  pvbrdata[2] == 'n' &&
489  pvbrdata[3] == 'g')
490  {
491  // get vbr flags
492  pvbrdata += 4;
493  vbr_flags = ExtractI4(pvbrdata);
494  pvbrdata += 4;
495 
496  // read entire vbr header
497  int vbr_header_size = VBR_HEADER_MIN_SIZE
498  + ((vbr_flags & FRAMES_FLAG)? 4:0)
499  + ((vbr_flags & BYTES_FLAG)? 4:0)
500  + ((vbr_flags & TOC_FLAG)? 100:0)
501  + ((vbr_flags & SCALE_FLAG)? 4:0);
502 
503  if (mp3size >= vbr_header_offest + vbr_header_size)
504  {
505  reader.readChars(&vbrheaderdata[VBR_HEADER_MIN_SIZE], vbr_header_size - VBR_HEADER_MIN_SIZE);
506  vbrheaderdata[vbr_header_size] = '\0';
507 
508  // get frames, bytes, toc and scale
509 
510  if (vbr_flags & FRAMES_FLAG)
511  {
512  vbr_frames = ExtractI4(pvbrdata);
513  pvbrdata +=4;
514  }
515 
516  if (vbr_flags & BYTES_FLAG)
517  {
518  vbr_filesize = ExtractI4(pvbrdata);
519  pvbrdata +=4;
520  }
521 
522  if (vbr_flags & TOC_FLAG)
523  {
524  // seek offsets
525  // we are not using
526  // for(i=0;i<100;i++) seek_offsets[i] = pvbrdata[i];
527 
528  pvbrdata +=100;
529  }
530 
531  if (vbr_flags & SCALE_FLAG)
532  {
533  vbr_scale = ExtractI4(pvbrdata);
534  pvbrdata +=4;
535  }
536 
537  if (vbr_frames > 0)
538  {
539  _mp3_header_output->vbr_bitrate = (((vbr_filesize!=0) ? vbr_filesize : mp3size) / vbr_frames) * _mp3_header_output->frequency / 144;
540  _mp3_header_output->vbr_bitrate -= _mp3_header_output->vbr_bitrate%1000; // round the bitrate:
541  }
542  }
543  }
544  }
545 
546  if (_mp3_header_output->framesize > 0 && mp3size >= _mp3_header_output->framesize) // this means bitrate is not none too
547  {
548  if (vbr_frames == 0)
549  _mp3_header_output->frames = fto_nearest_i((float)mp3size / _mp3_header_output->framesize);
550  else
551  _mp3_header_output->frames = vbr_frames;
552 
553  // bitrate becomes byterate (per second) if divided by 8
554  if (_mp3_header_output->vbr_bitrate == 0)
555  _mp3_header_output->time = fto_nearest_i( (float)mp3size / (_mp3_header_output->bitrate / 8) );
556  else
557  _mp3_header_output->time = fto_nearest_i( (float)mp3size / (_mp3_header_output->vbr_bitrate / 8) );
558  }
559  else
560  {
561  _mp3_header_output->frames = 0;
562  _mp3_header_output->time = 0;
563  }
564  //if we got to here it's okay
565  return true;
566 }
567 
568 
#define TOC_FLAG
Definition: mp3_parse.cpp:32
MP3_BitRates
Definition: globals.h:423
virtual pos_type getCur()=0
Return the current position in the reader.
virtual pos_type setCur(pos_type pos)=0
Set the value of the current position for reading.
virtual size_type readChars(char_type buf[], size_type len)=0
Read up to len characters into buf and advance the internal position accordingly. ...
#define BYTES_FLAG
Definition: mp3_parse.cpp:31
uint32 fto_nearest_i(float f)
Definition: mp3_parse.cpp:51
#define SCALE_FLAG
Definition: mp3_parse.cpp:33
Definition: tag_impl.h:41
Mp3_Frequencies
Definition: globals.h:471
Mp3_Crc
Definition: globals.h:513
bool Parse(ID3_Reader &, size_t mp3size)
Definition: mp3_parse.cpp:102
#define FRAMES_FLAG
Definition: mp3_parse.cpp:30
uint16 calcCRC(char *pFrame, size_t audiodatasize)
Definition: mp3_parse.cpp:68
#define NULL
Definition: globals.h:743
void Clean()
Definition: mp3_parse.cpp:93
uint32 pos_type
Definition: reader.h:38