home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / video / writeavi / writeavi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  14.1 KB  |  550 lines

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. /****************************************************************************
  12.  *
  13.  *  WRITEAVI.C
  14.  *
  15.  *  Creates the file OUTPUT.AVI, an AVI file consisting of a rotating clock
  16.  *  face.  This program demonstrates using the functions in AVIFILE.DLL
  17.  *  to make writing AVI files simple.
  18.  *
  19.  *  This is a stripped-down example; a real application would have a user
  20.  *  interface and check for errors.
  21.  *
  22.  ***************************************************************************/
  23.  
  24.  
  25. #define  STRICT
  26. #define  INC_OLE2
  27. #include <windows.h>
  28. #include <windowsx.h>
  29. #include <memory.h>
  30. #include <mmsystem.h>
  31. #include <vfw.h>
  32.  
  33. #include "writeavi.h"
  34. //---------------------------------------------------------------------------
  35. // Defines
  36. //---------------------------------------------------------------------------
  37. // Our movie is 160x120 and 15 frames long
  38. //
  39. #define BITMAP_X    160
  40. #define BITMAP_Y    120
  41. #define N_FRAMES    15
  42.  
  43. #define TEXT_HEIGHT    20
  44.  
  45. #define AVIIF_KEYFRAME    0x00000010L // this frame is a key frame.
  46.  
  47. #define BUFSIZE 260
  48.  
  49. #define LPLPBI    LPBITMAPINFOHEADER *
  50.  
  51. //---------------------------------------------------------------------------
  52. // Function declarations
  53. //---------------------------------------------------------------------------
  54. static void FreeFrames(LPLPBI) ;
  55. static void MakeFrames(LPLPBI, UINT, UINT, UINT) ;
  56. static HANDLE MakeDib(HBITMAP, UINT);
  57.  
  58. //---------------------------------------------------------------------------
  59. // A quick lookup table for Sin and Cos values
  60. //---------------------------------------------------------------------------
  61. //
  62. static int aSin[N_FRAMES] = {
  63.     0,    40,    74,    95,    99,
  64.     86,    58,    20,    -20,    -58,
  65.     -86,    -99,    -95,    -74,    -40,
  66.     } ;
  67.  
  68. static int aCos[N_FRAMES] = {
  69.     100,    91,    66,    30,    -10,
  70.     -49,    -80,    -97,    -97,    -80,
  71.     -50,    -10,    30,    66,    91,
  72.     } ;
  73.  
  74. //----------------------------------------------------------------------------
  75. //
  76. // We don't have a window, we just pop up a dialog
  77. // box, write the file, and quit
  78. //
  79. int PASCAL WinMain(
  80. HINSTANCE hInstance,
  81. HINSTANCE hPrevInstance,
  82. LPSTR szCmdLine,
  83. int sw)
  84. {
  85.     LPBITMAPINFOHEADER alpbi[N_FRAMES];
  86.     int i;
  87.     AVISTREAMINFO strhdr;
  88.     PAVIFILE pfile = NULL;
  89.     PAVISTREAM ps = NULL, psCompressed = NULL, psText = NULL;
  90.     char szText[BUFSIZE];
  91.     int iLen;
  92.     AVICOMPRESSOPTIONS opts;
  93.     AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts};
  94.     HRESULT hr;
  95.     DWORD dwTextFormat;
  96.     WORD wVer;
  97.     char szTitle[BUFSIZE];
  98.     char szMessage[BUFSIZE];
  99.  
  100.     /* first let's make sure we are running on 1.1 */
  101.     wVer = HIWORD(VideoForWindowsVersion());
  102.     if (wVer < 0x010a){
  103.          /* oops, we are too old, blow out of here */
  104.         LoadString(hInstance, IDS_APPERR, szTitle, BUFSIZE );
  105.         LoadString(hInstance, IDS_VFWTOOOLD, szMessage, BUFSIZE );
  106.         MessageBeep(MB_ICONHAND);
  107.         MessageBox(NULL, szMessage, szTitle, MB_OK|MB_ICONSTOP);
  108.         return FALSE;
  109.     }
  110.  
  111.     alpbi[0] = NULL;
  112.  
  113.     LoadString(hInstance, IDS_APPNAME, szTitle, BUFSIZE );
  114.     LoadString(hInstance, IDS_INTRO, szMessage, BUFSIZE );
  115.  
  116.     if (MessageBox(NULL, szMessage, szTitle, MB_OKCANCEL) == IDCANCEL)
  117.         return 0;
  118.  
  119.     //
  120.     // Set up the bitmaps for the file in an array
  121.     //
  122.     MakeFrames(alpbi, 8, BITMAP_X, BITMAP_Y);
  123.  
  124.     AVIFileInit();
  125.  
  126.     //
  127.     // Open the movie file for writing....
  128.     //
  129.     LoadString(hInstance, IDS_FILENAME, szTitle, BUFSIZE );
  130.     
  131.     hr = AVIFileOpen(&pfile,            // returned file pointer
  132.                szTitle,                    // file name
  133.                OF_WRITE | OF_CREATE,        // mode to open file with
  134.                NULL);                // use handler determined
  135.                             // from file extension....
  136.     if (hr != AVIERR_OK)
  137.         goto error;
  138.  
  139.     // Fill in the header for the video stream....
  140.  
  141.     // The video stream will run in 15ths of a second....
  142.  
  143.     _fmemset(&strhdr, 0, sizeof(strhdr));
  144.     strhdr.fccType                = streamtypeVIDEO;// stream type
  145.     strhdr.fccHandler             = 0;
  146.     strhdr.dwScale                = 1;
  147.     strhdr.dwRate                 = 15;            // 15 fps
  148.     strhdr.dwSuggestedBufferSize  = alpbi[0]->biSizeImage;
  149.     SetRect(&strhdr.rcFrame, 0, 0,            // rectangle for stream
  150.         (int) alpbi[0]->biWidth,
  151.         (int) alpbi[0]->biHeight);
  152.  
  153.     // And create the stream;
  154.     hr = AVIFileCreateStream(pfile,            // file pointer
  155.                      &ps,            // returned stream pointer
  156.                      &strhdr);        // stream header
  157.     if (hr != AVIERR_OK) {
  158.         goto error;
  159.     }
  160.  
  161.     _fmemset(&opts, 0, sizeof(opts));
  162.  
  163.     if (!AVISaveOptions(NULL, 0, 1, &ps, (LPAVICOMPRESSOPTIONS FAR *) &aopts))
  164.         goto error;
  165.  
  166.     hr = AVIMakeCompressedStream(&psCompressed, ps, &opts, NULL);
  167.     if (hr != AVIERR_OK) {
  168.         goto error;
  169.     }
  170.  
  171.     hr = AVIStreamSetFormat(psCompressed, 0,
  172.                    alpbi[0],        // stream format
  173.                    alpbi[0]->biSize +   // format size
  174.                    alpbi[0]->biClrUsed * sizeof(RGBQUAD));
  175.     if (hr != AVIERR_OK) {
  176.     goto error;
  177.     }
  178.  
  179.     // Fill in the stream header for the text stream....
  180.  
  181.     // The text stream is in 60ths of a second....
  182.  
  183.     _fmemset(&strhdr, 0, sizeof(strhdr));
  184.     strhdr.fccType                = streamtypeTEXT;
  185.     strhdr.fccHandler             = mmioFOURCC('D', 'R', 'A', 'W');
  186.     strhdr.dwScale                = 1;
  187.     strhdr.dwRate                 = 60;
  188.     strhdr.dwSuggestedBufferSize  = sizeof(szText);
  189.     SetRect(&strhdr.rcFrame, 0, (int) alpbi[0]->biHeight,
  190.         (int) alpbi[0]->biWidth, (int) alpbi[0]->biHeight + TEXT_HEIGHT);
  191.  
  192.     // ....and create the stream.
  193.     hr = AVIFileCreateStream(pfile, &psText, &strhdr);
  194.     if (hr != AVIERR_OK) {
  195.         goto error;
  196.     }
  197.  
  198.     dwTextFormat = sizeof(dwTextFormat);
  199.     hr = AVIStreamSetFormat(psText, 0, &dwTextFormat, sizeof(dwTextFormat));
  200.     if (hr != AVIERR_OK) {
  201.         goto error;
  202.     }
  203.  
  204.     //
  205.     // Now write out each video frame, along with a text label.
  206.     // The video frames are 2/3 of a second apart, which is 10
  207.     // in the video time scale and 40 in the text stream's time scale.
  208.     //
  209.     for (i = 0; i < N_FRAMES; i++) {
  210.         hr = AVIStreamWrite(psCompressed,    // stream pointer
  211.             i * 10,                // time of this frame
  212.             1,                // number to write
  213.             (LPBYTE) alpbi[i] +        // pointer to data
  214.                 alpbi[i]->biSize +
  215.                 alpbi[i]->biClrUsed * sizeof(RGBQUAD),
  216.                 alpbi[i]->biSizeImage,    // size of this frame
  217.             AVIIF_KEYFRAME,             // flags....
  218.             NULL,
  219.             NULL);
  220.         if (hr != AVIERR_OK)
  221.             break;
  222.     
  223.         // Make some text to put in the file ...
  224.         LoadString(hInstance, IDS_TEXTFORMAT, szMessage, BUFSIZE );
  225.         
  226.         iLen = wsprintf(szText, szMessage, (int)(i + 1));
  227.  
  228.         // ... and write it as well.
  229.         hr = AVIStreamWrite(psText,
  230.                 i * 40,
  231.                 1,
  232.                 szText,
  233.                 iLen + 1,
  234.                 AVIIF_KEYFRAME,
  235.                 NULL,
  236.                 NULL);
  237.         if (hr != AVIERR_OK)
  238.             break;
  239.     }
  240.     
  241. error:
  242.     //
  243.     // Now close the file
  244.     //
  245.     if (ps)
  246.         AVIStreamClose(ps);
  247.  
  248.     if (psCompressed)
  249.         AVIStreamClose(psCompressed);
  250.  
  251.     if (psText)
  252.         AVIStreamClose(psText);
  253.  
  254.     if (pfile)
  255.         AVIFileClose(pfile);
  256.  
  257.     AVIFileExit();
  258.     FreeFrames(alpbi);
  259.  
  260.     if (hr != NOERROR) {
  261.         LoadString(hInstance, IDS_APPERR, szTitle, BUFSIZE );
  262.         LoadString(hInstance, IDS_WRITEERR, szMessage, BUFSIZE );
  263.         
  264.         MessageBox(NULL, szMessage, szTitle, MB_OK);
  265.     }
  266.     return 0;
  267. }
  268.  
  269.  
  270.  
  271.  
  272. //
  273. // Fill an array of LPBI's with the frames for this movie
  274. //
  275. static void MakeFrames(LPLPBI alpbi, UINT bits, UINT wXSize,UINT wYSize )
  276. {
  277.     HDC         hdc ;
  278.     HDC         hdcMem ;
  279.     HBITMAP     hbitmap,hbitmapOld ;
  280.     HPEN        hpen3,hpen1,hpenwhite,hpenOld ;
  281.     HFONT       hfont,hfontOld ;
  282.     HBRUSH      hbrush,hbrushOld ;
  283.     RECT        rc ;
  284.     RECT        rcFrameNo ;
  285.     int         wXCent,wYCent ;
  286.     int         cxPixInch ;
  287.     int         cyPixInch ;
  288.     int         cxPixels ;
  289.     int         cyPixels ;
  290.     int         radius ;
  291.     int         x0,y0,x1,y1 ;
  292.     int         i,j ;
  293.     char        szNumber[3] ;
  294.  
  295.     //
  296.     // Make sure our resources are freed
  297.     //
  298.     FreeFrames(alpbi);
  299.  
  300.     //
  301.     // Find the center of the movie
  302.     //
  303.     wXCent = wXSize/2 ;
  304.     wYCent = wYSize/2 ;
  305.  
  306.     hdc = GetDC(NULL) ;
  307.     hdcMem = CreateCompatibleDC(NULL) ;
  308.  
  309.     //
  310.     // We need some gray and white brushes and pens, and a bitmap
  311.     //
  312.     hpen3 = CreatePen(PS_SOLID,3,RGB(128,128,128)) ;
  313.     hpen1 = CreatePen(PS_SOLID,1,RGB(64,64,64));
  314.     hpenwhite = CreatePen(PS_SOLID,1,RGB(255,255,255));
  315.     hpenOld = SelectPen(hdcMem, hpen3);
  316.     hbrush = CreateSolidBrush(RGB(192,192,192)) ;
  317.     hbrushOld = SelectBrush(hdcMem,hbrush) ;
  318.     hbitmap = CreateCompatibleBitmap(hdc,wXSize,wYSize) ;
  319.  
  320.     cxPixInch = GetDeviceCaps(hdc,LOGPIXELSX) ;
  321.     cyPixInch = GetDeviceCaps(hdc,LOGPIXELSY) ;
  322.  
  323.     //
  324.     // What radius of circle can we fit in this frame?  Make sure it's round
  325.     // regardless of the aspect ratio
  326.     //
  327.     radius = ( wXSize < wYSize ) ? wXSize : (wYSize*cxPixInch)/cyPixInch ;
  328.     radius = ( radius * 95 ) / 200 ;
  329.  
  330.     //
  331.     // Make a Rectangle in the center where the number will go
  332.     //
  333.     /* x0 = radius / sqrt(2) */
  334.     x0 = (radius*100)/141 ;
  335.     y0 = (x0*cyPixInch)/cxPixInch ;
  336.     x0 = (x0*9)/10 ;
  337.     y0 = (y0*9)/10 ;
  338.     SetRect( &rcFrameNo,wXCent-x0,wYCent-y0,wXCent+x0,wYCent+y0 ) ;
  339.  
  340.     //
  341.     // Move the rectangle in a little and make a font big enough for it
  342.     //
  343.     x0 = (x0*9)/10 ;
  344.     y0 = (y0*9)/10 ;
  345.  
  346.     hfont = CreateFont(
  347.         y0*2,
  348.         x0,
  349.         0,
  350.         0,
  351.         FW_BOLD,
  352.         0,
  353.         0,
  354.         0,
  355.         ANSI_CHARSET,
  356.         OUT_DEVICE_PRECIS,
  357.         CLIP_DEFAULT_PRECIS,
  358.         DEFAULT_QUALITY,
  359.         DEFAULT_PITCH|FF_SWISS,
  360.         NULL
  361.     );
  362.  
  363.     hfontOld = SelectFont(hdcMem, hfont);
  364.  
  365.     //
  366.     // Now walk through and make all the frames
  367.     //
  368.     for ( i=0; i<N_FRAMES; i++ ) {
  369.         hbitmapOld = SelectBitmap(hdcMem, hbitmap);
  370.     
  371.         //
  372.         // Fill the whole frame with white
  373.         //
  374.         SetRect(&rc,0,0,wXSize,wYSize) ;
  375.         FillRect(hdcMem,&rc,GetStockBrush(WHITE_BRUSH)) ;
  376.  
  377.         //
  378.         // Draw the circle inside the previously calculated radius
  379.         //
  380.         cxPixels = radius ;
  381.         cyPixels = (cxPixels*cyPixInch)/cxPixInch ;
  382.  
  383.         SelectPen(hdcMem,hpen3) ;
  384.         Ellipse(hdcMem,wXCent-cxPixels,wYCent-cyPixels,wXCent+cxPixels,
  385.             wYCent+cyPixels) ;
  386.  
  387.         SelectPen(hdcMem,hpen1) ;
  388.  
  389.         //
  390.         // Draw the number in the previously calculated area
  391.         //
  392.         wsprintf(szNumber,"%02u",i+1) ;
  393.  
  394.         SetBkColor(hdcMem,RGB(192,192,192)) ;
  395.         SetTextColor(hdcMem,RGB(255,255,255)) ;
  396.         ExtTextOut(
  397.             hdcMem,
  398.             rcFrameNo.left,
  399.             rcFrameNo.top+(rcFrameNo.bottom-rcFrameNo.top)/20,
  400.             ETO_CLIPPED,
  401.             &rcFrameNo,
  402.             szNumber,
  403.             2,
  404.             NULL);
  405.  
  406.         //
  407.         // Draw tic marks around the inside of the circle in equal divisions
  408.         //
  409.         for ( j=0; j<N_FRAMES; j++ ) {
  410.             x0 = (radius*aSin[j])/100 ;
  411.             y0 = (radius*aCos[j])/100 ;
  412.             x1 = (((radius*aSin[j])/100)*11)/12 ;
  413.             y1 = (((radius*aCos[j])/100)*11)/12 ;
  414.  
  415.             y0 = -(y0*cyPixInch)/cxPixInch ;
  416.             y1 = -(y1*cyPixInch)/cxPixInch ;
  417.  
  418.             MoveToEx(hdcMem,wXCent+x0,wYCent+y0,NULL) ;
  419.             LineTo(hdcMem,wXCent+x1,wYCent+y1) ;
  420.         }
  421.  
  422.         //
  423.         // Now draw the hand of the clock in the appropriate position
  424.         //
  425.         x1 = (((radius*aSin[i])/100)*5)/8 ;
  426.         y1 = (((radius*aCos[i])/100)*5)/8 ;
  427.         y1 = -(y1*cyPixInch)/cxPixInch ;
  428.  
  429.         MoveToEx(hdcMem,wXCent,wYCent,NULL) ;
  430.         LineTo(hdcMem,wXCent+x1,wYCent+y1) ;
  431.  
  432.         SelectBitmap(hdcMem, hbitmapOld);
  433.         //
  434.         // Make this into a DIB and stuff it into the array
  435.         //
  436.         alpbi[i] = (LPBITMAPINFOHEADER)GlobalLock(MakeDib(hbitmap, bits));
  437.  
  438.         //
  439.         // For an error, just duplicate the last frame if we can
  440.         //
  441.         if (alpbi[i] == NULL && i )
  442.             alpbi[i] = alpbi[i-1] ;
  443.     }
  444.  
  445.     //
  446.     // Select all the old objects back and delete resources
  447.     //
  448.     SelectPen(hdcMem, hpenOld);
  449.     SelectBrush(hdcMem,hbrushOld) ;
  450.     SelectFont(hdcMem,hfontOld) ;
  451.     DeletePen(hpen1) ;
  452.     DeletePen(hpen3) ;
  453.     DeletePen(hpenwhite) ;
  454.     DeleteBrush(hbrush) ;
  455.     DeleteBitmap(hbitmap) ;
  456.     DeleteFont(hfont) ;
  457.     DeleteObject(hdcMem) ;
  458.     ReleaseDC(NULL,hdc) ;
  459. }
  460.  
  461. //
  462. // Walk through our array of LPBI's and free them
  463. //
  464. static void FreeFrames(LPLPBI alpbi)
  465. {
  466.     UINT        w ;
  467.  
  468.     if (!alpbi[0])
  469.         return ;
  470.     //
  471.     // Don't free a frame if it's a duplicate of the previous one
  472.     //
  473.     for (w=0; w<N_FRAMES; w++)
  474.         if (alpbi[w] && alpbi[w] != alpbi[w-1])
  475.             GlobalFreePtr(alpbi[w]);
  476.     for (w=0; w<N_FRAMES; w++)
  477.         alpbi[w] = NULL;
  478. }
  479.  
  480. /*
  481. ** MakeDib(hbitmap)
  482. **
  483. ** Take the given bitmap and transform it into a DIB with parameters:
  484. **
  485. ** BitsPerPixel:    8
  486. ** Colors:          palette
  487. **
  488. */
  489. static HANDLE  MakeDib( HBITMAP hbitmap, UINT bits )
  490. {
  491.     HANDLE              hdib ;
  492.     HDC                 hdc ;
  493.     BITMAP              bitmap ;
  494.     UINT                wLineLen ;
  495.     DWORD               dwSize ;
  496.     DWORD               wColSize ;
  497.     LPBITMAPINFOHEADER  lpbi ;
  498.     LPBYTE              lpBits ;
  499.     
  500.     GetObject(hbitmap,sizeof(BITMAP),&bitmap) ;
  501.  
  502.     //
  503.     // DWORD align the width of the DIB
  504.     // Figure out the size of the colour table
  505.     // Calculate the size of the DIB
  506.     //
  507.     wLineLen = (bitmap.bmWidth*bits+31)/32 * 4;
  508.     wColSize = sizeof(RGBQUAD)*((bits <= 8) ? 1<<bits : 0);
  509.     dwSize = sizeof(BITMAPINFOHEADER) + wColSize +
  510.         (DWORD)(UINT)wLineLen*(DWORD)(UINT)bitmap.bmHeight;
  511.  
  512.     //
  513.     // Allocate room for a DIB and set the LPBI fields
  514.     //
  515.     hdib = GlobalAlloc(GHND,dwSize);
  516.     if (!hdib)
  517.         return hdib ;
  518.  
  519.     lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib) ;
  520.  
  521.     lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
  522.     lpbi->biWidth = bitmap.bmWidth ;
  523.     lpbi->biHeight = bitmap.bmHeight ;
  524.     lpbi->biPlanes = 1 ;
  525.     lpbi->biBitCount = (WORD) bits ;
  526.     lpbi->biCompression = BI_RGB ;
  527.     lpbi->biSizeImage = dwSize - sizeof(BITMAPINFOHEADER) - wColSize ;
  528.     lpbi->biXPelsPerMeter = 0 ;
  529.     lpbi->biYPelsPerMeter = 0 ;
  530.     lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
  531.     lpbi->biClrImportant = 0 ;
  532.  
  533.     //
  534.     // Get the bits from the bitmap and stuff them after the LPBI
  535.     //
  536.     lpBits = (LPBYTE)(lpbi+1)+wColSize ;
  537.  
  538.     hdc = CreateCompatibleDC(NULL) ;
  539.  
  540.     GetDIBits(hdc,hbitmap,0,bitmap.bmHeight,lpBits,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  541.  
  542.     // Fix this if GetDIBits messed it up....
  543.     lpbi->biClrUsed = (bits <= 8) ? 1<<bits : 0;
  544.  
  545.     DeleteDC(hdc) ;
  546.     GlobalUnlock(hdib);
  547.  
  548.     return hdib ;
  549. }
  550.