foobar2000 SDK  2015-01-14
mp3_utils.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 
3 using namespace bitreader_helper;
4 
5 static unsigned extract_header_bits(const t_uint8 p_header[4],unsigned p_base,unsigned p_bits)
6 {
7  assert(p_base+p_bits<=32);
8  return (unsigned) extract_bits(p_header,p_base,p_bits);
9 }
10 
11 namespace {
12 
13  class header_parser
14  {
15  public:
16  header_parser(const t_uint8 p_header[4]) : m_bitptr(0)
17  {
18  memcpy(m_header,p_header,4);
19  }
20  unsigned read(unsigned p_bits)
21  {
22  unsigned ret = extract_header_bits(m_header,m_bitptr,p_bits);
23  m_bitptr += p_bits;
24  return ret;
25  }
26  private:
27  t_uint8 m_header[4];
28  unsigned m_bitptr;
29  };
30 }
31 
32 typedef t_uint16 uint16;
33 
34 static const uint16 bitrate_table_l1v1[16] = { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448, 0};
35 static const uint16 bitrate_table_l2v1[16] = { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384, 0};
36 static const uint16 bitrate_table_l3v1[16] = { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320, 0};
37 static const uint16 bitrate_table_l1v2[16] = { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256, 0};
38 static const uint16 bitrate_table_l23v2[16] = { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160, 0};
39 static const uint16 sample_rate_table[] = {11025,12000,8000};
40 
41 unsigned mp3_utils::QueryMPEGFrameSize(const t_uint8 p_header[4])
42 {
44  if (!ParseMPEGFrameHeader(info,p_header)) return 0;
45  return info.m_bytes;
46 }
47 
48 bool mp3_utils::ParseMPEGFrameHeader(TMPEGFrameInfo & p_info,const t_uint8 p_header[4])
49 {
50  enum {MPEG_LAYER_1 = 3, MPEG_LAYER_2 = 2, MPEG_LAYER_3 = 1};
51  enum {_MPEG_1 = 3, _MPEG_2 = 2, _MPEG_25 = 0};
52 
53  header_parser parser(p_header);
54  if (parser.read(11) != 0x7FF) return false;
55  unsigned mpeg_version = parser.read(2);
56  unsigned layer = parser.read(2);
57  unsigned protection = parser.read(1);
58  unsigned bitrate_index = parser.read(4);
59  unsigned sample_rate_index = parser.read(2);
60  if (sample_rate_index == 3) return false;//reserved
61  unsigned paddingbit = parser.read(1);
62  int paddingdelta = 0;
63  parser.read(1);//private
64  unsigned channel_mode = parser.read(2);
65  parser.read(2);//channel_mode_extension
66  parser.read(1);//copyright
67  parser.read(1);//original
68  parser.read(2);//emphasis
69 
70  unsigned bitrate = 0,sample_rate = 0;
71 
72  switch(layer)
73  {
74  default:
75  return false;
76  case MPEG_LAYER_3:
77  paddingdelta = paddingbit ? 1 : 0;
78 
79  p_info.m_layer = 3;
80  switch(mpeg_version)
81  {
82  case _MPEG_1:
83  p_info.m_duration = 1152;
84  bitrate = bitrate_table_l3v1[bitrate_index];
85  break;
86  case _MPEG_2:
87  case _MPEG_25:
88  p_info.m_duration = 576;
89  bitrate = bitrate_table_l23v2[bitrate_index];
90  break;
91  default:
92  return false;
93  }
94 
95  break;
96  case MPEG_LAYER_2:
97  paddingdelta = paddingbit ? 1 : 0;
98  p_info.m_duration = 1152;
99  p_info.m_layer = 2;
100  switch(mpeg_version)
101  {
102  case _MPEG_1:
103  bitrate = bitrate_table_l2v1[bitrate_index];
104  break;
105  case _MPEG_2:
106  case _MPEG_25:
107  bitrate = bitrate_table_l23v2[bitrate_index];
108  break;
109  default:
110  return false;
111  }
112  break;
113  case MPEG_LAYER_1:
114  paddingdelta = paddingbit ? 4 : 0;
115  p_info.m_duration = 384;
116  p_info.m_layer = 1;
117  switch(mpeg_version)
118  {
119  case _MPEG_1:
120  bitrate = bitrate_table_l1v1[bitrate_index];
121  break;
122  case _MPEG_2:
123  case _MPEG_25:
124  bitrate = bitrate_table_l1v2[bitrate_index];
125  break;
126  default:
127  return false;
128  }
129  break;
130  }
131  if (bitrate == 0) return false;
132 
133  sample_rate = sample_rate_table[sample_rate_index];
134  if (sample_rate == 0) return false;
135  switch(mpeg_version)
136  {
137  case _MPEG_1:
138  sample_rate *= 4;
139  p_info.m_mpegversion = MPEG_1;
140  break;
141  case _MPEG_2:
142  sample_rate *= 2;
143  p_info.m_mpegversion = MPEG_2;
144  break;
145  case _MPEG_25:
146  p_info.m_mpegversion = MPEG_25;
147  break;
148  }
149 
150  switch(channel_mode)
151  {
152  case 0:
153  case 1:
154  case 2:
155  p_info.m_channels = 2;
156  break;
157  case 3:
158  p_info.m_channels = 1;
159  break;
160  }
161 
162  p_info.m_channel_mode = channel_mode;
163 
164  p_info.m_sample_rate = sample_rate;
165 
166 
167  p_info.m_bytes = ( bitrate /*kbps*/ * (1000/8) /* kbps-to-bytes*/ * p_info.m_duration /*samples-per-frame*/ ) / sample_rate + paddingdelta;
168 
169  if (p_info.m_layer == 1) p_info.m_bytes &= ~3;
170 
171  p_info.m_crc = protection == 0;
172 
173  return true;
174 }
175 
177 {
179  if (!decode(fr)) return 0;
180  return fr.m_duration;
181 }
182 
183 bool mp3_utils::IsSameStream(TMPEGFrameInfo const & p_frame1,TMPEGFrameInfo const & p_frame2) {
184  return
185  p_frame1.m_channel_mode == p_frame2.m_channel_mode &&
186  p_frame1.m_sample_rate == p_frame2.m_sample_rate &&
187  p_frame1.m_layer == p_frame2.m_layer &&
188  p_frame1.m_mpegversion == p_frame2.m_mpegversion;
189 }
190 
191 
192 
193 bool mp3_utils::ValidateFrameCRC(const t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & info) {
194  if (frameSize < info.m_bytes) return false; //FAIL, incomplete data
195  if (!info.m_crc) return true; //nothing to check, frame appears valid
196  return ExtractFrameCRC(frameData, frameSize, info) == CalculateFrameCRC(frameData, frameSize, info);
197 }
198 
199 static t_uint32 CRC_update(unsigned value, t_uint32 crc)
200 {
201  enum { CRC16_POLYNOMIAL = 0x8005 };
202  unsigned i;
203  value <<= 8;
204  for (i = 0; i < 8; i++) {
205  value <<= 1;
206  crc <<= 1;
207  if (((crc ^ value) & 0x10000)) crc ^= CRC16_POLYNOMIAL;
208  }
209  return crc;
210 }
211 
212 
213 void mp3_utils::RecalculateFrameCRC(t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & info) {
214  PFC_ASSERT( frameSize >= info.m_bytes && info.m_crc );
215 
216  const t_uint16 crc = CalculateFrameCRC(frameData, frameSize, info);
217  frameData[4] = (t_uint8)(crc >> 8);
218  frameData[5] = (t_uint8)(crc & 0xFF);
219 }
220 
221 static t_uint16 grabFrameCRC(const t_uint8 * frameData, t_size sideInfoLen) {
222  t_uint32 crc = 0xffff;
223  crc = CRC_update(frameData[2], crc);
224  crc = CRC_update(frameData[3], crc);
225  for (t_size i = 6; i < sideInfoLen; i++) {
226  crc = CRC_update(frameData[i], crc);
227  }
228 
229  return (t_uint32) (crc & 0xFFFF);
230 }
231 
232 t_uint16 mp3_utils::ExtractFrameCRC(const t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & info) {
233  PFC_ASSERT( frameSize >= info.m_bytes && info.m_crc );
234 
235  return ((t_uint16)frameData[4] << 8) | (t_uint16)frameData[5];
236 
237 }
238 t_uint16 mp3_utils::CalculateFrameCRC(const t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & info) {
239  PFC_ASSERT( frameSize >= info.m_bytes && info.m_crc );
240 
241  t_size sideInfoLen = 0;
242  if (info.m_mpegversion == MPEG_1)
243  sideInfoLen = (info.m_channels == 1) ? 4 + 17 : 4 + 32;
244  else
245  sideInfoLen = (info.m_channels == 1) ? 4 + 9 : 4 + 17;
246 
247  //CRC
248  sideInfoLen += 2;
249 
250  PFC_ASSERT( sideInfoLen <= frameSize );
251 
252  return grabFrameCRC(frameData, sideInfoLen);
253 }
254 
255 
256 bool mp3_utils::ValidateFrameCRC(const t_uint8 * frameData, t_size frameSize) {
257  if (frameSize < 4) return false; //FAIL, not a valid frame
259  if (!ParseMPEGFrameHeader(info, frameData)) return false; //FAIL, not a valid frame
260  return ValidateFrameCRC(frameData, frameSize, info);
261 }
void read(const service_ptr_t< file > &p_file, abort_callback &p_abort, pfc::string_base &p_out, bool &is_utf8)
bool ValidateFrameCRC(const t_uint8 *frameData, t_size frameSize)
Definition: mp3_utils.cpp:256
uint8_t t_uint8
Definition: int_types.h:9
t_uint16 ExtractFrameCRC(const t_uint8 *frameData, t_size frameSize, TMPEGFrameInfo const &frameInfo)
Assumes valid frame with CRC (frameInfo.m_crc set, frameInfo.m_bytes <= frameSize).
Definition: mp3_utils.cpp:232
static const uint16 sample_rate_table[]
Definition: mp3_utils.cpp:39
static t_uint16 grabFrameCRC(const t_uint8 *frameData, t_size sideInfoLen)
Definition: mp3_utils.cpp:221
t_uint16 uint16
Definition: mp3_utils.cpp:32
static const uint16 bitrate_table_l2v1[16]
Definition: mp3_utils.cpp:35
void info(const char *p_message)
Definition: console.cpp:4
static t_size extract_bits(const t_uint8 *p_buffer, t_size p_base, t_size p_count)
static unsigned extract_header_bits(const t_uint8 p_header[4], unsigned p_base, unsigned p_bits)
Definition: mp3_utils.cpp:5
unsigned QueryMPEGFrameSize(const t_uint8 p_header[4])
Definition: mp3_utils.cpp:41
static const uint16 bitrate_table_l3v1[16]
Definition: mp3_utils.cpp:36
static const uint16 bitrate_table_l23v2[16]
Definition: mp3_utils.cpp:38
t_uint16 CalculateFrameCRC(const t_uint8 *frameData, t_size frameSize, TMPEGFrameInfo const &frameInfo)
Assumes valid frame with CRC (frameInfo.m_crc set, frameInfo.m_bytes <= frameSize).
Definition: mp3_utils.cpp:238
bool IsSameStream(TMPEGFrameInfo const &p_frame1, TMPEGFrameInfo const &p_frame2)
Definition: mp3_utils.cpp:183
static t_uint32 CRC_update(unsigned value, t_uint32 crc)
Definition: mp3_utils.cpp:199
size_t t_size
Definition: int_types.h:48
bool ParseMPEGFrameHeader(TMPEGFrameInfo &p_info, const t_uint8 p_header[4])
Definition: mp3_utils.cpp:48
uint16_t t_uint16
Definition: int_types.h:7
void RecalculateFrameCRC(t_uint8 *frameData, t_size frameSize, TMPEGFrameInfo const &frameInfo)
Assumes valid frame with CRC (frameInfo.m_crc set, frameInfo.m_bytes <= frameSize).
Definition: mp3_utils.cpp:213
static const uint16 bitrate_table_l1v1[16]
Definition: mp3_utils.cpp:34
static const uint16 bitrate_table_l1v2[16]
Definition: mp3_utils.cpp:37
unsigned get_samples_per_frame()
Definition: mp3_utils.cpp:176
uint32_t t_uint32
Definition: int_types.h:5