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')
|
---|
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(self, 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.
|
---|