home *** CD-ROM | disk | FTP | other *** search
- /* tga2avi.c - This program was written specifically for the POV
- // community. The program takes a series of numbered .tga files
- // and makes an uncompressed .avi. I wrote this code very quickly
- // so there is alot of hard coding in here. If you feel that this
- // program needs to be extended, just email me. If I get enough
- // response then I will add compression and sound. I have written
- // this code to be highly portable, on most Unix systems a simple
- // gcc tga2avi.c should do the trick. I have written this using
- // MSVC5. I have tried to use all of the MS conventions and
- // structures so that this code could be ported to a more useful
- // win32 app easily. If you like this utility just email me
- // and say hi. If you don't like it - write your own.
- //
- // Bless the hex editor - For without it this would've been
- // impossible. The MS docs suck hard unless you only want to write
- // for Windows.
- //
- // Special Thanks go to: David McDuffee (75530,2626) for his docs
- // on the .tga file format. Although I've never met him.
- //
- // Timothy A. Grubb - WallySoft Dec 25 1997
- // wsft@neta.com
- // tim@flare.emg.com
- // www.wallysoft.com
- */
-
-
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <malloc.h>
-
-
- #define WORD unsigned short /* 2 bytes */
- #define DWORD unsigned long
- #define LONG long
- #define UINT unsigned int
- #define UCHAR unsigned char
- #define BI_RGB 0L
-
-
-
- typedef struct {
- LONG left;
- LONG top;
- LONG right;
- LONG bottom;
- } RECT;
-
- typedef struct {
- UCHAR chars_in_ID;
- UCHAR clr_map_type;
- UCHAR image_type;
- UCHAR map_origin_lo;
- UCHAR map_origin_hi;
- UCHAR clr_map_len_lo;
- UCHAR clr_map_len_hi;
- UCHAR clr_map_bpp;
- UCHAR x_origin_lo;
- UCHAR x_origin_hi;
- UCHAR y_origin_lo;
- UCHAR y_origin_hi;
- UCHAR width_lo;
- UCHAR width_hi;
- UCHAR height_lo;
- UCHAR height_hi;
- UCHAR bpp;
- UCHAR image_desc;
- } TARGA_TYPE2_HEADER;
-
- typedef struct {
- char fmt_id[4];
- char dk1[4];
- char type[4];
- char list1[4];
- char dk2[4];
- char hdrl[4];
- char avih[4];
- char dk3[4];
- } RIFF_HEADER;
-
-
- typedef struct {
- DWORD dwMicroSecPerFrame;
- DWORD dwMaxBytesPerSec;
- DWORD dwReserved1;
- DWORD dwFlags;
- DWORD dwTotalFrames;
- DWORD dwInitialFrames;
- DWORD dwStreams;
- DWORD dwSuggestedBufferSize;
- DWORD dwWidth;
- DWORD dwHeight;
- DWORD dwReserved[4];
- } MainAVIHeader;
-
-
- typedef struct {
- char fccType[4]; /* these should be FOURCC for MS */
- char fccHandler[4];
- DWORD dwFlags;
- WORD wPriority;
- WORD wLanguage;
- DWORD dwInitialFrames;
- DWORD dwScale;
- DWORD dwRate;
- DWORD dwStart;
- DWORD dwLength;
- DWORD dwSuggestedBufferSize;
- DWORD dwQuality;
- DWORD dwSampleSize;
- RECT rcFrame;
- } AVIStreamHeader;
-
- typedef struct {
- DWORD biSize;
- LONG biWidth;
- LONG biHeight;
- WORD biPlanes;
- WORD biBitCount;
- DWORD biCompression;
- DWORD biSizeImage;
- LONG biXPelsPerMeter;
- LONG biYPelsPerMeter;
- DWORD biClrUsed;
- DWORD biClrImportant;
- } BITMAPINFOHEADER;
-
-
- LONG gFsize = 0;
- LONG gheader_size = 0;
- UINT current_frame = 1;
-
-
- //Prototypes
- void printUsage(void);
- int parseFilename(char *);
- void writeBlankHeaders(FILE *);
- void writeAVIHeaders(RIFF_HEADER*, TARGA_TYPE2_HEADER*,
- MainAVIHeader*, AVIStreamHeader*, FILE *, int);
- void writeVideoData(FILE *, FILE *, TARGA_TYPE2_HEADER*);
- UINT convert_lohi(UCHAR, UCHAR);
- void write_idx(FILE *fp, UINT , TARGA_TYPE2_HEADER *);
-
-
-
-
-
- void main(int argc, char *argv[])
- {
-
- TARGA_TYPE2_HEADER targa_head;
- MainAVIHeader main_avi_head;
- AVIStreamHeader video_stream;
- RIFF_HEADER riff_head;
- UINT filenum = 0;
- FILE *tgafp, *avifp;
- char avi_filename[256] = {0};
- char tgafile[256] = {0};
-
-
- if(argc < 2) { /* if no params print message and exit */
- printUsage();
- exit(0);
- }
-
- sprintf(avi_filename,"%s.avi",argv[2]); /* bad strcat() experience */
-
- if((avifp=fopen(avi_filename,"wb")) == '\0') {
- printf("\nError opening %s \n", avi_filename);
- exit(0);
- }
-
- /* just moves the avi file pointer - probably could have
- just used fseek() */
-
- writeBlankHeaders(avifp);
-
- sprintf(tgafile,"%s.tga",argv[1]);
- while(tgafp=fopen(tgafile,"rb")) {
- filenum++;
- fread(&targa_head,sizeof(TARGA_TYPE2_HEADER),1,tgafp);
-
- if(targa_head.bpp != 24) {
- printf("Only supports 24 bit tga's at this time\n");
- exit(0);
- }
- writeVideoData(tgafp, avifp, &targa_head);
- fclose(tgafp); /* close the .tga so we can open the next one */
- parseFilename(argv[1]);
- sprintf(tgafile,"%s.tga",argv[1]);
- } /* end while(tgafp=... */
-
- if(filenum < 2) {
- printf("\nRecheck the name - Less than two files to process.\n");
- exit(0);
- }
-
-
- /* now go write the real data to the avi header */
- writeAVIHeaders(&riff_head, &targa_head, &main_avi_head,
- &video_stream, avifp, filenum);
-
- write_idx(avifp, filenum, &targa_head);
- printf("\nDone");
-
-
- fclose(avifp);
-
- }
-
- /*//////////////////////////////////////////////////////////////////
- //convert_lohi() - convert lo byte hi byte to hi byte lo byte
- // used for the .tga header
- */
-
- UINT convert_lohi(UCHAR lo, UCHAR hi)
- {
- UINT val = 0;
- val = hi << 8;
- val += lo;
-
- return val;
- }
-
- /*//////////////////////////////////////////////////////////////////
- //writeVideoData() - write the proper avi header data
- */
-
- void writeVideoData(FILE *sourcefp, FILE *destfp,
- TARGA_TYPE2_HEADER *t_head)
- {
- UINT width, height;
- UINT i = 0;
- char *buff;
- char dataID[] = {"00db"};
- int numread = 0;
- DWORD frame_size = 0;
- int origin;
- int lines = 0;
- long offset = 0;
- int line_size = 0;
-
- width = convert_lohi(t_head->width_lo, t_head->width_hi);
- height = convert_lohi(t_head->height_lo, t_head->height_hi);
- line_size = width * 3;
-
- printf("\nWriting Frame %d", current_frame++);
-
-
-
- origin = t_head->image_desc & 0x20;
- frame_size = (width * height * 3);
-
-
- /* If the image is stored with the origin at upper left */
- if(origin == 0x00) {
-
-
- /* allocate a buffer large enough for 1 frame of data */
- buff = (char *)malloc(frame_size);
-
- if(!buff) {
- printf("Error allocating memory for frame");
- exit(0);
- }
- fwrite(dataID,strlen(dataID),1,destfp);
- fwrite(&frame_size,sizeof(DWORD),1,destfp);
-
- fread(buff,frame_size,1,sourcefp);
- fwrite(buff,frame_size,1,destfp);
- }
- else { /* If the image is stored with the origin at lower left */
- buff = (char *)malloc(line_size);
-
- if(!buff) {
- printf("Error allocating memory for frame");
- exit(0);
- }
-
- fwrite(dataID,strlen(dataID),1,destfp);
- fwrite(&frame_size,sizeof(DWORD),1,destfp);
-
- for(lines=1;lines < height + 1;lines++) {
- fseek(sourcefp, -(lines * line_size),
- SEEK_END);
- fread(buff,line_size,1,sourcefp);
- fwrite(buff,line_size,1,destfp);
- // memset(buff,'\0',sizeof(buff));
- }
- }
-
- free(buff);
-
-
- }
-
- /*//////////////////////////////////////////////////////////////////
- //write_idx() - write the proper avi index data
- */
- void write_idx(FILE *fp, UINT filenum,
- TARGA_TYPE2_HEADER *t_head)
- {
- char index[]={"idx1"};
- char db00[] = {"00db"};
- DWORD offset = 0;
- UINT width, height;
- UINT dsize = 0;
- UINT i = 0;
- DWORD idc_chunk_size = 0;
- DWORD idc_field_size = 0x10;
- DWORD idc_frame_size = 0;
-
- width = convert_lohi(t_head->width_lo, t_head->width_hi);
- height = convert_lohi(t_head->height_lo, t_head->height_hi);
- idc_frame_size = width * height * (t_head->bpp / 8);
- dsize = idc_frame_size + 8;
-
- idc_chunk_size = 16 * filenum;
-
- fseek(fp, 0L, SEEK_END);
- fwrite(index,strlen(index),1,fp);
- fwrite(&idc_chunk_size,sizeof(DWORD),1,fp);
-
- offset = 0x04;
-
- /* write out the image indexes */
- for(i=0;i<filenum;i++) {
- fwrite(db00, strlen(db00),1,fp);
- fwrite(&idc_field_size,sizeof(DWORD),1,fp);
- fwrite(&offset, sizeof(DWORD),1,fp);
- fwrite(&idc_frame_size,sizeof(DWORD),1,fp);
- offset += dsize;
- }
-
-
- }
-
- /*//////////////////////////////////////////////////////////////////
- //writeAVIHeaders() - write the proper avi header data
- */
-
- void writeAVIHeaders(RIFF_HEADER *riff_head,
- TARGA_TYPE2_HEADER *t_head,
- MainAVIHeader *avi_head,
- AVIStreamHeader *v_stream,
- FILE *fp, int fnum)
- {
- char stuff1[] = {"LIST strlstrh "};
- char stuff2[] = {"LIST movi00db"};
- char strf[] = {"strf"};
- char strh[] = {"strh"};
- char strl[] = {"strl"};
- char db00[] = {"00db"};
- char movi[] = {"movi"};
- DWORD avih_size;
- DWORD list1_size;
- DWORD list2_size;
- DWORD strh_size;
- DWORD movi_size;
- DWORD filesize = 0;
- DWORD bminfo_size = 0;
- DWORD movi_chunk = 0;
- WORD framesize = 0;
- BITMAPINFOHEADER bminfo;
-
-
- bminfo.biSize = sizeof(BITMAPINFOHEADER);
- bminfo.biWidth = convert_lohi(t_head->width_lo,t_head->width_hi);
- bminfo.biHeight = convert_lohi(t_head->height_lo, t_head->height_hi);
- bminfo.biPlanes = 1;
- bminfo.biBitCount = 24;
- bminfo.biCompression = BI_RGB;
- bminfo.biSizeImage = bminfo.biWidth * bminfo.biHeight * 3;
- bminfo.biXPelsPerMeter = 0;
- bminfo.biYPelsPerMeter = 0;
- bminfo.biClrUsed = 0;
- bminfo.biClrImportant = 0;
-
- avi_head->dwMicroSecPerFrame = 33367;
- /* yes I know this gives a warning - leave it be */
- avi_head->dwMaxBytesPerSec =
- (bminfo.biWidth * bminfo.biHeight * 3) * 29.97;
- avi_head->dwReserved1 = 0;
- avi_head->dwFlags = 0x10;
- avi_head->dwTotalFrames = fnum;
- avi_head->dwInitialFrames = 0x00;
- avi_head->dwStreams = 0x01;
- avi_head->dwSuggestedBufferSize =
- (bminfo.biWidth * bminfo.biHeight * 3);
- avi_head->dwWidth = bminfo.biWidth;
- avi_head->dwHeight = bminfo.biHeight;
-
- v_stream->fccType[0] = 'v';
- v_stream->fccType[1] = 'i';
- v_stream->fccType[2] = 'd';
- v_stream->fccType[3] = 's';
- strcpy(v_stream->fccHandler,"DIB ");
- v_stream->dwFlags = 0x00;
- v_stream->wPriority = 0x00;
- v_stream->wLanguage = 0x00;
- v_stream->dwInitialFrames = 0x00;
- v_stream->dwScale = 100;
- v_stream->dwRate = 2997;
- v_stream->dwStart = 0;
- v_stream->dwLength = fnum;
- v_stream->dwSuggestedBufferSize = avi_head->dwSuggestedBufferSize;
- v_stream->dwQuality = 0;
- v_stream->dwSampleSize = bminfo.biWidth * bminfo.biHeight * 3;
- v_stream->rcFrame.left = 0;
- v_stream->rcFrame.top = 0;
- v_stream->rcFrame.right = bminfo.biWidth;
- v_stream->rcFrame.bottom = bminfo.biHeight;
-
- strcpy(riff_head->fmt_id,"RIFF");
- strcpy(riff_head->type,"AVI ");
- strcpy(riff_head->list1,"LIST");
- strcpy(riff_head->hdrl,"hdrl");
- strcpy(riff_head->avih,"avih");
-
-
- avih_size = sizeof(MainAVIHeader);
- list1_size = 0xC8; /* I don't know why */
- list2_size = sizeof(AVIStreamHeader) +
- sizeof(BITMAPINFOHEADER) + 20;
- strh_size = sizeof(AVIStreamHeader);
- movi_size = (fnum * bminfo.biWidth * bminfo.biHeight * 3);
- filesize = gFsize + movi_size;
- framesize = (bminfo.biWidth * bminfo.biHeight * 3);
- bminfo_size = sizeof(BITMAPINFOHEADER);
- movi_chunk = movi_size + (8 * fnum) + 4;
-
-
-
- fseek(fp, 0L, SEEK_SET);
- fwrite(riff_head->fmt_id, sizeof(DWORD),1,fp);
- fwrite(&filesize,sizeof(DWORD),1,fp);
-
- fwrite(riff_head->type, sizeof(DWORD),1,fp);
-
- fwrite(riff_head->list1, strlen(riff_head->list1),1,fp);
- fwrite(&list1_size,sizeof(DWORD),1,fp);
- fwrite(riff_head->hdrl, sizeof(DWORD),1,fp);
- fwrite(riff_head->avih, sizeof(DWORD),1,fp);
- fwrite(&avih_size,sizeof(DWORD),1,fp);
- fwrite(avi_head, sizeof(MainAVIHeader),1,fp);
-
- fwrite(riff_head->list1, strlen(riff_head->list1),1,fp);
- fwrite(&list2_size,sizeof(DWORD),1,fp);
- fwrite(strl, strlen(strl),1,fp);
- fwrite(strh, strlen(strh),1,fp);
- fwrite(&strh_size,sizeof(DWORD),1,fp);
- fwrite(v_stream,sizeof(AVIStreamHeader),1,fp);
-
- fwrite(strf, strlen(strf),1,fp);
- fwrite(&bminfo_size,sizeof(DWORD),1,fp);
- fwrite(&bminfo, sizeof(BITMAPINFOHEADER),1,fp);
-
- fwrite(riff_head->list1, strlen(riff_head->list1),1,fp);
- fwrite(&movi_chunk,sizeof(DWORD),1,fp);
- fwrite(movi, strlen(movi),1,fp);
-
- }
-
-
- /*//////////////////////////////////////////////////////////////////
- //writeBlankHeaders() - place temporary data in the avi header
- //
- */
-
- void writeBlankHeaders(FILE *fp)
- {
- int offset = 72;
- char ch = '0';
-
- offset += sizeof(AVIStreamHeader) + sizeof(BITMAPINFOHEADER) +
- sizeof(MainAVIHeader);
- fseek(fp,0L,SEEK_SET);
- fwrite(&ch,sizeof(char),offset,fp);
-
- gheader_size = offset;
- gFsize = offset - 8;
-
- }
-
- /*//////////////////////////////////////////////////////////////////
- //parseFilename() - manipulates the filename to increment to the
- //next file in series
- */
-
- int parseFilename(char *filename)
- {
- int i, j, k;
- char fchars[128] = {0};
- char fnum[128] = {0};
- char temp_num[128] = {0};
- char ch;
- int filenum;
- int len = 0;
- int tlen = 0;
- int tmp_len = 0;
- int c = 0;
-
- i = j = k = 0;
-
- len = strlen(filename) ;
- i = len - 1;
-
-
- while( (ch = filename[i]) < 58 && filename[i] > 47)
- i--;
- i++;
-
- for(c=0;c<i;c++)
- fchars[j++] = filename[c];
-
- fchars[j] = '\0';
-
- for(c=c;c<len;c++)
- fnum[k++] = filename[c];
-
- fnum[k] = '\0';
-
- filenum = atoi(fnum) + 1;
- /*itoa(filenum,temp_num,10);*/
-
- memset(fnum,'0',strlen(fnum));
- len = strlen(fnum);
- tlen = strlen(temp_num);
- tmp_len = tlen;
-
- for(i=0;i<tmp_len;i++) {
- fnum[--len] = temp_num[--tlen];
- }
-
- memset(filename,'\0',256);
- sprintf(filename,"%s%s",fchars,fnum);
-
- return 1;
- }
-
- /*//////////////////////////////////////////////////////////////////
- //printUsage() - Prints out the usage message when the program is
- //called with no params
- */
-
- void printUsage(void)
- {
- printf("\nThis program is used to take a series of uncompressed\n");
- printf(".tga files and turn them into an uncompressed .avi that\n");
- printf("can then be manipulated in other programs.\n\n");
- printf("Usage: tga2avi <fileseries> <output>\n\n");
- printf("IE: tga2avi myfiles00001 myanim \n\n");
- printf("Note: do not add the extensions as they will be assumed\n");
- printf("Also make sure the series is in sequential number order\n");
- printf("as this prog will take the name given as the start of the\n");
- printf("series\n\n");
-
- return;
- }
-