MythTV  master
audiofile.py
Go to the documentation of this file.
1 # -*- Mode: python; coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*-
2 """
3 read audio stream from audio file
4 """
5 
6 import os
7 import struct
8 
9 class UnknownFormat(Exception):pass
10 class FormatError(Exception):pass
11 
12 class AudioFile(object):
13  f = None
14  audioStart = 0
15 
16  def AudioFile(self):
17  self.f = None
18  self.audioStart = 0
19 
20  def Open(self,filename):
21  self.audioStart = 0
22  self.f = file(filename)
23  ext = os.path.splitext(filename)[1].lower()
24  if ext == '.mp3': self.AnalyzeMp3()
25  elif ext == '.ogg': self.AnalyzeOgg()
26  elif ext == '.wma': self.AnalyzeWma()
27  #elif ext == '.flac': self.AnalyzeFlac()
28  elif ext == '.flac': pass
29  elif ext == '.ape': pass
30  elif ext == '.wav': pass
31  else: # not supported format
32  self.f.close()
33  self.f = None
34  raise UnknownFormat
35 
36  def Close(self):
37  self.f.close()
38  self.f = None
39 
40  def ReadAudioStream(self, len, offset=0):
41  self.f.seek(self.audioStart+offset, 0)
42  return self.f.read(len)
43 
44  def AnalyzeMp3(self):
45  # Searching ID3v2 tag
46  while True:
47  buf = self.f.read(3)
48  if len(buf) < 3 or self.f.tell() > 50000:
49  # ID tag is not found
50  self.f.seek(0,0)
51  self.audioStart = 0
52  return
53  if buf == 'ID3':
54  self.f.seek(3,1) # skip version/flag
55  # ID length (synchsafe integer)
56  tl = struct.unpack('4b', self.f.read(4))
57  taglen = (tl[0]<<21)|(tl[1]<<14)|(tl[2]<<7)|tl[3]
58  self.f.seek(taglen,1)
59  break
60  self.f.seek(-2,1)
61  # Searching MPEG SOF
62  while True:
63  buf = self.f.read(1)
64  if len(buf) < 1 or self.f.seek(0,1) > 1000000:
65  raise FormatError
66  if buf == '\xff':
67  rbit = struct.unpack('B',self.f.read(1))[0] >> 5
68  if rbit == 7: # 11 1's in total
69  self.f.seek(-2,1)
70  self.audioStart = self.f.tell()
71  return
72 
73  def AnalyzeOgg(self):
74  # Parse page (OggS)
75  while True:
76  buf = self.f.read(27) # header
77  if len(buf) < 27 or self.f.tell() > 50000:
78  # parse error
79  raise FormatError
80  if buf[0:4] != 'OggS':
81  # not supported page format
82  raise UnknownFormat
83  numseg = struct.unpack('B', buf[26])[0]
84  #print "#seg: %d" % numseg
85 
86  segtbl = struct.unpack('%dB'%numseg, self.f.read(numseg)) # segment table
87  for seglen in segtbl:
88  buf = self.f.read(7) # segment header
89  #print "segLen(%s): %d" % (buf[1:7],seglen)
90  if buf == "\x05vorbis":
91  self.f.seek(-7,1) # rollback
92  self.audioStart = self.f.tell()
93  return
94  self.f.seek(seglen-7,1) # skip to next segment
95 
96  def AnalyzeWma(self):
97  # Searching GUID
98  while True:
99  buf = self.f.read(16)
100  if len(buf) < 16 or self.f.tell() > 50000:
101  raise FormatError
102  guid = buf.encode("hex");
103  if guid == "3626b2758e66cf11a6d900aa0062ce6c":
104  # ASF_Data_Object
105  self.f.seek(-16,1) # rollback
106  self.audioStart = self.f.tell()
107  return
108  else:
109  objlen = struct.unpack('<Q', self.f.read(8))[0]
110  self.f.seek(objlen-24,1) # jump to next object
111 
112  def AnalyzeFlac(self):
113  if self.f.read(4) != 'fLaC':
114  raise UnknownFormat
115  # Searching GUID
116  while True:
117  buf = self.f.read(4)
118  if len(buf) < 16 or self.f.tell() > 50000:
119  # not found
120  raise FormatError
121  metalen = buf[1] | (buf[2]<<8) | (buf[3]<<16);
122  self.f.seek(metalen,1) # skip this metadata block
123  if buf[0] & 0x80:
124  # it was the last metadata block
125  self.audioStart = self.f.tell()
126  return
127 
common.audiofile.AudioFile.audioStart
int audioStart
Definition: audiofile.py:14
common.audiofile.UnknownFormat
Definition: audiofile.py:9
discid.disc.read
def read(device=None, features=[])
Definition: disc.py:35
common.audiofile.AudioFile.ReadAudioStream
def ReadAudioStream(self, len, offset=0)
Definition: audiofile.py:40
build_compdb.file
file
Definition: build_compdb.py:55
common.audiofile.AudioFile.AudioFile
def AudioFile(self)
Definition: audiofile.py:16
close
#define close
Definition: compat.h:43
common.audiofile.FormatError
Definition: audiofile.py:10
common.audiofile.AudioFile.Close
def Close(self)
Definition: audiofile.py:36
common.audiofile.AudioFile.AnalyzeWma
def AnalyzeWma(self)
Definition: audiofile.py:96
common.audiofile.AudioFile.Open
def Open(self, filename)
Definition: audiofile.py:20
common.audiofile.AudioFile.f
f
Definition: audiofile.py:13
common.audiofile.AudioFile
Definition: audiofile.py:12
common.audiofile.AudioFile.AnalyzeMp3
def AnalyzeMp3(self)
Definition: audiofile.py:44
common.audiofile.AudioFile.AnalyzeFlac
def AnalyzeFlac(self)
Definition: audiofile.py:112
common.audiofile.AudioFile.AnalyzeOgg
def AnalyzeOgg(self)
Definition: audiofile.py:73