1 /* QuickTime parsing module for the Bitzi Bitcollider video plugin
2 *
3 * (PD) 2002 Mark Nelson [delirium] <delirium-bitzi@rufus.d2g.com>
4 * Please see file COPYING or http://bitzi.com/publicdomain for more
5 * information.
6 *
7 * The primary reference for the QuickTime file format is:
8 * http://developer.apple.com/techpubs/quicktime/qtdevdocs/QTFF/qtff.html
9 */
10
11 #include "video.h"
12
13 /* QuickTime uses big-endian ordering, and block ("atom") lengths include the
14 * entire atom, including the fourcc specifying atom type and the length
15 * integer itself.
16 */
parse_quicktime(FILE * file,Data * data)17 void parse_quicktime(FILE *file, Data *data)
18 {
19 char fourcc[5];
20 unsigned blockLen;
21 unsigned subBlockLen;
22 unsigned subSubBlockLen;
23 unsigned timescale;
24 long blockStart;
25 long subBlockStart;
26 long subSubBlockStart;
27
28 fseek(file, 4L, SEEK_SET);
29 fread(fourcc, sizeof(char), 4, file);
30 /* If data is first, header's at end of file, so skip to it */
31 if(memcmp(fourcc, "mdat", 4)==0)
32 {
33 fseek(file, 0L, SEEK_SET);
34 blockLen = fread_be(file, 4);
35 fseek(file, (long) (blockLen + 4), SEEK_SET);
36 fread(fourcc, sizeof(char), 4, file);
37 }
38
39 if(memcmp(fourcc, "moov", 4)!=0)
40 return;
41 blockStart = ftell(file);
42 blockLen = fread_be(file, 4); /* mvhd length */
43 fread(fourcc, sizeof(char), 4, file);
44 if(memcmp(fourcc, "mvhd", 4)!=0)
45 return;
46
47 /* Now we're at the start of the movie header */
48
49 /* 20: time scale (time units per second) (4 bytes) */
50 fseek(file, blockStart + 20, SEEK_SET);
51 timescale = fread_be(file, 4);
52
53 /* 24: duration in time units (4 bytes) */
54 data->duration = (unsigned int) round_double((double) fread_be(file, 4)
55 / timescale * 1000);
56
57 /* Skip the rest of the mvhd */
58 fseek(file, blockStart + blockLen, SEEK_SET);
59
60 /* Find and parse trak atoms */
61 while(!feof(file))
62 {
63 unsigned int width, height;
64
65 /* Find the next trak atom */
66 blockStart = ftell(file);
67 blockLen = fread_be(file, 4); /* trak (or other atom) length */
68 fread(fourcc, sizeof(char), 4, file);
69 if(memcmp(fourcc, "trak", 4)!=0) /* If it's not a trak atom, skip it */
70 {
71 if(!feof(file))
72 fseek(file, blockStart + blockLen, SEEK_SET);
73 continue;
74 }
75
76 subBlockStart = ftell(file);
77 subBlockLen = fread_be(file, 4); /* tkhd length */
78 fread(fourcc, sizeof(char), 4, file);
79 if(memcmp(fourcc, "tkhd", 4)!=0)
80 return;
81
82 /* Now in the track header */
83
84 /* 84: width (2 bytes) */
85 fseek(file, subBlockStart + 84, SEEK_SET);
86 width = fread_be(file, 2);
87
88 /* 88: height (2 bytes) */
89 fseek(file, subBlockStart + 88, SEEK_SET);
90 height = fread_be(file, 2);
91
92 /* Note on above: Apple's docs say that width/height are 4-byte integers,
93 * but all files I've seen have the data stored in the high-order two
94 * bytes, with the low-order two being 0x0000. Interpreting it the
95 * "official" way would make width/height be thousands of pixels each.
96 */
97
98 /* Skip rest of tkhd */
99 fseek(file, subBlockStart + subBlockLen, SEEK_SET);
100
101 /* Find mdia atom for this trak */
102 subBlockStart = ftell(file);
103 subBlockLen = fread_be(file, 4);
104 fread(fourcc, sizeof(char), 4, file);
105 while(memcmp(fourcc, "mdia", 4)!=0)
106 {
107 fseek(file, subBlockStart + subBlockLen, SEEK_SET);
108 subBlockStart = ftell(file);
109 subBlockLen = fread_be(file, 4);
110 fread(fourcc, sizeof(char), 4, file);
111 }
112
113 /* Now we're in the mdia atom; first sub-atom should be mdhd */
114 subSubBlockStart = ftell(file);
115 subSubBlockLen = fread_be(file, 4);
116 fread(fourcc, sizeof(char), 4, file);
117 if(memcmp(fourcc, "mdhd", 4)!=0)
118 return;
119 /* TODO: extract language from the mdhd? For now skip to hdlr. */
120 fseek(file, subSubBlockStart + subSubBlockLen, SEEK_SET);
121 subSubBlockStart = ftell(file);
122 subSubBlockLen = fread_be(file, 4);
123 fread(fourcc, sizeof(char), 4, file);
124 if(memcmp(fourcc, "hdlr", 4)!=0)
125 return;
126 /* 12: Component type: "mhlr" or "dhlr"; we only care about mhlr,
127 * which should (?) appear first */
128 fseek(file, subSubBlockStart + 12, SEEK_SET);
129 fread(fourcc, sizeof(char), 4, file);
130 if(memcmp(fourcc, "mhlr", 4)!=0)
131 return;
132 fread(fourcc, sizeof(char), 4, file);
133 if(memcmp(fourcc, "vide", 4)==0) /* This is a video trak */
134 {
135 data->height = height;
136 data->width = width;
137 }
138
139 /* Skip rest of the trak */
140 fseek(file, blockStart + blockLen, SEEK_SET);
141 }
142 }
143