#include #include #include #include #include #include #include extern const char *__progname; typedef struct track TRACK; struct track { TRACK *link; unsigned int data; unsigned int len; } ; static int file_fd; static const char *filename; static const unsigned char *file; static unsigned int filesize; static unsigned int moov_at = 0; static unsigned int moov_len; static unsigned int mdat_at = 0; static unsigned int mdat_len; static TRACK *tracks = 0; #define FOURCHAR(a,b,c,d) ( ((a) * 0x01000000) + \ ((b) * 0x010000) + \ ((c) * 0x0100) + \ ((d) * 0x01) ) static void usage(void) { fprintf(stderr,"Usage: %s filename\n",__progname); exit(1); } static void map_file(const char *name) { struct stat stb; void *mmrv; filename = name; file_fd = open(name,O_RDONLY,0); if (file_fd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,name,strerror(errno)); exit(1); } fstat(file_fd,&stb); filesize = stb.st_size; if (filesize != stb.st_size) { fprintf(stderr,"%s: %s: too large\n",__progname,name); exit(1); } mmrv = mmap(0,stb.st_size,PROT_READ,MAP_FILE|MAP_SHARED,file_fd,0); if (mmrv == MAP_FAILED) { fprintf(stderr,"%s: mmap %s: %s\n",__progname,name,strerror(errno)); exit(1); } file = mmrv; } static unsigned int get4be(unsigned int o) { return( (file[o ] * 0x01000000) + (file[o+1] * 0x010000) + (file[o+2] * 0x0100) + (file[o+3] * 0x01) ); } static unsigned long long int get8be(unsigned int o) { return( (file[o ] * 0x0100000000000000ULL) + (file[o+1] * 0x01000000000000ULL) + (file[o+2] * 0x010000000000ULL) + (file[o+3] * 0x0100000000ULL) + (file[o+4] * 0x01000000ULL) + (file[o+5] * 0x010000ULL) + (file[o+6] * 0x0100ULL) + (file[o+7] * 0x01ULL) ); } static void print_str_vis(FILE *to, const unsigned char *d, int len) { int i; for (i=len;i>0;i--) { if (*d < 32) { fprintf(to,"^%c",64+*d); } else if (*d < 127) { putc(*d,to); } else if (*d == 127) { fprintf(to,"^?"); } else if (*d < 160) { fprintf(to,"^%c",64+*d); } else { putc(*d,to); } d ++; } } static void scan_chunks(unsigned int start, unsigned int len, void (*chunk)(const unsigned char [4], unsigned int, unsigned int)) { unsigned int o; unsigned int l; o = 0; while (1) { if (o == len) break; if (o+8 > len) { printf("*** chunk overrun 1 (%u+8 > %u)\n",o,len); exit(1); } l = get4be(start+o); if (l == 1) { printf("*** 64-bit chunk length at %u+%u\n",start,o); exit(1); } if (l < 8) { printf("*** runt chunk (%u) at %u+%u\n",l,start,o); exit(1); } printf("%08x+%08x: chunk len=%x type=",start,o,l); print_str_vis(stdout,file+start+o+4,4); printf("\n"); if (o+l > len) { printf("*** chunk overrun 2 (%u+%u > %u)\n",o,l,len); exit(1); } (*chunk)(file+start+o+4,start+o+8,l-8); o += l; } } static void file_chunk(const unsigned char type[4], unsigned int data, unsigned int len) { int i; switch (FOURCHAR(type[0],type[1],type[2],type[3])) { default: printf("skipping unknown chunk\n"); return; break; case FOURCHAR('f','t','y','p'): if (len < 8) { printf("*** ftyp chunk too small (%u)\n",len); return; } if (len % 4) { printf("*** ftyp chunk length (%u) isn't a multiple of 4\n",len); return; } printf("ftyp: major `"); print_str_vis(stdout,file+data,4); printf("' minor %08x compat:",get4be(data+4)); for (i=8;idata = data; t->len = len; t->link = tracks; tracks = t; } static void moov_chunk(const unsigned char type[4], unsigned int data, unsigned int len) { switch (FOURCHAR(type[0],type[1],type[2],type[3])) { default: printf("skipping unknown chunk\n"); return; break; case FOURCHAR('m','v','h','d'): { unsigned char ver; unsigned long long int dur; unsigned int ts; if (len < 1) { printf("*** mvhd chunk too small 1 (%u)\n",len); return; } ver = file[data]; /* XXX what are the possible ver values? my reference gives some values and says ver 1 has others, but is it really 1-vs-not-1, or is it 0 and 1 and others not yet defined, or what? */ if (len < ((ver==1) ? 32 : 20)) { printf("*** mvhd chunk too small 2 (%u, ver=%d)\n",len,ver); return; } if (ver == 1) { ts = get4be(data+20); dur = get8be(data+24); } else { ts = get4be(data+12); dur = get4be(data+16); } printf("movie: ts=%u dur=%llu\n",ts,dur); } break; case FOURCHAR('t','r','a','k'): save_track(data,len); break; case FOURCHAR('u','d','t','a'): break; } } int main(int, char **); int main(int ac, char **av) { if (ac != 2) usage(); map_file(av[1]); printf("scanning file\n"); scan_chunks(0,filesize,&file_chunk); if (moov_at == 0) printf("no `moov' chunk\n"); if (mdat_at == 0) printf("no `mdat' chunk\n"); if (moov_at && mdat_at) { printf("scanning moov chunk\n"); scan_chunks(moov_at,moov_len,&moov_chunk); } return(0); }