aviball.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 14k
Category:

Windows Develop

Development Platform:

Visual C++

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