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 / aviview / aviball.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  14KB  |  437 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) 1993 - 1997  Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. /****************************************************************************
  12.  *
  13.  *  AVIBALL.C
  14.  *
  15.  *  Sample AVIStream handler for a bouncing ball.  This code demonstrates
  16.  *  how to write a custom stream handler so an application can deal with
  17.  *  your custom file/data/whatever by using the standard AVIStream functions.
  18.  *
  19. ***************************************************************************/
  20.  
  21. #define INC_OLE2
  22. #include <windows.h>
  23. #include <windowsx.h>
  24. #include <mmsystem.h>
  25. #include <vfw.h>
  26.  
  27. #include "aviball.h"
  28.  
  29. ///////////////////////////////////////////////////////////////////////////
  30. //
  31. // silly default parameters
  32. //
  33. ///////////////////////////////////////////////////////////////////////////
  34.  
  35. #define DEFAULT_WIDTH   240
  36. #define DEFAULT_HEIGHT  120
  37. #define DEFAULT_LENGTH  100
  38. #define DEFAULT_SIZE    6
  39. #define DEFAULT_COLOR   RGB(255,0,0)
  40. #define XSPEED        7
  41. #define YSPEED        5
  42.  
  43. ///////////////////////////////////////////////////////////////////////////
  44. //
  45. // useful macros
  46. //
  47. ///////////////////////////////////////////////////////////////////////////
  48.  
  49. #define ALIGNULONG(i)     ((i+3)&(~3))                  /* ULONG aligned ! */
  50. #define WIDTHBYTES(i)     ((unsigned)((i+31)&(~31))/8)  /* ULONG aligned ! */
  51. #define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  52. #define DIBPTR(lpbi) ((LPBYTE)(lpbi) + \
  53.         (int)(lpbi)->biSize + \
  54.         (int)(lpbi)->biClrUsed * sizeof(RGBQUAD) )
  55.  
  56. ///////////////////////////////////////////////////////////////////////////
  57. //
  58. // custom video stream instance structure
  59. //
  60. ///////////////////////////////////////////////////////////////////////////
  61.  
  62. typedef struct {
  63.  
  64.     //
  65.     // The Vtbl must come first
  66.     //
  67.     IAVIStreamVtbl * lpvtbl;
  68.  
  69.     //
  70.     //  private ball instance data
  71.     //
  72.     ULONG    ulRefCount;
  73.  
  74.     DWORD       fccType;        // is this audio/video
  75.  
  76.     int         width;          // size in pixels of each frame
  77.     int         height;
  78.     int         length;         // length in frames of the pretend AVI movie
  79.     int         size;
  80.     COLORREF    color;          // ball color
  81.  
  82. } AVIBALL, * PAVIBALL;
  83.  
  84. ///////////////////////////////////////////////////////////////////////////
  85. //
  86. // custom stream methods
  87. //
  88. ///////////////////////////////////////////////////////////////////////////
  89.  
  90. HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj);
  91. HRESULT STDMETHODCALLTYPE AVIBallCreate       (PAVISTREAM ps, LONG lParam1, LONG lParam2);
  92. ULONG   STDMETHODCALLTYPE AVIBallAddRef       (PAVISTREAM ps);
  93. ULONG   STDMETHODCALLTYPE AVIBallRelease      (PAVISTREAM ps);
  94. HRESULT STDMETHODCALLTYPE AVIBallInfo         (PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize);
  95. LONG    STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags);
  96. HRESULT STDMETHODCALLTYPE AVIBallReadFormat   (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG *lpcbFormat);
  97. HRESULT STDMETHODCALLTYPE AVIBallSetFormat    (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat);
  98. HRESULT STDMETHODCALLTYPE AVIBallRead         (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG * plBytes,LONG * plSamples);
  99. HRESULT STDMETHODCALLTYPE AVIBallWrite        (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten);
  100. HRESULT STDMETHODCALLTYPE AVIBallDelete       (PAVISTREAM ps, LONG lStart, LONG lSamples);
  101. HRESULT STDMETHODCALLTYPE AVIBallReadData     (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG *lpcb);
  102. HRESULT STDMETHODCALLTYPE AVIBallWriteData    (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG cb);
  103.  
  104. IAVIStreamVtbl AVIBallHandler = {
  105.     AVIBallQueryInterface,
  106.     AVIBallAddRef,
  107.     AVIBallRelease,
  108.     AVIBallCreate,
  109.     AVIBallInfo,
  110.     AVIBallFindSample,
  111.     AVIBallReadFormat,
  112.     AVIBallSetFormat,
  113.     AVIBallRead,
  114.     AVIBallWrite,
  115.     AVIBallDelete,
  116.     AVIBallReadData,
  117.     AVIBallWriteData
  118. };
  119.  
  120.  
  121. //
  122. // This is the function an application would call to create a PAVISTREAM to
  123. // reference the ball.  Then the standard AVIStream function calls can be
  124. // used to work with this stream.
  125. //
  126. PAVISTREAM WINAPI NewBall(void)
  127. {
  128.     PAVIBALL pball;
  129.  
  130.     //
  131.     // Create a pointer to our private structure which will act as our
  132.     // PAVISTREAM
  133.     //
  134.     pball = (PAVIBALL) GlobalAllocPtr(GHND, sizeof(AVIBALL));
  135.  
  136.     if (!pball)
  137.     return 0;
  138.  
  139.     //
  140.     // Fill the function table
  141.     //
  142.     pball->lpvtbl = &AVIBallHandler;
  143.  
  144.     //
  145.     // Call our own create code to create a new instance (calls AVIBallCreate)
  146.     // For now, don't use any lParams.
  147.     //
  148.     pball->lpvtbl->Create((PAVISTREAM) pball, 0, 0);
  149.  
  150.     return (PAVISTREAM) pball;
  151. }
  152.  
  153. ///////////////////////////////////////////////////////////////////////////
  154. //
  155. // This function is called to initialize an instance of the bouncing ball.
  156. //
  157. // When called, we look at the information possibly passed in <lParam1>,
  158. // if any, and use it to determine the length of movie they want. (Not
  159. // supported by NewBall right now, but it could be).
  160. //
  161. ///////////////////////////////////////////////////////////////////////////
  162. HRESULT STDMETHODCALLTYPE AVIBallCreate(PAVISTREAM ps, LONG lParam1, LONG lParam2)
  163. {
  164.     PAVIBALL pball = (PAVIBALL) ps;
  165.  
  166.     //
  167.     // what type of data are we? (audio/video/other stream)
  168.     //
  169.     pball->fccType = streamtypeVIDEO;
  170.  
  171.     //
  172.     // We define lParam1 as being the length of movie they want us to pretend
  173.     // to be.
  174.     //
  175.     if (lParam1)
  176.     pball->length = (int) lParam1;
  177.     else
  178.     pball->length = DEFAULT_LENGTH;
  179.  
  180.     switch (pball->fccType) {
  181.  
  182.     case streamtypeVIDEO:
  183.         pball->color  = DEFAULT_COLOR;
  184.         pball->width  = DEFAULT_WIDTH;
  185.         pball->height = DEFAULT_HEIGHT;
  186.         pball->size   = DEFAULT_SIZE;
  187.         pball->ulRefCount = 1;    // note that we are opened once
  188.         return AVIERR_OK;           // success
  189.  
  190.     case streamtypeAUDIO:
  191.         return ResultFromScode(AVIERR_UNSUPPORTED); // we don't do audio
  192.  
  193.     default:
  194.         return ResultFromScode(AVIERR_UNSUPPORTED); // or anything else
  195.     }
  196. }
  197.  
  198.  
  199. //
  200. // Increment our reference count
  201. //
  202. ULONG STDMETHODCALLTYPE AVIBallAddRef(PAVISTREAM ps)
  203. {
  204.     PAVIBALL pball = (PAVIBALL) ps;
  205.     return (++pball->ulRefCount);
  206. }
  207.  
  208.  
  209. //
  210. // Decrement our reference count
  211. //
  212. ULONG STDMETHODCALLTYPE AVIBallRelease(PAVISTREAM ps)
  213. {
  214.     PAVIBALL pball = (PAVIBALL) ps;
  215.     if (--pball->ulRefCount)
  216.     return pball->ulRefCount;
  217.  
  218.     // Free any data we're keeping around - like our private structure
  219.     GlobalFreePtr(pball);
  220.  
  221.     return 0;
  222. }
  223.  
  224.  
  225. //
  226. // Fills an AVISTREAMINFO structure
  227. //
  228. HRESULT STDMETHODCALLTYPE AVIBallInfo(PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize)
  229. {
  230.     PAVIBALL pball = (PAVIBALL) ps;
  231.  
  232.     if (lSize < sizeof(AVISTREAMINFO))
  233.     return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  234.  
  235.     _fmemset(psi, 0, (int)lSize);
  236.  
  237.     // Fill out a stream header with information about us.
  238.     psi->fccType                = pball->fccType;
  239.     psi->fccHandler             = mmioFOURCC('B','a','l','l');
  240.     psi->dwScale                = 1;
  241.     psi->dwRate                 = 15;
  242.     psi->dwLength               = pball->length;
  243.     psi->dwSuggestedBufferSize  = pball->height * ALIGNULONG(pball->width);
  244.     psi->rcFrame.right          = pball->width;
  245.     psi->rcFrame.bottom         = pball->height;
  246.     CopyMemory((PVOID)psi->szName,
  247.                (PVOID)L"Bouncing ball video",
  248.                sizeof(L"Bouncing ball video"));
  249.  
  250.     return AVIERR_OK;
  251. }
  252.  
  253. ///////////////////////////////////////////////////////////////////////////
  254. //
  255. // AVIBallReadFormat: needs to return the format of our data.
  256. //
  257. ///////////////////////////////////////////////////////////////////////////
  258. HRESULT STDMETHODCALLTYPE AVIBallReadFormat   (PAVISTREAM ps, LONG lPos,LPVOID lpFormat,LONG *lpcbFormat)
  259. {
  260.     PAVIBALL pball = (PAVIBALL) ps;
  261.     LPBITMAPINFO    lpbi = (LPBITMAPINFO) lpFormat;
  262.  
  263.     if (lpFormat == NULL || *lpcbFormat == 0) {
  264.     *lpcbFormat = sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);
  265.     return AVIERR_OK;
  266.     }
  267.  
  268.     if (*lpcbFormat < sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD))
  269.     return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  270.  
  271.     // This is a relatively silly example: we build up our
  272.     // format from scratch every time.
  273.  
  274.     lpbi->bmiHeader.biSize              = sizeof(BITMAPINFOHEADER);
  275.     lpbi->bmiHeader.biCompression       = BI_RGB;
  276.     lpbi->bmiHeader.biWidth             = pball->width;
  277.     lpbi->bmiHeader.biHeight            = pball->height;
  278.     lpbi->bmiHeader.biBitCount          = 8;
  279.     lpbi->bmiHeader.biPlanes            = 1;
  280.     lpbi->bmiHeader.biClrUsed           = 2;
  281.     lpbi->bmiHeader.biSizeImage         = pball->height * DIBWIDTHBYTES(lpbi->bmiHeader);
  282.  
  283.     lpbi->bmiColors[0].rgbRed           = 0;
  284.     lpbi->bmiColors[0].rgbGreen         = 0;
  285.     lpbi->bmiColors[0].rgbBlue          = 0;
  286.     lpbi->bmiColors[1].rgbRed           = GetRValue(pball->color);
  287.     lpbi->bmiColors[1].rgbGreen         = GetGValue(pball->color);
  288.     lpbi->bmiColors[1].rgbBlue          = GetBValue(pball->color);
  289.  
  290.     *lpcbFormat = sizeof(BITMAPINFOHEADER) + 2 * sizeof(RGBQUAD);
  291.  
  292.     return AVIERR_OK;
  293. }
  294.  
  295. ///////////////////////////////////////////////////////////////////////////
  296. //
  297. // AVIBallRead: needs to return the data for a particular frame.
  298. //
  299. ///////////////////////////////////////////////////////////////////////////
  300. HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart,LONG lSamples,LPVOID lpBuffer,LONG cbBuffer,LONG * plBytes,LONG * plSamples)
  301. {
  302.     PAVIBALL pball = (PAVIBALL) ps;
  303.     LONG   lSize = pball->height * ALIGNULONG(pball->width); // size of frame
  304.                                  // in bytes
  305.     int x, y;
  306.     HPSTR hp = lpBuffer;
  307.     int xPos, yPos;
  308.  
  309.     // Reject out of range values
  310.     if (lStart < 0 || lStart >= pball->length)
  311.     return ResultFromScode(AVIERR_BADPARAM);
  312.  
  313.     // Did they just want to know the size of our data?
  314.     if (lpBuffer == NULL || cbBuffer == 0)
  315.     goto exit;
  316.  
  317.     // Will our frame fit in the buffer passed?
  318.     if (lSize > cbBuffer)
  319.     return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  320.  
  321.     // Figure out the position of the ball.
  322.     // It just bounces back and forth.
  323.  
  324.     xPos = 5 + XSPEED * (int) lStart;                // x = x0 + vt
  325.     xPos = xPos % ((pball->width - pball->size) * 2);        // limit to 2xwidth
  326.     if (xPos > (pball->width - pball->size))            // reflect if
  327.     xPos = 2 * (pball->width - pball->size) - xPos;        //   needed
  328.  
  329.     yPos = 5 + YSPEED * (int) lStart;
  330.     yPos = yPos % ((pball->height - pball->size) * 2);
  331.     if (yPos > (pball->height - pball->size))
  332.     yPos = 2 * (pball->height - pball->size) - yPos;
  333.  
  334.     //
  335.     // Build a DIB from scratch by writing in 1's where the ball is, 0's
  336.     // where it isn't.
  337.     //
  338.     // Notice that we just build it in the buffer we've been passed.
  339.     //
  340.     // This is pretty ugly, I have to admit.
  341.     //
  342.     for (y = 0; y < pball->height; y++)
  343.     {
  344.     if (y >= yPos && y < yPos + pball->size)
  345.     {
  346.         for (x = 0; x < pball->width; x++)
  347.         {
  348.         *hp++ = (BYTE) ((x >= xPos && x < xPos + pball->size) ? 1 : 0);
  349.         }
  350.     }
  351.     else
  352.     {
  353.         for (x = 0; x < pball->width; x++)
  354.         {
  355.         *hp++ = 0;
  356.         }
  357.     }
  358.     
  359.     hp += pball->width - ALIGNULONG(pball->width);
  360.     }
  361.  
  362. exit:
  363.     // We always return exactly one frame
  364.     if (plSamples)
  365.     *plSamples = 1;
  366.  
  367.     // Return the size of our frame
  368.     if (plBytes)
  369.     *plBytes = lSize;
  370.  
  371.     return AVIERR_OK;
  372. }
  373.  
  374.  
  375. HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj)
  376. {
  377.     PAVIBALL pball = (PAVIBALL) ps;
  378.  
  379.     // We support the Unknown interface (everybody does) and our Stream
  380.     // interface.
  381.  
  382.     if (_fmemcmp(riid, &IID_IUnknown, sizeof(GUID)) == 0)
  383.         *ppvObj = (LPVOID)pball;
  384.  
  385.     else if (_fmemcmp(riid, &IID_IAVIStream, sizeof(GUID)) == 0)
  386.         *ppvObj = (LPVOID)pball;
  387.  
  388.     else {
  389.         *ppvObj = NULL;
  390.         return ResultFromScode(E_NOINTERFACE);
  391.     }
  392.  
  393.     AVIBallAddRef(ps);
  394.  
  395.     return AVIERR_OK;
  396. }
  397.  
  398. LONG    STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags)
  399. {
  400.     // The only format change is frame 0
  401.     if ((lFlags & FIND_TYPE) == FIND_FORMAT) {
  402.     if ((lFlags & FIND_DIR) == FIND_NEXT && lPos > 0)
  403.         return -1;    // no more format changes
  404.     else
  405.         return 0;
  406.  
  407.     // FIND_KEY and FIND_ANY always return the same position because
  408.     // every frame is non-empty and a key frame
  409.     } else
  410.         return lPos;
  411. }
  412.  
  413. HRESULT STDMETHODCALLTYPE AVIBallReadData     (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG *lpcb)
  414. {
  415.     return ResultFromScode(AVIERR_UNSUPPORTED);
  416. }
  417.  
  418. HRESULT STDMETHODCALLTYPE AVIBallSetFormat    (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat)
  419. {
  420.     return ResultFromScode(AVIERR_UNSUPPORTED);
  421. }
  422.  
  423. HRESULT STDMETHODCALLTYPE AVIBallWriteData    (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG cb)
  424. {
  425.     return ResultFromScode(AVIERR_UNSUPPORTED);
  426. }
  427.  
  428. HRESULT STDMETHODCALLTYPE AVIBallWrite        (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten)
  429. {
  430.     return ResultFromScode(AVIERR_UNSUPPORTED);
  431. }
  432.  
  433. HRESULT STDMETHODCALLTYPE AVIBallDelete       (PAVISTREAM ps, LONG lStart, LONG lSamples)
  434. {
  435.     return ResultFromScode(AVIERR_UNSUPPORTED);
  436. }
  437.