/* aoi0.c - Don Yang (uguu.org) Extract WAV from AVI files. 08/18/02 */ #include #include #include #define STATE_SEEN_HDRL 1 #define STATE_SEEN_AVIH 2 #define STATE_SEEN_AUDS 4 #define STATE_SEEN_MOVI 8 #define STATE_WROTE_WAVE 16 #define STATE_WROTE_MOVI 32 static unsigned int FourCC(char *str); static int ParseFile(FILE *infile, FILE *outfile, int *headersize, int *datasize); static int ParseChunk(FILE *infile, FILE *outfile, int chunksize, int *state, int *headersize, int *datasize); static int ParseList(FILE *infile, FILE *outfile, int listsize, int *state, int *headersize, int *datasize); /******************************************************************** main */ int main(int argc, char **argv) { FILE *infile, *outfile; int headersize, datasize; if( argc < 3 ) return printf("%s \n", *argv); if( (infile = fopen(argv[1], "rb")) == NULL ) { printf("Can not open %s\n", argv[1]); return 1; } if( (outfile = fopen(argv[2], "wb+")) == NULL ) { fclose(infile); printf("Can not create %s\n", argv[2]); return 1; } headersize = datasize = 0; if( ParseFile(infile, outfile, &headersize, &datasize) == 0 ) { fseek(outfile, 16, SEEK_SET); fwrite(&headersize, 4, 1, outfile); fseek(outfile, headersize + 4, SEEK_CUR); fwrite(&datasize, 4, 1, outfile); datasize += headersize + 20; fseek(outfile, 4, SEEK_SET); fwrite(&datasize, 4, 1, outfile); } else { puts("failed"); } fclose(infile); fclose(outfile); return 0; } /* main() */ /****************************************************************** FourCC */ static unsigned int FourCC(char *str) { return ((unsigned int)str[0]) | (((unsigned int)str[1]) << 8) | (((unsigned int)str[2]) << 16) | (((unsigned int)str[3]) << 24); } /* FourCC() */ /*************************************************************** ParseFile */ static int ParseFile(FILE *infile, FILE *outfile, int *headersize, int *datasize) { unsigned int tag; int size, rsize, state; fread(&tag, 4, 1, infile); fread(&size, 4, 1, infile); if( tag != FourCC("RIFF") ) return 1; fread(&tag, 4, 1, infile); if( tag != FourCC("AVI ") ) return 1; state = 0; do { rsize = ParseChunk(infile, outfile, size, &state, headersize, datasize); if( rsize == 0 ) return 1; size -= rsize; } while( (state & STATE_WROTE_MOVI) == 0 ); return 0; } /* ParseFile() */ /************************************************************** ParseChunk */ static int ParseChunk(FILE *infile, FILE *outfile, int chunksize, int *state, int *headersize, int *datasize) { unsigned int tag; char *buffer; int size; fread(&tag, 4, 1, infile); fread(&size, 4, 1, infile); if( tag == FourCC("LIST") ) return ParseList(infile, outfile, size, state, headersize, datasize); if( (*state & STATE_SEEN_HDRL) && tag == FourCC("avih") ) { *state |= STATE_SEEN_AVIH; fseek(infile, size, SEEK_CUR); } else if( (*state & STATE_SEEN_AVIH) && tag == FourCC("strh") ) { fread(&tag, 4, 1, infile); if( tag == FourCC("auds") ) *state |= STATE_SEEN_AUDS; fseek(infile, size - 4, SEEK_CUR); } else if( (*state & STATE_SEEN_AUDS) && tag == FourCC("strf") ) { fwrite("RIFF\0\0\0\0WAVEfmt \0\0\0\0", 20, 1, outfile); if( (buffer = (char*)alloca(size)) == NULL ) return 0; fread(buffer, size, 1, infile); fwrite(buffer, size, 1, outfile); *headersize = size; *state |= STATE_WROTE_WAVE; } else if( (*state & (STATE_WROTE_WAVE | STATE_SEEN_MOVI)) && (tag & 0xffff00ff) == FourCC("0\0wb") ) { if( (*state & STATE_WROTE_MOVI) == 0 ) { fwrite("data\0\0\0\0", 8, 1, outfile); *state |= STATE_WROTE_MOVI; } if( (buffer = (char*)alloca(size)) == NULL ) return 0; fread(buffer, size, 1, infile); fwrite(buffer, size, 1, outfile); *datasize += size; } else { fseek(infile, size, SEEK_CUR); } if( size & 1 ) { fgetc(infile); size++; } return size + 8; } /* ParseChunk() */ /*************************************************************** ParseList */ static int ParseList(FILE *infile, FILE *outfile, int listsize, int *state, int *headersize, int *datasize) { int tag, chunksize; fread(&tag, 4, 1, infile); if( tag == FourCC("hdrl") ) { *state |= STATE_SEEN_HDRL; } else if( tag == FourCC("movi") ) { *state |= STATE_SEEN_MOVI; } chunksize = 0; while( listsize > chunksize ) { chunksize += (tag = ParseChunk(infile, outfile, listsize, state, headersize, datasize)); if( tag == 0 ) return 0; } return listsize; } /* ParseList() */