|
1 # Parsers/generators for QuickTime media descriptions |
|
2 import struct |
|
3 |
|
4 Error = 'MediaDescr.Error' |
|
5 |
|
6 class _MediaDescriptionCodec: |
|
7 def __init__(self, trunc, size, names, fmt): |
|
8 self.trunc = trunc |
|
9 self.size = size |
|
10 self.names = names |
|
11 self.fmt = fmt |
|
12 |
|
13 def decode(self, data): |
|
14 if self.trunc: |
|
15 data = data[:self.size] |
|
16 values = struct.unpack(self.fmt, data) |
|
17 if len(values) != len(self.names): |
|
18 raise Error, ('Format length does not match number of names', descr) |
|
19 rv = {} |
|
20 for i in range(len(values)): |
|
21 name = self.names[i] |
|
22 value = values[i] |
|
23 if type(name) == type(()): |
|
24 name, cod, dec = name |
|
25 value = dec(value) |
|
26 rv[name] = value |
|
27 return rv |
|
28 |
|
29 def encode(dict): |
|
30 list = [self.fmt] |
|
31 for name in self.names: |
|
32 if type(name) == type(()): |
|
33 name, cod, dec = name |
|
34 else: |
|
35 cod = dec = None |
|
36 value = dict[name] |
|
37 if cod: |
|
38 value = cod(value) |
|
39 list.append(value) |
|
40 rv = struct.pack(*list) |
|
41 return rv |
|
42 |
|
43 # Helper functions |
|
44 def _tofixed(float): |
|
45 hi = int(float) |
|
46 lo = int(float*0x10000) & 0xffff |
|
47 return (hi<<16)|lo |
|
48 |
|
49 def _fromfixed(fixed): |
|
50 hi = (fixed >> 16) & 0xffff |
|
51 lo = (fixed & 0xffff) |
|
52 return hi + (lo / float(0x10000)) |
|
53 |
|
54 def _tostr31(str): |
|
55 return chr(len(str)) + str + '\0'*(31-len(str)) |
|
56 |
|
57 def _fromstr31(str31): |
|
58 return str31[1:1+ord(str31[0])] |
|
59 |
|
60 SampleDescription = _MediaDescriptionCodec( |
|
61 1, # May be longer, truncate |
|
62 16, # size |
|
63 ('descSize', 'dataFormat', 'resvd1', 'resvd2', 'dataRefIndex'), # Attributes |
|
64 "l4slhh" # Format |
|
65 ) |
|
66 |
|
67 SoundDescription = _MediaDescriptionCodec( |
|
68 1, |
|
69 36, |
|
70 ('descSize', 'dataFormat', 'resvd1', 'resvd2', 'dataRefIndex', |
|
71 'version', 'revlevel', 'vendor', 'numChannels', 'sampleSize', |
|
72 'compressionID', 'packetSize', ('sampleRate', _tofixed, _fromfixed)), |
|
73 "l4slhhhh4shhhhl" # Format |
|
74 ) |
|
75 |
|
76 SoundDescriptionV1 = _MediaDescriptionCodec( |
|
77 1, |
|
78 52, |
|
79 ('descSize', 'dataFormat', 'resvd1', 'resvd2', 'dataRefIndex', |
|
80 'version', 'revlevel', 'vendor', 'numChannels', 'sampleSize', |
|
81 'compressionID', 'packetSize', ('sampleRate', _tofixed, _fromfixed), 'samplesPerPacket', |
|
82 'bytesPerPacket', 'bytesPerFrame', 'bytesPerSample'), |
|
83 "l4slhhhh4shhhhlllll" # Format |
|
84 ) |
|
85 |
|
86 ImageDescription = _MediaDescriptionCodec( |
|
87 1, # May be longer, truncate |
|
88 86, # size |
|
89 ('idSize', 'cType', 'resvd1', 'resvd2', 'dataRefIndex', 'version', |
|
90 'revisionLevel', 'vendor', 'temporalQuality', 'spatialQuality', |
|
91 'width', 'height', ('hRes', _tofixed, _fromfixed), ('vRes', _tofixed, _fromfixed), |
|
92 'dataSize', 'frameCount', ('name', _tostr31, _fromstr31), |
|
93 'depth', 'clutID'), |
|
94 'l4slhhhh4sllhhlllh32shh', |
|
95 ) |
|
96 |
|
97 # XXXX Others, like TextDescription and such, remain to be done. |