00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include "mpg_common.h"
00031 #include "avi.h"
00032 #include "replex.h"
00033 #include "pes.h"
00034
00035
00036 #define DEBUG 1
00037
00038 #ifdef DEBUG
00039 #include "mpg_common.h"
00040 #endif
00041 uint32_t getle32(uint8_t *buf)
00042 {
00043 return (buf[3]<<24)|(buf[2]<<16)|(buf[1]<<8)|buf[0];
00044 }
00045
00046 uint32_t getbe32(uint8_t *buf)
00047 {
00048 return (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];
00049 }
00050
00051 void printhead(uint8_t *buf)
00052 {
00053 printf("%c%c%c%c ", buf[0], buf[1], buf[2], buf[3]);
00054 }
00055
00056 uint32_t getsize(int fd)
00057 {
00058 int len;
00059 uint8_t buf[4];
00060
00061 len=read(fd, buf, 4);
00062 return getle32(buf);
00063 }
00064
00065 uint32_t getsize_buf(uint8_t *buf)
00066 {
00067 return getle32(buf);
00068 }
00069
00070
00071 int check_riff(avi_context *ac, uint8_t *buf, int len)
00072 {
00073 uint32_t tag;
00074 int c = 0;
00075
00076 if (len < 12) return -1;
00077 tag = getle32(buf);
00078 if (tag != TAG_IT('R','I','F','F')) return -1;
00079 c+=4;
00080
00081 ac->riff_end = getle32(buf+c);
00082 c+=4;
00083
00084 tag = getle32(buf+c);
00085 if (tag != TAG_IT('A','V','I',' ') &&
00086 tag != TAG_IT('A','V','I','X') ) return -1;
00087
00088 return c+4;
00089 }
00090
00091 static
00092 int new_idx_frame( avi_context *ac, uint32_t pos, uint32_t len,
00093 uint32_t fl, uint32_t id)
00094 {
00095 int num = ac->num_idx_frames;
00096 if (ac->num_idx_alloc < num+1){
00097 avi_index *idx;
00098 uint32_t newnum = num + 1024;
00099
00100 if (ac->idx){
00101 idx = realloc(ac->idx,
00102 newnum*sizeof(avi_index));
00103 } else {
00104 idx = malloc(newnum*sizeof(avi_index));
00105 }
00106 if (!idx) return -1;
00107 ac->idx = idx;
00108 ac->num_idx_alloc = newnum;
00109 }
00110 ac->idx[num].off = pos;
00111 ac->idx[num].id = id;
00112 ac->idx[num].len = len;
00113 ac->idx[num].flags = fl;
00114 ac->num_idx_frames++;
00115
00116
00117
00118 return 0;
00119 }
00120
00121 void print_index(avi_context *ac, int num){
00122 char *cc;
00123 cc = (char *) &ac->idx[num].id;
00124 fprintf(stderr,"%d chunkid: %c%c%c%c ",
00125 num,
00126 *cc,*(cc+1),*(cc+2),*(cc+3));
00127 fprintf(stderr," chunkoff: 0x%04x ",
00128 (int)ac->idx[num].off);
00129 fprintf(stderr," chunksize: 0x%04x ",
00130 ac->idx[num].len);
00131 fprintf(stderr," chunkflags: 0x%04x \n",
00132 ac->idx[num].flags);
00133 }
00134
00135 int avi_read_index(avi_context *ac, int fd)
00136 {
00137 uint32_t tag;
00138 uint32_t isize;
00139 uint32_t c;
00140 off_t start;
00141 uint8_t buf[16];
00142 char *cc;
00143
00144 if (!(ac->avih_flags & AVI_HASINDEX)) return -2;
00145 fprintf(stderr,"READING INDEX\n");
00146 start = lseek(fd, 0, SEEK_CUR);
00147 lseek(fd, ac->movi_length+ac->movi_start+4, SEEK_SET);
00148
00149 read(fd,buf,4);
00150 tag = getle32(buf);
00151
00152 if (tag != TAG_IT('i','d','x','1')){
00153 cc = (char *) &tag;
00154 fprintf(stderr," tag: %c%c%c%c\n ",*cc,
00155 *(cc+1),*(cc+2),*(cc+3));
00156
00157 lseek(fd, start, SEEK_SET);
00158 return -1;
00159 }
00160 isize = getsize(fd);
00161 c = 0;
00162
00163 while ( c < isize ){
00164 uint32_t chunkid;
00165 uint32_t chunkflags;
00166 uint32_t chunkoff;
00167 uint32_t chunksize;
00168
00169 read(fd,buf,16);
00170 chunkid = getle32(buf);
00171 chunkflags = getle32(buf+4);
00172 chunkoff = getle32(buf+8);
00173 chunksize = getle32(buf+12);
00174
00175 new_idx_frame(ac, chunkoff, chunksize, chunkflags,chunkid);
00176 switch(chunkid){
00177 case TAG_IT('0','1','w','b'):
00178 ac->achunks++;
00179 if (!chunksize) ac->zero_achunks++;
00180 break;
00181
00182 case TAG_IT('0','0','d','c'):
00183 ac->vchunks++;
00184 if (!chunksize) ac->zero_vchunks++;
00185 break;
00186 }
00187
00188 #ifdef DEBUG
00189
00190
00191
00192 #endif
00193 c+=16;
00194 }
00195 #ifdef DEBUG
00196 fprintf(stderr,"Found %d video (%d were empty) and %d audio (%d were empty) chunks\n", (int)ac->vchunks, (int)ac->zero_vchunks, (int)ac->achunks, (int)ac->zero_achunks);
00197
00198 #endif
00199 lseek(fd, start, SEEK_SET);
00200
00201 return 0;
00202 }
00203
00204
00205 int read_avi_header( avi_context *ac, int fd)
00206 {
00207 uint8_t buf[256];
00208 uint32_t tag;
00209 uint32_t size = 0;
00210 int c = 0;
00211 int skip=0;
00212 int n;
00213 #ifdef DEBUG
00214 char *cc;
00215 #endif
00216
00217 while ((c=read(fd, buf, 4))==4) {
00218 skip=0;
00219 tag = getle32(buf);
00220
00221 #ifdef DEBUG
00222 cc = (char *) &tag;
00223 fprintf(stderr,"tag: %c%c%c%c ",*cc,*(cc+1),*(cc+2),*(cc+3));
00224 #endif
00225 switch(tag){
00226 case TAG_IT('L','I','S','T'):
00227 size = getsize(fd);
00228 break;
00229
00230
00231 case TAG_IT('m','o','v','i'):
00232 ac->done=1;
00233 ac->movi_start = lseek(fd, 0, SEEK_CUR);
00234 ac->movi_length = size-8;
00235 #ifdef DEBUG
00236 fprintf(stderr," size: %d",size);
00237 fprintf(stderr," header done\n");
00238 #endif
00239 return 0;
00240 break;
00241
00242 case TAG_IT('h','d','r','l'):
00243 break;
00244
00245
00246 case TAG_IT('s','t','r','l'):
00247 break;
00248
00249 case TAG_IT('J','U','N','K'):
00250 case TAG_IT('s','t','r','f'):
00251 case TAG_IT('s','t','r','d'):
00252 case TAG_IT('s','t','r','n'):
00253 size = getsize(fd);
00254 skip=1;
00255 break;
00256 case TAG_IT('a','v','i','h'):
00257 size = getsize(fd);
00258 c=0;
00259 read(fd,buf,size);
00260 ac->msec_per_frame = getle32(buf+c);
00261 c+=12;
00262 ac->avih_flags = getle32(buf+c);
00263 c+=4;
00264 ac->total_frames = getle32(buf+c);
00265 c+=4;
00266 ac->init_frames = getle32(buf+c);
00267 c+=4;
00268 ac->nstreams = getle32(buf+c);
00269 c+=8;
00270 ac->width = getle32(buf+c);
00271 c+=4;
00272 ac->height = getle32(buf+c);
00273 c+=4;
00274
00275
00276 #ifdef DEBUG
00277 fprintf(stderr," size: %d\n",size);
00278 fprintf(stderr," microsecs per frame %d\n",
00279 ac->msec_per_frame);
00280 if (ac->avih_flags & AVI_HASINDEX)
00281 fprintf(stderr," AVI has index\n");
00282 if (ac->avih_flags & AVI_USEINDEX)
00283 fprintf(stderr," AVI must use index\n");
00284 if (ac->avih_flags & AVI_INTERLEAVED)
00285 fprintf(stderr," AVI is interleaved\n");
00286 if(ac->total_frames)
00287 fprintf(stderr," total frames: %d\n",
00288 ac->total_frames);
00289
00290 fprintf(stderr," number of streams: %d\n",
00291 ac->nstreams);
00292 fprintf(stderr," size: %dx%d\n",
00293 ac->width, ac->height);
00294 #endif
00295 break;
00296
00297 case TAG_IT('s','t','r','h'):
00298 size = getsize(fd);
00299 #ifdef DEBUG
00300 fprintf(stderr," size: %d\n",size);
00301 #endif
00302
00303 c=0;
00304 read(fd,buf,size);
00305 tag = getle32(buf);
00306 c+=16;
00307 #ifdef DEBUG
00308 cc = (char *) &tag;
00309 fprintf(stderr," tag: %c%c%c%c ",*cc,
00310 *(cc+1),*(cc+2),*(cc+3));
00311 #endif
00312 switch ( tag ){
00313 case TAG_IT('v','i','d','s'):
00314 ac->vhandler = getle32(buf+4);
00315 #ifdef DEBUG
00316 if (ac->vhandler){
00317 cc = (char *) &ac->vhandler;
00318 fprintf(stderr," video handler: %c%c%c%c "
00319 ,*cc,*(cc+1),*(cc+2),*(cc+3));
00320 }
00321 #endif
00322 ac->vi.initial_frames = getle32(buf+c);
00323 c+=4;
00324 ac->vi.dw_scale = getle32(buf+c);
00325 c+=4;
00326 ac->vi.dw_rate = getle32(buf+c);
00327 c+=4;
00328 ac->vi.dw_start = getle32(buf+c);
00329 c+=4;
00330 if (ac->vi.dw_scale)
00331 ac->vi.fps = (ac->vi.dw_rate*1000)/
00332 ac->vi.dw_scale;
00333
00334 #ifdef DEBUG
00335 fprintf(stderr,"\n");
00336 #endif
00337 fprintf(stderr,"AVI video info: ");
00338 fprintf(stderr,"dw_scale %d dw_rate %d ",
00339 ac->vi.dw_scale, ac->vi.dw_rate);
00340 fprintf(stderr,"fps %0.3f ini_frames %d dw_start %d\n",
00341 ac->vi.fps/1000.0,
00342 ac->vi.initial_frames,
00343 ac->vi.dw_start);
00344 break;
00345 case TAG_IT('a','u','d','s'):
00346 ac->ahandler = getle32(buf+4);
00347 #ifdef DEBUG
00348 if (ac->vhandler){
00349 cc = (char *) &ac->ahandler;
00350 fprintf(stderr," audio handler: %c%c%c%c "
00351 ,*cc,*(cc+1),*(cc+2),*(cc+3));
00352 }
00353 #endif
00354
00355 if (ac->ntracks == MAX_TRACK) break;
00356 n = ac->ntracks;
00357 ac->ai[n].initial_frames = getle32(buf+c);
00358 c+=4;
00359 ac->ai[n].dw_scale = getle32(buf+c);
00360 c+=4;
00361 ac->ai[n].dw_rate = getle32(buf+c);
00362 c+=4;
00363 ac->ai[n].dw_start = getle32(buf+c);
00364 c+=16;
00365 ac->ai[n].dw_ssize = getle32(buf+c);
00366 if (ac->ai[n].dw_scale)
00367 ac->ai[n].fps =
00368 (ac->ai[n].dw_rate*1000)/
00369 ac->ai[n].dw_scale;
00370 #ifdef DEBUG
00371 fprintf(stderr,"\n");
00372 #endif
00373 fprintf(stderr,"AVI audio%d info: ",n);
00374 fprintf(stderr,"dw_scale %d dw_rate %d ",
00375 ac->ai[n].dw_scale, ac->ai[n].dw_rate);
00376 fprintf(stderr,"ini_frames %d dw_start %d",
00377 ac->ai[n].initial_frames,
00378 ac->ai[n].dw_start);
00379 fprintf(stderr," fps %0.3f sam_size %d\n",
00380 ac->ai[n].fps/1000.,
00381 ac->ai[n].dw_ssize);
00382
00383 ac->ntracks++;
00384 break;
00385 }
00386 break;
00387
00388 case TAG_IT('I','N','F','O'):
00389 size -=4;
00390 skip =1;
00391 #ifdef DEBUG
00392 fprintf(stderr," size: %d",size);
00393 #endif
00394 break;
00395
00396 }
00397 #ifdef DEBUG
00398 fprintf(stderr,"\n");
00399 #endif
00400
00401 if (skip){
00402 lseek(fd, size, SEEK_CUR);
00403 size = 0;
00404 }
00405
00406 }
00407
00408 return -1;
00409 }
00410
00411
00412 #define MAX_BUF_SIZE 0xffff
00413 int get_avi_from_index(pes_in_t *p, int fd, avi_context *ac,
00414 void (*func)(pes_in_t *p), int insize)
00415 {
00416 struct replex *rx= (struct replex *) p->priv;
00417 avi_index *idx = ac->idx;
00418 int cidx = ac->current_idx;
00419 uint8_t buf[MAX_BUF_SIZE];
00420 uint32_t cid;
00421 int c=0;
00422 off_t pos=0;
00423 int per = 0;
00424 static int lastper=0;
00425
00426 if (cidx > ac->num_idx_frames) return -2;
00427
00428 switch(idx[cidx].id){
00429 case TAG_IT('0','1','w','b'):
00430 p->type = 1;
00431 p->rbuf = &rx->arbuffer[0];
00432 break;
00433
00434 case TAG_IT('0','0','d','c'):
00435 p->type = 0xE0;
00436 p->rbuf = &rx->vrbuffer;
00437 break;
00438
00439 default:
00440 fprintf(stderr,"strange chunk :\n");
00441 show_buf((uint8_t *) &idx[cidx].id,4);
00442 fprintf(stderr,"offset: 0x%04x length: 0x%04x\n",
00443 (int)idx[cidx].off, (int)idx[cidx].len);
00444 ac->current_idx++;
00445 p->found=0;
00446 return 0;
00447 break;
00448 }
00449
00450 memset(buf, 0, MAX_BUF_SIZE);
00451 pos=lseek (fd, idx[cidx].off+ac->movi_start-4, SEEK_SET);
00452 read(fd,buf,idx[cidx].len);
00453 cid = getle32(buf);
00454 c+=4;
00455 p->plength = getsize_buf(buf+c);
00456
00457 if (idx[cidx].len > insize) return 0;
00458
00459 if (idx[cidx].len > MAX_BUF_SIZE){
00460 fprintf(stderr,"Buffer too small in get_avi_from_index\n");
00461 exit(1);
00462 }
00463 if (!idx[cidx].len){
00464 func(p);
00465 ac->current_idx++;
00466 p->found=0;
00467 return 0;
00468 }
00469 if (cid != idx[cidx].id){
00470 char *cc;
00471 cc = (char *)&idx[cidx].id;
00472 fprintf(stderr,"wrong chunk id: %c%c%c%c != %c%c%c%c\n",
00473 buf[0],buf[1],buf[2],buf[3]
00474 ,*cc,*(cc+1),*(cc+2),*(cc+3));
00475
00476 print_index(ac,cidx);
00477 exit(1);
00478 }
00479 if (p->plength != idx[cidx].len){
00480 fprintf(stderr,"wrong chunk size: %d != %d\n",
00481 (int)p->plength, idx[cidx].len);
00482 exit(1);
00483 }
00484 c+=4;
00485 p->done = 1;
00486 p->ini_pos = ring_wpos(p->rbuf);
00487
00488 per = (int)(100*(pos-ac->movi_start)/ac->movi_length);
00489 if (per>lastper) fprintf(stderr,"read %3d%%\r", per);
00490 lastper = per;
00491
00492 if (ring_write(p->rbuf, buf+c, p->plength)<0){
00493 fprintf(stderr, "ring buffer overflow %d 0x%02x\n"
00494 ,p->rbuf->size,p->type);
00495 exit(1);
00496 }
00497
00498 func(p);
00499 init_pes_in(p, 0, NULL, p->withbuf);
00500
00501 ac->current_idx++;
00502
00503 return 0;
00504 }
00505
00506
00507 void get_avi(pes_in_t *p, uint8_t *buf, int count, void (*func)(pes_in_t *p))
00508 {
00509 int l;
00510 int c=0;
00511 struct replex *rx= (struct replex *) p->priv;
00512
00513
00514
00515 while (c < count && p->found < 8
00516 && !p->done){
00517 switch ( p->found ){
00518 case 0:
00519 if (buf[c] == '0') p->found++;
00520 else p->found = 0;
00521 c++;
00522 break;
00523 case 1:
00524 if (buf[c] == '0'|| buf[c] == '1'){
00525 p->found++;
00526 p->which = buf[c] - '0';
00527 } else if (buf[c] == '0'){
00528 p->found = 1;
00529 } else p->found = 0;
00530 c++;
00531 break;
00532 case 2:
00533 switch(buf[c]){
00534 case 'w':
00535 case 'd':
00536 p->found++;
00537 p->type=buf[c];
00538 break;
00539 default:
00540 p->found = 0;
00541 break;
00542 }
00543 c++;
00544 break;
00545
00546 case 3:
00547 switch(buf[c]){
00548 case 'b':
00549 if (p->type == 'w'){
00550 p->found++;
00551 p->type = 1;
00552 } else p->found = 0;
00553 break;
00554 case 'c':
00555 if (p->type == 'd'){
00556 p->found++;
00557 p->type = 0xE0;
00558 } else p->found = 0;
00559 break;
00560 default:
00561 p->found = 0;
00562 break;
00563 }
00564 switch(p->type){
00565
00566 case 1:
00567 p->rbuf = &rx->arbuffer[0];
00568 break;
00569
00570 case 0xE0:
00571 p->rbuf = &rx->vrbuffer;
00572 break;
00573 }
00574 c++;
00575 break;
00576
00577 case 4:
00578 p->plen[0] = buf[c];
00579 c++;
00580 p->found++;
00581 break;
00582
00583 case 5:
00584 p->plen[1] = buf[c];
00585 c++;
00586 p->found++;
00587 break;
00588
00589 case 6:
00590 p->plen[2] = buf[c];
00591 c++;
00592 p->found++;
00593 break;
00594
00595 case 7:
00596 p->plen[3] = buf[c];
00597 c++;
00598 p->found++;
00599 p->plength = getsize_buf(p->plen);
00600 if (!p->plength){
00601 func(p);
00602 p->found=0;
00603 break;
00604 }
00605 p->done = 1;
00606 p->ini_pos = ring_wpos(p->rbuf);
00607
00608
00609
00610
00611
00612
00613 break;
00614
00615 default:
00616
00617 break;
00618 }
00619 }
00620 if (p->done || p->found > 8){
00621 while (c < count && p->found < p->plength+8){
00622 l = count -c;
00623 if (l+p->found > p->plength+8)
00624 l = p->plength+8-p->found;
00625 if (ring_write(p->rbuf, buf+c, l)<0){
00626 fprintf(stderr, "ring buffer overflow %d\n"
00627 ,p->rbuf->size);
00628 exit(1);
00629 }
00630 p->found += l;
00631 c += l;
00632 }
00633 if(p->found == p->plength+8){
00634 func(p);
00635 }
00636 }
00637
00638 if (p->plength && p->found == p->plength+8) {
00639 int a = 0;
00640 init_pes_in(p, 0, NULL, p->withbuf);
00641 if (c+a < count)
00642 get_avi(p, buf+c+a, count-c-a, func);
00643 }
00644 }