Leaked source code of windows server 2003
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.

2040 lines
69 KiB

  1. //////////////////////////////////////////////////////////////////////////////o
  2. //
  3. // ICM.C
  4. //
  5. // Helper routines for compressing/decompressing/and choosing compressors.
  6. //
  7. // (C) Copyright Microsoft Corp. 1991, 1992, 1993. All rights reserved.
  8. //
  9. // You have a royalty-free right to use, modify, reproduce and
  10. // distribute the Sample Files (and/or any modified version) in
  11. // any way you find useful, provided that you agree that
  12. // Microsoft has no warranty obligations or liability for any
  13. // Sample Application Files.
  14. //
  15. // If you did not get this from Microsoft Sources, then it may not be the
  16. // most current version. This sample code in particular will be updated
  17. // and include more documentation.
  18. //
  19. // Sources are:
  20. // CompuServe: WINSDK forum, MDK section.
  21. // Anonymous FTP from ftp.uu.net vendor\microsoft\multimedia
  22. //
  23. ///////////////////////////////////////////////////////////////////////////////
  24. #include <windows.h>
  25. #include <windowsx.h>
  26. #include <win32.h>
  27. #include <mmsystem.h>
  28. #ifdef DEBUG
  29. static void CDECL dprintf(LPSTR, ...);
  30. #define DPF(x) dprintf x
  31. #else
  32. #define DPF(x)
  33. #endif
  34. //
  35. // define these before compman.h, so are functions get declared right.
  36. //
  37. #ifndef WIN32
  38. #define VFWAPI FAR PASCAL _loadds
  39. #define VFWAPIV FAR CDECL _loadds
  40. #endif
  41. #include <vfw.h>
  42. #include "icm.rc"
  43. #define AVIStreamGetFrameOpen XAVIStreamGetFrameOpen
  44. #define AVIStreamGetFrame XAVIStreamGetFrame
  45. #define AVIStreamGetFrameClose XAVIStreamGetFrameClose
  46. HMODULE havifile;
  47. PGETFRAME (STDAPICALLTYPE *XAVIStreamGetFrameOpen)(PAVISTREAM pavi,
  48. LPBITMAPINFOHEADER lpbiWanted);
  49. LPVOID (STDAPICALLTYPE *XAVIStreamGetFrame)(PGETFRAME pgf, LONG pos);
  50. HRESULT (STDAPICALLTYPE *XAVIStreamGetFrameClose)(PGETFRAME pgf);
  51. #ifdef WIN32
  52. extern HANDLE ghInst;
  53. #else
  54. extern HINSTANCE ghInst;
  55. #endif
  56. ///////////////////////////////////////////////////////////////////////////////
  57. // DIB Macros
  58. ///////////////////////////////////////////////////////////////////////////////
  59. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  60. #define DibWidthBytes(lpbi) (UINT)WIDTHBYTES((UINT)(lpbi)->biWidth * (UINT)((lpbi)->biBitCount))
  61. #define DibSizeImage(lpbi) ((DWORD)(UINT)DibWidthBytes(lpbi) * (DWORD)(UINT)((lpbi)->biHeight))
  62. #define DibSize(lpbi) ((lpbi)->biSize + (lpbi)->biSizeImage + (int)(lpbi)->biClrUsed * sizeof(RGBQUAD))
  63. #define DibPtr(lpbi) (LPVOID)(DibColors(lpbi) + (UINT)(lpbi)->biClrUsed)
  64. #define DibColors(lpbi) ((LPRGBQUAD)((LPBYTE)(lpbi) + (int)(lpbi)->biSize))
  65. #define DibNumColors(lpbi) ((lpbi)->biClrUsed == 0 && (lpbi)->biBitCount <= 8 \
  66. ? (int)(1 << (int)(lpbi)->biBitCount) \
  67. : (int)(lpbi)->biClrUsed)
  68. // !!! Someday write this so you don't have to call ICCompressorChoose if you
  69. // !!! know what you want. Choose would then call this.
  70. // InitCompress(pc, hic/fccHandler, lQuality, lKey, lpbiIn, lpbiOut)
  71. /*****************************************************************************
  72. * @doc EXTERNAL COMPVARS ICAPPS
  73. *
  74. * @types COMPVARS | This structure describes
  75. * compressor when using functions such as <f ICCompressorChoose>,
  76. * <f ICSeqCompressFrame>, or <f ICCompressorFree>.
  77. *
  78. * @field LONG | cbSize | Set this to the size of this structure in bytes.
  79. * This member must be set to validate the structure
  80. * before calling any function using this structure.
  81. *
  82. * @field DWORD | dwFlags | Specifies the flags for this structure:
  83. *
  84. * @flag ICMF_COMPVARS_VALID | Indicates this structure has valid data.
  85. * Set this flag if you fill out this structure manually before
  86. * calling any functions. Do not set this flag if you let
  87. * <f ICCompressorChoose> initialize this structure.
  88. *
  89. * @field HIC | hic | Specifies the handle of the compressor to use.
  90. * The <f ICCompressorChoose> function opens the chosen compressor and
  91. * returns the handle to the compressor in this
  92. * member. The compressor is closed by <t ICCompressorFree>.
  93. *
  94. * @field DWORD | fccType | Specifies the type of compressor being used.
  95. * Currently only ICTYPE_VIDEO is supported. This can be set to zero.
  96. *
  97. * @field DWORD | fccHandler | Specifies the four-character code
  98. * of the compressor. NULL indicates the data is not
  99. * to be recompressed and and 'DIB ' indicates the data is full framed
  100. * (uncompressed). You can use this member to specify which
  101. * compressor is selected by default when the dialog box is
  102. * displayed.
  103. *
  104. * @field LPBITMAPINFO | lpbiIn | Specifies the input format. Used internally.
  105. *
  106. * @field LPBITMAPINFO | lpbiOut | Specifies the output format. Ths member
  107. * is set by <f ICCompressorChoose>. The <f ICSeqCompressFrameStart>
  108. * function uses this member to determine the compressed output format.
  109. * If you do not want to use the default format, specify
  110. * the preferred one.
  111. *
  112. * @field LPVOID | lpBitsOut | Used internally for compression.
  113. *
  114. * @field LPVOID | lpBitsPrev | Used internally for temporal compression.
  115. *
  116. * @field LONG | lFrame | Used internally to count the number of frames
  117. * compressed in a sequence.
  118. *
  119. * @field LONG | lKey | Set by <f ICCompressorChoose> to indicate the key frame
  120. * rate selected in the dialog box. The also specifies the rate that
  121. * <f ICSeqCompressFrameStart> uses for making key frames.
  122. *
  123. * @field LONG | lDataRate | Set by <f ICCompressorChoose> to indicate the
  124. * data rate selected in the dialog box. The units are kilobytes per second.
  125. *
  126. * @field LONG | lQ | Set by <f ICCompressChoose> to indicate the quality
  127. * selected in the dialog box. This also specifies the quality
  128. * <f ICSeqCompressFrameStart> will use. ICQUALITY_DEFAULT specifies
  129. * default quality.
  130. *
  131. * @field LONG | lKeyCount | Used internally to count key frames.
  132. *
  133. * @field LPVOID | lpState | Set by <f ICCompressorChoose> to the state selected
  134. * in the configuration dialog box for the compressor. The system
  135. * uses this information to restore the state of the dialog box if
  136. * it is redisplayed. Used internally.
  137. *
  138. * @field LONG | cbState | Used internally for the size of the state information.
  139. *
  140. ***************************************************************************/
  141. /*******************************************************************
  142. * @doc EXTERNAL ICCompressorFree ICAPPS
  143. *
  144. * @api void | ICCompressorFree | This function frees the resources
  145. * in the <t COMPVARS> structure used by other IC functions.
  146. *
  147. * @parm PCOMPVARS | pc | Specifies a pointer to the <t COMPVARS>
  148. * structure containing the resources to be freed.
  149. *
  150. * @comm After using the <f ICCompressorChoose>, <f ICSeqCompressFrameStart>,
  151. * <f ICSeqCompressFrame>, and <f ICSeqCompressFrameEnd> functions, call
  152. * this function to release the resources in the <t COMPVARS> structure.
  153. *
  154. * @xref <f ICCompressChoose> <f ICSeqCompressFrameStart> <f ICSeqCompressFrame>
  155. * <f ICSeqCompressFrameEnd>
  156. *
  157. *******************************************************************/
  158. ///////////////////////////////////////////////////////////////////////////////
  159. //
  160. // ICCompressorFree
  161. //
  162. ///////////////////////////////////////////////////////////////////////////////
  163. void VFWAPI ICCompressorFree(PCOMPVARS pc)
  164. {
  165. /* We were passed an invalid COMPPARMS */
  166. if (pc == NULL || pc->cbSize != sizeof(COMPVARS))
  167. return;
  168. // This function frees every thing in the structure (excuse my
  169. // french).
  170. /* Close the compressor */
  171. if (pc->hic) {
  172. ICClose(pc->hic);
  173. pc->hic = NULL;
  174. }
  175. /* Free the output format */
  176. if (pc->lpbiOut) {
  177. GlobalFreePtr(pc->lpbiOut);
  178. pc->lpbiOut = NULL;
  179. }
  180. /* Free the buffer for compressed image */
  181. if (pc->lpBitsOut) {
  182. GlobalFreePtr(pc->lpBitsOut);
  183. pc->lpBitsOut = NULL;
  184. }
  185. /* Free the buffer for the decompressed previous frame */
  186. if (pc->lpBitsPrev) {
  187. GlobalFreePtr(pc->lpBitsPrev);
  188. pc->lpBitsPrev = NULL;
  189. }
  190. /* Free the compressor state buffer */
  191. if (pc->lpState) {
  192. GlobalFreePtr(pc->lpState);
  193. pc->lpState = NULL;
  194. }
  195. /* This structure is no longer VALID */
  196. pc->dwFlags = 0;
  197. }
  198. /*******************************************************************
  199. * @doc EXTERNAL ICSeqCompressFrameStart ICAPPS
  200. *
  201. * @api BOOL | ICSeqCompressFrameStart | This function initializes the system
  202. * prior to using <f ICSeqCompressFrame>.
  203. *
  204. * @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS> structure
  205. * initialized with information for compression.
  206. *
  207. * @parm LPBITMAPINFO | lpbiIn | Specifies the format of the data to be
  208. * compressed.
  209. *
  210. * @rdesc Returns TRUE if successful; otherwise it returns FALSE.
  211. *
  212. * @comm Prior to using this function, use <f ICCompressorChoose> to let the
  213. * user specify a compressor, or initialize a <t COMPVARS> structure
  214. * manually. Use <f ICSeqCompressFrameStart>, <f ICSeqCompressFrame>
  215. * and <f ICSeqCompressFrameEnd> to compress a sequence of
  216. * frames to a specified data rate and number of key frames.
  217. * When finished comressing data, use
  218. * <f ICCompressorFree> to release the resources
  219. * specified in the <t COMPVARS> structure.
  220. *
  221. * If you do not use <f ICCompressorChoose> you must
  222. * initialize the following members of the <t COMPVARS> structure:
  223. *
  224. * <e COMPVARS.cbSize> Set to the sizeof(COMPVARS) to validate the structure.
  225. *
  226. * <e COMPVARS.hic> Set to the handle of a compressor you have opened with
  227. * <f ICOpen>. You do not need to close it (<f ICCompressorFree>
  228. * will do this for you).
  229. *
  230. * <e COMPVARS.lpbiOut> Optionally set this to force the compressor
  231. * to compress to a specific format instead of the default.
  232. * This will be freed by <f ICCompressorFree>.
  233. *
  234. * <e COMPVARS.lKey> Set this to the key-frame frequency you want
  235. * or zero for none.
  236. *
  237. * <e COMPVARS.lQ> Set this to the quality level to use or ICQUALITY_DEFAULT.
  238. *
  239. * <e COMPVARS.dwFlags> Set ICMF_COMPVARS_VALID flag to indicate the structure is initialized.
  240. *
  241. * @xref <f ICCompressorChoose> <f ICSeqCompressFrame> <f ICSeqCompressFrameEnd>
  242. * <f ICCompressorFree>
  243. *
  244. *******************************************************************/
  245. ///////////////////////////////////////////////////////////////////////////////
  246. //
  247. // ICSeqCompressFrameStart
  248. //
  249. ///////////////////////////////////////////////////////////////////////////////
  250. BOOL VFWAPI ICSeqCompressFrameStart(PCOMPVARS pc, LPBITMAPINFO lpbiIn)
  251. {
  252. DWORD dwSize;
  253. ICINFO icinfo;
  254. if (pc == NULL || pc->cbSize != sizeof(COMPVARS))
  255. return FALSE;
  256. if (pc->hic == NULL || lpbiIn == NULL)
  257. return FALSE;
  258. //
  259. // make sure the found compressor can handle something
  260. // if not, force back to the default setting
  261. //
  262. if (ICCompressQuery(pc->hic, lpbiIn, pc->lpbiOut) != ICERR_OK) {
  263. // If the input format has changed since the output was selected,
  264. // force a reinitialization of the output format
  265. if (pc->lpbiOut) {
  266. GlobalFreePtr (pc->lpbiOut);
  267. pc->lpbiOut = NULL;
  268. }
  269. }
  270. //
  271. // fill in defaults: key frame every frame, and default quality
  272. //
  273. if (pc->lKey < 0)
  274. pc->lKey = 1;
  275. if (pc->lQ == ICQUALITY_DEFAULT)
  276. pc->lQ = ICGetDefaultQuality(pc->hic);
  277. //
  278. // If no output format is given, use a default
  279. //
  280. if (pc->lpbiOut == NULL) {
  281. dwSize = ICCompressGetFormatSize(pc->hic, lpbiIn);
  282. if (!(pc->lpbiOut = (LPBITMAPINFO)GlobalAllocPtr(GMEM_MOVEABLE,dwSize)))
  283. goto StartError;
  284. ICCompressGetFormat(pc->hic, lpbiIn, pc->lpbiOut);
  285. }
  286. pc->lpbiOut->bmiHeader.biSizeImage =
  287. ICCompressGetSize (pc->hic, lpbiIn, pc->lpbiOut);
  288. pc->lpbiOut->bmiHeader.biClrUsed = DibNumColors(&(pc->lpbiOut->bmiHeader));
  289. //
  290. // Set the input format and initialize the key frame count
  291. //
  292. pc->lpbiIn = lpbiIn;
  293. pc->lKeyCount = pc->lKey;
  294. pc->lFrame = 0; // first frame we'll be compressing is 0
  295. if (ICCompressQuery(pc->hic, lpbiIn, pc->lpbiOut) != ICERR_OK)
  296. goto StartError;
  297. //
  298. // Allocate a buffer for the compressed bits
  299. //
  300. dwSize = pc->lpbiOut->bmiHeader.biSizeImage;
  301. // !!! Hack for VidCap... make it big enough for two RIFF structs and
  302. // !!! pad records.
  303. //
  304. dwSize += 2048 + 16;
  305. if (!(pc->lpBitsOut = GlobalAllocPtr(GMEM_MOVEABLE, dwSize)))
  306. goto StartError;
  307. //
  308. // Allocate a buffer for the decompressed previous frame if it can do
  309. // key frames and we want key frames and it needs such a buffer.
  310. //
  311. ICGetInfo(pc->hic, &icinfo, sizeof(icinfo));
  312. if ((pc->lKey != 1) && (icinfo.dwFlags & VIDCF_TEMPORAL) &&
  313. !(icinfo.dwFlags & VIDCF_FASTTEMPORALC)) {
  314. dwSize = lpbiIn->bmiHeader.biSizeImage;
  315. if (!(pc->lpBitsPrev = GlobalAllocPtr(GMEM_MOVEABLE, dwSize)))
  316. goto StartError;
  317. }
  318. //
  319. // now get compman ready for the big job
  320. //
  321. if (ICCompressBegin(pc->hic, lpbiIn, pc->lpbiOut) != ICERR_OK)
  322. goto StartError;
  323. //
  324. // Get ready to decompress previous frames if we're doing key frames
  325. // If we can't decompress, we must do all key frames
  326. //
  327. if (pc->lpBitsPrev) {
  328. if (ICDecompressBegin(pc->hic, pc->lpbiOut, lpbiIn) != ICERR_OK) {
  329. pc->lKey = pc->lKeyCount = 1;
  330. GlobalFreePtr(pc->lpBitsPrev);
  331. pc->lpBitsPrev = NULL;
  332. }
  333. }
  334. return TRUE;
  335. StartError:
  336. // !!! Leave stuff allocated because ICCompressorFree() will clear things
  337. return FALSE;
  338. }
  339. /*******************************************************************
  340. * @doc EXTERNAL ICSeqCompressFrameEnd ICAPPS
  341. *
  342. * @api void | ICSeqCompressFrameEnd | This function terminates sequence
  343. * compression using <f ICSeqCompressFrame>.
  344. *
  345. * @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS> structure
  346. * used during sequence compression.
  347. *
  348. * @comm Use <f ICCompressorChoose> to let the
  349. * user specify a compressor to use, or initialize a <t COMPVARS> structure
  350. * manually. Use <f ICSeqCompressFrameStart>, <f ICSeqCompressFrame>
  351. * and <f ICSeqCompressFrameEnd> functions to compress a sequence of
  352. * frames to a specified data rate and number of key frames. When
  353. * finished with compression, use <f ICCompressorFree> to
  354. * release the resources specified by the <t COMPVARS> structure.
  355. *
  356. * @xref <f ICCompressorChoose> <f ICSeqCompressFrame> <f ICCompressorFree>
  357. * <f ICSeqCompressFrameStart>
  358. *
  359. *******************************************************************/
  360. ///////////////////////////////////////////////////////////////////////////////
  361. //
  362. // ICSeqCompressFrameEnd
  363. //
  364. ///////////////////////////////////////////////////////////////////////////////
  365. void VFWAPI ICSeqCompressFrameEnd(PCOMPVARS pc)
  366. {
  367. if (pc == NULL || pc->cbSize != sizeof(COMPVARS))
  368. return;
  369. // This function still leaves pc->hic and pc->lpbiOut alloced and open
  370. // since they were set by ICCompressorChoose
  371. // Seems we've already freed everything - don't call ICCompressEnd twice
  372. if (pc->lpBitsOut == NULL)
  373. return;
  374. /* Stop compressing */
  375. if (pc->hic) {
  376. ICCompressEnd(pc->hic);
  377. if (pc->lpBitsPrev)
  378. ICDecompressEnd(pc->hic);
  379. }
  380. /* Free the buffer for compressed image */
  381. if (pc->lpBitsOut) {
  382. GlobalFreePtr(pc->lpBitsOut);
  383. pc->lpBitsOut = NULL;
  384. }
  385. /* Free the buffer for the decompressed previous frame */
  386. if (pc->lpBitsPrev) {
  387. GlobalFreePtr(pc->lpBitsPrev);
  388. pc->lpBitsPrev = NULL;
  389. }
  390. }
  391. /*******************************************************************
  392. * @doc EXTERNAL ICSeqCompressFrame ICAPPS
  393. *
  394. * @api LPVOID | ICSeqCompressFrame | This function compresses a
  395. * frame in a sequence of frames. The data rate for the sequence
  396. * as well as the key-frame frequency can be specified. Use this function
  397. * once for each frame to be compressed.
  398. *
  399. * @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS> structure
  400. * initialized with information about the compression.
  401. *
  402. * @parm UINT | uiFlags | Specifies flags for this function. Set this
  403. * parameter to zero.
  404. *
  405. * @parm LPVOID | lpBits | Specifies a pointer the data bits to compress.
  406. * (The data bits excludes header or format information.)
  407. *
  408. * @parm BOOL FAR * | pfKey | Returns whether or not the frame was compressed
  409. * into a keyframe.
  410. *
  411. * @parm LONG FAR * | plSize | Specifies the maximum size desired for
  412. * the compressed image. The compressor might not be able to
  413. * compress the data to within this size. When the function
  414. * returns, the parameter points to the size of the compressed
  415. * image. Images sizes are specified in bytes.
  416. *
  417. * @rdesc Returns a pointer to the compressed bits.
  418. *
  419. * @comm Use <f ICCompressorChoose> to let the
  420. * user specify a compressor to use, or initialize a <t COMPVARS> structure
  421. * manually. Use <f ICSeqCompressFrameStart>, <f ICSeqCompressFrame>
  422. * and <f ICSeqCompressFrameEnd> functions to compress a sequence of
  423. * frames to a specified data rate and number of key frames. When
  424. * finished with compression, use <f ICCompressorFree> to
  425. * release the resources specified by the <t COMPVARS> structure.
  426. *
  427. * Use this function repeatedly to compress a video sequence one
  428. * frame at a time. Use this function instead of <f ICCompress>
  429. * to compress a video sequence. This function supports creating key frames
  430. * in the compressed sequence at any frequency you like and handles
  431. * much of the initialization process.
  432. * @xref <f ICCompressorChoose> <f ICSeqCompressFrameEnd> <f ICCompressorFree>
  433. * <f ICCompressorFreeStart>
  434. *
  435. *******************************************************************/
  436. ///////////////////////////////////////////////////////////////////////////////
  437. //
  438. // ICSeqCompressFrame
  439. //
  440. // compresses a given image but supports KEY FRAMES EVERY
  441. //
  442. // input:
  443. // pc stuff
  444. // uiFlags flags (not used, must be 0)
  445. // lpBits input DIB bits
  446. // lQuality the reqested compression quality
  447. // pfKey did this frame end up being a key frame?
  448. //
  449. // returns:
  450. // a HANDLE to the converted image. The handle is a DIB in CF_DIB
  451. // format, ie a packed DIB. The caller is responsible for freeing
  452. // the memory. NULL is returned if error.
  453. //
  454. ///////////////////////////////////////////////////////////////////////////////
  455. LPVOID VFWAPI ICSeqCompressFrame(
  456. PCOMPVARS pc, // junk set up by Start()
  457. UINT uiFlags, // flags
  458. LPVOID lpBits, // input DIB bits
  459. BOOL FAR *pfKey, // did it end up being a key frame?
  460. LONG FAR *plSize) // requested size/size of returned image
  461. {
  462. LONG l;
  463. DWORD dwFlags = 0;
  464. DWORD ckid = 0;
  465. BOOL fKey;
  466. LONG lSize = plSize ? *plSize : 0;
  467. // Is it time to make a keyframe?
  468. // First frame will always be a keyframe cuz they initialize to the same
  469. // value.
  470. fKey = (pc->lKeyCount >= pc->lKey);
  471. l = ICCompress(pc->hic,
  472. fKey ? ICCOMPRESS_KEYFRAME : 0, // flags
  473. (LPBITMAPINFOHEADER)pc->lpbiOut, // output format
  474. pc->lpBitsOut, // output data
  475. (LPBITMAPINFOHEADER)pc->lpbiIn, // format of frame to compress
  476. lpBits, // frame data to compress
  477. &ckid, // ckid for data in AVI file
  478. &dwFlags, // flags in the AVI index.
  479. pc->lFrame, // frame number of seq.
  480. lSize, // reqested size in bytes. (if non zero)
  481. pc->lQ, // quality
  482. fKey ? NULL : (LPBITMAPINFOHEADER)pc->lpbiIn, // fmt of prev frame
  483. fKey ? NULL : pc->lpBitsPrev); // previous frame
  484. if (l < ICERR_OK)
  485. goto FrameError;
  486. /* Return the size of the compressed data */
  487. if (plSize)
  488. *plSize = pc->lpbiOut->bmiHeader.biSizeImage;
  489. /* Now decompress the frame into our buffer for the previous frame */
  490. if (pc->lpBitsPrev) {
  491. l = ICDecompress(pc->hic,
  492. 0,
  493. (LPBITMAPINFOHEADER)pc->lpbiOut,
  494. pc->lpBitsOut,
  495. (LPBITMAPINFOHEADER)pc->lpbiIn, // !!! should check for this.
  496. pc->lpBitsPrev);
  497. if (l != ICERR_OK)
  498. goto FrameError;
  499. }
  500. /* Was the compressed image a keyframe? */
  501. *pfKey = (BOOL)(dwFlags & AVIIF_KEYFRAME);
  502. /* After making a keyframe, reset our counter that tells us when we MUST */
  503. /* make another one. */
  504. if (*pfKey)
  505. pc->lKeyCount = 0;
  506. // Never make a keyframe again after the first one if we don't want them.
  507. // Increment our counter of how long its been since the last one if we do.
  508. if (pc->lKey)
  509. pc->lKeyCount++;
  510. else
  511. pc->lKeyCount = -1;
  512. // Next time we're called we're on the next frame
  513. pc->lFrame++;
  514. return (pc->lpBitsOut);
  515. FrameError:
  516. return NULL;
  517. }
  518. /*******************************************************************
  519. * @doc EXTERNAL ICImageCompress ICAPPS
  520. *
  521. * @api HANDLE | ICImageCompress | This function provides
  522. * convenient method of compressing an image to a given
  523. * size. This function does not require use of initialization functions.
  524. *
  525. * @parm HIC | hic | Specifies the handle to a compressor to be
  526. * opened with <f ICOpen> or NULL. Use NULL to choose a
  527. * default compressor for your compression format.
  528. * Applications can use the compressor handle returned
  529. * by <f ICCompressorChoose> in the <e COMPVARS.hic> member
  530. * of the <t COMPVARS> structure if they want the user to
  531. * select the compressor. This compressor is already opened.
  532. *
  533. * @parm UINT | uiFlags | Specifies flags for this function. Set this
  534. * to zero.
  535. *
  536. * @parm LPBITMAPINFO | lpbiIn | Specifies the input data format.
  537. *
  538. * @parm LPVOID | lpBits | Specifies a pointer to input data bits to compress.
  539. * (The data bits exclude header or format information.)
  540. *
  541. * @parm LPBITMAPINFO | lpbiOut | Specifies the compressed output format or NULL.
  542. * If NULL, the compressor uses a default format.
  543. *
  544. * @parm LONG | lQuality | Specifies the quality value the compressor.
  545. *
  546. * @parm LONG FAR * | plSize | Specifies the maximum size desired for
  547. * the compressed image. The compressor might not be able to
  548. * compress the data to within this size. When the function
  549. * returns, the parameter points to the size of the compressed
  550. * image. Images sizes are specified in bytes.
  551. *
  552. *
  553. * @rdesc Returns a handle to a compressed DIB. The image data follows the
  554. * format header.
  555. *
  556. * @comm This function returns a DIB with the format and image data.
  557. * To obtain the format information from the <t LPBITMAPINFOHEADER> structure,
  558. * use <f GlobalLock> to lock the data. Use <f GlobalFree> to free the
  559. * DIB when you have finished with it.
  560. *
  561. * @xref <f ICImageDecompress>
  562. *
  563. *******************************************************************/
  564. ///////////////////////////////////////////////////////////////////////////////
  565. //
  566. // ICImageCompress
  567. //
  568. // compresses a given image.
  569. //
  570. // input:
  571. // hic compressor to use, if NULL is specifed a
  572. // compressor will be located that can handle the conversion.
  573. // uiFlags flags (not used, must be 0)
  574. // lpbiIn input DIB format
  575. // lpBits input DIB bits
  576. // lpbiOut output format, if NULL is specifed the default
  577. // format choosen be the compressor will be used.
  578. // lQuality the reqested compression quality
  579. // plSize the reqested size for the image/returned size
  580. //
  581. // returns:
  582. // a handle to a DIB which is the compressed image.
  583. //
  584. ///////////////////////////////////////////////////////////////////////////////
  585. HANDLE VFWAPI ICImageCompress(
  586. HIC hic, // compressor (NULL if any will do)
  587. UINT uiFlags, // flags
  588. LPBITMAPINFO lpbiIn, // input DIB format
  589. LPVOID lpBits, // input DIB bits
  590. LPBITMAPINFO lpbiOut, // output format (NULL => default)
  591. LONG lQuality, // the reqested quality
  592. LONG FAR * plSize) // requested size for compressed frame
  593. {
  594. LONG l;
  595. BOOL fNuke;
  596. DWORD dwFlags = 0;
  597. DWORD ckid = 0;
  598. LONG lSize = plSize ? *plSize : 0;
  599. LPBITMAPINFOHEADER lpbi=NULL;
  600. //
  601. // either locate a compressor or use the one supplied.
  602. //
  603. if (fNuke = (hic == NULL))
  604. {
  605. hic = ICLocate(ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER)lpbiIn,
  606. (LPBITMAPINFOHEADER)lpbiOut, ICMODE_COMPRESS);
  607. if (hic == NULL)
  608. return NULL;
  609. }
  610. //
  611. // make sure the found compressor can compress something ??? WHY BOTHER ???
  612. //
  613. if (ICCompressQuery(hic, lpbiIn, NULL) != ICERR_OK)
  614. goto error;
  615. if (lpbiOut)
  616. {
  617. l = lpbiOut->bmiHeader.biSize + 256 * sizeof(RGBQUAD);
  618. }
  619. else
  620. {
  621. //
  622. // now make a DIB header big enough to hold the output format
  623. //
  624. l = ICCompressGetFormatSize(hic, lpbiIn);
  625. if (l <= 0)
  626. goto error;
  627. }
  628. lpbi = (LPVOID)GlobalAllocPtr(GHND, l);
  629. if (lpbi == NULL)
  630. goto error;
  631. //
  632. // if the compressor likes the passed format, use it else use the default
  633. // format of the compressor.
  634. //
  635. if (lpbiOut == NULL || ICCompressQuery(hic, lpbiIn, lpbiOut) != ICERR_OK)
  636. ICCompressGetFormat(hic, lpbiIn, lpbi);
  637. else
  638. hmemcpy(lpbi, lpbiOut, lpbiOut->bmiHeader.biSize +
  639. lpbiOut->bmiHeader.biClrUsed * sizeof(RGBQUAD));
  640. lpbi->biSizeImage = ICCompressGetSize(hic, lpbiIn, lpbi);
  641. lpbi->biClrUsed = DibNumColors(lpbi);
  642. //
  643. // now resize the DIB to be the maximal size.
  644. //
  645. lpbi = (LPVOID)GlobalReAllocPtr(lpbi,DibSize(lpbi), 0);
  646. if (lpbi == NULL)
  647. goto error;
  648. //
  649. // now compress it.
  650. //
  651. if (ICCompressBegin(hic, lpbiIn, lpbi) != ICERR_OK)
  652. goto error;
  653. if (lpBits == NULL)
  654. lpBits = DibPtr((LPBITMAPINFOHEADER)lpbiIn);
  655. if (lQuality == ICQUALITY_DEFAULT)
  656. lQuality = ICGetDefaultQuality(hic);
  657. l = ICCompress(hic,
  658. 0, // flags
  659. (LPBITMAPINFOHEADER)lpbi, // output format
  660. DibPtr(lpbi), // output data
  661. (LPBITMAPINFOHEADER)lpbiIn,// format of frame to compress
  662. lpBits, // frame data to compress
  663. &ckid, // ckid for data in AVI file
  664. &dwFlags, // flags in the AVI index.
  665. 0, // frame number of seq.
  666. lSize, // requested size in bytes. (if non zero)
  667. lQuality, // quality
  668. NULL, // format of previous frame
  669. NULL); // previous frame
  670. if (l < ICERR_OK) {
  671. DPF(("ICCompress returned %ld!\n", l));
  672. ICCompressEnd(hic);
  673. goto error;
  674. }
  675. // Return the size of the compressed data
  676. if (plSize)
  677. *plSize = lpbi->biSizeImage;
  678. if (ICCompressEnd(hic) != ICERR_OK)
  679. goto error;
  680. //
  681. // now resize the DIB to be the real size.
  682. //
  683. lpbi = (LPVOID)GlobalReAllocPtr(lpbi, DibSize(lpbi), 0);
  684. //
  685. // all done return the result to the caller
  686. //
  687. if (fNuke)
  688. ICClose(hic);
  689. return GlobalPtrHandle(lpbi);
  690. error:
  691. if (lpbi)
  692. GlobalFreePtr(lpbi);
  693. if (fNuke)
  694. ICClose(hic);
  695. return NULL;
  696. }
  697. /*******************************************************************
  698. *
  699. * @doc EXTERNAL ICImageDecompress ICAPPS
  700. *
  701. * @api HANDLE | ICImageDecompress | This function provides
  702. * convenient method of decompressing an image without
  703. * using initialization functions.
  704. **
  705. * @parm HIC | hic | Specifies the handle to a decompressor opened
  706. * with <f ICOpen> or NULL. Use NULL to choose a default
  707. * decompressor for your format.
  708. *
  709. * @parm UINT | uiFlags | Specifies flags for this function. Set this
  710. * to zero.
  711. *
  712. * @parm LPBITMAPINFO | lpbiIn | Specifies the compressed input data format.
  713. *
  714. * @parm LPVOID | lpBits | Specifies a pointer to input data bits to compress.
  715. * (The data bits excludes header or format information.)
  716. *
  717. * @parm LPBITMAPINFO | lpbiOut | Specifies the decompressed output format or NULL.
  718. * If NULL, the decompressor uses a default format.
  719. *
  720. * @rdesc Returns a handle to an uncompressed DIB in the CF_DIB format,
  721. * or NULL for an error. The image data follows the format header.
  722. *
  723. * @comm This function returns a DIB with the format and image data.
  724. * To obtain the format information from the <t LPBITMAPINFOHEADER> structure,
  725. * use <f GlobalLock> to lock the data. Use <f GlobalFree> to free the
  726. * DIB when you have finished with it.
  727. *
  728. * @xref <f ICImageCompress>
  729. *
  730. *******************************************************************/
  731. ///////////////////////////////////////////////////////////////////////////////
  732. //
  733. // ICImageDecompress
  734. //
  735. // decompresses a given image.
  736. //
  737. // input:
  738. // hic compressor to use, if NULL is specifed a
  739. // compressor will be located that can handle the conversion.
  740. // uiFlags flags (not used, must be 0)
  741. // lpbiIn input DIB format
  742. // lpBits input DIB bits
  743. // lpbiOut output format, if NULL is specifed the default
  744. // format choosen be the compressor will be used.
  745. //
  746. // returns:
  747. // a HANDLE to the converted image. The handle is a DIB in CF_DIB
  748. // format, ie a packed DIB. The caller is responsible for freeing
  749. // the memory. NULL is returned if error.
  750. //
  751. ///////////////////////////////////////////////////////////////////////////////
  752. HANDLE VFWAPI ICImageDecompress(
  753. HIC hic, // compressor (NULL if any will do)
  754. UINT uiFlags, // flags
  755. LPBITMAPINFO lpbiIn, // input DIB format
  756. LPVOID lpBits, // input DIB bits
  757. LPBITMAPINFO lpbiOut) // output format (NULL => default)
  758. {
  759. LONG l;
  760. BOOL fNuke;
  761. DWORD dwFlags = 0;
  762. DWORD ckid = 0;
  763. LPBITMAPINFOHEADER lpbi=NULL;
  764. //
  765. // either locate a compressor or use the one supplied.
  766. //
  767. if (fNuke = (hic == NULL))
  768. {
  769. hic = ICLocate(ICTYPE_VIDEO, 0L, (LPBITMAPINFOHEADER)lpbiIn,
  770. (LPBITMAPINFOHEADER)lpbiOut, ICMODE_DECOMPRESS);
  771. if (hic == NULL)
  772. return NULL;
  773. }
  774. //
  775. // make sure the found compressor can decompress at all ??? WHY BOTHER ???
  776. //
  777. if (ICDecompressQuery(hic, lpbiIn, NULL) != ICERR_OK)
  778. goto error;
  779. if (lpbiOut)
  780. {
  781. l = lpbiOut->bmiHeader.biSize + 256 * sizeof(RGBQUAD);
  782. }
  783. else
  784. {
  785. //
  786. // now make a DIB header big enough to hold the output format
  787. //
  788. l = ICDecompressGetFormatSize(hic, lpbiIn);
  789. if (l <= 0)
  790. goto error;
  791. }
  792. lpbi = (LPVOID)GlobalAllocPtr(GHND, l);
  793. if (lpbi == NULL)
  794. goto error;
  795. //
  796. // if we didn't provide an output format, use a default.
  797. //
  798. if (lpbiOut == NULL)
  799. ICDecompressGetFormat(hic, lpbiIn, lpbi);
  800. else
  801. hmemcpy(lpbi, lpbiOut, lpbiOut->bmiHeader.biSize +
  802. lpbiOut->bmiHeader.biClrUsed * sizeof(RGBQUAD));
  803. //
  804. // For decompress make sure the palette (ie color table) is correct
  805. // just in case they provided an output format and the decompressor used
  806. // that format but not their palette.
  807. //
  808. if (lpbi->biBitCount <= 8)
  809. ICDecompressGetPalette(hic, lpbiIn, lpbi);
  810. lpbi->biSizeImage = DibSizeImage(lpbi); // ICDecompressGetSize(hic, lpbi);
  811. lpbi->biClrUsed = DibNumColors(lpbi);
  812. //
  813. // now resize the DIB to be the right size.
  814. //
  815. lpbi = (LPVOID)GlobalReAllocPtr(lpbi,DibSize(lpbi),0);
  816. if (lpbi == NULL)
  817. goto error;
  818. //
  819. // now decompress it.
  820. //
  821. if (ICDecompressBegin(hic, lpbiIn, lpbi) != ICERR_OK)
  822. goto error;
  823. if (lpBits == NULL)
  824. lpBits = DibPtr((LPBITMAPINFOHEADER)lpbiIn);
  825. l = ICDecompress(hic,
  826. 0, // flags
  827. (LPBITMAPINFOHEADER)lpbiIn, // format of frame to decompress
  828. lpBits, // frame data to decompress
  829. (LPBITMAPINFOHEADER)lpbi, // output format
  830. DibPtr(lpbi)); // output data
  831. if (l < ICERR_OK) {
  832. ICDecompressEnd(hic);
  833. goto error;
  834. }
  835. if (ICDecompressEnd(hic) != ICERR_OK)
  836. goto error;
  837. //
  838. // now resize the DIB to be the real size.
  839. //
  840. lpbi = (LPVOID)GlobalReAllocPtr(lpbi,DibSize(lpbi),0);
  841. //
  842. // all done return the result to the caller
  843. //
  844. if (fNuke)
  845. ICClose(hic);
  846. return GlobalPtrHandle(lpbi);
  847. error:
  848. if (lpbi)
  849. GlobalFreePtr(lpbi);
  850. if (fNuke)
  851. ICClose(hic);
  852. return NULL;
  853. }
  854. ///////////////////////////////////////////////////////////////////////////////
  855. //
  856. // ICCompressorChooseStuff
  857. //
  858. ///////////////////////////////////////////////////////////////////////////////
  859. BOOL VFWAPI ICCompressorChooseDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  860. typedef struct {
  861. DWORD fccType;
  862. DWORD fccHandler;
  863. UINT uiFlags;
  864. LPVOID pvIn;
  865. LPVOID lpData;
  866. HWND hwnd;
  867. HIC hic;
  868. LONG lQ;
  869. LONG lKey;
  870. LONG lDataRate;
  871. ICINFO icinfo;
  872. LPSTR lpszTitle;
  873. PAVISTREAM pavi;
  874. AVISTREAMINFO info;
  875. HDRAWDIB hdd;
  876. PGETFRAME pgf;
  877. LPVOID lpState;
  878. LONG cbState;
  879. BOOL fClosing;
  880. } ICCompressorChooseStuff, FAR *PICCompressorChooseStuff;
  881. /*******************************************************************
  882. * @doc EXTERNAL ICCompressorChoose ICAPPS
  883. *
  884. * @api BOOL | ICCompressorChoose | Displays a dialog box for choosing a
  885. * compressor. It optionally provides a data rate box, key frame box, preview
  886. * window, and filtering to display only compressors that can handle a
  887. * specific format.
  888. *
  889. * @parm HWND | hwnd | Specifies the parent window for the dialog box.
  890. *
  891. * @parm UINT | uiFlags | Specifies flags for this function. The following
  892. * flags are defined:
  893. *
  894. * @flag ICMF_CHOOSE_KEYFRAME | Displays a check box and edit box to enter the
  895. * frequency of key frames.
  896. *
  897. * @flag ICMF_CHOOSE_DATARATE | Displays a check box and edit box to enter the
  898. * data rate for the movie.
  899. *
  900. * @flag ICMF_CHOOSE_PREVIEW | Displays a button to expand the dialog box to
  901. * include a preview window. The preview window shows how
  902. * frames of your movie will appear when compressed with the
  903. * current settings.
  904. *
  905. * @flag ICMF_CHOOSE_ALLCOMPRESSORS | Indicates all compressors should
  906. * should appear in the selection list. If this flag is not specified,
  907. * just the compressors that can handle the input format appear in
  908. * the selection list.
  909. *
  910. * @parm LPVOID | pvIn | Specifies the uncompressed
  911. * data input format. This parameter is optional.
  912. *
  913. * @parm LPVOID | lpData | Specifies a <t PAVISTREAM> of type
  914. * streamtypeVIDEO to use in the preview window. This parameter
  915. * is optional.
  916. *
  917. * @parm PCOMPVARS | pc | Specifies a pointer to a <t COMPVARS>
  918. * structure. The information returned initializes the
  919. * structure for use with other functions.
  920. *
  921. * @parm LPSTR | lpszTitle | Points to a optional zero-terminated string
  922. * containing a title for the dialog box.
  923. *
  924. * @rdesc Returns TRUE if the user chooses a compressor, and presses OK. Returns
  925. * FALSE for an error, or if the user presses CANCEL.
  926. *
  927. * @comm This function lets the user select a compressor from a list.
  928. * Before using it, set the <e COMPVARS.cbSize> member of the <t COMPVARS>
  929. * structure to sizeof(COMPVARS). Initialize the rest of the structure
  930. * to zeros unless you want to specify some valid defaults for
  931. * the dialog box. If specifing defaults, set the <e COMPVARS.dwFlags>
  932. * member to ICMF_COMPVARS_VALID, and initialize the other members of
  933. * the structure. See <f ICSeqCompressorFrameStart> and <t COMPVARS>
  934. * for more information about initializing the structure.
  935. *
  936. * @xref <f ICCompressorFree> <f ICSeqCompressFrameStart> <f ICSeqCompressFrame>
  937. * <f ICSeqCompressFrameEnd>
  938. *
  939. *******************************************************************/
  940. ///////////////////////////////////////////////////////////////////////////////
  941. //
  942. // ICCompressorChoose
  943. //
  944. // Brings up a dialog and allows the user to choose a compression
  945. // method and a quality level, and/or a key frame frequency.
  946. // All compressors in the system are displayed or can be optionally
  947. // filtered by "ability to compress" a specifed format.
  948. //
  949. // the dialog allows the user to configure or bring up the compressors
  950. // about box.
  951. //
  952. // A preview window can be provided to show a preview of a specific
  953. // compression.
  954. //
  955. // the selected compressor is opened (via ICOpen) and returned to the
  956. // caller, it must be disposed of by calling ICCompressorFree.
  957. //
  958. // input:
  959. // HWND hwnd parent window for dialog box.
  960. // UINT uiFlags flags
  961. // LPVOID pvIn input format (optional), only compressors that
  962. // handle this format will be displayed.
  963. // LPVOID pavi input stream for the options preview
  964. // PCOMPVARS pcj returns COMPVARS struct for use with other APIs
  965. // LPSTR lpszTitle Optional title for dialog box
  966. //
  967. // returns:
  968. // TRUE if dialog shown and user chose a compressor.
  969. // FALSE if dialog was not shown or user hit cancel.
  970. //
  971. ///////////////////////////////////////////////////////////////////////////////
  972. BOOL VFWAPI ICCompressorChoose(
  973. HWND hwnd, // parent window for dialog
  974. UINT uiFlags, // flags
  975. LPVOID pvIn, // input format (optional)
  976. LPVOID pavi, // input stream (for preview - optional)
  977. PCOMPVARS pcj, // state of compressor/dlg
  978. LPSTR lpszTitle) // dialog title (if NULL, use default)
  979. {
  980. BOOL f;
  981. PICCompressorChooseStuff p;
  982. DWORD dwSize;
  983. if (pcj == NULL || pcj->cbSize != sizeof(COMPVARS))
  984. return FALSE;
  985. //
  986. // !!! Initialize the structure
  987. //
  988. if (!(pcj->dwFlags & ICMF_COMPVARS_VALID)) {
  989. pcj->hic = NULL;
  990. pcj->fccType = 0;
  991. pcj->fccHandler = 0;
  992. pcj->lQ = ICQUALITY_DEFAULT;
  993. pcj->lKey = 1;
  994. pcj->lDataRate = 0;
  995. pcj->lpbiOut = NULL;
  996. pcj->lpBitsOut = NULL;
  997. pcj->lpBitsPrev = NULL;
  998. pcj->dwFlags = 0;
  999. pcj->lpState = NULL;
  1000. pcj->cbState = 0;
  1001. }
  1002. // Default type is a video compressor
  1003. if (pcj->fccType == 0)
  1004. pcj->fccType = ICTYPE_VIDEO;
  1005. p = (LPVOID)GlobalAllocPtr(GHND, sizeof(ICCompressorChooseStuff));
  1006. if (p == NULL)
  1007. return FALSE;
  1008. p->fccType = pcj->fccType;
  1009. p->fccHandler = pcj->fccHandler;
  1010. p->uiFlags = uiFlags;
  1011. p->pvIn = pvIn;
  1012. p->lQ = pcj->lQ;
  1013. p->lKey = pcj->lKey;
  1014. p->lDataRate = pcj->lDataRate;
  1015. p->lpszTitle = lpszTitle;
  1016. p->pavi = (PAVISTREAM)pavi;
  1017. p->hdd = NULL;
  1018. p->lpState = pcj->lpState;
  1019. pcj->lpState = NULL; // so it won't be freed
  1020. p->cbState = pcj->cbState;
  1021. // !!! Validate this pointer
  1022. // !!! AddRef if it is
  1023. if (p->pavi) {
  1024. if (p->pavi->lpVtbl->Info(p->pavi, &p->info, sizeof(p->info)) !=
  1025. AVIERR_OK || p->info.fccType != streamtypeVIDEO)
  1026. p->pavi = NULL;
  1027. }
  1028. f = DialogBoxParam(ghInst, TEXT("ICCDLG"),
  1029. hwnd, ICCompressorChooseDlgProc, (LPARAM)(LPVOID)p);
  1030. // !!! Treat error like cancel
  1031. if (f == -1)
  1032. f = FALSE;
  1033. //
  1034. // if the user picked a compressor then return this info to the caller
  1035. //
  1036. if (f) {
  1037. // If we are called twice in a row, we have good junk in here that
  1038. // needs to be freed before we tromp over it.
  1039. ICCompressorFree(pcj);
  1040. pcj->lQ = p->lQ;
  1041. pcj->lKey = p->lKey;
  1042. pcj->lDataRate = p->lDataRate;
  1043. pcj->hic = p->hic;
  1044. pcj->fccHandler = p->fccHandler;
  1045. pcj->lpState = p->lpState;
  1046. pcj->cbState = p->cbState;
  1047. pcj->dwFlags |= ICMF_COMPVARS_VALID;
  1048. }
  1049. GlobalFreePtr(p);
  1050. if (!f)
  1051. return FALSE;
  1052. if (pcj->hic && pvIn) { // hic is NULL if no compression selected
  1053. /* Get the format we're going to compress into. */
  1054. dwSize = ICCompressGetFormatSize(pcj->hic, pvIn);
  1055. if ((pcj->lpbiOut =
  1056. (LPBITMAPINFO)GlobalAllocPtr(GMEM_MOVEABLE, dwSize)) == NULL) {
  1057. ICClose(pcj->hic); // Close this since we're erroring
  1058. pcj->hic = NULL;
  1059. return FALSE;
  1060. }
  1061. ICCompressGetFormat(pcj->hic, pvIn, pcj->lpbiOut);
  1062. }
  1063. return TRUE;
  1064. }
  1065. void SizeDialog(HWND hwnd, WORD id) {
  1066. RECT rc;
  1067. GetWindowRect(GetDlgItem(hwnd, id), &rc);
  1068. /* First, get rc in Client co-ords */
  1069. ScreenToClient(hwnd, (LPPOINT)&rc + 1);
  1070. rc.top = 0; rc.left = 0;
  1071. /* Grow by non-client size */
  1072. AdjustWindowRect(&rc, GetWindowLong(hwnd, GWL_STYLE),
  1073. GetMenu(hwnd) !=NULL);
  1074. /* That's the new size for the dialog */
  1075. SetWindowPos(hwnd, NULL, 0, 0, rc.right-rc.left,
  1076. rc.bottom-rc.top,
  1077. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1078. }
  1079. void TermPreview(PICCompressorChooseStuff p)
  1080. {
  1081. if (p->hdd)
  1082. DrawDibClose(p->hdd);
  1083. p->hdd = NULL;
  1084. }
  1085. BOOL InitPreview(HWND hwnd, PICCompressorChooseStuff p) {
  1086. p->hdd = DrawDibOpen();
  1087. if (!p->hdd)
  1088. return FALSE;
  1089. }
  1090. #ifdef SAFETOYIELD
  1091. //
  1092. // Code to yield while we're not calling GetMessage.
  1093. // Dispatch all messages. Pressing ESC or closing aborts.
  1094. //
  1095. BOOL WinYield(HWND hwnd)
  1096. {
  1097. MSG msg;
  1098. BOOL fAbort=FALSE;
  1099. while(/* fWait > 0 && */ !fAbort && PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  1100. {
  1101. if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
  1102. fAbort = TRUE;
  1103. if (msg.message == WM_SYSCOMMAND && (msg.wParam & 0xFFF0) == SC_CLOSE)
  1104. fAbort = TRUE;
  1105. if (msg.hwnd == hwnd) {
  1106. if (msg.message == WM_KEYDOWN ||
  1107. msg.message == WM_SYSKEYDOWN ||
  1108. msg.message == WM_HSCROLL ||
  1109. msg.message == WM_PARENTNOTIFY ||
  1110. msg.message == WM_LBUTTONDOWN) {
  1111. PostMessage(hwnd, msg.message, msg.wParam, msg.lParam);
  1112. return TRUE;
  1113. }
  1114. }
  1115. TranslateMessage(&msg);
  1116. DispatchMessage(&msg);
  1117. }
  1118. return fAbort;
  1119. }
  1120. #endif
  1121. LONG CALLBACK _loadds PreviewStatusProc(LPARAM lParam, UINT message, LONG l)
  1122. {
  1123. TCHAR ach[100], achT[100];
  1124. BOOL f;
  1125. PICCompressorChooseStuff p = (PICCompressorChooseStuff) lParam;
  1126. if (message != ICSTATUS_STATUS) {
  1127. DPF(("Status callback: lParam = %lx, message = %u, l = %lu\n", lParam, message, l));
  1128. }
  1129. // !!!!
  1130. // !!!! Status messages need to be fixed!!!!!!
  1131. // !!!!
  1132. switch (message) {
  1133. case ICSTATUS_START:
  1134. break;
  1135. case ICSTATUS_STATUS:
  1136. LoadString (ghInst, ID_FRAMECOMPRESSING, achT, sizeof(achT));
  1137. wsprintf(ach, achT, GetScrollPos(GetDlgItem(p->hwnd,
  1138. ID_PREVIEWSCROLL), SB_CTL), l);
  1139. SetDlgItemText(p->hwnd, ID_PREVIEWTEXT, ach);
  1140. break;
  1141. case ICSTATUS_END:
  1142. break;
  1143. case ICSTATUS_YIELD:
  1144. break;
  1145. }
  1146. #ifdef SAFETOYIELD
  1147. f = WinYield(p->hwnd);
  1148. #else
  1149. f = FALSE;
  1150. #endif;
  1151. if (f) {
  1152. DPF(("Aborting from within status proc!\n"));
  1153. }
  1154. return f;
  1155. }
  1156. void Preview(HWND hwnd, PICCompressorChooseStuff p, BOOL fCompress)
  1157. {
  1158. RECT rc;
  1159. HDC hdc;
  1160. int pos;
  1161. HANDLE h;
  1162. HCURSOR hcur = NULL;
  1163. LPBITMAPINFOHEADER lpbi, lpbiU, lpbiC = NULL;
  1164. TCHAR ach[120], achT[100];
  1165. LONG lsizeD = 0;
  1166. LONG lSize;
  1167. int x;
  1168. // Not previewing right now!
  1169. if (!p->hdd || !p->pgf)
  1170. return;
  1171. pos = GetScrollPos(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL);
  1172. lpbi = lpbiU = AVIStreamGetFrame(p->pgf, pos);
  1173. if (!lpbi)
  1174. return;
  1175. //
  1176. // What would the image look like compressed?
  1177. //
  1178. if (fCompress && (int)p->hic > 0) {
  1179. LRESULT lRet;
  1180. lRet = ICSetStatusProc(p->hic, 0, p, PreviewStatusProc);
  1181. if (lRet != 0) {
  1182. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1183. }
  1184. // !!! Gives whole data rate to this stream
  1185. // !!! What to do if Rate or Scale is zero?
  1186. lSize = (GetDlgItemInt(hwnd, ID_DATARATE, NULL, FALSE) * 1024L) /
  1187. ((p->info.dwScale && p->info.dwRate) ?
  1188. (p->info.dwRate / p->info.dwScale) : 1L);
  1189. h = ICImageCompress(p->hic,
  1190. 0,
  1191. (LPBITMAPINFO)lpbi,
  1192. (LPBYTE)lpbi + lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD),
  1193. NULL,
  1194. GetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL) * 100,
  1195. &lSize);
  1196. if (hcur)
  1197. SetCursor(hcur);
  1198. if (h)
  1199. lpbiC = (LPBITMAPINFOHEADER)GlobalLock(h);
  1200. // Use the compressed image if we have one.. else use the original frame
  1201. if (lpbiC)
  1202. lpbi = lpbiC;
  1203. }
  1204. //
  1205. // If we chose NO COMPRESSION, tell them the size of the data as its
  1206. // compressed now. Otherwise, use the size it will become when compressed
  1207. // or the full frame size.
  1208. //
  1209. if (fCompress && (int)p->hic == 0) {
  1210. p->pavi->lpVtbl->Read(p->pavi, pos, 1, NULL, 0, &lsizeD, NULL);
  1211. } else {
  1212. lsizeD = (lpbiC ? lpbiC->biSizeImage : lpbiU->biSizeImage);
  1213. }
  1214. hdc = GetDC(GetDlgItem(hwnd, ID_PREVIEWWIN));
  1215. GetClientRect(GetDlgItem(hwnd, ID_PREVIEWWIN), &rc);
  1216. // Clip regions aren't set up right for windows in a dialog, so make sure
  1217. // we'll only paint into the window and not spill around it.
  1218. IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
  1219. // Now go ahead and draw a miniature frame that preserves the aspect ratio
  1220. // centred in our preview window
  1221. x = MulDiv((int)lpbi->biWidth, 3, 4);
  1222. if (x <= (int)lpbi->biHeight) {
  1223. rc.left = (rc.right - MulDiv(rc.right, x, (int)lpbi->biHeight)) / 2;
  1224. rc.right -= rc.left;
  1225. } else {
  1226. x = MulDiv((int)lpbi->biHeight, 4, 3);
  1227. rc.top = (rc.bottom - MulDiv(rc.bottom, x, (int)lpbi->biWidth)) / 2;
  1228. rc.bottom -= rc.top;
  1229. }
  1230. DrawDibDraw(p->hdd, hdc, rc.left, rc.top, rc.right - rc.left,
  1231. rc.bottom - rc.top, lpbi, NULL, 0, 0, -1, -1, 0);
  1232. // Print the sizes and ratio for this frame
  1233. LoadString (ghInst, ID_FRAMESIZE, achT, sizeof(achT));
  1234. wsprintf(ach, achT,
  1235. GetScrollPos(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL),
  1236. lsizeD,
  1237. lpbiU->biSizeImage,
  1238. lsizeD * 100 / lpbiU->biSizeImage);
  1239. SetDlgItemText(hwnd, ID_PREVIEWTEXT, ach);
  1240. if (lpbiC)
  1241. GlobalFreePtr(lpbiC);
  1242. ReleaseDC(GetDlgItem(hwnd, ID_PREVIEWWIN), hdc);
  1243. }
  1244. ///////////////////////////////////////////////////////////////////////////////
  1245. //
  1246. // ICCompressorChooseDlgProc
  1247. //
  1248. // dialog box procedure for ICCompressorChoose, a pointer to a
  1249. // ICCompressorChooseStuff pointer must be passed to initialize this
  1250. // dialog.
  1251. //
  1252. // NOTE: this dialog box procedure does not use any globals
  1253. // so I did not bother to _export it or use MakeProcAddress() if
  1254. // you change this code to use globals, etc, be aware of this fact.
  1255. //
  1256. ///////////////////////////////////////////////////////////////////////////////
  1257. INT_PTR CALLBACK ICCompressorChooseDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1258. {
  1259. int i,n;
  1260. int pos;
  1261. HWND hwndC;
  1262. PICCompressorChooseStuff p;
  1263. HIC hic;
  1264. BOOL fConfig, fAbout, fQuality, fKey, fDataRate;
  1265. BOOL fShowKeyFrame, fShowDataRate, fShowPreview;
  1266. int nSelectMe = -1;
  1267. TCHAR ach[120], achT[80];
  1268. RECT rc;
  1269. UINT id;
  1270. HDC hdc;
  1271. BOOL f = FALSE, fCanDecompress = FALSE;
  1272. LONG lsize;
  1273. LPBITMAPINFOHEADER lpbi = NULL;
  1274. BOOL fStreamIsCompressed = FALSE;
  1275. HRESULT hr;
  1276. p = (PICCompressorChooseStuff)GetWindowLong(hwnd,DWL_USER);
  1277. switch (msg)
  1278. {
  1279. case WM_INITDIALOG:
  1280. #define but &&
  1281. #define and &&
  1282. #define is ==
  1283. #define isnt !=
  1284. if (lParam == 0)
  1285. return FALSE;
  1286. SetWindowLong(hwnd,DWL_USER,lParam);
  1287. p = (PICCompressorChooseStuff)lParam;
  1288. p->hwnd = hwnd;
  1289. // Let the user change the title of the dialog
  1290. if (p->lpszTitle != NULL)
  1291. SetWindowTextA(hwnd, p->lpszTitle);
  1292. havifile = GetModuleHandle("avifile");
  1293. if (havifile) {
  1294. (FARPROC)AVIStreamGetFrameOpen =
  1295. GetProcAddress((HINSTANCE)havifile,
  1296. (LPCSTR)"AVIStreamGetFrameOpen");
  1297. (FARPROC)AVIStreamGetFrame =
  1298. GetProcAddress((HINSTANCE)havifile,
  1299. (LPCSTR)"AVIStreamGetFrame");
  1300. (FARPROC)AVIStreamGetFrameClose =
  1301. GetProcAddress((HINSTANCE)havifile,
  1302. (LPCSTR)"AVIStreamGetFrameClose");
  1303. if (p->pavi)
  1304. p->pgf = AVIStreamGetFrameOpen(p->pavi, NULL);
  1305. }
  1306. // We weren't passed in an input format but we have a PAVI we
  1307. // can get a format from
  1308. if (p->pvIn is NULL but p->pavi isnt NULL and p->pgf isnt NULL) {
  1309. // We need to nuke pvIn later
  1310. f = TRUE;
  1311. // Find out if the AVI Stream is compressed or not
  1312. p->pavi->lpVtbl->ReadFormat(p->pavi, 0, NULL, &lsize);
  1313. if (lsize)
  1314. lpbi = (LPBITMAPINFOHEADER)GlobalAllocPtr(GMEM_MOVEABLE,
  1315. lsize);
  1316. if (lpbi) {
  1317. hr = p->pavi->lpVtbl->ReadFormat(p->pavi, 0, lpbi, &lsize);
  1318. if (hr == AVIERR_OK)
  1319. fStreamIsCompressed = lpbi->biCompression != BI_RGB;
  1320. GlobalFreePtr(lpbi);
  1321. }
  1322. // Get the decompressed format of the AVI stream
  1323. lpbi = AVIStreamGetFrame(p->pgf, 0);
  1324. if (lpbi) {
  1325. lsize = lpbi->biSize +
  1326. lpbi->biClrUsed * sizeof(PALETTEENTRY);
  1327. p->pvIn = (LPBITMAPINFOHEADER)GlobalAllocPtr(GMEM_MOVEABLE,
  1328. lsize);
  1329. if (p->pvIn)
  1330. hmemcpy(p->pvIn, lpbi, lsize);
  1331. }
  1332. }
  1333. //
  1334. // now fill the combo box with all compressors
  1335. //
  1336. hwndC = GetDlgItem(hwnd, ID_COMPRESSOR);
  1337. for (i=0; ICInfo(p->fccType, i, &p->icinfo); i++)
  1338. {
  1339. hic = ICOpen(p->icinfo.fccType, p->icinfo.fccHandler,
  1340. ICMODE_COMPRESS);
  1341. if (hic)
  1342. {
  1343. //
  1344. // skip this compressor if it can't handle the
  1345. // specified format and we want to skip such compressors
  1346. //
  1347. if (!(p->uiFlags & ICMF_CHOOSE_ALLCOMPRESSORS) &&
  1348. p->pvIn != NULL &&
  1349. ICCompressQuery(hic, p->pvIn, NULL) != ICERR_OK)
  1350. {
  1351. ICClose(hic);
  1352. continue;
  1353. }
  1354. //
  1355. // find out the compressor name.
  1356. //
  1357. ICGetInfo(hic, &p->icinfo, sizeof(p->icinfo));
  1358. //
  1359. // stuff it into the combo box and remember which one it was
  1360. //
  1361. n = ComboBox_AddString(hwndC,p->icinfo.szDescription);
  1362. #ifdef WIN32
  1363. barf // Making a LONG out of a hic and an int just won't cut it
  1364. barf // Look at the GetItemData's as well which will also break
  1365. #endif
  1366. ComboBox_SetItemData(hwndC, n, MAKELONG(hic, i));
  1367. // This compressor is the one we want to come up default ?
  1368. // Set its state
  1369. // !!! Combo Box better not be sorted!
  1370. // Convert both to upper case for an insensitive compare
  1371. AnsiUpperBuff((LPSTR)&p->icinfo.fccHandler, sizeof(FOURCC));
  1372. AnsiUpperBuff((LPSTR)&p->fccHandler, sizeof(FOURCC));
  1373. if (p->icinfo.fccHandler == p->fccHandler) {
  1374. nSelectMe = n;
  1375. if (p->lpState)
  1376. ICSetState(hic, p->lpState, p->cbState);
  1377. }
  1378. }
  1379. }
  1380. //
  1381. // Next add a "No Recompression" item unless they passed in an
  1382. // uncompressed format
  1383. //
  1384. if (!p->pvIn || fStreamIsCompressed ||
  1385. ((LPBITMAPINFOHEADER)p->pvIn)->biCompression != BI_RGB) {
  1386. LoadString (ghInst, ID_NOCOMPSTRING, ach, sizeof (ach));
  1387. n = ComboBox_AddString(hwndC, ach);
  1388. ComboBox_SetItemData(hwndC, n, 0);
  1389. // Select "No Recompression" as the default if nobody else has
  1390. // set it.
  1391. if (nSelectMe == -1)
  1392. nSelectMe = n;
  1393. }
  1394. //
  1395. // Now add a "Full Frames (Uncompressed)" item unless we can't
  1396. // decompress this format and they don't want all choices anyway
  1397. //
  1398. if (!(p->uiFlags & ICMF_CHOOSE_ALLCOMPRESSORS) && p->pvIn) {
  1399. // If it's RGB, of course, just offer the option.
  1400. if (((LPBITMAPINFOHEADER)p->pvIn)->biCompression != BI_RGB) {
  1401. if ((hic = ICLocate(ICTYPE_VIDEO, 0, p->pvIn, NULL,
  1402. ICMODE_DECOMPRESS)) == NULL)
  1403. goto SkipFF;
  1404. else
  1405. ICClose(hic);
  1406. }
  1407. }
  1408. LoadString (ghInst, ID_FULLFRAMESSTRING, ach, sizeof (ach));
  1409. n = ComboBox_AddString(hwndC, ach);
  1410. ComboBox_SetItemData(hwndC, n, MAKELONG(-1, 0));
  1411. // Select "Full Frames" if that was the last one chosen
  1412. // !!! Combo Box better not be sorted!
  1413. if (nSelectMe == -1 &&
  1414. (p->fccHandler == comptypeDIB || p->fccHandler == 0))
  1415. nSelectMe = n;
  1416. fCanDecompress = TRUE;
  1417. SkipFF:
  1418. // If we haven't selected anything yet, choose something at random.
  1419. if (nSelectMe == -1)
  1420. nSelectMe = 0;
  1421. fShowKeyFrame = p->uiFlags & ICMF_CHOOSE_KEYFRAME;
  1422. fShowDataRate = p->uiFlags & ICMF_CHOOSE_DATARATE;
  1423. // Don't show a preview if we can't draw it!
  1424. fShowPreview = (p->uiFlags & ICMF_CHOOSE_PREVIEW) && p->pavi &&
  1425. fCanDecompress;
  1426. // Hide our secret small place holders
  1427. ShowWindow(GetDlgItem(hwnd, ID_CHOOSE_SMALL), SW_HIDE);
  1428. ShowWindow(GetDlgItem(hwnd, ID_CHOOSE_NORMAL), SW_HIDE);
  1429. ShowWindow(GetDlgItem(hwnd, ID_CHOOSE_BIG), SW_HIDE);
  1430. if (!fShowKeyFrame) {
  1431. ShowWindow(GetDlgItem(hwnd, ID_KEYFRAME), SW_HIDE);
  1432. ShowWindow(GetDlgItem(hwnd, ID_KEYFRAMEBOX), SW_HIDE);
  1433. ShowWindow(GetDlgItem(hwnd, ID_KEYFRAMETEXT), SW_HIDE);
  1434. }
  1435. if (!fShowDataRate) {
  1436. ShowWindow(GetDlgItem(hwnd, ID_DATARATE), SW_HIDE);
  1437. ShowWindow(GetDlgItem(hwnd, ID_DATARATEBOX), SW_HIDE);
  1438. ShowWindow(GetDlgItem(hwnd, ID_DATARATETEXT), SW_HIDE);
  1439. }
  1440. if (!fShowPreview) {
  1441. ShowWindow(GetDlgItem(hwnd, ID_PREVIEW), SW_HIDE);
  1442. }
  1443. // We start without these
  1444. ShowWindow(GetDlgItem(hwnd, ID_PREVIEWWIN), SW_HIDE);
  1445. ShowWindow(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SW_HIDE);
  1446. ShowWindow(GetDlgItem(hwnd, ID_PREVIEWTEXT), SW_HIDE);
  1447. //
  1448. // What size dialog do we need?
  1449. //
  1450. if (!fShowPreview && (!fShowDataRate || !fShowKeyFrame))
  1451. SizeDialog(hwnd, ID_CHOOSE_SMALL);
  1452. else
  1453. SizeDialog(hwnd, ID_CHOOSE_NORMAL);
  1454. //
  1455. // Swap places for KeyFrameEvery and DataRate
  1456. //
  1457. if (fShowDataRate && !fShowKeyFrame) {
  1458. GetWindowRect(GetDlgItem(hwnd, ID_KEYFRAME), &rc);
  1459. ScreenToClient(hwnd, (LPPOINT)&rc);
  1460. ScreenToClient(hwnd, (LPPOINT)&rc + 1);
  1461. MoveWindow(GetDlgItem(hwnd, ID_DATARATE), rc.left, rc.top,
  1462. rc.right - rc.left, rc.bottom - rc.top, FALSE);
  1463. GetWindowRect(GetDlgItem(hwnd, ID_KEYFRAMEBOX), &rc);
  1464. ScreenToClient(hwnd, (LPPOINT)&rc);
  1465. ScreenToClient(hwnd, (LPPOINT)&rc + 1);
  1466. MoveWindow(GetDlgItem(hwnd, ID_DATARATEBOX), rc.left, rc.top,
  1467. rc.right - rc.left, rc.bottom - rc.top, FALSE);
  1468. GetWindowRect(GetDlgItem(hwnd, ID_KEYFRAMETEXT), &rc);
  1469. ScreenToClient(hwnd, (LPPOINT)&rc);
  1470. ScreenToClient(hwnd, (LPPOINT)&rc + 1);
  1471. MoveWindow(GetDlgItem(hwnd, ID_DATARATETEXT), rc.left, rc.top,
  1472. rc.right - rc.left, rc.bottom - rc.top, TRUE);
  1473. }
  1474. //
  1475. // Restore the dlg to the settings found in the structure
  1476. //
  1477. SetScrollRange(GetDlgItem(hwnd, ID_QUALITY), SB_CTL, 0, 100, FALSE);
  1478. CheckDlgButton(hwnd, ID_KEYFRAMEBOX, (BOOL)(p->lKey));
  1479. CheckDlgButton(hwnd, ID_DATARATEBOX, (BOOL)(p->lDataRate));
  1480. SetDlgItemInt(hwnd, ID_KEYFRAME, (int)p->lKey, FALSE);
  1481. SetDlgItemInt(hwnd, ID_DATARATE, (int)p->lDataRate, FALSE);
  1482. ComboBox_SetCurSel(GetDlgItem(hwnd, ID_COMPRESSOR), nSelectMe);
  1483. SendMessage(hwnd, WM_COMMAND, ID_COMPRESSOR,
  1484. MAKELONG(hwndC, CBN_SELCHANGE));
  1485. // We alloced this ourselves and need to free it now
  1486. if (f && p->pvIn)
  1487. GlobalFreePtr(p->pvIn);
  1488. return TRUE;
  1489. case WM_PALETTECHANGED:
  1490. // It came from us. Ignore it
  1491. if (wParam == (WORD)hwnd)
  1492. break;
  1493. case WM_QUERYNEWPALETTE:
  1494. if (!p->hdd)
  1495. break;
  1496. hdc = GetDC(hwnd);
  1497. //
  1498. // Realize the palette of the first video stream
  1499. // !!! If first stream isn't video, we're DEAD!
  1500. //
  1501. if (f = DrawDibRealize(p->hdd, hdc, FALSE))
  1502. InvalidateRect(hwnd, NULL, FALSE);
  1503. ReleaseDC(hwnd, hdc);
  1504. return f;
  1505. case WM_PAINT:
  1506. if (!p->hdd)
  1507. break;
  1508. // Paint everybody else before the Preview window since that'll
  1509. // take awhile, and we don't want an ugly window during it.
  1510. DefWindowProc(hwnd, msg, wParam, lParam);
  1511. UpdateWindow(hwnd);
  1512. Preview(hwnd, p, TRUE);
  1513. return 0;
  1514. case WM_HSCROLL:
  1515. #ifdef WIN32
  1516. id = GetWindowLong((HWND)HIWORD(lParam), GWL_ID);
  1517. #else
  1518. id = GetWindowWord((HWND)HIWORD(lParam), GWW_ID);
  1519. #endif
  1520. pos = GetScrollPos((HWND)HIWORD(lParam), SB_CTL);
  1521. switch (wParam)
  1522. {
  1523. case SB_LINEDOWN: pos += 1; break;
  1524. case SB_LINEUP: pos -= 1; break;
  1525. case SB_PAGEDOWN: pos += (id == ID_QUALITY) ? 10 :
  1526. (int)p->info.dwLength / 10; break;
  1527. case SB_PAGEUP: pos -= (id == ID_QUALITY) ? 10 :
  1528. (int)p->info.dwLength / 10; break;
  1529. case SB_THUMBTRACK:
  1530. case SB_THUMBPOSITION: pos = LOWORD(lParam); break;
  1531. case SB_ENDSCROLL:
  1532. Preview(hwnd, p, TRUE); // Draw this compressed frame
  1533. return TRUE; // don't fall through and invalidate
  1534. default:
  1535. return TRUE;
  1536. }
  1537. if (id == ID_QUALITY) {
  1538. if (pos < 0)
  1539. pos = 0;
  1540. if (pos > (ICQUALITY_HIGH/100))
  1541. pos = (ICQUALITY_HIGH/100);
  1542. SetDlgItemInt(hwnd, ID_QUALITYTEXT, pos, FALSE);
  1543. SetScrollPos((HWND)HIWORD(lParam), SB_CTL, pos, TRUE);
  1544. } else if (id == ID_PREVIEWSCROLL) {
  1545. // !!! round off !!!
  1546. if (pos < (int)p->info.dwStart)
  1547. pos = (int)p->info.dwStart;
  1548. if (pos >= (int)p->info.dwStart + (int)p->info.dwLength)
  1549. pos = (int)(p->info.dwStart + p->info.dwLength - 1);
  1550. SetScrollPos((HWND)HIWORD(lParam), SB_CTL, pos, TRUE);
  1551. LoadString (ghInst, ID_FRAME, achT, sizeof(achT));
  1552. wsprintf(ach, achT, pos);
  1553. SetDlgItemText(hwnd, ID_PREVIEWTEXT, ach);
  1554. //Drawing while scrolling flashes palettes because they aren't
  1555. //compressed.
  1556. //Preview(hwnd, p, FALSE);
  1557. }
  1558. break;
  1559. case WM_COMMAND:
  1560. hwndC = GetDlgItem(hwnd, ID_COMPRESSOR);
  1561. n = ComboBox_GetCurSel(hwndC);
  1562. hic = (n == -1) ? NULL : (HIC)LOWORD(ComboBox_GetItemData(hwndC,n));
  1563. if (!p->fClosing)
  1564. p->hic = hic;
  1565. switch ((int)wParam)
  1566. {
  1567. // When data rate box loses focus, update our preview
  1568. case ID_DATARATE:
  1569. if (HIWORD(lParam) == EN_KILLFOCUS)
  1570. Preview(hwnd, p, TRUE);
  1571. break;
  1572. case ID_COMPRESSOR:
  1573. if (HIWORD(lParam) != CBN_SELCHANGE)
  1574. break;
  1575. if ((int)p->hic > 0) {
  1576. ICGetInfo(p->hic, &p->icinfo, sizeof(p->icinfo));
  1577. fConfig = (BOOL)ICQueryConfigure(p->hic);
  1578. fAbout = ICQueryAbout(p->hic);
  1579. fQuality = (p->icinfo.dwFlags & VIDCF_QUALITY) != 0;
  1580. fKey = (p->icinfo.dwFlags & VIDCF_TEMPORAL) != 0;
  1581. // if they do quality we fake crunch
  1582. fDataRate= (p->icinfo.dwFlags &
  1583. (VIDCF_QUALITY|VIDCF_CRUNCH)) != 0;
  1584. } else {
  1585. fConfig = fAbout = fQuality = fKey = fDataRate = FALSE;
  1586. }
  1587. EnableWindow(GetDlgItem(hwnd, ID_CONFIG), fConfig);
  1588. EnableWindow(GetDlgItem(hwnd, ID_ABOUT), fAbout);
  1589. EnableWindow(GetDlgItem(hwnd, ID_QUALITY), fQuality);
  1590. EnableWindow(GetDlgItem(hwnd, ID_QUALITYLABEL), fQuality);
  1591. EnableWindow(GetDlgItem(hwnd, ID_QUALITYTEXT), fQuality);
  1592. EnableWindow(GetDlgItem(hwnd, ID_KEYFRAMEBOX), fKey);
  1593. EnableWindow(GetDlgItem(hwnd, ID_KEYFRAME), fKey);
  1594. EnableWindow(GetDlgItem(hwnd, ID_KEYFRAMETEXT), fKey);
  1595. EnableWindow(GetDlgItem(hwnd, ID_DATARATEBOX), fDataRate);
  1596. EnableWindow(GetDlgItem(hwnd, ID_DATARATE), fDataRate);
  1597. EnableWindow(GetDlgItem(hwnd, ID_DATARATETEXT), fDataRate);
  1598. if (fQuality)
  1599. {
  1600. if (p->lQ == ICQUALITY_DEFAULT && (int)p->hic > 0)
  1601. {
  1602. SetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL,
  1603. (int)ICGetDefaultQuality(p->hic) / 100, TRUE);
  1604. }
  1605. else
  1606. {
  1607. SetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL,
  1608. (int)p->lQ / 100, TRUE);
  1609. }
  1610. pos = GetScrollPos(GetDlgItem(hwnd, ID_QUALITY),SB_CTL);
  1611. SetDlgItemInt(hwnd, ID_QUALITYTEXT, pos, FALSE);
  1612. }
  1613. // redraw with new compressor
  1614. Preview(hwnd, p, TRUE);
  1615. break;
  1616. case ID_CONFIG:
  1617. if ((int)p->hic > 0) {
  1618. ICConfigure(p->hic, hwnd);
  1619. Preview(hwnd, p, TRUE);
  1620. }
  1621. break;
  1622. case ID_ABOUT:
  1623. if ((int)p->hic > 0)
  1624. ICAbout(p->hic, hwnd);
  1625. break;
  1626. case ID_PREVIEW:
  1627. ShowWindow(GetDlgItem(hwnd, ID_PREVIEW), SW_HIDE);
  1628. ShowWindow(GetDlgItem(hwnd, ID_PREVIEWWIN), SW_SHOW);
  1629. ShowWindow(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SW_SHOW);
  1630. ShowWindow(GetDlgItem(hwnd, ID_PREVIEWTEXT), SW_SHOW);
  1631. SizeDialog(hwnd, ID_CHOOSE_BIG);
  1632. // !!! truncation
  1633. SetScrollRange(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL,
  1634. (int)p->info.dwStart,
  1635. (int)(p->info.dwStart + p->info.dwLength - 1),
  1636. FALSE);
  1637. SetScrollPos(GetDlgItem(hwnd, ID_PREVIEWSCROLL), SB_CTL,
  1638. (int)p->info.dwStart, TRUE);
  1639. LoadString (ghInst, ID_FRAME, achT, sizeof(achT));
  1640. wsprintf(ach, achT, p->info.dwStart);
  1641. SetDlgItemText(hwnd, ID_PREVIEWTEXT, ach);
  1642. InitPreview(hwnd, p);
  1643. break;
  1644. case IDOK:
  1645. // !!! We need to call ICInfo to get the FOURCC used
  1646. // in system.ini. Calling ICGetInfo will return the
  1647. // FOURCC the compressor thinks it is, which won't
  1648. // work.
  1649. // Get the HIWORD before we nuke it.
  1650. i = HIWORD(ComboBox_GetItemData(hwndC, n));
  1651. //
  1652. // Don't close the current compressor in our CANCEL loop
  1653. //
  1654. ComboBox_SetItemData(hwndC, n, 0);
  1655. //
  1656. // Return the values of the dlg to the caller
  1657. //
  1658. p->hic = hic;
  1659. p->lQ = 100 *
  1660. GetScrollPos(GetDlgItem(hwnd, ID_QUALITY), SB_CTL);
  1661. if (IsDlgButtonChecked(hwnd, ID_KEYFRAMEBOX))
  1662. p->lKey = GetDlgItemInt(hwnd, ID_KEYFRAME, NULL, FALSE);
  1663. else
  1664. p->lKey = 0;
  1665. if (IsDlgButtonChecked(hwnd, ID_DATARATEBOX))
  1666. p->lDataRate = GetDlgItemInt(hwnd, ID_DATARATE, NULL,
  1667. FALSE);
  1668. else
  1669. p->lDataRate = 0;
  1670. // We've chosen a valid compressor. Do stuff.
  1671. if ((int)p->hic > 0) {
  1672. // !!! We need to call ICInfo to get the FOURCC used
  1673. // in system.ini. Calling ICGetInfo will return the
  1674. // FOURCC the compressor thinks it is, which won't
  1675. // work.
  1676. ICInfo(p->fccType, i, &p->icinfo);
  1677. p->fccHandler = p->icinfo.fccHandler; // identify it
  1678. // Free the old state
  1679. if (p->lpState)
  1680. GlobalFreePtr(p->lpState);
  1681. p->lpState = NULL;
  1682. // Get the new state
  1683. p->cbState = ICGetStateSize(p->hic);
  1684. if (p->cbState) { // Remember it's config state
  1685. p->lpState = GlobalAllocPtr(GMEM_MOVEABLE,
  1686. p->cbState);
  1687. if (p->lpState) {
  1688. ICGetState(p->hic, p->lpState, p->cbState);
  1689. }
  1690. }
  1691. } else if ((int)p->hic == -1) { // "Full Frames"
  1692. p->fccHandler = comptypeDIB;
  1693. p->hic = 0;
  1694. } else { // "No Compression"
  1695. p->fccHandler = 0L;
  1696. p->hic = 0;
  1697. }
  1698. // fall through
  1699. case IDCANCEL:
  1700. p->fClosing = TRUE;
  1701. if (wParam == IDCANCEL)
  1702. p->hic = NULL;
  1703. n = ComboBox_GetCount(hwndC);
  1704. for (i=0; i<n; i++)
  1705. {
  1706. if ((int)(hic =
  1707. (HIC)LOWORD(ComboBox_GetItemData(hwndC,i))) > 0)
  1708. ICClose(hic);
  1709. }
  1710. TermPreview(p);
  1711. if (p->pgf)
  1712. AVIStreamGetFrameClose(p->pgf);
  1713. p->pgf = NULL;
  1714. EndDialog(hwnd, wParam == IDOK);
  1715. break;
  1716. }
  1717. break;
  1718. }
  1719. return FALSE;
  1720. }
  1721. /*****************************************************************************
  1722. *
  1723. * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1724. *
  1725. * The messages will be send to COM1: like any debug message. To
  1726. * enable debug output, add the following to WIN.INI :
  1727. *
  1728. * [debug]
  1729. * ICSAMPLE=1
  1730. *
  1731. ****************************************************************************/
  1732. #ifdef DEBUG
  1733. static BOOL fDebug = -1;
  1734. #define MODNAME "ICM"
  1735. static void cdecl dprintf(LPSTR szFormat, ...)
  1736. {
  1737. char ach[128];
  1738. #ifdef WIN32
  1739. va_list va;
  1740. if (fDebug == -1)
  1741. fDebug = GetProfileIntA("Debug",MODNAME, FALSE);
  1742. if (!fDebug)
  1743. return;
  1744. va_start(va, szFormat);
  1745. if (szFormat[0] == '!')
  1746. ach[0]=0, szFormat++;
  1747. else
  1748. lstrcpyA(ach, MODNAME ": ");
  1749. wvsprintfA(ach+lstrlenA(ach),szFormat,(LPSTR)va);
  1750. va_end(va);
  1751. // lstrcat(ach, "\r\r\n");
  1752. #else
  1753. if (fDebug == -1)
  1754. fDebug = GetProfileInt("Debug",MODNAME, FALSE);
  1755. if (!fDebug)
  1756. return;
  1757. if (szFormat[0] == '!')
  1758. ach[0]=0, szFormat++;
  1759. else
  1760. lstrcpy(ach, MODNAME ": ");
  1761. wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
  1762. // lstrcat(ach, "\r\r\n");
  1763. #endif
  1764. OutputDebugStringA(ach);
  1765. }
  1766. #endif