Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
13 KiB

  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. // 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 odd 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. }