| # Parsers/generators for QuickTime media descriptions | |
| import struct | |
| Error = 'MediaDescr.Error' | |
| class _MediaDescriptionCodec: | |
| def __init__(self, trunc, size, names, fmt): | |
| self.trunc = trunc | |
| self.size = size | |
| self.names = names | |
| self.fmt = fmt | |
| def decode(self, data): | |
| if self.trunc: | |
| data = data[:self.size] | |
| values = struct.unpack(self.fmt, data) | |
| if len(values) != len(self.names): | |
| raise Error, ('Format length does not match number of names') | |
| rv = {} | |
| for i in range(len(values)): | |
| name = self.names[i] | |
| value = values[i] | |
| if type(name) == type(()): | |
| name, cod, dec = name | |
| value = dec(value) | |
| rv[name] = value | |
| return rv | |
| def encode(self, dict): | |
| list = [self.fmt] | |
| for name in self.names: | |
| if type(name) == type(()): | |
| name, cod, dec = name | |
| else: | |
| cod = dec = None | |
| value = dict[name] | |
| if cod: | |
| value = cod(value) | |
| list.append(value) | |
| rv = struct.pack(*list) | |
| return rv | |
| # Helper functions | |
| def _tofixed(float): | |
| hi = int(float) | |
| lo = int(float*0x10000) & 0xffff | |
| return (hi<<16)|lo | |
| def _fromfixed(fixed): | |
| hi = (fixed >> 16) & 0xffff | |
| lo = (fixed & 0xffff) | |
| return hi + (lo / float(0x10000)) | |
| def _tostr31(str): | |
| return chr(len(str)) + str + '\0'*(31-len(str)) | |
| def _fromstr31(str31): | |
| return str31[1:1+ord(str31[0])] | |
| SampleDescription = _MediaDescriptionCodec( | |
| 1, # May be longer, truncate | |
| 16, # size | |
| ('descSize', 'dataFormat', 'resvd1', 'resvd2', 'dataRefIndex'), # Attributes | |
| "l4slhh" # Format | |
| ) | |
| SoundDescription = _MediaDescriptionCodec( | |
| 1, | |
| 36, | |
| ('descSize', 'dataFormat', 'resvd1', 'resvd2', 'dataRefIndex', | |
| 'version', 'revlevel', 'vendor', 'numChannels', 'sampleSize', | |
| 'compressionID', 'packetSize', ('sampleRate', _tofixed, _fromfixed)), | |
| "l4slhhhh4shhhhl" # Format | |
| ) | |
| SoundDescriptionV1 = _MediaDescriptionCodec( | |
| 1, | |
| 52, | |
| ('descSize', 'dataFormat', 'resvd1', 'resvd2', 'dataRefIndex', | |
| 'version', 'revlevel', 'vendor', 'numChannels', 'sampleSize', | |
| 'compressionID', 'packetSize', ('sampleRate', _tofixed, _fromfixed), 'samplesPerPacket', | |
| 'bytesPerPacket', 'bytesPerFrame', 'bytesPerSample'), | |
| "l4slhhhh4shhhhlllll" # Format | |
| ) | |
| ImageDescription = _MediaDescriptionCodec( | |
| 1, # May be longer, truncate | |
| 86, # size | |
| ('idSize', 'cType', 'resvd1', 'resvd2', 'dataRefIndex', 'version', | |
| 'revisionLevel', 'vendor', 'temporalQuality', 'spatialQuality', | |
| 'width', 'height', ('hRes', _tofixed, _fromfixed), ('vRes', _tofixed, _fromfixed), | |
| 'dataSize', 'frameCount', ('name', _tostr31, _fromstr31), | |
| 'depth', 'clutID'), | |
| 'l4slhhhh4sllhhlllh32shh', | |
| ) | |
| # XXXX Others, like TextDescription and such, remain to be done. |