home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 28 / amigaformatcd28.iso / -seriously_amiga- / graphics / tga2avi-1.228 / tga2avi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-05-09  |  14.0 KB  |  562 lines

  1. /* tga2avi.c - This program was written specifically for the POV
  2. // community. The program takes a series of numbered .tga files
  3. // and makes an uncompressed .avi.  I wrote this code very quickly
  4. // so there is alot of hard coding in here. If you feel that this 
  5. // program needs to be extended, just email me. If I get enough
  6. // response then I will add compression and sound. I have written 
  7. // this code to be highly portable, on most Unix systems a simple
  8. // gcc tga2avi.c   should do the trick.  I have written this using 
  9. // MSVC5.  I have tried to use all of the MS conventions and
  10. // structures so that this code could be ported to a more useful
  11. // win32 app easily. If you like this utility just email me
  12. // and say hi. If you don't like it - write your own.
  13. //
  14. // Bless the hex editor - For without it this would've been 
  15. // impossible. The MS docs suck hard unless you only want to write
  16. // for Windows.
  17. //
  18. // Special Thanks go to: David McDuffee (75530,2626) for his docs
  19. // on the .tga file format. Although I've never met him. 
  20. //
  21. // Timothy A. Grubb - WallySoft Dec 25 1997 
  22. // wsft@neta.com
  23. // tim@flare.emg.com
  24. // www.wallysoft.com
  25. */
  26.  
  27.  
  28.  
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <stdlib.h>
  32. #include <malloc.h>
  33.  
  34.  
  35. #define WORD unsigned short  /* 2 bytes */
  36. #define DWORD unsigned long
  37. #define LONG long
  38. #define UINT unsigned int
  39. #define UCHAR unsigned char
  40. #define BI_RGB  0L
  41.  
  42.  
  43.  
  44. typedef struct {   
  45.     LONG left;   
  46.     LONG top;   
  47.     LONG right;   
  48.     LONG bottom;
  49. } RECT;
  50.  
  51. typedef struct {
  52.     UCHAR chars_in_ID;
  53.     UCHAR clr_map_type;
  54.     UCHAR image_type;
  55.     UCHAR map_origin_lo;
  56.     UCHAR map_origin_hi;
  57.     UCHAR clr_map_len_lo;
  58.     UCHAR clr_map_len_hi;
  59.     UCHAR clr_map_bpp;
  60.     UCHAR x_origin_lo;
  61.     UCHAR x_origin_hi;
  62.     UCHAR y_origin_lo;
  63.     UCHAR y_origin_hi;
  64.     UCHAR width_lo;
  65.     UCHAR width_hi;
  66.     UCHAR height_lo;
  67.     UCHAR height_hi;
  68.      UCHAR bpp;
  69.     UCHAR image_desc;
  70. } TARGA_TYPE2_HEADER;
  71.  
  72. typedef struct {
  73.     char fmt_id[4];
  74.     char dk1[4];
  75.     char type[4];
  76.     char list1[4];
  77.     char dk2[4];
  78.     char hdrl[4];
  79.     char avih[4];
  80.     char dk3[4];
  81. } RIFF_HEADER;
  82.  
  83.  
  84. typedef struct {
  85.     DWORD dwMicroSecPerFrame;
  86.     DWORD dwMaxBytesPerSec;
  87.     DWORD dwReserved1;
  88.     DWORD dwFlags;
  89.     DWORD dwTotalFrames;
  90.     DWORD dwInitialFrames;
  91.     DWORD dwStreams;
  92.     DWORD dwSuggestedBufferSize;
  93.     DWORD dwWidth;
  94.     DWORD dwHeight;
  95.     DWORD dwReserved[4];
  96. } MainAVIHeader;
  97.  
  98.  
  99. typedef struct {
  100.     char   fccType[4];      /* these should be FOURCC for MS */
  101.     char   fccHandler[4];
  102.     DWORD  dwFlags;
  103.     WORD   wPriority;
  104.      WORD   wLanguage;
  105.     DWORD  dwInitialFrames;
  106.     DWORD  dwScale;
  107.     DWORD  dwRate;
  108.     DWORD  dwStart;
  109.     DWORD  dwLength;
  110.     DWORD  dwSuggestedBufferSize;
  111.     DWORD  dwQuality;
  112.     DWORD  dwSampleSize;
  113.     RECT   rcFrame;
  114. } AVIStreamHeader;
  115.  
  116. typedef struct {
  117.     DWORD biSize;
  118.     LONG  biWidth;
  119.     LONG  biHeight;
  120.     WORD  biPlanes;
  121.     WORD  biBitCount;
  122.     DWORD biCompression;
  123.     DWORD biSizeImage;
  124.     LONG  biXPelsPerMeter;
  125.     LONG  biYPelsPerMeter;
  126.     DWORD biClrUsed;
  127.     DWORD biClrImportant;
  128. } BITMAPINFOHEADER;
  129.  
  130.  
  131.   LONG gFsize = 0;
  132.   LONG gheader_size = 0;
  133.   UINT current_frame = 1;
  134.  
  135.  
  136. //Prototypes
  137. void printUsage(void);
  138. int parseFilename(char *);
  139. void writeBlankHeaders(FILE *);
  140. void writeAVIHeaders(RIFF_HEADER*, TARGA_TYPE2_HEADER*, 
  141.                      MainAVIHeader*, AVIStreamHeader*, FILE *, int);
  142. void writeVideoData(FILE *, FILE *, TARGA_TYPE2_HEADER*);
  143. UINT convert_lohi(UCHAR, UCHAR);
  144. void write_idx(FILE *fp, UINT , TARGA_TYPE2_HEADER *);
  145.  
  146.  
  147.  
  148.  
  149.  
  150. void main(int argc, char *argv[])
  151. {
  152.  
  153.   TARGA_TYPE2_HEADER targa_head;
  154.   MainAVIHeader main_avi_head;
  155.   AVIStreamHeader video_stream;
  156.   RIFF_HEADER riff_head;
  157.   UINT filenum = 0;
  158.   FILE *tgafp, *avifp;
  159.   char avi_filename[256] = {0};
  160.   char tgafile[256] = {0};
  161.  
  162.  
  163.   if(argc < 2) {        /* if no params print message and exit */
  164.     printUsage();
  165.     exit(0);
  166.   }
  167.  
  168.   sprintf(avi_filename,"%s.avi",argv[2]); /* bad strcat() experience */
  169.  
  170.   if((avifp=fopen(avi_filename,"wb")) == '\0') {
  171.       printf("\nError opening %s \n", avi_filename);
  172.       exit(0);
  173.   }
  174.  
  175.             /* just moves the avi file pointer - probably could have 
  176.              just used fseek()  */
  177.  
  178.   writeBlankHeaders(avifp);
  179.  
  180.   sprintf(tgafile,"%s.tga",argv[1]);
  181.   while(tgafp=fopen(tgafile,"rb")) {
  182.       filenum++;
  183.     fread(&targa_head,sizeof(TARGA_TYPE2_HEADER),1,tgafp);
  184.  
  185.     if(targa_head.bpp != 24) {
  186.       printf("Only supports 24 bit tga's at this time\n");
  187.       exit(0);
  188.     }
  189.      writeVideoData(tgafp, avifp, &targa_head);
  190.      fclose(tgafp);    /* close the .tga so we can open the next one */
  191.      parseFilename(argv[1]);
  192.      sprintf(tgafile,"%s.tga",argv[1]);
  193.   } /* end while(tgafp=... */
  194.  
  195.   if(filenum < 2) {
  196.       printf("\nRecheck the name - Less than two files to process.\n");
  197.       exit(0);
  198.   }
  199.  
  200.  
  201.                  /* now go write the real data to the avi header */
  202.  writeAVIHeaders(&riff_head, &targa_head, &main_avi_head, 
  203.                       &video_stream, avifp, filenum);
  204.  
  205.  write_idx(avifp, filenum, &targa_head);
  206.  printf("\nDone");
  207.  
  208.  
  209.   fclose(avifp);
  210.   
  211. }
  212.  
  213. /*//////////////////////////////////////////////////////////////////
  214. //convert_lohi() - convert lo byte hi byte to hi byte lo byte
  215. //                 used for the .tga header
  216. */
  217.  
  218. UINT convert_lohi(UCHAR lo, UCHAR hi)
  219. {
  220.   UINT val = 0;
  221.   val = hi << 8;
  222.   val += lo;
  223.  
  224.   return val;
  225. }
  226.  
  227. /*//////////////////////////////////////////////////////////////////
  228. //writeVideoData() - write the proper avi header data
  229. */
  230.  
  231. void writeVideoData(FILE *sourcefp, FILE *destfp, 
  232.                     TARGA_TYPE2_HEADER *t_head)
  233. {
  234.   UINT width, height;
  235.   UINT i = 0;
  236.   char *buff;
  237.   char dataID[] = {"00db"};
  238.   int numread = 0;
  239.   DWORD frame_size = 0;
  240.   int origin;
  241.   int lines = 0;
  242.   long offset = 0;
  243.   int line_size = 0;
  244.  
  245.   width = convert_lohi(t_head->width_lo, t_head->width_hi); 
  246.   height = convert_lohi(t_head->height_lo, t_head->height_hi);
  247.   line_size = width * 3;
  248.  
  249.   printf("\nWriting Frame %d", current_frame++);
  250.  
  251.   
  252.  
  253.   origin = t_head->image_desc & 0x20;
  254.   frame_size = (width * height * 3);
  255.  
  256.  
  257.          /* If the image is stored with the origin at upper left */
  258.   if(origin == 0x00) {
  259.      
  260.  
  261.          /* allocate a buffer large enough for 1 frame of data */
  262.   buff = (char *)malloc(frame_size);
  263.  
  264.   if(!buff) {
  265.       printf("Error allocating memory for frame");
  266.       exit(0);
  267.   }
  268.      fwrite(dataID,strlen(dataID),1,destfp);
  269.      fwrite(&frame_size,sizeof(DWORD),1,destfp);
  270.  
  271.     fread(buff,frame_size,1,sourcefp);
  272.      fwrite(buff,frame_size,1,destfp);
  273.   }
  274.   else {  /* If the image is stored with the origin at lower left */
  275.      buff = (char *)malloc(line_size);
  276.  
  277.      if(!buff) {
  278.       printf("Error allocating memory for frame");
  279.       exit(0);
  280.     }
  281.  
  282.   fwrite(dataID,strlen(dataID),1,destfp);
  283.   fwrite(&frame_size,sizeof(DWORD),1,destfp);
  284.       
  285.     for(lines=1;lines < height + 1;lines++) { 
  286.         fseek(sourcefp, -(lines * line_size), 
  287.                 SEEK_END);
  288.           fread(buff,line_size,1,sourcefp);
  289.           fwrite(buff,line_size,1,destfp);
  290.     // memset(buff,'\0',sizeof(buff));
  291.     }
  292.   }
  293.  
  294.  free(buff);
  295.  
  296.   
  297. }
  298.  
  299. /*//////////////////////////////////////////////////////////////////
  300. //write_idx() - write the proper avi index data
  301. */
  302. void write_idx(FILE *fp, UINT filenum, 
  303.                  TARGA_TYPE2_HEADER *t_head)
  304. {
  305.     char index[]={"idx1"};
  306.     char db00[] = {"00db"};
  307.     DWORD offset = 0;
  308.     UINT width, height;
  309.     UINT dsize = 0;
  310.     UINT i = 0;
  311.     DWORD idc_chunk_size = 0;
  312.     DWORD idc_field_size = 0x10;
  313.     DWORD idc_frame_size = 0;
  314.  
  315.     width = convert_lohi(t_head->width_lo, t_head->width_hi); 
  316.      height = convert_lohi(t_head->height_lo, t_head->height_hi);
  317.     idc_frame_size = width * height * (t_head->bpp / 8);
  318.      dsize = idc_frame_size + 8;
  319.  
  320.     idc_chunk_size = 16 * filenum;
  321.  
  322.     fseek(fp, 0L, SEEK_END);
  323.     fwrite(index,strlen(index),1,fp);
  324.     fwrite(&idc_chunk_size,sizeof(DWORD),1,fp);
  325.  
  326.     offset = 0x04;
  327.  
  328.                                          /* write out the image indexes */
  329.     for(i=0;i<filenum;i++) {     
  330.       fwrite(db00, strlen(db00),1,fp);
  331.       fwrite(&idc_field_size,sizeof(DWORD),1,fp);
  332.       fwrite(&offset, sizeof(DWORD),1,fp);
  333.       fwrite(&idc_frame_size,sizeof(DWORD),1,fp);
  334.       offset += dsize;
  335.     }
  336.  
  337.  
  338. }
  339.  
  340. /*//////////////////////////////////////////////////////////////////
  341. //writeAVIHeaders() - write the proper avi header data
  342. */
  343.  
  344. void writeAVIHeaders(RIFF_HEADER *riff_head, 
  345.                      TARGA_TYPE2_HEADER *t_head, 
  346.                      MainAVIHeader *avi_head, 
  347.                           AVIStreamHeader *v_stream, 
  348.                      FILE *fp, int fnum)
  349. {
  350.     char stuff1[] = {"LIST    strlstrh    "};
  351.     char stuff2[] = {"LIST    movi00db"};
  352.     char strf[] = {"strf"};
  353.     char strh[] = {"strh"};
  354.     char strl[] = {"strl"};
  355.     char db00[] = {"00db"};
  356.     char movi[] = {"movi"};
  357.     DWORD avih_size;
  358.     DWORD list1_size;
  359.     DWORD list2_size; 
  360.     DWORD strh_size;
  361.     DWORD movi_size;
  362.     DWORD filesize = 0;
  363.     DWORD bminfo_size = 0;
  364.     DWORD movi_chunk = 0;
  365.     WORD  framesize = 0;
  366.     BITMAPINFOHEADER bminfo;
  367.  
  368.  
  369.     bminfo.biSize = sizeof(BITMAPINFOHEADER);
  370.     bminfo.biWidth = convert_lohi(t_head->width_lo,t_head->width_hi); 
  371.      bminfo.biHeight = convert_lohi(t_head->height_lo, t_head->height_hi);
  372.     bminfo.biPlanes = 1;
  373.     bminfo.biBitCount = 24;
  374.     bminfo.biCompression = BI_RGB;
  375.     bminfo.biSizeImage = bminfo.biWidth * bminfo.biHeight * 3;
  376.     bminfo.biXPelsPerMeter = 0;
  377.     bminfo.biYPelsPerMeter = 0;
  378.     bminfo.biClrUsed = 0;
  379.     bminfo.biClrImportant = 0;
  380.  
  381.     avi_head->dwMicroSecPerFrame = 33367;
  382.           /* yes I know this gives a warning - leave it be */
  383.     avi_head->dwMaxBytesPerSec = 
  384.              (bminfo.biWidth * bminfo.biHeight * 3) * 29.97;
  385.     avi_head->dwReserved1 = 0;
  386.     avi_head->dwFlags = 0x10;
  387.     avi_head->dwTotalFrames = fnum;
  388.     avi_head->dwInitialFrames = 0x00;
  389.     avi_head->dwStreams = 0x01;
  390.     avi_head->dwSuggestedBufferSize = 
  391.              (bminfo.biWidth * bminfo.biHeight * 3);
  392.     avi_head->dwWidth = bminfo.biWidth;
  393.     avi_head->dwHeight = bminfo.biHeight;
  394.     
  395.     v_stream->fccType[0] = 'v';
  396.     v_stream->fccType[1] = 'i';
  397.     v_stream->fccType[2] = 'd';
  398.     v_stream->fccType[3] = 's';
  399.     strcpy(v_stream->fccHandler,"DIB ");
  400.     v_stream->dwFlags = 0x00;
  401.     v_stream->wPriority = 0x00;
  402.     v_stream->wLanguage = 0x00;
  403.     v_stream->dwInitialFrames = 0x00;
  404.     v_stream->dwScale = 100;
  405.     v_stream->dwRate = 2997;
  406.     v_stream->dwStart = 0;
  407.     v_stream->dwLength = fnum;
  408.     v_stream->dwSuggestedBufferSize = avi_head->dwSuggestedBufferSize;
  409.     v_stream->dwQuality = 0;
  410.     v_stream->dwSampleSize = bminfo.biWidth * bminfo.biHeight * 3;
  411.     v_stream->rcFrame.left = 0;
  412.     v_stream->rcFrame.top = 0;
  413.     v_stream->rcFrame.right = bminfo.biWidth;
  414.     v_stream->rcFrame.bottom = bminfo.biHeight;
  415.  
  416.     strcpy(riff_head->fmt_id,"RIFF");   
  417.     strcpy(riff_head->type,"AVI ");
  418.     strcpy(riff_head->list1,"LIST");
  419.     strcpy(riff_head->hdrl,"hdrl");
  420.     strcpy(riff_head->avih,"avih");
  421.  
  422.  
  423.     avih_size = sizeof(MainAVIHeader);
  424.     list1_size = 0xC8; /* I don't know why */
  425.     list2_size = sizeof(AVIStreamHeader) + 
  426.                     sizeof(BITMAPINFOHEADER) + 20;
  427.     strh_size = sizeof(AVIStreamHeader);
  428.     movi_size = (fnum * bminfo.biWidth * bminfo.biHeight * 3);
  429.     filesize = gFsize + movi_size;
  430.     framesize = (bminfo.biWidth * bminfo.biHeight * 3);
  431.     bminfo_size = sizeof(BITMAPINFOHEADER);
  432.     movi_chunk = movi_size + (8 * fnum) + 4;
  433.  
  434.  
  435.  
  436.     fseek(fp, 0L, SEEK_SET);
  437.     fwrite(riff_head->fmt_id, sizeof(DWORD),1,fp);
  438.     fwrite(&filesize,sizeof(DWORD),1,fp);
  439.  
  440.     fwrite(riff_head->type, sizeof(DWORD),1,fp);
  441.  
  442.     fwrite(riff_head->list1, strlen(riff_head->list1),1,fp);
  443.     fwrite(&list1_size,sizeof(DWORD),1,fp);
  444.      fwrite(riff_head->hdrl, sizeof(DWORD),1,fp);
  445.     fwrite(riff_head->avih, sizeof(DWORD),1,fp);
  446.     fwrite(&avih_size,sizeof(DWORD),1,fp);
  447.     fwrite(avi_head, sizeof(MainAVIHeader),1,fp);
  448.  
  449.      fwrite(riff_head->list1, strlen(riff_head->list1),1,fp);
  450.     fwrite(&list2_size,sizeof(DWORD),1,fp);
  451.     fwrite(strl, strlen(strl),1,fp);
  452.     fwrite(strh, strlen(strh),1,fp);
  453.     fwrite(&strh_size,sizeof(DWORD),1,fp);
  454.     fwrite(v_stream,sizeof(AVIStreamHeader),1,fp);
  455.  
  456.     fwrite(strf, strlen(strf),1,fp);
  457.     fwrite(&bminfo_size,sizeof(DWORD),1,fp);
  458.     fwrite(&bminfo, sizeof(BITMAPINFOHEADER),1,fp);
  459.  
  460.     fwrite(riff_head->list1, strlen(riff_head->list1),1,fp);
  461.     fwrite(&movi_chunk,sizeof(DWORD),1,fp);
  462.     fwrite(movi, strlen(movi),1,fp);
  463.  
  464. }
  465.  
  466.  
  467. /*//////////////////////////////////////////////////////////////////
  468. //writeBlankHeaders() - place temporary data in the avi header
  469. //
  470. */
  471.  
  472. void writeBlankHeaders(FILE *fp)
  473. {
  474.   int offset = 72;
  475.   char ch = '0';
  476.  
  477.   offset += sizeof(AVIStreamHeader) + sizeof(BITMAPINFOHEADER) +
  478.               sizeof(MainAVIHeader);
  479.   fseek(fp,0L,SEEK_SET);
  480.   fwrite(&ch,sizeof(char),offset,fp);
  481.  
  482.   gheader_size = offset;
  483.   gFsize = offset - 8;
  484.  
  485. }
  486.  
  487. /*//////////////////////////////////////////////////////////////////
  488. //parseFilename() - manipulates the filename to increment to the
  489. //next file in series
  490. */
  491.  
  492. int parseFilename(char *filename)
  493. {
  494.     int i, j, k;
  495.     char fchars[128] = {0};
  496.     char fnum[128] = {0};
  497.     char temp_num[128] = {0};
  498.     char ch;
  499.     int filenum;
  500.     int len = 0;
  501.     int tlen = 0;
  502.     int tmp_len = 0;
  503.     int c = 0;
  504.  
  505.     i = j = k = 0;
  506.  
  507.     len = strlen(filename) ;
  508.      i = len - 1;
  509.  
  510.  
  511.     while( (ch = filename[i]) < 58 && filename[i] > 47)
  512.         i--;
  513.      i++;
  514.  
  515.     for(c=0;c<i;c++) 
  516.       fchars[j++] = filename[c];
  517.  
  518.     fchars[j] = '\0';
  519.  
  520.     for(c=c;c<len;c++)
  521.       fnum[k++] = filename[c];
  522.  
  523.     fnum[k] = '\0';
  524.  
  525.      filenum = atoi(fnum) + 1;
  526.     /*itoa(filenum,temp_num,10);*/
  527.  
  528.     memset(fnum,'0',strlen(fnum));
  529.      len = strlen(fnum);
  530.     tlen = strlen(temp_num);
  531.     tmp_len = tlen;
  532.  
  533.     for(i=0;i<tmp_len;i++) {
  534.       fnum[--len] = temp_num[--tlen];
  535.     }
  536.      
  537.     memset(filename,'\0',256);
  538.     sprintf(filename,"%s%s",fchars,fnum);
  539.  
  540.     return 1;
  541. }
  542.  
  543. /*//////////////////////////////////////////////////////////////////
  544. //printUsage() - Prints out the usage message when the program is
  545. //called with no params
  546. */
  547.  
  548. void printUsage(void)
  549. {
  550.     printf("\nThis program is used to take a series of uncompressed\n");
  551.     printf(".tga files and turn them into an uncompressed .avi that\n");
  552.     printf("can then be manipulated in other programs.\n\n");
  553.     printf("Usage:  tga2avi <fileseries> <output>\n\n");
  554.     printf("IE: tga2avi myfiles00001 myanim  \n\n");
  555.     printf("Note: do not add the extensions as they will be assumed\n");
  556.     printf("Also make sure the series is in sequential number order\n");
  557.     printf("as this prog will take the name given as the start of the\n");
  558.     printf("series\n\n");
  559.  
  560.  return;
  561. }
  562.