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