1 /********************************************************************* 2 * $file : libavi.c 3 * $desc : parsing AVI format file 4 * $author : rockins 5 * $date : Mon Nov 26 02:50:17 CST 2007 6 * $copyright : all copyrights(c) reserved by rockins. 7 **********************************************************************/ 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 extension 108 fourcc_type = FOURCC_RIFF; 109 110 // main parse place 111 switch (fourcc_type) { 112 case FOURCC_LIST: 113 // reserved chunk size, used by movi handler branch 114 len = *(int *)(data + 4); 115 ALIGN_EVEN(len); // align chunk size to even border 116 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, aligned 130 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 length 135 avi->aviheader.movi_length = len; 136 137 // if there are indicies at file end, just skip movi block 138 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 border 147 lseek(avi->fd, len, SEEK_CUR); 148 } 149 break; 150 case FOURCC_avih: 151 if ( avi->aviheader.have_hdrl ) { 152 // back trace 8 bytes 153 lseek(avi->fd, -8, SEEK_CUR); 154 155 len = sizeof(AVIMAINHEADER); 156 ALIGN_EVEN(len); // align chunk size to even border 157 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 bytes 169 lseek(avi->fd, -8, SEEK_CUR); 170 171 len = sizeof(AVISTREAMHEADER); 172 ALIGN_EVEN(len); // align chunk size to even border 173 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 index 185 len = *(int *)(data + 4); 186 ALIGN_EVEN(len); // align chunk size to even border 187 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 index 199 len = *(int *)(data + 4); 200 ALIGN_EVEN(len); // align chunk size to even border 201 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 AVISUPERINDEX 215 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 OpenDML 227 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 /* We got an extended AVI header, so we need to switch to 233 * OpenDML to get seeking to work, provided we got indx chunks 234 * in the header(have_indx == 1)*/ 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 // skipped 245 len = *(int *)(data + 4); 246 ALIGN_EVEN(len); // align chunk size to even border 247 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 idx1 253 if (!avi->aviheader.have_idx1 && !avi->aviheader.have_indx) { 254 //rewind the stream position to the beginning of the file 255 lseek(avi->fd, 0, SEEK_SET); 256 257 //seek to the begining of movi chunk 258 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); // FOURCC 275 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 movi 279 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 index 289 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 indices 300 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 beginning 307 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 /* 330 * convert the index by translating all entries into AVIIDX1ENTRYs 331 * and sorting them by offset. 332 */ 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 offset 356 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 block 365 // return 0 if found, else -1 366 // 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 it 388 return (0); 389 } 390 } else 391 return (AVI_ERR_NOT_AVI); 392 393 return (-1); 394 } 395 396 // 397 // go to first audio block 398 // return 0 if found, else -1 399 // 400 int 401 avi_goto_first_audio_block(AVI * avi) 402 { 403 AVIIDX1ENTRY * pIdx1Entry; 404 FOURCC four_cc; 405 406 if ( avi->aviheader.have_idx1 || avi->aviheader.have_indx) { 407 pIdx1Entry = avi->aviheader.idx1_table.idx1_head; 408 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4); 409 410 while ( ! (four_cc[2] == 'w' && four_cc[3] == 'b') ) { 411 if ( pIdx1Entry++ < avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count ) 412 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4); 413 } 414 415 if ( pIdx1Entry >= avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count ) { 416 avi->aviheader.idx1_table.current_aud_idx = NULL; 417 return (-1); 418 } else { 419 avi->aviheader.idx1_table.current_aud_idx = pIdx1Entry; // that's it 420 return (0); 421 } 422 } else 423 return (AVI_ERR_NOT_AVI); 424 425 return (-1); 426 } 427 428 // 429 // step to next video block 430 // returns: 1 if next video block exist, otherwise 0 431 // 432 int 433 avi_goto_next_video_block(AVI * avi) 434 { 435 AVIIDX1ENTRY * pIdx1Entry; 436 FOURCC four_cc; 437 438 pIdx1Entry = avi->aviheader.idx1_table.current_vid_idx + 1; 439 if (pIdx1Entry < avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) { 440 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4); 441 442 while ( ! ( (four_cc[2] == 'd' && four_cc[3] == 'b') || 443 (four_cc[2] == 'd' && four_cc[3] == 'c') ) ) { 444 if (pIdx1Entry++ < avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) 445 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4); 446 else 447 break; 448 } 449 450 if (pIdx1Entry >= avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) { 451 avi->aviheader.idx1_table.current_vid_idx = NULL; 452 } else { 453 avi->aviheader.idx1_table.current_vid_idx = pIdx1Entry; // that's it, update it 454 } 455 } else { 456 avi->aviheader.idx1_table.current_vid_idx = NULL; 457 } 458 459 return (avi->aviheader.idx1_table.current_vid_idx?1:0); 460 } 461 462 // 463 // step to next audio block 464 // returns: 1 if next audio block exist, otherwise 0 465 // 466 int 467 avi_goto_next_audio_block(AVI * avi) 468 { 469 AVIIDX1ENTRY * pIdx1Entry; 470 FOURCC four_cc; 471 472 pIdx1Entry = avi->aviheader.idx1_table.current_aud_idx + 1; 473 if (pIdx1Entry < avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) { 474 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4); 475 476 while ( ! (four_cc[2] == 'w' && four_cc[3] == 'b') ) { 477 if (pIdx1Entry++ < avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) 478 memcpy(four_cc, &pIdx1Entry->dwChunkId, 4); 479 else 480 break; 481 } 482 483 if (pIdx1Entry >= avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) { 484 avi->aviheader.idx1_table.current_aud_idx = NULL; 485 } else { 486 avi->aviheader.idx1_table.current_aud_idx = pIdx1Entry; // that's it, update it 487 } 488 } else { 489 avi->aviheader.idx1_table.current_aud_idx = NULL; 490 } 491 492 return (avi->aviheader.idx1_table.current_aud_idx?1:0); 493 } 494 495 // 496 // get current video block size: 497 // return block size in byte if success, else -1 498 // 499 int 500 avi_get_curr_video_block_size(AVI * avi) 501 { 502 if ( avi->aviheader.have_idx1 || avi->aviheader.have_indx ) { 503 if ( avi->aviheader.idx1_table.current_vid_idx == NULL || 504 avi->aviheader.idx1_table.current_vid_idx >= 505 avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) { 506 avi->aviheader.idx1_table.current_vid_idx == NULL; 507 return (-1); 508 } else 509 return ( avi->aviheader.idx1_table.current_vid_idx->dwSize ); 510 } 511 512 return (-1); 513 } 514 515 // 516 // get current audio block size 517 // return block size in byte if success, else -1 518 // 519 int 520 avi_get_curr_audio_block_size(AVI * avi) 521 { 522 if ( avi->aviheader.have_idx1 || avi->aviheader.have_indx) { 523 if ( avi->aviheader.idx1_table.current_aud_idx == NULL || 524 avi->aviheader.idx1_table.current_aud_idx >= 525 avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count) { 526 avi->aviheader.idx1_table.current_aud_idx == NULL; 527 return (-1); 528 } else 529 return ( avi->aviheader.idx1_table.current_aud_idx->dwSize ); 530 } 531 532 return (-1); 533 } 534 535 // 536 // get current video block 537 // return actual size if success, else -1 538 // 539 int 540 avi_get_curr_video_block(AVI * avi, char * video_block, int len) 541 { 542 FOURCC four_cc; 543 int ret; 544 545 if (avi->aviheader.have_idx1 || avi->aviheader.have_indx) { 546 // validate 547 if ( avi->aviheader.idx1_table.current_vid_idx == NULL || 548 avi->aviheader.idx1_table.current_vid_idx->dwSize > len || 549 avi->aviheader.idx1_table.current_vid_idx >= 550 avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count ) 551 return (-1); 552 553 // seek and read video block 554 lseek(avi->fd, (1 - avi->aviheader.have_indx) * (avi->aviheader.movi_offset + 4) + 555 avi->aviheader.idx1_table.current_vid_idx->dwOffset, SEEK_SET); 556 ret = read(avi->fd, video_block, 557 avi->aviheader.idx1_table.current_vid_idx->dwSize); 558 559 return (ret); 560 } 561 562 return (-1); 563 } 564 565 // 566 // get current audio block 567 // return actual size in byte if success, else -1 568 // 569 int 570 avi_get_curr_audio_block(AVI * avi, char * audio_block, int len) 571 { 572 FOURCC four_cc; 573 int ret; 574 575 if (avi->aviheader.have_idx1 || avi->aviheader.have_indx) { 576 // validate 577 if ( avi->aviheader.idx1_table.current_aud_idx == NULL || 578 avi->aviheader.idx1_table.current_aud_idx->dwSize > len || 579 avi->aviheader.idx1_table.current_aud_idx >= 580 avi->aviheader.idx1_table.idx1_head + avi->aviheader.idx1_table.idx1_count ) 581 return (-1); 582 583 // seek and read audio block 584 lseek(avi->fd, (1 - avi->aviheader.have_indx) * (avi->aviheader.movi_offset + 4) + 585 avi->aviheader.idx1_table.current_aud_idx->dwOffset, SEEK_SET); 586 ret = read(avi->fd, audio_block, 587 avi->aviheader.idx1_table.current_aud_idx->dwSize); 588 589 return (ret); 590 } 591 592 return (-1); 593 } 594 595 596 /************ constructor & deconstructor ******************/ 597 // 598 // constructor: 599 // param: file - input file's name 600 // return: an AVI object if success, otherwise NULL 601 // 602 AVI * avi_new(char * file) 603 { 604 AVI * avi; 605 606 avi = (AVI *)malloc(sizeof(AVI)); 607 if (avi) { 608 avi->file_name = file; 609 avi->fd = open(file, O_RDONLY); 610 } 611 612 // install member functions 613 avi->init = avi_init; 614 avi->parse = avi_parse; 615 avi->goto_first_video_block = avi_goto_first_video_block; 616 avi->goto_first_audio_block = avi_goto_first_audio_block; 617 avi->goto_next_video_block = avi_goto_next_video_block; 618 avi->goto_next_audio_block = avi_goto_next_audio_block; 619 avi->get_curr_video_block_size = avi_get_curr_video_block_size; 620 avi->get_curr_audio_block_size = avi_get_curr_audio_block_size; 621 avi->get_curr_video_block = avi_get_curr_video_block; 622 avi->get_curr_audio_block = avi_get_curr_audio_block; 623 624 return (avi?avi:NULL); 625 } 626 627 // 628 // deconstructor 629 // param: an AVI object 630 // 631 void avi_del(AVI * avi) 632 { 633 if (avi) { 634 close(avi->fd); 635 free(avi); 636 } 637 } |