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.

2163 lines
71 KiB

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