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

1965 lines
52 KiB

  1. #include <windows.h>
  2. #include <windowsx.h>
  3. #include <win32.h>
  4. #include <mmsystem.h>
  5. #include <vfw.h>
  6. #include "aviview.h"
  7. #include "audplay.h"
  8. #include "aviplay.h"
  9. #ifdef DEBUG
  10. extern void FAR CDECL dprintf(LPSTR, ...);
  11. #define DPF dprintf
  12. #define DPF2 / ## /
  13. #define DPF3 / ## /
  14. #else
  15. #define DPF / ## /
  16. #define DPF2 / ## /
  17. #define DPF3 / ## /
  18. #endif
  19. #define ProfBegin() ProfClear(); ProfSampRate(5,1); ProfStart();
  20. #define ProfEnd() ProfStop(); ProfFlush();
  21. #define FillR(hdc, x, y, dx, dy, rgb) \
  22. SetBkColor(hdc, rgb); \
  23. SetRect(&rc, x, y, x+dx, y+dy); \
  24. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  25. // Why is this necessary?
  26. #define HPBYTE BYTE huge *
  27. // !!! All of this is out of thin air
  28. #define MAXNUMSTREAMS 10
  29. #define AUD_BUFFERS_MAX_SIZE 4096L // never read > this many bytes
  30. #define NUM_WAVE_HEADERS 32
  31. #define YIELD_WAIT_TIME 150
  32. #define READ_WAIT_TIME 150
  33. #define DECOMPRESS_WAIT_TIME 150
  34. #define DRAW_WAIT_TIME 150
  35. #ifndef WIN32
  36. extern LONG FAR PASCAL muldiv32(LONG, LONG, LONG);
  37. #endif
  38. extern BOOL gfCheat, gfDecompress; // do we cheat? does our queue hold
  39. // compressed/decompressed data?
  40. extern BOOL gfYieldBound, gfReadBound; // pretend to be these things?
  41. extern BOOL gfDecompressBound, gfDrawBound;
  42. static LPVOID AllocMem(DWORD dw);
  43. ///////////////////////////////////////////////////////////////////////////
  44. //
  45. // useful macros
  46. //
  47. ///////////////////////////////////////////////////////////////////////////
  48. #define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
  49. #define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
  50. #define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
  51. #define DIBPTR(lpbi) ((LPBYTE)(lpbi) + \
  52. (int)(lpbi)->biSize + \
  53. (int)(lpbi)->biClrUsed * sizeof(RGBQUAD) )
  54. extern BOOL gfPlaying; // are we playing?
  55. extern HWND ghwndApp;
  56. extern HACCEL ghAccel;
  57. // for DPF's
  58. int Skip, Jump, Empty, Cheat;
  59. LONG frPlayed, frStart;
  60. BOOL fAudioBroke;
  61. // Decide whether or not you want the profiler running
  62. #define PROFILE
  63. #ifdef PROFILE
  64. #define TIME(x) \
  65. LONG time ## x, cnt ## x;
  66. #define ZERO(x) \
  67. time ## x = 0, cnt ## x = 0
  68. #define START(x) \
  69. time ## x -= (LONG)timeGetTime()
  70. #define END(x) \
  71. (time ## x += (LONG)timeGetTime()), cnt ## x ++
  72. #else
  73. #define TIME(x)
  74. #define ZERO(x)
  75. #define START(x)
  76. #define END(x)
  77. #endif
  78. TIME(Total); // for profiling
  79. TIME(Other);
  80. TIME(Time);
  81. TIME(Key);
  82. TIME(Read);
  83. TIME(Copy);
  84. TIME(Draw);
  85. TIME(Audio);
  86. TIME(Decomp);
  87. TIME(Yield);
  88. TIME(Free);
  89. // wFlags in Q structure
  90. #define FAST_TEMPORAL 1
  91. typedef struct {
  92. HWND hwnd;
  93. HDC hdc;
  94. LPBITMAPINFOHEADER lpbi;
  95. HDRAWDIB hdd;
  96. RECT rc;
  97. } VIDEORENDER, FAR *LPVIDEORENDER;
  98. typedef struct {
  99. HWAVEOUT hWaveOut;
  100. WAVEHDR wavehdr[NUM_WAVE_HEADERS];
  101. BOOL fBusy[NUM_WAVE_HEADERS]; // waiting for WHDR_DONE
  102. } AUDIORENDER, FAR *LPAUDIORENDER;
  103. typedef struct _QENTRY {
  104. LONG start; // first TIME!!! sample number in our buffer
  105. LONG length; // number of samples in our buffer
  106. LONG size; // length in bytes of the buffer
  107. struct _QENTRY huge *next; // where to find the next bunch of data
  108. // after struct comes the compressed data from the stream
  109. } QENTRY, huge *HPQENTRY;
  110. typedef struct {
  111. PAVISTREAM pavi; // stream we'll read from
  112. DWORD fccType;// what kind of stream is this? (eg. streamtypeVIDEO)
  113. DWORD dwSampleSize; // 0 if samples are variable length
  114. //!!!!
  115. HIC hic; // a compressor that can decompress the stream
  116. WORD wFlags; // eg. FAST_TEMPORAL
  117. LPVOID lpfmtIn; // format of the compressed data in the stream
  118. LPVOID lpfmtOut; // decompressed format stored in queue
  119. LPVOID lpRender; // handle to rendering information
  120. //!!!
  121. LONG timeStart; // the time when the stream started playing
  122. LONG sampleStart; // the first sample number we played
  123. LONG streamEnd; // the last sample in the stream
  124. HPBYTE buffer; // points to the beginning of the buffer
  125. LONG bufsize; // size of buffer
  126. LONG buffree; // how many of these bytes are free?
  127. HPQENTRY head; // where next chunk from disk is written
  128. HPQENTRY tail; // other end of queue - start of real data
  129. HPQENTRY read; // where render will read from to get data
  130. HPQENTRY recent; // last thing read into the q (to update ->next)
  131. int count; // how many chunks of junk in the queue?
  132. int countR; // how many of them haven't started rendering?
  133. long pos; // which sample we'll start reading next
  134. DWORD dwSampPerRead; // How many samples to read at a time
  135. HPBYTE lpBitsIn; // buffer for a stream read
  136. LONG cbBitsIn; // size of buffer
  137. LONG cbBitsInUsed; // amount of data read into buffer
  138. BOOL fBitsInReady; // does this buffer have frame data in it?
  139. LONG lBitsInSample; // 1st sample in the buffer
  140. } QUEUE, *PQUEUE, FAR *LPQUEUE;
  141. typedef struct {
  142. int count;
  143. LPQUEUE queue[MAXNUMSTREAMS];
  144. } AVIQUEUE, *PAVIQUEUE, far *LPAVIQUEUE;
  145. // global - for aviTime()
  146. LPAVIQUEUE qAVI;
  147. /***************************************************************************/
  148. /***************************************************************************/
  149. /***** INTERNAL FUNCTIONS THAT KNOW ABOUT SPECIFIC STREAM TYPES **********/
  150. /***************************************************************************/
  151. /***************************************************************************/
  152. //
  153. // Wait the specified number of milliseconds
  154. //
  155. void NEAR PASCAL Wait(LONG msec)
  156. {
  157. LONG l;
  158. l = timeGetTime();
  159. while ((LONG)timeGetTime() < l + msec);
  160. return;
  161. }
  162. //
  163. // Determine if the given stream is compressed.
  164. //
  165. BOOL NEAR qIsCompressed(LPQUEUE q)
  166. {
  167. if (q->fccType == streamtypeVIDEO) {
  168. // If we want DRAWDIB to decompress for us, just pretend we're
  169. // not comrpressed!
  170. return gfDecompress &&
  171. ((LPBITMAPINFOHEADER)q->lpfmtIn)->biCompression != BI_RGB;
  172. } else {
  173. return FALSE; // !!! decompression is pretty video specific now.
  174. }
  175. }
  176. //
  177. // Return how much space it will take to decompress the given bits
  178. //
  179. LONG NEAR qDecompressedSize(LPQUEUE q, HPBYTE hp, LONG cb)
  180. {
  181. if (q->fccType == streamtypeVIDEO) {
  182. if (qIsCompressed(q))
  183. return ((LPBITMAPINFOHEADER)q->lpfmtOut)->biSizeImage;
  184. else
  185. return cb;
  186. } else {
  187. return cb; // it's not compressed
  188. }
  189. }
  190. //
  191. // Locate and return the HIC of a compressor that can decompress the given
  192. // type of format from the given type of stream.
  193. // This will return the output format that it will decompress into.
  194. //
  195. HIC NEAR qLocate(LPQUEUE q, LPVOID FAR *lplpfmtOut) {
  196. DWORD fccHandler;
  197. HIC hic;
  198. LONG cb;
  199. if (q->fccType == streamtypeVIDEO) {
  200. if (lplpfmtOut == NULL)
  201. return NULL;
  202. // ICM won't search for compressors to decompress BI_RLE8.
  203. // We need to provide the handler of a known decompressor that comes
  204. // with our AVIFile read API code. !!! HACK
  205. if (((LPBITMAPINFOHEADER)q->lpfmtIn)->biCompression == BI_RLE8)
  206. fccHandler = mmioFOURCC('R','L','E',' ');
  207. else
  208. fccHandler = 0;
  209. // trust that the default format to decompress to is something usable
  210. hic = ICLocate(ICTYPE_VIDEO, fccHandler, q->lpfmtIn, NULL,
  211. ICMODE_DECOMPRESS);
  212. if (hic == NULL)
  213. return NULL;
  214. // get ready for the Decompress calls we'll be making later
  215. *lplpfmtOut = GlobalAllocPtr(GMEM_MOVEABLE,
  216. sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD));
  217. if (*lplpfmtOut == NULL) {
  218. ICClose(hic);
  219. return NULL;
  220. }
  221. //!!! pass the size of the video so it knows whether to dither or not.
  222. // Making it stretch the dither will look ugly!
  223. ICGetDisplayFormat(hic, q->lpfmtIn, *lplpfmtOut, 0, 0, 0);
  224. // !!! ICM bug... biSizeImage is not set right by ICGetDisplayFormat
  225. // Luckily I happen to know it's uncompressed and can set it myself
  226. ((LPBITMAPINFOHEADER)*lplpfmtOut)->biSizeImage =
  227. ((LPBITMAPINFOHEADER)*lplpfmtOut)->biHeight *
  228. DIBWIDTHBYTES(*(LPBITMAPINFOHEADER)(*lplpfmtOut));
  229. } else {
  230. hic = NULL;
  231. if (hic) {
  232. // get ready for the Decompress calls we'll be making later
  233. cb = ICDecompressGetFormatSize(hic, q->lpfmtIn);
  234. *lplpfmtOut = GlobalAllocPtr(GMEM_MOVEABLE, cb);
  235. if (*lplpfmtOut == NULL) {
  236. ICClose(hic);
  237. return NULL;
  238. }
  239. ICDecompressGetFormat(hic, q->lpfmtIn, *lplpfmtOut);
  240. }
  241. }
  242. return hic;
  243. }
  244. //
  245. // Set flags specific to the type of data we're handling.
  246. //
  247. WORD NEAR qSetFlags(LPQUEUE q)
  248. {
  249. ICINFO icinfo;
  250. WORD wFlags = 0;
  251. if (q->fccType == streamtypeVIDEO) {
  252. // Figure out if we can do fast temporal compression or not.
  253. // (Do we need to decompress on top of the previous frame?)
  254. if (q->hic) {
  255. ICGetInfo(q->hic, &icinfo, sizeof(ICINFO));
  256. if (icinfo.dwFlags & VIDCF_FASTTEMPORALD)
  257. wFlags |= FAST_TEMPORAL;
  258. }
  259. }
  260. q->wFlags = wFlags;
  261. return wFlags;
  262. }
  263. //
  264. // Pick an arbitrary size to make the buffer in the queue
  265. //
  266. BOOL NEAR qBufferStuff(LPQUEUE q)
  267. {
  268. LONG cb;
  269. // !!! Pick a better size for our video queue?
  270. #define NUM_VID_BUFFERS 6
  271. if (q->fccType == streamtypeVIDEO) {
  272. if (q->lpfmtOut) { // stream is compressed, use uncompressed size
  273. cb = ((LPBITMAPINFOHEADER)(q->lpfmtOut))->biSizeImage;
  274. q->bufsize = cb * NUM_VID_BUFFERS + NUM_VID_BUFFERS *sizeof(QENTRY);
  275. } else { // stream is not compressed, use input size
  276. cb = ((LPBITMAPINFOHEADER)(q->lpfmtIn))->biSizeImage;
  277. q->bufsize = cb * NUM_VID_BUFFERS + NUM_VID_BUFFERS *sizeof(QENTRY);
  278. }
  279. q->dwSampPerRead = 1;
  280. q->buffree = q->bufsize;
  281. // We want n reads of Audio to exactly fill the buffer so no space is wasted
  282. // and we'll never waste time trying to read into buffers that are too small
  283. } else if (q->fccType == streamtypeAUDIO) {
  284. if (q->dwSampleSize == 0) {
  285. DPF("***********ASSERT! Audio has variable sample size!");
  286. }
  287. q->dwSampPerRead = AUD_BUFFERS_MAX_SIZE / q->dwSampleSize;
  288. cb = AUD_BUFFERS_MAX_SIZE;
  289. q->bufsize = cb * NUM_WAVE_HEADERS + NUM_WAVE_HEADERS * sizeof(QENTRY);
  290. q->buffree = q->bufsize;
  291. } else {
  292. cb = 0;
  293. q->dwSampPerRead = 0;
  294. q->bufsize = 0;
  295. q->buffree = q->bufsize;
  296. }
  297. // Make a buffer to read the stream data into. Unfortunately, I have
  298. // no good way of knowing how big the buffer needs to be. I can't
  299. // re-alloc it bigger while we're playing if my guess is wrong (not
  300. // enough time). Hopefully 3/2 the uncompressed size is big enough
  301. //
  302. // Use DOS Memory for speed
  303. q->fBitsInReady = FALSE;
  304. q->cbBitsInUsed = 0;
  305. q->cbBitsIn = cb * 3 / 2;
  306. q->lpBitsIn = AllocMem(cb * 3 / 2); // !!! What is the real size?
  307. if (q->lpBitsIn == NULL)
  308. return FALSE;
  309. return TRUE;
  310. }
  311. // Return the decompressed format
  312. LPVOID NEAR qFmt(LPQUEUE q)
  313. {
  314. // If we're decompressing, we know it already
  315. if (qIsCompressed(q))
  316. return q->lpfmtOut;
  317. // If not, it's the same as the input format
  318. else {
  319. return q->lpfmtIn;
  320. }
  321. }
  322. // !!! ouch
  323. LPVOID NEAR PASCAL qRead(LPQUEUE q);
  324. BOOL NEAR PASCAL qEat(LPQUEUE q);
  325. LPVOID NEAR PASCAL qPeek(LPQUEUE q);
  326. LONG NEAR PASCAL qPeekSize(LPQUEUE q);
  327. BOOL NEAR qRender(LPQUEUE q, LPVOID lpBits, LONG cbBits, BOOL fRender)
  328. {
  329. #define VidRender ((LPVIDEORENDER)q->lpRender)
  330. #define AudRender ((LPAUDIORENDER)q->lpRender)
  331. if (q->fccType == streamtypeVIDEO) {
  332. RECT rc = VidRender->rc;
  333. WORD wFlags = DDF_SAME_HDC | DDF_SAME_DRAW;
  334. if (lpBits == NULL)
  335. return FALSE;
  336. // We don't want to draw this, but the decompressor needs to see it
  337. // (eg. for temporal compression)
  338. if (!fRender)
  339. wFlags |= DDF_DONTDRAW;
  340. START(Draw);
  341. DrawDibDraw(VidRender->hdd, VidRender->hdc,
  342. rc.left, rc.top,
  343. rc.right - rc.left,
  344. rc.bottom - rc.top,
  345. VidRender->lpbi, lpBits, 0, 0, -1, -1,
  346. wFlags);
  347. if (fRender)
  348. qEat(q); // we're done with this right away - remove w/o render
  349. if (!gfDecompress && gfDecompressBound)
  350. Wait(DECOMPRESS_WAIT_TIME);
  351. if (gfDrawBound)
  352. Wait(DRAW_WAIT_TIME);
  353. DPF3("DRAW: Rendered a video frame");
  354. END(Draw);
  355. return TRUE;
  356. } else if (q->fccType == streamtypeAUDIO) {
  357. BOOL f = FALSE;
  358. int i;
  359. UINT w;
  360. START(Audio);
  361. //
  362. // First of all, free up any buffers from the queue that are done
  363. // !!! Assumes they come back in the order they were sent
  364. //
  365. for (i = 0; i < NUM_WAVE_HEADERS; i++) {
  366. if (AudRender->fBusy[i] &&
  367. (AudRender->wavehdr[i].dwFlags & WHDR_DONE)) {
  368. DPF3("AUDIO: Wave Buffer %d freed", i);
  369. qEat(q); // remove from queue - without rendering it
  370. AudRender->fBusy[i] = FALSE;
  371. }
  372. }
  373. for (i = 0; i < NUM_WAVE_HEADERS; i++) {
  374. if (!(AudRender->wavehdr[i].dwFlags & WHDR_DONE))
  375. break;
  376. }
  377. if (i == NUM_WAVE_HEADERS && !fAudioBroke &&
  378. q->pos < AVIStreamEnd(q->pavi)) {
  379. DPF("AUDIO: ************** AUDIO BROKE!!! ***************");
  380. fAudioBroke = TRUE;
  381. }
  382. if (!lpBits || !fRender) {
  383. DPF3("AUDIO: No bits to render");
  384. END(Audio);
  385. return FALSE;
  386. }
  387. for (i = 0; i < NUM_WAVE_HEADERS; i++) {
  388. if ((AudRender->wavehdr[i].dwFlags & WHDR_DONE) &&
  389. AudRender->hWaveOut) {
  390. AudRender->wavehdr[i].lpData = lpBits;
  391. AudRender->wavehdr[i].dwBufferLength = cbBits;
  392. AudRender->fBusy[i] = TRUE;
  393. w = waveOutWrite(AudRender->hWaveOut, &AudRender->wavehdr[i],
  394. sizeof(WAVEHDR));
  395. f = TRUE;
  396. DPF3("AUDIO: Wrote audio buffer %d", i);
  397. // We used some data - advance the read pointer so the next
  398. // read will give us new wave data
  399. qRead(q);
  400. break;
  401. }
  402. }
  403. if (i == NUM_WAVE_HEADERS) { // braces necessary
  404. DPF3("AUDIO: Can't render - no free buffers");
  405. }
  406. END(Audio);
  407. return f;
  408. } else {
  409. return FALSE;
  410. }
  411. }
  412. void NEAR qRenderFini(LPQUEUE q)
  413. {
  414. #define VidRender ((LPVIDEORENDER)q->lpRender)
  415. #define AudRender ((LPAUDIORENDER)q->lpRender)
  416. int i;
  417. UINT w;
  418. if (q->fccType == streamtypeVIDEO) {
  419. SelectPalette(VidRender->hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
  420. RealizePalette(VidRender->hdc);
  421. DrawDibClose(VidRender->hdd);
  422. ReleaseDC(VidRender->hwnd, VidRender->hdc);
  423. GlobalFreePtr(VidRender);
  424. } else if (q->fccType == streamtypeAUDIO) {
  425. if (AudRender->hWaveOut) {
  426. w = waveOutReset(AudRender->hWaveOut);
  427. for (i = 0; i < NUM_WAVE_HEADERS; i++) {
  428. // set these back to what they were when we prepared them
  429. AudRender->wavehdr[i].lpData = (LPBYTE) q->buffer;
  430. AudRender->wavehdr[i].dwBufferLength = q->bufsize;
  431. waveOutUnprepareHeader(AudRender->hWaveOut,
  432. &AudRender->wavehdr[i], sizeof(WAVEHDR));
  433. }
  434. w = waveOutClose(AudRender->hWaveOut);
  435. }
  436. GlobalFreePtr(AudRender);
  437. } else {
  438. }
  439. }
  440. BOOL NEAR qRenderInit(LPQUEUE q, HWND hwnd, RECT rc)
  441. {
  442. #define VidRender ((LPVIDEORENDER)q->lpRender)
  443. #define AudRender ((LPAUDIORENDER)q->lpRender)
  444. int i;
  445. UINT w;
  446. if (q->fccType == streamtypeVIDEO) {
  447. LPVOID lpfmt = qFmt(q);
  448. VidRender = (LPVIDEORENDER)GlobalAllocPtr(GMEM_MOVEABLE,
  449. sizeof(VIDEORENDER));
  450. if (VidRender == NULL)
  451. return FALSE;
  452. VidRender->hwnd = hwnd;
  453. VidRender->hdc = GetDC(hwnd);
  454. VidRender->lpbi = (LPBITMAPINFOHEADER)lpfmt;
  455. VidRender->hdd = DrawDibOpen();
  456. VidRender->rc = rc;
  457. // !!! Error code?
  458. DrawDibBegin(VidRender->hdd, VidRender->hdc,
  459. rc.right - rc.left,
  460. rc.bottom - rc.top,
  461. VidRender->lpbi,
  462. (int)VidRender->lpbi->biWidth,
  463. (int)VidRender->lpbi->biHeight, 0);
  464. DrawDibRealize(VidRender->hdd, VidRender->hdc, FALSE);
  465. q->timeStart = timeGetTime(); // start the clock
  466. return TRUE;
  467. } else if (q->fccType == streamtypeAUDIO) {
  468. AudRender = (LPAUDIORENDER)GlobalAllocPtr(GMEM_MOVEABLE,
  469. sizeof(AUDIORENDER));
  470. if (AudRender == NULL)
  471. return FALSE;
  472. w = waveOutOpen(&AudRender->hWaveOut, WAVE_MAPPER, q->lpfmtIn,
  473. 0, 0L, 0);
  474. if (w) { // close the device and try once more before giving up
  475. // !!! Hack for known bugs in other people's stuff
  476. LPWAVEFORMAT lpwf = q->lpfmtIn;
  477. if (lpwf->wFormatTag == WAVE_FORMAT_PCM) {
  478. lpwf->nAvgBytesPerSec = lpwf->nSamplesPerSec*lpwf->nBlockAlign;
  479. }
  480. sndPlaySound(NULL, 0);
  481. w = waveOutOpen(&AudRender->hWaveOut, WAVE_MAPPER, q->lpfmtIn,
  482. 0, 0L, 0);
  483. }
  484. if (w) {
  485. DPF("AUDIO: *************Cannot open the wave device");
  486. AudRender->hWaveOut = NULL; // paranoia?
  487. return FALSE;
  488. }
  489. for (i = 0; i < NUM_WAVE_HEADERS; i++) {
  490. AudRender->fBusy[i] = FALSE; // not outstanding
  491. AudRender->wavehdr[i].dwFlags = 0;
  492. AudRender->wavehdr[i].lpData = (LPBYTE) q->buffer;
  493. AudRender->wavehdr[i].dwBufferLength = q->bufsize;
  494. if (waveOutPrepareHeader(AudRender->hWaveOut,&AudRender->wavehdr[i],
  495. sizeof(WAVEHDR))) {
  496. DPF("AUDIO: *************Cannot prepare header %d", i);
  497. qRenderFini(q);
  498. return FALSE;
  499. }
  500. AudRender->wavehdr[i].dwFlags |= WHDR_DONE; // nuked by Prepare
  501. }
  502. // Pause for now so we can start instantly by un-pausing
  503. waveOutPause(AudRender->hWaveOut);
  504. // we must pre-stuff our audio wave buffers with all the data we have
  505. // so that whenever a buffer is free we know it's because it's done with
  506. // some more data
  507. // !!! If we have more wavebuffers than data, the leftovers will think
  508. // !!! that they've completed and destroy some audio!
  509. while (qRender(q, qPeek(q), qPeekSize(q), TRUE)); //don't remove from Q
  510. q->timeStart = timeGetTime(); // start the clock
  511. return TRUE;
  512. } else {
  513. return 0;
  514. }
  515. }
  516. /***************************************************************************/
  517. /***************************************************************************/
  518. /************* END OF SPECIFIC STREAM TYPE FUNCTIONS ********************/
  519. /***************************************************************************/
  520. /***************************************************************************/
  521. //
  522. // Determine if a queue is getting low on data.
  523. // Returns the percentage of queue buffer space that is full.
  524. //
  525. int NEAR qStarved(LPQUEUE q)
  526. {
  527. int i;
  528. i = (int)(100L - (q->buffree * 100L / q->bufsize));
  529. DPF3("STARVED: %ld%%", i);
  530. return i;
  531. }
  532. // Shut down the queueing system
  533. void NEAR PASCAL qFini(LPQUEUE q)
  534. {
  535. if (q->lpfmtIn)
  536. GlobalFreePtr(q->lpfmtIn);
  537. q->lpfmtIn = NULL;
  538. if (q->hic) {
  539. ICDecompressEnd(q->hic);
  540. ICClose(q->hic);
  541. if (q->lpfmtOut)
  542. GlobalFreePtr(q->lpfmtOut);
  543. q->lpfmtOut = NULL;
  544. }
  545. q->hic = NULL;
  546. if (q->lpBitsIn)
  547. GlobalFreePtr(q->lpBitsIn);
  548. q->lpBitsIn = NULL;
  549. if (q->buffer)
  550. GlobalFreePtr(q->buffer);
  551. q->buffer = NULL;
  552. q->head = q->tail = q->read = NULL;
  553. }
  554. // initialize the queueing system
  555. BOOL NEAR PASCAL qInit(PAVISTREAM pavi, LPQUEUE q)
  556. {
  557. LONG cb;
  558. AVISTREAMINFO avis;
  559. if (q == NULL)
  560. return FALSE;
  561. q->pavi = pavi;
  562. q->lpfmtIn = q->lpfmtOut = NULL;
  563. q->buffer = q->lpBitsIn = NULL;
  564. q->recent = NULL;
  565. q->hic = NULL;
  566. if (pavi == NULL)
  567. return FALSE;
  568. if (AVIStreamInfo(pavi, &avis, sizeof(avis)) != AVIERR_OK)
  569. goto qInitError;
  570. q->fccType = avis.fccType;
  571. q->dwSampleSize = avis.dwSampleSize;
  572. // Get the format of the compressed data from the stream
  573. AVIStreamReadFormat(pavi, AVIStreamStart(pavi), NULL, &cb);
  574. q->lpfmtIn = GlobalAllocPtr(GMEM_MOVEABLE, cb);
  575. if (q->lpfmtIn == NULL)
  576. goto qInitError;
  577. AVIStreamReadFormat(pavi, 0, q->lpfmtIn, &cb);
  578. // Maybe we haven't been given the size of a compressed image. Fix it.
  579. if (((LPBITMAPINFOHEADER)q->lpfmtIn)->biSizeImage == 0)
  580. ((LPBITMAPINFOHEADER)q->lpfmtIn)->biSizeImage =
  581. avis.dwSuggestedBufferSize;
  582. if (((LPBITMAPINFOHEADER)q->lpfmtIn)->biSizeImage == 0)
  583. ((LPBITMAPINFOHEADER)q->lpfmtIn)->biSizeImage = 20000; // !!!
  584. // Open a compressor that can decompress it
  585. if (qIsCompressed(q)) {
  586. // Find a decompressor and get the decompressed format
  587. q->hic = qLocate(q, &(q->lpfmtOut));
  588. if (q->hic == NULL)
  589. goto qInitError;
  590. ICDecompressBegin(q->hic, q->lpfmtIn, q->lpfmtOut);
  591. }
  592. // Pick a buffer size, and the number of samples to read each time
  593. // !!! Must have a valid output format before we call this.
  594. if (!qBufferStuff(q))
  595. goto qInitError;
  596. qSetFlags(q);
  597. // Queue starts empty, and is about to read the first sample
  598. q->count = q->countR = 0;
  599. q->pos = q->sampleStart = AVIStreamStart(pavi);
  600. q->streamEnd = AVIStreamEnd(pavi);
  601. q->buffer = GlobalAllocPtr(GMEM_MOVEABLE, q->bufsize);
  602. q->head = q->tail = q->read = (HPQENTRY)q->buffer;
  603. if (q->buffer == NULL)
  604. goto qInitError;
  605. return TRUE;
  606. qInitError:
  607. qFini(q);
  608. return FALSE;
  609. }
  610. #if 0
  611. // return the previous buffer of the queue
  612. HPSTR NEAR qPrev(LPQUEUE q, HPSTR hp)
  613. {
  614. // !!! Even if the queue is empty, the old information is still there.
  615. // Special case that we're at the beginning of the buffer
  616. if (hp == q->buffer)
  617. return hp + (QSIZE - 1) * q->size;
  618. else
  619. return hp - q->size;
  620. }
  621. #endif
  622. #define HeadBuf(q) (HPBYTE)((q)->head + 1)
  623. #define TailBuf(q) (HPBYTE)((q)->tail + 1)
  624. #define ReadBuf(q) (HPBYTE)((q)->read + 1)
  625. #define BufEnd(q) (HPBYTE)((HPBYTE)((q)->buffer) + (q)->bufsize)
  626. // Decompress the entry in our input buffer into the queue
  627. BOOL NEAR qDecompress(LPQUEUE q)
  628. {
  629. LONG lBytesNeeded, lBytesFree;
  630. LONG lKey;
  631. BOOL fHack;
  632. // Sometimes the RLE8 file has RGB frames in it and will blow if we
  633. // try to decompress them.
  634. // !!! fix RLEC so this hack is not needed!
  635. #define qlpbi ((LPBITMAPINFOHEADER)q->lpfmtIn)
  636. fHack = q->fccType == streamtypeVIDEO &&
  637. qlpbi->biCompression == BI_RLE8 &&
  638. (LONG)(qlpbi->biSizeImage) == q->cbBitsInUsed;
  639. lBytesNeeded = (qIsCompressed(q) && !fHack) ?
  640. qDecompressedSize(q, q->lpBitsIn, q->cbBitsInUsed) : q->cbBitsInUsed;
  641. // How many contiguous bytes do we have left in the queue?
  642. if ((HPBYTE)(q->tail) <= (HPBYTE)(q->head)) {
  643. lBytesFree = BufEnd(q) - HeadBuf(q);
  644. // If head and tail are equal - some special cases
  645. if ((HPBYTE)(q->tail) == (HPBYTE)(q->head)) {
  646. if (q->count > 0)
  647. lBytesFree = 0;
  648. else {
  649. q->head = q->tail = q->read = (HPQENTRY)q->buffer;
  650. lBytesFree = BufEnd(q) - HeadBuf(q);
  651. }
  652. }
  653. } else {
  654. lBytesFree = (HPBYTE)(q->tail) - HeadBuf(q);
  655. }
  656. // Not enough space in the queue to decompress this frame!
  657. if (lBytesFree < lBytesNeeded) {
  658. // Did we fail because we're at the end of the queue? Then
  659. // try reading into the beginning of the queue.
  660. if ((HPBYTE)(q->head) > (HPBYTE)(q->tail) &&
  661. (HPBYTE)(q->tail) != (HPBYTE)(q->buffer)) {
  662. q->head = (HPQENTRY)q->buffer;
  663. if (q->countR == 0)
  664. q->read = q->head;
  665. lBytesFree = (HPBYTE)(q->tail) - HeadBuf(q);
  666. } else {
  667. lBytesFree = 0;
  668. }
  669. }
  670. // Still not enough space in the queue? Then the queue is really full
  671. if (lBytesFree < lBytesNeeded) {
  672. DPF3("Q too full to decompress into");
  673. return FALSE;
  674. }
  675. //
  676. // Now decompress the frame into our buffer
  677. // If we're not compressed, we can do a straight copy.
  678. //
  679. if (fHack || !qIsCompressed(q)) {
  680. START(Copy);
  681. hmemcpy(HeadBuf(q), q->lpBitsIn, lBytesNeeded);
  682. END(Copy);
  683. } else {
  684. // !!! This is kind of video specific, isn't it? What will decompressing
  685. // audio look like?
  686. START(Key);
  687. lKey = AVIStreamFindKeyFrame(q->pavi, q->lBitsInSample, 0);
  688. END(Key);
  689. // We need to copy of the previous bits and decompress on top of them
  690. // !!! This assumes the previous entry is the previous bits!
  691. // !!! And that they're still there!
  692. if (!(q->wFlags & FAST_TEMPORAL) && lKey != q->lBitsInSample &&
  693. q->recent) {
  694. START(Copy);
  695. hmemcpy(HeadBuf(q), q->recent + 1, q->recent->size);
  696. END(Copy);
  697. }
  698. START(Decomp);
  699. ICDecompress(q->hic, 0, q->lpfmtIn, q->lpBitsIn, q->lpfmtOut,
  700. HeadBuf(q));
  701. if (gfDecompressBound)
  702. Wait(DECOMPRESS_WAIT_TIME);
  703. DPF3("DECOMPRESS: %ld --> %ld bytes", q->cbBitsInUsed, lBytesNeeded);
  704. END(Decomp);
  705. }
  706. // Now recognize that less space is available in the queue
  707. q->buffree -= lBytesNeeded + sizeof(QENTRY);
  708. // Fix the link from the previous read to this one in case it's moved
  709. if (q->recent && q->count)
  710. q->recent->next = q->head;
  711. q->recent = q->head;
  712. q->head->start = q->pos;
  713. // !!! Audio picked it's own number of samples to read -- video read one
  714. q->head->length = q->dwSampleSize ? lBytesNeeded / q->dwSampleSize
  715. : q->dwSampPerRead;
  716. q->head->size = lBytesNeeded;
  717. q->head = (HPQENTRY)(HeadBuf(q) + lBytesNeeded);
  718. if ((HPBYTE)(q->head) > BufEnd(q)) {
  719. DPF("*************Head went past Buffer End!");
  720. }
  721. if ((HPBYTE)(q->head) >= BufEnd(q))
  722. q->head = (HPQENTRY)q->buffer;
  723. // Initially, the block we just read in will say its next block will be
  724. // wherever the new head is. This could change later.
  725. q->recent->next = q->head;
  726. q->pos += q->dwSampleSize ? lBytesNeeded / q->dwSampleSize
  727. : q->dwSampPerRead;
  728. q->count++;
  729. q->countR++;
  730. q->fBitsInReady = FALSE;
  731. return TRUE;
  732. }
  733. // read something into the queue
  734. BOOL NEAR qFill(LPQUEUE q)
  735. {
  736. LONG lBytesRead;
  737. HRESULT hRet;
  738. BOOL f = FALSE;
  739. // If there is already a compressed frame in the buffer, stuff it in the
  740. // queue before reading another frame.
  741. if (q->fBitsInReady) {
  742. DPF3("Purging a previous buffer");
  743. f = qDecompress(q);
  744. }
  745. // The buffer is still full! I guess the queue was full. Bail.
  746. if (q->fBitsInReady) {
  747. DPF3("Can't purge buffer!");
  748. return FALSE;
  749. }
  750. // Seems we're at the end of the stream! No more to read.
  751. if (q->pos >= q->streamEnd)
  752. return FALSE;
  753. START(Read);
  754. // For fixed sample sizes, read a "convenient" number of samples, ie.
  755. // how ever many samples are left in this AVI chunk. Never read more than
  756. // a certain amount, though.
  757. if (q->dwSampleSize) {
  758. // !!! READ CONVENIENT NUMBER!!!
  759. hRet = AVIStreamRead(q->pavi, q->pos, q->dwSampPerRead, q->lpBitsIn,
  760. min((DWORD)q->cbBitsIn, q->dwSampPerRead * q->dwSampleSize),
  761. &lBytesRead, NULL);
  762. // for variable length samples, just read normally whatever we'd decided
  763. } else {
  764. hRet = AVIStreamRead(q->pavi, q->pos, q->dwSampPerRead, q->lpBitsIn,
  765. q->cbBitsIn, &lBytesRead, NULL);
  766. }
  767. if (gfReadBound)
  768. Wait(READ_WAIT_TIME);
  769. DPF3("READ: Read %ld bytes", lBytesRead);
  770. END(Read);
  771. if (hRet == AVIERR_OK) {
  772. q->fBitsInReady = TRUE;
  773. q->cbBitsInUsed = lBytesRead;
  774. q->lBitsInSample = q->pos;
  775. } else {
  776. DPF("******************Stream read failed");
  777. return FALSE; // uh oh! This shouldn't happen!
  778. }
  779. // Now decompress into the queue
  780. return (f || qDecompress(q));
  781. }
  782. // Fill the entire queue
  783. void NEAR qPrime(LPQUEUE q) // Preroll for clockwork people
  784. {
  785. while (qFill(q))
  786. ;
  787. }
  788. // Return the number of entries in the queue
  789. int NEAR qCount(LPQUEUE q)
  790. {
  791. return q->count;
  792. }
  793. // Return the lowest sample number in the queue that hasn't been rendered yet.
  794. // If the queue is empty, it will return the next sample it will read, because
  795. // it would then become the lowest sample in the queue.
  796. LONG NEAR PASCAL qSample(LPQUEUE q)
  797. {
  798. if (q->countR == 0)
  799. return q->pos;
  800. else
  801. return q->read->start;
  802. }
  803. //
  804. // Return a pointer to the lowest sample in the queue that hasn't been
  805. // rendered yet. Don't eat it out of the queue because it's still needed,
  806. // and don't skip past it or anything.
  807. //
  808. LPVOID NEAR PASCAL qPeek(LPQUEUE q)
  809. {
  810. if (q->countR == 0)
  811. return NULL;
  812. return ReadBuf(q);
  813. }
  814. //
  815. // Return the size of what qPeek() would return.
  816. //
  817. LONG NEAR PASCAL qPeekSize(LPQUEUE q)
  818. {
  819. if (q->countR == 0)
  820. return 0;
  821. return q->read->size;
  822. }
  823. //
  824. // Return a pointer to the lowest sample in the queue. Don't eat it out of the
  825. // queue because it's still needed, but subsequent Peeks will get newer data
  826. //
  827. LPVOID NEAR PASCAL qRead(LPQUEUE q)
  828. {
  829. LPVOID lp;
  830. if (q->countR == 0)
  831. return NULL;
  832. lp = ReadBuf(q);
  833. // We can't destroy this data yet... so don't move the tail
  834. q->read = (HPQENTRY)(q->read->next);
  835. q->countR--;
  836. // paranoia
  837. if (q->countR == 0)
  838. q->read = q->head;
  839. return lp;
  840. }
  841. //
  842. // return the Next sample that will be read into the queue.
  843. //
  844. long qPos(LPQUEUE q)
  845. {
  846. return q->pos;
  847. }
  848. //
  849. // Remove something from the queue without decompressing or remembering it.
  850. // But pass it to the renderer in case it needs to see the bits (eg. temporal
  851. // compression).
  852. //
  853. BOOL NEAR qSkip(LPQUEUE q)
  854. {
  855. // !!! This code should be identical to qEat() except it renders!
  856. if (q->count == 0)
  857. return FALSE;
  858. // More space is now available in the queue
  859. q->buffree += sizeof(QENTRY) + q->tail->size;
  860. if (q->count == 1) {
  861. // Renderer may need to see the data even though we're skipping it
  862. // (e.g. for temporal video compression)
  863. qRender(q, qPeek(q), qPeekSize(q), FALSE); // DON'T ACTUALLY RENDER
  864. q->tail = q->read = q->head = (HPQENTRY)q->buffer;
  865. q->countR = 0;
  866. // !!! q->recent = NULL; // hmemcpy needs recent bits for non key frames
  867. } else {
  868. qRender(q, qPeek(q), qPeekSize(q), FALSE); // DON'T ACTUALLY RENDER
  869. if (q->tail == q->read && q->countR) {
  870. q->countR--;
  871. q->read = (HPQENTRY)(q->tail->next);
  872. }
  873. q->tail = (HPQENTRY)(q->tail->next);
  874. }
  875. if ((HPBYTE)(q->tail) >= BufEnd(q)) {
  876. DPF("******************Tail went past Buffer End!");
  877. }
  878. q->count--;
  879. return TRUE;
  880. }
  881. //
  882. // Remove the first thing in the queue, without sending it to the renderer first
  883. // Returns whether or not anything was removed.
  884. //
  885. BOOL NEAR PASCAL qEat(LPQUEUE q)
  886. {
  887. // !!! This code should be identical to qSkip() except it doesn't render!
  888. if (q->count == 0)
  889. return FALSE;
  890. // More space is now available in the queue
  891. q->buffree += sizeof(QENTRY) + q->tail->size;
  892. if (q->count == 1) {
  893. q->tail = q->read = q->head = (HPQENTRY)q->buffer;
  894. q->countR = 0;
  895. // !!! q->recent = NULL; // hmemcpy needs recent bits for non key frames
  896. } else {
  897. if (q->tail == q->read && q->countR) {
  898. q->countR--;
  899. q->read = (HPQENTRY)(q->tail->next);
  900. }
  901. q->tail = (HPQENTRY)(q->tail->next);
  902. }
  903. if ((HPBYTE)(q->tail) >= BufEnd(q)) {
  904. DPF("******************Tail went past Buffer End!");
  905. }
  906. q->count--;
  907. return TRUE;
  908. }
  909. //
  910. // set the Next sample to be read into the queue using the time provided
  911. //
  912. void NEAR qSeek(LPQUEUE q, LONG pos)
  913. {
  914. // !!! Don't necessarily just empty the queue!
  915. while (qEat(q)); // remove from queue without rendering
  916. q->fBitsInReady = FALSE; // never bother to decompress this guy
  917. // !!! Do something intelligent if they seek to something in the queue
  918. // !!! already
  919. if (pos < q->pos) {
  920. DPF("******************Seeking backwards!");
  921. }
  922. q->pos = pos;
  923. // USED FOR DPRINTF ONLY
  924. if (q->fccType == streamtypeVIDEO)
  925. frPlayed = max(frPlayed, pos - 1);
  926. }
  927. //
  928. // Inform a stream what time it is.
  929. //
  930. void NEAR PASCAL qInformTime(LPQUEUE q, LONG time)
  931. {
  932. LONG fr, frNextKey, frPrevKey;
  933. if (q->fccType == streamtypeVIDEO) {
  934. LONG frEnd;
  935. // What frame of video should be showing?
  936. fr = AVIStreamTimeToSample(q->pavi, time) + q->sampleStart;
  937. DPF2("VIDEO: Time for frame %ld", fr);
  938. // Don't go past the end
  939. frEnd = AVIStreamEnd(q->pavi);
  940. if (fr >= frEnd)
  941. return;
  942. // for DPF's at end
  943. frPlayed = max(frPlayed, fr);
  944. // The earliest frame available is later in the movie, so we'll
  945. // need to wait until we can draw something. (We're caught up).
  946. if (qSample(q) > fr) {
  947. START(Free);
  948. DPF2("VIDEO: First available frame is %ld. Free time!", qSample(q));
  949. qFill(q); // read at LEAST one no matter how full we are
  950. END(Free);
  951. goto DontStarve; // !!! make sure we're aren't starving?
  952. }
  953. //
  954. // the frame we want is not in the q at all, and not the next frame
  955. // what should we do?
  956. //
  957. if (fr - qPos(q) > 0) {
  958. START(Key);
  959. frPrevKey = AVIStreamFindKeyFrame(q->pavi, fr,SEARCH_BACKWARD);
  960. frNextKey = AVIStreamFindKeyFrame(q->pavi, fr, SEARCH_FORWARD);
  961. END(Key);
  962. DPF2("VIDEO: Panic! qPos=%ld prev=%ld fr=%ld next=%ld",qPos(q),frPrevKey,fr,frNextKey);
  963. // If the previous key frame is in the queue somewhere, let's
  964. // draw it !!!
  965. if (qCount(q) &&
  966. frPrevKey >= qSample(q) && frPrevKey < qPos(q)) {
  967. while (qSample(q) < frPrevKey) { // find the prev key
  968. qSkip(q);
  969. Skip++; // remember we skipped a frame
  970. }
  971. if (qSample(q) == frPrevKey) {
  972. DPF2("VIDEO: Found PREV key %ld in queue", frPrevKey);
  973. qRender(q, qPeek(q), qPeekSize(q), TRUE); // draw it
  974. if (gfCheat) Cheat++; // not at exact time we wanted
  975. }
  976. if (qCount(q) == 0)
  977. Empty++;
  978. }
  979. // !!! Random if statement
  980. if (frPrevKey >= qPos(q) &&
  981. (fr - frPrevKey) <= (frNextKey - fr)) {
  982. DPF2("VIDEO: Jumping %d to PREV key frame %ld", (int)(frPrevKey - qSample(q)), frPrevKey);
  983. Jump += (int)(frPrevKey - qSample(q));
  984. Empty++;
  985. qSeek(q, frPrevKey);
  986. if (qFill(q)) { // get prev key frame
  987. qRender(q, qPeek(q), qPeekSize(q), TRUE); // draw it
  988. if (fr != frPrevKey && gfCheat)
  989. Cheat++; // weren't supposed to draw now
  990. }
  991. //qFill(q); // !!! waste of time?
  992. return; // !!! goto DontStarve would waste time ???
  993. } else if (frNextKey >= fr && frNextKey < frEnd) {
  994. DPF2("VIDEO: Jumping %d to NEXT key frame %ld", (int)(frNextKey - qSample(q)), frNextKey);
  995. Jump += (int)(frNextKey - qSample(q));
  996. Empty++;
  997. if (frPrevKey >= qPos(q)) {
  998. qSeek(q, frPrevKey);
  999. if (qFill(q)) { // get prev key frame
  1000. qRender(q, qPeek(q), qPeekSize(q), TRUE); // draw it
  1001. Jump -= 1; // we didn't jump this 1
  1002. if (gfCheat) Cheat++;
  1003. }
  1004. }
  1005. qSeek(q, frNextKey);
  1006. qFill(q); // put something in the empty queue
  1007. return; // !!! goto DontStarve ???
  1008. } else { // braces necessary
  1009. DPF2("VIDEO: Not jumping anywhere. End of movie");
  1010. }
  1011. }
  1012. // The frame available is too early, get some more frames until we
  1013. // have the one we need.
  1014. while (!qCount(q) || qSample(q) < fr) {
  1015. DPF2("VIDEO: We're behind! Count=%d, Available=%ld Want=%ld", qCount(q), qSample(q), fr);
  1016. if (qCount(q) == 0) { // get another sample if we're empty
  1017. Empty++; // remember we've been empty
  1018. DPF2("VIDEO: Queue is empty. Reading frame %ld, want frame %ld - SAME???", qPos(q), fr);
  1019. if (!qFill(q)) { // don't get caught in endless loop
  1020. DPF("VIDEO: ********Assertion failure! Heading south!");
  1021. break;
  1022. }
  1023. continue;
  1024. }
  1025. if (qSample(q) == fr - 1 && gfCheat) {
  1026. // Cheat! If we only need to skip one frame, draw it now
  1027. // and pretend we never skipped it
  1028. DPF2("VIDEO: Cheating at frame %ld", fr - 1);
  1029. qRender(q, qPeek(q), qPeekSize(q), TRUE);
  1030. Cheat++;
  1031. // !!! Return now? Or always draw frame fr next?
  1032. } else {
  1033. Skip++; // remember we skipped a frame
  1034. qSkip(q); // skip the frame we'll never need
  1035. }
  1036. }
  1037. // Something went wrong, abort
  1038. if (qSample(q) != fr) {
  1039. DPF("VIDEO: ***********Assertion failure! Wanted frame %ld but we died at frame %ld with %d entries in the queue", fr, qSample(q), qCount(q));
  1040. // !!! How to abort the main loop from here?
  1041. return;
  1042. }
  1043. // Read something if we're empty - we're about to need it
  1044. if (qCount(q) == 0) {
  1045. DPF("VIDEO: *************Why are we empty?");
  1046. Empty++; // remember we've been empty
  1047. if (!qFill(q)) // can't draw if this fails
  1048. return;
  1049. }
  1050. // Eat a frame and draw it
  1051. qRender(q, qPeek(q), qPeekSize(q), TRUE);
  1052. DontStarve:
  1053. // It's bad to let the queue get too empty
  1054. while (qStarved(q) < 50 && qFill(q)) { // braces necessary
  1055. DPF2("VIDEO: Filling a starving queue");
  1056. }
  1057. } else if (q->fccType == streamtypeAUDIO) {
  1058. // I don't care what time it is, I'm going to read and play audio
  1059. // as fast as I possibly can!
  1060. // Send all the information we can to the wave device to make sure
  1061. // audio never breaks. If there's nothing to send, it'll at least
  1062. // notice all of the buffers that are done and let them be re-used.
  1063. while (qRender(q, qPeek(q), qPeekSize(q), TRUE));
  1064. // Now Read and render at least one chunk of audio
  1065. qFill(q);
  1066. qRender(q, qPeek(q), qPeekSize(q), TRUE);
  1067. // If we're starving, keep reading and rendering
  1068. while (qStarved(q) < 50 && qFill(q)) {
  1069. DPF2("AUDIO: Filling a starving queue");
  1070. qRender(q, qPeek(q), qPeekSize(q), TRUE);
  1071. }
  1072. } else {
  1073. return;
  1074. }
  1075. }
  1076. // !!! static variables
  1077. static LONG timeDriverPrev = -1, timeClockBase, timeBase;
  1078. ///////////////////////////////////////////////////////////////////////////////
  1079. // Video Stream method:
  1080. // Just take the current time minus the start time
  1081. // Audio Stream method:
  1082. // We can't just use timeGetTime cuz the audio clock drifts from the real
  1083. // time clock and we need to sync to the audio we're hearing, even if it's the
  1084. // wrong time. But we can't use the wave driver call to find out what time it
  1085. // is either, cuz it may only be accurate to 1/5 of a second. So we have to
  1086. // use a combination of the two.
  1087. ///////////////////////////////////////////////////////////////////////////////
  1088. LONG NEAR PASCAL qNow(LPQUEUE q)
  1089. {
  1090. if (q->fccType == streamtypeVIDEO) {
  1091. return timeGetTime() - q->timeStart;
  1092. } else if (q->fccType == streamtypeAUDIO) {
  1093. MMTIME mmtime;
  1094. LONG now, timeDriver, l;
  1095. //
  1096. // Get the current time
  1097. //
  1098. now = timeGetTime();
  1099. //
  1100. // Ask the wave driver how long it's been playing for
  1101. //
  1102. if (((LPAUDIORENDER)q->lpRender)->hWaveOut) {
  1103. mmtime.wType = TIME_SAMPLES;
  1104. waveOutGetPosition(((LPAUDIORENDER)q->lpRender)->hWaveOut,
  1105. &mmtime, sizeof(mmtime));
  1106. if (mmtime.wType == TIME_SAMPLES)
  1107. timeDriver = AVIStreamSampleToTime(q->pavi, q->sampleStart) +
  1108. muldiv32(mmtime.u.sample, 1000,
  1109. ((LPWAVEFORMAT)q->lpfmtIn)->nSamplesPerSec);
  1110. else if (mmtime.wType == TIME_BYTES)
  1111. timeDriver = AVIStreamSampleToTime(q->pavi, q->sampleStart) +
  1112. muldiv32(mmtime.u.cb, 1000,
  1113. ((LPWAVEFORMAT)q->lpfmtIn)->nAvgBytesPerSec);
  1114. else
  1115. timeDriver = -1;
  1116. } else
  1117. timeDriver = -1;
  1118. //
  1119. // Something's wrong with the audio clock.. just use the main clock
  1120. //
  1121. if (timeDriver == -1) {
  1122. DPF("AUDIO: **********Can't get current time from audio driver!");
  1123. return now - q->timeStart;
  1124. }
  1125. //
  1126. // Audio driver still thinks it's playing the same spot as last time
  1127. //
  1128. if (timeDriver == timeDriverPrev) {
  1129. // !!! Assumes timeDriver was 0 at the beginning of play
  1130. l = now - timeClockBase + timeDriverPrev - timeBase;
  1131. //
  1132. // Ah! A new sample of audio being played
  1133. //
  1134. } else {
  1135. timeClockBase = now;
  1136. timeDriverPrev = timeDriver;
  1137. // !!! Assumes timeDriver was 0 at the beginning of play
  1138. l = timeDriverPrev - timeBase;
  1139. }
  1140. return l;
  1141. } else {
  1142. return timeGetTime() - q->timeStart;
  1143. }
  1144. }
  1145. //
  1146. // Set the first sample we will play, so we can time things properly
  1147. // This is the first thing in our queue, or the sample we're going to read next
  1148. // if it's empty.
  1149. //
  1150. void NEAR PASCAL qSetStartSample(LPQUEUE q)
  1151. {
  1152. q->sampleStart = qSample(q);
  1153. }
  1154. //
  1155. // Set the start time of the movie to the current time
  1156. //
  1157. void NEAR PASCAL qStartClock(LPQUEUE q)
  1158. {
  1159. q->timeStart = timeGetTime();
  1160. if (q->fccType == streamtypeAUDIO) {
  1161. MMTIME mmtime;
  1162. LONG timeDriver;
  1163. if (!((LPAUDIORENDER)q->lpRender)->hWaveOut) {
  1164. timeBase = timeDriver = -1;
  1165. DPF("AUDIO: Can't Start Clock");
  1166. return;
  1167. }
  1168. // un-pause the device
  1169. waveOutRestart(((LPAUDIORENDER)q->lpRender)->hWaveOut);
  1170. //
  1171. // Ask the wave driver how long it's been playing for
  1172. //
  1173. mmtime.wType = TIME_SAMPLES;
  1174. waveOutGetPosition(((LPAUDIORENDER)q->lpRender)->hWaveOut,
  1175. &mmtime, sizeof(mmtime));
  1176. if (mmtime.wType == TIME_SAMPLES)
  1177. timeDriver = AVIStreamSampleToTime(q->pavi, q->sampleStart) +
  1178. muldiv32(mmtime.u.sample, 1000,
  1179. ((LPWAVEFORMAT)q->lpfmtIn)->nSamplesPerSec);
  1180. else if (mmtime.wType == TIME_BYTES)
  1181. timeDriver = AVIStreamSampleToTime(q->pavi, q->sampleStart) +
  1182. muldiv32(mmtime.u.cb, 1000,
  1183. ((LPWAVEFORMAT)q->lpfmtIn)->nAvgBytesPerSec);
  1184. else
  1185. timeDriver = -1;
  1186. timeBase = timeDriver;
  1187. }
  1188. }
  1189. ///////////////////////////////////////////////////////////////////////////////
  1190. ///////////////////////////////////////////////////////////////////////////////
  1191. /////// Top layer q routines an application would call //////////////////
  1192. ///////////////////////////////////////////////////////////////////////////////
  1193. ///////////////////////////////////////////////////////////////////////////////
  1194. LPAVIQUEUE NEAR PASCAL QueueInit(PAVIFILE pfile)
  1195. {
  1196. PAVISTREAM pavi;
  1197. LPAVIQUEUE aviQ;
  1198. int i;
  1199. aviQ = (LPAVIQUEUE)GlobalAllocPtr(GMEM_MOVEABLE, sizeof(AVIQUEUE));
  1200. if (!aviQ)
  1201. return NULL;
  1202. for (i = 0; i < MAXNUMSTREAMS; i++) {
  1203. if (AVIFileGetStream(pfile, &pavi, 0L, i) != AVIERR_OK)
  1204. break;
  1205. aviQ->queue[i] = (LPQUEUE)GlobalAllocPtr(GMEM_MOVEABLE, sizeof(QUEUE));
  1206. if (!qInit(pavi, aviQ->queue[i]))
  1207. goto QIError;
  1208. }
  1209. aviQ->count = i;
  1210. if (i == 0)
  1211. return NULL;
  1212. return aviQ;
  1213. QIError:
  1214. for (--i; i >= 0; i--) {
  1215. if (aviQ->queue[i]) {
  1216. GlobalFreePtr(aviQ->queue[i]);
  1217. qFini(aviQ->queue[i]);
  1218. }
  1219. }
  1220. return NULL;
  1221. }
  1222. //
  1223. // Throw away all the queue stuff
  1224. //
  1225. void NEAR PASCAL QueueFini(LPAVIQUEUE q)
  1226. {
  1227. int i;
  1228. // Just tell each stream to seek there
  1229. for (i = 0; i < q->count; i++) {
  1230. qFini(q->queue[i]);
  1231. AVIStreamClose(q->queue[i]->pavi);
  1232. GlobalFreePtr(q->queue[i]);
  1233. }
  1234. GlobalFreePtr(q);
  1235. }
  1236. //
  1237. // Seek to a certain spot in the movie. We are given a TIME and convert it to
  1238. // a sample number for each stream. This is the point we'll start playing
  1239. // from, so remember this sample number.
  1240. //
  1241. void NEAR PASCAL QueueSeek(LPAVIQUEUE q, LONG time)
  1242. {
  1243. int i;
  1244. // Just tell each stream to seek there
  1245. for (i = 0; i < q->count; i++) {
  1246. qSeek(q->queue[i], AVIStreamTimeToSample(q->queue[i]->pavi, time));
  1247. qSetStartSample(q->queue[i]);
  1248. // FOR DPF ONLY
  1249. if (q->queue[i]->fccType == streamtypeVIDEO)
  1250. frStart = frPlayed = qPos(q->queue[i]);
  1251. }
  1252. }
  1253. //
  1254. // Prime all the queues -- (fill them up entirely)
  1255. //
  1256. void NEAR PASCAL QueuePrime(LPAVIQUEUE q)
  1257. {
  1258. int i;
  1259. // Prime each queue
  1260. for (i = 0; i < q->count; i++) {
  1261. qPrime(q->queue[i]);
  1262. }
  1263. }
  1264. //
  1265. // Get the time when the movie ends
  1266. //
  1267. LONG NEAR PASCAL QueueGetEndTime(LPAVIQUEUE q)
  1268. {
  1269. int i;
  1270. LONG time = 0;
  1271. // Ask each stream
  1272. for (i = 0; i < q->count; i++) {
  1273. time = max(time, AVIStreamEndTime(q->queue[i]->pavi));
  1274. }
  1275. return time;
  1276. }
  1277. //
  1278. // Get the decompressed video format that will be used to display this movie
  1279. // (use the first video stream found). If DRAWDIB is decompressing for us,
  1280. // we don't know it and will return some compressed format !!!
  1281. //
  1282. LPVOID NEAR PASCAL QueueGetVideoDisplayFormat(LPAVIQUEUE q)
  1283. {
  1284. int i;
  1285. // Ask each stream
  1286. for (i = 0; i < q->count; i++) {
  1287. if (q->queue[i]->fccType == streamtypeVIDEO)
  1288. return qFmt(q->queue[i]);
  1289. }
  1290. return NULL; // no video streams
  1291. }
  1292. //
  1293. // Prepare to render each stream. We are passed pointers to an array of
  1294. // hwnd's and rc's to use for the different video streams. Audio streams ignore
  1295. // those parameters.
  1296. // !!! Does audio need anything passed to it?
  1297. // !!! Return an error code? Abort on error? Continue anyway?
  1298. //
  1299. BOOL NEAR PASCAL QueueRenderInit(LPAVIQUEUE q, HWND FAR *phwnd, RECT FAR *prc)
  1300. {
  1301. int i, v = 0;
  1302. // Init each stream, give different parms to each video stream
  1303. for (i = 0; i < q->count; i++) {
  1304. qRenderInit(q->queue[i], *(phwnd + v), *(prc + v));
  1305. if (q->queue[i]->fccType == streamtypeVIDEO)
  1306. v++;
  1307. }
  1308. return TRUE;
  1309. }
  1310. //
  1311. // Finish up rendering.
  1312. //
  1313. void NEAR PASCAL QueueRenderFini(LPAVIQUEUE q)
  1314. {
  1315. int i;
  1316. // Tell each stream
  1317. for (i = 0; i < q->count; i++) {
  1318. qRenderFini(q->queue[i]);
  1319. }
  1320. }
  1321. //
  1322. // Inform the master queue what time it is. This should be called often.
  1323. //
  1324. void NEAR PASCAL QueueInformTime(LPAVIQUEUE q, LONG time)
  1325. {
  1326. int i;
  1327. // Just tell each stream what time it is
  1328. for (i = 0; i < q->count; i++) {
  1329. qInformTime(q->queue[i], time);
  1330. }
  1331. }
  1332. void NEAR PASCAL QueueStartClock(LPAVIQUEUE q)
  1333. {
  1334. int i;
  1335. // Set the play start time for each stream
  1336. for (i = 0; i < q->count; i++) {
  1337. qStartClock(q->queue[i]);
  1338. }
  1339. }
  1340. //
  1341. // Find out how many milliseconds since we started playing. Ask an AUDIO stream
  1342. // first, if there is one (they have priority). If not, ask a VIDEO stream.
  1343. // If not, ask any stream.
  1344. //
  1345. LONG NEAR PASCAL QueueNow(LPAVIQUEUE q)
  1346. {
  1347. int i;
  1348. for (i = 0; i < q->count; i++) {
  1349. if (q->queue[i]->fccType == streamtypeAUDIO)
  1350. return qNow(q->queue[i]);
  1351. }
  1352. for (i = 0; i < q->count; i++) {
  1353. if (q->queue[i]->fccType == streamtypeVIDEO)
  1354. return qNow(q->queue[i]);
  1355. }
  1356. return qNow(q->queue[0]);
  1357. }
  1358. BOOL NEAR PASCAL WinYield()
  1359. {
  1360. MSG msg;
  1361. BOOL fAbort=FALSE;
  1362. START(Yield);
  1363. DPF2("YIELDING...");
  1364. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1365. {
  1366. if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE)
  1367. fAbort = TRUE;
  1368. if (msg.message == WM_SYSCOMMAND && (msg.wParam & 0xFFF0) == SC_CLOSE)
  1369. fAbort = TRUE;
  1370. if (TranslateAccelerator(ghwndApp, ghAccel, &msg))
  1371. continue;
  1372. TranslateMessage(&msg);
  1373. DispatchMessage(&msg);
  1374. }
  1375. if (gfYieldBound)
  1376. Wait(YIELD_WAIT_TIME);
  1377. END(Yield);
  1378. return fAbort;
  1379. }
  1380. //
  1381. // should have function take :
  1382. //
  1383. // pavis[] and a count
  1384. // along with a "draw" proc () to render wierd custom streams
  1385. //
  1386. LONG FAR PASCAL aviPlay(HWND hwnd, PAVIFILE pfile, LONG movieStart)
  1387. {
  1388. extern UINT gwZoom;
  1389. LONG l = 0, movieEnd;
  1390. int iYield=0;
  1391. RECT rcFrame, rc;
  1392. LPBITMAPINFOHEADER lpbi;
  1393. HDC hdc;
  1394. // Clear these out, so we don't abort by mistake
  1395. GetAsyncKeyState(VK_ESCAPE);
  1396. GetAsyncKeyState(VK_RBUTTON);
  1397. fAudioBroke = TRUE;
  1398. // Init the queue and fill it up
  1399. if ((qAVI = QueueInit(pfile)) == NULL)
  1400. return movieStart; // error code?
  1401. QueueSeek(qAVI, movieStart); // decide where we'll start playing
  1402. QueuePrime(qAVI); // pre-stuff all the queues
  1403. // When does this AVI end?
  1404. movieEnd = QueueGetEndTime(qAVI);
  1405. GetClientRect(hwnd, &rc);
  1406. ////PatBlt(hdc, 0, 0, rc.right, rc.bottom, WHITENESS);
  1407. //
  1408. // Calculate the location to play the video based on its frame size
  1409. //
  1410. lpbi = (LPBITMAPINFOHEADER)QueueGetVideoDisplayFormat(qAVI);
  1411. rcFrame.left = rc.right / 2 -((int)lpbi->biWidth*gwZoom/4)/2;
  1412. rcFrame.top = 40; //!!! yStreamTop + TSPACE;
  1413. rcFrame.right = rcFrame.left + (int)lpbi->biWidth*gwZoom/4;
  1414. rcFrame.bottom = rcFrame.top + (int)lpbi->biHeight*gwZoom/4;
  1415. // Play the AVI in our window, centred.
  1416. // !!! This will die if > 1 video stream in a movie!
  1417. QueueRenderInit(qAVI, &hwnd, &rcFrame);
  1418. hdc = GetDC(hwnd);
  1419. if (WinYield()) // let palette change happen
  1420. // goto byebye;
  1421. // ProfBegin();
  1422. ZERO(Total);
  1423. ZERO(Other);
  1424. ZERO(Time);
  1425. ZERO(Key);
  1426. ZERO(Read);
  1427. ZERO(Copy);
  1428. ZERO(Draw);
  1429. ZERO(Audio);
  1430. ZERO(Decomp);
  1431. ZERO(Yield);
  1432. ZERO(Free);
  1433. // for DPF
  1434. Skip = Jump = Empty = Cheat = 0;
  1435. fAudioBroke = FALSE;
  1436. // Call just before main loop to set start time and waveBase hack
  1437. QueueStartClock(qAVI);
  1438. START(Total);
  1439. while (1) {
  1440. // We've been told to stop, so do so
  1441. // -1 means close after stopping
  1442. if (gfPlaying == 0 || gfPlaying == -1)
  1443. break;
  1444. // What time is it right now?
  1445. START(Time);
  1446. // What time in the movie are we at right now?
  1447. l = QueueNow(qAVI); // elapsed time since play start
  1448. END(Time);
  1449. DPF3("Time %ld", l);
  1450. // Ah! The movie is done!
  1451. if (l > movieEnd - movieStart)
  1452. break;
  1453. QueueInformTime(qAVI, l);
  1454. #ifdef DDEBUG
  1455. {
  1456. int i;
  1457. char ach[128];
  1458. i = wsprintfA(ach,
  1459. "Time %d.%02d S %d J %d E %d ",
  1460. (int)(l/1000), (int)(l%1000)/10,
  1461. Skip, Jump, Empty);
  1462. SetBkColor(hdc, RGB(255,255,255));
  1463. TextOutA(hdc, 0, 0, ach, i);
  1464. }
  1465. #endif
  1466. #ifdef DDEBUG // !!! move into a specific stream
  1467. #define W 16
  1468. #define H 16
  1469. i = qCount(q) * W;
  1470. FillR(hdc, 4, 20, i, H, RGB(255,255,0));
  1471. FillR(hdc, 4+i, 20, QSIZE*W-i, H, RGB(255,0,0));
  1472. i = (fr - qSample(q)) * W;
  1473. FillR(hdc, 4+i, 20, 1, H, RGB(0,0,0));
  1474. #endif
  1475. // Yield every once in a while. Always yielding makes performance
  1476. // plummet.
  1477. if ((++iYield % 8) == 0) {
  1478. if (WinYield())
  1479. break;
  1480. }
  1481. }
  1482. END(Total);
  1483. // ProfEnd();
  1484. timeOther =
  1485. timeTotal -
  1486. timeTime -
  1487. timeKey -
  1488. timeRead -
  1489. timeCopy -
  1490. timeDraw -
  1491. timeAudio -
  1492. timeDecomp -
  1493. timeYield;
  1494. byebye:
  1495. #ifdef PROFILE
  1496. DPF("***********************************************************");
  1497. if (fAudioBroke) { // braces necessary
  1498. DPF("****************** AUDIO BROKE!!! ************************");
  1499. }
  1500. DPF("Total Frames: %d", frPlayed - frStart + 1);
  1501. DPF("Frames skipped: %d", Skip);
  1502. DPF("Frames jumped: %d", Jump);
  1503. DPF("Total Frames missed: %d, (%d %%)", Skip + Jump, (int)(100l * (Skip + Jump) / (frPlayed - frStart + 1)));
  1504. DPF("Times cheated: %d", Cheat);
  1505. DPF("Times empty: %d", Empty);
  1506. #define SEC(x) SECA(x), SECB(x), (timeTotal ? (int)(time ## x * 100 / timeTotal) : 0)
  1507. #define SECA(x) (time ## x / 1000l) , (time ## x % 1000l)
  1508. #define SECB(x) (cnt ## x ? (time ## x / cnt ## x / 1000l) : 0l), (cnt ## x ? ((time ## x / cnt ## x) % 1000l) : 0l)
  1509. DPF(" timeTotal: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Total));
  1510. DPF(" timeOther: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Other));
  1511. DPF(" timeTime: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Time));
  1512. DPF(" timeKey: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Key));
  1513. DPF(" timeRead: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Read));
  1514. DPF(" timeCopy: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Copy));
  1515. DPF(" timeDraw: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Draw));
  1516. DPF(" timeAudio: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Audio));
  1517. DPF(" timeDecompress: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Decomp));
  1518. DPF(" timeYield: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Yield));
  1519. DPF("");
  1520. DPF(" timeFree: %3ld.%03ldsec (%3ld.%03ldsec) %d%%",SEC(Free));
  1521. DPF("***********************************************************");
  1522. #endif
  1523. ReleaseDC(hwnd, hdc);
  1524. QueueRenderFini(qAVI);
  1525. QueueFini(qAVI);
  1526. InvalidateRect(hwnd, NULL, TRUE); // we've hosed their DC
  1527. // Tell where the movie stopped
  1528. return movieStart + l;
  1529. }
  1530. void FAR PASCAL aviStop(void)
  1531. {
  1532. gfPlaying = 0;
  1533. }
  1534. LONG FAR PASCAL aviTime(void)
  1535. {
  1536. if (gfPlaying && qAVI)
  1537. return QueueNow(qAVI);
  1538. else
  1539. return -1;
  1540. }
  1541. /***************************************************************************
  1542. *
  1543. * @doc INTERNAL MCIAVI
  1544. *
  1545. * @api LPVOID | AllocMem | try to allocate DOS memory (< 1Mb)
  1546. *
  1547. * @parm DWORD | dw | size in bytes
  1548. *
  1549. ***************************************************************************/
  1550. static LPVOID AllocMem(DWORD dw)
  1551. {
  1552. #ifndef WIN32
  1553. /* Memory allocation internal routines */
  1554. extern DWORD FAR PASCAL GlobalDosAlloc(DWORD);
  1555. LPVOID p;
  1556. if (p = (LPVOID)MAKELONG(0, LOWORD(GlobalDosAlloc(dw))))
  1557. {
  1558. GlobalReAlloc((HANDLE)HIWORD((DWORD)p), 0, GMEM_MODIFY|GMEM_SHARE);
  1559. return p;
  1560. }
  1561. else
  1562. #endif
  1563. {
  1564. DPF("Couldn't get DOS Memory");
  1565. return GlobalLock(GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE, dw));
  1566. }
  1567. }
  1568. /*****************************************************************************
  1569. *
  1570. * dprintf() is called by the DPF macro if DEBUG is defined at compile time.
  1571. *
  1572. * The messages will be send to COM1: like any debug message. To
  1573. * enable debug output, add the following to WIN.INI :
  1574. *
  1575. * [debug]
  1576. * AVIView=1
  1577. *
  1578. ****************************************************************************/
  1579. #ifdef DEBUG
  1580. #define MODNAME "AVIView"
  1581. void FAR cdecl dprintf(LPSTR szFormat, ...)
  1582. {
  1583. char ach[128];
  1584. va_list va;
  1585. static BOOL fDebug = -1;
  1586. if (fDebug == -1)
  1587. fDebug = GetProfileIntA("Debug", MODNAME, FALSE);
  1588. if (!fDebug)
  1589. return;
  1590. lstrcpyA(ach, MODNAME ": ");
  1591. va_start(va, szFormat);
  1592. wvsprintfA(ach+lstrlenA(ach),szFormat, va);
  1593. va_end(va);
  1594. lstrcatA(ach, "\r\n");
  1595. OutputDebugStringA(ach);
  1596. }
  1597. #endif