1 /***************************************************************************
2 Small scanner for avi/openDML streams
3
4
5 ***************************************************************************/
6
7 /***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <string.h>
21 #include <math.h>
22
23 #define uint8_t unsigned char
24 #define uint32_t unsigned long int
25 #define uint64_t unsigned long long int
26 //#define QUIET
27
28 #ifdef QUIET
29 #define Q(c) NULL
30 #else
31 #define Q(x) x
32 #endif
33 int nesting=0;
34 int parse(int maxSize);
35 void riff(int maxSize);
36 void skip(int maxSize);
37 void list(int maxSize);
38 void indx(int maxSize);
39 void ix(int maxSize);
40 void idx1(int maxSize);
41
42 #define xprintf for(int i=0;i<nesting;i++) printf("\t");printf
43
44 FILE *fd=NULL;
45 //
46 typedef struct
47 {
48 const char *tag;
49 bool recurse;
50 void (*func)(int maxSize);
51 }chunkDesc;
52 //
53 chunkDesc allChunks[]=
54 {
55 {"RIFF",false,riff},
56 {"AVI ",true,NULL},
57 {"LIST",false,list},
58 {"avih",false,NULL},
59 {"strh",false,NULL},
60 {"strf",false,NULL},
61 {"indx",false,Q(indx)},
62 {"ix00",false,Q(ix)},
63 {"ix01",false,Q(ix)},
64 {"00dc",false,NULL},
65 {"01wd",false,NULL},
66 {"JUNK",false,NULL},
67 {"idx1",false,Q(idx1)},
68
69 {NULL,true,NULL}
70
71 };
read32()72 uint32_t read32()
73 {
74 uint32_t r=0;
75 for(int i=0;i<4;i++)
76 {
77 int x=fgetc(fd);
78 r=r+(x<<(8*i));
79 }
80 return r;
81 }
read64()82 uint64_t read64()
83 {
84 uint64_t r=0;
85 for(int i=0;i<8;i++)
86 {
87 int x=fgetc(fd);
88 r=r+(x<<(8*i));
89 //r=(r<<8)+x;
90 }
91 return r;
92 }
93 //
lookupChunk(const char * n)94 chunkDesc *lookupChunk(const char *n)
95 {
96 chunkDesc *c=allChunks;
97 while(1)
98 {
99 if(!c->tag) return NULL;
100 if(!strcmp(c->tag,n)) return c;
101 c++;
102 }
103 return NULL;
104 }
105 //
ix(int maxSize)106 void ix(int maxSize)
107 {
108 uint64_t base;
109 uint32_t pos=ftello(fd);
110 skip(4);
111 uint32_t n,fcc;
112 n=read32();
113 fcc=read32();
114 char xfcc[5];
115 *(uint32_t *)xfcc=fcc;
116 xfcc[4]=0;
117 base=read64();
118 read32();
119 xprintf("At 0x%lx, found regular index for %s,nbEntries=%d base=0x%llx\n",pos,xfcc,(int)n,base);
120 for(int i=0;i<n;i++)
121 {
122 uint64_t off=read32();
123 uint32_t size=read32();
124 xprintf("at offset 0x%llx, absolute offset=0x%llx size=%d\n",
125 off,off+base,(int)(size&0x7fffffff));
126 }
127 fseeko(fd,pos+maxSize,SEEK_SET);
128
129 }
idx1(int maxSize)130 void idx1(int maxSize)
131 {
132 int n=maxSize/16;
133 for(int i=0;i<n;i++)
134 {
135 uint32_t fcc=read32();
136 char xfcc[5];
137 *(uint32_t *)xfcc=fcc;
138 xfcc[4]=0;
139 uint32_t y=read32();
140 uint32_t z=read32();
141 uint32_t t=read32();
142 xprintf("\t %s : off=0x%x size=%d\n",xfcc,z,t);
143 }
144 }
145 //
indx(int maxSize)146 void indx(int maxSize)
147 {
148 uint32_t pos=ftello(fd);
149 skip(4);
150 uint32_t n,fcc;
151 n=read32();
152 fcc=read32();
153 char xfcc[5];
154 *(uint32_t *)xfcc=fcc;
155 xfcc[4]=0;
156 read32();
157 read32();
158 read32();
159 xprintf("At 0x%lx, found index for %s,nbEntries=%d\n",pos,xfcc,(int)n);
160 for(int i=0;i<n;i++)
161 {
162 uint64_t off=read64();
163 uint32_t size=read32();
164 uint32_t duration=read32();
165 xprintf("at offset 0x%llx, size=%d, duration=%d\n",off,(int)size,(int)duration);
166 }
167 fseeko(fd,pos+maxSize,SEEK_SET);
168
169 }
skip(int maxSize)170 void skip(int maxSize)
171 {
172 fseeko(fd,maxSize,SEEK_CUR);
173 }
174 //---
riff(int maxSize)175 void riff(int maxSize)
176 {
177 skip(4);
178 maxSize-=4;
179 uint64_t tail=ftello(fd)+maxSize;
180 while(1)
181 {
182 if(ftello(fd)==tail) return;
183 int size=tail-ftello(fd);
184 parse(size);
185 }
186
187 }
list(int maxSize)188 void list(int maxSize)
189 {
190 char y[5];
191 fread(y,4,1,fd);
192 maxSize-=4;
193 y[4]=0;
194 xprintf("\t of type %s\n",y);
195 if(!strcmp(y,"index"))
196 return skip(maxSize);
197 #ifdef QUIET
198 if(!strcmp(y,"movi"))
199 return skip(maxSize);
200 #endif
201 //
202 uint64_t tail=ftello(fd)+maxSize;
203 while(1)
204 {
205 if(ftello(fd)==tail) return;
206 int size=tail-ftello(fd);
207 parse(size);
208 }
209
210 }
211 //_____________________________
212 //_____________________________
main(int argc,char ** argv)213 int main(int argc, char **argv)
214 {
215 if(!argv[1]) exit(0);
216
217 fd=fopen(argv[1],"rb");
218 if(!fd)
219 {
220
221 xprintf("Cannot open %s\n",argv[1]);
222 }
223 fseeko(fd,0,SEEK_END);
224 uint64_t fileSize=ftello(fd);
225 fseeko(fd,0,SEEK_SET);
226 xprintf("Scanning file %s, size=%llu\n",argv[1],fileSize);
227 parse(fileSize);
228 fclose(fd);
229 xprintf("\nDone.\n");
230 }
231
232 // Parse until we find a PES header to identify the stream
233 //
parse(int maxSize)234 int parse(int maxSize)
235 {
236 uint8_t fcc[5],len[5];
237 uint64_t pos=ftell(fd);
238 fread(fcc,4,1,fd);
239 fread(len,4,1,fd);
240 nesting++;
241 fcc[4]=0;
242 uint64_t l=len[0]+(len[1]<<8)+(len[2]<<16)+(len[3]<<24);
243 if(l&1) l++;
244 xprintf("Found tag %s len=%llu at pos %llx\n",fcc,l,pos);
245 const chunkDesc *chunk=lookupChunk((const char *)fcc);
246 bool recurse=false;
247 if(!chunk)
248 {
249 xprintf("Unknown chunk\n");
250 xprintf("Skipping\n");
251 fseeko(fd,l,SEEK_CUR);
252 }else
253 {
254 if(chunk->func)
255 chunk->func(l);
256 else
257 if(chunk->recurse==true)
258 parse(l);
259 else
260 {
261 xprintf("Skipping\n");
262 skip(l);
263 }
264 }
265 uint64_t pos2=ftell(fd);
266 if(pos+l+8!=pos2)
267 {
268 xprintf("Mismatch : 0x%llx != 0x%llx + 0x%llx +8\n",pos2,pos,l);
269 xprintf("Mismatch : %lld != %lld + %lld +8\n",pos2,pos,l);
270 exit(-1);
271 }
272 nesting--;
273 return 0;
274 }
275