1 #include "config.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <ctype.h>
9 #include <locale.h>
10 #include <fcntl.h>
11 #include <inttypes.h>
12 #include <time.h>
13
14 #ifndef PRId64
15 # define PRId64 "lld"
16 # define PRIx64 "llx"
17 #endif
18
19 #if BYTE_ORDER == LITTLE_ENDIAN
20 # define SWAP2(x) ((((uint16_t)x>>8) & (uint16_t)0x00ff) |\
21 (((uint16_t)x<<8) & (uint16_t)0xff00))
22
23 # define SWAP4(x) ((((uint32_t)x>>24) & (uint32_t)0x000000ff) |\
24 (((uint32_t)x>>8) & (uint32_t)0x0000ff00) |\
25 (((uint32_t)x<<8) & (uint32_t)0x00ff0000) |\
26 (((uint32_t)x<<24) & (uint32_t)0xff000000))
27
28 # define SWAP8(x) ((((uint64_t)x>>56) & (uint64_t)0x00000000000000ff) |\
29 (((uint64_t)x>>40) & (uint64_t)0x000000000000ff00) |\
30 (((uint64_t)x>>24) & (uint64_t)0x0000000000ff0000) |\
31 (((uint64_t)x>> 8) & (uint64_t)0x00000000ff000000) |\
32 (((uint64_t)x<< 8) & (uint64_t)0x000000ff00000000) |\
33 (((uint64_t)x<<24) & (uint64_t)0x0000ff0000000000) |\
34 (((uint64_t)x<<40) & (uint64_t)0x00ff000000000000) |\
35 (((uint64_t)x<<56) & (uint64_t)0xff00000000000000))
36 #else
37 # define SWAP2(a) (a)
38 # define SWAP4(a) (a)
39 # define SWAP8(a) (a)
40 #endif
41
42 #define MAKEFOURCC(a,b,c,d) ((((uint32_t)a)<<24) | (((uint32_t)b)<<16) | \
43 (((uint32_t)c)<< 8) | ( (uint32_t)d) )
44
45 #define a_clip MAKEFOURCC('c','l','i','p')
46 #define a_co64 MAKEFOURCC('c','o','6','4')
47 #define a_dinf MAKEFOURCC('d','i','n','f')
48 #define a_dref MAKEFOURCC('d','r','e','f')
49 #define a_free MAKEFOURCC('f','r','e','e')
50 #define a_edts MAKEFOURCC('e','d','t','s')
51 #define a_elst MAKEFOURCC('e','l','s','t')
52 #define a_hdlr MAKEFOURCC('h','d','l','r')
53 #define a_mdat MAKEFOURCC('m','d','a','t')
54 #define a_mdhd MAKEFOURCC('m','d','h','d')
55 #define a_mdia MAKEFOURCC('m','d','i','a')
56 #define a_minf MAKEFOURCC('m','i','n','f')
57 #define a_moov MAKEFOURCC('m','o','o','v')
58 #define a_mvhd MAKEFOURCC('m','v','h','d')
59 #define a_skip MAKEFOURCC('s','k','i','p')
60 #define a_smhd MAKEFOURCC('s','m','h','d')
61 #define a_stbl MAKEFOURCC('s','t','b','l')
62 #define a_stco MAKEFOURCC('s','t','c','o')
63 #define a_stsc MAKEFOURCC('s','t','s','c')
64 #define a_stsd MAKEFOURCC('s','t','s','d')
65 #define a_stsh MAKEFOURCC('s','t','s','h')
66 #define a_stss MAKEFOURCC('s','t','s','s')
67 #define a_stsz MAKEFOURCC('s','t','s','z')
68 #define a_stts MAKEFOURCC('s','t','t','s')
69 #define a_tkhd MAKEFOURCC('t','k','h','d')
70 #define a_trak MAKEFOURCC('t','r','a','k')
71 #define a_udta MAKEFOURCC('u','d','t','a')
72 #define a_vmhd MAKEFOURCC('v','m','h','d')
73 #define a_wide MAKEFOURCC('w','i','d','e')
74
75 /* ------------------------------------------------------------------ */
76
77 struct classic_atom {
78 uint32_t size;
79 uint32_t type;
80 uint64_t extsize;
81 };
82
83 struct qt_atom {
84 uint32_t size;
85 uint32_t type;
86 uint64_t extsize;
87 };
88
89 enum field_type {
90 END_OF_LIST = 0,
91 INT16,
92 INT32,
93 INT64,
94 FIX16,
95 FIX32,
96 FOURCC,
97 VER,
98 FLAGS3,
99 TIME,
100 LANG,
101 COLOR,
102 COUNT,
103 RES2,
104 RES4,
105 RES6,
106 RES8,
107 RES10,
108 MATRIX,
109 };
110
111 struct field_list {
112 enum field_type type;
113 char *name;
114 };
115
116 struct atom_list {
117 uint32_t type;
118 struct field_list *fields;
119 };
120
121 struct fcc_names {
122 uint32_t type;
123 char *name;
124 };
125
126 static int handle_classic_atom(int fh, off_t pos, off_t size, int depth);
127 #if 0
128 static int handle_qt_atom(int fh, off_t pos, off_t size, int depth);
129 #endif
130
131 /* ------------------------------------------------------------------ */
132
133 static struct field_list l_co64[] = {
134 { VER, "version" },
135 { FLAGS3, "flags" },
136 { COUNT, "number of entries" },
137 /* FIXME: loop */
138 { INT64, "offset64" },
139 { END_OF_LIST }
140 };
141
142 static struct field_list l_dref[] = {
143 { VER, "version" },
144 { FLAGS3, "flags" },
145 { INT32, "number of entries" },
146 /* FIXME: loop */
147 { INT32, "size" },
148 { FOURCC, "type" },
149 { VER, "version" },
150 { FLAGS3, "flags" },
151 { END_OF_LIST }
152 };
153
154 static struct field_list l_elst[] = {
155 { VER, "version" },
156 { FLAGS3, "flags" },
157 { COUNT, "number of entries" },
158 /* FIXME: loop */
159 { INT32, "track duration" },
160 { INT32, "media time" },
161 { FIX32, "media rate" },
162 { END_OF_LIST }
163 };
164
165 static struct field_list l_hdlr[] = {
166 { VER, "version" },
167 { FLAGS3, "flags" },
168 { FOURCC, "component type" },
169 { FOURCC, "component subtype" },
170 { RES4, "component manufacturer" },
171 { RES4, "component flags" },
172 { RES4, "component flags mask" },
173 /* FIXME: name */
174 { END_OF_LIST }
175 };
176
177 static struct field_list l_mdhd[] = {
178 { VER, "version" },
179 { FLAGS3, "flags" },
180 { TIME, "ctime" },
181 { TIME, "mtime" },
182 { INT32, "time scale" },
183 { INT32, "duration" },
184 { LANG, "language" },
185 { INT16, "quality" },
186 { END_OF_LIST }
187 };
188
189 static struct field_list l_mvhd[] = {
190 { VER, "version" },
191 { FLAGS3, "flags" },
192 { TIME, "ctime" },
193 { TIME, "mtime" },
194 { INT32, "time scale" },
195 { INT32, "duration" },
196 { FIX32, "preferred rate" },
197 { FIX16, "preferred volume" },
198 { RES10, "reserved" },
199 { MATRIX, "matrix" },
200 { INT32, "preview time" },
201 { INT32, "preview duration" },
202 { INT32, "poster time" },
203 { INT32, "selection time" },
204 { INT32, "selection duration" },
205 { INT32, "current time" },
206 { INT32, "next track id" },
207 { END_OF_LIST }
208 };
209
210 static struct field_list l_smhd[] = {
211 { VER, "version" },
212 { FLAGS3, "flags" },
213 { INT16, "balance" },
214 { RES2, "reserved" },
215 { END_OF_LIST }
216 };
217
218 static struct field_list l_stco[] = {
219 { VER, "version" },
220 { FLAGS3, "flags" },
221 { COUNT, "number of entries" },
222 /* FIXME: loop */
223 { INT32, "offset" },
224 { END_OF_LIST }
225 };
226
227 static struct field_list l_stsc[] = {
228 { VER, "version" },
229 { FLAGS3, "flags" },
230 { COUNT, "number of entries" },
231 /* FIXME: loop */
232 { INT32, "first chunk" },
233 { INT32, "samples per chunk" },
234 { INT32, "sample description id" },
235 { END_OF_LIST }
236 };
237
238 static struct field_list l_stsd[] = {
239 { VER, "version" },
240 { FLAGS3, "flags" },
241 { COUNT, "number of entries" },
242 /* FIXME: loop */
243 { INT32, "size" },
244 { FOURCC, "format" },
245 { RES6, "reserved" },
246 { INT16, "data reference index" },
247 { END_OF_LIST }
248 };
249
250 static struct field_list l_stts[] = {
251 { VER, "version" },
252 { FLAGS3, "flags" },
253 { COUNT, "number of entries" },
254 /* FIXME: loop */
255 { INT32, "sample count" },
256 { INT32, "sample duration" },
257 { END_OF_LIST }
258 };
259
260 static struct field_list l_stsz[] = {
261 { VER, "version" },
262 { FLAGS3, "flags" },
263 { INT32, "sample size" },
264 { COUNT, "number of entries" },
265 /* FIXME: loop if "sample size is 0" */
266 #if 0
267 { INT32, "sample size" },
268 #endif
269 { END_OF_LIST }
270 };
271
272 static struct field_list l_tkhd[] = {
273 { VER, "version" },
274 { FLAGS3, "flags" },
275 { TIME, "ctime" },
276 { TIME, "mtime" },
277 { INT32, "track id" },
278 { RES4, "reserved" },
279 { INT32, "duration" },
280 { RES8, "reserved" },
281 { INT16, "layer" },
282 { INT16, "alternate group" },
283 { INT16, "volume" },
284 { RES2, "reserved" },
285 { MATRIX, "matrix" },
286 { FIX32, "width" },
287 { FIX32, "height" },
288 { END_OF_LIST }
289 };
290
291 static struct field_list l_vmhd[] = {
292 { VER, "version" },
293 { FLAGS3, "flags" },
294 { INT16, "graphics mode" },
295 { COLOR, "opcolor" },
296 { END_OF_LIST }
297 };
298
299 static struct atom_list alist[] = {
300 { a_co64, l_co64 },
301 { a_dref, l_dref },
302 { a_elst, l_elst },
303 { a_hdlr, l_hdlr },
304 { a_mdhd, l_mdhd },
305 { a_mvhd, l_mvhd },
306 { a_smhd, l_smhd },
307 { a_stco, l_stco },
308 { a_stsc, l_stsc },
309 { a_stsd, l_stsd },
310 { a_stsz, l_stsz },
311 { a_stts, l_stts },
312 { a_tkhd, l_tkhd },
313 { a_vmhd, l_vmhd },
314 { /* end of list */}
315 };
316
317 /* ------------------------------------------------------------------ */
318
319 static struct fcc_names flist[] = {
320 { a_co64, "chunk offset64 atom" },
321 { a_clip, "movie clipping atom" },
322 { a_dinf, "data information atom" },
323 { a_dref, "data reference atom" },
324 { a_edts, "edit atom" },
325 { a_elst, "edit list atom" },
326 { a_free, "unused space" },
327 { a_hdlr, "handler reference atom" },
328 { a_mdat, "movie data atom" },
329 { a_mdhd, "media header atom" },
330 { a_mdia, "media atom" },
331 { a_minf, "media information atom" },
332 { a_moov, "movie atom" },
333 { a_mvhd, "movie header atom" },
334 { a_skip, "unused space" },
335 { a_smhd, "sound media information header atom" },
336 { a_stbl, "sample table atom" },
337 { a_stco, "chunk offset atom" },
338 { a_stsc, "sample-to-chunk atom" },
339 { a_stsd, "sample description atom" },
340 { a_stsz, "sample size atom" },
341 { a_stts, "time-to-sample atom" },
342 { a_tkhd, "track header atom" },
343 { a_trak, "track atom" },
344 { a_udta, "user data atom" },
345 { a_vmhd, "video media information header atom" },
346 { a_wide, "reserved space for extsize field" },
347 { /* end of list */}
348 };
349
350 /* ------------------------------------------------------------------ */
351
352 static int verbose=0;
353
354 static void swap_classic_atom(struct classic_atom *a)
355 {
356 a->size = SWAP4(a->size);
357 a->type = SWAP4(a->type);
358 a->extsize = SWAP8(a->extsize);
359 }
360
361 #if 0
362 static void swap_qt_atom(struct qt_atom *a)
363 {
364 }
365 #endif
366
367 static int xisprint(int c)
368 {
369 switch (c) {
370 case 169: /* copyright */
371 return 1;
372 default:
373 return isprint(c);
374 }
375 }
376
377 static char* strfcc(uint32_t type)
378 {
379 static char retval[64];
380 int i,l;
381
382 if (xisprint((type >> 24) & 0xff) &&
383 xisprint((type >> 16) & 0xff) &&
384 xisprint((type >> 8) & 0xff) &&
385 xisprint( type & 0xff)) {
386 l = sprintf(retval,"%c%c%c%c",
387 (type >> 24) & 0xff,
388 (type >> 16) & 0xff,
389 (type >> 8) & 0xff,
390 type & 0xff);
391 } else {
392 l = sprintf(retval,"0x%08x",type);
393 }
394 for (i = 0; flist[i].type != 0; i++)
395 if (flist[i].type == type)
396 break;
397 if (flist[i].type != 0)
398 sprintf(retval+l," [%s]",flist[i].name);
399 return retval;
400 }
401
402 #define FIELD_NAME "\t%s%-20s = "
403 static void dump_fields(int fh, off_t pos, struct field_list *list)
404 {
405 char dummy[64],si[8];
406 int i,loop,cpos;
407 int8_t int8;
408 int16_t int16;
409 int32_t int32, fcc, count;
410 int64_t int64;
411 uint16_t color[3];
412 uint32_t uint32;
413 time_t t;
414
415 if (0 == verbose)
416 return;
417 if (-1 == lseek(fh,pos,SEEK_SET)) {
418 perror("lseek");
419 exit(1);
420 }
421 si[0] = 0;
422 count = 0;
423 cpos = 0;
424 loop = 0;
425 for (i = 0; list[i].type != END_OF_LIST || loop < count-1; i++) {
426 switch (list[i].type) {
427 case FOURCC:
428 read(fh,&fcc,sizeof(fcc));
429 printf(FIELD_NAME "%s\n",si,list[i].name,strfcc(SWAP4(fcc)));
430 break;
431 case VER:
432 read(fh,&int8,sizeof(int8));
433 if (verbose > 1 || int8 > 0)
434 printf(FIELD_NAME "%d\n",si,list[i].name,(int)int8);
435 break;
436 case LANG:
437 case INT16:
438 read(fh,&int16,sizeof(int16));
439 printf(FIELD_NAME "%d\n",si,list[i].name,(int)SWAP2(int16));
440 break;
441 case INT32:
442 read(fh,&int32,sizeof(int32));
443 printf(FIELD_NAME "%d\n",si,list[i].name,SWAP4(int32));
444 break;
445 case INT64:
446 read(fh,&int64,sizeof(int64));
447 printf(FIELD_NAME "%" PRId64 "\n",si,list[i].name,SWAP8(int64));
448 break;
449 case FIX16:
450 read(fh,&int16,sizeof(int16));
451 printf(FIELD_NAME "%f\n",si,list[i].name,
452 SWAP2(int16) / 256.0);
453 break;
454 case FIX32:
455 read(fh,&int32,sizeof(int32));
456 printf(FIELD_NAME "%f\n",si,list[i].name,
457 SWAP4(int32) / 65536.0);
458 break;
459 case FLAGS3:
460 read(fh,dummy,3);
461 int32 = dummy[0] << 16 | dummy[1] << 8 | dummy[2];
462 if (verbose > 1 || int32 > 0)
463 printf(FIELD_NAME "0x%06x\n",si,list[i].name,int32);
464 break;
465 case TIME:
466 read(fh,&uint32,sizeof(uint32));
467 t = SWAP4(uint32) - 2082848400;
468 strftime(dummy,sizeof(dummy),"%d. %b %Y - %H:%M:%S",localtime(&t));
469 printf(FIELD_NAME "%s\n",si,list[i].name,dummy);
470 break;
471 case COLOR:
472 read(fh,&color,sizeof(color));
473 printf(FIELD_NAME "%d/%d/%d (rgb)\n",si,list[i].name,
474 (int)SWAP2(color[0]),
475 (int)SWAP2(color[0]),
476 (int)SWAP2(color[0]));
477 break;
478 case RES2:
479 read(fh,dummy,2);
480 break;
481 case RES4:
482 read(fh,dummy,4);
483 break;
484 case RES6:
485 read(fh,dummy,6);
486 break;
487 case RES8:
488 read(fh,dummy,8);
489 break;
490 case RES10:
491 read(fh,dummy,10);
492 break;
493 case MATRIX:
494 read(fh,dummy,36);
495 break;
496 case COUNT:
497 read(fh,&count,sizeof(count));
498 count = SWAP4(count);
499 cpos = i;
500 if (verbose < 2) {
501 printf("\t[list follows]\n");
502 return;
503 }
504 printf(FIELD_NAME "%d\n",si,list[i].name,count);
505 sprintf(si,"[%d] ",loop);
506 break;
507 case END_OF_LIST:
508 i = cpos;
509 loop++;
510 sprintf(si,"[%d] ",loop);
511 break;
512 }
513 }
514 }
515
516 static void dump_string(int fh, off_t pos, off_t size)
517 {
518 off_t off;
519 uint16_t ssize,stype;
520 char *str;
521
522 if (0 == verbose)
523 return;
524 if (-1 == lseek(fh,pos,SEEK_SET)) {
525 perror("lseek");
526 exit(1);
527 }
528 /* FIXME: specs say size is _including_ size+type */
529 for (off = 0; off < size; off += ssize+4) {
530 read(fh,&ssize,sizeof(ssize));
531 read(fh,&stype,sizeof(stype));
532 ssize = SWAP2(ssize);
533 stype = SWAP2(stype);
534 str = malloc(ssize+1);
535 read(fh,str,ssize);
536 str[ssize] = 0;
537 printf("\t%d[%d] = %s\n",(int)stype,(int)ssize,str);
538 free(str);
539 }
540 if (off != size) {
541 fprintf(stderr,"Huh? string size mismatch!\n");
542 exit(1);
543 }
544 }
545
546 static int handle_classic_atom(int fh, off_t pos, off_t size, int depth)
547 {
548 struct classic_atom a;
549 uint64_t asize;
550 size_t off;
551 int i;
552
553 if (-1 == lseek(fh,pos,SEEK_SET)) {
554 perror("lseek");
555 exit(1);
556 }
557 if (sizeof(a) != read(fh,&a,sizeof(a))) {
558 perror("read");
559 exit(1);
560 }
561 swap_classic_atom(&a);
562 switch (a.size) {
563 case 0:
564 asize = size;
565 off = 8;
566 break;
567 case 1:
568 asize = a.extsize;
569 off = 16;
570 break;
571 default:
572 asize = a.size;
573 off = 8;
574 }
575 printf("0x%08" PRIx64 " 0x%08" PRIx64 " %*s%s\n",
576 (int64_t)pos,(int64_t)asize,depth,"",strfcc(a.type));
577 switch (a.type) {
578 case a_dinf:
579 case a_edts:
580 case a_mdia:
581 case a_minf:
582 case a_moov:
583 case a_stbl:
584 case a_trak:
585 case a_udta:
586 while (off < asize)
587 off += handle_classic_atom(fh,pos+off,asize-off,depth+3);
588 if (off != asize) {
589 fprintf(stderr,"Huh? atom size mismatch!\n");
590 exit(1);
591 }
592 break;
593 default:
594 if (169 == ((a.type >> 24) & 0xff)) {
595 dump_string(fh,pos+off,asize-off);
596 } else {
597 for (i = 0; alist[i].type != 0; i++)
598 if (alist[i].type == a.type)
599 break;
600 if (alist[i].type != 0)
601 dump_fields(fh,pos+off,alist[i].fields);
602 }
603 }
604 return asize;
605 }
606
607 #if 0
608 static int handle_qt_atom(int fh, off_t pos, off_t size, int depth)
609 {
610 return 0;
611 }
612 #endif
613
614 /* ------------------------------------------------------------------ */
615
616 static void
617 usage(char *prog)
618 {
619 char *h;
620
621 if (NULL != (h = strrchr(prog,'/')))
622 prog = h+1;
623 fprintf(stderr,
624 "%s - dump structure of quicktime files\n"
625 "\n"
626 "usage: %s [ -j ] [ -e ] filename\n"
627 "options:\n"
628 " -h this text\n"
629 " -v increase verbose level\n"
630 "\n",
631 prog,prog);
632 }
633
634 int main(int argc, char *argv[])
635 {
636 int fh;
637 off_t off,size;
638
639 int c;
640
641 /* parse options */
642 for (;;) {
643 if (-1 == (c = getopt(argc, argv, "hv")))
644 break;
645 switch (c) {
646 case 'v':
647 verbose++;
648 break;
649 case 'h':
650 default:
651 usage(argv[0]);
652 exit(1);
653 }
654 }
655
656 if (optind == argc) {
657 usage(argv[0]);
658 exit(1);
659 }
660
661 setlocale(LC_ALL,NULL);
662 fh = open(argv[optind],O_RDONLY);
663 if (-1 == fh) {
664 fprintf(stderr,"open %s: %s\n",argv[optind],strerror(errno));
665 exit(1);
666 }
667 size = lseek(fh,0,SEEK_END);
668 for (off = 0; off < size;)
669 off += handle_classic_atom(fh,off,size,0);
670 if (off != size) {
671 fprintf(stderr,"Huh? File size mismatch!\n");
672 exit(1);
673 }
674 return 0;
675 }
676
|
This page was automatically generated by the
LXR engine.
|