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