|
接上一篇
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <strings.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include "libavi.h"
16
17 // 18 // compare two indices' offset 19 // returns: 20 // 1 if elem1's offset large than elem2's 21 // 0 if equal 22 // -1 if less 23 // 24 int avi_idx_cmp(const void * elem1, const void * elem2)
25 {
26 AVIIDX1ENTRY * e1 = (AVIIDX1ENTRY *)elem1;
27 AVIIDX1ENTRY * e2 = (AVIIDX1ENTRY *)elem2;
28 DWORD a = e1->dwOffset;
29 DWORD b = e2->dwOffset;
30 return (a > b) - (b > a);
31 }
32
33 // 34 // initializae: return 0 35 // 36 int
37 avi_init(AVI * avi)
38 {
39 // clear aviheader 40 memset(&avi->aviheader, 0, sizeof(AVIHEADER));
41
42 return (0);
43 }
44
45 // 46 // parse: 47 // parse the AVI file 48 // returns: 49 // 0 if success, otherwise following error code returned. 50 // AVI_ERR_READ if read error 51 // AVI_ERR_NOT_RIFF if not RIFF chunk 52 // AVI_ERR_NOT_AVI if not AVI file 53 // AVI_ERR_MEM if memory error 54 // AVI_ERR_BROKEN if AVI file is damaged 55 // 56 int
57 avi_parse(AVI * avi)
58 {
59 AVISTREAMHEADER avi_streamheader;
60 AVISUPERINDEX * s;
61 char data[256];
62 int len;
63 int file_len;
64 AVI_FOURCC_TYPE fourcc_type = FOURCC_UNDEF;
65 AVI_TWOCC_TYPE twocc_type = TWOCC_UNDEF;
66
67 // get file's total length 68 file_len = lseek(avi->fd, 0, SEEK_END);
69
70 // reset input stream to beginning 71 lseek(avi->fd, 0, SEEK_SET);
72
73 // validate that the file is a RIFF AVI format file 74 if ( read(avi->fd, data, 12) != 12 )
75 return (AVI_ERR_READ);
76 if ( !(strncasecmp(data, "RIFF", 4) == 0 ) )
77 return (AVI_ERR_NOT_RIFF);
78 if ( !(strncasecmp(data+8, "AVI ", 4) == 0) )
79 return (AVI_ERR_NOT_AVI);
80
81 do {
82 // clear data and read 83 len = 0;
84 memset(data, 0, 256);
85 if ( read(avi->fd, data, 8) != 8 )
86 return (AVI_ERR_READ);
87
88 fourcc_type = FOURCC_UNDEF;
89 if ( strncasecmp(data, "LIST", 4) == 0 ) // list type 90 fourcc_type = FOURCC_LIST;
91 else if ( strncasecmp(data, "avih", 4) == 0 ) // following are all chunks type 92 fourcc_type = FOURCC_avih;
93 else if ( strncasecmp(data, "strh", 4) == 0 )
94 fourcc_type = FOURCC_strh;
95 else if ( strncasecmp(data, "strf", 4) == 0 )
96 fourcc_type = FOURCC_strf;
97 else if ( strncasecmp(data, "strd", 4) == 0 )
98 fourcc_type = FOURCC_strd;
99 else if ( strncasecmp(data, "strn", 4) == 0 )
100 fourcc_type = FOURCC_strn;
101 else if ( strncasecmp(data, "idx1", 4) == 0 )
102 fourcc_type = FOURCC_idx1;
103 else if ( strncasecmp(data, "indx", 4) == 0 )
104 fourcc_type = FOURCC_indx;
105 else if ( strncasecmp(data, "JUNK", 4) == 0 )
106 fourcc_type = FOURCC_JUNK;
107 else if ( strncasecmp(data, "RIFF", 4) == 0 ) // for OpenDML extension108 fourcc_type = FOURCC_RIFF;
109
110 // main parse place111 switch (fourcc_type) {
112 case FOURCC_LIST:
113 // reserved chunk size, used by movi handler branch114 len = *(int *)(data + 4);
115 ALIGN_EVEN(len); // align chunk size to even border116
117 if ( read(avi->fd, data, 4) != 4 )
118 return (AVI_ERR_READ);
119
120 if ( strncasecmp(data, "hdrl", 4) == 0 )
121 avi->aviheader.have_hdrl = 1;
122 if ( strncasecmp(data, "strl", 4) == 0 )
123 avi->aviheader.have_strl = 1;
124 if ( strncasecmp(data, "rec ", 4) == 0 )
125 avi->aviheader.have_rec = 1;
126 if ( strncasecmp(data, "movi", 4) == 0 ) {
127 avi->aviheader.have_movi = 1;
128
129 // get movi offset, aligned130 if(!avi->aviheader.movi_offset){
131 avi->aviheader.movi_offset = lseek(avi->fd, 0, SEEK_CUR);
132 ALIGN_EVEN(avi->aviheader.movi_offset);
133 }
134 // get movi length135 avi->aviheader.movi_length = len;
136
137 // if there are indicies at file end, just skip movi block138 if ( avi->aviheader.have_idx1 )
139 lseek(avi->fd, len - 4, SEEK_CUR);
140 }
141 if (strncasecmp(data, "INFO", 4) == 0) {
142 lseek(avi->fd, -12, SEEK_CUR);
143 if ( read(avi->fd, data, 8) != 8 )
144 return (AVI_ERR_READ);
145 len = *(int *)(data + 4);
146 ALIGN_EVEN(len); // align chunk size to even border147 lseek(avi->fd, len, SEEK_CUR);
148 }
149 break;
150 case FOURCC_avih:
151 if ( avi->aviheader.have_hdrl ) {
152 // back trace 8 bytes153 lseek(avi->fd, -8, SEEK_CUR);
154
155 len = sizeof(AVIMAINHEADER);
156 ALIGN_EVEN(len); // align chunk size to even border157 if ( read(avi->fd,
158 (char *)&avi->aviheader.mainheader,
159 len) != len )
160 return (AVI_ERR_READ);
161
162 if ( avi->aviheader.mainheader.dwFlags & AMHF_HASINDEX)
163 avi->aviheader.have_idx1 = 1;
164 }
165 break;
166 case FOURCC_strh:
167 if ( avi->aviheader.have_strl ) {
168 // back trace 8 bytes169 lseek(avi->fd, -8, SEEK_CUR);
170
171 len = sizeof(AVISTREAMHEADER);
172 ALIGN_EVEN(len); // align chunk size to even border173 if ( read(avi->fd,
174 (char *)&avi_streamheader, len) != len )
175 return (AVI_ERR_READ);
176
177 if ( strncasecmp(avi_streamheader.fccType, "vids", 4) == 0 )
178 avi->aviheader.vid_streamheader = avi_streamheader;
179 else if ( strncasecmp(avi_streamheader.fccType, "auds", 4) == 0 )
180 avi->aviheader.aud_streamheader = avi_streamheader;
181 }
182 break;
183 case FOURCC_idx1:
184 // read in index185 len = *(int *)(data + 4);
186 ALIGN_EVEN(len); // align chunk size to even border187 avi->aviheader.idx1_table.idx1_head = (AVIIDX1ENTRY *)malloc(len);
188 if ( avi->aviheader.idx1_table.idx1_head == NULL )
189 return (AVI_ERR_MEM);
190 if ( read(avi->fd, (char *)avi->aviheader.idx1_table.idx1_head,
191 len) != len )
192 return (AVI_ERR_READ);
193 avi->aviheader.idx1_table.idx1_length = len;
194 avi->aviheader.idx1_table.idx1_count = len / sizeof(AVIIDX1ENTRY);
195 avi->aviheader.have_idx1 = 1;
196 break;
197 case FOURCC_indx:
198 // super index199 len = *(int *)(data + 4);
200 ALIGN_EVEN(len); // align chunk size to even border201 if (len < 24)
202 break;
203 avi->aviheader.index_table.index_count++;
204 avi->aviheader.index_table.index_head = realloc(
205 avi->aviheader.index_table.index_head,
206 avi->aviheader.index_table.index_count * sizeof(AVISUPERINDEX));
207 if (avi->aviheader.index_table.index_head == NULL)
208 return (AVI_ERR_MEM);
209 s = avi->aviheader.index_table.index_head + avi->aviheader.index_table.index_count -1;
210 memcpy(s->fcc, "indx", 4);
211 s->cb = len ;
212 if (read(avi->fd, ((char *)s)+8, 24)!=24)
213 return (AVI_ERR_READ);
214 memset(s->dwReserved, 0, 3 * 4); // stuff dwReserved[3] of AVISUPERINDEX215 s->aIndex = calloc(s->nEntriesInUse, sizeof(avisuperindex_entry));
216 s->stdidx = calloc(s->nEntriesInUse, sizeof(avistdindex_chunk));
217 if (s->aIndex == NULL)
218 return (AVI_ERR_MEM);
219 if (read(avi->fd, (char *)s->aIndex,
220 s->nEntriesInUse * sizeof(avisuperindex_entry))
221 != s->nEntriesInUse * sizeof(avisuperindex_entry))
222 return (AVI_ERR_READ);
223 avi->aviheader.have_indx = 1 ;
224 break;
225 case FOURCC_RIFF:
226 // another RIFF List, for OpenDML227 if (read(avi->fd, data, 4) != 4)
228 return (AVI_ERR_READ);
229 if (strncmp(data, "AVIX", 4))
230 return (AVI_ERR_NOT_RIFF);
231 else{
232
235 if( avi->aviheader.have_indx)
236 avi->aviheader.isodml = 1 ;
237 }
238 break;
239 case FOURCC_strf:
240 case FOURCC_strd:
241 case FOURCC_strn:
242 case FOURCC_JUNK:
243 default:
244 // skipped245 len = *(int *)(data + 4);
246 ALIGN_EVEN(len); // align chunk size to even border247 lseek(avi->fd, len, SEEK_CUR);
248 break;
249 }
250 } while ( lseek(avi->fd, 0, SEEK_CUR) < file_len );
251
252 // if neither idx1 nor indx, then generate idx1253 if (!avi->aviheader.have_idx1 && !avi->aviheader.have_indx) {
254 //rewind the stream position to the beginning of the file255 lseek(avi->fd, 0, SEEK_SET);
256
257 //seek to the begining of movi chunk258 lseek(avi->fd, avi->aviheader.movi_offset, SEEK_CUR);
259
260 AVIIDX1ENTRY * curidx;
261 char id[4];
262 while (read(avi->fd, id, 4) >=0 && lseek(avi->fd, 0, SEEK_CUR) <
263 avi->aviheader.movi_offset + avi->aviheader.movi_length - 4){
264 if (read(avi->fd, data, 4) != 4)
265 return (AVI_ERR_READ);
266 len = *(int*)data;
267 avi->aviheader.idx1_table.idx1_head = realloc(
268 avi->aviheader.idx1_table.idx1_head,
269 avi->aviheader.idx1_table.idx1_length + sizeof(AVIIDX1ENTRY));
270 if ( avi->aviheader.idx1_table.idx1_head != NULL )
271 curidx = avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count;
272 else
273 return (AVI_ERR_MEM);
274 memcpy(&curidx->dwChunkId, id, 4); // FOURCC275 curidx->dwFlags = AVIIF_KEYFRAME;
276 curidx->dwFlags |= (lseek(avi->fd, 0, SEEK_CUR)) >> 16 & 0xffff0000U;
277 curidx->dwOffset = (unsigned int)(lseek(avi->fd, 0, SEEK_CUR) -
278 avi->aviheader.movi_offset - 4); // offset relative to movi279 curidx->dwSize = len;
280 avi->aviheader.idx1_table.idx1_count++;
281 avi->aviheader.idx1_table.idx1_length += sizeof(AVIIDX1ENTRY);
282 ALIGN_EVEN(len);
283 lseek(avi->fd, len, SEEK_CUR);
284 }
285 avi->aviheader.have_idx1 = 1 ;
286 }
287
288 //deal with super index289 if (avi->aviheader.isodml && avi->aviheader.have_indx) {
290 AVISUPERINDEX * cx;
291 AVIIDX1ENTRY * idx;
292 int i, j;
293
294 if (avi->aviheader.idx1_table.idx1_head)
295 free(avi->aviheader.idx1_table.idx1_head);
296 avi->aviheader.idx1_table.idx1_count = 0;
297 avi->aviheader.idx1_table.idx1_head = NULL ;
298
299 // read the standard indices300 for (cx = &avi->aviheader.index_table.index_head[0], i = 0;
301 i < avi->aviheader.index_table.index_count; cx++, i++) {
302 for (j = 0; j < cx->nEntriesInUse; j++){
303 int ret1, ret2;
304
305 memset(&cx->stdidx[j], 0, 32);
306 // reset input stream to beginning307 lseek(avi->fd, 0, SEEK_SET);
308 ret1 = lseek(avi->fd, (DWORDLONG)cx->aIndex[j].qwOffset, SEEK_CUR);
309 if ((ret2 = read(avi->fd, (char *)&cx->stdidx[j], 32)) != 32)
310 return (AVI_ERR_READ);
311 if (ret1 < 0 || cx->stdidx[j].nEntriesInUse == 0) {
312 // this is a broken file (probably incomplete)313 avi->aviheader.isodml = 0;
314 avi->aviheader.idx1_table.idx1_count = 0 ;
315 return (AVI_ERR_BROKEN);
316 }
317 avi->aviheader.idx1_table.idx1_count += cx->stdidx[j].nEntriesInUse;
318 cx->stdidx[j].aIndex = malloc(cx->stdidx[j].nEntriesInUse * sizeof(avistdindex_entry));
319 if (cx->stdidx[j].aIndex == NULL)
320 return (AVI_ERR_MEM);
321 if (read(avi->fd, (char *)cx->stdidx[j].aIndex,
322 cx->stdidx[j].nEntriesInUse * sizeof(avistdindex_entry)) !=
323 cx->stdidx[j].nEntriesInUse * sizeof(avistdindex_entry))
324 return (AVI_ERR_READ);
325 cx->stdidx[j].dwReserved3 = 0;
326 }
327 }
328
329
333 avi->aviheader.idx1_table.idx1_head = malloc(
334 avi->aviheader.idx1_table.idx1_count * sizeof(AVIIDX1ENTRY));
335 idx = avi->aviheader.idx1_table.idx1_head;
336 if (idx == NULL)
337 return (AVI_ERR_MEM);
338 for (cx = avi->aviheader.index_table.index_head;
339 cx != &avi->aviheader.index_table.index_head[avi->aviheader.index_table.index_count]; cx++) {
340 avistdindex_chunk * sic;
341 for (sic = cx->stdidx; sic != &cx->stdidx[cx->nEntriesInUse]; sic++){
342 avistdindex_entry * sie;
343 for (sie=sic->aIndex; sie != &sic->aIndex[sic->nEntriesInUse]; sie++){
344 DWORDLONG offset = sie->dwOffset + sic->qwBaseOffset;
345 memcpy(idx->dwChunkId, sic->dwChunkId, 4);
346 idx->dwOffset = offset;
347 idx->dwFlags = (offset >> 32) << 16;
348 idx->dwSize = sie->dwSize & 0x7fffffff;
349 idx->dwFlags |= (sie->dwSize & 0x80000000)?0x0:AVIIF_KEYFRAME;
350 idx++;
351 }
352 }
353 }
354
355 // sorting in offset356 qsort(avi->aviheader.idx1_table.idx1_head, avi->aviheader.idx1_table.idx1_count,
357 sizeof(AVIIDX1ENTRY), avi_idx_cmp);
358 }
359
360 return (0);
361 }
362
363 //364 // go to first video block365 // return 0 if found, else -1366 //367 int
368 avi_goto_first_video_block(AVI * avi)
369 {
370 AVIIDX1ENTRY * pIdx1Entry;
371 FOURCC four_cc;
372
373 if ( avi->aviheader.have_idx1 || avi->aviheader.have_indx) {
374 pIdx1Entry = avi->aviheader.idx1_table.idx1_head;
375 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4);
376
377 while ( ! ( (four_cc[2] == 'd' && four_cc[3] == 'b') ||
378 (four_cc[2] == 'd' && four_cc[3] == 'c') ) ) {
379 if ( pIdx1Entry++ < avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count )
380 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4);
381 }
382
383 if ( pIdx1Entry >= avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count ) {
384 avi->aviheader.idx1_table.current_vid_idx = NULL;
385 return (-1);
386 } else {
387 avi->aviheader.idx1_table.current_vid_idx = pIdx1Entry; // that's it388 return (0);
389 }
390 } else
391 return (AVI_ERR_NOT_AVI);
392
393 return (-1);
394 }
395 |
|