Windows NT 4.0 source code leak
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.

742 lines
21 KiB

4 years ago
  1. /****************************************************************************
  2. *
  3. * capdib.c
  4. *
  5. * DIB processing module.
  6. *
  7. * Microsoft Video for Windows Sample Capture Class
  8. *
  9. * Copyright (c) 1992, 1993 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. #define INC_OLE2
  19. #pragma warning(disable:4103)
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <win32.h>
  23. #include <mmsystem.h>
  24. #include <msvideo.h>
  25. #include <drawdib.h>
  26. #include "ivideo32.h"
  27. #include "avicap.h"
  28. #include "avicapi.h"
  29. //
  30. // Initialize a DIB to the default format of 160x120x8, BI_RGB
  31. //
  32. void SetDefaultCaptureFormat (LPBITMAPINFOHEADER lpbih)
  33. {
  34. lpbih->biSize = sizeof (BITMAPINFOHEADER);
  35. lpbih->biWidth = 160;
  36. lpbih->biHeight = 120;
  37. lpbih->biBitCount = 8;
  38. lpbih->biPlanes = 1;
  39. lpbih->biCompression = BI_RGB;
  40. lpbih->biSizeImage = DIBWIDTHBYTES (*lpbih) * lpbih->biHeight;
  41. lpbih->biXPelsPerMeter = 0;
  42. lpbih->biYPelsPerMeter = 0;
  43. lpbih->biClrUsed = 256;
  44. lpbih->biClrImportant = 0;
  45. }
  46. //
  47. // Whenever we get a new format from the driver, OR
  48. // start using a new palette, we must reallocate
  49. // our global BITMAPINFOHEADER. This allows JPEG
  50. // quantization tables to be tacked onto the BITMAPINFO
  51. // or any other format specific stuff. The color table
  52. // is always offset biSize from the start of the BITMAPINFO.
  53. // Returns: 0 on success, or DV_ERR_... code
  54. //
  55. DWORD AllocNewGlobalBitmapInfo (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbi)
  56. {
  57. DWORD dwSize;
  58. dwSize = lpbi->biSize + 256 * sizeof (RGBQUAD);
  59. // The 256 entry above is HARDWIRED ON PURPOSE
  60. // If biClrUsed was used instead, we would have to realloc
  61. // whenever a palette is pasted (during DibNewPalette())!!!
  62. if (lpcs->lpBitsInfo)
  63. lpcs->lpBitsInfo = (LPBITMAPINFO) GlobalReAllocPtr (lpcs->lpBitsInfo,
  64. dwSize, GHND);
  65. else
  66. lpcs->lpBitsInfo = (LPBITMAPINFO) GlobalAllocPtr (GHND, dwSize);
  67. if (!lpcs->lpBitsInfo)
  68. return (DV_ERR_NOMEM);
  69. // Copy over the BITMAPINFOHEADER
  70. CopyMemory (lpcs->lpBitsInfo, lpbi, lpbi->biSize);
  71. return DV_ERR_OK;
  72. }
  73. //
  74. // Whenever we get a new format from the driver
  75. // allocate a new global bitspace. This bitspace is used
  76. // in preview mode and single frame capture.
  77. // Returns: 0 on success, or DV_ERR_... code
  78. //
  79. DWORD AllocNewBitSpace (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih)
  80. {
  81. DWORD dwSize;
  82. // Allow room for a RIFF chunk prepended to the actual image,
  83. // and a junk chunk on the tail end
  84. #define RESERVE_FOR_RIFF (512+sizeof(RIFF))
  85. dwSize = lpbih->biSizeImage + RESERVE_FOR_RIFF;
  86. if (lpcs->lpBitsUnaligned) {
  87. #ifdef CHICAGO
  88. vidxFreePreviewBuffer (lpcs->hVideoIn,
  89. lpcs->lpBitsUnaligned);
  90. #else
  91. FreeSectorAlignedMem (lpcs->lpBitsUnaligned);
  92. #endif
  93. lpcs->lpBitsUnaligned = NULL;
  94. lpcs->lpBits = NULL;
  95. }
  96. #ifdef CHICAGO
  97. if (MMSYSERR_NOERROR == vidxAllocPreviewBuffer (
  98. lpcs->hVideoIn,
  99. &lpcs->lpBitsUnaligned,
  100. dwSize)) {
  101. lpcs->lpBits = (LPBYTE) (ROUNDUPTOSECTORSIZE(lpcs->lpBitsUnaligned, 512)
  102. + sizeof(RIFF));
  103. }
  104. #else
  105. if (lpcs->lpBitsUnaligned = ((LPBYTE)AllocSectorAlignedMem (dwSize, 512))) {
  106. lpcs->lpBits = (LPBYTE) (ROUNDUPTOSECTORSIZE(lpcs->lpBitsUnaligned, 512)
  107. + sizeof(RIFF));
  108. }
  109. #endif
  110. if (!lpcs->lpBits)
  111. return (DV_ERR_NOMEM);
  112. return DV_ERR_OK;
  113. }
  114. //
  115. // Dib Initialization code
  116. // Returns: 0 on success, or DV_ERR_... code
  117. //
  118. DWORD DibInit (LPCAPSTREAM lpcs)
  119. {
  120. BITMAPINFOHEADER bmih;
  121. SetDefaultCaptureFormat (&bmih);
  122. return ((WORD) AllocNewGlobalBitmapInfo (lpcs, &bmih));
  123. }
  124. //
  125. // Fini code to free all bitmap resources
  126. //
  127. void DibFini (LPCAPSTREAM lpcs)
  128. {
  129. if (lpcs->lpBits) {
  130. #ifdef CHICAGO
  131. vidxFreePreviewBuffer (lpcs->hVideoIn, lpcs->lpBitsUnaligned);
  132. #else
  133. FreeSectorAlignedMem (lpcs->lpBitsUnaligned);
  134. #endif
  135. lpcs->lpBits = NULL;
  136. lpcs->lpBitsUnaligned = NULL;
  137. }
  138. if (lpcs->lpBitsInfo) {
  139. GlobalFreePtr (lpcs->lpBitsInfo);
  140. lpcs->lpBitsInfo = NULL;
  141. }
  142. lpcs->dxBits = 0;
  143. lpcs->dyBits = 0;
  144. }
  145. //
  146. // Send a format to the driver.
  147. // Whenever we do a format change, send the driver the
  148. // Source and destination rects.
  149. // Returns: 0 on success, or DV_ERR_... code
  150. //
  151. DWORD SendDriverFormat (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih, DWORD dwInfoHeaderSize)
  152. {
  153. RECT rc;
  154. DWORD dwError = DV_ERR_NOTSUPPORTED;
  155. rc.left = rc.top = 0;
  156. rc.right = (int) lpbih->biWidth;
  157. rc.bottom = (int) lpbih->biHeight;
  158. if (dwError = videoConfigure(lpcs->hVideoIn,
  159. DVM_FORMAT,
  160. VIDEO_CONFIGURE_SET, NULL,
  161. (LPBITMAPINFOHEADER)lpbih, dwInfoHeaderSize,
  162. NULL, 0 ) ) {
  163. return dwError;
  164. } else {
  165. videoSetRect (lpcs->hVideoCapture, DVM_DST_RECT, rc);
  166. videoSetRect (lpcs->hVideoIn, DVM_SRC_RECT, rc);
  167. videoSetRect (lpcs->hVideoIn, DVM_DST_RECT, rc);
  168. }
  169. return dwError;
  170. }
  171. //
  172. // Given a DIB, see if the driver likes it, then
  173. // allocate the global BITMAPINFOHEADER and bitspace.
  174. //
  175. //
  176. DWORD SetFormatFromDIB (LPCAPSTREAM lpcs, LPBITMAPINFOHEADER lpbih)
  177. {
  178. DWORD dwError;
  179. // Fill optional fields in the DIB header
  180. if (lpbih->biSizeImage == 0)
  181. lpbih->biSizeImage = DIBWIDTHBYTES (*lpbih) * lpbih->biHeight;
  182. // Is the format palatized or full-color
  183. if (lpbih->biBitCount <= 8 && lpbih->biClrUsed == 0)
  184. lpbih->biClrUsed = (1 << lpbih->biBitCount); // paletized
  185. // See if the driver will support it
  186. if (dwError = SendDriverFormat (lpcs, lpbih, lpbih->biSize) )
  187. return dwError;
  188. // Realloc our global header
  189. if (dwError = AllocNewGlobalBitmapInfo (lpcs, lpbih))
  190. return dwError;
  191. // Realloc the bits
  192. if (dwError = AllocNewBitSpace (lpcs, lpbih))
  193. return dwError;
  194. lpcs->dxBits = (int)lpbih->biWidth;
  195. lpcs->dyBits = (int)lpbih->biHeight;
  196. lpcs->VidHdr.lpData = lpcs->lpBits;
  197. lpcs->VidHdr.dwBufferLength = lpbih->biSizeImage;
  198. lpcs->VidHdr.dwUser = 0;
  199. lpcs->VidHdr.dwFlags = 0;
  200. return (DV_ERR_OK);
  201. }
  202. //
  203. // Returns: a LPBITMAPINFO allocated from global memory
  204. // containing the current format, or NULL on error.
  205. // Note that this structure can be larger than
  206. // sizeof (BITMAPINFO), ie. JPEG !!!
  207. //
  208. LPBITMAPINFO DibGetCurrentFormat (LPCAPSTREAM lpcs)
  209. {
  210. DWORD dwError;
  211. DWORD dwSize = 0;
  212. LPBITMAPINFO lpBInfo = NULL;
  213. if (!lpcs->fHardwareConnected)
  214. return NULL;
  215. // How large is the BITMAPINFOHEADER?
  216. videoConfigure( lpcs->hVideoIn,
  217. DVM_FORMAT,
  218. VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERYSIZE,
  219. &dwSize, 0, 0, NULL, 0);
  220. if (!dwSize)
  221. dwSize = sizeof (BITMAPINFOHEADER);
  222. if (!(lpBInfo = (LPBITMAPINFO) GlobalAllocPtr (GMEM_MOVEABLE, dwSize)))
  223. return (NULL);
  224. if (dwError = videoConfigure( lpcs->hVideoIn,
  225. DVM_FORMAT,
  226. VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT, NULL,
  227. (LPBITMAPINFOHEADER) lpBInfo, dwSize,
  228. NULL, 0 ) ) {
  229. // very bad. the driver can't tell us its format. we're hosed.
  230. GlobalFreePtr (lpBInfo);
  231. return NULL;
  232. }
  233. return (lpBInfo);
  234. }
  235. //
  236. // Main entry point when changing capture formats.
  237. // This is called when the user closes the drivers format dialog.
  238. // Returns: 0 on success, or DV_ERR_... code
  239. //
  240. DWORD DibGetNewFormatFromDriver (LPCAPSTREAM lpcs)
  241. {
  242. BOOL f;
  243. BITMAPINFOHEADER bih;
  244. DWORD dwError;
  245. LPBITMAPINFO lpBInfo;
  246. if (!lpcs->fHardwareConnected)
  247. return DV_ERR_OK; // Return OK if no hardware exists
  248. lpBInfo = DibGetCurrentFormat (lpcs);
  249. if (lpBInfo == NULL)
  250. return DV_ERR_NOTSUPPORTED;
  251. // Set our internal state
  252. if (dwError = SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER) lpBInfo)) {
  253. // Holy shit, couldn't change formats, time to punt!
  254. // Try to switch back to minimal format (120x160x8)
  255. errorDriverID (lpcs, dwError);
  256. SetDefaultCaptureFormat (&bih);
  257. dwError = SetFormatFromDIB (lpcs, &bih);
  258. }
  259. // Force a new frame to be taken, so the DIB contains good
  260. // data. Especially important to prevent codecs from exploding!
  261. if (!dwError)
  262. videoFrame (lpcs->hVideoIn, &lpcs->VidHdr);
  263. if (lpBInfo)
  264. GlobalFreePtr (lpBInfo);
  265. f = DrawDibBegin(lpcs->hdd,NULL,-1,-1,(LPBITMAPINFOHEADER)(lpcs->lpBitsInfo),-1,-1,0);
  266. if (!f) {
  267. errorUpdateError(lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
  268. }
  269. return (dwError);
  270. }
  271. //
  272. // Main entry point when changing capture formats via App message.
  273. // Returns: TRUE on success, or FALSE if format not supported
  274. //
  275. BOOL DibNewFormatFromApp (LPCAPSTREAM lpcs, LPBITMAPINFO lpbiNew, UINT dwSize)
  276. {
  277. BOOL f;
  278. DWORD dwError;
  279. LPBITMAPINFO lpBInfo;
  280. if (!lpcs->fHardwareConnected)
  281. return FALSE;
  282. lpBInfo = DibGetCurrentFormat (lpcs); // Allocs memory!!!
  283. if (lpBInfo == NULL)
  284. return FALSE;
  285. // Set our internal state
  286. if (dwError = SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER) lpbiNew)) {
  287. // Driver didn't accept the format,
  288. // switch back to the original
  289. errorDriverID (lpcs, dwError);
  290. SetFormatFromDIB (lpcs, (LPBITMAPINFOHEADER)lpBInfo);
  291. }
  292. // Force a new frame to be taken, so the DIB contains good
  293. // data. Especially important to prevent codecs from exploding!
  294. videoFrame (lpcs->hVideoIn, &lpcs->VidHdr);
  295. if (lpBInfo)
  296. GlobalFreePtr (lpBInfo);
  297. f = DrawDibBegin(lpcs->hdd,NULL,-1,-1,(LPBITMAPINFOHEADER)(lpcs->lpBitsInfo),-1,-1,0);
  298. if (!f) {
  299. errorUpdateError(lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
  300. //errorDriverID (lpcs, IDS_CAP_AVI_DRAWDIB_ERROR);
  301. }
  302. return (dwError == DV_ERR_OK);
  303. }
  304. void xlatClut8 (BYTE HUGE *pb, DWORD dwSize, BYTE HUGE *xlat)
  305. {
  306. DWORD dw;
  307. for (dw = 0; dw < dwSize; dw++, ((BYTE huge *)pb)++)
  308. *pb = xlat[*pb];
  309. }
  310. //
  311. // DibNewPalette
  312. //
  313. // Performs three functions:
  314. // 1. Updates the biClrUsed field if biBitCount <= 8.
  315. // 2. Remaps BI_RGB images through a LUT when a new palette is assigned.
  316. // 3. Copies the palette entries into our global BITMAPINFO
  317. //
  318. // Returns: TRUE on success
  319. //
  320. DWORD DibNewPalette (LPCAPSTREAM lpcs, HPALETTE hPalNew)
  321. {
  322. LPBITMAPINFOHEADER lpbi;
  323. int n;
  324. short nColors;
  325. BYTE FAR * lpBits;
  326. RGBQUAD FAR * lpRgb;
  327. BYTE xlat[256];
  328. DWORD dwSize;
  329. PALETTEENTRY pe;
  330. if (!hPalNew || !lpcs->lpBits || !lpcs->lpBitsInfo)
  331. return FALSE;
  332. lpbi = &(lpcs->lpBitsInfo->bmiHeader);
  333. lpRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (UINT)lpbi->biSize);
  334. lpBits = lpcs->lpBits;
  335. GetObject(hPalNew, sizeof(short), (LPSTR) &nColors);
  336. if (nColors > 256)
  337. nColors = 256;
  338. // Get the palette entries regardless of the compression
  339. // Supermac uses non BI_RGB with a palette!
  340. if (lpbi->biBitCount == 8) {
  341. for (n=0; n<nColors; n++) {
  342. GetPaletteEntries(hPalNew, n, 1, &pe);
  343. lpRgb[n].rgbRed = pe.peRed;
  344. lpRgb[n].rgbGreen = pe.peGreen;
  345. lpRgb[n].rgbBlue = pe.peBlue;
  346. }
  347. }
  348. if (lpbi->biBitCount == 8 && lpbi->biCompression == BI_RGB) {
  349. //
  350. // build a xlat table. from the old Palette to the new palette.
  351. //
  352. for (n=0; n<(int)lpbi->biClrUsed; n++) {
  353. xlat[n] = (BYTE)GetNearestPaletteIndex(hPalNew,
  354. RGB(lpRgb[n].rgbRed,lpRgb[n].rgbGreen,lpRgb[n].rgbBlue));
  355. }
  356. //
  357. // translate the DIB bits
  358. //
  359. if ((dwSize = lpbi->biSizeImage) == 0)
  360. dwSize = lpbi->biHeight * DIBWIDTHBYTES(*lpbi);
  361. switch ((WORD)lpbi->biCompression)
  362. {
  363. case BI_RGB:
  364. xlatClut8(lpBits, dwSize, xlat);
  365. }
  366. }
  367. // Fix for Supermac, force biClrUsed to the number of palette entries
  368. // even if non-BI_RGB formats.
  369. if (lpbi->biBitCount <= 8)
  370. lpbi->biClrUsed = nColors;
  371. return TRUE;
  372. }
  373. /* DibPaint(LPCAPSTREAM lpcs, hdc)
  374. *
  375. * Paint the current DIB into the window;
  376. */
  377. void DibPaint(LPCAPSTREAM lpcs, HDC hdc)
  378. {
  379. RECT rc;
  380. BOOL fOK;
  381. fOK = (lpcs->lpBits != NULL);
  382. if (fOK) {
  383. if (lpcs->fScale) {
  384. GetClientRect(lpcs->hwnd, &rc);
  385. fOK = DrawDibDraw(lpcs->hdd, hdc, 0, 0,
  386. rc.right - rc.left, rc.bottom - rc.top,
  387. (LPBITMAPINFOHEADER)lpcs->lpBitsInfo, lpcs->lpBits,
  388. 0, 0, -1, -1,
  389. #if defined _WIN32 && defined UNICODE
  390. 0 // we don't support BACKGROUNDPAL yet in drawdib
  391. #else
  392. DDF_BACKGROUNDPAL
  393. #endif
  394. );
  395. }
  396. else
  397. fOK = DrawDibDraw(lpcs->hdd, hdc, 0, 0,
  398. lpcs->dxBits, lpcs->dyBits,
  399. (LPBITMAPINFOHEADER)lpcs->lpBitsInfo, lpcs->lpBits,
  400. 0, 0, -1, -1,
  401. #if defined _WIN32 && defined UNICODE
  402. 0 // we don't support BACKGROUNDPAL yet in drawdib
  403. #else
  404. DDF_BACKGROUNDPAL
  405. #endif
  406. );
  407. }
  408. if (!fOK) {
  409. SelectObject(hdc, GetStockObject(BLACK_BRUSH));
  410. GetClientRect(lpcs->hwnd, &rc);
  411. PatBlt(hdc, 0, 0, rc.right, rc.bottom, PATCOPY);
  412. }
  413. }
  414. /*
  415. *
  416. * CreatePackedDib() - return the current DIB in packed (ie CF_DIB) format
  417. *
  418. */
  419. HANDLE CreatePackedDib (LPBITMAPINFO lpBitsInfo, LPSTR lpSrcBits, HPALETTE hPalette)
  420. {
  421. HANDLE hdib;
  422. LPBITMAPINFO lpbi;
  423. int i;
  424. DWORD dwSize;
  425. PALETTEENTRY pe;
  426. LPBYTE lpBits;
  427. RGBQUAD FAR * lpRgb;
  428. // If the data is compressed, let ICM do the work for us...
  429. if (lpBitsInfo->bmiHeader.biCompression != BI_RGB &&
  430. lpBitsInfo->bmiHeader.biCompression != BI_RLE8 &&
  431. (lpBitsInfo->bmiHeader.biBitCount != 8 ||
  432. lpBitsInfo->bmiHeader.biBitCount != 24 )) {
  433. LPBITMAPINFO lpOutFormat = NULL;
  434. HANDLE hPackedDIBOut = NULL;
  435. if (!(lpOutFormat = (LPBITMAPINFO)GlobalAllocPtr(
  436. GMEM_MOVEABLE, sizeof (BITMAPINFOHEADER) +
  437. 256 * sizeof (RGBQUAD))))
  438. return NULL;
  439. CopyMemory (lpOutFormat, lpBitsInfo, sizeof (BITMAPINFOHEADER));
  440. // Try to get an RGB format
  441. lpOutFormat->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
  442. lpOutFormat->bmiHeader.biCompression = BI_RGB;
  443. lpOutFormat->bmiHeader.biClrUsed = 0;
  444. lpOutFormat->bmiHeader.biClrImportant = 0;
  445. // Uh, oh, force to a 24-bit DIB if > 8 BPP
  446. if (lpBitsInfo->bmiHeader.biBitCount <= 8)
  447. lpOutFormat->bmiHeader.biBitCount = 8;
  448. else
  449. lpOutFormat->bmiHeader.biBitCount = 24;
  450. lpOutFormat->bmiHeader.biSizeImage =
  451. WIDTHBYTES (lpOutFormat->bmiHeader.biWidth *
  452. (lpOutFormat->bmiHeader.biBitCount == 8 ? 1 : 3)) *
  453. lpOutFormat->bmiHeader.biHeight;
  454. hPackedDIBOut = ICImageDecompress (
  455. NULL, /*hic*/
  456. 0, /*uiFlags*/
  457. lpBitsInfo, /*lpbiIn*/
  458. lpSrcBits, /*lpBits*/
  459. lpOutFormat); /*use default format chosen by compressor*/
  460. if (lpOutFormat)
  461. GlobalFreePtr (lpOutFormat);
  462. return (hPackedDIBOut);
  463. }
  464. dwSize = lpBitsInfo->bmiHeader.biSize +
  465. lpBitsInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD) +
  466. lpBitsInfo->bmiHeader.biSizeImage;
  467. hdib = GlobalAlloc(GMEM_MOVEABLE, dwSize);
  468. if (!hdib)
  469. return NULL;
  470. lpbi = (LPVOID)GlobalLock(hdib);
  471. //
  472. // copy the header
  473. //
  474. CopyMemory (lpbi, lpBitsInfo, lpBitsInfo->bmiHeader.biSize);
  475. //
  476. // copy the color table
  477. //
  478. lpRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->bmiHeader.biSize);
  479. for (i=0; i < (int)lpBitsInfo->bmiHeader.biClrUsed; i++) {
  480. GetPaletteEntries(hPalette, i, 1, &pe);
  481. lpRgb[i].rgbRed = pe.peRed;
  482. lpRgb[i].rgbGreen = pe.peGreen;
  483. lpRgb[i].rgbBlue = pe.peBlue;
  484. lpRgb[i].rgbReserved = 0;
  485. }
  486. //
  487. // copy the bits.
  488. //
  489. lpBits = (LPBYTE)lpbi +
  490. lpbi->bmiHeader.biSize +
  491. lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD);
  492. CopyMemory (lpBits, lpSrcBits,
  493. lpbi->bmiHeader.biSizeImage);
  494. GlobalUnlock (hdib);
  495. return hdib;
  496. }
  497. /*---------------------------------------------------------------------+
  498. | dibIsWritable() - return TRUE if the dib format is writable, |
  499. | by out dibWrite() function, FALSE if not. |
  500. | |
  501. +---------------------------------------------------------------------*/
  502. BOOL FAR PASCAL dibIsWritable (LPBITMAPINFO lpBitsInfo)
  503. {
  504. if (!lpBitsInfo)
  505. return FALSE;
  506. // For now, just assume that all capture formats have an installed
  507. // codec which can convert to RGB. In the future, each time the
  508. // format is changed, test that the codec actually accepts the format.
  509. return TRUE;
  510. }
  511. /*---------------------------------------------------------------------+
  512. | dibWrite() - write out the DIB to a file. The global header is |
  513. | in <glpBitsInfo> and the actual dib bits are in |
  514. | <glpBits>. If it is palettized then the palette is in |
  515. | <ghPalCurrent>. |
  516. | |
  517. | We won't do error reporting in this function, let the caller take |
  518. | care of that along with Opening and Closing the HMMIO. |
  519. | |
  520. +---------------------------------------------------------------------*/
  521. BOOL FAR PASCAL dibWrite(LPCAPSTREAM lpcs, HMMIO hmmio)
  522. {
  523. BITMAPFILEHEADER bfh;
  524. DWORD dw;
  525. HANDLE hPackedDib = NULL;
  526. LPBITMAPINFO lpbi = NULL;
  527. BOOL fOK = FALSE;
  528. /* do some checking */
  529. WinAssert(hmmio != 0);
  530. if (!lpcs->lpBits || !lpcs->lpBitsInfo)
  531. return FALSE;
  532. // Create a packed DIB, converting from a compressed format,
  533. // if necessary.
  534. hPackedDib = CreatePackedDib (lpcs->lpBitsInfo,
  535. lpcs->lpBits,
  536. lpcs->hPalCurrent);
  537. lpbi = (LPBITMAPINFO) GlobalLock (hPackedDib);
  538. if (!lpbi)
  539. goto WriteError;
  540. /* initialize the bitmap file header */
  541. bfh.bfType = 'B' | 'M' << 8;
  542. bfh.bfSize = sizeof(bfh) + sizeof(BITMAPINFOHEADER) +
  543. lpbi->bmiHeader.biSizeImage +
  544. (lpbi->bmiHeader.biBitCount > 8 ? 0 : (lpbi->bmiHeader.biClrUsed * sizeof(RGBQUAD)));
  545. bfh.bfReserved1 = bfh.bfReserved2 = 0;
  546. bfh.bfOffBits = bfh.bfSize - lpbi->bmiHeader.biSizeImage ;
  547. // dw is the size of the BITMAPINFO + color table + image
  548. dw = bfh.bfSize - sizeof(bfh);
  549. /* write out the file header portion */
  550. if (mmioWrite(hmmio, (HPSTR)&bfh, (LONG)sizeof(BITMAPFILEHEADER)) !=
  551. sizeof(BITMAPFILEHEADER)){
  552. goto WriteError;
  553. }
  554. /* now write out the header and bits */
  555. if (mmioWrite(hmmio, (HPSTR)lpbi, (LONG) dw) == (LONG) dw) {
  556. fOK = TRUE;
  557. }
  558. WriteError:
  559. if (lpbi)
  560. GlobalUnlock (hPackedDib);
  561. if (hPackedDib)
  562. GlobalFree (hPackedDib);
  563. return fOK;
  564. }
  565. /*--------------------------------------------------------------+
  566. | fileSaveDIB - save the frame as a DIB |
  567. | Top level routine to save a single frame |
  568. +--------------------------------------------------------------*/
  569. BOOL FAR PASCAL fileSaveDIB(LPCAPSTREAM lpcs, LPTSTR lpszFileName)
  570. {
  571. HMMIO hmmio;
  572. HCURSOR hOldCursor;
  573. BOOL fOK;
  574. hmmio = mmioOpen(lpszFileName, NULL, MMIO_WRITE);
  575. if( !hmmio ) {
  576. /* try and create */
  577. hmmio = mmioOpen(lpszFileName, NULL, MMIO_CREATE | MMIO_WRITE);
  578. if( !hmmio ) {
  579. /* find out if the file was read only or we are just */
  580. /* totally hosed up here. */
  581. hmmio = mmioOpen(lpszFileName, NULL, MMIO_READ);
  582. if (hmmio){
  583. /* file was read only, error on it */
  584. errorUpdateError (lpcs, IDS_CAP_READONLYFILE, (LPSTR)lpszFileName);
  585. mmioClose(hmmio, 0);
  586. return FALSE;
  587. } else {
  588. /* even weirder error has occured here, give CANTOPEN */
  589. errorUpdateError (lpcs, IDS_CAP_CANTOPEN, (LPSTR) lpszFileName);
  590. return FALSE;
  591. }
  592. }
  593. }
  594. hOldCursor = SetCursor( lpcs->hWaitCursor );
  595. mmioSeek(hmmio, 0, SEEK_SET);
  596. fOK = dibWrite(lpcs, hmmio);
  597. mmioClose( hmmio, 0 );
  598. SetCursor( hOldCursor );
  599. if (!fOK)
  600. errorUpdateError (lpcs, IDS_CAP_ERRORDIBSAVE, (LPSTR) lpszFileName);
  601. return fOK;
  602. }