root/eyeD3/mp3.py

Revision 6ab8361a61197bb0a951e5f77d4d1c5c25a9702f, 11.0 kB (checked in by Jason Michalski <armooo@armooo.net>, 2 years ago)

pyTivo
- ID3 suport for music

  • Property mode set to 100644
Line 
1 ################################################################################
2 #
3 #  Copyright (C) 2002-2005  Travis Shirk <travis@pobox.com>
4 #
5 #  This program is free software; you can redistribute it and/or modify
6 #  it under the terms of the GNU General Public License as published by
7 #  the Free Software Foundation; either version 2 of the License, or
8 #  (at your option) any later version.
9 #
10 #  This program is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU General Public License for more details.
14 #
15 #  You should have received a copy of the GNU General Public License
16 #  along with this program; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 #
19 ################################################################################
20 from binfuncs import *;
21 from utils import *;
22
23 #######################################################################
24 class Mp3Exception(Exception):
25    '''Error reading mp3'''
26
27
28 #                   MPEG1  MPEG2  MPEG2.5
29 SAMPLE_FREQ_TABLE = ((44100, 22050, 11025),
30                      (48000, 24000, 12000),
31                      (32000, 16000, 8000),
32                      (None,  None,  None));
33
34 #              V1/L1  V1/L2 V1/L3 V2/L1 V2/L2&L3
35 BIT_RATE_TABLE = ((0,    0,    0,    0,    0),
36                   (32,   32,   32,   32,   8),
37                   (64,   48,   40,   48,   16),
38                   (96,   56,   48,   56,   24),
39                   (128,  64,   56,   64,   32),
40                   (160,  80,   64,   80,   40),
41                   (192,  96,   80,   96,   44),
42                   (224,  112,  96,   112,  56),
43                   (256,  128,  112,  128,  64),
44                   (288,  160,  128,  144,  80),
45                   (320,  192,  160,  160,  96),
46                   (352,  224,  192,  176,  112),
47                   (384,  256,  224,  192,  128),
48                   (416,  320,  256,  224,  144),
49                   (448,  384,  320,  256,  160),
50                   (None, None, None, None, None));
51
52 #                             L1    L2    L3
53 TIME_PER_FRAME_TABLE = (None, 384, 1152, 1152);
54
55 # Emphasis constants
56 EMPHASIS_NONE = "None";
57 EMPHASIS_5015 = "50/15 ms";
58 EMPHASIS_CCIT = "CCIT J.17";
59
60 # Mode constants
61 MODE_STEREO              = "Stereo";
62 MODE_JOINT_STEREO        = "Joint stereo";
63 MODE_DUAL_CHANNEL_STEREO = "Dual channel stereo";
64 MODE_MONO                = "Mono";
65
66 # Flag bits
67 FRAMES_FLAG    = 0x0001
68 BYTES_FLAG     = 0x0002
69 TOC_FLAG       = 0x0004
70 VBR_SCALE_FLAG = 0x0008
71
72 #######################################################################
73 def computeTimePerFrame(frameHeader):
74    tpf = TIME_PER_FRAME_TABLE[frameHeader.layer];
75    tpf = float(tpf) / float(frameHeader.sampleFreq);
76    return tpf;
77
78 #######################################################################
79 class Header:
80    version = float();
81    layer = int();
82    errorProtection = 0;
83    bitRate = int();
84    playTime = long();
85    sampleFreq = int();
86    padding = 0;
87    privateBit = 0;
88    copyright = 0;
89    original = 0;
90    emphasis = str();
91    mode = str();
92    # This value is left as is: 0 <= modeExtension <= 3.  Consult the
93    # mp3 spec here http://www.dv.co.yu/mpgscript/mpeghdr.htm if you wish to
94    # interpret it.
95    modeExtension = 0;
96
97    # Pass in a 4 byte integer to determine if it matches a valid mp3 frame
98    # header.
99    def isValid(self, header):
100       # Test for the mp3 frame sync: 11 set bits.
101       if (header & 0xffe00000L) != 0xffe00000L:
102          return 0;
103       if not ((header >> 17) & 3):
104          return 0;
105       if ((header >> 12) & 0xf) == 0xf:
106          return 0;
107       if not ((header >> 12) & 0xf):
108          return 0;
109       if ((header >> 10) & 0x3) == 0x3:
110          return 0;
111       if (((header >> 19) & 1) == 1) and (((header >> 17) & 3) == 3) and \
112          (((header >> 16) & 1) == 1):
113          return 0;
114       if (header & 0xffff0000L) == 0xfffe0000L:
115          return 0;
116
117       return 1;
118
119    # This may throw an Mp3Exception if the header is malformed.
120    def decode(self, header):
121       # MPEG audio version from bits 19 and 20.
122       if not header & (1 << 20) and header & (1 << 19):
123          raise Mp3Exception("Illegal MPEG audio version");
124       elif not header & (1 << 20) and not header & (1 << 19):
125          self.version = 2.5;
126       else:
127          if not header & (1 << 19):
128             self.version = 2.0;
129          else:
130             self.version = 1.0;
131
132      
133       # MPEG audio layer from bits 18 and 17.
134       if not header & (1 << 18) and not header & (1 << 17):
135          raise Mp3Exception("Illegal MPEG layer value");
136       elif not header & (1 << 18) and header & (1 << 17):
137          self.layer = 3;
138       elif header & (1 << 18) and not header & (1 << 17):
139          self.layer = 2;
140       else:
141          self.layer = 1;
142
143       # Decode some simple values.
144       self.errorProtection = not (header >> 16) & 0x1;
145       self.padding = (header >> 9) & 0x1;
146       self.privateBit = (header >> 8) & 0x1;
147       self.copyright = (header >> 3) & 0x1;
148       self.original = (header >> 2) & 0x1;
149
150       # Obtain sampling frequency.
151       sampleBits = (header >> 10) & 0x3;
152       if self.version == 2.5:
153          freqCol = 2;
154       else:
155          freqCol = int(self.version - 1);
156       self.sampleFreq = SAMPLE_FREQ_TABLE[sampleBits][freqCol];
157       if not self.sampleFreq:
158          raise Mp3Exception("Illegal MPEG sampling frequency");
159
160
161       # Compute bitrate.
162       bitRateIndex = (header >> 12) & 0xf;
163       if int(self.version) == 1 and self.layer == 1:
164          bitRateCol = 0;
165       elif int(self.version) == 1 and self.layer == 2:
166          bitRateCol = 1;
167       elif int(self.version) == 1 and self.layer == 3:
168          bitRateCol = 2;
169       elif int(self.version) == 2 and self.layer == 1:
170          bitRateCol = 3;
171       elif int(self.version) == 2 and (self.layer == 2 or \
172                                        self.layer == 3):
173          bitRateCol = 4;
174       else:
175          raise Mp3Exception("Mp3 version %f and layer %d is an invalid "\
176                             "combination" % (self.version, self.layer));
177       self.bitRate = BIT_RATE_TABLE[bitRateIndex][bitRateCol];
178       if self.bitRate == None:
179          raise Mp3Exception("Invalid bit rate");
180       # We know know the bit rate specified in this frame, but if the file
181       # is VBR we need to obtain the average from the Xing header.
182       # This is done by the caller since right now all we have is the frame
183       # header.
184
185       # Emphasis; whatever that means??
186       emph = header & 0x3;
187       if emph == 0:
188          self.emphasis = EMPHASIS_NONE;
189       elif emph == 1:
190          self.emphasis = EMPHASIS_5015;
191       elif emph == 2:
192          self.emphasis = EMPHASIS_CCIT;
193       elif strictID3():
194          raise Mp3Exception("Illegal mp3 emphasis value: %d" % emph);
195
196       # Channel mode.
197       modeBits = (header >> 6) & 0x3;
198       if modeBits == 0:
199          self.mode = MODE_STEREO;
200       elif modeBits == 1:
201          self.mode = MODE_JOINT_STEREO;
202       elif modeBits == 2:
203          self.mode = MODE_DUAL_CHANNEL_STEREO;
204       else:
205          self.mode = MODE_MONO;
206       self.modeExtension = (header >> 4) & 0x3;
207
208       # Layer II has restrictions wrt to mode and bit rate.  This code
209       # enforces them.
210       if self.layer == 2:
211          m = self.mode;
212          br = self.bitRate;
213          if (br == 32 or br == 48 or br == 56 or br == 80) and \
214             (m != MODE_MONO):
215             raise Mp3Exception("Invalid mode/bitrate combination for layer "\
216                                "II");
217          if (br == 224 or br == 256 or br == 320 or br == 384) and \
218             (m == MODE_MONO):
219             raise Mp3Exception("Invalid mode/bitrate combination for layer "\
220                                "II");
221
222       br = self.bitRate * 1000;
223       sf = self.sampleFreq;
224       p  = self.padding;
225       if self.layer == 1:
226          # Layer 1 uses 32 bit slots for padding.
227          p  = self.padding * 4;
228          self.frameLength = int((((12 * br) / sf) + p) * 4);
229       else:
230          # Layer 2 and 3 uses 8 bit slots for padding.
231          p  = self.padding * 1;
232          self.frameLength = int(((144 * br) / sf) + p);
233
234       # Dump the state.
235       TRACE_MSG("MPEG audio version: " + str(self.version));
236       TRACE_MSG("MPEG audio layer: " + ("I" * self.layer));
237       TRACE_MSG("MPEG sampling frequency: " + str(self.sampleFreq));
238       TRACE_MSG("MPEG bit rate: " + str(self.bitRate));
239       TRACE_MSG("MPEG channel mode: " + self.mode);
240       TRACE_MSG("MPEG channel mode extension: " + str(self.modeExtension));
241       TRACE_MSG("MPEG CRC error protection: " + str(self.errorProtection));
242       TRACE_MSG("MPEG original: " + str(self.original));
243       TRACE_MSG("MPEG copyright: " + str(self.copyright));
244       TRACE_MSG("MPEG private bit: " + str(self.privateBit));
245       TRACE_MSG("MPEG padding: " + str(self.padding));
246       TRACE_MSG("MPEG emphasis: " + str(self.emphasis));
247       TRACE_MSG("MPEG frame length: " + str(self.frameLength));
248
249 #######################################################################
250 class XingHeader:
251    numFrames = int();
252    numBytes = int();
253    toc = [0] * 100;
254    vbrScale = int();
255
256    # Pass in the first mp3 frame from the file as a byte string.
257    # If an Xing header is present in the file it'll be in the first mp3
258    # frame.  This method returns true if the Xing header is found in the
259    # frame, and false otherwise.
260    def decode(self, frame):
261       # mp3 version
262       id      = (ord(frame[1]) >> 3) & 0x1;
263       # channel mode.
264       mode    = (ord(frame[3]) >> 6) & 0x3;
265
266       # Find the start of the Xing header.
267       if id:
268          if mode != 3:
269             pos = 32 + 4;
270          else:
271             pos = 17 + 4;
272       else:
273          if mode != 3:
274             pos = 17 + 4;
275          else:
276             pos = 9 + 4;
277       if frame[pos] != 'X' or frame[pos + 1] != 'i' or \
278          frame[pos + 2] != 'n' or frame[pos + 3] != 'g':
279          return 0;
280       TRACE_MSG("Xing header detected");
281       pos += 4;
282
283       # Read Xing flags.
284       headFlags = bin2dec(bytes2bin(frame[pos:pos + 4]));
285       pos += 4;
286       TRACE_MSG("Xing header flags: 0x%x" % headFlags);
287
288       # Read frames header flag and value if present
289       if headFlags & FRAMES_FLAG:
290          self.numFrames = bin2dec(bytes2bin(frame[pos:pos + 4]));
291          pos += 4;
292          TRACE_MSG("Xing numFrames: %d" % self.numFrames);
293
294       # Read bytes header flag and value if present
295       if headFlags & BYTES_FLAG:
296          self.numBytes = bin2dec(bytes2bin(frame[pos:pos + 4]));
297          pos += 4;
298          TRACE_MSG("Xing numBytes: %d" % self.numBytes);
299
300       # Read TOC header flag and value if present
301       if headFlags & TOC_FLAG:
302          i = 0;
303          self.toc = frame[pos:pos + 100];
304          pos += 100;
305          TRACE_MSG("Xing TOC (100 bytes): PRESENT");
306       else:
307          TRACE_MSG("Xing TOC (100 bytes): NOT PRESENT");
308
309       # Read vbr scale header flag and value if present
310       if headFlags & VBR_SCALE_FLAG:
311          self.vbrScale = bin2dec(bytes2bin(frame[pos:pos + 4]));
312          pos += 4;
313          TRACE_MSG("Xing vbrScale: %d" % self.vbrScale);
314
315       return 1;
Note: See TracBrowser for help on using the browser.