MythTV  0.26-pre
avi.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends