|
MythTV
0.26-pre
|
00001 /* 00002 * avi.c: AVI container functions for replex 00003 * 00004 * 00005 * Copyright (C) 2003 Marcus Metzler <mocm@metzlerbros.de> 00006 * Metzler Brothers Systementwicklung GbR 00007 * Changes to use MythTV logging 00008 * Copyright (C) 2011 Gavin Hurlbut <ghurlbut@mythtv.org> 00009 * 00010 * This program is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU General Public License 00012 * as published by the Free Software Foundation; either version 2 00013 * of the License, or (at your option) any later version. 00014 * 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * General Public License for more details. 00020 * 00021 * 00022 * You should have received a copy of the GNU General Public License 00023 * along with this program; if not, write to the Free Software 00024 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00025 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 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 print_index(ac,ac->num_idx_frames-1); 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 // show_buf(buf,16); 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 // show_buf(buf,16); 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;//ALIGN(p->plength); 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 }
1.7.6.1