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.

3320 lines
93 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1985-1991. All rights reserved.
  3. Title: aviplay.c - Code for actually playing AVI files, part of
  4. AVI's background task.
  5. *****************************************************************************/
  6. #include "graphic.h"
  7. #define AVIREADMANY // read more than one record at a time
  8. #ifdef WIN32
  9. //#define AVIREAD // multi-threaded async read of file
  10. #else
  11. #undef AVIREAD
  12. #endif
  13. #ifdef AVIREAD
  14. #include "aviread.h"
  15. #endif
  16. #define BOUND(x, low, high) max(min(x, high), low)
  17. #define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
  18. //
  19. // redefine StreamFromFOURCC to only handle 0-9 streams!
  20. //
  21. #undef StreamFromFOURCC
  22. #define StreamFromFOURCC(fcc) (UINT)(HIBYTE(LOWORD(fcc)) - (BYTE)'0')
  23. #ifdef DEBUG
  24. static char szBadFrame[] = "Bad frame number";
  25. static char szBadPos[] = "Bad stream position";
  26. #define AssertFrame(i) AssertSz((long)(i) <= npMCI->lFrames && (long)(i) >= -(long)npMCI->wEarlyRecords, szBadFrame)
  27. #define AssertPos(psi,i) AssertSz((long)(i) <= psi->lEnd && (long)(i) >= psi->lStart, szBadPos)
  28. #else
  29. #define AssertFrame(i)
  30. #define AssertPos(psi,i)
  31. #endif
  32. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  33. #define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  34. LONG NEAR PASCAL WhatFrameIsItTimeFor(NPMCIGRAPHIC npMCI);
  35. BOOL NEAR PASCAL TimeToQuit(NPMCIGRAPHIC npMCI);
  36. void NEAR PASCAL FindKeyFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos);
  37. LONG NEAR PASCAL FindPrevKeyFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos);
  38. LONG NEAR PASCAL FindNextKeyFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos);
  39. BOOL NEAR PASCAL CalculateTargetFrame(NPMCIGRAPHIC npMCI);
  40. DWORD NEAR PASCAL CalculatePosition(NPMCIGRAPHIC npMCI);
  41. BOOL NEAR PASCAL ReadRecord(NPMCIGRAPHIC npMCI);
  42. BOOL NEAR PASCAL ReadNextVideoFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi);
  43. DWORD NEAR PASCAL ReadNextChunk(NPMCIGRAPHIC npMCI);
  44. BOOL NEAR PASCAL ReadBuffer(NPMCIGRAPHIC npMCI, LONG off, LONG len);
  45. BOOL NEAR PASCAL AllocateReadBuffer(NPMCIGRAPHIC npMCI);
  46. BOOL NEAR PASCAL ResizeReadBuffer(NPMCIGRAPHIC npMCI, DWORD dwNewSize);
  47. void NEAR PASCAL ReleaseReadBuffer(NPMCIGRAPHIC npMCI);
  48. BOOL NEAR PASCAL ProcessPaletteChanges(NPMCIGRAPHIC npMCI, LONG lFrame);
  49. void DealWithOtherStreams(NPMCIGRAPHIC npMCI, LONG lFrame);
  50. BOOL NEAR PASCAL StreamRead(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos);
  51. static LPVOID AllocMem(DWORD dw);
  52. #ifndef WIN32
  53. #define FreeMem(lp) GlobalFree((HGLOBAL)SELECTOROF(lp))
  54. #else
  55. #define FreeMem(lp) GlobalFreePtr(lp)
  56. #endif
  57. INT gwSkipTolerance = 4;
  58. INT gwHurryTolerance = 2;
  59. INT gwMaxSkipEver = 60;
  60. #define YIELDEVERY 8
  61. #ifdef DEBUG
  62. #define WAITHISTOGRAM /* Extra debugging information */
  63. #define SHOWSKIPPED
  64. //#define BEHINDHIST
  65. #define DRAWTIMEHIST
  66. #define READTIMEHIST
  67. #define TIMEPLAY
  68. #endif
  69. #ifdef WAITHISTOGRAM
  70. UINT wHist[100];
  71. #endif
  72. #ifdef SHOWSKIPPED
  73. #define NUMSKIPSSHOWN 25
  74. LONG lSkipped[NUMSKIPSSHOWN];
  75. UINT wSkipped = 0;
  76. #endif
  77. #ifdef BEHINDHIST
  78. #define NUMBEHIND 50
  79. #define BEHINDOFFSET 10
  80. WORD wBehind[NUMBEHIND];
  81. #endif
  82. #ifdef DRAWTIMEHIST
  83. #define NUMDRAWN 100
  84. DWORD dwDrawTime[NUMDRAWN];
  85. UINT wDrawn;
  86. #endif
  87. #ifdef READTIMEHIST
  88. #define NUMREAD 100
  89. DWORD dwReadTime[NUMREAD];
  90. UINT wRead;
  91. #endif
  92. #ifdef AVIREAD
  93. /*
  94. * the aviread object creates a worker thread to read the file
  95. * asynchronously. That thread calls this callback function
  96. * to actually read a buffer from the file. The 'instance data' DWORD in
  97. * this case is npMCI. see aviread.h for outline.
  98. */
  99. BOOL mciaviReadBuffer(PBYTE pData, DWORD dwInstanceData, long lSize, long * lpNextSize)
  100. {
  101. NPMCIGRAPHIC npMCI = (NPMCIGRAPHIC) dwInstanceData;
  102. DWORD size;
  103. DWORD UNALIGNED * lp;
  104. if(mmioRead(npMCI->hmmio, pData, lSize) != lSize) {
  105. return(FALSE);
  106. }
  107. /* we've read in the complete chunk, plus the FOURCC, size and formtype of
  108. * the next chunk. So the size of the next chunk is the last but one
  109. * DWORD in this buffer
  110. */
  111. lp = (DWORD UNALIGNED *) (pData + lSize - 2 * sizeof(DWORD));
  112. size = *lp;
  113. /* don't forget to add on the FOURCC and size dwords */
  114. *lpNextSize = size + 2 * sizeof(DWORD);
  115. return(TRUE);
  116. }
  117. #endif
  118. DWORD NEAR PASCAL PrepareToPlay(NPMCIGRAPHIC npMCI);
  119. void NEAR PASCAL CleanUpPlay(NPMCIGRAPHIC npMCI);
  120. void NEAR PASCAL CheckSignals(NPMCIGRAPHIC npMCI, LONG lFrame);
  121. BOOL NEAR PASCAL PlayNonInterleaved(NPMCIGRAPHIC npMCI);
  122. BOOL NEAR PASCAL PlayInterleaved(NPMCIGRAPHIC npMCI);
  123. BOOL NEAR PASCAL PlayAudioOnly(NPMCIGRAPHIC npMCI);
  124. BOOL NEAR PASCAL PlayNonIntFromCD(NPMCIGRAPHIC npMCI);
  125. /***************************************************************************
  126. *
  127. * @doc INTERNAL MCIAVI
  128. *
  129. * @api UINT | mciaviPlayFile | Play an AVI file.
  130. *
  131. * @parm NPMCIGRAPHIC | npMCI | Pointer to instance data.
  132. *
  133. * @rdesc Notification code that should be returned.
  134. *
  135. ***************************************************************************/
  136. UINT NEAR PASCAL mciaviPlayFile (NPMCIGRAPHIC npMCI)
  137. {
  138. BOOL fContinue;
  139. DWORD dwFlags = npMCI->dwFlags;
  140. BOOL (NEAR PASCAL *Play)(NPMCIGRAPHIC npMCI);
  141. #ifdef WAITHISTOGRAM
  142. UINT w;
  143. #endif
  144. #ifdef SHOWSKIPPED
  145. wSkipped = 0;
  146. #endif
  147. #ifdef WAITHISTOGRAM
  148. for (w = 0; (int)w < (sizeof(wHist)/sizeof(wHist[0])); w++)
  149. wHist[w] = 0;
  150. #endif
  151. #ifdef BEHINDHIST
  152. for (w = 0; w < NUMBEHIND; w++)
  153. wBehind[w] = 0;
  154. #endif
  155. #ifdef DRAWTIMEHIST
  156. wDrawn = 0;
  157. for (w = 0; w < NUMDRAWN; w++)
  158. dwDrawTime[w] = 0;
  159. #endif
  160. #ifdef READTIMEHIST
  161. wRead = 0;
  162. for (w = 0; w < NUMREAD; w++)
  163. dwReadTime[w] = 0;
  164. #endif
  165. Repeat:
  166. Assert(npMCI->wTaskState == TASKSTARTING);
  167. TIMEZERO(timePlay);
  168. TIMEZERO(timePrepare);
  169. TIMEZERO(timeCleanup);
  170. TIMEZERO(timePaused);
  171. TIMEZERO(timeRead);
  172. TIMEZERO(timeWait);
  173. TIMEZERO(timeYield);
  174. TIMEZERO(timeVideo);
  175. TIMEZERO(timeOther);
  176. TIMEZERO(timeAudio);
  177. TIMEZERO(timeDraw);
  178. TIMEZERO(timeDecompress);
  179. TIMESTART(timePrepare);
  180. npMCI->dwTaskError = PrepareToPlay(npMCI);
  181. TIMEEND(timePrepare);
  182. //
  183. // pick a play function.
  184. //
  185. switch (npMCI->wPlaybackAlg) {
  186. case MCIAVI_ALG_INTERLEAVED:
  187. Play = PlayInterleaved;
  188. break;
  189. case MCIAVI_ALG_CDROM:
  190. Play = PlayNonIntFromCD;
  191. break;
  192. case MCIAVI_ALG_HARDDISK:
  193. Play = PlayNonInterleaved;
  194. break;
  195. case MCIAVI_ALG_AUDIOONLY:
  196. Play = PlayAudioOnly;
  197. break;
  198. default:
  199. Assert(0);
  200. return MCI_NOTIFY_ABORTED; //???
  201. }
  202. // bias lTo by dwBufferedVideo so we play to the right place
  203. npMCI->lTo += npMCI->dwBufferedVideo;
  204. npMCI->lFramePlayStart = npMCI->lRealStart;
  205. DPF(("Playing from %ld to %ld, starting at %ld.\n", npMCI->lFrom, npMCI->lTo, npMCI->lCurrentFrame));
  206. if (npMCI->dwTaskError != 0L)
  207. goto SKIP_PLAYING;
  208. /* We're done initializing; now we're warming up to play. */
  209. npMCI->wTaskState = TASKCUEING;
  210. TIMESTART(timePlay);
  211. /* Loop until things are done */
  212. while (1) {
  213. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  214. if (npMCI->lCurrentFrame < npMCI->lTo)
  215. break;
  216. } else {
  217. if (npMCI->lCurrentFrame > npMCI->lTo)
  218. break;
  219. }
  220. if ((npMCI->wTaskState != TASKPLAYING) &&
  221. !(npMCI->dwFlags & MCIAVI_UPDATING)) {
  222. TIMESTART(timeYield);
  223. aviTaskYield();
  224. TIMEEND(timeYield);
  225. }
  226. fContinue = Play(npMCI);
  227. if (!fContinue)
  228. break;
  229. if (TimeToQuit(npMCI))
  230. break;
  231. //
  232. // while playing we may need to update
  233. //
  234. // always mark the movie as clean, even if a stream fails to update
  235. // otherwise we will need to stop play and restart.
  236. //
  237. if (!(npMCI->dwFlags & MCIAVI_SEEKING) &&
  238. (npMCI->dwFlags & MCIAVI_NEEDUPDATE)) {
  239. DoStreamUpdate(npMCI, FALSE);
  240. if (npMCI->dwFlags & MCIAVI_NEEDUPDATE) {
  241. DOUT("Update failed while playing, I dont care!\n");
  242. npMCI->dwFlags &= ~MCIAVI_NEEDUPDATE; //!!! I dont care if it failed
  243. }
  244. }
  245. /* Increment the frame number. If we're done, don't increment
  246. ** it an extra time, but just get out.
  247. */
  248. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  249. if (npMCI->lCurrentFrame > npMCI->lTo)
  250. --npMCI->lCurrentFrame;
  251. else
  252. break;
  253. } else {
  254. if (npMCI->lCurrentFrame < npMCI->lTo)
  255. ++npMCI->lCurrentFrame;
  256. else
  257. break;
  258. }
  259. }
  260. TIMEEND(timePlay);
  261. if (npMCI->lCurrentFrame != npMCI->lTo) {
  262. DPF(("Ended at %ld, not %ld (drawn = %ld).\n", npMCI->lCurrentFrame, npMCI->lTo, npMCI->lFrameDrawn));
  263. //
  264. // if we ended early lets set lCurrentFrame to the last frame
  265. // drawn to guarentee we can re-paint the frame, we dont
  266. // want to do this when we play to end because after playing
  267. // from A to B the current position *must* be B or preston will
  268. // enter a bug.
  269. //
  270. // but only set this if lFrameDraw is valid
  271. //
  272. if (npMCI->lFrameDrawn > (-(LONG)npMCI->wEarlyRecords))
  273. npMCI->lCurrentFrame = npMCI->lFrameDrawn;
  274. }
  275. SKIP_PLAYING:
  276. /* Flush any extra changes out to screen */
  277. DPF2(("Updating unfinished changes....\n"));
  278. // Make sure we really draw.... !!!do we need this?
  279. // npMCI->lRealStart = npMCI->lCurrentFrame;
  280. if (npMCI->hdc)
  281. DoStreamUpdate(npMCI, FALSE);
  282. // !!! should we set npMCI->lCurrentFrame = npMCI->lFrameDrawn?
  283. ///!!!npMCI->lCurrentFrame = npMCI->lFrameDrawn;
  284. // !!! Should we update npMCI->lFrom to be npMCI->lCurrentFrame,
  285. // to make that the default location play will start from next?
  286. //SKIP_PLAYING:
  287. npMCI->lTo -= npMCI->dwBufferedVideo;
  288. npMCI->lCurrentFrame -= npMCI->dwBufferedVideo;
  289. npMCI->dwBufferedVideo = 0;
  290. if (npMCI->lCurrentFrame < 0) {
  291. DPF2(("Adjusting position to be >= 0.\n"));
  292. npMCI->lCurrentFrame = 0;
  293. }
  294. if (npMCI->lTo < 0)
  295. npMCI->lTo = 0;
  296. /* Adjust position to be > start? */
  297. /* Adjust position to be > where it was when we began? */
  298. npMCI->dwTotalMSec += Now() - npMCI->dwMSecPlayStart;
  299. TIMESTART(timeCleanup);
  300. CleanUpPlay(npMCI);
  301. TIMEEND(timeCleanup);
  302. #ifdef AVIREAD
  303. /* shut down async reader */
  304. if (npMCI->hAviRd) {
  305. avird_endread(npMCI->hAviRd);
  306. npMCI->hAviRd = NULL;
  307. }
  308. #endif
  309. /* If we're repeating, do it. It sure would be nice if we could repeat
  310. ** without de-allocating and then re-allocating all of our buffers....
  311. */
  312. if (npMCI->dwTaskError == 0 && (!(npMCI->dwFlags & MCIAVI_STOP)) &&
  313. (npMCI->dwFlags & MCIAVI_REPEATING)) {
  314. npMCI->lFrom = npMCI->lRepeatFrom;
  315. //
  316. // DrawEnd() likes to clear this flag so make sure it gets set
  317. // in the repeat case.
  318. //
  319. if (dwFlags & MCIAVI_FULLSCREEN)
  320. npMCI->dwFlags |= MCIAVI_FULLSCREEN;
  321. //
  322. // make sure we set the task state back before we repeat.
  323. // otherwise our code will think we are playing, for example.
  324. // if the audio code thinks we are playing and see's the wave buffers
  325. // are empty it will reset the wave device then restart it when
  326. // they get full again, this is bad if we are pre-rolling audio.
  327. //
  328. npMCI->wTaskState = TASKSTARTING;
  329. goto Repeat;
  330. }
  331. /* Turn off flags only used during play. */
  332. npMCI->dwFlags &= ~(MCIAVI_STOP | MCIAVI_PAUSE | MCIAVI_SEEKING |
  333. MCIAVI_REPEATING | MCIAVI_FULLSCREEN);
  334. if (npMCI->wTaskState == TASKPLAYING) {
  335. DWORD dwCorrectTime;
  336. DWORD dwFramesPlayed;
  337. dwFramesPlayed = (npMCI->dwFlags & MCIAVI_REVERSE) ?
  338. npMCI->lFramePlayStart - npMCI->lCurrentFrame :
  339. npMCI->lCurrentFrame - npMCI->lFramePlayStart;
  340. dwCorrectTime = muldiv32(dwFramesPlayed,
  341. muldiv32(npMCI->dwMicroSecPerFrame,
  342. 1000L,
  343. (npMCI->dwSpeedFactor == 0 ?
  344. 1000 : npMCI->dwSpeedFactor)),
  345. 1000);
  346. if (dwCorrectTime != 0 && npMCI->dwTotalMSec != 0)
  347. npMCI->dwSpeedPercentage = muldiv32(dwCorrectTime, 100,
  348. npMCI->dwTotalMSec);
  349. else
  350. npMCI->dwSpeedPercentage = 100;
  351. if (dwFramesPlayed > 15) {
  352. npMCI->lFramesPlayed = (LONG)dwFramesPlayed;
  353. npMCI->lFramesSeekedPast = (LONG)npMCI->dwFramesSeekedPast;
  354. npMCI->lSkippedFrames = (LONG)npMCI->dwSkippedFrames;
  355. npMCI->lAudioBreaks = (LONG)npMCI->dwAudioBreaks;
  356. }
  357. #ifdef DEBUG
  358. if (npMCI->dwFramesSeekedPast) {
  359. DPF(("Didn't even read %ld frames.\n", npMCI->dwFramesSeekedPast));
  360. }
  361. if (npMCI->dwSkippedFrames && dwFramesPlayed > 0) {
  362. DPF(("Skipped %ld of %ld frames. (%ld%%)\n",
  363. npMCI->dwSkippedFrames, dwFramesPlayed,
  364. npMCI->dwSkippedFrames*100/dwFramesPlayed));
  365. }
  366. if (npMCI->dwAudioBreaks) {
  367. DPF(("Audio broke up %lu times.\n", npMCI->dwAudioBreaks));
  368. }
  369. #ifndef TIMEPLAY
  370. DPF(("Played at %lu%% of correct speed.\n", npMCI->dwSpeedPercentage));
  371. DPF(("Correct time = %lu ms, Actual = %lu ms.\n",
  372. dwCorrectTime, npMCI->dwTotalMSec));
  373. #endif
  374. #endif
  375. #ifdef SHOWSKIPPED
  376. if (wSkipped) {
  377. DPF(("Skipped: "));
  378. for (w = 0; w < wSkipped; w++) {
  379. DPF(("%ld ", lSkipped[w]));
  380. }
  381. DPF(("\n"));
  382. }
  383. #endif
  384. #ifdef WAITHISTOGRAM
  385. if (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED) {
  386. DPF(("Wait histogram: "));
  387. for (w = 0; (int)w <= (int)npMCI->wABs; w++) {
  388. if (wHist[w]) {
  389. DPF(("[%d]: %d ",w,wHist[w]));
  390. }
  391. }
  392. DPF(("\n"));
  393. }
  394. #endif
  395. #ifdef BEHINDHIST
  396. DPF(("Behind histogram: "));
  397. for (w = 0; w <= NUMBEHIND; w++) {
  398. if (wBehind[w]) {
  399. DPF(("[%d]: %d ",w - BEHINDOFFSET,wBehind[w]));
  400. }
  401. }
  402. DPF(("\n"));
  403. #endif
  404. #ifdef DRAWTIMEHIST
  405. DPF(("Draw times: "));
  406. for (w = 0; w < wDrawn; w++) {
  407. DPF(("%lu ", dwDrawTime[w]));
  408. }
  409. DPF(("\n"));
  410. #endif
  411. #ifdef READTIMEHIST
  412. DPF(("Read times: "));
  413. for (w = 0; w < wRead; w++) {
  414. DPF(("%lu ", dwReadTime[w]));
  415. }
  416. DPF(("\n"));
  417. #endif
  418. #ifdef TIMEPLAY
  419. #define SEC(time) (UINT)(npMCI->time / 1000l) , (UINT)(npMCI->time % 1000l)
  420. #define SECX(time,t) SEC(time) , (npMCI->t ? (UINT)(npMCI->time * 100l / npMCI->t) : 0)
  421. DPF(("***********************************************************\r\n"));
  422. DPF((" timePlay: %3d.%03dsec\r\n",SEC(timePlay)));
  423. DPF((" timeRead: %3d.%03dsec (%d%%)\r\n",SECX(timeRead, timePlay)));
  424. DPF((" timeWait: %3d.%03dsec (%d%%)\r\n",SECX(timeWait, timePlay)));
  425. DPF((" timeYield: %3d.%03dsec (%d%%)\r\n",SECX(timeYield, timePlay)));
  426. DPF((" timeVideo: %3d.%03dsec (%d%%)\r\n",SECX(timeVideo, timePlay)));
  427. DPF((" timeDraw: %3d.%03dsec (%d%%)\r\n",SECX(timeDraw, timeVideo)));
  428. DPF((" timeDecompress: %3d.%03dsec (%d%%)\r\n",SECX(timeDecompress, timeVideo)));
  429. DPF((" timeAudio: %3d.%03dsec (%d%%)\r\n",SECX(timeAudio, timePlay)));
  430. DPF((" timeOther: %3d.%03dsec (%d%%)\r\n",SECX(timeOther, timePlay)));
  431. DPF((" timePaused: %3d.%03dsec\r\n",SEC(timePaused)));
  432. DPF((" timePrepare: %3d.%03dsec\r\n",SEC(timePrepare)));
  433. DPF((" timeCleanup: %3d.%03dsec\r\n",SEC(timeCleanup)));
  434. DPF(("***********************************************************\r\n"));
  435. #endif
  436. }
  437. if (npMCI->dwTaskError)
  438. return MCI_NOTIFY_FAILURE;
  439. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  440. if (npMCI->lCurrentFrame <= npMCI->lTo)
  441. return MCI_NOTIFY_SUCCESSFUL;
  442. } else {
  443. if (npMCI->lCurrentFrame >= npMCI->lTo)
  444. return MCI_NOTIFY_SUCCESSFUL;
  445. }
  446. return MCI_NOTIFY_ABORTED;
  447. }
  448. BOOL NEAR PASCAL RestartAVI(NPMCIGRAPHIC npMCI);
  449. BOOL NEAR PASCAL PauseAVI(NPMCIGRAPHIC npMCI);
  450. BOOL NEAR PASCAL BePaused(NPMCIGRAPHIC npMCI);
  451. /******************************************************************************
  452. *****************************************************************************/
  453. #ifdef DEBUG
  454. INLINE void FillR(HDC hdc, LPRECT prc, DWORD rgb)
  455. {
  456. SetBkColor(hdc,rgb);
  457. ExtTextOut(hdc,0,0,ETO_OPAQUE,prc,NULL,0,NULL);
  458. }
  459. void StatusBar(NPMCIGRAPHIC npMCI, int n, int dx, int max, int cur)
  460. {
  461. HDC hdc;
  462. RECT rc;
  463. if (npMCI->dwFlags & MCIAVI_FULLSCREEN)
  464. return;
  465. if (cur > max)
  466. cur = max+1;
  467. if (cur < 0)
  468. cur = 0;
  469. hdc = GetWindowDC(npMCI->hwnd);
  470. //
  471. // show the amount of audio and how far behind we are
  472. //
  473. rc.left = 32;
  474. rc.top = 4 + n*5;
  475. rc.bottom = rc.top + 4;
  476. rc.right = rc.left + cur * dx;
  477. FillR(hdc, &rc, RGB(255,255,0));
  478. rc.left = rc.right;
  479. rc.right = rc.left + (max - cur) * dx;
  480. FillR(hdc, &rc, RGB(255,0,0));
  481. ReleaseDC(npMCI->hwnd, hdc);
  482. }
  483. #else
  484. #define StatusBar(p,a,b,c,d)
  485. #endif
  486. /******************************************************************************
  487. *****************************************************************************/
  488. BOOL NEAR PASCAL PlayInterleaved(NPMCIGRAPHIC npMCI)
  489. {
  490. LONG iFrame;
  491. LONG iKey;
  492. LONG iNextKey;
  493. LONG iPrevKey;
  494. BOOL fHurryUp=FALSE;
  495. int iHurryUp=0;
  496. BOOL fPlayedAudio = FALSE;
  497. BOOL f;
  498. BOOL NEAR PASCAL WaitTillNextFrame(NPMCIGRAPHIC npMCI);
  499. /* If lCurrentFrame == lFrames, we're really at the end of
  500. ** the file, so there isn't another record to read.
  501. */
  502. if (npMCI->lCurrentFrame < npMCI->lFrames) {
  503. /* Read new record into buffer */
  504. DPF2(("Reading", iFrame = (LONG)timeGetTime()));
  505. TIMESTART(timeRead);
  506. f = ReadRecord(npMCI);
  507. TIMEEND(timeRead);
  508. DPF2((".done %ldms\n", (LONG)timeGetTime() - iFrame));
  509. if (!f) {
  510. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  511. DPF(("Error reading frame #%ld\n", npMCI->lCurrentFrame));
  512. return FALSE;
  513. }
  514. #ifdef JUMPINTERLEAVED
  515. if (npMCI->hWave && npMCI->wABFull == 0 &&
  516. npMCI->wTaskState == TASKPLAYING &&
  517. (npMCI->dwOptionFlags & MCIAVIO_SKIPFRAMES)) {
  518. LONG lTemp;
  519. // !!! figure out how far ahead to skip!
  520. PauseAVI(npMCI);
  521. npMCI->lFrom = npMCI->lCurrentFrame;
  522. npMCI->lFrom += npMCI->wABs;
  523. npMCI->lFrom += (((Now() - npMCI->dwTimingStart) * 1000L)
  524. - npMCI->dwNextFrameMicroSec) /
  525. npMCI->dwPlayMicroSecPerFrame;
  526. lTemp = FindNextKeyFrame(npMCI, npMCI->lFrom);
  527. if (lTemp >= npMCI->lFrom)
  528. npMCI->lFrom = lTemp;
  529. if (npMCI->lFrom > npMCI->lFrames - 1)
  530. npMCI->lFrom = npMCI->lFrames - 1;
  531. DPF2(("Interleaved: jumping from %ld to %ld\n", npMCI->lCurrentFrame, npMCI->lFrom));
  532. CalculateTargetFrame(npMCI);
  533. return TRUE;
  534. }
  535. #endif
  536. if (npMCI->hWave && npMCI->lCurrentFrame >= npMCI->lAudioStart) {
  537. TIMESTART(timeAudio);
  538. if (!PlayRecordAudio(npMCI, &fHurryUp, &fPlayedAudio)) {
  539. DPF(("Error playing frame #%ld audio\n", npMCI->lCurrentFrame));
  540. return FALSE;
  541. }
  542. TIMEEND(timeAudio);
  543. }
  544. }
  545. /* If we're at the right frame, and we haven't started yet,
  546. ** then begin play and start timing.
  547. */
  548. if ((npMCI->lCurrentFrame > npMCI->lRealStart + (LONG) npMCI->dwBufferedVideo) &&
  549. (npMCI->wTaskState != TASKPLAYING)) {
  550. if (!(npMCI->dwFlags & MCIAVI_PAUSE)) {
  551. goto RestartPlay0;
  552. } else
  553. goto PauseNow0;
  554. }
  555. if (npMCI->wTaskState == TASKPLAYING) {
  556. if (npMCI->dwFlags & MCIAVI_PAUSE) {
  557. PauseNow0:
  558. PauseAVI(npMCI);
  559. #ifndef WIN32
  560. // no way do we want to do this on NT. If you get a slow disk, you will
  561. // never get to pause because we can't get the stuff in fast enough to keep up
  562. /* The line below says that if we're trying to pause,
  563. ** but we're behind on our audio, we should keep playing
  564. ** for a little bit so that our audio buffers get full.
  565. ** Unfortunately, the current code causes the code
  566. ** above to get called over and over, which is bad.
  567. */
  568. if (fPlayedAudio && npMCI->wABFull < npMCI->wABs)
  569. goto KeepFilling;
  570. #endif
  571. BePaused(npMCI);
  572. RestartPlay0:
  573. if (npMCI->dwFlags & MCIAVI_STOP)
  574. return FALSE;
  575. RestartAVI(npMCI);
  576. }
  577. }
  578. KeepFilling:
  579. if (npMCI->lCurrentFrame > npMCI->lVideoStart &&
  580. npMCI->lCurrentFrame < npMCI->lFrames &&
  581. npMCI->wTaskState == TASKPLAYING) {
  582. iFrame = WhatFrameIsItTimeFor(npMCI);
  583. if (iFrame >= npMCI->lFrames)
  584. goto dontskip;
  585. iHurryUp = (int)(iFrame - npMCI->lCurrentFrame);
  586. fHurryUp = iHurryUp > gwHurryTolerance;
  587. // if (iHurryUp > gwSkipTolerance && !npMCI->hpFrameIndex)
  588. // DPF("We should read the index?\n");
  589. if (iHurryUp > 1 && npMCI->hpFrameIndex && (npMCI->dwOptionFlags & MCIAVIO_SKIPFRAMES)) {
  590. //
  591. // WE ARE BEHIND!!! by one or more frames.
  592. //
  593. // if we are late we can do one of the following:
  594. //
  595. // dont draw frames but keep reading/decompressing them
  596. // (ie set fHurryUp)
  597. //
  598. // skip ahead to a key frame.
  599. //
  600. // !!! If we're very close to the next key frame, be more
  601. // willing to skip ahead....
  602. //
  603. if (iHurryUp > gwSkipTolerance) {
  604. iNextKey = FrameNextKey(iFrame);
  605. iPrevKey = FramePrevKey(iFrame);
  606. if (iPrevKey > npMCI->lCurrentFrame &&
  607. iFrame - iPrevKey < gwHurryTolerance &&
  608. iNextKey - iFrame > gwSkipTolerance) {
  609. DPF2(("Skipping from %ld to PREV KEY %ld (time for %ld next key=%ld).\n", npMCI->lCurrentFrame, iPrevKey, iFrame, iNextKey));
  610. iKey = iPrevKey;
  611. }
  612. // !!! We'll only skip if the key frame is at most as far
  613. // ahead as we are behind.....
  614. else if (iNextKey > npMCI->lCurrentFrame &&
  615. iNextKey <= iFrame + gwSkipTolerance /*gwMaxSkipEver*/) {
  616. DPF2(("Skipping from %ld to NEXT KEY %ld (time for %ld prev key=%ld).\n", npMCI->lCurrentFrame, iNextKey, iFrame, iPrevKey));
  617. iKey = iNextKey;
  618. } else {
  619. DPF2(("WANTED to skip from %ld to %ld (time for %ld)!\n", npMCI->lCurrentFrame,iNextKey,iFrame));
  620. goto dontskip;
  621. }
  622. npMCI->lVideoStart = iKey;
  623. npMCI->dwSkippedFrames += iKey - npMCI->lCurrentFrame;
  624. dontskip:
  625. fHurryUp = TRUE;
  626. }
  627. else {
  628. iKey = FrameNextKey(npMCI->lCurrentFrame);
  629. if (iKey - npMCI->lCurrentFrame > 0 &&
  630. iKey - npMCI->lCurrentFrame <= gwHurryTolerance) {
  631. DPF2(("Skipping from %ld to next key frame %ld (time for %ld).\n", npMCI->lCurrentFrame, iKey, iFrame));
  632. npMCI->dwSkippedFrames += iKey - npMCI->lCurrentFrame;
  633. npMCI->lVideoStart = iKey;
  634. fHurryUp = TRUE;
  635. }
  636. }
  637. }
  638. }
  639. if (npMCI->dwFlags & MCIAVI_WAVEPAUSED)
  640. fHurryUp = TRUE;
  641. /* If we've actually started timing:
  642. ** Check if we should send a signal.
  643. ** Check to see if we should break out of the loop.
  644. ** Wait until it's time for the next frame.
  645. */
  646. if (npMCI->wTaskState == TASKPLAYING &&
  647. npMCI->lCurrentFrame >= npMCI->lVideoStart) {
  648. if (npMCI->dwSignals)
  649. CheckSignals(npMCI, npMCI->lCurrentFrame - npMCI->dwBufferedVideo);
  650. #ifdef WAITHISTOGRAM
  651. /* Adjust to achieve proper tension. */
  652. if (fPlayedAudio) {
  653. /* If we're playing, keep statistics about how we're doing. */
  654. ++wHist[npMCI->wABFull];
  655. }
  656. #endif
  657. if (!WaitTillNextFrame(npMCI))
  658. return FALSE;
  659. }
  660. if (npMCI->lCurrentFrame >= npMCI->lVideoStart &&
  661. npMCI->lCurrentFrame < npMCI->lFrames) {
  662. #ifdef SHOWSKIPPED
  663. if (fHurryUp && wSkipped < NUMSKIPSSHOWN) {
  664. lSkipped[wSkipped++] = npMCI->lCurrentFrame;
  665. }
  666. #endif
  667. /* hold critsec round all worker thread drawing */
  668. EnterCrit(npMCI);
  669. TIMESTART(timeVideo);
  670. if (!DisplayVideoFrame(npMCI, fHurryUp)) {
  671. LeaveCrit(npMCI);
  672. npMCI->dwTaskError = MCIERR_AVI_DISPLAYERROR;
  673. return FALSE;
  674. }
  675. TIMEEND(timeVideo);
  676. LeaveCrit(npMCI);
  677. #ifdef DRAWTIMEHIST
  678. if (!fHurryUp && (wDrawn < NUMDRAWN)) {
  679. dwDrawTime[wDrawn++] = npMCI->dwLastDrawTime;
  680. }
  681. #endif
  682. }
  683. StatusBar(npMCI, 0, 4, npMCI->wABs, npMCI->wABFull);
  684. StatusBar(npMCI, 1, 4, npMCI->wABs, npMCI->wABs - iHurryUp);
  685. #ifdef AVIREAD
  686. if ((npMCI->hAviRd) && (npMCI->lpBuffer != NULL)) {
  687. /* finished with this buffer - put back on queue */
  688. avird_emptybuffer(npMCI->hAviRd, npMCI->lpBuffer);
  689. npMCI->lpBuffer = NULL;
  690. }
  691. #endif
  692. return TRUE;
  693. }
  694. /******************************************************************************
  695. *****************************************************************************/
  696. BOOL NEAR PASCAL PlayNonInterleaved(NPMCIGRAPHIC npMCI)
  697. {
  698. BOOL fHurryUp = FALSE;
  699. int iHurryUp;
  700. LONG iFrame;
  701. LONG iKey;
  702. LONG iNextKey;
  703. LONG iPrevKey;
  704. if (npMCI->hWave) {
  705. TIMESTART(timeAudio);
  706. KeepPlayingAudio(npMCI);
  707. TIMEEND(timeAudio);
  708. }
  709. if (npMCI->wTaskState == TASKPLAYING) {
  710. iFrame = WhatFrameIsItTimeFor(npMCI);
  711. if (iFrame >= npMCI->lFrames)
  712. goto dontskip;
  713. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  714. /* Since we're going backwards, always skip to key frame. */
  715. DPF3((" Current = %ld, time for %ld.\n", npMCI->lCurrentFrame, iFrame));
  716. iFrame = FramePrevKey(iFrame);
  717. // !!! Send signals for skipped frames?
  718. npMCI->dwFramesSeekedPast += npMCI->lCurrentFrame - iFrame;
  719. npMCI->dwSkippedFrames += npMCI->lCurrentFrame - iFrame;
  720. npMCI->lCurrentFrame = iFrame;
  721. } else if (npMCI->lCurrentFrame < npMCI->lFrames) {
  722. #ifdef BEHINDHIST
  723. {
  724. int iDelta;
  725. iDelta = iFrame - npMCI->lCurrentFrame + BEHINDOFFSET;
  726. iDelta = min(NUMBEHIND, max(0, iDelta));
  727. wBehind[iDelta]++;
  728. }
  729. #endif
  730. iHurryUp = (int)(iFrame - npMCI->lCurrentFrame);
  731. fHurryUp = iHurryUp > gwHurryTolerance;
  732. if (iHurryUp > 1 && npMCI->hpFrameIndex && (npMCI->dwOptionFlags & MCIAVIO_SKIPFRAMES)) {
  733. //
  734. // WE ARE BEHIND!!! by one or more frames.
  735. //
  736. // if we are late we can do one of the following:
  737. //
  738. // dont draw frames but keep reading/decompressing them
  739. // (ie set fHurryUp)
  740. //
  741. // skip ahead to a key frame.
  742. //
  743. // !!! If we're very close to the next key frame, be more
  744. // willing to skip ahead....
  745. //
  746. if (iHurryUp > gwSkipTolerance) {
  747. iNextKey = FrameNextKey(iFrame);
  748. iPrevKey = FramePrevKey(iFrame);
  749. if (iPrevKey > npMCI->lCurrentFrame &&
  750. iFrame - iPrevKey < gwHurryTolerance &&
  751. iNextKey - iFrame > gwSkipTolerance) {
  752. DPF2(("Skipping from %ld to PREV KEY %ld (time for %ld next key=%ld).\n", npMCI->lCurrentFrame, iPrevKey, iFrame, iNextKey));
  753. iKey = iPrevKey;
  754. fHurryUp = TRUE;
  755. }
  756. // !!! We'll only skip if the key frame is at most as far
  757. // ahead as we are behind.....
  758. else if (iNextKey > npMCI->lCurrentFrame &&
  759. iNextKey <= iFrame + gwSkipTolerance /*gwMaxSkipEver*/) {
  760. DPF2(("Skipping from %ld to NEXT KEY %ld (time for %ld prev key=%ld).\n", npMCI->lCurrentFrame, iNextKey, iFrame, iPrevKey));
  761. iKey = iNextKey; // assume next key
  762. fHurryUp = FALSE;
  763. } else {
  764. DPF2(("WANTED to skip from %ld to %ld (time for %ld)!\n", npMCI->lCurrentFrame,iNextKey,iFrame));
  765. goto dontskip;
  766. }
  767. npMCI->dwFramesSeekedPast += iKey - npMCI->lCurrentFrame;
  768. npMCI->dwSkippedFrames += iKey - npMCI->lCurrentFrame;
  769. npMCI->lCurrentFrame = iKey;
  770. dontskip:
  771. ;
  772. }
  773. else if (FramePrevKey(iFrame) == iFrame) {
  774. DPF2(("Skipping from %ld to %ld (time for key frame).\n", npMCI->lCurrentFrame, iFrame));
  775. iKey = iFrame;
  776. npMCI->dwFramesSeekedPast += iKey - npMCI->lCurrentFrame;
  777. npMCI->dwSkippedFrames += iKey - npMCI->lCurrentFrame;
  778. npMCI->lCurrentFrame = iKey;
  779. fHurryUp = FALSE;
  780. }
  781. else {
  782. iKey = FrameNextKey(npMCI->lCurrentFrame);
  783. if (iKey > npMCI->lCurrentFrame &&
  784. iKey - npMCI->lCurrentFrame <= gwHurryTolerance) {
  785. DPF2(("Skipping from %ld to next key frame %ld (time for %ld).\n", npMCI->lCurrentFrame, iKey, iFrame));
  786. npMCI->dwFramesSeekedPast += iKey - npMCI->lCurrentFrame;
  787. npMCI->dwSkippedFrames += iKey - npMCI->lCurrentFrame;
  788. npMCI->lCurrentFrame = iKey;
  789. fHurryUp = ((iKey - iFrame) > gwHurryTolerance);
  790. }
  791. }
  792. }
  793. StatusBar(npMCI, 0, 4, npMCI->wABs, npMCI->wABFull);
  794. StatusBar(npMCI, 1, 4, npMCI->wABs, npMCI->wABs - iHurryUp);
  795. }
  796. }
  797. // !!! Somewhere in here, read other streams.
  798. // Should this be before, or after, video?
  799. /* If lCurrentFrame == lFrames, we're really at the end of
  800. ** the file, so there isn't another record to read.
  801. */
  802. if (npMCI->lCurrentFrame < npMCI->lFrames) {
  803. /* Read new record into buffer */
  804. npMCI->dwLastReadTime = (DWORD)(-(LONG)timeGetTime());
  805. TIMESTART(timeRead);
  806. if (!ReadNextVideoFrame(npMCI, NULL)) {
  807. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  808. DPF2(("Error reading frame #%ld\n", npMCI->lCurrentFrame));
  809. return FALSE;
  810. }
  811. TIMEEND(timeRead);
  812. npMCI->dwLastReadTime += timeGetTime();
  813. npMCI->lLastRead = npMCI->lCurrentFrame;
  814. #ifdef READTIMEHIST
  815. if (wRead < NUMREAD) {
  816. dwReadTime[wRead++] = npMCI->dwLastReadTime;
  817. }
  818. #endif
  819. }
  820. /* If we're at the right frame, and we haven't started yet,
  821. ** then begin play and start timing.
  822. */
  823. if ((((npMCI->lCurrentFrame > (npMCI->lRealStart +
  824. (LONG) npMCI->dwBufferedVideo)) &&
  825. (npMCI->lCurrentFrame < (npMCI->lTo))) ||
  826. (npMCI->dwFlags & MCIAVI_REVERSE)) &&
  827. (npMCI->wTaskState != TASKPLAYING) &&
  828. !(npMCI->dwFlags & MCIAVI_SEEKING)) {
  829. if (!(npMCI->dwFlags & MCIAVI_PAUSE)) {
  830. goto RestartPlay;
  831. } else
  832. goto PauseNow;
  833. }
  834. /* If we've actually started timing:
  835. ** Check if we should send a signal.
  836. ** Check to see if we should return FALSE out of the loop.
  837. ** Wait until it's time for the next frame.
  838. */
  839. if (npMCI->wTaskState == TASKPLAYING) {
  840. if (npMCI->dwFlags & MCIAVI_PAUSE) {
  841. PauseNow:
  842. PauseAVI(npMCI);
  843. BePaused(npMCI);
  844. RestartPlay:
  845. if (TimeToQuit(npMCI))
  846. return FALSE;
  847. RestartAVI(npMCI);
  848. }
  849. if (npMCI->dwSignals)
  850. CheckSignals(npMCI, npMCI->lCurrentFrame - npMCI->dwBufferedVideo);
  851. if (npMCI->lCurrentFrame < npMCI->lFrames + (LONG) npMCI->dwBufferedVideo) {
  852. while (1) {
  853. iFrame = WhatFrameIsItTimeFor(npMCI);
  854. TIMESTART(timeYield);
  855. aviTaskYield();
  856. TIMEEND(timeYield);
  857. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  858. if (iFrame <= npMCI->lCurrentFrame)
  859. break;
  860. if (npMCI->lCurrentFrame < npMCI->lTo)
  861. break;
  862. } else {
  863. if (iFrame >= npMCI->lCurrentFrame)
  864. break;
  865. if (npMCI->lCurrentFrame > npMCI->lTo)
  866. break;
  867. }
  868. if (npMCI->hWave) {
  869. TIMESTART(timeAudio);
  870. KeepPlayingAudio(npMCI);
  871. TIMEEND(timeAudio);
  872. }
  873. DPF3(("Waiting: Current = %ld, time for %ld.\n", npMCI->lCurrentFrame, iFrame));
  874. if (TimeToQuit(npMCI))
  875. return FALSE;
  876. }
  877. }
  878. if (TimeToQuit(npMCI))
  879. return FALSE;
  880. }
  881. if (((npMCI->lCurrentFrame >= npMCI->lVideoStart) &&
  882. (npMCI->lCurrentFrame < npMCI->lFrames)) ||
  883. (npMCI->dwFlags & MCIAVI_REVERSE)) {
  884. EnterCrit(npMCI);
  885. TIMESTART(timeVideo);
  886. if (!DisplayVideoFrame(npMCI, fHurryUp)) {
  887. npMCI->dwTaskError = MCIERR_AVI_DISPLAYERROR;
  888. LeaveCrit(npMCI);
  889. return FALSE;
  890. }
  891. TIMEEND(timeVideo);
  892. LeaveCrit(npMCI);
  893. #ifdef DRAWTIMEHIST
  894. if (!fHurryUp && (wDrawn < NUMDRAWN)) {
  895. dwDrawTime[wDrawn++] = npMCI->dwLastDrawTime;
  896. }
  897. #endif
  898. }
  899. //
  900. // now is a good time to deal with other streams
  901. //
  902. if (npMCI->nOtherStreams > 0 || npMCI->nVideoStreams > 1) {
  903. if (npMCI->wTaskState != TASKPLAYING)
  904. iFrame = npMCI->lCurrentFrame;
  905. TIMESTART(timeOther);
  906. DealWithOtherStreams(npMCI, iFrame);
  907. TIMEEND(timeOther);
  908. }
  909. return TRUE;
  910. }
  911. /******************************************************************************
  912. *****************************************************************************/
  913. BOOL NEAR PASCAL PlayAudioOnly(NPMCIGRAPHIC npMCI)
  914. {
  915. npMCI->lFrameDrawn = npMCI->lCurrentFrame;
  916. if (npMCI->hWave) {
  917. TIMESTART(timeAudio);
  918. KeepPlayingAudio(npMCI);
  919. TIMEEND(timeAudio);
  920. }
  921. /* If we're at the right frame, and we haven't started yet,
  922. ** then begin play and start timing.
  923. */
  924. if ((npMCI->wTaskState != TASKPLAYING) &&
  925. !(npMCI->dwFlags & MCIAVI_SEEKING)) {
  926. if (!(npMCI->dwFlags & MCIAVI_PAUSE)) {
  927. goto RestartPlay;
  928. } else
  929. goto PauseNow;
  930. }
  931. /* If we've actually started timing:
  932. ** Check if we should send a signal.
  933. ** Check to see if we should return FALSE out of the loop.
  934. ** Wait until it's time for the next frame.
  935. */
  936. if (npMCI->wTaskState == TASKPLAYING) {
  937. npMCI->lCurrentFrame = WhatFrameIsItTimeFor(npMCI);
  938. if (npMCI->dwFlags & MCIAVI_PAUSE) {
  939. PauseNow:
  940. PauseAVI(npMCI);
  941. BePaused(npMCI);
  942. RestartPlay:
  943. if (TimeToQuit(npMCI))
  944. return FALSE;
  945. RestartAVI(npMCI);
  946. }
  947. if (npMCI->dwSignals)
  948. CheckSignals(npMCI, npMCI->lCurrentFrame - npMCI->dwBufferedVideo);
  949. //
  950. // dont yield if updating
  951. //
  952. if (!(npMCI->dwFlags & MCIAVI_UPDATING)) {
  953. TIMESTART(timeYield);
  954. aviTaskYield();
  955. TIMEEND(timeYield);
  956. }
  957. if (TimeToQuit(npMCI))
  958. return FALSE;
  959. }
  960. return TRUE;
  961. }
  962. /******************************************************************************
  963. *****************************************************************************/
  964. #pragma message("PlayNonIntFromCD needs fixed?")
  965. BOOL NEAR PASCAL PlayNonIntFromCD(NPMCIGRAPHIC npMCI)
  966. {
  967. BOOL fHurryUp = FALSE;
  968. LONG lNewFrame;
  969. DWORD ckid;
  970. UINT wStream;
  971. AnotherChunk:
  972. /* If lCurrentFrame == lFrames, we're really at the end of
  973. ** the file, so there isn't another record to read.
  974. */
  975. if (npMCI->lCurrentFrame < npMCI->lFrames) {
  976. /* Read new record into buffer */
  977. TIMESTART(timeRead);
  978. ckid = ReadNextChunk(npMCI);
  979. TIMEEND(timeRead);
  980. if (ckid == 0) {
  981. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  982. DPF(("Error reading frame #%ld\n", npMCI->lCurrentFrame));
  983. return FALSE;
  984. }
  985. npMCI->lLastRead = npMCI->lCurrentFrame;
  986. wStream = StreamFromFOURCC(ckid);
  987. if (wStream == (UINT) npMCI->nVideoStream) {
  988. if (TWOCCFromFOURCC(ckid) == cktypePALchange) {
  989. npMCI->lp += 2 * sizeof(DWORD);
  990. ProcessPaletteChange(npMCI, npMCI->dwThisRecordSize -
  991. 2 * sizeof(DWORD));
  992. npMCI->lLastPaletteChange = npMCI->lCurrentFrame;
  993. goto AnotherChunk;
  994. }
  995. } else if (wStream == (UINT) npMCI->nAudioStream) {
  996. TIMESTART(timeAudio);
  997. if (npMCI->hWave)
  998. HandleAudioChunk(npMCI);
  999. TIMEEND(timeAudio);
  1000. goto AnotherChunk;
  1001. } else {
  1002. goto AnotherChunk;
  1003. }
  1004. }
  1005. if (npMCI->wTaskState == TASKPLAYING) {
  1006. lNewFrame = WhatFrameIsItTimeFor(npMCI);
  1007. DPF3((" Current = %ld, time for %ld.\n", npMCI->lCurrentFrame, lNewFrame));
  1008. if (npMCI->lCurrentFrame < lNewFrame) {
  1009. fHurryUp = TRUE;
  1010. }
  1011. }
  1012. /* If we're at the right frame, and we haven't started yet,
  1013. ** then begin play and start timing.
  1014. */
  1015. if ((npMCI->lCurrentFrame > npMCI->lRealStart + (LONG) npMCI->dwBufferedVideo) &&
  1016. (npMCI->lCurrentFrame < npMCI->lTo) &&
  1017. (npMCI->wTaskState != TASKPLAYING)) {
  1018. if (!(npMCI->dwFlags & MCIAVI_PAUSE)) {
  1019. goto RestartPlay;
  1020. } else
  1021. goto PauseNow;
  1022. }
  1023. /* If we've actually started timing:
  1024. ** Check if we should send a signal.
  1025. ** Check to see if we should return FALSE out of the loop.
  1026. ** Wait until it's time for the next frame.
  1027. */
  1028. if (npMCI->wTaskState == TASKPLAYING) {
  1029. if (npMCI->dwFlags & MCIAVI_PAUSE) {
  1030. PauseNow:
  1031. PauseAVI(npMCI);
  1032. BePaused(npMCI);
  1033. RestartPlay:
  1034. if (TimeToQuit(npMCI))
  1035. return FALSE;
  1036. RestartAVI(npMCI);
  1037. }
  1038. if (npMCI->dwSignals)
  1039. CheckSignals(npMCI, npMCI->lCurrentFrame - npMCI->dwBufferedVideo);
  1040. WaitMore:
  1041. lNewFrame = WhatFrameIsItTimeFor(npMCI);
  1042. TIMESTART(timeYield);
  1043. aviTaskYield();
  1044. TIMEEND(timeYield);
  1045. if (lNewFrame < npMCI->lCurrentFrame) {
  1046. DPF3(("Waiting: Current = %ld, time for %ld.\n", npMCI->lCurrentFrame, lNewFrame));
  1047. if (TimeToQuit(npMCI))
  1048. return FALSE;
  1049. else
  1050. goto WaitMore;
  1051. }
  1052. }
  1053. if (npMCI->lCurrentFrame >= npMCI->lVideoStart) {
  1054. TIMESTART(timeVideo);
  1055. EnterCrit(npMCI);
  1056. if (!DisplayVideoFrame(npMCI, fHurryUp)) {
  1057. npMCI->dwTaskError = MCIERR_AVI_DISPLAYERROR;
  1058. LeaveCrit(npMCI);
  1059. return FALSE;
  1060. }
  1061. TIMEEND(timeVideo);
  1062. LeaveCrit(npMCI);
  1063. }
  1064. return TRUE;
  1065. }
  1066. /******************************************************************************
  1067. *****************************************************************************/
  1068. /* This function returns what frame we should be on. */
  1069. LONG NEAR PASCAL WhatFrameIsItTimeFor(NPMCIGRAPHIC npMCI)
  1070. {
  1071. LONG lTime;
  1072. LONG lFrame;
  1073. // If timing is off, it's always just time to play the current frame.
  1074. if (npMCI->dwPlayMicroSecPerFrame == 0)
  1075. return npMCI->lCurrentFrame;
  1076. //
  1077. // if we have not started playing npMCI->dwTimingStart is bogus
  1078. //
  1079. Assert(npMCI->wTaskState == TASKPLAYING);
  1080. AssertFrame(npMCI->lCurrentFrame - (LONG)npMCI->dwBufferedVideo);
  1081. //
  1082. // NOTE we must grab dwTimingStart *before* calling
  1083. // timeGetTime() because dwTimingStart is changed in the wave
  1084. // callback and we dont want to have time go backward.
  1085. //
  1086. lTime = (volatile DWORD)npMCI->dwTimingStart; // grab this as one unit!
  1087. lTime = (LONG)timeGetTime() - lTime
  1088. + npMCI->dwLastDrawTime
  1089. // + npMCI->dwLastReadTime
  1090. ;
  1091. Assert(lTime >= 0);
  1092. if (npMCI->hWave) {
  1093. if (npMCI->dwFlags & MCIAVI_WAVEPAUSED)
  1094. lTime = 0;
  1095. lTime += muldiv32(npMCI->dwAudioPlayed,
  1096. 1000L, npMCI->pWF->nAvgBytesPerSec);
  1097. }
  1098. /* Convert from MS to frames.... */
  1099. lFrame = muldiv32(lTime, 1000, npMCI->dwPlayMicroSecPerFrame);
  1100. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  1101. lFrame = npMCI->lFramePlayStart - lFrame;
  1102. if (lFrame < npMCI->lTo)
  1103. lFrame = npMCI->lTo;
  1104. }
  1105. else {
  1106. lFrame = lFrame + npMCI->lFramePlayStart + npMCI->dwBufferedVideo;
  1107. if ((lFrame > npMCI->lTo) && (lFrame > npMCI->lCurrentFrame))
  1108. lFrame = npMCI->lTo;
  1109. }
  1110. if (lFrame > npMCI->lFrames + (LONG)npMCI->dwBufferedVideo || lFrame < 0) {
  1111. DPF(("WhatFrameIsItTimeFor: bad frame %ld\n", lFrame));
  1112. AssertSz(0, "bad frame in WhatFrameIsItTimeFor");
  1113. lFrame = npMCI->lCurrentFrame;
  1114. }
  1115. return lFrame;
  1116. }
  1117. /******************************************************************************
  1118. *****************************************************************************/
  1119. BOOL NEAR PASCAL PauseAVI(NPMCIGRAPHIC npMCI)
  1120. {
  1121. if (npMCI->wTaskState == TASKPLAYING) {
  1122. int stream;
  1123. if (npMCI->hWave)
  1124. waveOutPause(npMCI->hWave);
  1125. if (npMCI->hicDraw)
  1126. ICDrawStop(npMCI->hicDraw);
  1127. for (stream = 0; stream < npMCI->streams; stream++) {
  1128. if (SI(stream)->hicDraw)
  1129. ICDrawStop(SI(stream)->hicDraw);
  1130. }
  1131. npMCI->dwPauseTime = Now();
  1132. npMCI->dwTotalMSec += npMCI->dwPauseTime - npMCI->dwMSecPlayStart;
  1133. }
  1134. if (npMCI->dwFlags & MCIAVI_CUEING) {
  1135. /* If we're cueing, report that it was successful. */
  1136. npMCI->dwFlags &= ~(MCIAVI_CUEING);
  1137. GraphicDelayedNotify(npMCI, MCI_NOTIFY_SUCCESSFUL);
  1138. }
  1139. DPF2(("MCIAVI: Pausing\n"));
  1140. npMCI->wTaskState = TASKPAUSED;
  1141. return TRUE;
  1142. }
  1143. /******************************************************************************
  1144. *****************************************************************************/
  1145. BOOL NEAR PASCAL BePaused(NPMCIGRAPHIC npMCI)
  1146. {
  1147. TIMEEND(timePlay);
  1148. TIMESTART(timePaused);
  1149. while (npMCI->dwFlags & MCIAVI_PAUSE) {
  1150. if (npMCI->dwFlags & MCIAVI_STOP)
  1151. return FALSE;
  1152. if (npMCI->dwFlags & MCIAVI_NEEDUPDATE) {
  1153. /* Since we're paused and we have nothing better
  1154. ** to do, update the screen.
  1155. */
  1156. DoStreamUpdate(npMCI, FALSE);
  1157. }
  1158. mmTaskBlock(npMCI->hTask);
  1159. }
  1160. TIMEEND(timePaused);
  1161. TIMESTART(timePlay);
  1162. return TRUE;
  1163. }
  1164. /******************************************************************************
  1165. *****************************************************************************/
  1166. BOOL NEAR PASCAL RestartAVI(NPMCIGRAPHIC npMCI)
  1167. {
  1168. int stream;
  1169. Assert(npMCI->wTaskState != TASKPLAYING);
  1170. /* Mark that play has actually begun */
  1171. npMCI->wTaskState = TASKPLAYING;
  1172. DPF(("MCIAVI: Starting\n"));
  1173. TIMESTART(timeYield);
  1174. aviTaskYield();
  1175. aviTaskYield();
  1176. aviTaskYield();
  1177. TIMEEND(timeYield);
  1178. DPF2(("MCIAVI: Starting (done yielding)\n"));
  1179. /* Reset clock and restart */
  1180. if (npMCI->dwPauseTime == 0)
  1181. Assert(npMCI->dwTimingStart == 0);
  1182. npMCI->dwMSecPlayStart = Now(); // get the time we started playing
  1183. //
  1184. // if we were paused subtract off the time we spent paused from
  1185. // the timing start
  1186. //
  1187. if (npMCI->dwPauseTime == 0)
  1188. npMCI->dwTimingStart = npMCI->dwMSecPlayStart;
  1189. else
  1190. npMCI->dwTimingStart += (npMCI->dwMSecPlayStart - npMCI->dwPauseTime);
  1191. if (npMCI->hWave)
  1192. waveOutRestart(npMCI->hWave);
  1193. if (npMCI->hicDraw)
  1194. ICDrawStart(npMCI->hicDraw);
  1195. for (stream = 0; stream < npMCI->streams; stream++) {
  1196. if (SI(stream)->hicDraw)
  1197. ICDrawStart(SI(stream)->hicDraw);
  1198. }
  1199. return TRUE;
  1200. }
  1201. /* This function sets up things that will be needed to play.
  1202. **
  1203. ** Returns zero if no error, otherwise an MCI error code.
  1204. **
  1205. ** Note: Even if this function returns an error, CleanUpPlay()
  1206. ** will still be called, so we don't have to cleanup here.
  1207. */
  1208. DWORD NEAR PASCAL PrepareToPlay(NPMCIGRAPHIC npMCI)
  1209. {
  1210. UINT w;
  1211. DWORD dwPosition;
  1212. int stream;
  1213. BOOL fCDFile;
  1214. BOOL fNetFile;
  1215. BOOL fHardFile;
  1216. Assert(npMCI->wTaskState != TASKPLAYING);
  1217. //
  1218. // lets choose the play back method:
  1219. //
  1220. // playing reverse: (random access!)
  1221. // use MCIAVI_ALG_HARDDISK always (random access mode)
  1222. //
  1223. // audio is preloaded: (will never happen?)
  1224. // on a CD-ROM use MCIAVI_ALG_INTERLEAVED
  1225. // on a HARDDISK use MCIAVI_ALG_HARDDISK
  1226. // on a NET use MCIAVI_ALG_HARDDISK
  1227. //
  1228. // file is interleaved:
  1229. // on a CD-ROM use MCIAVI_ALG_INTERLEAVED
  1230. // on a HARDDISK use MCIAVI_ALG_HARDDISK
  1231. // on a NET use MCIAVI_ALG_HARDDISK
  1232. //
  1233. // file is not interleaved:
  1234. // on a CD-ROM use MCIAVI_ALG_CDROM
  1235. // on a HARDDISK use MCIAVI_ALG_HARDDISK
  1236. // on a NET use MCIAVI_ALG_HARDDISK
  1237. //
  1238. fCDFile = npMCI->uDriveType == DRIVE_CDROM;
  1239. fNetFile = npMCI->uDriveType == DRIVE_REMOTE;
  1240. fHardFile = !fCDFile && !fNetFile;
  1241. if (npMCI->nVideoStreams == 0 && npMCI->nOtherStreams == 0) {
  1242. npMCI->wPlaybackAlg = MCIAVI_ALG_AUDIOONLY;
  1243. } else if (npMCI->dwFlags & MCIAVI_REVERSE || npMCI->pf) {
  1244. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1245. }
  1246. else if (npMCI->dwFlags & MCIAVI_NOTINTERLEAVED) {
  1247. #if 0
  1248. if (fCDFile)
  1249. npMCI->wPlaybackAlg = MCIAVI_ALG_CDROM;
  1250. else
  1251. #endif
  1252. if (fNetFile)
  1253. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1254. else
  1255. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1256. }
  1257. else {
  1258. if (fCDFile)
  1259. npMCI->wPlaybackAlg = MCIAVI_ALG_INTERLEAVED;
  1260. #if 0
  1261. else if (fNetFile)
  1262. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1263. else
  1264. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1265. #else
  1266. else if (fNetFile)
  1267. npMCI->wPlaybackAlg = MCIAVI_ALG_INTERLEAVED;
  1268. else
  1269. npMCI->wPlaybackAlg = MCIAVI_ALG_INTERLEAVED;
  1270. #endif
  1271. }
  1272. // Interleaved playback doesn't work well at very low speeds!
  1273. if ((npMCI->dwSpeedFactor < 100) &&
  1274. (npMCI->wPlaybackAlg != MCIAVI_ALG_HARDDISK) &&
  1275. (npMCI->wPlaybackAlg != MCIAVI_ALG_AUDIOONLY)) {
  1276. DPF(("Was going to play interleaved, but speed < 10%% of normal...\n"));
  1277. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1278. }
  1279. #if 0
  1280. //
  1281. // sigh! we need to always have the index read now, so we do it in
  1282. // aviopen
  1283. //
  1284. /* Be sure the index has been read, if we need it. */
  1285. if (npMCI->hpFrameIndex == NULL)
  1286. if (npMCI->wPlaybackAlg != MCIAVI_ALG_INTERLEAVED || npMCI->lFrom > 0)
  1287. ReadIndex(npMCI);
  1288. #endif
  1289. #ifdef DEBUG
  1290. switch (npMCI->wPlaybackAlg) {
  1291. case MCIAVI_ALG_INTERLEAVED:
  1292. Assert(!(npMCI->dwFlags & MCIAVI_NOTINTERLEAVED));
  1293. DPF(("playing a interleaved file\n"));
  1294. break;
  1295. case MCIAVI_ALG_CDROM:
  1296. Assert(npMCI->dwFlags & MCIAVI_NOTINTERLEAVED);
  1297. DPF(("playing a non interleaved file from CD-ROM\n"));
  1298. break;
  1299. case MCIAVI_ALG_HARDDISK:
  1300. if (npMCI->dwFlags & MCIAVI_NOTINTERLEAVED)
  1301. DPF(("random access play (non-interleaved file)\n"));
  1302. else
  1303. DPF(("random access play (interleaved file)\n"));
  1304. break;
  1305. case MCIAVI_ALG_AUDIOONLY:
  1306. Assert(npMCI->nAudioStreams);
  1307. DPF(("audio-only!\n"));
  1308. break;
  1309. default:
  1310. Assert(0);
  1311. break;
  1312. }
  1313. #endif
  1314. #if 0
  1315. //
  1316. // set a MMIO buffer if we are playing interleaved of a non cd-rom
  1317. //
  1318. if (npMCI->hmmio && fNetFile && npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED) {
  1319. #define BUFFER_SIZE (32l*1024)
  1320. if (npMCI->lpMMIOBuffer == NULL) {
  1321. DPF(("Using %u byte MMIO buffer...\n", BUFFER_SIZE));
  1322. npMCI->lpMMIOBuffer = AllocMem(BUFFER_SIZE);
  1323. mmioSetBuffer(npMCI->hmmio, npMCI->lpMMIOBuffer, BUFFER_SIZE, 0);
  1324. }
  1325. //!!! should we do this for a seek?
  1326. //!!! should we free this in CleanUpPlay?
  1327. }
  1328. else {
  1329. if (npMCI->lpMMIOBuffer != NULL)
  1330. FreeMem(npMCI->lpMMIOBuffer);
  1331. npMCI->lpMMIOBuffer = NULL;
  1332. if (npMCI->hmmio)
  1333. mmioSetBuffer(npMCI->hmmio, NULL, 0, 0);
  1334. }
  1335. #endif
  1336. // !!!!
  1337. gwHurryTolerance = GetProfileInt(TEXT("MCIAVI"), TEXT("Hurry"), 2);
  1338. gwSkipTolerance = GetProfileInt(TEXT("MCIAVI"), TEXT("Skip"), gwHurryTolerance * 2);
  1339. gwMaxSkipEver = GetProfileInt(TEXT("MCIAVI"), TEXT("MaxSkip"), max(60, gwSkipTolerance * 10));
  1340. Assert(npMCI->lTo <= npMCI->lFrames);
  1341. Assert(npMCI->lFrom >= 0);
  1342. /* Clear out variables, so we'll know what needs to be released. */
  1343. npMCI->hWave = NULL;
  1344. npMCI->lpAudio = NULL;
  1345. npMCI->lpBuffer = NULL;
  1346. npMCI->dwBufferSize = 0L;
  1347. npMCI->wABFull = 0;
  1348. npMCI->dwSkippedFrames = 0L;
  1349. npMCI->dwFramesSeekedPast = 0L;
  1350. npMCI->dwAudioBreaks = 0L;
  1351. npMCI->dwTotalMSec = 0;
  1352. npMCI->dwLastDrawTime = 0;
  1353. npMCI->dwLastReadTime = 0;
  1354. npMCI->dwBufferedVideo = 0;
  1355. npMCI->dwPauseTime = 0;
  1356. npMCI->dwTimingStart = 0;
  1357. /* Figure out how fast we're playing.... */
  1358. if (npMCI->dwSpeedFactor)
  1359. npMCI->dwPlayMicroSecPerFrame = muldiv32(npMCI->dwMicroSecPerFrame,
  1360. 1000L,
  1361. npMCI->dwSpeedFactor);
  1362. else
  1363. npMCI->dwPlayMicroSecPerFrame = 0; // Special "play every frame" mode
  1364. /* If we're already at the end, and we're going to repeat from the
  1365. ** start of the file, just repeat now.
  1366. */
  1367. if ((npMCI->lFrom == npMCI->lTo) &&
  1368. (npMCI->dwFlags & MCIAVI_REPEATING) &&
  1369. (npMCI->lFrom != npMCI->lRepeatFrom)) {
  1370. DPF(("Repeating from beginning before we've even started....\n"));
  1371. npMCI->lFrom = npMCI->lRepeatFrom;
  1372. }
  1373. if (npMCI->lFrom == npMCI->lTo) {
  1374. npMCI->dwFlags |= MCIAVI_SEEKING;
  1375. npMCI->dwFlags &= ~(MCIAVI_REVERSE);
  1376. }
  1377. if (npMCI->dwFlags & MCIAVI_SEEKING)
  1378. goto PlayWithoutWave;
  1379. if (npMCI->hicDraw) {
  1380. ICGetBuffersWanted(npMCI->hicDraw, &npMCI->dwBufferedVideo);
  1381. }
  1382. #ifdef DEBUG
  1383. npMCI->dwBufferedVideo = GetProfileInt(TEXT("MCIAVI"), TEXT("Buffer"), (int) npMCI->dwBufferedVideo);
  1384. #endif
  1385. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  1386. npMCI->dwBufferedVideo = 0;
  1387. }
  1388. if (npMCI->dwBufferedVideo) {
  1389. DPF(("Buffering %lu frames of video ahead....\n", npMCI->dwBufferedVideo));
  1390. }
  1391. //
  1392. // now initialize the audio stream
  1393. //
  1394. /* Open up our wave output device, if appropriate. */
  1395. if ((npMCI->nAudioStreams > 0)
  1396. && (npMCI->dwFlags & MCIAVI_PLAYAUDIO)
  1397. && (npMCI->dwPlayMicroSecPerFrame != 0)) {
  1398. npMCI->dwTaskError = SetUpAudio(npMCI, TRUE);
  1399. if ((npMCI->dwTaskError == MCIERR_OUT_OF_MEMORY) &&
  1400. (npMCI->wPlaybackAlg != MCIAVI_ALG_AUDIOONLY)) {
  1401. DPF(("Not enough memory to play audio; continuing onward....\n"));
  1402. CleanUpAudio(npMCI);
  1403. npMCI->dwTaskError = 0;
  1404. }
  1405. if (npMCI->dwTaskError == MCIERR_WAVE_OUTPUTSINUSE) {
  1406. //
  1407. // we cant get the wave device, time to go steal one.
  1408. //
  1409. // only do this if we got a real play command
  1410. // from the user, and not a internal play command
  1411. // (like when repeating or restarting)
  1412. //
  1413. // MCIAVI_NEEDTOSHOW is set when the play command
  1414. // came in through graphic.c (ie from the outside world)
  1415. //
  1416. if (npMCI->dwFlags & MCIAVI_NEEDTOSHOW) {
  1417. if (StealWaveDevice(npMCI))
  1418. npMCI->dwTaskError = SetUpAudio(npMCI, TRUE);
  1419. }
  1420. }
  1421. if (npMCI->dwTaskError == MCIERR_WAVE_OUTPUTSINUSE) {
  1422. //
  1423. // even though we did not steal the wave device we still
  1424. // want it.
  1425. //
  1426. npMCI->dwFlags |= MCIAVI_LOSTAUDIO; // we want it
  1427. }
  1428. if (((npMCI->dwTaskError == MCIERR_WAVE_OUTPUTSINUSE) ||
  1429. (npMCI->dwTaskError == MCIERR_WAVE_OUTPUTSUNSUITABLE)) &&
  1430. (npMCI->wPlaybackAlg != MCIAVI_ALG_AUDIOONLY))
  1431. npMCI->dwTaskError = 0;
  1432. if (npMCI->dwTaskError)
  1433. return npMCI->dwTaskError;
  1434. }
  1435. PlayWithoutWave:
  1436. if (npMCI->dwFlags & MCIAVI_NEEDTOSHOW) {
  1437. ShowStage(npMCI);
  1438. }
  1439. /* Get and prepare the DC we're going to be playing into */
  1440. // must hold the critsec when getting dc to avoid
  1441. // interaction with window thread calling DeviceRealize
  1442. EnterCrit(npMCI);
  1443. if (npMCI->hdc == NULL) {
  1444. npMCI->hdc = GetDC(npMCI->hwnd); // Shouldn't use cached DC!
  1445. npMCI->dwFlags |= MCIAVI_RELEASEDC;
  1446. }
  1447. if (npMCI->hdc == NULL) {
  1448. LeaveCrit(npMCI);
  1449. return MCIERR_DRIVER_INTERNAL;
  1450. }
  1451. if (npMCI->dwFlags & MCIAVI_SEEKING) {
  1452. //
  1453. // audio only
  1454. //
  1455. if (npMCI->nVideoStreams == 0 && npMCI->nOtherStreams == 0) {
  1456. npMCI->lCurrentFrame = npMCI->lFrom;
  1457. LeaveCrit(npMCI);
  1458. return 0;
  1459. }
  1460. }
  1461. /* Start up the external decompressor, if any */
  1462. /* !!!We should check these for errors */
  1463. if (!DrawBegin(npMCI, NULL)) {
  1464. LeaveCrit(npMCI);
  1465. return npMCI->dwTaskError ? npMCI->dwTaskError : MCIERR_DRIVER_INTERNAL;
  1466. }
  1467. if (!(npMCI->dwFlags & MCIAVI_SEEKING))
  1468. PrepareDC(npMCI);
  1469. // critsec just held around getting and preparing dc - look at
  1470. // devicerealize to see the function we are protecting against.
  1471. LeaveCrit(npMCI);
  1472. /*
  1473. ** what if selecting the palette causes palette changes? we should
  1474. ** yield and let the palette changes happen.
  1475. */
  1476. //aviTaskYield(); ????????
  1477. if (npMCI->hicDraw && !(npMCI->dwFlags & MCIAVI_SEEKING) &&
  1478. (npMCI->dwBufferedVideo > 0)) {
  1479. ICDrawFlush(npMCI->hicDraw);
  1480. npMCI->lFrameDrawn = (- (LONG) npMCI->wEarlyRecords) - 1;
  1481. }
  1482. if (npMCI->dwFlags & MCIAVI_FULLSCREEN) {
  1483. /* Clear out key state flags:
  1484. ** We watch for escape, space, and the left button.
  1485. */
  1486. GetAsyncKeyState(VK_ESCAPE);
  1487. GetAsyncKeyState(VK_SPACE);
  1488. GetAsyncKeyState(VK_LBUTTON);
  1489. }
  1490. /* Figure out where in the file to start playing from */
  1491. CalculateTargetFrame(npMCI);
  1492. // !!! ACK: We're starting from after where we planned to finish....
  1493. if ((npMCI->dwFlags & MCIAVI_REVERSE) &&
  1494. (npMCI->lCurrentFrame <= npMCI->lTo)) {
  1495. npMCI->dwFlags |= MCIAVI_SEEKING;
  1496. }
  1497. // !!! This should be in CalcTarget
  1498. if (npMCI->dwFlags & MCIAVI_SEEKING)
  1499. npMCI->lTo = npMCI->lRealStart;
  1500. //
  1501. // start all the streams
  1502. //
  1503. for (stream = 0; stream < npMCI->streams; stream++) {
  1504. STREAMINFO *psi = SI(stream);
  1505. if (!(npMCI->dwFlags & MCIAVI_SEEKING)) {
  1506. if (SI(stream)->ps) {
  1507. AVIStreamBeginStreaming(SI(stream)->ps,
  1508. MovieToStream(SI(stream), npMCI->lFrom),
  1509. MovieToStream(SI(stream), npMCI->lTo),
  1510. npMCI->dwPlayMicroSecPerFrame); // !!!
  1511. }
  1512. }
  1513. //
  1514. // NOTE DrawBegin() handled the default draw guy
  1515. //
  1516. if (psi->hicDraw && psi->hicDraw != npMCI->hicDraw) {
  1517. DWORD dw;
  1518. dw = ICDrawBegin(psi->hicDraw,
  1519. (npMCI->dwFlags & MCIAVI_FULLSCREEN) ?
  1520. ICDRAW_FULLSCREEN : ICDRAW_HDC,
  1521. npMCI->hpal, // palette to draw with
  1522. npMCI->hwnd, // window to draw to
  1523. npMCI->hdc, // HDC to draw to
  1524. RCX(psi->rcDest),
  1525. RCY(psi->rcDest),
  1526. RCW(psi->rcDest),
  1527. RCH(psi->rcDest),
  1528. SI(stream)->lpFormat,
  1529. RCX(psi->rcSource),
  1530. RCY(psi->rcSource),
  1531. RCW(psi->rcSource),
  1532. RCH(psi->rcSource),
  1533. muldiv32(psi->sh.dwRate, npMCI->dwSpeedFactor, 1000),
  1534. psi->sh.dwScale);
  1535. if ((LONG)dw < 0) {
  1536. // !!! Error checking?
  1537. DPF(("Draw handler failed ICDrawBegin() (err = %ld)\n", dw));
  1538. }
  1539. //
  1540. // tell the draw handler the play range
  1541. //
  1542. ICDrawStartPlay(psi->hicDraw,psi->lPlayFrom, psi->lPlayTo);
  1543. }
  1544. }
  1545. //
  1546. // tell the draw handler the play range
  1547. //
  1548. if (npMCI->hicDraw) {
  1549. ICDrawStartPlay(npMCI->hicDraw,npMCI->lRealStart,npMCI->lTo);
  1550. }
  1551. //
  1552. // seek to the right place in the file.
  1553. //
  1554. dwPosition = CalculatePosition(npMCI);
  1555. if (dwPosition == 0) {
  1556. return MCIERR_DRIVER_INTERNAL;
  1557. }
  1558. #ifdef AVIREADMANY
  1559. //
  1560. // see if we want to try to read two records at a shot, this
  1561. // should cut down the time spent in DOS doing reads.
  1562. //
  1563. // we only can do this if we have a index, and the buffer
  1564. // sizes are "small enough"
  1565. //
  1566. // if reading 2 buffers works good how about 3? 4?
  1567. //
  1568. // this helps on CD's and Networks but makes things slower
  1569. // on KenO's hard disk, so dont do hard disks.
  1570. //
  1571. // default is read many when coming from a Network, this is
  1572. // better than the old mmioSetBuffer() we used to do.
  1573. //
  1574. if (npMCI->uDriveType == DRIVE_REMOTE)
  1575. npMCI->fReadMany = TRUE;
  1576. else
  1577. npMCI->fReadMany = FALSE;
  1578. if (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED &&
  1579. npMCI->dwSuggestedBufferSize <= 30*1024 &&
  1580. GetProfileInt(TEXT("MCIAVI"), TEXT("ReadMany"), npMCI->fReadMany) &&
  1581. npMCI->hpFrameIndex) {
  1582. npMCI->dwBufferSize = npMCI->dwSuggestedBufferSize * 2;
  1583. npMCI->fReadMany = TRUE;
  1584. }
  1585. else {
  1586. npMCI->fReadMany = FALSE;
  1587. }
  1588. if (npMCI->fReadMany) {
  1589. DPF(("MCIAVI: reading two records at once (%ld bytes).\n", npMCI->dwBufferSize));
  1590. npMCI->lLastRead = npMCI->lCurrentFrame - 2;
  1591. }
  1592. #endif
  1593. AllocateReadBuffer(npMCI);
  1594. // look for palette changes between the last place we read and where
  1595. // we're starting....
  1596. ProcessPaletteChanges(npMCI, npMCI->lVideoStart);
  1597. if (npMCI->hmmio) {
  1598. /* Seek to the start of frame we're playing from */
  1599. mmioSeek(npMCI->hmmio, dwPosition, SEEK_SET);
  1600. }
  1601. #ifdef AVIREAD
  1602. /* start the async read object if we are using interleaved
  1603. * and therefore consecutive reads
  1604. */
  1605. if (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED) {
  1606. /* start async reader - allocates itself new buffers */
  1607. npMCI->hAviRd = avird_startread(mciaviReadBuffer, (DWORD) npMCI,
  1608. npMCI->dwNextRecordSize,
  1609. npMCI->lCurrentFrame,
  1610. min(npMCI->lTo+1, npMCI->lFrames));
  1611. if (!npMCI->hAviRd) {
  1612. DPF(("async read failed - reading synchronously\n"));
  1613. ResizeReadBuffer(npMCI, npMCI->dwNextRecordSize);
  1614. }
  1615. } else {
  1616. npMCI->hAviRd = NULL;
  1617. }
  1618. if (!npMCI->hAviRd)
  1619. #endif
  1620. {
  1621. if (!npMCI->lpBuffer) {
  1622. return MCIERR_OUT_OF_MEMORY;
  1623. }
  1624. }
  1625. if (npMCI->hWave) {
  1626. TIMESTART(timeAudio);
  1627. if (npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  1628. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY) {
  1629. /* Load audio into our buffers */
  1630. for (w = 0; w < npMCI->wABs; w++)
  1631. KeepPlayingAudio(npMCI);
  1632. } else if (npMCI->wPlaybackAlg == MCIAVI_ALG_CDROM) {
  1633. //!!!!
  1634. npMCI->wPlaybackAlg = MCIAVI_ALG_HARDDISK;
  1635. }
  1636. TIMEEND(timeAudio);
  1637. }
  1638. return 0L; /* Success! */
  1639. }
  1640. /******************************************************************************
  1641. *****************************************************************************/
  1642. void NEAR PASCAL CleanUpPlay(NPMCIGRAPHIC npMCI)
  1643. {
  1644. int stream;
  1645. if (npMCI->wTaskState == TASKPLAYING) {
  1646. if (npMCI->hicDraw) {
  1647. ICDrawStop(npMCI->hicDraw);
  1648. ICDrawStopPlay(npMCI->hicDraw);
  1649. }
  1650. for (stream = 0; stream < npMCI->streams; stream++) {
  1651. if (SI(stream)->hicDraw) {
  1652. ICDrawStop(SI(stream)->hicDraw);
  1653. ICDrawStopPlay(SI(stream)->hicDraw);
  1654. }
  1655. }
  1656. if (npMCI->hWave) {
  1657. waveOutRestart(npMCI->hWave); // some wave devices need this
  1658. waveOutReset(npMCI->hWave);
  1659. }
  1660. } else if (npMCI->wTaskState == TASKCUEING) {
  1661. if (npMCI->hicDraw) {
  1662. /* Kick the device in the head to make sure it draws when we seek. */
  1663. ICDrawRenderBuffer(npMCI->hicDraw);
  1664. }
  1665. }
  1666. if (!(npMCI->dwFlags & MCIAVI_SEEKING) &&
  1667. (npMCI->dwBufferedVideo > 0)) {
  1668. ICDrawFlush(npMCI->hicDraw);
  1669. npMCI->lFrameDrawn = (- (LONG) npMCI->wEarlyRecords) - 1;
  1670. }
  1671. /* end drawing this will leave fullscreen mode etc. */
  1672. DrawEnd(npMCI);
  1673. for (stream = 0; stream < npMCI->streams; stream++) {
  1674. if (SI(stream)->hicDraw) {
  1675. DWORD dw;
  1676. dw = ICDrawEnd(SI(stream)->hicDraw);
  1677. // !!! Error checking?
  1678. }
  1679. if (!(npMCI->dwFlags & MCIAVI_SEEKING)) {
  1680. if (SI(stream)->ps) {
  1681. AVIStreamEndStreaming(SI(stream)->ps);
  1682. }
  1683. }
  1684. }
  1685. /* Clean up and close our wave output device. */
  1686. if (npMCI->hWave) {
  1687. Assert(!(npMCI->dwFlags & MCIAVI_LOSTAUDIO));
  1688. CleanUpAudio(npMCI);
  1689. //
  1690. // if we are not being forced to give up the audio try to
  1691. // give it to someone.
  1692. //
  1693. if (!(npMCI->dwFlags & MCIAVI_NEEDTOSHOW) &&
  1694. !(npMCI->dwFlags & MCIAVI_UPDATING))
  1695. GiveWaveDevice(npMCI);
  1696. }
  1697. else {
  1698. //
  1699. // done playing, we dont want a wave device any more
  1700. //
  1701. npMCI->dwFlags &= ~MCIAVI_LOSTAUDIO;
  1702. }
  1703. /* Release the DC we played into. */
  1704. // worker thread must hold critsec round all access to hdc
  1705. // (can be used by DeviceRealize on app thread)
  1706. EnterCrit(npMCI);
  1707. if (npMCI->hdc) {
  1708. //
  1709. // we MUST call this otherwise our palette will stay selected
  1710. // as the foreground palette and it may get deleted (ie by
  1711. // DrawDibBegin) while still the foreground palette and GDI
  1712. // get's real pissed about this.
  1713. //
  1714. UnprepareDC(npMCI);
  1715. #if 0
  1716. UnprepareDC(npMCI);
  1717. if (npMCI->dwFlags & MCIAVI_ANIMATEPALETTE)
  1718. RealizePalette(npMCI->hdc);
  1719. #endif
  1720. if (npMCI->dwFlags & MCIAVI_RELEASEDC) {
  1721. ReleaseDC(npMCI->hwnd, npMCI->hdc);
  1722. npMCI->hdc = NULL;
  1723. npMCI->dwFlags &= ~MCIAVI_RELEASEDC;
  1724. }
  1725. }
  1726. LeaveCrit(npMCI);
  1727. #ifdef AVIREAD
  1728. /* shut down async reader */
  1729. if (npMCI->hAviRd) {
  1730. avird_endread(npMCI->hAviRd);
  1731. npMCI->hAviRd = NULL;
  1732. } else
  1733. #endif
  1734. {
  1735. /* we weren't using async reader - so release the buffer we
  1736. * allocated
  1737. */
  1738. ReleaseReadBuffer(npMCI);
  1739. }
  1740. }
  1741. /******************************************************************************
  1742. *****************************************************************************/
  1743. // !!! Should this take a "how many frames to check for" parameter,
  1744. // in case we need to check for signals on several frames at once?
  1745. void NEAR PASCAL CheckSignals(NPMCIGRAPHIC npMCI, LONG lFrame)
  1746. {
  1747. LONG lTemp;
  1748. lTemp = npMCI->signal.dwPeriod == 0 ? lFrame :
  1749. (((lFrame - npMCI->signal.dwPosition) %
  1750. npMCI->signal.dwPeriod) +
  1751. npMCI->signal.dwPosition);
  1752. if ((DWORD) lTemp == npMCI->signal.dwPosition) {
  1753. /* Send the signal in the right time format */
  1754. SEND_DGVSIGNAL(npMCI->dwSignalFlags,
  1755. npMCI->signal.dwCallback,
  1756. 0,
  1757. (HANDLE) npMCI->wDevID,
  1758. npMCI->signal.dwUserParm,
  1759. ConvertFromFrames(npMCI, lFrame));
  1760. // !!! Needs to use time format at time of signal command!
  1761. }
  1762. }
  1763. /******************************************************************************
  1764. *****************************************************************************/
  1765. BOOL NEAR PASCAL WaitTillNextFrame(NPMCIGRAPHIC npMCI)
  1766. {
  1767. #ifdef DEBUG
  1768. int iWait = 0;
  1769. StatusBar(npMCI,2,1,100,iWait);
  1770. #endif
  1771. /* Here we wait for a while if we're ahead
  1772. * of schedule (so that we can yield nicely instead of blocking
  1773. * in the driver, for instance, and also so that we'll work off
  1774. * faster devices.)
  1775. */
  1776. /* Always yield at least once in a while */
  1777. if ((npMCI->lCurrentFrame % YIELDEVERY) == 0) {
  1778. TIMESTART(timeYield);
  1779. aviTaskYield();
  1780. TIMEEND(timeYield);
  1781. }
  1782. if (npMCI->dwFlags & MCIAVI_WAVEPAUSED)
  1783. return TRUE;
  1784. if (TimeToQuit(npMCI))
  1785. return FALSE;
  1786. Assert(npMCI->wTaskState == TASKPLAYING);
  1787. AssertFrame(npMCI->lCurrentFrame - (LONG)npMCI->dwBufferedVideo);
  1788. Assert(npMCI->lCurrentFrame <= npMCI->lTo);
  1789. Assert(!(npMCI->dwFlags & MCIAVI_REVERSE));
  1790. while (WhatFrameIsItTimeFor(npMCI) < npMCI->lCurrentFrame) {
  1791. DPF2(("Waiting for %ld, time for %ld\n", npMCI->lCurrentFrame, WhatFrameIsItTimeFor(npMCI)));
  1792. StatusBar(npMCI,2,1,100,++iWait);
  1793. TIMESTART(timeWait);
  1794. aviTaskYield();
  1795. TIMEEND(timeWait);
  1796. if (TimeToQuit(npMCI))
  1797. return FALSE;
  1798. }
  1799. return TRUE;
  1800. }
  1801. /* Idea: this should go from the current frame to the frame
  1802. ** we actually have to be at to start playing from.
  1803. **
  1804. ** If fPlaying is set, that means we're really going to play.
  1805. **
  1806. ** When this finishes:
  1807. ** lAudioStart is set to the first frame with meaningful audio info
  1808. ** lVideoStart is the first frame with meaningful video info
  1809. ** lRealStart is the first frame that's 'real', namely
  1810. ** the original value of lCurrentFrame. If the
  1811. ** SEEK EXACT flag is not set, then lRealStart may
  1812. ** actually not be what lCurrentFrame was, indicating
  1813. ** that play may start from somewhere else.
  1814. ** lCurrentFrame gets set to the first frame we have to read from.
  1815. **
  1816. ** !!! This also needs to look for "palette key frames" or something.
  1817. */
  1818. BOOL NEAR PASCAL CalculateTargetFrame(NPMCIGRAPHIC npMCI)
  1819. {
  1820. int i;
  1821. LONG lVideoPlace;
  1822. BOOL fForceBeginning = FALSE;
  1823. npMCI->lCurrentFrame = npMCI->lFrom;
  1824. npMCI->lRealStart = npMCI->lFrom;
  1825. //
  1826. // walk all streams and figure out where to start
  1827. //
  1828. for (i=0; i<npMCI->streams; i++) {
  1829. STREAMINFO *psi = SI(i);
  1830. if (!(psi->dwFlags & STREAM_ENABLED))
  1831. continue;
  1832. if (psi->dwFlags & STREAM_ERROR)
  1833. continue;
  1834. if (psi->dwFlags & STREAM_AUDIO)
  1835. continue;
  1836. //
  1837. // map from movie time to stream time.
  1838. //
  1839. psi->lPlayFrom = MovieToStream(psi, npMCI->lFrom);
  1840. psi->lPlayTo = MovieToStream(psi, npMCI->lTo);
  1841. psi->dwFlags &= ~STREAM_ACTIVE;
  1842. //
  1843. // is this stream part of play?
  1844. //
  1845. if (psi->lPlayFrom < psi->lStart && psi->lPlayTo < psi->lStart)
  1846. continue;
  1847. if (psi->lPlayFrom >= psi->lEnd && psi->lPlayTo >= psi->lEnd)
  1848. continue;
  1849. psi->dwFlags |= STREAM_ACTIVE;
  1850. psi->lPlayFrom = BOUND(psi->lPlayFrom,psi->lStart,psi->lEnd);
  1851. psi->lPlayTo = BOUND(psi->lPlayTo, psi->lStart,psi->lEnd);
  1852. psi->lPlayStart = FindPrevKeyFrame(npMCI,psi,psi->lPlayFrom);
  1853. //
  1854. // if the main frame is invalid invalidate the stream too.
  1855. //
  1856. if (npMCI->lFrameDrawn <= (-(LONG)npMCI->wEarlyRecords)) {
  1857. psi->lFrameDrawn = -4242;
  1858. }
  1859. //
  1860. // if we have a drawn frame use it!
  1861. //
  1862. if ((psi->lFrameDrawn > psi->lPlayStart) &&
  1863. (psi->lFrameDrawn <= psi->lPlayFrom))
  1864. psi->lPlayStart = npMCI->lFrameDrawn + 1;
  1865. //
  1866. // if seek exactly is off start play at the key frame
  1867. //
  1868. if (!(npMCI->dwOptionFlags & MCIAVIO_SEEKEXACT)) {
  1869. if (psi->lPlayFrom == psi->lPlayTo)
  1870. psi->lPlayTo = psi->lPlayStart;
  1871. psi->lPlayFrom = psi->lPlayStart;
  1872. //!!! is this right for reverse?
  1873. if (StreamToMovie(psi, psi->lPlayFrom) < npMCI->lFrom) {
  1874. // npMCI->lRealStart = StreamToMovie(psi, psi->lPlayFrom);
  1875. // npMCI->lFrom = npMCI->lRealStart;
  1876. }
  1877. }
  1878. // if (StreamToMovie(psi, psi->lPlayStart) < npMCI->lCurrentFrame)
  1879. // npMCI->lCurrentFrame = StreamToMovie(psi, psi->lPlayStart);
  1880. DPF(("CalculateTargetFrame: Stream #%d: from:%ld, to:%ld, start:%ld\n", i, psi->lPlayFrom, psi->lPlayTo, psi->lPlayStart));
  1881. }
  1882. //
  1883. // we are done with now special case the video and audio streams.
  1884. //
  1885. /* If we're starting from the beginning, don't force the index
  1886. ** to be read, but use it if we've already read it.
  1887. */
  1888. if (npMCI->lFrom == 0 && npMCI->hpFrameIndex == NULL)
  1889. goto ForceBeginning;
  1890. if (!npMCI->pbiFormat) {
  1891. npMCI->lVideoStart = npMCI->lFrom;
  1892. if (npMCI->lVideoStart >= npMCI->lFrames)
  1893. npMCI->lVideoStart = npMCI->lFrames - 1;
  1894. lVideoPlace = npMCI->lVideoStart;
  1895. } else
  1896. if (npMCI->dwFlags & MCIAVI_HASINDEX) {
  1897. if (npMCI->hpFrameIndex == NULL)
  1898. goto ForceBeginning;
  1899. //
  1900. // get nearest key frame
  1901. //
  1902. npMCI->lVideoStart = FramePrevKey(npMCI->lFrom);
  1903. if (npMCI->lVideoStart) {
  1904. lVideoPlace = npMCI->lVideoStart;
  1905. } else {
  1906. /* Didn't find a key frame--retreat to the beginning. */
  1907. npMCI->lVideoStart = -(LONG)npMCI->wEarlyVideo;
  1908. lVideoPlace = 0;
  1909. }
  1910. if ((npMCI->lFrameDrawn > npMCI->lVideoStart) &&
  1911. (npMCI->lFrameDrawn <= npMCI->lFrom)) {
  1912. npMCI->lVideoStart = npMCI->lFrameDrawn + 1;
  1913. if (npMCI->lVideoStart >= npMCI->lFrames)
  1914. npMCI->lVideoStart = npMCI->lFrames - 1;
  1915. lVideoPlace = npMCI->lFrameDrawn;
  1916. }
  1917. } else {
  1918. /* Always go back to frame 0 */
  1919. ForceBeginning:
  1920. npMCI->lVideoStart = - (LONG) npMCI->wEarlyVideo;
  1921. lVideoPlace = 0;
  1922. fForceBeginning = TRUE;
  1923. }
  1924. if (!(npMCI->dwOptionFlags & MCIAVIO_SEEKEXACT)) {
  1925. npMCI->lRealStart = lVideoPlace;
  1926. }
  1927. if (npMCI->hWave) {
  1928. npMCI->lAudioStart = npMCI->lRealStart - (LONG) npMCI->wEarlyAudio;
  1929. }
  1930. if (npMCI->hWave && (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED))
  1931. npMCI->lCurrentFrame = min(npMCI->lAudioStart, npMCI->lVideoStart);
  1932. else
  1933. npMCI->lCurrentFrame = npMCI->lVideoStart;
  1934. if (npMCI->lRealStart < npMCI->lCurrentFrame)
  1935. npMCI->lCurrentFrame = npMCI->lRealStart;
  1936. if (fForceBeginning) {
  1937. if (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED)
  1938. npMCI->lCurrentFrame = - (LONG) npMCI->wEarlyRecords;
  1939. else
  1940. npMCI->lCurrentFrame = - (LONG) npMCI->wEarlyVideo;
  1941. }
  1942. if (npMCI->hWave) {
  1943. LONG l;
  1944. /* Figure out what sample of audio we should be starting at */
  1945. //
  1946. // convert frame number to block
  1947. //
  1948. npMCI->dwAudioPos = MovieToStream(npMCI->psiAudio, npMCI->lRealStart);
  1949. //
  1950. // now convert block to byte position
  1951. //
  1952. npMCI->dwAudioPos = npMCI->dwAudioPos * npMCI->pWF->nBlockAlign;
  1953. Assert(npMCI->dwAudioPos % npMCI->pWF->nBlockAlign == 0);
  1954. if (npMCI->dwAudioPos > npMCI->dwAudioLength)
  1955. npMCI->dwAudioPos = npMCI->dwAudioLength;
  1956. npMCI->dwAudioPlayed = 0L;
  1957. //
  1958. // convert the audio start back to a frame number.
  1959. // and posibly readjust the video start time.
  1960. //
  1961. l = npMCI->lRealStart - StreamToMovie(npMCI->psiAudio,
  1962. npMCI->dwAudioPos/npMCI->pWF->nBlockAlign);
  1963. if (l < 0)
  1964. DPF(("Audio will be ahead of the video by %ld frames\n", -l));
  1965. else if (l > 0)
  1966. DPF(("Audio will be behind the video by %ld frames\n", l));
  1967. }
  1968. #ifdef DEBUG
  1969. Assert(npMCI->lCurrentFrame < npMCI->lFrames);
  1970. if (npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED) {
  1971. Assert(npMCI->lCurrentFrame >= - (LONG) npMCI->wEarlyRecords);
  1972. }
  1973. if (npMCI->hWave) {
  1974. Assert(npMCI->lAudioStart <= npMCI->lFrames);
  1975. }
  1976. Assert(npMCI->lVideoStart < npMCI->lFrames);
  1977. #endif
  1978. return TRUE;
  1979. }
  1980. /******************************************************************************
  1981. *****************************************************************************/
  1982. void ReturnToOriginalPalette(NPMCIGRAPHIC npMCI)
  1983. {
  1984. if (npMCI->bih.biClrUsed) {
  1985. hmemcpy(npMCI->argb, npMCI->argbOriginal,
  1986. npMCI->bih.biClrUsed * sizeof(RGBQUAD));
  1987. if (npMCI->pbiFormat->biBitCount == 8) {
  1988. hmemcpy((LPBYTE) npMCI->pbiFormat + npMCI->pbiFormat->biSize,
  1989. (LPBYTE) npMCI->argb,
  1990. sizeof(RGBQUAD) * npMCI->pbiFormat->biClrUsed);
  1991. }
  1992. npMCI->dwFlags |= MCIAVI_PALCHANGED;
  1993. npMCI->lLastPaletteChange = 0;
  1994. }
  1995. }
  1996. /* Returns the position in the file where the frame referenced
  1997. ** by lCurrentFrame is.
  1998. **
  1999. ** input npMCI->lCurrentFrame
  2000. **
  2001. ** output npMCI->dwNextRecordSize set correctly
  2002. ** npMCI->lLastRead set correctly
  2003. ** returns offset to read from
  2004. **
  2005. ** If there's an error, returns zero.
  2006. */
  2007. DWORD NEAR PASCAL CalculatePosition(NPMCIGRAPHIC npMCI)
  2008. {
  2009. DWORD dwPosition;
  2010. AssertFrame(npMCI->lCurrentFrame);
  2011. if (npMCI->pf || npMCI->nVideoStreams == 0)
  2012. return 1;
  2013. if (npMCI->lCurrentFrame + npMCI->wEarlyRecords == 0) {
  2014. ForceBeginning:
  2015. npMCI->lCurrentFrame = - (LONG)npMCI->wEarlyRecords;
  2016. //!!!BeforeBeginning:
  2017. dwPosition = npMCI->dwFirstRecordPosition;
  2018. npMCI->dwNextRecordSize = npMCI->dwFirstRecordSize;
  2019. npMCI->dwNextRecordType = npMCI->dwFirstRecordType;
  2020. } else if (npMCI->dwFlags & MCIAVI_HASINDEX) {
  2021. if (npMCI->hpFrameIndex == NULL)
  2022. goto ForceBeginning;
  2023. dwPosition = FrameOffset(npMCI->lCurrentFrame);
  2024. npMCI->dwNextRecordSize = FrameLength(npMCI->lCurrentFrame) + 8;
  2025. npMCI->dwNextRecordType = 0;
  2026. } else {
  2027. goto ForceBeginning;
  2028. }
  2029. npMCI->lLastRead = npMCI->lCurrentFrame - 1;
  2030. DPF3(("Frame %ld: Seeking to position %lX\n", npMCI->lCurrentFrame, dwPosition));
  2031. DPF3(("CalculatePosition: next record = %lu bytes.\n", npMCI->dwNextRecordSize));
  2032. mmioSeek(npMCI->hmmio, dwPosition, SEEK_SET);
  2033. return dwPosition;
  2034. }
  2035. /***************************************************************************
  2036. *
  2037. ***************************************************************************/
  2038. BOOL NEAR PASCAL ReadIndexChunk(NPMCIGRAPHIC npMCI, LONG iIndex)
  2039. {
  2040. Assert(iIndex >= 0 && iIndex < (LONG)npMCI->macIndex);
  2041. return ReadBuffer(npMCI, (LONG)IndexOffset(iIndex), (LONG)IndexLength(iIndex) + 8);
  2042. }
  2043. /***************************************************************************
  2044. *
  2045. * @doc INTERNAL MCIAVI
  2046. *
  2047. * @api void | DealWithOtherStreams | does what is says
  2048. *
  2049. * this function is called inside of the non-interlaved play loop.
  2050. * it's mission is to catch the "other" streams up to the current time.
  2051. *
  2052. * right now all we do is go to key frames, we should fix this
  2053. *
  2054. * @parm NPMCIGRAPHIC | npMCI | pointer to instance data block.
  2055. *
  2056. ***************************************************************************/
  2057. void DealWithOtherStreams(NPMCIGRAPHIC npMCI, LONG lFrame)
  2058. {
  2059. int i;
  2060. STREAMINFO *psi;
  2061. LONG lPos;
  2062. LONG err;
  2063. for (i=0; i<npMCI->streams; i++) {
  2064. psi = SI(i);
  2065. if (!(psi->dwFlags & STREAM_ENABLED))
  2066. continue;
  2067. if (i == npMCI->nVideoStream)
  2068. continue;
  2069. if (i == npMCI->nAudioStream)
  2070. continue;
  2071. if (psi->hicDraw == NULL)
  2072. continue;
  2073. lPos = MovieToStream(psi, lFrame);
  2074. if (lPos < psi->lPlayStart || lPos > psi->lPlayTo) {
  2075. DPF2(("OtherStream(%d): out of range lPos = %ld [%ld, %ld]\n", i, lPos, psi->lPlayStart, psi->lPlayTo));
  2076. continue;
  2077. }
  2078. //
  2079. // we have the right thing drawn now
  2080. //
  2081. // !!!we should not always go to a key frame.
  2082. //
  2083. //
  2084. if (psi->lFrameDrawn >= psi->lLastKey &&
  2085. psi->lFrameDrawn <= lPos &&
  2086. lPos < psi->lNextKey) {
  2087. DPF2(("OtherStream(%d) lPos = %ld, lFrameDrawn=%ld, NextKey=%ld\n", i, lPos, psi->lFrameDrawn, psi->lNextKey));
  2088. continue;
  2089. }
  2090. FindKeyFrame(npMCI, psi, lPos);
  2091. DPF2(("OtherStream(%d): pos=%ld (prev key=%ld, next key=%ld)\n",i,lPos,psi->lLastKey,psi->lNextKey));
  2092. lPos = psi->lLastKey;
  2093. if (!StreamRead(npMCI, psi, lPos)) {
  2094. DPF2(("StreamRead failed\n"));
  2095. continue;
  2096. }
  2097. //
  2098. // now draw the data.
  2099. //
  2100. err = (LONG)ICDraw(psi->hicDraw, 0L, psi->lpFormat,
  2101. npMCI->lpBuffer,npMCI->dwThisRecordSize,
  2102. psi->lLastKey - psi->lPlayFrom);
  2103. if (err >= 0) {
  2104. psi->dwFlags &= ~STREAM_NEEDUPDATE;
  2105. psi->lFrameDrawn = lPos;
  2106. }
  2107. else {
  2108. DPF2(("Draw failed!\n"));
  2109. }
  2110. }
  2111. }
  2112. /***************************************************************************
  2113. *
  2114. * FindKeyFrame
  2115. *
  2116. * given a stream position, find the previous and next key frame
  2117. * cacheing the last ones found to make it sort of fast.
  2118. *
  2119. ***************************************************************************/
  2120. void NEAR PASCAL FindKeyFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos)
  2121. {
  2122. if (psi == NULL)
  2123. psi = npMCI->psiVideo;
  2124. Assert(psi);
  2125. // AssertPos(psi, lPos);
  2126. //
  2127. // if we are in the current key range return it.
  2128. //
  2129. if (psi->lLastKey <= lPos && lPos < psi->lNextKey)
  2130. return;
  2131. if (lPos < psi->lStart || lPos >= psi->lEnd)
  2132. return;
  2133. //
  2134. // otherwise query from the stream
  2135. //
  2136. if (psi->ps) {
  2137. if (lPos == psi->lNextKey)
  2138. psi->lLastKey = psi->lNextKey;
  2139. else
  2140. psi->lLastKey = AVIStreamFindSample(psi->ps, lPos, FIND_KEY|FIND_PREV);
  2141. psi->lNextKey = AVIStreamFindSample(psi->ps, lPos+1, FIND_KEY|FIND_NEXT);
  2142. if (psi->lLastKey == -1)
  2143. ; // psi->lLastKey = psi->lStart;
  2144. if (psi->lNextKey == -1)
  2145. psi->lNextKey = psi->lEnd+1;
  2146. }
  2147. else if (psi->dwFlags & STREAM_VIDEO) {
  2148. //
  2149. // for a video stream either read our index or assume no key frames.
  2150. //
  2151. if (npMCI->hpFrameIndex && psi == npMCI->psiVideo) {
  2152. psi->lLastKey = FramePrevKey(lPos);
  2153. psi->lNextKey = FrameNextKey(lPos);
  2154. }
  2155. else {
  2156. psi->lLastKey = psi->lStart;
  2157. psi->lNextKey = psi->lEnd+1;
  2158. }
  2159. }
  2160. else {
  2161. //
  2162. // for a non-video stream assume all key frames
  2163. //
  2164. psi->lLastKey = lPos;
  2165. psi->lNextKey = lPos+1;
  2166. }
  2167. return;
  2168. }
  2169. /***************************************************************************
  2170. ***************************************************************************/
  2171. LONG NEAR PASCAL FindPrevKeyFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos)
  2172. {
  2173. FindKeyFrame(npMCI, psi, lPos);
  2174. return psi->lLastKey;
  2175. }
  2176. /***************************************************************************
  2177. ***************************************************************************/
  2178. LONG NEAR PASCAL FindNextKeyFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos)
  2179. {
  2180. FindKeyFrame(npMCI, psi, lPos);
  2181. return psi->lNextKey;
  2182. }
  2183. /***************************************************************************
  2184. ***************************************************************************/
  2185. BOOL NEAR PASCAL ProcessPaletteChanges(NPMCIGRAPHIC npMCI, LONG lFrame)
  2186. {
  2187. LONG iPalette;
  2188. LONG iFrame;
  2189. STREAMINFO *psi;
  2190. DWORD dw;
  2191. if (!(npMCI->dwFlags & MCIAVI_ANIMATEPALETTE))
  2192. return TRUE;
  2193. psi = npMCI->psiVideo;
  2194. Assert(psi);
  2195. #ifdef USEAVIFILE
  2196. if (psi->ps) {
  2197. //
  2198. // we are in the palette range nohting to do.
  2199. //
  2200. if (npMCI->lLastPaletteChange <= lFrame &&
  2201. npMCI->lNextPaletteChange > lFrame) {
  2202. return TRUE;
  2203. }
  2204. dw = psi->cbFormat;
  2205. //!!! should be psi->lpFormat
  2206. if (AVIStreamReadFormat(psi->ps, lFrame, npMCI->pbiFormat, &dw) != 0) {
  2207. DOUT("Unable to read Stream format\n");
  2208. return FALSE;
  2209. }
  2210. npMCI->lLastPaletteChange = lFrame;
  2211. npMCI->lNextPaletteChange = AVIStreamFindSample(psi->ps, lFrame+1, FIND_NEXT|FIND_FORMAT);
  2212. if (npMCI->lNextPaletteChange == -1)
  2213. npMCI->lNextPaletteChange = npMCI->lFrames+2;
  2214. npMCI->dwFlags |= MCIAVI_PALCHANGED;
  2215. return TRUE;
  2216. }
  2217. #endif
  2218. DPF2(("Looking for palette changes at %ld, last=%ld\n", lFrame, npMCI->lLastPaletteChange));
  2219. if (lFrame < npMCI->lLastPaletteChange) {
  2220. ReturnToOriginalPalette(npMCI);
  2221. }
  2222. /* If there's no index, assume we're starting from the beginning
  2223. ** and thus we don't have to worry about palette changes.
  2224. */
  2225. if (npMCI->hpFrameIndex == NULL)
  2226. return TRUE;
  2227. //
  2228. // walk from the last palette change to the current frame, and apply any
  2229. // palette changes we find.
  2230. //
  2231. for (iFrame = npMCI->lLastPaletteChange,
  2232. iPalette = FramePalette(iFrame);
  2233. iFrame <= lFrame;
  2234. iFrame++) {
  2235. if (iPalette != FramePalette(iFrame)) {
  2236. iPalette = FramePalette(iFrame);
  2237. /* We've found a palette change we need to deal with */
  2238. DPF2(("Processing palette change at frame %ld.\n", iFrame));
  2239. Assert(iPalette >= 0 && iPalette < (LONG)npMCI->macIndex);
  2240. if (!ReadIndexChunk(npMCI, iPalette))
  2241. return FALSE;
  2242. npMCI->lp += 2 * sizeof(DWORD);
  2243. ProcessPaletteChange(npMCI, IndexLength(iPalette));
  2244. npMCI->lLastPaletteChange = iFrame;
  2245. }
  2246. }
  2247. return TRUE;
  2248. }
  2249. BOOL NEAR PASCAL ReadRecord(NPMCIGRAPHIC npMCI)
  2250. {
  2251. LPDWORD pdw;
  2252. AssertFrame(npMCI->lCurrentFrame);
  2253. #ifdef AVIREADMANY
  2254. if (npMCI->fReadMany) {
  2255. //
  2256. // either read two records or return the one we read last time.
  2257. //
  2258. Assert(npMCI->hpFrameIndex);
  2259. Assert(npMCI->lCurrentFrame - npMCI->lLastRead > 0);
  2260. Assert(npMCI->lCurrentFrame - npMCI->lLastRead <= 2);
  2261. if (npMCI->lLastRead == npMCI->lCurrentFrame-1) {
  2262. //
  2263. // return the second half of the buffer.
  2264. //
  2265. npMCI->lp = npMCI->lpBuffer + (UINT)npMCI->dwThisRecordSize;
  2266. npMCI->dwThisRecordSize = npMCI->dwNextRecordSize;
  2267. }
  2268. else {
  2269. //
  2270. // read in two buffers, and return the first one
  2271. //
  2272. // figure out how much to read by looking at the index
  2273. // we dont have to worry about the last frame because
  2274. // the dummy index entry on the end is 0 in length.
  2275. //
  2276. npMCI->dwThisRecordSize = FrameLength(npMCI->lCurrentFrame) + 8;
  2277. npMCI->dwNextRecordSize = FrameLength(npMCI->lCurrentFrame+1) + 8;
  2278. if (!ReadBuffer(npMCI, -1,
  2279. npMCI->dwThisRecordSize + npMCI->dwNextRecordSize))
  2280. return FALSE;
  2281. npMCI->lLastRead = npMCI->lCurrentFrame;
  2282. npMCI->lp = npMCI->lpBuffer;
  2283. npMCI->dwThisRecordSize -= npMCI->dwNextRecordSize;
  2284. }
  2285. #ifdef DEBUG
  2286. pdw = (LPDWORD)(npMCI->lp + npMCI->dwThisRecordSize - 3 * sizeof(DWORD));
  2287. if (npMCI->lCurrentFrame < npMCI->lFrames - 1) {
  2288. Assert(pdw[0] == FOURCC_LIST);
  2289. Assert(pdw[2] == listtypeAVIRECORD);
  2290. }
  2291. #endif
  2292. return TRUE;
  2293. }
  2294. else
  2295. #endif
  2296. #ifdef AVIREAD
  2297. if (npMCI->hAviRd) {
  2298. /* async reader is going - get the next buffer from him */
  2299. npMCI->lpBuffer = avird_getnextbuffer(npMCI->hAviRd, &dwThisBuffer);
  2300. npMCI->dwThisRecordSize = npMCI->dwNextRecordSize;
  2301. if ((dwThisBuffer == 0) || (npMCI->lpBuffer == NULL)) {
  2302. npMCI->dwTaskError = MCIERR_FILE_READ;
  2303. return FALSE;
  2304. }
  2305. } else
  2306. #endif
  2307. {
  2308. if (!ReadBuffer(npMCI, -1, (LONG)npMCI->dwNextRecordSize))
  2309. return FALSE;
  2310. }
  2311. pdw = (LPDWORD)(npMCI->lp + npMCI->dwThisRecordSize - 3 * sizeof(DWORD));
  2312. npMCI->dwNextRecordType = pdw[0];
  2313. npMCI->dwNextRecordSize = pdw[1] + 2 * sizeof(DWORD);
  2314. #ifdef DEBUG
  2315. if (npMCI->lCurrentFrame < npMCI->lFrames - 1) {
  2316. Assert(pdw[0] == FOURCC_LIST);
  2317. Assert(pdw[2] == listtypeAVIRECORD);
  2318. }
  2319. #endif
  2320. return TRUE;
  2321. }
  2322. DWORD NEAR PASCAL ReadNextChunk(NPMCIGRAPHIC npMCI)
  2323. {
  2324. LPDWORD pdw;
  2325. DWORD dw;
  2326. ReadAgain:
  2327. dw = npMCI->dwNextRecordType;
  2328. if (!ReadBuffer(npMCI, -1, (LONG)npMCI->dwNextRecordSize))
  2329. return 0;
  2330. pdw = (LPDWORD)(npMCI->lp + npMCI->dwNextRecordSize - 2 * sizeof(DWORD));
  2331. if (dw == FOURCC_LIST)
  2332. pdw--;
  2333. npMCI->dwNextRecordType = pdw[0];
  2334. npMCI->dwNextRecordSize = pdw[1] + 2 * sizeof(DWORD);
  2335. if (dw == ckidAVIPADDING)
  2336. goto ReadAgain;
  2337. return dw;
  2338. }
  2339. BOOL NEAR PASCAL StreamRead(NPMCIGRAPHIC npMCI, STREAMINFO *psi, LONG lPos)
  2340. {
  2341. LONG lSize;
  2342. Assert(psi);
  2343. Assert(psi->ps);
  2344. //
  2345. // if we are before the start or after the end, read nothing.
  2346. //
  2347. if (lPos < psi->lStart || lPos >= psi->lEnd) {
  2348. lSize = 0;
  2349. goto done;
  2350. }
  2351. if (AVIStreamRead(psi->ps, lPos, 1,
  2352. (LPSTR)npMCI->lpBuffer,npMCI->dwBufferSize,&lSize, NULL) != 0) {
  2353. //
  2354. // the read failed try incressing the buffer size
  2355. //
  2356. AVIStreamRead(psi->ps, lPos, 1, NULL, 0, &lSize, NULL);
  2357. if (lSize > (LONG) (npMCI->dwBufferSize)) {
  2358. DPF2(("ReadStream: Enlarging buffer....\n"));
  2359. if (!ResizeReadBuffer(npMCI, lSize)) {
  2360. DPF(("Failed to increase buffer size!\n"));
  2361. npMCI->dwTaskError = MCIERR_OUT_OF_MEMORY;
  2362. return FALSE;
  2363. }
  2364. }
  2365. if (AVIStreamRead(psi->ps, lPos, 1,
  2366. (LPSTR)npMCI->lpBuffer,npMCI->dwBufferSize,&lSize,NULL) != 0) {
  2367. npMCI->dwTaskError = MCIERR_FILE_READ;
  2368. return FALSE;
  2369. }
  2370. }
  2371. done:
  2372. npMCI->lp = npMCI->lpBuffer;
  2373. npMCI->dwThisRecordSize = lSize;
  2374. return TRUE;
  2375. }
  2376. BOOL NEAR PASCAL ReadNextVideoFrame(NPMCIGRAPHIC npMCI, STREAMINFO *psi)
  2377. {
  2378. MMCKINFO ck;
  2379. if (psi == NULL)
  2380. psi = npMCI->psiVideo;
  2381. Assert(psi);
  2382. AssertFrame(npMCI->lCurrentFrame);
  2383. #ifdef USEAVIFILE
  2384. if (psi->ps) {
  2385. LONG lSize;
  2386. LONG lPos;
  2387. //
  2388. // map from movie time into this stream.
  2389. //
  2390. lPos = MovieToStream(psi, npMCI->lCurrentFrame);
  2391. //
  2392. // if we are before the start or after the end, read nothing.
  2393. //
  2394. if (lPos < (LONG)psi->sh.dwStart ||
  2395. lPos >= (LONG)psi->sh.dwStart+(LONG)psi->sh.dwLength) {
  2396. lSize = 0;
  2397. goto done;
  2398. }
  2399. //
  2400. // if this frame has a new palette then deal wiht it
  2401. //
  2402. if (npMCI->dwFlags & MCIAVI_ANIMATEPALETTE) {
  2403. ProcessPaletteChanges(npMCI, lPos);
  2404. }
  2405. if (AVIStreamRead(psi->ps, lPos, 1,
  2406. (LPSTR) npMCI->lpBuffer + 2 * sizeof(DWORD),
  2407. npMCI->dwBufferSize - 2 * sizeof(DWORD),
  2408. &lSize, NULL) != 0) {
  2409. //
  2410. // the read failed try incressing the buffer size
  2411. //
  2412. AVIStreamRead(psi->ps, lPos, 1, NULL, 0, &lSize, NULL);
  2413. if (lSize > (LONG) (npMCI->dwBufferSize - 2 * sizeof(DWORD))) {
  2414. DPF2(("ReadNextVideoFrame: Enlarging buffer....\n"));
  2415. if (!ResizeReadBuffer(npMCI, lSize + 2 * sizeof(DWORD))) {
  2416. DPF(("Failed to increase buffer size!\n"));
  2417. npMCI->dwTaskError = MCIERR_OUT_OF_MEMORY;
  2418. return FALSE;
  2419. }
  2420. }
  2421. if (AVIStreamRead(psi->ps, lPos, 1,
  2422. (LPSTR) npMCI->lpBuffer + 2 * sizeof(DWORD),
  2423. npMCI->dwBufferSize - 2 * sizeof(DWORD),
  2424. &lSize, NULL) != 0) {
  2425. return FALSE;
  2426. }
  2427. }
  2428. done:
  2429. ((DWORD FAR *)npMCI->lpBuffer)[0] = MAKEAVICKID(cktypeDIBbits,
  2430. npMCI->nVideoStream);
  2431. ((DWORD FAR *)npMCI->lpBuffer)[1] = lSize;
  2432. npMCI->lp = npMCI->lpBuffer;
  2433. npMCI->dwThisRecordSize = lSize + 2 * sizeof(DWORD);
  2434. return TRUE;
  2435. }
  2436. #endif
  2437. //
  2438. // if we are not reading the "next" frame then figure out where it is.
  2439. //
  2440. if (npMCI->lLastRead != npMCI->lCurrentFrame-1)
  2441. CalculatePosition(npMCI);
  2442. //
  2443. // dwNextRecordSize is the size to read
  2444. // and we are seeked to the right place.
  2445. //
  2446. if (npMCI->hpFrameIndex) {
  2447. //
  2448. // if this frame has a new palette then deal wiht it
  2449. //
  2450. if (npMCI->dwFlags & MCIAVI_ANIMATEPALETTE) {
  2451. if (FramePalette(npMCI->lCurrentFrame) !=
  2452. FramePalette(npMCI->lLastPaletteChange))
  2453. ProcessPaletteChanges(npMCI, npMCI->lCurrentFrame);
  2454. }
  2455. //
  2456. // now just go read the frame from the disk.
  2457. //
  2458. // if interleaved add 8 to skip the 'REC'!!!!
  2459. //
  2460. return ReadBuffer(npMCI,
  2461. (LONG)FrameOffset(npMCI->lCurrentFrame),
  2462. (LONG)FrameLength(npMCI->lCurrentFrame) + 8);
  2463. } else {
  2464. ReadAgainNoIndex:
  2465. for (;;) {
  2466. if (mmioDescend(npMCI->hmmio, &ck, NULL, 0) != 0) {
  2467. DPF(("Unable to descend!\n"));
  2468. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  2469. return FALSE;
  2470. }
  2471. /* If it's a list, stay descended in it. */
  2472. /* Hack: we never ascend. */
  2473. if (ck.ckid == FOURCC_LIST)
  2474. continue;
  2475. #ifdef ALPHAFILES
  2476. /* Skip wave bytes, since they've been preloaded. */
  2477. if (npMCI->dwFlags & MCIAVI_USINGALPHAFORMAT) {
  2478. if ((ck.ckid != ckidAVIPADDING) &&
  2479. (ck.ckid != ckidOLDPADDING) &&
  2480. (ck.ckid != ckidWAVEbytes))
  2481. break;
  2482. } else
  2483. #endif
  2484. {
  2485. if (StreamFromFOURCC(ck.ckid) == (WORD)npMCI->nVideoStream)
  2486. break;
  2487. }
  2488. mmioAscend(npMCI->hmmio, &ck, 0);
  2489. }
  2490. if (ck.cksize + 2 * sizeof(DWORD) > npMCI->dwBufferSize) {
  2491. if (!ResizeReadBuffer(npMCI, ck.cksize + 2 * sizeof(DWORD))) {
  2492. DPF(("ReadNextVideoFrame: Failed to increase buffer size!\n"));
  2493. npMCI->dwTaskError = MCIERR_OUT_OF_MEMORY;
  2494. return FALSE;
  2495. }
  2496. }
  2497. *((LPMMCKINFO) npMCI->lpBuffer) = ck;
  2498. if (mmioRead(npMCI->hmmio, npMCI->lpBuffer + 2 * sizeof(DWORD),
  2499. ck.cksize) != (LONG) ck.cksize) {
  2500. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  2501. return FALSE;
  2502. }
  2503. mmioAscend(npMCI->hmmio, &ck, 0);
  2504. npMCI->lp = npMCI->lpBuffer;
  2505. npMCI->dwThisRecordSize = ck.cksize + 2 * sizeof(DWORD);
  2506. if (TWOCCFromFOURCC(ck.ckid) == cktypePALchange) {
  2507. npMCI->lp += 2 * sizeof(DWORD);
  2508. ProcessPaletteChange(npMCI, ck.cksize);
  2509. npMCI->lLastPaletteChange = npMCI->lCurrentFrame;
  2510. goto ReadAgainNoIndex;
  2511. }
  2512. }
  2513. return TRUE;
  2514. }
  2515. BOOL NEAR PASCAL TimeToQuit(NPMCIGRAPHIC npMCI)
  2516. {
  2517. /* If we're using DisplayDib, give the user a chance to break. */
  2518. if ((npMCI->dwFlags & MCIAVI_FULLSCREEN) &&
  2519. !(npMCI->dwFlags & MCIAVI_NOBREAK) &&
  2520. (npMCI->wTaskState == TASKPLAYING)) {
  2521. UINT u;
  2522. u = GetAsyncKeyState(VK_ESCAPE) |
  2523. GetAsyncKeyState(VK_SPACE) |
  2524. GetAsyncKeyState(VK_LBUTTON);
  2525. if (u & 1) {
  2526. /* Break out of play loop */
  2527. npMCI->dwFlags |= MCIAVI_STOP;
  2528. }
  2529. }
  2530. if (npMCI->dwFlags & MCIAVI_STOP)
  2531. return TRUE;
  2532. return FALSE;
  2533. }
  2534. /***************************************************************************
  2535. *
  2536. * @doc INTERNAL MCIAVI
  2537. *
  2538. * @api BOOL | AllocateReadBuffer | Allocates buffers needed to read
  2539. * disk information in to. The amount of memory to allocate
  2540. * is in npMCI->dwBufferSize.
  2541. *
  2542. * @parm NPMCIGRAPHIC | npMCI | pointer to instance data block.
  2543. *
  2544. * @rdesc TRUE means OK, otherwise unable to allocate memory.
  2545. *
  2546. ***************************************************************************/
  2547. BOOL NEAR PASCAL AllocateReadBuffer(NPMCIGRAPHIC npMCI)
  2548. {
  2549. if (npMCI->dwBufferSize == 0)
  2550. npMCI->dwBufferSize = npMCI->dwSuggestedBufferSize;
  2551. if (npMCI->dwBufferSize <= 8 * sizeof(DWORD))
  2552. {
  2553. if (npMCI->dwBytesPerSec > 0 &&
  2554. npMCI->dwBytesPerSec < 600l*1024 &&
  2555. npMCI->dwMicroSecPerFrame > 0)
  2556. npMCI->dwBufferSize = (muldiv32(npMCI->dwBytesPerSec,
  2557. npMCI->dwMicroSecPerFrame,1000000L) + 2047) & ~2047;
  2558. else
  2559. npMCI->dwBufferSize = 10*1024;
  2560. npMCI->dwSuggestedBufferSize == npMCI->dwBufferSize;
  2561. }
  2562. DPF3(("MCIAVI: allocating %lu byte read buffer.\n", npMCI->dwBufferSize));
  2563. if (npMCI->lpBuffer) {
  2564. DPF(("Already have buffer in AllocateReadBuffer!\n"));
  2565. return ResizeReadBuffer(npMCI, npMCI->dwBufferSize);
  2566. }
  2567. //!!! we dont need DOS memory when we have a MMIO buffer!
  2568. //!!! we dont need DOS memory when we are using AVIFile???
  2569. if (npMCI->lpMMIOBuffer != NULL || npMCI->pf)
  2570. npMCI->lpBuffer = GlobalAllocPtr(GHND | GMEM_SHARE, npMCI->dwBufferSize);
  2571. else
  2572. npMCI->lpBuffer = AllocMem(npMCI->dwBufferSize);
  2573. return npMCI->lpBuffer != NULL;
  2574. }
  2575. /***************************************************************************
  2576. *
  2577. * @doc INTERNAL MCIAVI
  2578. *
  2579. * @api BOOL | ResizeReadBuffer | Enlarges buffer needed to read
  2580. * disk information in to.
  2581. *
  2582. * @parm NPMCIGRAPHIC | npMCI | pointer to instance data block.
  2583. *
  2584. * @parm DWORD | dwNewSize | new amount of memory to allocate
  2585. *
  2586. * @rdesc TRUE means OK, otherwise unable to allocate memory.
  2587. *
  2588. ***************************************************************************/
  2589. BOOL NEAR PASCAL ResizeReadBuffer(NPMCIGRAPHIC npMCI, DWORD dwNewSize)
  2590. {
  2591. if (dwNewSize > npMCI->dwSuggestedBufferSize && !npMCI->fReadMany)
  2592. npMCI->dwSuggestedBufferSize = dwNewSize;
  2593. if (dwNewSize <= npMCI->dwBufferSize)
  2594. return TRUE;
  2595. DPF(("Increasing buffer size to %ld (was %ld).\n", dwNewSize, npMCI->dwBufferSize));
  2596. ReleaseReadBuffer(npMCI);
  2597. npMCI->dwBufferSize = dwNewSize;
  2598. return AllocateReadBuffer(npMCI);
  2599. }
  2600. /***************************************************************************
  2601. *
  2602. * @doc INTERNAL MCIAVI
  2603. *
  2604. * @api void | ReleaseReadBuffer | Releases read buffer.
  2605. *
  2606. * @parm NPMCIGRAPHIC | npMCI | pointer to instance data block.
  2607. *
  2608. ***************************************************************************/
  2609. void NEAR PASCAL ReleaseReadBuffer(NPMCIGRAPHIC npMCI)
  2610. {
  2611. if (npMCI->lpBuffer) {
  2612. DPF3(("Releasing read buffer.\n"));
  2613. GlobalFreePtr(npMCI->lpBuffer);
  2614. npMCI->lpBuffer = NULL;
  2615. npMCI->dwBufferSize = 0L;
  2616. npMCI->fReadMany = FALSE;
  2617. }
  2618. }
  2619. /***************************************************************************
  2620. *
  2621. * @doc INTERNAL MCIAVI
  2622. *
  2623. * @api BOOL | ReadBuffer
  2624. *
  2625. ***************************************************************************/
  2626. BOOL NEAR PASCAL ReadBuffer(NPMCIGRAPHIC npMCI, LONG off, LONG len)
  2627. {
  2628. npMCI->lp = npMCI->lpBuffer;
  2629. npMCI->dwThisRecordSize = len;
  2630. if (len == 0) {
  2631. ((DWORD FAR *)npMCI->lpBuffer)[0] = 0; //!!!lpIndexEntry->ckid;
  2632. ((DWORD FAR *)npMCI->lpBuffer)[1] = 0;
  2633. npMCI->dwThisRecordSize = 8;
  2634. return TRUE;
  2635. }
  2636. if (len > (LONG)npMCI->dwBufferSize) {
  2637. if (!ResizeReadBuffer(npMCI, len)) {
  2638. DPF(("Failed to increase buffer size!\n"));
  2639. npMCI->dwTaskError = MCIERR_OUT_OF_MEMORY;
  2640. return FALSE;
  2641. }
  2642. npMCI->lp = npMCI->lpBuffer;
  2643. }
  2644. if (off >= 0)
  2645. DPF2(("ReadBuffer %ld bytes at %ld\n", len, off));
  2646. else
  2647. DPF2(("ReadBuffer %ld bytes\n", len));
  2648. if (off >= 0)
  2649. mmioSeek(npMCI->hmmio, off, SEEK_SET);
  2650. if (mmioRead(npMCI->hmmio, npMCI->lp, len) != len) {
  2651. npMCI->dwTaskError = MCIERR_FILE_READ;
  2652. return FALSE;
  2653. }
  2654. return TRUE;
  2655. }
  2656. /***************************************************************************
  2657. *
  2658. * @doc INTERNAL MCIAVI
  2659. *
  2660. * @api LPVOID | AllocMem | try to allocate DOS memory (< 1Mb)
  2661. *
  2662. * @parm DWORD | dw | size in bytes
  2663. *
  2664. ***************************************************************************/
  2665. static LPVOID AllocMem(DWORD dw)
  2666. {
  2667. #ifndef WIN32
  2668. /* Memory allocation internal routines */
  2669. extern DWORD FAR PASCAL GlobalDosAlloc(DWORD);
  2670. LPVOID p;
  2671. if (p = (LPVOID)MAKELONG(0, LOWORD(GlobalDosAlloc(dw))))
  2672. {
  2673. DPF(("Got %ld bytes DOS memory\n", dw));
  2674. GlobalReAlloc((HANDLE)HIWORD((DWORD)p), 0, GMEM_MODIFY|GMEM_SHARE);
  2675. return p;
  2676. }
  2677. else
  2678. #endif
  2679. {
  2680. DPF(("unable to get %ld bytes of DOS memory\n", dw));
  2681. return GlobalLock(GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, dw));
  2682. }
  2683. }