1
2
3
4
5
6
7
8
9
10 """ Deal with WMA file format"""
11
12
13 import struct
14
15
16
17
18 ASF_Header_Object_GUID="\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C"
19 ASF_File_Properties_Object_GUID="\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65"
20 ASF_Stream_Properties_Object_GUID="\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65"
21 ASF_Header_Extension_Object_GUID="\xB5\x03\xBF\x5F\x2E\xA9\xCF\x11\x8E\xE3\x00\xC0\x0C\x20\x53\x65"
22 ASF_Content_Description_Object_GUID="\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C"
23 ASF_Extended_Content_Description_Object_GUID="\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50"
24
25
27 - def __init__(self, data, keep_data=False):
28 self.guid=None
29 self.size=None
30 self.data=None
31 if len(data)<24:
32
33 return
34 self.guid=data[:16]
35 self.size=struct.unpack('<Q', data[16:24])[0]
36 self.decode(data[24:self.size])
37 self.valid=bool(self.guid and self.size)
38 if keep_data:
39 self.data=data[:self.size]
40
41 - def unpack(self, format, data, start=0):
45
46
48 - def __init__(self, data, keep_data=False):
50
52 self.file_id=data[:16]
53 (self.file_size, self.creation_date, self.data_packets_count,
54 _play_duration, self.send_duration, self.preroll, _flags,
55 self.min_packet_size, self.max_packet_size,
56 self.max_bitrate)=self.unpack('<QQQQQQLLLL', data, 16)
57 self.play_duration=_play_duration*100e-9
58 self.broadcast_flag=_flags&1
59 self.seekable_flag=_flags&2
60
61
63 - def __init__(self, data, keep_data=False):
66 self.stream_type=data[:16]
67 self.error_correction_type=data[16:32]
68 (self.time_offset, self.type_specific_data_len,
69 self.error_correction_data_len, _flags)=self.unpack('<QLLH', data, 32)
70 self.stream_number=_flags&0x7F
71 self.encrypted_content_flag=_flags&0x8000
72
73
78 self.header_extension_data_size=self.unpack('<L', data, 18)[0]
79
80
82 - def __init__(self, data, keep_data=False):
84 - def _substr(self, data, start, len):
85 if len:
86 _s=str(data[start:start+len]).decode('utf_16_le', 'ignore')
87 if _s[-1]=='\x00':
88 _s=_s[:-1]
89 return (start+len, _s)
90 return (start, '')
91 - def decode(self, data):
92 (_title_len, _author_len, _cpright_len, _desc_len,
93 _rating_len)=self.unpack('<HHHHH', data)
94 _start=10
95 (_start, self.title)=self._substr(data, _start, _title_len)
96 (_start, self.author)=self._substr(data, _start, _author_len)
97 (_start, self.copyright)=self._substr(data, _start, _cpright_len)
98 (_start, self.description)=self._substr(data, _start, _desc_len)
99 (_start, self.rating)=self._substr(data, _start, _rating_len)
100
101
103 - def __init__(self, data, keep_data=False):
106 - def _decode_descriptor(self, data, start, res):
107 _start=start
108 _name_len=self.unpack('<H', data, _start)[0]
109 _start+=2
110 _name=data[_start:_start+_name_len].decode('utf_16_le', 'ignore')
111 if _name[-1]=='\x00':
112 _name=_name[:-1]
113 _start+=_name_len
114 (_value_type,
115 _value_len)=self.unpack('<HH', data, _start)
116 _start+=4
117 if _value_type==0:
118
119 _value=data[_start:_start+_value_len].decode('utf_16_le', 'ignore')
120 if _value[-1]=='\x00':
121 _value=_value[:-1]
122 elif _value_type==1:
123
124 _value=data[_start:_start+_value_len]
125 elif _value_type==2 or _value_type==3:
126 _value=self.unpack('<L', data, _start)[0]
127 elif _value_type==4:
128 _value=self.unpack('<Q', data, _start)[0]
129 elif _value_type==5:
130 _value=self.unpack('<H', data, _start)[0]
131 else:
132 _value=None
133 res[_name]=_value
134 return _start+_value_len
135
136 - def decode(self, data):
137 self.descriptors_count=self.unpack('<H', data)[0]
138 _start=2
139 self.descriptors={}
140 for _cnt in range(self.descriptors_count):
141 _start=self._decode_descriptor(data, _start,
142 self.descriptors)
143
144
176
177
178
179 Object_Table={
180 ASF_Header_Object_GUID: ASF_Header_Object,
181 ASF_File_Properties_Object_GUID: ASF_File_Properties_Object,
182 ASF_Stream_Properties_Object_GUID: ASF_Stream_Properties_Object,
183 ASF_Header_Extension_Object_GUID: ASF_Header_Extension_Object,
184 ASF_Content_Description_Object_GUID: ASF_Content_Description_Object,
185 ASF_Extended_Content_Description_Object_GUID: ASF_Extended_Content_Description_Object,
186 }
187
199
200
203 global Object_Table, ASF_Header_Object_GUID
204 self.valid=False
205 self.header=None
206 self.play_duration=None
207 self.title=None
208 self.author=None
209 self.album=None
210 self.genre=None
211
212 if file_wrapper.size<24 or \
213 file_wrapper.GetBytes(0, 16)!=ASF_Header_Object_GUID:
214 return
215 _size=struct.unpack('<Q', file_wrapper.GetBytes(16, 8))[0]
216 self.header=ASF_Header_Object(file_wrapper.GetBytes(0, _size), False)
217 self.valid=self.header.valid
218 if not self.valid:
219 return
220 if self.header.file_properties and \
221 self.header.file_properties.valid:
222 self.play_duration=self.header.file_properties.play_duration
223 if self.header.content_description and \
224 self.header.content_description.valid:
225 self.title=self.header.content_description.title
226 self.author=self.header.content_description.author
227 if self.header.extended_content_description and \
228 self.header.extended_content_description.valid:
229 _descriptors=self.header.extended_content_description.descriptors
230 self.album=_descriptors.get('WM/AlbumTitle', '')
231 self.genre=_descriptors.get('WM/Genre', '')
232