Blender V2.61 - r43446

avi.c

Go to the documentation of this file.
00001 /*
00002  *
00003  * This is external code.
00004  *
00005  * ***** BEGIN GPL LICENSE BLOCK *****
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software Foundation,
00019  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00022  * All rights reserved.
00023  *
00024  * The Original Code is: all of this file.
00025  *
00026  * Contributor(s): none yet.
00027  *
00028  * ***** END GPL LICENSE BLOCK *****
00029  *
00030  */
00031 
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <stdarg.h>
00040 #include <stdio.h>
00041 #include <ctype.h>
00042 
00043 #include "MEM_guardedalloc.h"
00044 #include "MEM_sys_types.h"
00045 
00046 #include "BLI_winstuff.h"
00047 
00048 #include "AVI_avi.h"
00049 #include "avi_intern.h"
00050 
00051 #include "endian.h"
00052 
00053 static int AVI_DEBUG=0;
00054 static char DEBUG_FCC[4];
00055 
00056 #define DEBUG_PRINT(x) if(AVI_DEBUG) printf("AVI DEBUG: " x);
00057 
00058 /* local functions */
00059 char *fcc_to_char (unsigned int fcc);
00060 char *tcc_to_char (unsigned int tcc);
00061 
00062 
00063 
00064 /* implemetation */
00065 
00066 unsigned int GET_FCC (FILE *fp)
00067 {
00068     unsigned char tmp[4];
00069 
00070     tmp[0] = getc(fp);
00071     tmp[1] = getc(fp);
00072     tmp[2] = getc(fp);
00073     tmp[3] = getc(fp);
00074 
00075     return FCC (tmp);
00076 }
00077 
00078 unsigned int GET_TCC (FILE *fp)
00079 {
00080     char tmp[5];
00081 
00082     tmp[0] = getc(fp);
00083     tmp[1] = getc(fp);
00084     tmp[2] = 0;
00085     tmp[3] = 0;
00086 
00087     return FCC (tmp);
00088 }
00089 
00090 char *fcc_to_char (unsigned int fcc)
00091 {
00092     DEBUG_FCC[0]= (fcc)&127;
00093     DEBUG_FCC[1]= (fcc>>8)&127;
00094     DEBUG_FCC[2]= (fcc>>16)&127;
00095     DEBUG_FCC[3]= (fcc>>24)&127;
00096 
00097     return DEBUG_FCC;   
00098 }
00099 
00100 char *tcc_to_char (unsigned int tcc)
00101 {
00102     DEBUG_FCC[0]= (tcc)&127;
00103     DEBUG_FCC[1]= (tcc>>8)&127;
00104     DEBUG_FCC[2]= 0;
00105     DEBUG_FCC[3]= 0;
00106 
00107     return DEBUG_FCC;   
00108 }
00109 
00110 int AVI_get_stream (AviMovie *movie, int avist_type, int stream_num)
00111 {
00112     int cur_stream;
00113 
00114     if (movie == NULL)
00115         return -AVI_ERROR_OPTION;
00116 
00117     for (cur_stream=0; cur_stream < movie->header->Streams; cur_stream++) {
00118         if (movie->streams[cur_stream].sh.Type == avist_type) {
00119             if (stream_num == 0)
00120                 return cur_stream;
00121             else
00122                 stream_num--;
00123         }
00124     }
00125 
00126     return -AVI_ERROR_FOUND;
00127 }
00128 
00129 static int fcc_get_stream (int fcc)
00130 {
00131     char fccs[4];
00132 
00133     fccs[0] = fcc;
00134     fccs[1] = fcc>>8;
00135     fccs[2] = fcc>>16;
00136     fccs[3] = fcc>>24;
00137 
00138     return 10*(fccs[0]-'0') + (fccs[1]-'0');
00139 }
00140 
00141 static int fcc_is_data (int fcc)
00142 {
00143     char fccs[4];
00144 
00145     fccs[0] = fcc;
00146     fccs[1] = fcc>>8;
00147     fccs[2] = fcc>>16;
00148     fccs[3] = fcc>>24;
00149 
00150     if (!isdigit (fccs[0]) || !isdigit (fccs[1]) || (fccs[2] != 'd' && fccs[2] != 'w'))
00151         return 0;
00152     if (fccs[3] != 'b' && fccs[3] != 'c')
00153         return 0;
00154 
00155     return 1;
00156 }
00157 
00158 AviError AVI_print_error (AviError in_error)
00159 {
00160     int error;
00161 
00162     if ((int) in_error < 0)
00163         error = -in_error;
00164     else
00165         error = in_error;
00166 
00167     switch (error) {
00168     case AVI_ERROR_NONE:
00169         break;
00170     case AVI_ERROR_COMPRESSION:
00171         printf ("AVI ERROR: compressed in an unsupported format\n");
00172         break;
00173     case AVI_ERROR_OPEN:
00174         printf ("AVI ERROR: could not open file\n");
00175         break;
00176     case AVI_ERROR_READING:
00177         printf ("AVI ERROR: could not read from file\n");
00178         break;
00179     case AVI_ERROR_WRITING:
00180         printf ("AVI ERROR: could not write to file\n");
00181         break;
00182     case AVI_ERROR_FORMAT:
00183         printf ("AVI ERROR: file is in an illegal or unrecognized format\n");
00184         break;
00185     case AVI_ERROR_ALLOC:
00186         printf ("AVI ERROR: error encountered while allocating memory\n");
00187         break;
00188     case AVI_ERROR_OPTION:
00189         printf ("AVI ERROR: program made illegal request\n");
00190         break;
00191     case AVI_ERROR_FOUND:
00192         printf ("AVI ERROR: movie did not contain expected item\n");
00193         break;
00194     default: 
00195         break;
00196     }
00197 
00198     return in_error;
00199 }
00200 /*
00201 void AVI_set_debug (int mode)
00202 {
00203     AVI_DEBUG= mode;
00204 }
00205 */
00206 /*
00207 int AVI_is_avi (char *name)
00208 {
00209     FILE *fp;
00210     int ret;
00211     
00212     fp = fopen (name, "rb");
00213     if (fp == NULL)
00214         return 0;
00215 
00216     if (GET_FCC (fp) != FCC("RIFF") ||
00217         !GET_FCC (fp) ||
00218         GET_FCC (fp) != FCC("AVI ")) {
00219         ret = 0;
00220     } else {
00221         ret = 1;
00222     }
00223 
00224     fclose(fp);
00225     return ret;
00226 }
00227 */
00228 
00229 int AVI_is_avi (const char *name)
00230 {
00231     int temp, fcca, j;
00232     AviMovie movie= {NULL};
00233     AviMainHeader header;
00234     AviBitmapInfoHeader bheader;
00235     int movie_tracks = 0;
00236     
00237     DEBUG_PRINT("opening movie\n");
00238 
00239     movie.type = AVI_MOVIE_READ;
00240     movie.fp = fopen (name, "rb");
00241     movie.offset_table = NULL;
00242 
00243     if (movie.fp == NULL)
00244         return 0;
00245 
00246     if (GET_FCC (movie.fp) != FCC("RIFF") ||
00247         !(movie.size = GET_FCC (movie.fp))) {
00248         fclose(movie.fp);
00249         return 0;
00250     }
00251 
00252     movie.header = &header;
00253 
00254     if (GET_FCC (movie.fp) != FCC("AVI ") ||
00255         GET_FCC (movie.fp) != FCC("LIST") ||
00256         !GET_FCC (movie.fp) ||
00257         GET_FCC (movie.fp) != FCC("hdrl") ||
00258         (movie.header->fcc = GET_FCC (movie.fp)) != FCC("avih") ||
00259         !(movie.header->size = GET_FCC (movie.fp))) {
00260         DEBUG_PRINT("bad initial header info\n");
00261         fclose(movie.fp);
00262         return 0;
00263     }
00264     
00265     movie.header->MicroSecPerFrame = GET_FCC(movie.fp);
00266     movie.header->MaxBytesPerSec = GET_FCC(movie.fp);
00267     movie.header->PaddingGranularity = GET_FCC(movie.fp);
00268     movie.header->Flags = GET_FCC(movie.fp);
00269     movie.header->TotalFrames = GET_FCC(movie.fp);
00270     movie.header->InitialFrames = GET_FCC(movie.fp);
00271     movie.header->Streams = GET_FCC(movie.fp);
00272     movie.header->SuggestedBufferSize = GET_FCC(movie.fp);
00273     movie.header->Width = GET_FCC(movie.fp);
00274     movie.header->Height = GET_FCC(movie.fp);
00275     movie.header->Reserved[0] = GET_FCC(movie.fp);
00276     movie.header->Reserved[1] = GET_FCC(movie.fp);
00277     movie.header->Reserved[2] = GET_FCC(movie.fp);
00278     movie.header->Reserved[3] = GET_FCC(movie.fp);
00279 
00280     fseek (movie.fp, movie.header->size-14*4, SEEK_CUR);
00281 
00282     if (movie.header->Streams < 1) {
00283         DEBUG_PRINT("streams less than 1\n");
00284         fclose(movie.fp);
00285         return 0;
00286     }
00287     
00288     movie.streams = (AviStreamRec *) MEM_callocN (sizeof(AviStreamRec) * movie.header->Streams, "moviestreams");
00289 
00290     for (temp=0; temp < movie.header->Streams; temp++) {
00291 
00292         if (GET_FCC(movie.fp) != FCC("LIST") ||
00293             !GET_FCC (movie.fp) ||
00294             GET_FCC (movie.fp) != FCC ("strl") ||
00295             (movie.streams[temp].sh.fcc = GET_FCC (movie.fp)) != FCC ("strh") ||
00296             !(movie.streams[temp].sh.size = GET_FCC (movie.fp))) {
00297             DEBUG_PRINT("bad stream header information\n");
00298             
00299             MEM_freeN(movie.streams);
00300             fclose(movie.fp);
00301             return 0;               
00302         }
00303 
00304         movie.streams[temp].sh.Type = GET_FCC (movie.fp);
00305         movie.streams[temp].sh.Handler = GET_FCC (movie.fp);
00306 
00307         fcca = movie.streams[temp].sh.Handler;
00308         
00309         if (movie.streams[temp].sh.Type == FCC("vids")) {
00310             if (fcca == FCC ("DIB ") ||
00311                 fcca == FCC ("RGB ") ||
00312                 fcca == FCC ("rgb ") ||
00313                 fcca == FCC ("RAW ") ||
00314                 fcca == 0) {
00315                 movie.streams[temp].format = AVI_FORMAT_AVI_RGB;
00316             } else if (fcca == FCC ("mjpg")||fcca == FCC ("MJPG")) {
00317                 movie.streams[temp].format = AVI_FORMAT_MJPEG;
00318             } else {
00319                 MEM_freeN(movie.streams);
00320                 fclose(movie.fp);
00321                 return 0;
00322             }
00323             movie_tracks++;
00324         }
00325         
00326         movie.streams[temp].sh.Flags = GET_FCC (movie.fp);
00327         movie.streams[temp].sh.Priority = GET_TCC (movie.fp);
00328         movie.streams[temp].sh.Language = GET_TCC (movie.fp);
00329         movie.streams[temp].sh.InitialFrames = GET_FCC (movie.fp);
00330         movie.streams[temp].sh.Scale = GET_FCC (movie.fp);
00331         movie.streams[temp].sh.Rate = GET_FCC (movie.fp);
00332         movie.streams[temp].sh.Start = GET_FCC (movie.fp);
00333         movie.streams[temp].sh.Length = GET_FCC (movie.fp);
00334         movie.streams[temp].sh.SuggestedBufferSize = GET_FCC (movie.fp);
00335         movie.streams[temp].sh.Quality = GET_FCC (movie.fp);
00336         movie.streams[temp].sh.SampleSize = GET_FCC (movie.fp);
00337         movie.streams[temp].sh.left = GET_TCC (movie.fp);
00338         movie.streams[temp].sh.top = GET_TCC (movie.fp);
00339         movie.streams[temp].sh.right = GET_TCC (movie.fp);
00340         movie.streams[temp].sh.bottom = GET_TCC (movie.fp);
00341 
00342         fseek (movie.fp, movie.streams[temp].sh.size-14*4, SEEK_CUR);
00343 
00344         if (GET_FCC (movie.fp) != FCC("strf")) {
00345             DEBUG_PRINT("no stream format information\n");
00346             MEM_freeN(movie.streams);
00347             fclose(movie.fp);
00348             return 0;
00349         }
00350 
00351         movie.streams[temp].sf_size= GET_FCC(movie.fp);
00352         if (movie.streams[temp].sh.Type == FCC("vids")) {
00353             j = movie.streams[temp].sf_size - (sizeof(AviBitmapInfoHeader) - 8);
00354             if (j >= 0) {
00355                 AviBitmapInfoHeader *bi;
00356                 
00357                 movie.streams[temp].sf= &bheader;
00358                 bi= (AviBitmapInfoHeader *) movie.streams[temp].sf;
00359                 
00360                 bi->fcc= FCC("strf");
00361                 bi->size= movie.streams[temp].sf_size;
00362                 bi->Size= GET_FCC(movie.fp);
00363                 bi->Width= GET_FCC(movie.fp);
00364                 bi->Height= GET_FCC(movie.fp);
00365                 bi->Planes= GET_TCC(movie.fp);
00366                 bi->BitCount= GET_TCC(movie.fp);
00367                 bi->Compression= GET_FCC(movie.fp);
00368                 bi->SizeImage= GET_FCC(movie.fp);
00369                 bi->XPelsPerMeter= GET_FCC(movie.fp);
00370                 bi->YPelsPerMeter= GET_FCC(movie.fp);
00371                 bi->ClrUsed= GET_FCC(movie.fp);
00372                 bi->ClrImportant= GET_FCC(movie.fp);
00373                 
00374                 fcca = bi->Compression;
00375 
00376                 if ( movie.streams[temp].format ==
00377                      AVI_FORMAT_AVI_RGB) {
00378                     if (fcca == FCC ("DIB ") ||
00379                         fcca == FCC ("RGB ") ||
00380                         fcca == FCC ("rgb ") ||
00381                         fcca == FCC ("RAW ") ||
00382                         fcca == 0 ) {
00383                     } else if ( fcca == FCC ("mjpg") || 
00384                         fcca == FCC ("MJPG")) {
00385                             movie.streams[temp].format = AVI_FORMAT_MJPEG;
00386                     } else {
00387                         MEM_freeN(movie.streams);
00388                         fclose(movie.fp);
00389                         return 0;
00390                     }
00391                 }
00392 
00393             } 
00394             if (j > 0) fseek (movie.fp, j, SEEK_CUR);
00395         } else fseek (movie.fp, movie.streams[temp].sf_size, SEEK_CUR);
00396 
00397         /* Walk to the next LIST */     
00398         while (GET_FCC (movie.fp) != FCC("LIST")) {
00399             temp= GET_FCC (movie.fp);
00400             if (temp<0 || ftell(movie.fp) > movie.size) {
00401                 DEBUG_PRINT("incorrect size in header or error in AVI\n");
00402                 
00403                 MEM_freeN(movie.streams);
00404                 fclose(movie.fp);
00405                 return 0;               
00406             }
00407             fseek(movie.fp, temp, SEEK_CUR);            
00408         }
00409 
00410         fseek(movie.fp, -4L, SEEK_CUR);
00411     }
00412     
00413     MEM_freeN(movie.streams);
00414     fclose(movie.fp);
00415 
00416     /* at least one video track is needed */
00417     return (movie_tracks != 0); 
00418 
00419 }
00420 
00421 AviError AVI_open_movie (const char *name, AviMovie *movie)
00422 {
00423     int temp, fcca, size, j;
00424     
00425     DEBUG_PRINT("opening movie\n");
00426 
00427     memset(movie, 0, sizeof(AviMovie));
00428 
00429     movie->type = AVI_MOVIE_READ;
00430     movie->fp = fopen (name, "rb");
00431     movie->offset_table = NULL;
00432 
00433     if (movie->fp == NULL)
00434         return AVI_ERROR_OPEN;
00435 
00436     if (GET_FCC (movie->fp) != FCC("RIFF") ||
00437         !(movie->size = GET_FCC (movie->fp)))
00438         return AVI_ERROR_FORMAT;
00439 
00440     movie->header = (AviMainHeader *) MEM_mallocN (sizeof (AviMainHeader), "movieheader");
00441 
00442     if (GET_FCC (movie->fp) != FCC("AVI ") ||
00443         GET_FCC (movie->fp) != FCC("LIST") ||
00444         !GET_FCC (movie->fp) ||
00445         GET_FCC (movie->fp) != FCC("hdrl") ||
00446         (movie->header->fcc = GET_FCC (movie->fp)) != FCC("avih") ||
00447         !(movie->header->size = GET_FCC (movie->fp))) {
00448         DEBUG_PRINT("bad initial header info\n");
00449         return AVI_ERROR_FORMAT;
00450     }
00451     
00452     movie->header->MicroSecPerFrame = GET_FCC(movie->fp);
00453     movie->header->MaxBytesPerSec = GET_FCC(movie->fp);
00454     movie->header->PaddingGranularity = GET_FCC(movie->fp);
00455     movie->header->Flags = GET_FCC(movie->fp);
00456     movie->header->TotalFrames = GET_FCC(movie->fp);
00457     movie->header->InitialFrames = GET_FCC(movie->fp);
00458     movie->header->Streams = GET_FCC(movie->fp);
00459     movie->header->SuggestedBufferSize = GET_FCC(movie->fp);
00460     movie->header->Width = GET_FCC(movie->fp);
00461     movie->header->Height = GET_FCC(movie->fp);
00462     movie->header->Reserved[0] = GET_FCC(movie->fp);
00463     movie->header->Reserved[1] = GET_FCC(movie->fp);
00464     movie->header->Reserved[2] = GET_FCC(movie->fp);
00465     movie->header->Reserved[3] = GET_FCC(movie->fp);
00466 
00467     fseek (movie->fp, movie->header->size-14*4, SEEK_CUR);
00468 
00469     if (movie->header->Streams < 1) {
00470         DEBUG_PRINT("streams less than 1\n");
00471         return AVI_ERROR_FORMAT;
00472     }
00473     
00474     movie->streams = (AviStreamRec *) MEM_callocN (sizeof(AviStreamRec) * movie->header->Streams, "moviestreams");
00475 
00476     for (temp=0; temp < movie->header->Streams; temp++) {
00477 
00478         if (GET_FCC(movie->fp) != FCC("LIST") ||
00479             !GET_FCC (movie->fp) ||
00480             GET_FCC (movie->fp) != FCC ("strl") ||
00481             (movie->streams[temp].sh.fcc = GET_FCC (movie->fp)) != FCC ("strh") ||
00482             !(movie->streams[temp].sh.size = GET_FCC (movie->fp))) {
00483             DEBUG_PRINT("bad stream header information\n");
00484             return AVI_ERROR_FORMAT;                
00485         }
00486 
00487         movie->streams[temp].sh.Type = GET_FCC (movie->fp);
00488         movie->streams[temp].sh.Handler = GET_FCC (movie->fp);
00489 
00490         fcca = movie->streams[temp].sh.Handler;
00491         
00492         if (movie->streams[temp].sh.Type == FCC("vids")) {
00493             if (fcca == FCC ("DIB ") ||
00494                 fcca == FCC ("RGB ") ||
00495                 fcca == FCC ("rgb ") ||
00496                 fcca == FCC ("RAW ") ||
00497                 fcca == 0) {
00498                 movie->streams[temp].format = AVI_FORMAT_AVI_RGB;
00499             } else if (fcca == FCC ("mjpg")||fcca == FCC ("MJPG")) {
00500                 movie->streams[temp].format = AVI_FORMAT_MJPEG;
00501             } else {
00502                 return AVI_ERROR_COMPRESSION;
00503             }
00504         }
00505         
00506         movie->streams[temp].sh.Flags = GET_FCC (movie->fp);
00507         movie->streams[temp].sh.Priority = GET_TCC (movie->fp);
00508         movie->streams[temp].sh.Language = GET_TCC (movie->fp);
00509         movie->streams[temp].sh.InitialFrames = GET_FCC (movie->fp);
00510         movie->streams[temp].sh.Scale = GET_FCC (movie->fp);
00511         movie->streams[temp].sh.Rate = GET_FCC (movie->fp);
00512         movie->streams[temp].sh.Start = GET_FCC (movie->fp);
00513         movie->streams[temp].sh.Length = GET_FCC (movie->fp);
00514         movie->streams[temp].sh.SuggestedBufferSize = GET_FCC (movie->fp);
00515         movie->streams[temp].sh.Quality = GET_FCC (movie->fp);
00516         movie->streams[temp].sh.SampleSize = GET_FCC (movie->fp);
00517         movie->streams[temp].sh.left = GET_TCC (movie->fp);
00518         movie->streams[temp].sh.top = GET_TCC (movie->fp);
00519         movie->streams[temp].sh.right = GET_TCC (movie->fp);
00520         movie->streams[temp].sh.bottom = GET_TCC (movie->fp);
00521 
00522         fseek (movie->fp, movie->streams[temp].sh.size-14*4, SEEK_CUR);
00523 
00524         if (GET_FCC (movie->fp) != FCC("strf")) {
00525             DEBUG_PRINT("no stream format information\n");
00526             return AVI_ERROR_FORMAT;
00527         }
00528 
00529         movie->streams[temp].sf_size= GET_FCC(movie->fp);
00530         if (movie->streams[temp].sh.Type == FCC("vids")) {
00531             j = movie->streams[temp].sf_size - (sizeof(AviBitmapInfoHeader) - 8);
00532             if (j >= 0) {
00533                 AviBitmapInfoHeader *bi;
00534                 
00535                 movie->streams[temp].sf= MEM_mallocN(sizeof(AviBitmapInfoHeader), "streamformat");
00536                 
00537                 bi= (AviBitmapInfoHeader *) movie->streams[temp].sf;
00538                 
00539                 bi->fcc= FCC("strf");
00540                 bi->size= movie->streams[temp].sf_size;
00541                 bi->Size= GET_FCC(movie->fp);
00542                 bi->Width= GET_FCC(movie->fp);
00543                 bi->Height= GET_FCC(movie->fp);
00544                 bi->Planes= GET_TCC(movie->fp);
00545                 bi->BitCount= GET_TCC(movie->fp);
00546                 bi->Compression= GET_FCC(movie->fp);
00547                 bi->SizeImage= GET_FCC(movie->fp);
00548                 bi->XPelsPerMeter= GET_FCC(movie->fp);
00549                 bi->YPelsPerMeter= GET_FCC(movie->fp);
00550                 bi->ClrUsed= GET_FCC(movie->fp);
00551                 bi->ClrImportant= GET_FCC(movie->fp);
00552                 
00553                 fcca = bi->Compression;
00554 
00555                                 if ( movie->streams[temp].format ==
00556                      AVI_FORMAT_AVI_RGB) {
00557                     if (fcca == FCC ("DIB ") ||
00558                         fcca == FCC ("RGB ") ||
00559                         fcca == FCC ("rgb ") ||
00560                         fcca == FCC ("RAW ") ||
00561                         fcca == 0 ) {
00562                     } else if ( fcca == FCC ("mjpg") || 
00563                         fcca == FCC ("MJPG")) {
00564                             movie->streams[temp].format = AVI_FORMAT_MJPEG;
00565                     } else {
00566                         return AVI_ERROR_COMPRESSION;
00567                     }
00568                 }
00569 
00570             } 
00571             if (j > 0) fseek (movie->fp, j, SEEK_CUR);
00572         } else fseek (movie->fp, movie->streams[temp].sf_size, SEEK_CUR);
00573         
00574         /* Walk to the next LIST */     
00575         while (GET_FCC (movie->fp) != FCC("LIST")) {
00576             temp= GET_FCC (movie->fp);
00577             if (temp<0 || ftell(movie->fp) > movie->size) {
00578                 DEBUG_PRINT("incorrect size in header or error in AVI\n");
00579                 return AVI_ERROR_FORMAT;                
00580             }
00581             fseek(movie->fp, temp, SEEK_CUR);           
00582         }
00583         
00584         fseek(movie->fp, -4L, SEEK_CUR);        
00585     }
00586 
00587     while (1) {
00588         temp = GET_FCC (movie->fp);
00589         size = GET_FCC (movie->fp);
00590 
00591         if (size == 0)
00592             break;
00593 
00594         if (temp == FCC("LIST")) {
00595             if (GET_FCC(movie->fp) == FCC ("movi"))
00596                 break;
00597             else
00598                 fseek (movie->fp, size-4, SEEK_CUR);
00599         } else {
00600             fseek (movie->fp, size, SEEK_CUR);
00601         }
00602         if (ftell(movie->fp) > movie->size) {
00603             DEBUG_PRINT("incorrect size in header or error in AVI\n");
00604             return AVI_ERROR_FORMAT;
00605         }
00606     }
00607 
00608     movie->movi_offset = ftell (movie->fp);
00609     movie->read_offset = movie->movi_offset;
00610     
00611     /* Read in the index if the file has one, otherwise create one */
00612     if (movie->header->Flags & AVIF_HASINDEX) {
00613         fseek(movie->fp, size-4, SEEK_CUR);
00614 
00615         if (GET_FCC(movie->fp) != FCC("idx1")) {
00616             DEBUG_PRINT("bad index informatio\n");
00617             return AVI_ERROR_FORMAT;
00618         }
00619 
00620         movie->index_entries = GET_FCC (movie->fp)/sizeof(AviIndexEntry);
00621         if (movie->index_entries == 0) {
00622             DEBUG_PRINT("no index entries\n");
00623             return AVI_ERROR_FORMAT;
00624         }
00625 
00626         movie->entries = (AviIndexEntry *) MEM_mallocN (movie->index_entries * sizeof(AviIndexEntry),"movieentries");
00627 
00628         for (temp=0; temp < movie->index_entries; temp++) {
00629             movie->entries[temp].ChunkId = GET_FCC (movie->fp);
00630             movie->entries[temp].Flags = GET_FCC (movie->fp);
00631             movie->entries[temp].Offset = GET_FCC (movie->fp);
00632             movie->entries[temp].Size = GET_FCC (movie->fp);
00633             
00634             if (AVI_DEBUG) {
00635                 printf("Index entry %04d: ChunkId:%s Flags:%d Offset:%d Size:%d\n",
00636                        temp, fcc_to_char(movie->entries[temp].ChunkId), movie->entries[temp].Flags,
00637                        movie->entries[temp].Offset, movie->entries[temp].Size);
00638             }
00639         }
00640 
00641 /* Some AVI's have offset entries in absolute coordinates
00642  * instead of an offset from the movie beginning... this is...
00643  * wacky, but we need to handle it. The wacky offset always
00644  * starts at movi_offset it seems... so we'll check that.
00645  * Note the the offset needs an extra 4 bytes for some 
00646  * undetermined reason */
00647  
00648         if (movie->entries[0].Offset == movie->movi_offset)
00649             movie->read_offset= 4;
00650     }
00651 
00652     DEBUG_PRINT("movie succesfully opened\n");
00653     return AVI_ERROR_NONE;
00654 }
00655 
00656 void *AVI_read_frame (AviMovie *movie, AviFormat format, int frame, int stream)
00657 {
00658     int cur_frame=-1, temp, i=0, rewind=1;
00659     void *buffer;
00660 
00661     /* Retrieve the record number of the desired frame in the index 
00662         If a chunk has Size 0 we need to rewind to previous frame */
00663     while(rewind && frame > -1) {
00664         i=0;
00665         cur_frame=-1;
00666         rewind = 0;
00667 
00668         while (cur_frame < frame && i < movie->index_entries) {
00669             if (fcc_is_data (movie->entries[i].ChunkId) &&
00670                 fcc_get_stream (movie->entries[i].ChunkId) == stream) {
00671                 if ((cur_frame == frame -1) && (movie->entries[i].Size == 0)) {
00672                     rewind = 1;
00673                     frame = frame -1;
00674                 } else {
00675                     cur_frame++;
00676                 }
00677             }
00678             i++;
00679         }
00680     }
00681 
00682     if (cur_frame != frame) return NULL;
00683 
00684 
00685     fseek (movie->fp, movie->read_offset + movie->entries[i-1].Offset, SEEK_SET);
00686 
00687     temp = GET_FCC(movie->fp);
00688     buffer = MEM_mallocN (temp,"readbuffer");
00689 
00690     if (fread (buffer, 1, temp, movie->fp) != temp) {
00691         MEM_freeN(buffer);
00692 
00693         return NULL;
00694     }
00695     
00696     buffer = avi_format_convert (movie, stream, buffer, movie->streams[stream].format, format, &temp);
00697 
00698     return buffer;
00699 }
00700 
00701 AviError AVI_close (AviMovie *movie)
00702 {
00703     int i;
00704 
00705     fclose (movie->fp);
00706 
00707     for (i=0; i < movie->header->Streams; i++) {
00708         if (movie->streams[i].sf != NULL)
00709             MEM_freeN (movie->streams[i].sf);
00710     }
00711 
00712     if (movie->header != NULL)
00713         MEM_freeN (movie->header);
00714     if (movie->streams!= NULL)
00715         MEM_freeN (movie->streams);
00716     if (movie->entries != NULL)
00717         MEM_freeN (movie->entries);
00718     if (movie->offset_table != NULL)
00719         MEM_freeN (movie->offset_table);
00720 
00721     return AVI_ERROR_NONE;
00722 }
00723 
00724 AviError AVI_open_compress (char *name, AviMovie *movie, int streams, ...)
00725 {
00726     va_list ap;
00727     AviList list;
00728     AviChunk chunk;
00729     int i;
00730     int64_t header_pos1, header_pos2;
00731     int64_t stream_pos1, stream_pos2;
00732 
00733     movie->type = AVI_MOVIE_WRITE;
00734     movie->fp = fopen (name, "wb");
00735 
00736     movie->index_entries = 0;
00737 
00738     if (movie->fp == NULL)
00739         return AVI_ERROR_OPEN;
00740 
00741     movie->offset_table = (int64_t *) MEM_mallocN ((1+streams*2) * sizeof (int64_t),"offsettable");
00742     
00743     for (i=0; i < 1 + streams*2; i++)
00744         movie->offset_table[i] = -1L;
00745 
00746     movie->entries = NULL;
00747 
00748     movie->header = (AviMainHeader *) MEM_mallocN (sizeof(AviMainHeader),"movieheader");
00749 
00750     movie->header->fcc = FCC("avih");
00751     movie->header->size = 56;
00752     movie->header->MicroSecPerFrame = 66667;
00753     movie->header->MaxBytesPerSec = 0;
00754     movie->header->PaddingGranularity = 0;
00755     movie->header->Flags = AVIF_HASINDEX | AVIF_MUSTUSEINDEX;
00756     movie->header->TotalFrames = 0;
00757     movie->header->InitialFrames = 0;
00758     movie->header->Streams = streams;
00759     movie->header->SuggestedBufferSize = 0;
00760     movie->header->Width = 0;
00761     movie->header->Height = 0;
00762     movie->header->Reserved[0] = 0;
00763     movie->header->Reserved[1] = 0;
00764     movie->header->Reserved[2] = 0;
00765     movie->header->Reserved[3] = 0;
00766 
00767     movie->streams = (AviStreamRec *) MEM_mallocN (sizeof(AviStreamRec) * movie->header->Streams,"moviestreams");
00768 
00769     va_start (ap, streams);
00770 
00771     for (i=0; i < movie->header->Streams; i++) {
00772         movie->streams[i].format = va_arg(ap, AviFormat);
00773 
00774         movie->streams[i].sh.fcc = FCC ("strh");
00775         movie->streams[i].sh.size = 56;
00776         movie->streams[i].sh.Type = avi_get_format_type (movie->streams[i].format);
00777         if (movie->streams[i].sh.Type == 0)
00778             return AVI_ERROR_FORMAT;
00779 
00780         movie->streams[i].sh.Handler = avi_get_format_fcc (movie->streams[i].format);
00781         if (movie->streams[i].sh.Handler == 0)
00782             return AVI_ERROR_FORMAT;
00783 
00784         movie->streams[i].sh.Flags = 0;
00785         movie->streams[i].sh.Priority = 0;
00786         movie->streams[i].sh.Language = 0;
00787         movie->streams[i].sh.InitialFrames = 0;
00788         movie->streams[i].sh.Scale = 66667;
00789         movie->streams[i].sh.Rate = 1000000;
00790         movie->streams[i].sh.Start = 0;
00791         movie->streams[i].sh.Length = 0;
00792         movie->streams[i].sh.SuggestedBufferSize = 0;
00793         movie->streams[i].sh.Quality = 10000;
00794         movie->streams[i].sh.SampleSize = 0;
00795         movie->streams[i].sh.left = 0;
00796         movie->streams[i].sh.top = 0;
00797         movie->streams[i].sh.right = 0;
00798         movie->streams[i].sh.bottom = 0;
00799 
00800         if (movie->streams[i].sh.Type == FCC("vids")) { 
00801 /*
00802             if (movie->streams[i].format == AVI_FORMAT_MJPEG) {
00803                 movie->streams[i].sf = MEM_mallocN (sizeof(AviBitmapInfoHeader) 
00804                                         + sizeof(AviMJPEGUnknown),"moviestreamformatL");
00805                 movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader) + sizeof(AviMJPEGUnknown);
00806             } else {
00807 */
00808             movie->streams[i].sf = MEM_mallocN (sizeof(AviBitmapInfoHeader),  "moviestreamformatS");
00809             movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader);
00810 
00811             ((AviBitmapInfoHeader *) movie->streams[i].sf)->fcc = FCC ("strf");
00812             ((AviBitmapInfoHeader *) movie->streams[i].sf)->size = movie->streams[i].sf_size - 8;
00813             ((AviBitmapInfoHeader *) movie->streams[i].sf)->Size = movie->streams[i].sf_size - 8;
00814             ((AviBitmapInfoHeader *) movie->streams[i].sf)->Width = 0;
00815             ((AviBitmapInfoHeader *) movie->streams[i].sf)->Height = 0;
00816             ((AviBitmapInfoHeader *) movie->streams[i].sf)->Planes = 1;
00817             ((AviBitmapInfoHeader *) movie->streams[i].sf)->BitCount = 24;
00818             ((AviBitmapInfoHeader *) movie->streams[i].sf)->Compression = avi_get_format_compression (movie->streams[i].format);
00819             ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = 0;
00820             ((AviBitmapInfoHeader *) movie->streams[i].sf)->XPelsPerMeter = 0;
00821             ((AviBitmapInfoHeader *) movie->streams[i].sf)->YPelsPerMeter = 0;
00822             ((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrUsed = 0;
00823             ((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrImportant = 0;
00824 
00825 /*
00826             if (movie->streams[i].format == AVI_FORMAT_MJPEG) {
00827                 AviMJPEGUnknown *tmp;
00828                 
00829                 tmp = (AviMJPEGUnknown *) ((char*) movie->streams[i].sf +sizeof(AviBitmapInfoHeader));
00830                 
00831                 tmp->a = 44;
00832                 tmp->b = 24;
00833                 tmp->c = 0;
00834                 tmp->d = 2;
00835                 tmp->e = 8;
00836                 tmp->f = 2;
00837                 tmp->g = 1;
00838             }
00839         } else if (movie->streams[i].sh.Type == FCC("auds")) {
00840             ;
00841 */
00842         }
00843     }
00844 
00845     list.fcc = FCC("RIFF");
00846     list.size = 0;
00847     list.ids = FCC("AVI ");
00848 
00849     awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
00850 
00851     list.fcc = FCC("LIST");
00852     list.size = 0;
00853     list.ids = FCC("hdrl");
00854 
00855     awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
00856 
00857     header_pos1 = ftell(movie->fp);
00858 
00859     movie->offset_table[0] = ftell(movie->fp);
00860 
00861     awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
00862 
00863     for (i=0; i < movie->header->Streams; i++) {
00864         list.fcc = FCC("LIST");
00865         list.size = 0;
00866         list.ids = FCC("strl");
00867 
00868         awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
00869 
00870         stream_pos1 = ftell(movie->fp);
00871 
00872         movie->offset_table[1+i*2] = ftell(movie->fp);
00873         awrite (movie, &movie->streams[i].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH);
00874 
00875         movie->offset_table[1+i*2+1] = ftell(movie->fp);
00876         awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
00877 
00878         stream_pos2 = ftell(movie->fp);
00879 
00880         fseek (movie->fp, stream_pos1-8, SEEK_SET);
00881 
00882         PUT_FCCN((stream_pos2-stream_pos1+4L), movie->fp);
00883 
00884         fseek (movie->fp, stream_pos2, SEEK_SET);
00885     }
00886 
00887     if (ftell(movie->fp) < 2024 - 8) {
00888         chunk.fcc = FCC("JUNK");
00889         chunk.size = 2024-8-ftell(movie->fp);
00890 
00891         awrite (movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK);
00892 
00893         for (i=0; i < chunk.size; i++)
00894             putc(0, movie->fp);
00895     }
00896 
00897     header_pos2 = ftell(movie->fp);
00898 
00899     list.fcc = FCC("LIST");
00900     list.size = 0;
00901     list.ids = FCC("movi");
00902 
00903     awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
00904 
00905     movie->movi_offset = ftell(movie->fp)-8L;
00906 
00907     fseek (movie->fp, AVI_HDRL_SOFF, SEEK_SET);
00908 
00909     PUT_FCCN((header_pos2-header_pos1+4L), movie->fp);
00910 
00911     return AVI_ERROR_NONE;
00912 }
00913 
00914 AviError AVI_write_frame (AviMovie *movie, int frame_num, ...)
00915 {
00916     AviList list;
00917     AviChunk chunk;
00918     AviIndexEntry *temp;
00919     va_list ap;
00920     int stream;
00921     int64_t rec_off;
00922     AviFormat format;
00923     void *buffer;
00924     int size;
00925 
00926     if (frame_num < 0)
00927         return AVI_ERROR_OPTION;
00928 
00929     /* Allocate the new memory for the index entry */
00930 
00931     if (frame_num+1 > movie->index_entries) {
00932         temp = (AviIndexEntry *) MEM_mallocN ((frame_num+1) * 
00933             (movie->header->Streams+1) * sizeof(AviIndexEntry),"newidxentry");
00934         if (movie->entries != NULL) {
00935             memcpy (temp, movie->entries, movie->index_entries * (movie->header->Streams+1)
00936                 * sizeof(AviIndexEntry));
00937             MEM_freeN (movie->entries);
00938         }
00939 
00940         movie->entries = temp;
00941         movie->index_entries = frame_num+1;
00942     }
00943 
00944     /* Slap a new record entry onto the end of the file */
00945 
00946     fseek (movie->fp, 0L, SEEK_END);
00947 
00948     list.fcc = FCC("LIST");
00949     list.size = 0;
00950     list.ids = FCC("rec ");
00951 
00952     awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
00953 
00954     rec_off = ftell (movie->fp)-8L;
00955 
00956     /* Write a frame for every stream */
00957 
00958     va_start (ap, frame_num);
00959 
00960     for (stream=0; stream < movie->header->Streams; stream++) {
00961         unsigned int tbuf=0;
00962         
00963         format = va_arg (ap, AviFormat);
00964         buffer = va_arg (ap, void*);
00965         size = va_arg (ap, int);
00966 
00967         /* Convert the buffer into the output format */
00968         buffer = avi_format_convert (movie, stream, buffer, format, movie->streams[stream].format, &size);
00969 
00970         /* Write the header info for this data chunk */
00971 
00972         fseek (movie->fp, 0L, SEEK_END);
00973 
00974         chunk.fcc = avi_get_data_id (format, stream);
00975         chunk.size = size;
00976         
00977         if (size%4) chunk.size += 4 - size%4;
00978         
00979         awrite (movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK);
00980 
00981         /* Write the index entry for this data chunk */
00982 
00983         movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].ChunkId = chunk.fcc;
00984         movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Flags = AVIIF_KEYFRAME;
00985         movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Offset = ftell(movie->fp)-12L-movie->movi_offset;
00986         movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Size = chunk.size;
00987 
00988         /* Write the chunk */
00989         awrite (movie, buffer, 1, size, movie->fp, AVI_RAW);
00990         MEM_freeN (buffer);
00991 
00992         if (size%4) awrite (movie, &tbuf, 1, 4-size%4, movie->fp, AVI_RAW);
00993 
00994         /* Update the stream headers length field */
00995         movie->streams[stream].sh.Length++;
00996         fseek (movie->fp, movie->offset_table[1+stream*2], SEEK_SET);
00997         awrite (movie, &movie->streams[stream].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH);
00998     }
00999     va_end (ap);
01000 
01001     /* Record the entry for the new record */
01002 
01003     fseek (movie->fp, 0L, SEEK_END);
01004 
01005     movie->entries[frame_num * (movie->header->Streams+1)].ChunkId = FCC("rec ");
01006     movie->entries[frame_num * (movie->header->Streams+1)].Flags = AVIIF_LIST;
01007     movie->entries[frame_num * (movie->header->Streams+1)].Offset = rec_off-8L-movie->movi_offset;
01008     movie->entries[frame_num * (movie->header->Streams+1)].Size = ftell(movie->fp)-(rec_off+4L);
01009 
01010     /* Update the record size */
01011     fseek (movie->fp, rec_off, SEEK_SET);
01012     PUT_FCCN (movie->entries[frame_num * (movie->header->Streams+1)].Size, movie->fp);
01013 
01014     /* Update the main header information in the file */
01015     movie->header->TotalFrames++;
01016     fseek (movie->fp, movie->offset_table[0], SEEK_SET);
01017     awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
01018 
01019     return AVI_ERROR_NONE;
01020 }
01021 
01022 AviError AVI_close_compress (AviMovie *movie)
01023 {
01024     int temp, movi_size, i;
01025 
01026     fseek (movie->fp, 0L, SEEK_END);
01027     movi_size = ftell (movie->fp);
01028 
01029     PUT_FCC ("idx1", movie->fp);
01030     PUT_FCCN ((movie->index_entries*(movie->header->Streams+1)*16), movie->fp);
01031 
01032     for (temp=0; temp < movie->index_entries*(movie->header->Streams+1); temp++)
01033         awrite (movie, &movie->entries[temp], 1, sizeof(AviIndexEntry), movie->fp, AVI_INDEXE);
01034 
01035     temp = ftell (movie->fp);
01036 
01037     fseek (movie->fp, AVI_RIFF_SOFF, SEEK_SET);
01038 
01039     PUT_FCCN((temp-8L), movie->fp);
01040 
01041     fseek (movie->fp, movie->movi_offset, SEEK_SET);
01042 
01043     PUT_FCCN((movi_size-(movie->movi_offset+4L)),movie->fp);
01044 
01045     fclose (movie->fp);
01046 
01047     for (i=0; i < movie->header->Streams; i++) {
01048         if (movie->streams[i].sf != NULL)
01049             MEM_freeN (movie->streams[i].sf);
01050     }
01051     if (movie->header != NULL)
01052         MEM_freeN (movie->header);
01053     if (movie->entries != NULL)
01054         MEM_freeN (movie->entries);
01055     if (movie->streams != NULL)
01056         MEM_freeN (movie->streams);
01057     if (movie->offset_table != NULL)
01058         MEM_freeN (movie->offset_table);
01059     return AVI_ERROR_NONE;
01060 }