Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1333 lines
36 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1991-1995. All rights reserved.
  3. Title: avidraw.c - Functions that actually draw video for AVI.
  4. *****************************************************************************/
  5. #include "graphic.h"
  6. //
  7. // if the average key frame spacing is greater than this value, always
  8. // force a buffer.
  9. //
  10. #define KEYFRAME_PANIC_SPACE 2500
  11. #define YIELDATFUNNYTIMES
  12. #define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
  13. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  14. #define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  15. #ifdef _WIN32
  16. #define LockCurrentTask(x) (x)
  17. #else
  18. extern FAR PASCAL LockCurrentTask(BOOL);
  19. #endif
  20. BOOL NEAR PASCAL DrawBits(NPMCIGRAPHIC npMCI, DWORD ckid, DWORD cksize, BOOL fHurryUp);
  21. void NEAR PASCAL UpdateDisplayDibPalette(NPMCIGRAPHIC npMCI);
  22. BOOL NEAR PASCAL ProcessPaletteChange(NPMCIGRAPHIC npMCI, DWORD cksize)
  23. {
  24. UINT wStartIndex;
  25. UINT wNumEntries;
  26. UINT w;
  27. LPPALETTEENTRY ppe;
  28. npMCI->dwFlags |= MCIAVI_PALCHANGED;
  29. DPF2(("Setting PALCHANGED\n"));
  30. while (cksize > 4) {
  31. wStartIndex = GET_BYTE();
  32. wNumEntries = GET_BYTE();
  33. /* Skip filler word */
  34. GET_WORD();
  35. /* Zero is used as a shorthand for 256 */
  36. if (wNumEntries == 0)
  37. wNumEntries = 256;
  38. ppe = (LPVOID)npMCI->lp;
  39. for (w=0; w<wNumEntries; w++)
  40. {
  41. npMCI->argb[wStartIndex+w].rgbRed = ppe[w].peRed;
  42. npMCI->argb[wStartIndex+w].rgbGreen = ppe[w].peGreen;
  43. npMCI->argb[wStartIndex+w].rgbBlue = ppe[w].peBlue;
  44. }
  45. SKIP_BYTES(wNumEntries * sizeof(PALETTEENTRY));
  46. cksize -= 4 + wNumEntries * sizeof(PALETTEENTRY);
  47. }
  48. if (npMCI->pbiFormat->biBitCount == 8) {
  49. hmemcpy((LPBYTE) npMCI->pbiFormat + npMCI->pbiFormat->biSize,
  50. (LPBYTE) npMCI->argb,
  51. sizeof(RGBQUAD) * npMCI->pbiFormat->biClrUsed);
  52. }
  53. #ifdef DEBUG
  54. /* Make sure we've used up the entire chunk... */
  55. if (cksize != 0) {
  56. DPF(("Problem with palc chunk\n"));
  57. }
  58. #endif
  59. return TRUE;
  60. }
  61. /* Display the video from the current record.
  62. */
  63. BOOL NEAR PASCAL DisplayVideoFrame(NPMCIGRAPHIC npMCI, BOOL fHurryUp)
  64. {
  65. DWORD ckid;
  66. DWORD cksize;
  67. BOOL fRet;
  68. int stream;
  69. DWORD dwRet;
  70. LONG len;
  71. DWORD dwDrawStart;
  72. LPVOID lpSave;
  73. LPVOID lpChunk;
  74. /* If we're allowed to skip frames, apply some relatively
  75. ** bogus heuristics to decide if we should do it, and
  76. ** pass the appropriate flag on to the driver.
  77. */
  78. if ((npMCI->lCurrentFrame & 0x0f) == 0) {
  79. fHurryUp = FALSE;
  80. }
  81. /* Even if SKIPFRAMES is off, count how many frames we _would_ have
  82. ** skipped if we could.
  83. */
  84. if (fHurryUp)
  85. ++npMCI->dwSkippedFrames;
  86. if (!(npMCI->dwOptionFlags & MCIAVIO_SKIPFRAMES))
  87. fHurryUp = FALSE;
  88. /* Keep track of what we've drawn. */
  89. npMCI->lFrameDrawn = npMCI->lCurrentFrame;
  90. len = (LONG)npMCI->dwThisRecordSize;
  91. lpSave = npMCI->lp;
  92. /* If it's interleaved, adjust for the next record header.... */
  93. // !!! Only if not last frame?
  94. if (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED)
  95. len -= 3 * sizeof(DWORD);
  96. while (len >= 2 * sizeof(DWORD)) {
  97. /* Look at the next chunk */
  98. ckid = GET_DWORD();
  99. cksize = GET_DWORD();
  100. DPF3(("'Chunk %.4s': %lu bytes\n", (LPSTR) &ckid, cksize));
  101. if ((LONG) cksize > len) {
  102. AssertSz(FALSE, "Chunk obviously too big!");
  103. break;
  104. }
  105. len -= ((cksize+1)&~1) + 8;
  106. if (len < -1) {
  107. AssertSz(FALSE, "Chunk overflowed what was read in!");
  108. break;
  109. }
  110. lpChunk = npMCI->lp;
  111. stream = StreamFromFOURCC(ckid);
  112. if (stream == npMCI->nVideoStream) {
  113. if ((npMCI->lCurrentFrame < npMCI->lVideoStart) &&
  114. !(npMCI->dwFlags & MCIAVI_REVERSE))
  115. goto skip;
  116. switch(TWOCCFromFOURCC(ckid)) {
  117. case cktypePALchange:
  118. ProcessPaletteChange(npMCI, cksize);
  119. npMCI->lLastPaletteChange = npMCI->lCurrentFrame;
  120. break;
  121. default:
  122. /* Some other chunk... */
  123. if (!fHurryUp && ckid) {
  124. dwDrawStart = timeGetTime();
  125. }
  126. //!!! we need to handle half frames!!!
  127. fRet = DrawBits(npMCI, ckid, cksize, fHurryUp);
  128. if (!fRet)
  129. return FALSE;
  130. if (npMCI->dwBufferedVideo)
  131. npMCI->dwLastDrawTime = 0;
  132. else
  133. if (!fHurryUp && ckid) {
  134. npMCI->dwLastDrawTime = timeGetTime() - dwDrawStart;
  135. }
  136. break;
  137. }
  138. } else if (stream >= 0 && stream < npMCI->streams &&
  139. SI(stream)->hicDraw) {
  140. dwRet = ICDraw(SI(stream)->hicDraw, (fHurryUp ? ICDRAW_HURRYUP : 0L),
  141. SI(stream)->lpFormat,
  142. (ckid == 0) ? 0L : npMCI->lp, cksize, npMCI->lCurrentFrame);
  143. // !!! Error check?
  144. }
  145. skip:
  146. /* If not interleaved, we're done. */
  147. if (npMCI->wPlaybackAlg != MCIAVI_ALG_INTERLEAVED)
  148. return TRUE;
  149. /* Skip to the next chunk */
  150. npMCI->lp = (HPSTR) lpChunk + ((cksize+1)&~1);
  151. }
  152. npMCI->lp = lpSave;
  153. return TRUE;
  154. }
  155. //
  156. // mark all streams in the passed RECT as dirty
  157. //
  158. void NEAR PASCAL StreamInvalidate(NPMCIGRAPHIC npMCI, LPRECT prc)
  159. {
  160. int i;
  161. int n;
  162. STREAMINFO *psi;
  163. RECT rc;
  164. if (prc)
  165. DPF2(("StreamInvalidate: [%d, %d, %d, %d]\n", *prc));
  166. else
  167. DPF2(("StreamInvalidate: NULL\n", *prc));
  168. for (n=i=0; i<npMCI->streams; i++) {
  169. psi = SI(i);
  170. // we always update any visible error streams
  171. if (!(psi->dwFlags & STREAM_ERROR) &&
  172. !(psi->dwFlags & STREAM_ENABLED))
  173. continue;
  174. if (IsRectEmpty(&psi->rcDest))
  175. continue;
  176. if (prc && !IntersectRect(&rc, prc, &psi->rcDest))
  177. continue;
  178. n++;
  179. psi->dwFlags |= STREAM_NEEDUPDATE;
  180. }
  181. //
  182. // !!!is this right? or should we always dirty the movie?
  183. //
  184. if (n > 0)
  185. npMCI->dwFlags |= MCIAVI_NEEDUPDATE;
  186. else
  187. npMCI->dwFlags &= ~MCIAVI_NEEDUPDATE;
  188. }
  189. //
  190. // update all dirty streams
  191. //
  192. // if fPaint is set paint the area even if the stream handler does not
  193. //
  194. BOOL NEAR PASCAL DoStreamUpdate(NPMCIGRAPHIC npMCI, BOOL fPaint)
  195. {
  196. int i;
  197. BOOL f=TRUE;
  198. STREAMINFO *psi;
  199. // This routine is called on both the winproc and worker threads
  200. EnterHDCCrit(npMCI); // Protect hdc use/changes
  201. Assert(npMCI->hdc);
  202. SaveDC(npMCI->hdc);
  203. for (i=0; i<npMCI->streams; i++) {
  204. psi = SI(i);
  205. //
  206. // this stream is clean, dont paint it.
  207. //
  208. if (!(psi->dwFlags & (STREAM_DIRTY|STREAM_NEEDUPDATE))) {
  209. ExcludeClipRect(npMCI->hdc,
  210. DEST(i).left,DEST(i).top,DEST(i).right,DEST(i).bottom);
  211. continue;
  212. }
  213. psi->dwFlags &= ~STREAM_NEEDUPDATE;
  214. psi->dwFlags &= ~STREAM_DIRTY;
  215. if (psi->dwFlags & STREAM_ERROR) {
  216. UINT u, cb;
  217. TCHAR ach[80];
  218. TCHAR szMessage[80];
  219. HBRUSH hbr = CreateHatchBrush(HS_BDIAGONAL, RGB(128,0,0));
  220. if (psi->sh.fccType == streamtypeVIDEO)
  221. LoadString(ghModule, MCIAVI_CANT_DRAW_VIDEO, ach, NUMELMS(ach));
  222. else
  223. LoadString(ghModule, MCIAVI_CANT_DRAW_STREAM, ach, NUMELMS(ach));
  224. FillRect(npMCI->hdc, &DEST(i), hbr);
  225. u = SetBkMode(npMCI->hdc, OPAQUE);
  226. cb = wsprintf(szMessage, ach,
  227. (LPVOID)&psi->sh.fccType,
  228. (LPVOID)&psi->sh.fccHandler);
  229. DrawText(npMCI->hdc, szMessage, cb, &DEST(i),
  230. DT_NOPREFIX|DT_WORDBREAK|DT_VCENTER|DT_CENTER);
  231. SetBkMode(npMCI->hdc, u);
  232. DeleteObject(hbr);
  233. FrameRect(npMCI->hdc, &DEST(i), GetStockObject(BLACK_BRUSH));
  234. }
  235. else if (!(psi->dwFlags & STREAM_ENABLED)) {
  236. FillRect(npMCI->hdc, &DEST(i), GetStockObject(DKGRAY_BRUSH));
  237. }
  238. else if (psi->sh.fccType == streamtypeVIDEO &&
  239. !(npMCI->dwFlags & MCIAVI_SHOWVIDEO)) {
  240. continue; // we will paint black here.
  241. }
  242. else if (npMCI->nVideoStreams > 0 && i == npMCI->nVideoStream) {
  243. BOOL fDraw;
  244. try {
  245. fDraw = DrawBits(npMCI, 0L, 0L, FALSE);
  246. } except (EXCEPTION_EXECUTE_HANDLER) {
  247. fDraw = FALSE;
  248. }
  249. if (!fDraw) {
  250. psi->dwFlags |= STREAM_NEEDUPDATE;
  251. f = FALSE;
  252. if (fPaint) // will paint back if told to.
  253. continue;
  254. }
  255. }
  256. else if (psi->hicDraw == NULL) {
  257. FillRect(npMCI->hdc, &DEST(i), GetStockObject(DKGRAY_BRUSH));
  258. }
  259. else if (ICDraw(psi->hicDraw,ICDRAW_UPDATE,psi->lpFormat,NULL,0,0) != 0) {
  260. psi->dwFlags |= STREAM_NEEDUPDATE;
  261. f = FALSE;
  262. // should other streams work like this?
  263. if (fPaint) // will paint back if told to.
  264. continue;
  265. }
  266. //
  267. // we painted so clean this area
  268. //
  269. ExcludeClipRect(npMCI->hdc,
  270. DEST(i).left,DEST(i).top,DEST(i).right,DEST(i).bottom);
  271. }
  272. // now paint black every where else
  273. FillRect(npMCI->hdc,&npMCI->rcDest,GetStockObject(BLACK_BRUSH));
  274. RestoreDC(npMCI->hdc, -1);
  275. LeaveHDCCrit(npMCI);
  276. //
  277. // do we still still need a update?
  278. //
  279. if (f) {
  280. npMCI->dwFlags &= ~MCIAVI_NEEDUPDATE;
  281. }
  282. else {
  283. DPF2(("StreamUpdate: update failed\n"));
  284. npMCI->dwFlags |= MCIAVI_NEEDUPDATE;
  285. }
  286. return f;
  287. }
  288. #ifdef _WIN32
  289. #define DWORG POINT
  290. #define GETDCORG(hdc, dwOrg) GetDCOrgEx(hdc, &dwOrg)
  291. #else
  292. #define DWORG DWORD
  293. #define GETDCORG(hdc, dwOrg) dwOrg = GetDCOrg(hdc)
  294. #endif
  295. #ifdef DAYTONA
  296. #define AlignPlaybackWindow(npMCI)
  297. #else
  298. STATICFN void NEAR PASCAL AlignPlaybackWindow(NPMCIGRAPHIC npMCI)
  299. {
  300. DWORG dw;
  301. int x,y;
  302. HWND hwnd; // the window we will move.
  303. RECT rc;
  304. // if (npMCI->hicDraw != npMCI->hicDrawInternal)
  305. // return; !!! only align if using the default draw guy?
  306. #pragma message("**** move this into the draw handler and/or DrawDib")
  307. #pragma message("**** we need to query the alignment from the codec????")
  308. #define X_ALIGN 4
  309. #define Y_ALIGN 4
  310. // the MCIAVI_RELEASEDC flags means the DC came from a GetDC(npMCI->hwnd)
  311. if (!(npMCI->dwFlags & MCIAVI_RELEASEDC)) {
  312. DPF0(("Align: MCIAVI_RELEASEDC\n"));
  313. return;
  314. }
  315. //
  316. // dont align if the dest rect is not at 0,0
  317. //
  318. if (npMCI->rcMovie.left != 0 || npMCI->rcMovie.top != 0) {
  319. DPF0(("Align: not at 0,0\n"));
  320. return;
  321. }
  322. GETDCORG(npMCI->hdc, dw);
  323. #ifdef _WIN32
  324. x = dw.x + npMCI->rcMovie.left;
  325. y = dw.y + npMCI->rcMovie.top;
  326. #else
  327. x = LOWORD(dw) + npMCI->rcMovie.left;
  328. y = HIWORD(dw) + npMCI->rcMovie.top;
  329. #endif
  330. if ((x & (X_ALIGN-1)) || (y & (Y_ALIGN-1)))
  331. {
  332. DPF0(("*** warning movie is not aligned! (%d,%d)***\n",x,y));
  333. //
  334. // find the first moveable window walking up the tree.
  335. //
  336. for (hwnd = npMCI->hwndPlayback; hwnd; hwnd = GetParent(hwnd))
  337. {
  338. LONG l = GetWindowLong(hwnd, GWL_STYLE);
  339. // this window is toplevel stop
  340. if (!(l & WS_CHILD))
  341. break;
  342. // this window is sizeable (should be movable too)
  343. if (l & WS_THICKFRAME)
  344. break;
  345. // this window has a caption (is moveable)
  346. if ((l & WS_CAPTION) == WS_CAPTION)
  347. break;
  348. }
  349. //
  350. // dont move the window if it does not want to be moved.
  351. //
  352. if (IsWindowVisible(hwnd) &&
  353. !IsZoomed(hwnd) &&
  354. !IsIconic(hwnd) &&
  355. IsWindowEnabled(hwnd))
  356. {
  357. GetClientRect(hwnd, &rc);
  358. ClientToScreen(hwnd, (LPPOINT)&rc);
  359. //
  360. // if the movie is not in the upper corner of the window
  361. // don't align
  362. //
  363. if (x < rc.left || x-rc.left > 16 ||
  364. y < rc.top || y-rc.top > 16)
  365. return;
  366. GetWindowRect(hwnd, &rc);
  367. OffsetRect(&rc, -(x & (X_ALIGN-1)), -(y & (Y_ALIGN-1)));
  368. if (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
  369. ScreenToClient(GetParent(hwnd), (LPPOINT)&rc);
  370. // dont move window off the screen.
  371. if (rc.left < 0 || rc.top < 0) {
  372. DPF0(("Align: not off the screen\n"));
  373. return;
  374. }
  375. DPF0(("*** moving window to [%d,%d,%d,%d]\n",rc));
  376. // We must relinquish the critical section before moving the
  377. // window otherwise the WinProc thread will not run
  378. LeaveWinCrit(npMCI);
  379. SetWindowPos(hwnd,NULL,rc.left,rc.top,0,0,
  380. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
  381. EnterWinCrit(npMCI);
  382. DPF0(("Align: window moved\n"));
  383. #ifdef _WIN32
  384. // with fulldrag the window may move again between setting the
  385. // position and checking here that it is aligned. Do NOT assert...
  386. return;
  387. #endif
  388. #ifdef DEBUG
  389. GETDCORG(npMCI->hdc, dw);
  390. #ifdef _WIN32
  391. x = dw.x + npMCI->rcMovie.left;
  392. y = dw.y + npMCI->rcMovie.top;
  393. #else
  394. x = LOWORD(dw) + npMCI->rcMovie.left;
  395. y = HIWORD(dw) + npMCI->rcMovie.top;
  396. #endif
  397. Assert(!(x & (X_ALIGN-1)) && !(y & (Y_ALIGN-1)));
  398. #endif
  399. }
  400. } else {
  401. DPF0(("Aligning playback window - no movement\n"));
  402. }
  403. }
  404. #endif
  405. UINT NEAR PASCAL PrepareDC(NPMCIGRAPHIC npMCI)
  406. {
  407. UINT u;
  408. int i;
  409. STREAMINFO *psi;
  410. HDCCritCheckIn(npMCI);
  411. DPF2(("*** PrepareDC(%04X)\n",npMCI->hdc));
  412. // If we simply
  413. // Assert(npMCI->hdc != NULL);
  414. // and the assertion fails a message box appears. Message boxes allow
  415. // processing to continue. In all likelihood the avi will need repainting, and
  416. // a WM_PAINT (or a palette change) will cause GraphicWndProc to wake up while the
  417. // assertion is being displayed. This will only add to the confusion.
  418. if (npMCI->hdc == NULL) {
  419. DPF0(("** NULL hdc from PrepareDC **\n"));
  420. return 0;
  421. }
  422. if (!(npMCI->dwFlags & MCIAVI_FULLSCREEN) &&
  423. !(npMCI->dwFlags & MCIAVI_SEEKING) &&
  424. !(npMCI->dwFlags & MCIAVI_UPDATING) &&
  425. (npMCI->dwFlags & MCIAVI_SHOWVIDEO) ) {
  426. AlignPlaybackWindow(npMCI);
  427. }
  428. if (npMCI->hicDraw) {
  429. DPF2(("Calling ICDrawRealize\n"));
  430. u = (UINT)ICDrawRealize(npMCI->hicDraw, npMCI->hdc, npMCI->fForceBackground);
  431. } else {
  432. u = 0;
  433. }
  434. //
  435. // realize the other strems, but force them into the background.
  436. //
  437. for (i=0; i<npMCI->streams; i++) {
  438. psi = SI(i);
  439. if (!(psi->dwFlags & STREAM_ENABLED))
  440. continue;
  441. if (psi->dwFlags & STREAM_ERROR)
  442. continue;
  443. if (psi == npMCI->psiVideo)
  444. continue;
  445. if (psi->hicDraw == NULL)
  446. continue;
  447. if (psi->hicDraw == npMCI->hicDraw)
  448. continue;
  449. ICDrawRealize(psi->hicDraw, npMCI->hdc, TRUE);
  450. }
  451. //
  452. // return "master" stream realize value.
  453. //
  454. return u;
  455. }
  456. void NEAR PASCAL UnprepareDC(NPMCIGRAPHIC npMCI)
  457. {
  458. Assert(npMCI->hdc);
  459. DPF2(("*** UnprepareDC(%04X)\n",npMCI->hdc));
  460. SelectPalette(npMCI->hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
  461. RealizePalette(npMCI->hdc);
  462. //RestoreDC(npMCI->hdc, -1);
  463. }
  464. /* This function is called to actually handle drawing.
  465. **
  466. ** ckid and cksize specify the type and size of the data to be drawn;
  467. ** it's located at npMCI->lp.
  468. **
  469. ** If the fHurryUp flag is set, that means that we're behind and we
  470. ** shouldn't draw now. all we do it update the current buffered image
  471. ** and return...
  472. */
  473. BOOL NEAR PASCAL DrawBits(NPMCIGRAPHIC npMCI, DWORD ckid, DWORD cksize, BOOL fHurryUp)
  474. {
  475. LPVOID lp = npMCI->lp;
  476. LPBITMAPINFOHEADER lpFormat = npMCI->pbiFormat;
  477. DWORD dwRet;
  478. DWORD dwFlags;
  479. STREAMINFO *psi;
  480. if (!npMCI->pbiFormat)
  481. return TRUE;
  482. if (npMCI->fNoDrawing || !(npMCI->dwFlags & MCIAVI_SHOWVIDEO))
  483. return TRUE;
  484. psi = SI(npMCI->nVideoStream);
  485. //
  486. // let's compute the flags we need to pass to ICDecompress() and
  487. // to ICDraw()
  488. //
  489. // ICDRAW_HURRYUP - we are behind
  490. // ICDRAW_PREROLL - we are seeking (before a play)
  491. // ICDRAW_UPDATE - update of frame (repaint, ...)
  492. // ICDRAW_NOTKEYFRAME - this frame data is not a key.
  493. //
  494. dwFlags = 0;
  495. if (psi->dwFlags & STREAM_NEEDUPDATE)
  496. dwFlags |= ICDRAW_UPDATE;
  497. if (cksize == 0)
  498. dwFlags |= ICDRAW_NULLFRAME;
  499. if (ckid == 0) {
  500. dwFlags |= ICDRAW_UPDATE;
  501. lp = 0;
  502. }
  503. else if (fHurryUp) {
  504. dwFlags |= ICDRAW_HURRYUP;
  505. psi->dwFlags |= STREAM_DIRTY;
  506. }
  507. else if (!(npMCI->dwFlags & MCIAVI_REVERSE) &&
  508. (npMCI->lCurrentFrame < npMCI->lRealStart)) {
  509. dwFlags |= ICDRAW_PREROLL;
  510. psi->dwFlags |= STREAM_DIRTY;
  511. }
  512. if (npMCI->hpFrameIndex) {
  513. if ((ckid == 0L || cksize == 0) ||
  514. FramePrevKey(npMCI->lCurrentFrame) != npMCI->lCurrentFrame)
  515. dwFlags |= ICDRAW_NOTKEYFRAME;
  516. }
  517. //
  518. // now draw the frame, decompress first if needed.
  519. //
  520. if (npMCI->hic) {
  521. if (ckid != 0L && cksize != 0) {
  522. TIMESTART(timeDecompress);
  523. npMCI->pbiFormat->biSizeImage = cksize; // !!! Is this safe?
  524. dwRet = ICDecompress(npMCI->hic,
  525. dwFlags,
  526. npMCI->pbiFormat,
  527. npMCI->lp,
  528. &npMCI->bih,
  529. npMCI->hpDecompress);
  530. TIMEEND(timeDecompress);
  531. if (dwRet == ICERR_DONTDRAW) {
  532. return TRUE; // !!!???
  533. }
  534. // ICERR_NEWPALETTE?
  535. dwFlags &= (~ICDRAW_NOTKEYFRAME); // It's a key frame now....
  536. }
  537. if (dwFlags & (ICDRAW_HURRYUP|ICDRAW_PREROLL))
  538. return TRUE;
  539. lpFormat = &npMCI->bih;
  540. lp = npMCI->hpDecompress;
  541. cksize = npMCI->bih.biSizeImage;
  542. }
  543. TIMESTART(timeDraw);
  544. if ((npMCI->dwFlags & MCIAVI_PALCHANGED) &&
  545. !(dwFlags & (ICDRAW_HURRYUP|ICDRAW_PREROLL))) {
  546. #ifdef USEAVIFILE
  547. if (psi->ps) {
  548. if (npMCI->hic) {
  549. //!!! should be psi->lpFormat *not* npMCI->pbiFormat
  550. ICDecompressGetPalette(npMCI->hic, npMCI->pbiFormat, &npMCI->bih);
  551. ICDrawChangePalette(npMCI->hicDraw, &npMCI->bih);
  552. }
  553. else {
  554. ICDrawChangePalette(npMCI->hicDraw, npMCI->pbiFormat);
  555. }
  556. }
  557. else
  558. #endif
  559. {
  560. DPF2(("Calling ICDrawChangePalette\n"));
  561. ICDrawChangePalette(npMCI->hicDraw, &npMCI->bih);
  562. }
  563. npMCI->dwFlags &= ~(MCIAVI_PALCHANGED);
  564. dwFlags &= ~ICDRAW_HURRYUP; // should realy draw this!
  565. }
  566. if ((npMCI->dwFlags & MCIAVI_SEEKING) &&
  567. !(dwFlags & ICDRAW_PREROLL))
  568. PrepareDC(npMCI);
  569. lpFormat->biSizeImage = cksize; // !!! ??? Is this safe?
  570. //
  571. // !!!do we realy realy want to do this here?
  572. // or just relay on the MPlay(er) status function
  573. //
  574. ////if (npMCI->dwFlags & MCIAVI_WANTMOVE)
  575. //// CheckWindowMoveFast(npMCI);
  576. DPF3(("Calling ICDraw on frame %ld (%08lx)\n", npMCI->lCurrentFrame, dwFlags));
  577. dwRet = ICDraw(npMCI->hicDraw, dwFlags, lpFormat, lp, cksize,
  578. npMCI->lCurrentFrame - npMCI->lFramePlayStart);
  579. TIMEEND(timeDraw);
  580. if ((LONG) dwRet < ICERR_OK) {
  581. DPF(("Driver failed ICM_DRAW message err=%ld\n", dwRet));
  582. return FALSE;
  583. }
  584. else {
  585. psi->dwFlags &= ~STREAM_NEEDUPDATE;
  586. if (!(dwFlags & (ICDRAW_HURRYUP|ICDRAW_PREROLL)))
  587. psi->dwFlags &= ~STREAM_DIRTY;
  588. }
  589. if (ICERR_STOPDRAWING == dwRet) {
  590. npMCI->dwFlags |= MCIAVI_STOP;
  591. }
  592. #ifdef INTERVAL_TIMES
  593. // grab the interframe interval as soon as the video is shown
  594. if (npMCI->wTaskState == TASKPLAYING) {
  595. DWORD dwTime = timeGetTime();
  596. if (npMCI->nFrames > 0) {
  597. long lMsecs = (LONG) dwTime - npMCI->dwStartTime;
  598. if (lMsecs < npMCI->msFrameMin) {
  599. npMCI->msFrameMin = lMsecs;
  600. }
  601. if (lMsecs > npMCI->msFrameMax) {
  602. npMCI->msFrameMax = lMsecs;
  603. }
  604. npMCI->msFrameTotal += lMsecs;
  605. npMCI->msSquares += (lMsecs * lMsecs);
  606. if (lMsecs < NBUCKETS * BUCKETSIZE)
  607. npMCI->buckets[lMsecs/BUCKETSIZE]++;
  608. else
  609. npMCI->buckets[NBUCKETS]++;
  610. if (npMCI->nFrames < npMCI->cIntervals)
  611. *(npMCI->paIntervals+npMCI->nFrames) = lMsecs;
  612. }
  613. npMCI->nFrames++;
  614. npMCI->dwStartTime = dwTime;
  615. }
  616. #endif
  617. return TRUE;
  618. }
  619. /***************************************************************************
  620. ***************************************************************************/
  621. #if 0
  622. static void FreeDecompressBuffer(NPMCIGRAPHIC npMCI)
  623. {
  624. if (npMCI->hpDecompress)
  625. GlobalFreePtr(npMCI->hpDecompress);
  626. npMCI->hpDecompress = NULL;
  627. npMCI->cbDecompress = 0;
  628. }
  629. #endif
  630. /***************************************************************************
  631. ***************************************************************************/
  632. static BOOL GetDecompressBuffer(NPMCIGRAPHIC npMCI)
  633. {
  634. int n = npMCI->nVideoStream;
  635. int dxDest = RCW(DEST(n));
  636. int dyDest = RCH(DEST(n));
  637. HPSTR hp;
  638. npMCI->bih.biSizeImage = npMCI->bih.biHeight * DIBWIDTHBYTES(npMCI->bih);
  639. if ((LONG) npMCI->bih.biSizeImage <= npMCI->cbDecompress)
  640. return TRUE;
  641. if (!npMCI->hpDecompress)
  642. hp = GlobalAllocPtr(GHND|GMEM_SHARE, npMCI->bih.biSizeImage);
  643. else
  644. hp = GlobalReAllocPtr(npMCI->hpDecompress,
  645. npMCI->bih.biSizeImage,
  646. GMEM_MOVEABLE | GMEM_SHARE);
  647. if (hp == NULL) {
  648. npMCI->dwTaskError = MCIERR_OUT_OF_MEMORY;
  649. return FALSE;
  650. }
  651. npMCI->hpDecompress = hp;
  652. npMCI->cbDecompress = npMCI->bih.biSizeImage;
  653. return TRUE;
  654. }
  655. /*
  656. Possibilities:
  657. 1. We're starting to play.
  658. We may need to switch into fullscreen mode.
  659. We need a DrawBegin.
  660. 2. We're updating the screen.
  661. Do we send a new DrawBegin?
  662. Has anything changed since we last updated? Perhaps we can use
  663. a flag to say whether something has changed, and set it when we leave
  664. fullscreen mode or when the window is stretched.
  665. What if we're updating to memory?
  666. 3. We're playing, and the user has stretched the window.
  667. The Draw device may need us to go back to a key frame.
  668. If we have a separate decompressor, it may need us to go back to a key frame.
  669. */
  670. #if 0
  671. RestartCompressor()
  672. {
  673. DWORD dwDrawFlags;
  674. dwDrawFlags = (npMCI->dwFlags & MCIAVI_FULLSCREEN) ?
  675. ICDRAW_FULLSCREEN : ICDRAW_HDC;
  676. if (pfRestart)
  677. dwDrawFlags |= ICDRAW_CONTINUE;
  678. if (npMCI->dwFlags & MCIAVI_UPDATETOMEMORY)
  679. dwDrawFlags |= ICDRAW_MEMORYDC;
  680. if (npMCI->hic) {
  681. static struct {
  682. BITMAPINFOHEADER bi;
  683. RGBQUAD rgbq[256];
  684. } dib;
  685. }
  686. }
  687. #endif
  688. STATICFN BOOL TryDrawDevice(NPMCIGRAPHIC npMCI, HIC hicDraw, DWORD dwDrawFlags, BOOL fTryDecompress)
  689. {
  690. LRESULT dw;
  691. int n = npMCI->nVideoStream;
  692. STREAMINFO *psi = SI(n);
  693. Assert(psi);
  694. if (hicDraw == NULL)
  695. return FALSE;
  696. // See if the standard draw device can handle the format
  697. dw = ICDrawBegin(hicDraw,
  698. dwDrawFlags,
  699. npMCI->hpal, // palette to draw with
  700. npMCI->hwndPlayback, // window to draw to
  701. npMCI->hdc, // HDC to draw to
  702. RCX(DEST(n)),
  703. RCY(DEST(n)),
  704. RCW(DEST(n)),
  705. RCH(DEST(n)),
  706. npMCI->pbiFormat,
  707. RCX(SOURCE(n)),
  708. RCY(SOURCE(n)),
  709. RCW(SOURCE(n)),
  710. RCH(SOURCE(n)),
  711. // !!! First of all, these two are backwards.
  712. // !!! Secondly, what if PlayuSec == 0?
  713. npMCI->dwPlayMicroSecPerFrame,
  714. 1000000L);
  715. if (dw == ICERR_OK) {
  716. npMCI->hic = 0;
  717. npMCI->hicDraw = hicDraw;
  718. return TRUE;
  719. }
  720. if (npMCI->hicDecompress && fTryDecompress) {
  721. RECT rc;
  722. // Ask the draw device to suggest a format, then try to get our
  723. // decompressor to make that format.
  724. dw = ICDrawSuggestFormat(hicDraw,
  725. npMCI->pbiFormat,
  726. &npMCI->bih,
  727. RCW(SOURCE(n)),
  728. RCH(SOURCE(n)),
  729. RCW(DEST(n)),
  730. RCH(DEST(n)),
  731. npMCI->hicDecompress);
  732. if ((LONG)dw >= 0)
  733. dw = ICDecompressQuery(npMCI->hicDecompress,
  734. npMCI->pbiFormat,&npMCI->bih);
  735. if ((LONG)dw < 0) {
  736. //
  737. // default to the right format for the screen, in case the draw guy
  738. // fails the draw suggest.
  739. //
  740. ICGetDisplayFormat(npMCI->hicDecompress,
  741. npMCI->pbiFormat,&npMCI->bih, 0,
  742. MulDiv((int)npMCI->pbiFormat->biWidth, RCW(psi->rcDest),RCW(psi->rcSource)),
  743. MulDiv((int)npMCI->pbiFormat->biHeight,RCH(psi->rcDest),RCH(psi->rcSource)));
  744. dw = ICDecompressQuery(npMCI->hicDecompress,
  745. npMCI->pbiFormat,&npMCI->bih);
  746. if (dw != ICERR_OK) {
  747. npMCI->dwTaskError = MCIERR_INTERNAL;
  748. return FALSE;
  749. }
  750. }
  751. if (npMCI->bih.biBitCount <= 8) {
  752. ICDecompressGetPalette(npMCI->hicDecompress,
  753. npMCI->pbiFormat, &npMCI->bih);
  754. }
  755. #ifdef DEBUG
  756. DPF(("InitDecompress: Decompressing %dx%dx%d '%4.4ls' to %dx%dx%d\n",
  757. (int)npMCI->pbiFormat->biWidth,
  758. (int)npMCI->pbiFormat->biHeight,
  759. (int)npMCI->pbiFormat->biBitCount,
  760. (LPSTR)(
  761. npMCI->pbiFormat->biCompression == BI_RGB ? "None" :
  762. npMCI->pbiFormat->biCompression == BI_RLE8 ? "Rle8" :
  763. npMCI->pbiFormat->biCompression == BI_RLE4 ? "Rle4" :
  764. (LPSTR)&npMCI->pbiFormat->biCompression),
  765. (int)npMCI->bih.biWidth,
  766. (int)npMCI->bih.biHeight,
  767. (int)npMCI->bih.biBitCount));
  768. #endif
  769. if (!GetDecompressBuffer(npMCI))
  770. return FALSE;
  771. //
  772. // setup the "real" source rect we will draw with.
  773. //
  774. #if 0
  775. rc.left = (int) ((SOURCE(n).left * npMCI->bih.biWidth) / npMCI->pbiFormat->biWidth);
  776. rc.right = (int) ((SOURCE(n).right * npMCI->bih.biWidth) / npMCI->pbiFormat->biWidth);
  777. rc.top = (int) ((SOURCE(n).top * npMCI->bih.biHeight) / npMCI->pbiFormat->biHeight);
  778. rc.bottom = (int) ((SOURCE(n).bottom * npMCI->bih.biHeight) / npMCI->pbiFormat->biHeight);
  779. #else
  780. rc = SOURCE(n);
  781. rc.left = (int) ((rc.left * npMCI->bih.biWidth) / npMCI->pbiFormat->biWidth);
  782. rc.right = (int) ((rc.right * npMCI->bih.biWidth) / npMCI->pbiFormat->biWidth);
  783. rc.top = (int) ((rc.top * npMCI->bih.biHeight) / npMCI->pbiFormat->biHeight);
  784. rc.bottom = (int) ((rc.bottom * npMCI->bih.biHeight) / npMCI->pbiFormat->biHeight);
  785. #endif
  786. dw = ICDrawBegin(hicDraw,
  787. dwDrawFlags,
  788. npMCI->hpal, // palette to draw with
  789. npMCI->hwndPlayback, // window to draw to
  790. npMCI->hdc, // HDC to draw to
  791. RCX(DEST(n)),
  792. RCY(DEST(n)),
  793. RCW(DEST(n)),
  794. RCH(DEST(n)),
  795. &npMCI->bih,
  796. rc.left, rc.top,
  797. rc.right - rc.left,
  798. rc.bottom - rc.top,
  799. // !!! First of all, these two are backwards.
  800. // !!! Secondly, what if PlayuSec == 0?
  801. npMCI->dwPlayMicroSecPerFrame,
  802. 1000000L);
  803. if (dw == ICERR_OK) {
  804. npMCI->hic = npMCI->hicDecompress;
  805. npMCI->hicDraw = hicDraw;
  806. // Now, we have the format we'd like the decompressor to decompress to...
  807. dw = ICDecompressBegin(npMCI->hicDecompress,
  808. npMCI->pbiFormat,
  809. &npMCI->bih);
  810. if (dw != ICERR_OK) {
  811. DPF(("DrawBegin: decompressor succeeded query, failed begin!\n"));
  812. ICDrawEnd(npMCI->hicDraw);
  813. return FALSE;
  814. }
  815. return TRUE;
  816. }
  817. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  818. npMCI->dwTaskError = MCIERR_AVI_NODISPDIB;
  819. }
  820. }
  821. return FALSE;
  822. }
  823. #ifndef DEBUG
  824. INLINE
  825. #endif
  826. STATICFN BOOL FindDrawDevice(NPMCIGRAPHIC npMCI, DWORD dwDrawFlags)
  827. {
  828. if (npMCI->dwFlags & MCIAVI_USERDRAWPROC) {
  829. // If the user has set a draw procedure, try it.
  830. if (TryDrawDevice(npMCI, npMCI->hicDrawDefault, dwDrawFlags, TRUE)) {
  831. if (npMCI->hic) {
  832. DPF2(("Using decompressor, then application's draw device...\n"));
  833. } else {
  834. DPF2(("Using application's draw device...\n"));
  835. }
  836. return TRUE;
  837. }
  838. // If it fails, it fails.
  839. DPF(("Can't use application's draw device!\n"));
  840. return FALSE;
  841. }
  842. // First, try a pure draw device we've found.
  843. if (TryDrawDevice(npMCI, SI(npMCI->nVideoStream)->hicDraw, dwDrawFlags, FALSE)) {
  844. DPF2(("Draw device is drawing to the screen...\n"));
  845. return TRUE;
  846. }
  847. // Next, try see if the decompressor we found can draw too.
  848. // Should this even get asked before the guy above?!!!!
  849. if (TryDrawDevice(npMCI, npMCI->hicDecompress, dwDrawFlags, FALSE)) {
  850. DPF2(("Decompressor is drawing to the screen...\n"));
  851. return TRUE;
  852. }
  853. // No? Then, get the standard draw device, for fullscreen or not.
  854. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  855. // !!! If it's fullscreen, should we force a re-begin?
  856. // !!! Assume fullscreen only happens when play is starting?
  857. if (npMCI->hicDrawFull == NULL) {
  858. DPF2(("Opening default fullscreen codec...\n"));
  859. npMCI->hicDrawFull = ICOpen(streamtypeVIDEO,
  860. FOURCC_AVIFull,ICMODE_DRAW);
  861. if (!npMCI->hicDrawFull)
  862. npMCI->hicDrawFull = (HIC) -1;
  863. }
  864. npMCI->hicDraw = npMCI->hicDrawFull;
  865. } else {
  866. if (npMCI->hicDrawDefault == NULL) {
  867. DPF2(("Opening default draw codec...\n"));
  868. npMCI->hicDrawDefault = ICOpen(streamtypeVIDEO,
  869. FOURCC_AVIDraw,ICMODE_DRAW);
  870. if (!npMCI->hicDrawDefault)
  871. npMCI->hicDrawDefault = (HIC) -1;
  872. }
  873. npMCI->hicDraw = npMCI->hicDrawDefault;
  874. }
  875. // If there's an installed draw device, try it.
  876. if (npMCI->hicDraw && npMCI->hicDraw != (HIC) -1) {
  877. if (TryDrawDevice(npMCI, npMCI->hicDraw, dwDrawFlags, TRUE)) {
  878. if (npMCI->hic) {
  879. DPF2(("Using decompressor, then default draw device...\n"));
  880. } else {
  881. DPF2(("Using default draw device...\n"));
  882. }
  883. return TRUE;
  884. }
  885. }
  886. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  887. if (!npMCI->hicInternalFull)
  888. npMCI->hicInternalFull = ICOpenFunction(streamtypeVIDEO,
  889. FOURCC_AVIFull,ICMODE_DRAW,(FARPROC)ICAVIFullProc);
  890. npMCI->hicDraw = npMCI->hicInternalFull;
  891. } else {
  892. if (!npMCI->hicInternal) {
  893. npMCI->hicInternal = ICOpenFunction(streamtypeVIDEO,
  894. FOURCC_AVIDraw,ICMODE_DRAW,(FARPROC)ICAVIDrawProc);
  895. #ifdef DEBUG
  896. {
  897. // This is a hack to get the hdd back from AVIDrawOpen
  898. extern HDRAWDIB ghdd;
  899. npMCI->hdd = ghdd;
  900. ghdd = NULL;
  901. }
  902. #endif
  903. }
  904. npMCI->hicDraw = npMCI->hicInternal;
  905. }
  906. // As a last resort, try the built-in draw device.
  907. if (TryDrawDevice(npMCI, npMCI->hicDraw, dwDrawFlags, TRUE)) {
  908. if (npMCI->hic) {
  909. DPF2(("Using decompressor, then built-in draw device...\n"));
  910. } else {
  911. DPF2(("Using built-in draw device...\n"));
  912. }
  913. return TRUE;
  914. }
  915. // if we are failing because fullscreen, then return an error
  916. // indicating this
  917. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  918. npMCI->dwTaskError = MCIERR_AVI_NODISPDIB;
  919. }
  920. return FALSE;
  921. }
  922. /**************************************************************************
  923. * @doc INTERNAL DRAWDIB
  924. *
  925. * @api BOOL | DibEq | This function compares two dibs.
  926. *
  927. * @parm LPBITMAPINFOHEADER lpbi1 | Pointer to one bitmap.
  928. * this DIB is assumed to have the colors after the BITMAPINFOHEADER
  929. *
  930. * @parm LPBITMAPINFOHEADER | lpbi2 | Pointer to second bitmap.
  931. * this DIB is assumed to have the colors after biSize bytes.
  932. *
  933. * @rdesc Returns TRUE if bitmaps are identical, FALSE otherwise.
  934. *
  935. **************************************************************************/
  936. INLINE BOOL DibEq(LPBITMAPINFOHEADER lpbi1, LPBITMAPINFOHEADER lpbi2)
  937. {
  938. return
  939. lpbi1->biCompression == lpbi2->biCompression &&
  940. lpbi1->biSize == lpbi2->biSize &&
  941. lpbi1->biWidth == lpbi2->biWidth &&
  942. lpbi1->biHeight == lpbi2->biHeight &&
  943. lpbi1->biBitCount == lpbi2->biBitCount;
  944. }
  945. /***************************************************************************
  946. *
  947. * @doc INTERNAL MCIAVI
  948. *
  949. * @api void | DrawBegin
  950. *
  951. *
  952. ***************************************************************************/
  953. BOOL FAR PASCAL DrawBegin(NPMCIGRAPHIC npMCI, BOOL FAR *pfRestart)
  954. {
  955. DWORD dwDrawFlags;
  956. HIC hicLast = npMCI->hic;
  957. HIC hicLastDraw = npMCI->hicDraw;
  958. BITMAPINFOHEADER bihDecompLast = npMCI->bih;
  959. if (npMCI->nVideoStreams == 0)
  960. return TRUE;
  961. if (!npMCI->pbiFormat)
  962. return TRUE;
  963. npMCI->fNoDrawing = FALSE;
  964. // if fullscreen, make sure we re-initialize....
  965. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  966. npMCI->dwFlags |= MCIAVI_NEEDDRAWBEGIN;
  967. }
  968. dwDrawFlags = (npMCI->dwFlags & MCIAVI_FULLSCREEN) ?
  969. ICDRAW_FULLSCREEN : ICDRAW_HDC;
  970. if (pfRestart) {
  971. dwDrawFlags |= ICDRAW_CONTINUE;
  972. *pfRestart = TRUE;
  973. }
  974. if (npMCI->dwFlags & MCIAVI_UPDATETOMEMORY)
  975. dwDrawFlags |= ICDRAW_MEMORYDC;
  976. // !!! What about "stupid mode"?
  977. //
  978. // if the file has no keyframes force a buffer
  979. //
  980. if (npMCI->dwKeyFrameInfo == 0)
  981. dwDrawFlags |= ICDRAW_BUFFER;
  982. //
  983. // if the file has few keyframes also force a buffer.
  984. //
  985. if (MovieToTime(npMCI->dwKeyFrameInfo) > KEYFRAME_PANIC_SPACE)
  986. dwDrawFlags |= ICDRAW_BUFFER;
  987. if (dwDrawFlags & ICDRAW_BUFFER)
  988. DPF(("Forcing a decompress buffer because too few key frames\n"));
  989. if (npMCI->wTaskState > TASKIDLE &&
  990. !(npMCI->dwFlags & MCIAVI_SEEKING) &&
  991. !(npMCI->dwFlags & MCIAVI_FULLSCREEN) &&
  992. (npMCI->dwFlags & MCIAVI_ANIMATEPALETTE)) {
  993. dwDrawFlags |= ICDRAW_ANIMATE;
  994. #if 0
  995. //
  996. // I moved all this into ShowStage() where you could claim it realy belongs.
  997. //
  998. if (npMCI->hwnd == npMCI->hwndDefault &&
  999. !(GetWindowLong(npMCI->hwnd, GWL_STYLE) & WS_CHILD))
  1000. SetActiveWindow(npMCI->hwnd);
  1001. #endif
  1002. }
  1003. if (npMCI->hdc == NULL) {
  1004. DPF2(("DrawBegin() with NULL hdc!\n"));
  1005. }
  1006. if (FindDrawDevice(npMCI, dwDrawFlags)) {
  1007. if (npMCI->hicDraw != hicLastDraw || (npMCI->hic != hicLast) ||
  1008. (npMCI->hic && !DibEq(&npMCI->bih, &bihDecompLast))) {
  1009. // !!! This obviously shouldn't always be invalidated!
  1010. //
  1011. // make sure the current image buffer is invalidated
  1012. //
  1013. DPF2(("Draw device is different; restarting....\n"));
  1014. npMCI->lFrameDrawn = (- (LONG) npMCI->wEarlyRecords) - 1;
  1015. npMCI->dwFlags |= MCIAVI_WANTMOVE;
  1016. if (pfRestart)
  1017. *pfRestart = TRUE;
  1018. }
  1019. if (npMCI->dwFlags & MCIAVI_WANTMOVE)
  1020. CheckWindowMove(npMCI, TRUE);
  1021. // if (pfRestart)
  1022. // *pfRestart = (dw == ICERR_GOTOKEYFRAME);
  1023. npMCI->dwFlags &= ~(MCIAVI_NEEDDRAWBEGIN);
  1024. #if 0
  1025. //
  1026. // tell the compressor some interesting info.
  1027. //
  1028. if (npMCI->hicDraw) { // !!! Does npMCI->hic need to know this?
  1029. ICSendMessage(npMCI->hic, ICM_SET, ICM_FRAMERATE, npMCI->dwPlayMicroSecPerFrame);
  1030. ICSendMessage(npMCI->hic, ICM_SET, ICM_KEYFRAMERATE, npMCI->dwKeyFrameInfo);
  1031. }
  1032. #endif
  1033. return TRUE;
  1034. }
  1035. return FALSE;
  1036. }
  1037. /***************************************************************************
  1038. *
  1039. * @doc INTERNAL MCIAVI
  1040. *
  1041. * @api void | DrawEnd
  1042. *
  1043. * @parm NPMCIGRAPHIC | npMCI | pointer to instance data block.
  1044. *
  1045. ***************************************************************************/
  1046. void NEAR PASCAL DrawEnd(NPMCIGRAPHIC npMCI)
  1047. {
  1048. if (!npMCI->pbiFormat)
  1049. return;
  1050. ICDrawEnd(npMCI->hicDraw);
  1051. // if we were fullscreen, we now need to repaint and things....
  1052. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  1053. npMCI->dwFlags |= MCIAVI_NEEDDRAWBEGIN;
  1054. }
  1055. /*
  1056. ** let DrawDib clean up if we're animating the palette.
  1057. */
  1058. if (npMCI->wTaskState > TASKIDLE &&
  1059. !(npMCI->dwFlags & MCIAVI_SEEKING) &&
  1060. !(npMCI->dwFlags & MCIAVI_FULLSCREEN) &&
  1061. !(npMCI->dwFlags & MCIAVI_UPDATING) &&
  1062. (npMCI->dwFlags & MCIAVI_ANIMATEPALETTE)) {
  1063. npMCI->dwFlags |= MCIAVI_NEEDDRAWBEGIN;
  1064. InvalidateRect(npMCI->hwndPlayback, NULL, FALSE);
  1065. }
  1066. }