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