1 /*
2
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 */
19 // QUIKCONV.C QuickTime file chunk reading and conversion
20 // Rex E. Bradford
21
22 /*
23 * $Source: r:/prj/lib/src/afile/RCS/quikconv.c $
24 * $Revision: 1.2 $
25 * $Author: rex $
26 * $Date: 1994/09/30 16:59:24 $
27 * $Log: quikconv.c $
28 * Revision 1.2 1994/09/30 16:59:24 rex
29 * Modified conversion routines to support writing too
30 *
31 * Revision 1.1 1994/09/27 17:22:58 rex
32 * Initial revision
33 *
34 */
35
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 //#include <dbg.h>
42 //#include <fname.h>
43 #include "quiktime.h"
44
45 typedef struct { // THIS STRUCT MUST MATCH QT_ChunkInfo IN FIRST VARS
46 ulong ctype;
47 uchar isleaf;
48 void (*f_convert)(void *data, ulong length, uchar read);
49 } QT_ChunkInfoAndConvert;
50
51 void ConvertELST(void *data, ulong length, uchar read);
52 void ConvertHDLR(void *data, ulong length, uchar read);
53 void ConvertMDHD(void *data, ulong length, uchar read);
54 void ConvertMVHD(void *data, ulong length, uchar read);
55 void ConvertSMHD(void *data, ulong length, uchar read);
56 void ConvertSTCO(void *data, ulong length, uchar read);
57 void ConvertSTSC(void *data, ulong length, uchar read);
58 void ConvertSTSD(void *data, ulong length, uchar read);
59 void ConvertSTSH(void *data, ulong length, uchar read);
60 void ConvertSTSS(void *data, ulong length, uchar read);
61 void ConvertSTSZ(void *data, ulong length, uchar read);
62 void ConvertSTTS(void *data, ulong length, uchar read);
63 void ConvertTKHD(void *data, ulong length, uchar read);
64 void ConvertVMHD(void *data, ulong length, uchar read);
65
66 QT_ChunkInfoAndConvert chunkInfo[] = {
67 QT_CLIP, FALSE, NULL, QT_CRGN, TRUE, NULL, QT_DINF, FALSE, NULL, QT_DREF, TRUE, NULL,
68 QT_EDTS, FALSE, NULL, QT_ELST, TRUE, ConvertELST, QT_HDLR, TRUE, ConvertHDLR, QT_KMAT, TRUE, NULL,
69 QT_MATT, FALSE, NULL, QT_MDAT, TRUE, NULL, QT_MDIA, FALSE, NULL, QT_MDHD, TRUE, ConvertMDHD,
70 QT_MINF, FALSE, NULL, QT_MOOV, FALSE, NULL, QT_MVHD, TRUE, ConvertMVHD, QT_SMHD, TRUE, ConvertSMHD,
71 QT_STBL, FALSE, NULL, QT_STCO, TRUE, ConvertSTCO, QT_STSC, TRUE, ConvertSTSC, QT_STSD, TRUE, ConvertSTSD,
72 QT_STSH, TRUE, ConvertSTSH, QT_STSS, TRUE, ConvertSTSS, QT_STSZ, TRUE, ConvertSTSZ, QT_STTS, TRUE, ConvertSTTS,
73 QT_TKHD, TRUE, ConvertTKHD, QT_TRAK, FALSE, NULL, QT_UDTA, FALSE, NULL, QT_VMHD, TRUE, ConvertVMHD,
74 0, 0, NULL,
75 };
76
77 TrackType currTrackType;
78
79 /*
80 // --------------------------------------------------------------
81 // PUBLIC FUNCTIONS
82 // --------------------------------------------------------------
83 //
84 // QuikOpenFile() attempts to open a quicktime file for reading.
85
86 FILE *QuikOpenFile(char *filename)
87 {
88 FILE *fp;
89 Fname fname;
90
91 FnameExtract(&fname, filename);
92 FnameAddExt(&fname, "qtm");
93 FnameBuild(filename, &fname);
94 fp = fopen(filename, "rb");
95 return(fp);
96 }
97
98 // --------------------------------------------------------------
99 //
100 // QuikReadChunkHdr() reads in the next chunk header, returns TRUE if ok.
101
102 uchar QuikReadChunkHdr(FILE *fp, QT_ChunkHdr *phdr)
103 {
104 fread(phdr, sizeof(QT_ChunkHdr), 1, fp);
105 Flip4(&phdr->length);
106 Flip4(&phdr->ctype);
107
108 switch (phdr->ctype)
109 {
110 case QT_TRAK:
111 currTrackType = TRACK_OTHER;
112 break;
113
114 case QT_VMHD:
115 currTrackType = TRACK_VIDEO;
116 break;
117
118 case QT_SMHD:
119 currTrackType = TRACK_AUDIO;
120 break;
121 }
122
123 return(feof(fp) == 0);
124 }
125
126 // --------------------------------------------------------------
127 //
128 // QuikSkipChunk() skips over the data in the current chunk.
129
130 void QuikSkipChunk(FILE *fp, QT_ChunkHdr *phdr)
131 {
132 fseek(fp, phdr->length - sizeof(QT_ChunkHdr), SEEK_CUR);
133 }
134
135 // ----------------------------------------------------------------
136 //
137 // QuikReadChunk() reads data in chunk.
138
139 uchar QuikReadChunk(FILE *fp, QT_ChunkHdr *phdr, void *buff, ulong bufflen)
140 {
141 QT_ChunkInfoAndConvert *pinfo;
142
143 if ((phdr->length - sizeof(QT_ChunkHdr)) > bufflen)
144 {
145 Warning(("QuikReadChunk: chunk too big!\n"));
146 return FALSE;
147 }
148
149 fread(buff, phdr->length - sizeof(QT_ChunkHdr), 1, fp);
150
151 pinfo = (QT_ChunkInfoAndConvert *) QuikFindChunkInfo(phdr);
152 if (pinfo && pinfo->f_convert)
153 (*pinfo->f_convert)(buff, phdr->length - sizeof(QT_ChunkHdr), TRUE);
154 return TRUE;
155 }
156 */
157 // --------------------------------------------------------------
158 //
159 // QuikWriteChunkHdr() writes a chunk header.
160
QuikWriteChunkHdr(FILE * fp,QT_ChunkHdr chunkHdr)161 void QuikWriteChunkHdr(FILE *fp, QT_ChunkHdr chunkHdr) {
162 Flip4(&chunkHdr.length);
163 Flip4(&chunkHdr.ctype);
164 fwrite(&chunkHdr, sizeof(chunkHdr), 1, fp);
165 }
166
167 // --------------------------------------------------------------
168 //
169 // QuikWriteChunkLength() writes a chunk length.
170
QuikWriteChunkLength(FILE * fp,long length)171 void QuikWriteChunkLength(FILE *fp, long length) {
172 Flip4(&length);
173 fwrite(&length, sizeof(long), 1, fp);
174 }
175
176 // --------------------------------------------------------------
177 //
178 // QuikWriteChunk() writes a chunk.
179
QuikWriteChunk(FILE * fp,QT_Ctype ctype,void * data,ulong len)180 void QuikWriteChunk(FILE *fp, QT_Ctype ctype, void *data, ulong len) {
181 QT_ChunkInfoAndConvert *pinfo;
182 QT_ChunkHdr chunkHdr;
183
184 chunkHdr.length = len + sizeof(chunkHdr);
185 chunkHdr.ctype = ctype;
186 QuikWriteChunkHdr(fp, chunkHdr);
187
188 if (len) {
189 pinfo = (QT_ChunkInfoAndConvert *)QuikFindChunkInfo(&chunkHdr);
190 if (pinfo && pinfo->f_convert)
191 (*pinfo->f_convert)(data, len, FALSE);
192 fwrite(data, len, 1, fp);
193 }
194 }
195
196 // --------------------------------------------------------------
197 //
198 // QuikFindChunkInfo() finds info for a chunk.
199
QuikFindChunkInfo(QT_ChunkHdr * phdr)200 QT_ChunkInfo *QuikFindChunkInfo(QT_ChunkHdr *phdr) {
201 static QT_Ctype lastType = 0;
202 static QT_ChunkInfoAndConvert *lastInfoPtr = NULL;
203
204 QT_ChunkInfoAndConvert *pinfo;
205
206 if (lastType == phdr->ctype)
207 return ((QT_ChunkInfo *)lastInfoPtr);
208
209 pinfo = chunkInfo;
210 while (pinfo->ctype) {
211 if (pinfo->ctype == phdr->ctype) {
212 lastType = phdr->ctype;
213 lastInfoPtr = pinfo;
214 return ((QT_ChunkInfo *)pinfo);
215 }
216 ++pinfo;
217 }
218 return NULL;
219 }
220
221 // ----------------------------------------------------------------
222 // CONVERTER ROUTINES
223 // ----------------------------------------------------------------
224
ConvertELST(void * data,ulong length,uchar read)225 void ConvertELST(void *data, ulong length, uchar read) {
226 int i;
227 QTS_ELST *p = (QTS_ELST *)data;
228
229 if (read)
230 Flip4(&p->numEntries);
231 for (i = 0; i < p->numEntries; i++) {
232 Flip4(&p->editList[i].trackDuration);
233 Flip4(&p->editList[i].mediaTime);
234 Flip4(&p->editList[i].mediaRate);
235 }
236 if (!read)
237 Flip4(&p->numEntries);
238 }
239
ConvertHDLR(void * data,ulong length,uchar read)240 void ConvertHDLR(void *data, ulong length, uchar read) {
241 QTS_HDLR *p = (QTS_HDLR *)data;
242
243 Flip4(&p->compType);
244 Flip4(&p->compSubtype);
245 Flip4(&p->compManufacturer);
246 Flip4(&p->compFlags);
247 Flip4(&p->compFlagsMask);
248 }
249
ConvertMDHD(void * data,ulong length,uchar read)250 void ConvertMDHD(void *data, ulong length, uchar read) {
251 QTS_MDHD *p = (QTS_MDHD *)data;
252
253 Flip4(&p->createTime);
254 Flip4(&p->modTime);
255 Flip4(&p->timeScale);
256 Flip4(&p->duration);
257 Flip2(&p->language);
258 Flip2(&p->quality);
259 }
260
ConvertMVHD(void * data,ulong length,uchar read)261 void ConvertMVHD(void *data, ulong length, uchar read) {
262 int i;
263 QTS_MVHD *p = (QTS_MVHD *)data;
264
265 Flip4(&p->createTime);
266 Flip4(&p->modTime);
267 Flip4(&p->timeScale);
268 Flip4(&p->duration);
269 Flip4(&p->preferredRate);
270 Flip2(&p->preferredVol);
271 for (i = 0; i < 9; i++)
272 Flip4(&p->matrix[i]);
273 Flip4(&p->previewTime);
274 Flip4(&p->previewDur);
275 Flip4(&p->posterTime);
276 Flip4(&p->selTime);
277 Flip4(&p->selDur);
278 Flip4(&p->currTime);
279 Flip4(&p->nextTrackId);
280 }
281
ConvertSMHD(void * data,ulong length,uchar read)282 void ConvertSMHD(void *data, ulong length, uchar read) {
283 QTS_SMHD *p = (QTS_SMHD *)data;
284
285 Flip2(&p->balance);
286 }
287
ConvertSTCO(void * data,ulong length,uchar read)288 void ConvertSTCO(void *data, ulong length, uchar read) {
289 int i;
290 QTS_STCO *p = (QTS_STCO *)data;
291
292 if (read)
293 Flip4(&p->numEntries);
294 for (i = 0; i < p->numEntries; i++)
295 Flip4(&p->offset[i]);
296 if (!read)
297 Flip4(&p->numEntries);
298 }
299
ConvertSTSC(void * data,ulong length,uchar read)300 void ConvertSTSC(void *data, ulong length, uchar read) {
301 int i;
302 QTS_STSC *p = (QTS_STSC *)data;
303
304 if (read)
305 Flip4(&p->numEntries);
306 for (i = 0; i < p->numEntries; i++) {
307 Flip4(&p->samp2chunk[i].firstChunk);
308 Flip4(&p->samp2chunk[i].sampsPerChunk);
309 Flip4(&p->samp2chunk[i].sampDescId);
310 }
311 if (!read)
312 Flip4(&p->numEntries);
313 }
314
ConvertSTSD(void * data,ulong length,uchar read)315 void ConvertSTSD(void *data, ulong length, uchar read) {
316 QTS_STSD *p = (QTS_STSD *)data;
317
318 Flip4(&p->base.numEntries);
319
320 Flip4(&p->sdesc.descSize);
321 Flip4(&p->sdesc.dataFormat);
322
323 if (currTrackType == TRACK_AUDIO) {
324 Flip2(&p->sdesc.dataRefIndex);
325 Flip2(&p->sdesc.version);
326 Flip2(&p->sdesc.revLevel);
327 Flip4(&p->sdesc.vendor);
328 Flip2(&p->sdesc.numChans);
329 Flip2(&p->sdesc.sampSize);
330 Flip2(&p->sdesc.compId);
331 Flip2(&p->sdesc.packetSize);
332 Flip4(&p->sdesc.sampRate);
333 } else if (currTrackType == TRACK_VIDEO) {
334 Flip2(&p->idesc.dataRefIndex);
335 Flip2(&p->idesc.version);
336 Flip2(&p->idesc.revLevel);
337 Flip4(&p->idesc.vendor);
338 Flip4(&p->idesc.temporalQuality);
339 Flip4(&p->idesc.spatialQuality);
340 Flip2(&p->idesc.width);
341 Flip2(&p->idesc.height);
342 Flip4(&p->idesc.hRes);
343 Flip4(&p->idesc.vRes);
344 Flip4(&p->idesc.dataSize);
345 Flip2(&p->idesc.frameCount);
346 Flip2(&p->idesc.depth);
347 Flip2(&p->idesc.clutId);
348 } else {
349 }
350 }
351
ConvertSTSH(void * data,ulong length,uchar read)352 void ConvertSTSH(void *data, ulong length, uchar read) {
353 int i;
354 QTS_STSH *p = (QTS_STSH *)data;
355
356 if (read)
357 Flip4(&p->numEntries);
358 for (i = 0; i < p->numEntries; i++) {
359 Flip4(&p->shadowSync[i].frameDiffSampNum);
360 Flip4(&p->shadowSync[i].syncSampNum);
361 }
362 if (!read)
363 Flip4(&p->numEntries);
364 }
365
ConvertSTSS(void * data,ulong length,uchar read)366 void ConvertSTSS(void *data, ulong length, uchar read) {
367 int i;
368 QTS_STSS *p = (QTS_STSS *)data;
369
370 if (read)
371 Flip4(&p->numEntries);
372 for (i = 0; i < p->numEntries; i++)
373 Flip4(&p->sample[i]);
374 if (!read)
375 Flip4(&p->numEntries);
376 }
377
ConvertSTSZ(void * data,ulong length,uchar read)378 void ConvertSTSZ(void *data, ulong length, uchar read) {
379 int i;
380 QTS_STSZ *p = (QTS_STSZ *)data;
381
382 Flip4(&p->sampSize);
383 if (read)
384 Flip4(&p->numEntries);
385 if (p->sampSize == 0) {
386 for (i = 0; i < p->numEntries; i++)
387 Flip4(&p->sampSizeTab[i]);
388 }
389 if (!read)
390 Flip4(&p->numEntries);
391 }
392
ConvertSTTS(void * data,ulong length,uchar read)393 void ConvertSTTS(void *data, ulong length, uchar read) {
394 int i;
395 QTS_STTS *p = (QTS_STTS *)data;
396
397 if (read)
398 Flip4(&p->numEntries);
399 for (i = 0; i < p->numEntries; i++) {
400 Flip4(&p->time2samp[i].count);
401 Flip4(&p->time2samp[i].duration);
402 }
403 if (!read)
404 Flip4(&p->numEntries);
405 }
406
ConvertTKHD(void * data,ulong length,uchar read)407 void ConvertTKHD(void *data, ulong length, uchar read) {
408 int i;
409 QTS_TKHD *p = (QTS_TKHD *)data;
410
411 Flip4(&p->createTime);
412 Flip4(&p->modTime);
413 Flip4(&p->trackId);
414 Flip4(&p->duration);
415 Flip2(&p->layer);
416 Flip2(&p->altGroup);
417 Flip2(&p->volume);
418 for (i = 0; i < 9; i++)
419 Flip4(&p->matrix[i]);
420 Flip4(&p->trackWidth);
421 Flip4(&p->trackHeight);
422 }
423
ConvertVMHD(void * data,ulong length,uchar read)424 void ConvertVMHD(void *data, ulong length, uchar read) {
425 int i;
426 QTS_VMHD *p = (QTS_VMHD *)data;
427
428 Flip2(&p->graphicsMode);
429 for (i = 0; i < 3; i++)
430 Flip2(&p->opColor[i]);
431 }
432
433 // ----------------------------------------------------------------
434 // INTERNAL ROUTINES
435 // ----------------------------------------------------------------
436
Flip4Func(ulong * pval4)437 void Flip4Func(ulong *pval4) {
438 //¥¥¥ For mac version
439 // *pval4 = MAKE4(*pval4 & 0xFF,
440 // (*pval4 >> 8) & 0xFF,
441 // (*pval4 >> 16) & 0xFF,
442 // *pval4 >> 24);
443 }
444
Flip2Func(ushort * pval2)445 void Flip2Func(ushort *pval2) {
446 //¥¥¥ For mac version
447 // *pval2 = ((*pval2 & 0xFF) << 8) | ((*pval2 >> 8) & 0xFF);
448 }
449