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.

1233 lines
32 KiB

  1. /****************************************************************************
  2. *
  3. * AVICMPRS.C
  4. *
  5. * routine for compressing AVI files...
  6. *
  7. * AVISave()
  8. *
  9. * Copyright (c) 1992 Microsoft Corporation. All Rights Reserved.
  10. *
  11. * You have a royalty-free right to use, modify, reproduce and
  12. * distribute the Sample Files (and/or any modified version) in
  13. * any way you find useful, provided that you agree that
  14. * Microsoft has no warranty obligations or liability for any
  15. * Sample Application Files which are modified.
  16. *
  17. ***************************************************************************/
  18. //
  19. // What this file does:
  20. //
  21. // Given an AVI Stream (that is, essentially, a function that it can call
  22. // to get video frames), this presents the same sort of interface and allows
  23. // other people to call it to get compressed frames.
  24. //
  25. #include <win32.h>
  26. #include <compobj.h>
  27. #include <compman.h>
  28. #include <avifmt.h>
  29. #include "avifile.h"
  30. #include "avifilei.h"
  31. #include "avicmprs.h"
  32. #include "debug.h"
  33. #define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
  34. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  35. #define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  36. #define DIBPTR(lpbi) ((LPBYTE)(lpbi) + \
  37. (int)(lpbi)->biSize + \
  38. (int)(lpbi)->biClrUsed * sizeof(RGBQUAD) )
  39. void CAVICmpStream::ResetInst(void)
  40. {
  41. lFrameCurrent = -1;
  42. lLastKeyFrame = 0;
  43. dwQualityLast = ICQUALITY_HIGH;
  44. dwSaved = 0;
  45. }
  46. /* - - - - - - - - */
  47. HRESULT CAVICmpStream::Create(
  48. IUnknown FAR* pUnknownOuter,
  49. const IID FAR& riid,
  50. void FAR* FAR* ppv)
  51. {
  52. IUnknown FAR* pUnknown;
  53. CAVICmpStream FAR* pAVIStream;
  54. HRESULT hresult;
  55. pAVIStream = new FAR CAVICmpStream(pUnknownOuter, &pUnknown);
  56. if (!pAVIStream)
  57. return ResultFromScode(E_OUTOFMEMORY);
  58. hresult = pUnknown->QueryInterface(riid, ppv);
  59. if (FAILED(GetScode(hresult)))
  60. delete pAVIStream;
  61. return hresult;
  62. }
  63. /* - - - - - - - - */
  64. CAVICmpStream::CAVICmpStream(
  65. IUnknown FAR* pUnknownOuter,
  66. IUnknown FAR* FAR* ppUnknown) :
  67. m_Unknown(this),
  68. m_AVIStream(this)
  69. {
  70. // !!! clear extra junk!
  71. pavi = 0;
  72. pgf = 0;
  73. hic = 0;
  74. lpbiC = 0;
  75. lpbiU = 0;
  76. lpFormat = 0;
  77. cbFormat = 0;
  78. lpFormatOrig = 0;
  79. cbFormatOrig = 0;
  80. lpHandler = 0;
  81. cbHandler = 0;
  82. if (pUnknownOuter)
  83. m_pUnknownOuter = pUnknownOuter;
  84. else
  85. m_pUnknownOuter = &m_Unknown;
  86. *ppUnknown = &m_Unknown;
  87. }
  88. /* - - - - - - - - */
  89. CAVICmpStream::CUnknownImpl::CUnknownImpl(
  90. CAVICmpStream FAR* pAVIStream)
  91. {
  92. m_pAVIStream = pAVIStream;
  93. m_refs = 0;
  94. }
  95. /* - - - - - - - - */
  96. STDMETHODIMP CAVICmpStream::CUnknownImpl::QueryInterface(
  97. const IID FAR& iid,
  98. void FAR* FAR* ppv)
  99. {
  100. if (iid == IID_IUnknown)
  101. *ppv = &m_pAVIStream->m_Unknown;
  102. else if (iid == IID_IAVIStream)
  103. *ppv = &m_pAVIStream->m_AVIStream;
  104. else
  105. return ResultFromScode(E_NOINTERFACE);
  106. AddRef();
  107. return AVIERR_OK;
  108. }
  109. /* - - - - - - - - */
  110. STDMETHODIMP_(ULONG) CAVICmpStream::CUnknownImpl::AddRef()
  111. {
  112. uUseCount++;
  113. return ++m_refs;
  114. }
  115. /* - - - - - - - - */
  116. CAVICmpStream::CAVICmpStreamImpl::CAVICmpStreamImpl(
  117. CAVICmpStream FAR* pAVIStream)
  118. {
  119. m_pAVIStream = pAVIStream;
  120. }
  121. /* - - - - - - - - */
  122. CAVICmpStream::CAVICmpStreamImpl::~CAVICmpStreamImpl()
  123. {
  124. }
  125. /* - - - - - - - - */
  126. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::QueryInterface(
  127. const IID FAR& iid,
  128. void FAR* FAR* ppv)
  129. {
  130. return m_pAVIStream->m_pUnknownOuter->QueryInterface(iid, ppv);
  131. }
  132. /* - - - - - - - - */
  133. STDMETHODIMP_(ULONG) CAVICmpStream::CAVICmpStreamImpl::AddRef()
  134. {
  135. return m_pAVIStream->m_pUnknownOuter->AddRef();
  136. }
  137. /* - - - - - - - - */
  138. STDMETHODIMP_(ULONG) CAVICmpStream::CAVICmpStreamImpl::Release()
  139. {
  140. return m_pAVIStream->m_pUnknownOuter->Release();
  141. }
  142. /* - - - - - - - - */
  143. HRESULT CAVICmpStream::SetUpCompression()
  144. {
  145. LONG lRet = AVIERR_OK;
  146. LPBITMAPINFOHEADER lpbi;
  147. CAVICmpStream FAR * pinst = this; // for convenience....
  148. DWORD dw;
  149. pinst->pgf = AVIStreamGetFrameOpen(pinst->pavi, NULL);
  150. if (!pinst->pgf) {
  151. // !!! we couldn't decompress the stream!
  152. lRet = AVIERR_INTERNAL;
  153. goto exit;
  154. }
  155. if (pinst->avistream.fccHandler == comptypeDIB)
  156. goto exit;
  157. lpbi = (LPBITMAPINFOHEADER) AVIStreamGetFrame(pinst->pgf, 0);
  158. if (lpbi == NULL) {
  159. lRet = AVIERR_INTERNAL;
  160. goto exit;
  161. }
  162. /*
  163. ** get the size requied to hold the format.
  164. */
  165. dw = ICCompressGetFormatSize(pinst->hic, lpbi);
  166. if ((LONG) dw < sizeof(BITMAPINFOHEADER))
  167. goto ic_error;
  168. pinst->cbFormat = dw;
  169. pinst->lpFormat = (LPBITMAPINFOHEADER) GlobalAllocPtr(GHND | GMEM_SHARE, pinst->cbFormat);
  170. if (!pinst->lpFormat) {
  171. lRet = AVIERR_MEMORY;
  172. goto exit;
  173. }
  174. /*
  175. ** get the compressed format from the compressor.
  176. */
  177. dw = ICCompressGetFormat(pinst->hic, lpbi, pinst->lpFormat);
  178. if ((LONG) dw < 0)
  179. goto ic_error;
  180. pinst->avistream.rcFrame.right = pinst->avistream.rcFrame.left +
  181. (int) pinst->lpFormat->biWidth;
  182. pinst->avistream.rcFrame.bottom = pinst->avistream.rcFrame.top +
  183. (int) pinst->lpFormat->biHeight;
  184. dw = ICCompressBegin(pinst->hic, lpbi, pinst->lpFormat);
  185. if (dw != ICERR_OK)
  186. goto ic_error;
  187. /*
  188. ** allocate buffer to hold compressed data.
  189. */
  190. dw = ICCompressGetSize(pinst->hic, lpbi, pinst->lpFormat);
  191. pinst->lpbiC = (LPBITMAPINFOHEADER)
  192. GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, pinst->cbFormat + dw);
  193. if (!pinst->lpbiC) {
  194. lRet = AVIERR_MEMORY;
  195. goto exit;
  196. }
  197. hmemcpy((LPVOID)pinst->lpbiC, pinst->lpFormat, pinst->cbFormat);
  198. pinst->lpC = (LPSTR) pinst->lpbiC + pinst->lpbiC->biSize +
  199. pinst->lpbiC->biClrUsed * sizeof(RGBQUAD);
  200. //
  201. // check for temporal compress, and alocate a previous
  202. // DIB buffer if needed
  203. //
  204. if (pinst->dwKeyFrameEvery != 1) {
  205. pinst->lpbiU = (LPBITMAPINFOHEADER)
  206. GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  207. sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
  208. if (!pinst->lpbiU) {
  209. lRet = AVIERR_MEMORY;
  210. goto exit;
  211. }
  212. dw = ICDecompressGetFormat(pinst->hic, pinst->lpFormat, pinst->lpbiU);
  213. if ((LONG) dw < 0)
  214. goto ic_error;
  215. if (pinst->lpbiU->biSizeImage == 0)
  216. pinst->lpbiU->biSizeImage = pinst->lpbiU->biHeight *
  217. DIBWIDTHBYTES(*pinst->lpbiU);
  218. pinst->lpbiU = (LPBITMAPINFOHEADER)
  219. GlobalReAllocPtr(pinst->lpbiU,
  220. pinst->lpbiU->biSize +
  221. pinst->lpbiU->biClrUsed * sizeof(RGBQUAD) +
  222. pinst->lpbiU->biSizeImage,
  223. GMEM_MOVEABLE | GMEM_SHARE);
  224. if (!pinst->lpbiU) {
  225. lRet = AVIERR_MEMORY;
  226. goto exit;
  227. }
  228. pinst->lpU = (LPSTR) pinst->lpbiU + pinst->lpbiU->biSize +
  229. pinst->lpbiU->biClrUsed * sizeof(RGBQUAD);
  230. dw = ICDecompressBegin(pinst->hic, pinst->lpFormat, pinst->lpbiU);
  231. if (dw != ICERR_OK)
  232. goto ic_error;
  233. }
  234. // !!! We really should check if the new stream has palette changes....
  235. exit:
  236. if (lRet != AVIERR_OK)
  237. // Clean up before returning...
  238. ;
  239. return ResultFromScode(lRet);
  240. ic_error:
  241. if (dw == ICERR_BADFORMAT)
  242. lRet = AVIERR_BADFORMAT;
  243. else if (dw == ICERR_MEMORY)
  244. lRet = AVIERR_MEMORY;
  245. else
  246. lRet = AVIERR_INTERNAL;
  247. goto exit;
  248. }
  249. /* - - - - - - - - */
  250. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Create(LONG lParam1, LONG lParam2)
  251. {
  252. CAVICmpStream FAR * pinst = m_pAVIStream;
  253. ICINFO icinfo;
  254. AVICOMPRESSOPTIONS FAR *lpOpt = (AVICOMPRESSOPTIONS FAR *)lParam2;
  255. LONG lRet = AVIERR_OK;
  256. // The AVI Stream that we're compressing is passsed in in the <szFile>
  257. // parameter.
  258. pinst->pavi = (PAVISTREAM)lParam1;
  259. // Make sure the uncompressed stream doesn't go away without our
  260. // knowledge....
  261. AVIStreamAddRef(pinst->pavi);
  262. // !!! how can we check if pinst->pavi is valid?
  263. // Get the stream header for future reference....
  264. AVIStreamInfo(pinst->pavi, &pinst->avistream, sizeof(pinst->avistream));
  265. pinst->ResetInst();
  266. if (!lpOpt || (lpOpt->fccHandler == comptypeDIB)) {
  267. pinst->avistream.fccHandler = comptypeDIB;
  268. lRet = AVIERR_OK;
  269. goto exit;
  270. }
  271. pinst->avistream.fccHandler = lpOpt->fccHandler;
  272. // Open the compressor they asked for in the options structure...
  273. pinst->hic = ICOpen(ICTYPE_VIDEO, lpOpt->fccHandler, ICMODE_COMPRESS);
  274. if (!pinst->hic) {
  275. lRet = AVIERR_NOCOMPRESSOR;
  276. goto exit;
  277. }
  278. if (lpOpt->cbParms) {
  279. ICSetState(pinst->hic, lpOpt->lpParms, lpOpt->cbParms);
  280. }
  281. pinst->avistream.dwQuality = lpOpt->dwQuality;
  282. if (pinst->avistream.dwQuality == ICQUALITY_DEFAULT) {
  283. pinst->avistream.dwQuality = ICGetDefaultQuality(pinst->hic);
  284. }
  285. /*
  286. ** get info about this compressor
  287. */
  288. ICGetInfo(pinst->hic,&icinfo,sizeof(icinfo));
  289. pinst->dwICFlags = icinfo.dwFlags;
  290. if (lpOpt->dwFlags & AVICOMPRESSF_KEYFRAMES)
  291. pinst->dwKeyFrameEvery = lpOpt->dwKeyFrameEvery;
  292. else
  293. pinst->dwKeyFrameEvery = 1;
  294. if (!(icinfo.dwFlags & VIDCF_TEMPORAL))
  295. pinst->dwKeyFrameEvery = 1; // compressor doesn't do temporal
  296. if (lpOpt->dwFlags & AVICOMPRESSF_DATARATE)
  297. pinst->dwMaxSize = muldiv32(lpOpt->dwBytesPerSecond,
  298. pinst->avistream.dwScale,
  299. pinst->avistream.dwRate);
  300. else
  301. pinst->dwMaxSize = 0;
  302. {
  303. ICCOMPRESSFRAMES iccf;
  304. DWORD dw;
  305. iccf.lpbiOutput = pinst->lpbiC;
  306. iccf.lOutput = 0;
  307. iccf.lpbiInput = pinst->lpbiU;
  308. iccf.lInput = 0;
  309. iccf.lStartFrame = 0;
  310. iccf.lFrameCount = (LONG) pinst->avistream.dwLength;
  311. iccf.lQuality = (LONG) pinst->avistream.dwQuality;
  312. iccf.lDataRate = (LONG) lpOpt->dwBytesPerSecond;
  313. iccf.lKeyRate = (LONG) pinst->dwKeyFrameEvery;
  314. iccf.dwRate = pinst->avistream.dwRate;
  315. iccf.dwScale = pinst->avistream.dwScale;
  316. iccf.dwOverheadPerFrame = 0;
  317. iccf.dwReserved2 = 0;
  318. iccf.GetData = NULL;
  319. iccf.PutData = NULL;
  320. dw = ICSendMessage(pinst->hic,
  321. ICM_COMPRESS_FRAMES_INFO,
  322. (DWORD) (LPVOID) &iccf,
  323. sizeof(iccf));
  324. // If they support this message, don't give
  325. // warning for data rate!
  326. if (dw == ICERR_OK) {
  327. DPF("Compressor supports COMPRESSFRAMESINFO\n");
  328. // !!! fDataRateChanged = TRUE;
  329. }
  330. #ifdef STATUSCALLBACKS
  331. ICSetStatusProc(pinst->hic,
  332. 0,
  333. pinst,
  334. CompressStatusProc);
  335. #endif
  336. }
  337. exit:
  338. if (lRet != AVIERR_OK)
  339. // Clean up before returning...
  340. ;
  341. return ResultFromScode(lRet);
  342. }
  343. STDMETHODIMP_(ULONG) CAVICmpStream::CUnknownImpl::Release()
  344. {
  345. CAVICmpStream FAR * pinst = m_pAVIStream;
  346. uUseCount--;
  347. if (!--m_refs) {
  348. if (pinst->hic) {
  349. ICCompressEnd(pinst->hic);
  350. if (pinst->dwKeyFrameEvery != 1 && pinst->lpbiU)
  351. ICDecompressEnd(pinst->hic);
  352. if (pinst->lpbiU)
  353. GlobalFreePtr((LPVOID) pinst->lpbiU);
  354. if (pinst->lpbiC)
  355. GlobalFreePtr((LPVOID) pinst->lpbiC);
  356. ICClose(pinst->hic);
  357. }
  358. if (pinst->pgf) {
  359. AVIStreamGetFrameClose(pinst->pgf);
  360. pinst->pgf = 0;
  361. }
  362. if (pinst->pavi) {
  363. // Release our hold on the uncompressed stream....
  364. AVIStreamClose(pinst->pavi);
  365. }
  366. if (pinst->lpFormat)
  367. GlobalFreePtr(pinst->lpFormat);
  368. if (pinst->lpFormatOrig)
  369. GlobalFreePtr(pinst->lpFormatOrig);
  370. delete pinst;
  371. return 0;
  372. }
  373. return m_refs;
  374. }
  375. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Info(AVISTREAMINFO FAR * psi, LONG lSize)
  376. {
  377. CAVICmpStream FAR * pinst = m_pAVIStream;
  378. hmemcpy(psi, &pinst->avistream, min(lSize, sizeof(pinst->avistream)));
  379. // return sizeof(pinst->avistream);
  380. return ResultFromScode(0);
  381. }
  382. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::ReadFormat(LONG lPos, LPVOID lpFormat, LONG FAR *lpcbFormat)
  383. {
  384. CAVICmpStream FAR * pinst = m_pAVIStream;
  385. LPBITMAPINFOHEADER lpbi;
  386. if (!pinst->pgf) {
  387. HRESULT hr;
  388. hr = pinst->SetUpCompression();
  389. if (hr != NOERROR)
  390. return hr;
  391. }
  392. lpbi = (LPBITMAPINFOHEADER) AVIStreamGetFrame(pinst->pgf, lPos);
  393. if (!lpbi)
  394. return ResultFromScode(AVIERR_MEMORY);
  395. if (pinst->hic == 0) {
  396. pinst->cbFormat = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
  397. if (lpFormat)
  398. hmemcpy(lpFormat, lpbi, min(*lpcbFormat, (LONG) pinst->cbFormat));
  399. } else {
  400. if (lpFormat) {
  401. hmemcpy(lpFormat, pinst->lpFormat, min(*lpcbFormat, (LONG) pinst->cbFormat));
  402. if (pinst->lpFormat->biClrUsed > 0) {
  403. // Make sure we have the right colors!
  404. // !!! This is bad--We may need to restart the compressor...
  405. hmemcpy((LPBYTE) lpFormat + pinst->lpFormat->biSize,
  406. (LPBYTE) lpbi + lpbi->biSize,
  407. pinst->lpFormat->biClrUsed * sizeof(RGBQUAD));
  408. }
  409. }
  410. }
  411. *lpcbFormat = pinst->cbFormat;
  412. return AVIERR_OK;
  413. }
  414. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Read(
  415. LONG lStart,
  416. LONG lSamples,
  417. LPVOID lpBuffer,
  418. LONG cbBuffer,
  419. LONG FAR * plBytes,
  420. LONG FAR * plSamples)
  421. {
  422. CAVICmpStream FAR * pinst = m_pAVIStream;
  423. LPBITMAPINFOHEADER lpbi;
  424. LONG lRet;
  425. if (!pinst->pgf) {
  426. HRESULT hr;
  427. hr = pinst->SetUpCompression();
  428. if (hr != NOERROR)
  429. return hr;
  430. }
  431. if (pinst->hic == 0) {
  432. lpbi = (LPBITMAPINFOHEADER) AVIStreamGetFrame(pinst->pgf, lStart);
  433. if (!lpbi)
  434. return ResultFromScode(AVIERR_MEMORY);
  435. if (plBytes)
  436. *plBytes = lpbi->biSizeImage;
  437. if ((LONG) lpbi->biSizeImage > cbBuffer)
  438. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  439. if (lpBuffer)
  440. hmemcpy(lpBuffer, DIBPTR(lpbi), min((DWORD) cbBuffer, lpbi->biSizeImage));
  441. if (plSamples)
  442. *plSamples = 1;
  443. return AVIERR_OK;
  444. }
  445. if (lStart < pinst->lFrameCurrent)
  446. pinst->ResetInst();
  447. while (pinst->lFrameCurrent < lStart) {
  448. ++pinst->lFrameCurrent;
  449. lpbi = (LPBITMAPINFOHEADER) AVIStreamGetFrame(pinst->pgf, pinst->lFrameCurrent);
  450. if (lpbi == NULL) {
  451. pinst->ResetInst(); // Make sure we don't assume anything
  452. return ResultFromScode(AVIERR_INTERNAL);
  453. }
  454. // !!! Check if format has changed!
  455. lRet = pinst->ICCrunch(lpbi, DIBPTR(lpbi));
  456. if (lRet != AVIERR_OK) {
  457. pinst->ResetInst(); // Make sure we don't assume anything
  458. return ResultFromScode(AVIERR_INTERNAL); // !!! error < 0.
  459. }
  460. }
  461. if (plBytes)
  462. *plBytes = pinst->lpbiC->biSizeImage;
  463. if ((LONG) pinst->lpbiC->biSizeImage > cbBuffer)
  464. return ResultFromScode(AVIERR_BUFFERTOOSMALL);
  465. if (lpBuffer)
  466. hmemcpy(lpBuffer, pinst->lpC,
  467. min((DWORD) cbBuffer, pinst->lpbiC->biSizeImage));
  468. if (plSamples)
  469. *plSamples = 1;
  470. return AVIERR_OK;
  471. }
  472. STDMETHODIMP_(LONG) CAVICmpStream::CAVICmpStreamImpl::FindSample(LONG lPos, LONG lFlags)
  473. {
  474. CAVICmpStream FAR * pinst = m_pAVIStream;
  475. if (lFlags & FIND_KEY) {
  476. if (pinst->hic == 0)
  477. return lPos;
  478. if (lFlags & FIND_PREV) {
  479. /* If the frame they're asking about isn't the one we have,
  480. ** we have to go actually do the work and find out.
  481. */
  482. if (lPos < pinst->lLastKeyFrame || lPos > pinst->lFrameCurrent)
  483. Read(lPos, 1, NULL, 0, NULL, NULL);
  484. return pinst->lLastKeyFrame;
  485. } else {
  486. return -1; // !!! Find Next KeyFrame
  487. }
  488. }
  489. if (lFlags & FIND_ANY) {
  490. return lPos;
  491. }
  492. if (lFlags & FIND_FORMAT) {
  493. // !!! This is wrong in the case where we're compressing something
  494. // with a palette change and the compressor preserves it....
  495. if (lFlags & FIND_PREV)
  496. return 0;
  497. else
  498. return -1;
  499. }
  500. return -1;
  501. }
  502. /////////////////////////////////////////////////////////////////////////////
  503. //
  504. // ICCrunch()
  505. //
  506. // crunch a frame and make it fit into the specifed size, by varing the
  507. // quality. the suplied quality is the upper bound.
  508. //
  509. // if the compressor can crunch, then let it crunch
  510. //
  511. // if the compressor does quality, then vary the quality
  512. //
  513. // if the compressor does not do quality, then the caller gets what
  514. // ever it will do.
  515. //
  516. //
  517. // The frame to be compressed is passed in in lpbi.
  518. //
  519. // The compressed frame can be found in the lpC member variable....
  520. //
  521. /////////////////////////////////////////////////////////////////////////////
  522. LONG CAVICmpStream::ICCrunch(LPBITMAPINFOHEADER lpbi, LPVOID lp)
  523. {
  524. DWORD dw;
  525. DWORD dwFlags;
  526. DWORD dwSize;
  527. DWORD ckid;
  528. DWORD dwQuality = avistream.dwQuality;
  529. DWORD dwQualityMin;
  530. DWORD dwQualityMax;
  531. DWORD dwMaxSizeThisFrame;
  532. DWORD dwSizeMin;
  533. DWORD dwSizeMax;
  534. BOOL fKeyFrame=FALSE;
  535. BOOL fCrunch; /* are we crunching? */
  536. BOOL fFirst=TRUE;
  537. dwMaxSizeThisFrame = dwMaxSize;
  538. if (lFrameCurrent == 0 || (dwKeyFrameEvery != 0 &&
  539. lFrameCurrent - lLastKeyFrame >= (long)dwKeyFrameEvery)) {
  540. fKeyFrame = TRUE;
  541. }
  542. //
  543. // give the key frames more space, and take some away from the
  544. // non key frames.
  545. //
  546. // give the key frame two shares, assuming we have more frames to
  547. // go around.
  548. //
  549. if (dwKeyFrameEvery > 0) {
  550. if (lFrameCurrent == 0) {
  551. dwMaxSizeThisFrame = 0xffffff;
  552. } else if (fKeyFrame) {
  553. dwMaxSizeThisFrame = dwMaxSizeThisFrame + dwSaved;
  554. dwSaved = 0;
  555. } else {
  556. DWORD dwTakeAway;
  557. dwTakeAway = dwMaxSizeThisFrame / dwKeyFrameEvery;
  558. if (dwSaved > dwMaxSizeThisFrame)
  559. dwTakeAway = 0;
  560. /* If we're padding, take away a multiple of 2K. */
  561. if (fPad) {
  562. if (dwMaxSizeThisFrame > dwTakeAway + 2048)
  563. dwTakeAway += 2047;
  564. dwTakeAway -= dwTakeAway % 2048;
  565. }
  566. dwMaxSizeThisFrame -= dwTakeAway;
  567. dwSaved += dwTakeAway;
  568. if (!fPad) {
  569. /* Try to give a little extra space to each frame */
  570. dwMaxSizeThisFrame += dwSaved / dwKeyFrameEvery;
  571. dwSaved -= dwSaved / dwKeyFrameEvery;
  572. }
  573. }
  574. } else {
  575. // the only key frame is frame zero
  576. if (lFrameCurrent == 0)
  577. dwMaxSizeThisFrame = 0xffffff;
  578. else {
  579. /* Give each frame whatever extra there is.... */
  580. dwMaxSizeThisFrame += dwSaved;
  581. dwSaved = 0;
  582. }
  583. }
  584. //
  585. // if the device supports crunching or does not do quality we dont
  586. // crunch.
  587. //
  588. fCrunch = dwMaxSizeThisFrame > 0 && !(dwICFlags & VIDCF_CRUNCH) &&
  589. (dwICFlags & VIDCF_QUALITY);
  590. ////if (lFrameCurrent > 0 && fCrunch)
  591. //// dwQuality = dwQualityLast;
  592. DPF("ICCrunch: Frame %ld, Quality = %ld, MaxSize = %ld\n", lFrameCurrent, avistream.dwQuality, dwMaxSizeThisFrame);
  593. dwQualityMin = 0;
  594. dwQualityMax = dwQuality;
  595. dwSizeMin = 0;
  596. dwSizeMax = dwMaxSizeThisFrame;
  597. for (;;) {
  598. ckid = 0L;
  599. dwFlags = fKeyFrame ? AVIIF_KEYFRAME : 0;
  600. //
  601. // compress the frame
  602. //
  603. dw = ICCompress(hic,
  604. 0, // flags
  605. lpbiC, // ouput format
  606. lpC, // output data
  607. lpbi, // format of frame to compress
  608. lp, // frame data to compress
  609. &ckid, // ckid for data in AVI file
  610. &dwFlags, // flags in the AVI index.
  611. lFrameCurrent, // frame number of seq.
  612. dwMaxSizeThisFrame, // reqested size in bytes. (if non zero)
  613. dwQuality, // quality value
  614. fKeyFrame ? NULL : lpbiU,
  615. fKeyFrame ? NULL : lpU);
  616. if (dw != ICERR_OK)
  617. break;
  618. dwSize = lpbiC->biSizeImage;
  619. DPF(" Quality = %ld, Size = %ld, %c\n", dwQuality, dwSize, (dwFlags & AVIIF_KEYFRAME) ? 'K' : ' ');
  620. //
  621. // if the device can't crunch (does not do it it self, or does not do
  622. // quality) then we are done.
  623. //
  624. if (!fCrunch)
  625. break;
  626. //
  627. // we are crunching, see if the frame fit.
  628. //
  629. if (dwSize <= dwMaxSizeThisFrame) {
  630. dwQualityMin = dwQuality;
  631. dwSizeMin = dwSize;
  632. //
  633. // when the quality gets too close bail out.
  634. //
  635. if (dwQualityMax - dwQualityMin <= 10)
  636. break;
  637. //
  638. // if we get within 512 bytes it is good enough
  639. //
  640. if ((LONG) (dwMaxSizeThisFrame - dwSize) <= (LONG) min(512L, dwMaxSizeThisFrame / 8L))
  641. break;
  642. //
  643. // if the first try, (with the user specifed quality) made it
  644. // then use it. otherwise we need to search.
  645. //
  646. if (fFirst)
  647. break;
  648. }
  649. else {
  650. //
  651. // when the quality gets too close bail out.
  652. //
  653. if (dwQualityMax - dwQualityMin <= 1)
  654. break;
  655. dwQualityMax = dwQuality;
  656. dwSizeMax = dwSize;
  657. }
  658. if (fFirst && dwQuality != dwQualityLast)
  659. dwQuality = dwQualityLast;
  660. else
  661. dwQuality = (dwQualityMin + dwQualityMax) / 2;
  662. #if 0
  663. //
  664. // make a guess based on how close we are now.
  665. //
  666. dwQuality = dwQualityMin + muldiv32(dwQualityMax-dwQualityMin,
  667. dwMaxSizeThisFrame-dwSizeMin,dwSizeMax-dwSizeMin);
  668. #endif
  669. fFirst = FALSE;
  670. }
  671. #if 0
  672. /* If this wasn't the first frame, save up any extra space for later */
  673. if (dwSize < dwMaxSizeThisFrame && lFrameCurrent > 0) {
  674. dwSaved += dwMaxSizeThisFrame - dwSize;
  675. if (fPad) {
  676. dwSaved -= ((dwMaxSizeThisFrame - dwSize) % 2048L);
  677. }
  678. // HACK: limit this, so it doesn't get too big!!!
  679. if (dwSaved > 32768L)
  680. dwSaved = 32768L;
  681. if (dwSaved > dwMaxSizeThisFrame * 5)
  682. dwSaved = dwMaxSizeThisFrame * 5;
  683. }
  684. #endif
  685. if (dw != ICERR_OK) {
  686. if (dw == ICERR_BADFORMAT)
  687. return AVIERR_BADFORMAT;
  688. else
  689. return AVIERR_INTERNAL;
  690. }
  691. if (dwFlags & AVIIF_KEYFRAME) {
  692. lLastKeyFrame = lFrameCurrent;
  693. }
  694. //
  695. // remember the quality that worked, it will be the best guess next time.
  696. //
  697. dwQualityLast = dwQuality;
  698. //
  699. // decompress the image into the offscreen buffer, for use next time.
  700. //
  701. if (dwKeyFrameEvery != 1 && lpbiU) {
  702. dw = ICDecompress(hic, 0,
  703. lpbiC,lpC,
  704. lpbiU,lpU);
  705. // !!! error check?
  706. }
  707. //
  708. // return the dwFlags and ckid, by stuffing them in the stream info.
  709. //
  710. m_ckid = ckid;
  711. m_dwFlags = dwFlags;
  712. return AVIERR_OK;
  713. }
  714. /**************************************************************************
  715. * @doc INTERNAL DRAWDIB
  716. *
  717. * @api BOOL | DibEq | This function compares two dibs.
  718. *
  719. * @parm LPBITMAPINFOHEADER lpbi1 | Pointer to one bitmap.
  720. * this DIB is assumed to have the colors after the BITMAPINFOHEADER
  721. *
  722. * @parm LPBITMAPINFOHEADER | lpbi2 | Pointer to second bitmap.
  723. * this DIB is assumed to have the colors after biSize bytes.
  724. *
  725. * @rdesc Returns TRUE if bitmaps are identical, FALSE otherwise.
  726. *
  727. **************************************************************************/
  728. inline BOOL DibEq(LPBITMAPINFOHEADER lpbi1, LPBITMAPINFOHEADER lpbi2)
  729. {
  730. return
  731. lpbi1->biCompression == lpbi2->biCompression &&
  732. lpbi1->biSize == lpbi2->biSize &&
  733. lpbi1->biWidth == lpbi2->biWidth &&
  734. lpbi1->biHeight == lpbi2->biHeight &&
  735. lpbi1->biBitCount == lpbi2->biBitCount;
  736. }
  737. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::SetFormat(LONG lPos,LPVOID lpFormat,LONG cbFormat)
  738. {
  739. CAVICmpStream FAR * pinst = m_pAVIStream;
  740. LONG lRet = AVIERR_OK;
  741. HRESULT hr;
  742. LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER) lpFormat;
  743. DWORD dw;
  744. if (pinst->pgf)
  745. return ResultFromScode(AVIERR_UNSUPPORTED);
  746. if (lpbi->biCompression != BI_RGB)
  747. return ResultFromScode(AVIERR_UNSUPPORTED);
  748. if (pinst->avistream.fccHandler == comptypeDIB)
  749. goto exit;
  750. if (pinst->lpFormatOrig) {
  751. if ((cbFormat = pinst->cbFormatOrig) &&
  752. (_fmemcmp(pinst->lpFormatOrig, lpFormat, (int) cbFormat) == 0))
  753. return AVIERR_OK;
  754. DPF("AVICmprs: SetFormat when format already set!\n");
  755. }
  756. //
  757. // Can only currently set the palette at the end of the file
  758. //
  759. if (lPos < (LONG) (pinst->avistream.dwStart + pinst->avistream.dwLength))
  760. return ResultFromScode(AVIERR_UNSUPPORTED);
  761. if (pinst->lpFormatOrig) {
  762. //
  763. // We can only change the palette for things with palettes....
  764. //
  765. if (lpbi->biBitCount > 8 || lpbi->biClrUsed == 0)
  766. return ResultFromScode(AVIERR_UNSUPPORTED);
  767. //
  768. // Be sure only the palette is changing, nothing else....
  769. //
  770. if (cbFormat != pinst->cbFormatOrig)
  771. return ResultFromScode(AVIERR_UNSUPPORTED);
  772. if (!DibEq((LPBITMAPINFOHEADER) lpFormat,
  773. (LPBITMAPINFOHEADER) pinst->lpFormatOrig))
  774. return ResultFromScode(AVIERR_UNSUPPORTED);
  775. dw = ICCompressGetFormat(pinst->hic, lpFormat, pinst->lpFormat);
  776. if ((LONG) dw < 0)
  777. goto ic_error;
  778. ICCompressEnd(pinst->hic);
  779. dw = ICCompressBegin(pinst->hic, lpFormat, pinst->lpFormat);
  780. if (dw != ICERR_OK)
  781. goto ic_error;
  782. if (pinst->dwKeyFrameEvery != 1 && pinst->lpbiU) {
  783. ICDecompressEnd(pinst->hic);
  784. dw = ICDecompressGetFormat(pinst->hic, pinst->lpFormat, pinst->lpbiU);
  785. if ((LONG) dw < 0)
  786. goto ic_error;
  787. dw = ICDecompressBegin(pinst->hic, pinst->lpFormat, pinst->lpbiU);
  788. if (dw != ICERR_OK)
  789. goto ic_error;
  790. }
  791. goto setformatandexit;
  792. }
  793. pinst->lpFormatOrig = (LPBITMAPINFOHEADER)
  794. GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, cbFormat);
  795. pinst->cbFormatOrig = cbFormat;
  796. if (!pinst->lpFormatOrig) {
  797. lRet = AVIERR_MEMORY;
  798. goto exit;
  799. }
  800. hmemcpy(pinst->lpFormatOrig, lpFormat, cbFormat);
  801. /*
  802. ** get the size requied to hold the format.
  803. */
  804. dw = ICCompressGetFormatSize(pinst->hic, lpFormat);
  805. if ((LONG) dw < sizeof(BITMAPINFOHEADER))
  806. goto ic_error;
  807. pinst->cbFormat = dw;
  808. pinst->lpFormat = (LPBITMAPINFOHEADER) GlobalAllocPtr(GHND | GMEM_SHARE, pinst->cbFormat);
  809. if (!pinst->lpFormat) {
  810. lRet = AVIERR_MEMORY;
  811. goto exit;
  812. }
  813. /*
  814. ** get the compressed format from the compressor.
  815. */
  816. dw = ICCompressGetFormat(pinst->hic, lpFormat, pinst->lpFormat);
  817. if ((LONG) dw < 0)
  818. goto ic_error;
  819. pinst->avistream.rcFrame.right = pinst->avistream.rcFrame.left +
  820. (int) pinst->lpFormat->biWidth;
  821. pinst->avistream.rcFrame.bottom = pinst->avistream.rcFrame.top +
  822. (int) pinst->lpFormat->biHeight;
  823. dw = ICCompressBegin(pinst->hic, lpFormat, pinst->lpFormat);
  824. if (dw != ICERR_OK)
  825. goto ic_error;
  826. /*
  827. ** allocate buffer to hold compressed data.
  828. */
  829. dw = ICCompressGetSize(pinst->hic, lpFormat, pinst->lpFormat);
  830. pinst->lpbiC = (LPBITMAPINFOHEADER)
  831. GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, pinst->cbFormat + dw);
  832. if (!pinst->lpbiC) {
  833. lRet = AVIERR_MEMORY;
  834. goto exit;
  835. }
  836. hmemcpy((LPVOID)pinst->lpbiC, pinst->lpFormat, pinst->cbFormat);
  837. pinst->lpC = (LPSTR) pinst->lpbiC + pinst->lpbiC->biSize +
  838. pinst->lpbiC->biClrUsed * sizeof(RGBQUAD);
  839. //
  840. // check for temporal compress, and alocate a previous
  841. // DIB buffer if needed
  842. //
  843. if (pinst->dwKeyFrameEvery != 1) {
  844. pinst->lpbiU = (LPBITMAPINFOHEADER)
  845. GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  846. sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
  847. if (!pinst->lpbiU) {
  848. lRet = AVIERR_MEMORY;
  849. goto exit;
  850. }
  851. dw = ICDecompressGetFormat(pinst->hic, pinst->lpFormat, pinst->lpbiU);
  852. if ((LONG) dw < 0)
  853. goto ic_error;
  854. if (pinst->lpbiU->biSizeImage == 0)
  855. pinst->lpbiU->biSizeImage = pinst->lpbiU->biHeight *
  856. DIBWIDTHBYTES(*pinst->lpbiU);
  857. pinst->lpbiU = (LPBITMAPINFOHEADER)
  858. GlobalReAllocPtr(pinst->lpbiU,
  859. pinst->lpbiU->biSize +
  860. pinst->lpbiU->biClrUsed * sizeof(RGBQUAD) +
  861. pinst->lpbiU->biSizeImage,
  862. GMEM_MOVEABLE | GMEM_SHARE);
  863. if (!pinst->lpbiU) {
  864. lRet = AVIERR_MEMORY;
  865. goto exit;
  866. }
  867. pinst->lpU = (LPSTR) pinst->lpbiU + pinst->lpbiU->biSize +
  868. pinst->lpbiU->biClrUsed * sizeof(RGBQUAD);
  869. dw = ICDecompressBegin(pinst->hic, pinst->lpFormat, pinst->lpbiU);
  870. if (dw != ICERR_OK)
  871. goto ic_error;
  872. }
  873. setformatandexit:
  874. hr = AVIStreamSetFormat(pinst->pavi, lPos,
  875. pinst->lpFormat, pinst->cbFormat);
  876. if (hr != NOERROR)
  877. return hr;
  878. exit:
  879. if (lRet != AVIERR_OK)
  880. // Clean up before returning...
  881. ;
  882. return ResultFromScode(lRet);
  883. ic_error:
  884. if (dw == ICERR_BADFORMAT)
  885. lRet = AVIERR_BADFORMAT;
  886. else if (dw == ICERR_MEMORY)
  887. lRet = AVIERR_MEMORY;
  888. else
  889. lRet = AVIERR_INTERNAL;
  890. goto exit;
  891. }
  892. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Write(LONG lStart,
  893. LONG lSamples,
  894. LPVOID lpBuffer,
  895. LONG cbBuffer,
  896. DWORD dwFlags,
  897. LONG FAR *plSampWritten,
  898. LONG FAR *plBytesWritten)
  899. {
  900. CAVICmpStream FAR * pinst = m_pAVIStream;
  901. LONG lRet;
  902. if (pinst->pgf)
  903. return ResultFromScode(AVIERR_UNSUPPORTED);
  904. if (lStart < (LONG) (pinst->avistream.dwStart + pinst->avistream.dwLength))
  905. return ResultFromScode(AVIERR_UNSUPPORTED);
  906. if (lSamples > 1)
  907. return ResultFromScode(AVIERR_UNSUPPORTED);
  908. pinst->lFrameCurrent = lStart;
  909. if (pinst->avistream.fccHandler == comptypeDIB) {
  910. dwFlags |= AVIIF_KEYFRAME;
  911. } else {
  912. lRet = pinst->ICCrunch(pinst->lpFormatOrig, lpBuffer);
  913. if (lRet != AVIERR_OK)
  914. return ResultFromScode(lRet);
  915. lpBuffer = pinst->lpC;
  916. cbBuffer = pinst->lpbiC->biSizeImage;
  917. dwFlags = pinst->lLastKeyFrame == lStart ? AVIIF_KEYFRAME : 0;
  918. }
  919. return AVIStreamWrite(pinst->pavi,
  920. lStart,
  921. lSamples,
  922. lpBuffer,
  923. cbBuffer,
  924. dwFlags,
  925. plSampWritten,
  926. plBytesWritten);
  927. }
  928. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Delete(LONG lStart,LONG lSamples)
  929. {
  930. CAVICmpStream FAR * pinst = m_pAVIStream;
  931. return ResultFromScode(AVIERR_UNSUPPORTED);
  932. }
  933. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::ReadData(DWORD fcc, LPVOID lp, LONG FAR *lpcb)
  934. {
  935. CAVICmpStream FAR * pinst = m_pAVIStream;
  936. // Don't pass through 'strd' data!
  937. if (fcc == ckidSTREAMHANDLERDATA) {
  938. if (pinst->cbHandler) {
  939. hmemcpy(lp, pinst->lpHandler, min(*lpcb, pinst->cbHandler));
  940. }
  941. *lpcb = pinst->cbHandler;
  942. return AVIERR_OK;
  943. }
  944. return AVIStreamReadData(pinst->pavi, fcc, lp, lpcb);
  945. }
  946. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::WriteData(DWORD fcc, LPVOID lp, LONG cb)
  947. {
  948. CAVICmpStream FAR * pinst = m_pAVIStream;
  949. return ResultFromScode(AVIERR_UNSUPPORTED);
  950. }
  951. #if 0
  952. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Clone(PAVISTREAM FAR * ppaviNew)
  953. {
  954. CAVICmpStream FAR * pinst = m_pAVIStream;
  955. return ResultFromScode(AVIERR_UNSUPPORTED);
  956. }
  957. #endif
  958. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Reserved1(void)
  959. {
  960. return ResultFromScode(AVIERR_UNSUPPORTED);
  961. }
  962. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Reserved2(void)
  963. {
  964. return ResultFromScode(AVIERR_UNSUPPORTED);
  965. }
  966. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Reserved3(void)
  967. {
  968. return ResultFromScode(AVIERR_UNSUPPORTED);
  969. }
  970. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Reserved4(void)
  971. {
  972. return ResultFromScode(AVIERR_UNSUPPORTED);
  973. }
  974. STDMETHODIMP CAVICmpStream::CAVICmpStreamImpl::Reserved5(void)
  975. {
  976. return ResultFromScode(AVIERR_UNSUPPORTED);
  977. }