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.

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