Module wma_file
[hide private]
[frames] | no frames]

Source Code for Module wma_file

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2006 Joe Pham <djpham@bitpim.org> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: wma_file.py 3608 2006-10-06 02:51:56Z djpham $ 
  9   
 10  """ Deal with WMA file format""" 
 11   
 12  # System modules 
 13  import struct 
 14   
 15  # BitPim modules 
 16   
 17  # constants 
 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  #------------------------------------------------------------------------------- 
26 -class ASF_Object(object):
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 # not a valid ASF Object 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):
42 return struct.unpack(format, data[start:start+struct.calcsize(format)])
43 - def decode(self, data):
44 pass
45 46 #-------------------------------------------------------------------------------
47 -class ASF_File_Properties_Object(ASF_Object):
48 - def __init__(self, data, keep_data=False):
49 super(ASF_File_Properties_Object, self).__init__(data, keep_data)
50
51 - def decode(self, data):
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 #-------------------------------------------------------------------------------
62 -class ASF_Stream_Properties_Object(ASF_Object):
63 - def __init__(self, data, keep_data=False):
64 super(ASF_Stream_Properties_Object, self).__init__(data, keep_data)
65 - def decode(self, data):
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 #-------------------------------------------------------------------------------
74 -class ASF_Header_Extension_Object(ASF_Object):
75 - def __init__(self, data, keep_data=False):
76 super(ASF_Header_Extension_Object, self).__init__(data, keep_data)
77 - def decode(self, data):
78 self.header_extension_data_size=self.unpack('<L', data, 18)[0]
79 80 #-------------------------------------------------------------------------------
81 -class ASF_Content_Description_Object(ASF_Object):
82 - def __init__(self, data, keep_data=False):
83 super(ASF_Content_Description_Object, self).__init__(data, keep_data)
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 #-------------------------------------------------------------------------------
102 -class ASF_Extended_Content_Description_Object(ASF_Object):
103 - def __init__(self, data, keep_data=False):
104 super(ASF_Extended_Content_Description_Object, self).__init__(data, 105 keep_data)
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 # unicode type 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 # byte array 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 #-------------------------------------------------------------------------------
145 -class ASF_Header_Object(ASF_Object):
146 - def __init__(self, data, keep_data=False):
147 # Madatory objects 148 self.file_properties=None 149 self.stream_properties=None 150 self.header_extension=None 151 # List of options objects, not all are recognized and decoded 152 self.content_description=None 153 self.extended_content_description=None 154 super(ASF_Header_Object, self).__init__(data, keep_data)
155 156 _obj_attr_tab={ 157 ASF_File_Properties_Object: 'file_properties', 158 ASF_Stream_Properties_Object: 'stream_properties', 159 ASF_Header_Extension_Object: 'header_extension', 160 ASF_Content_Description_Object: 'content_description', 161 ASF_Extended_Content_Description_Object: 'extended_content_description', 162 } 163
164 - def decode(self, data):
165 self.obj_cnt=self.unpack('<L', data)[0] 166 _start=6 167 for _cnt in range(self.obj_cnt): 168 _obj=Create_ASF_Object(data[_start:], False, ASF_Object) 169 if _obj: 170 _start+=_obj.size 171 _attr_name=self._obj_attr_tab.get(type(_obj), None) 172 if _attr_name: 173 setattr(self, _attr_name, _obj) 174 else: 175 break
176 177 #------------------------------------------------------------------------------- 178 # lookup table for object instantiation 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
188 -def Create_ASF_Object(data, keep_data=False, default_class=None):
189 global Object_Table 190 # look at the data and return a corresponding ASF Object 191 if len(data)<24: 192 # not long enough for an ASF Header block 193 return None 194 _guid=data[:16] 195 if Object_Table.has_key(_guid): 196 return Object_Table[_guid](data, keep_data) 197 if default_class: 198 return default_class(data, keep_data)
199 200 #-------------------------------------------------------------------------------
201 -class WMA_File(object):
202 - def __init__(self, file_wrapper):
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