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.

2507 lines
80 KiB

  1. /****************************************************************************
  2. *
  3. * capavi.c
  4. *
  5. * Main video capture module.
  6. *
  7. * Microsoft Video for Windows Sample Capture Class
  8. *
  9. * Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved.
  10. *
  11. * You have a royalty-free right to use, modify, reproduce and
  12. * distribute the Sample Files (and/or any modified version) in
  13. * any way you find useful, provided that you agree that
  14. * Microsoft has no warranty obligations or liability for any
  15. * Sample Application Files which are modified.
  16. *
  17. ***************************************************************************/
  18. #define INC_OLE2
  19. #pragma warning(disable:4103)
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <win32.h>
  23. #include <mmsystem.h>
  24. #include <msvideo.h>
  25. #include <drawdib.h>
  26. #include <mmreg.h>
  27. #include <mmddk.h>
  28. #include "ivideo32.h"
  29. #include "mmdebug.h"
  30. #ifdef USE_ACM
  31. #include <msacm.h>
  32. #endif
  33. #include <avifmt.h>
  34. #include "avicap.h"
  35. #include "avicapi.h"
  36. #include "time.h"
  37. #define JMK_HACK_TIMERS TRUE
  38. #ifdef JMK_HACK_TIMERS
  39. #define _INC_MMTIMERS_CODE_ TRUE
  40. #define CLIPBOARDLOGSIZE 1000
  41. #ifndef MAKEFOURCC
  42. #define MAKEFOURCC(a,b,c,d) ((DWORD)(a) | ((DWORD)(b) << 8) | ((DWORD)(c) << 16) | ((DWORD)(d) << 24))
  43. #endif
  44. #define RIFFTYPE(dw) (((dw & 0xFF) << 24) | ((dw & 0xFF00) << 8) | ((dw & 0xFF0000) >> 8) | ((dw & 0xFF000000) >> 24))
  45. #include "mmtimers.h"
  46. typedef struct _timerstuff {
  47. DWORD dwFrameTickTime; // What we think the current frame time should be
  48. DWORD dwFrameStampTime; // Stamped in the VIDEOHDR
  49. DWORD dwTimeWritten; // Time WriteFile called
  50. DWORD dwTimeToWrite; // Time WriteFile returned
  51. WORD nFramesAppended; // Accumulated appended dropped frames
  52. WORD nDummyFrames; // frames calc'ed as dropped
  53. DWORD dwVideoChunkCount; // current 'frame'
  54. WORD nAudioIndex; // next audio buffer
  55. WORD nVideoIndex; // next video buffer
  56. WORD bPending;
  57. WORD nSleepCount;
  58. DWORD dwSleepBegin;
  59. DWORD dwSleepEnd;
  60. };
  61. STATICDT PCTIMER pctWriteBase;
  62. STATICDT struct _timerstuff * pCurTimerStuff;
  63. STATICDT struct _timerstuff * pTimerStuff;
  64. STATICDT HGLOBAL hMemTimers;
  65. STATICDT struct _timerriff {
  66. FOURCC fccRIFF; // 'RIFF'
  67. DWORD cbTotal; // total (inclusive) size of riff data
  68. FOURCC fccJMKD; // 'JMKD' data type identifier
  69. DWORD fccVCHD; // 'VCHD' capture data header
  70. DWORD cbVCHD; // sizeof vchd data
  71. struct _vchd {
  72. DWORD nPrio;
  73. DWORD dwFramesCaptured;
  74. DWORD dwFramesDropped;
  75. DWORD dwDropFramesAppended;
  76. DWORD dwDropFramesNotAppended;
  77. DWORD dwTimerFrequency;
  78. DWORD dwSpare[2];
  79. CAPTUREPARMS cap;
  80. BITMAPINFOHEADER bmih;
  81. DWORD nMaxVideoBuffers;
  82. struct _thkvideohdr {
  83. VIDEOHDR vh;
  84. LPBYTE p32Buff;
  85. DWORD p16Alloc;
  86. DWORD dwMemHandle;
  87. DWORD dwReserved;
  88. } atvh[64];
  89. } vchd;
  90. DWORD fccChunk; // chunk data type tag
  91. DWORD cbChunk; // non-inclusive size of chunk data
  92. } * pTimerRiff;
  93. STATICDT UINT nTimerIndex;
  94. STATICDT UINT nSleepCount;
  95. #endif
  96. #ifdef _DEBUG
  97. #define DSTATUS(lpcs, sz) statusUpdateStatus(lpcs, IDS_CAP_INFO, (LPTSTR) TEXT(sz))
  98. #else
  99. #define DSTATUS(lpcs, sz)
  100. #endif
  101. // Allocate memory which can be page aligned
  102. LPVOID FAR PASCAL AllocSectorAlignedMem (DWORD dwRequest, DWORD dwAlign)
  103. {
  104. LPVOID pbuf;
  105. dwRequest = ROUNDUPTOSECTORSIZE (dwRequest, dwAlign) + dwAlign; // round up to next page boundary
  106. pbuf = VirtualAlloc (NULL, dwRequest,
  107. MEM_COMMIT | MEM_RESERVE,
  108. PAGE_READWRITE);
  109. AuxDebugEx(4, DEBUGLINE "Allocated %d bytes of sector aligned memory at %8x\r\n", dwRequest, pbuf);
  110. return pbuf;
  111. }
  112. void FAR PASCAL FreeSectorAlignedMem (LPVOID pbuf)
  113. {
  114. // the pointer we free had better be aligned on at least a 256 byte
  115. // boundary
  116. //
  117. assert (!((DWORD)pbuf & 255));
  118. (DWORD)pbuf &= ~255;
  119. VirtualFree (pbuf, 0, MEM_RELEASE);
  120. }
  121. #define ONEMEG (1024L * 1024L)
  122. DWORDLONG GetFreePhysicalMemory(void)
  123. {
  124. MEMORYSTATUSEX ms;
  125. ms.dwLength = sizeof(ms);
  126. GlobalMemoryStatusEx(&ms);
  127. if (ms.ullTotalPhys > 8L * ONEMEG)
  128. return ms.ullTotalPhys - ONEMEG * 4;
  129. return(ms.ullTotalPhys /2);
  130. }
  131. // ****************************************************************
  132. // ******************** Audio Buffer Control **********************
  133. // ****************************************************************
  134. // Audio buffers are always allocated under the presumption that
  135. // audio capture may be enabled at any time.
  136. // AVIAudioInit must be matched with AVIAudioFini (both only called once)
  137. // AVIAudioPrepare must be matched with AVIAudioUnPrepare
  138. // (which may be called multiple times to enable and disable audio)
  139. // AVI AudioInit - Allocate and initialize buffers for audio capture.
  140. // This routine is also used by MCI capture.
  141. // Returns: 0 on success, otherwise an error code.
  142. UINT AVIAudioInit (LPCAPSTREAM lpcs)
  143. {
  144. int i;
  145. LPVOID pHdr;
  146. LPVOID p;
  147. if (lpcs->sCapParms.wNumAudioRequested == 0)
  148. lpcs->sCapParms.wNumAudioRequested = DEF_WAVE_BUFFERS;
  149. // .5 second of audio per buffer (or 10K, whichever is larger)
  150. if (lpcs->sCapParms.dwAudioBufferSize == 0)
  151. lpcs->dwWaveSize = CalcWaveBufferSize (lpcs);
  152. else {
  153. lpcs->dwWaveSize = 0;
  154. if (lpcs->lpWaveFormat)
  155. lpcs->dwWaveSize = lpcs->sCapParms.dwAudioBufferSize;
  156. }
  157. // Alloc the wave memory
  158. for(i = 0; i < (int)lpcs->sCapParms.wNumAudioRequested; i++) {
  159. pHdr = GlobalAllocPtr(GPTR, sizeof(WAVEHDR));
  160. if (pHdr == NULL)
  161. break;
  162. lpcs->alpWaveHdr[i] = pHdr;
  163. p = AllocSectorAlignedMem( sizeof(RIFF) + lpcs->dwWaveSize, lpcs->dwBytesPerSector);
  164. if (p == NULL) {
  165. GlobalFreePtr (pHdr);
  166. lpcs->alpWaveHdr[i] = NULL;
  167. break;
  168. }
  169. lpcs->alpWaveHdr[i]->lpData = (LPBYTE)p + sizeof(RIFF);
  170. lpcs->alpWaveHdr[i]->dwBufferLength = lpcs->dwWaveSize;
  171. lpcs->alpWaveHdr[i]->dwBytesRecorded = 0;
  172. lpcs->alpWaveHdr[i]->dwUser = 0;
  173. lpcs->alpWaveHdr[i]->dwFlags = 0;
  174. lpcs->alpWaveHdr[i]->dwLoops = 0;
  175. ((LPRIFF)p)->dwType = MAKEAVICKID(cktypeWAVEbytes, 1);
  176. ((LPRIFF)p)->dwSize = lpcs->dwWaveSize;
  177. }
  178. lpcs->iNumAudio = i;
  179. return ((lpcs->iNumAudio == 0) ? IDS_CAP_WAVE_ALLOC_ERROR : 0);
  180. }
  181. //
  182. // AVI AudioFini - UnPrepares headers
  183. // This routine is also used by MCI capture.
  184. // Returns: 0 on success, otherwise an error code.
  185. UINT AVIAudioFini (LPCAPSTREAM lpcs)
  186. {
  187. int ii;
  188. /* free headers and data */
  189. for (ii=0; ii < MAX_WAVE_BUFFERS; ++ii) {
  190. if (lpcs->alpWaveHdr[ii]) {
  191. if (lpcs->alpWaveHdr[ii]->lpData)
  192. FreeSectorAlignedMem((LPBYTE)lpcs->alpWaveHdr[ii]->lpData - sizeof (RIFF));
  193. GlobalFreePtr(lpcs->alpWaveHdr[ii]);
  194. lpcs->alpWaveHdr[ii] = NULL;
  195. }
  196. }
  197. return 0;
  198. }
  199. //
  200. // AVI AudioPrepare - Opens the wave device and adds the buffers
  201. // Prepares headers and adds buffers to the device
  202. // This routine is also used by MCI capture.
  203. // Returns: 0 on success, otherwise an error code.
  204. UINT AVIAudioPrepare (LPCAPSTREAM lpcs)
  205. {
  206. UINT uiError;
  207. int ii;
  208. /* See if we can open that format for input */
  209. // register event callback to avoid polling
  210. uiError = waveInOpen(&lpcs->hWaveIn,
  211. WAVE_MAPPER, lpcs->lpWaveFormat,
  212. (DWORD) lpcs->hCaptureEvent, 0, CALLBACK_EVENT );
  213. if (uiError != MMSYSERR_NOERROR)
  214. return IDS_CAP_WAVE_OPEN_ERROR;
  215. lpcs->fAudioYield = FALSE; // ACM is separate thread, don't yield
  216. lpcs->fAudioBreak = FALSE;
  217. DPF("AudioYield = %d", lpcs->fAudioYield);
  218. for (ii = 0; ii < (int)lpcs->sCapParms.wNumAudioRequested; ++ii) {
  219. if (waveInPrepareHeader (lpcs->hWaveIn, lpcs->alpWaveHdr[ii],
  220. sizeof(WAVEHDR)))
  221. return IDS_CAP_WAVE_ALLOC_ERROR;
  222. if (waveInAddBuffer (lpcs->hWaveIn, lpcs->alpWaveHdr[ii],
  223. sizeof(WAVEHDR)))
  224. return IDS_CAP_WAVE_ALLOC_ERROR;
  225. AuxDebugEx(3, DEBUGLINE "Added wave buffer %d (%8x)\r\n", ii, lpcs->alpWaveHdr[ii]);
  226. }
  227. lpcs->iNextWave = 0; // current wave
  228. lpcs->dwWaveBytes = 0L; // number of wave bytes
  229. lpcs->dwWaveChunkCount = 0; // number of wave frames
  230. return 0;
  231. }
  232. //
  233. // AVI AudioUnPrepare - UnPrepares headers and closes the wave device.
  234. // This routine is also used by MCI capture.
  235. // Returns: 0 on success, otherwise an error code.
  236. UINT AVIAudioUnPrepare (LPCAPSTREAM lpcs)
  237. {
  238. int ii;
  239. if (lpcs->hWaveIn)
  240. {
  241. waveInReset(lpcs->hWaveIn);
  242. // unprepare any headers that have been prepared
  243. //
  244. for (ii=0; ii < lpcs->iNumAudio; ++ii)
  245. if (lpcs->alpWaveHdr[ii] &&
  246. (lpcs->alpWaveHdr[ii]->dwFlags & WHDR_PREPARED))
  247. waveInUnprepareHeader (lpcs->hWaveIn,
  248. lpcs->alpWaveHdr[ii],
  249. sizeof(WAVEHDR));
  250. waveInClose(lpcs->hWaveIn);
  251. lpcs->hWaveIn = NULL;
  252. }
  253. return 0;
  254. }
  255. // ****************************************************************
  256. // ******************** Video Buffer Control **********************
  257. // ****************************************************************
  258. // AVIVideoInit - Allocates, and initialize buffers for video capture.
  259. // This routine is also used by MCI capture.
  260. // Returns: 0 on success, otherwise an error code.
  261. #if defined CHICAGO
  262. UINT AVIVideoInit (LPCAPSTREAM lpcs)
  263. {
  264. UINT iMaxVideo;
  265. DWORD mmr;
  266. LPTHKVIDEOHDR ptvh;
  267. UINT ii;
  268. DWORD cbVideo;
  269. lpcs->iNumVideo = 0;
  270. lpcs->iNextVideo = 0;
  271. lpcs->dwVideoChunkCount = 0;
  272. lpcs->dwFramesDropped = 0;
  273. lpcs->fBuffersOnHardware = FALSE;
  274. // When performing MCI step capture, buffer array is not used
  275. if (lpcs->sCapParms.fStepMCIDevice)
  276. return 0;
  277. // If the user hasn't specified the number of video buffers to use,
  278. // assume the minimum
  279. if (lpcs->sCapParms.wNumVideoRequested == 0)
  280. lpcs->sCapParms.wNumVideoRequested = MIN_VIDEO_BUFFERS;
  281. cbVideo = ROUNDUPTOSECTORSIZE (lpcs->lpBitsInfo->bmiHeader.biSizeImage
  282. + sizeof(RIFF),
  283. lpcs->dwBytesPerSector)
  284. + lpcs->dwBytesPerSector;
  285. // use the number of video buffers that the user requested
  286. // or the maximum that will fit in memory.
  287. //
  288. iMaxVideo = min (MAX_VIDEO_BUFFERS, lpcs->sCapParms.wNumVideoRequested);
  289. if (iMaxVideo > 1)
  290. {
  291. DWORDLONG dwFreeMem;
  292. DWORDLONG dwUserRequests;
  293. DWORDLONG dwAudioMem;
  294. // How much actual free physical memory exists?
  295. dwFreeMem = GetFreePhysicalMemory();
  296. dwAudioMem = lpcs->dwWaveSize * lpcs->sCapParms.wNumAudioRequested;
  297. #define FOREVER_FREE 32768L // Always keep this free for swap space
  298. // How much memory will be used if we allocate per the request?
  299. //
  300. dwUserRequests = dwAudioMem
  301. + cbVideo * iMaxVideo
  302. + FOREVER_FREE;
  303. // If request is greater than available memory, force fewer buffers
  304. //
  305. if (dwUserRequests > dwFreeMem)
  306. {
  307. if (dwFreeMem > dwAudioMem)
  308. dwFreeMem -= dwAudioMem;
  309. iMaxVideo = (int)(((dwFreeMem * 8) / 10) / cbVideo);
  310. iMaxVideo = min (MAX_VIDEO_BUFFERS, iMaxVideo);
  311. dprintf("iMaxVideo = %d\n", iMaxVideo);
  312. }
  313. }
  314. mmr = vidxAllocHeaders(lpcs->hVideoIn, iMaxVideo, &ptvh);
  315. if (mmr != MMSYSERR_NOERROR)
  316. return IDS_CAP_VIDEO_ALLOC_ERROR;
  317. AuxDebugEx (3, DEBUGLINE "vidxAllocHdrs returned ptvh=%X\r\n", ptvh);
  318. AuxDebugDump (8, ptvh, sizeof(*ptvh) * iMaxVideo);
  319. for (ii = 0; ii < iMaxVideo; ++ii)
  320. {
  321. LPVIDEOHDR pvh = NULL;
  322. LPRIFF priff;
  323. // in chicago we let the thunk layer allocate memory
  324. // so that we can be assured that the memory can be easily
  325. // thunked.
  326. //
  327. // the pointer will be rounded up to a sector size boundary
  328. //
  329. mmr = vidxAllocBuffer (lpcs->hVideoIn, ii, &ptvh, cbVideo);
  330. if ((mmr != MMSYSERR_NOERROR) || (ptvh == NULL))
  331. break;
  332. lpcs->alpVideoHdr[ii] = pvh = &ptvh->vh;
  333. // vidxAllocBuffer actually returns a couple of extra fields
  334. // after the video header. the first of these holds the
  335. // linear address of the buffer.
  336. //
  337. priff = (LPVOID) ROUNDUPTOSECTORSIZE (ptvh->p32Buff, lpcs->dwBytesPerSector);
  338. #ifdef DEBUG
  339. {
  340. LPBYTE pb = (LPVOID)ptvh->p32Buff;
  341. AuxDebugEx (4, DEBUGLINE "buffer[%d] at %x linear. Doing touch test\r\n",
  342. ii, ptvh->p32Buff);
  343. pb[0] = 0;
  344. pb[cbVideo-1] = 0;
  345. }
  346. #endif
  347. // write the riff header for this chunk.
  348. //
  349. priff->dwType = MAKEAVICKID(cktypeDIBbits, 0);
  350. if (lpcs->lpBitsInfo->bmiHeader.biCompression == BI_RLE8)
  351. priff->dwType = MAKEAVICKID(cktypeDIBcompressed, 0);
  352. priff->dwSize = lpcs->lpBitsInfo->bmiHeader.biSizeImage;
  353. // init the video header
  354. //
  355. pvh->lpData = (LPVOID)(priff + 1);
  356. pvh->dwBufferLength = priff->dwSize;
  357. pvh->dwBytesUsed = 0;
  358. pvh->dwTimeCaptured = 0;
  359. pvh->dwUser = 0;
  360. pvh->dwFlags = 0;
  361. AuxDebugEx (4, DEBUGLINE "lpVideoHdr[%d]==%X\r\n", ii, lpcs->alpVideoHdr[ii]);
  362. AuxDebugDump (8, lpcs->alpVideoHdr[ii], sizeof(*ptvh));
  363. }
  364. lpcs->iNumVideo = ii;
  365. lpcs->cbVideoAllocation = cbVideo;
  366. dprintf("cbVideo = %ld \n", cbVideo);
  367. dprintf("iNumVideo Allocated = %d \n", lpcs->iNumVideo);
  368. return lpcs->iNumVideo ? 0 : IDS_CAP_VIDEO_ALLOC_ERROR;
  369. }
  370. //
  371. // AVIVideoPrepare - Prepares headers and adds buffers to the device
  372. // This routine is also used by MCI capture.
  373. // Returns: 0 on success, otherwise an error code.
  374. UINT AVIVideoPrepare (LPCAPSTREAM lpcs)
  375. {
  376. int ii;
  377. // When performing MCI step capture, buffer array is not used
  378. if (lpcs->sCapParms.fStepMCIDevice)
  379. return 0;
  380. #ifdef JMK_HACK_CHECKHDR
  381. {
  382. LPTHKVIDEOHDR lptvh = (LPVOID)lpcs->alpVideoHdr[0];
  383. if (HIWORD(lptvh->vh.lpData) != HIWORD(lptvh->p32Buff))
  384. {
  385. AuxDebugEx (0, DEBUGLINE "before stream init: hdr trouble\r\n");
  386. AuxDebugEx (0, DEBUGLINE "iNext=%d, ptvh=%X\r\n", lpcs->iNextVideo, lptvh);
  387. AuxDebugDump (0, lptvh, sizeof(*lptvh));
  388. AuxDebugEx (0, DEBUGLINE "alpVideoHdrs=%X\r\n", lpcs->alpVideoHdr);
  389. AuxDebugDump (0, lpcs->alpVideoHdr, sizeof(lpcs->alpVideoHdr[0]) * 8);
  390. INLINE_BREAK;
  391. return IDS_CAP_VIDEO_OPEN_ERROR;
  392. }
  393. }
  394. #endif
  395. // Open the video stream, setting the capture rate
  396. //
  397. if (videoStreamInit(lpcs->hVideoIn,
  398. lpcs->sCapParms.dwRequestMicroSecPerFrame,
  399. lpcs->hRing0CapEvt,
  400. 0,
  401. CALLBACK_EVENT))
  402. {
  403. dprintf("cant open video device!\n");
  404. return IDS_CAP_VIDEO_OPEN_ERROR;
  405. }
  406. #ifdef JMK_HACK_CHECKHDR
  407. {
  408. LPTHKVIDEOHDR lptvh = (LPVOID)lpcs->alpVideoHdr[0];
  409. if (HIWORD(lptvh->vh.lpData) != HIWORD(lptvh->p32Buff))
  410. {
  411. AuxDebugEx (0, DEBUGLINE "after stream init: hdr trouble\r\n");
  412. AuxDebugEx (0, DEBUGLINE "iNext=%d, ptvh=%X\r\n", lpcs->iNextVideo, lptvh);
  413. AuxDebugDump (0, lptvh, sizeof(*lptvh));
  414. AuxDebugEx (0, DEBUGLINE "alpVideoHdrs=%X\r\n", lpcs->alpVideoHdr);
  415. AuxDebugDump (0, lpcs->alpVideoHdr, sizeof(lpcs->alpVideoHdr[0]) * 8);
  416. INLINE_BREAK;
  417. return IDS_CAP_VIDEO_OPEN_ERROR;
  418. }
  419. }
  420. #endif
  421. // Prepare (lock) the buffers, and give them to the device
  422. //
  423. for (ii = 0; ii < lpcs->iNumVideo; ++ii)
  424. {
  425. if (vidxAddBuffer (lpcs->hVideoIn,
  426. lpcs->alpVideoHdr[ii],
  427. sizeof(VIDEOHDR)))
  428. {
  429. lpcs->iNumVideo = ii;
  430. dprintf("**** could only prepare %d Video buffers!\n", lpcs->iNumVideo);
  431. break;
  432. }
  433. }
  434. #ifdef JMK_HACK_CHECKHDR
  435. {
  436. LPTHKVIDEOHDR lptvh = (LPVOID)lpcs->alpVideoHdr[0];
  437. if (IsBadWritePtr (lptvh, sizeof(*lptvh)) ||
  438. HIWORD(lptvh->vh.lpData) != HIWORD(lptvh->p16Alloc))
  439. {
  440. AuxDebugEx (0, DEBUGLINE "after add buffers: hdr trouble\r\n");
  441. AuxDebugEx (0, DEBUGLINE "iNext=%d, ptvh=%X\r\n", lpcs->iNextVideo, lptvh);
  442. AuxDebugDump (0, lptvh, sizeof(*lptvh));
  443. AuxDebugEx (0, DEBUGLINE "alpVideoHdrs=%X\r\n", lpcs->alpVideoHdr);
  444. AuxDebugDump (0, lpcs->alpVideoHdr, sizeof(lpcs->alpVideoHdr[0]) * 8);
  445. INLINE_BREAK;
  446. return IDS_CAP_VIDEO_OPEN_ERROR;
  447. }
  448. }
  449. #endif
  450. return 0;
  451. }
  452. #else // code below is !CHICAGO
  453. // this structure is used to keep track of memory allocation
  454. // for video buffers used in capture. it is allocated when
  455. // allocating a videohdr would be called for
  456. //
  457. typedef struct _cap_videohdr {
  458. VIDEOHDR vh;
  459. LPBYTE pAlloc; // address of allocated buffer
  460. DWORD dwMemIdent; // identity of allocation (used in Chicago)
  461. DWORD dwReserved; // used in chicago
  462. BOOL bHwBuffer; // TRUE if buffer is allocated using videoStreamAllocBuffer
  463. } CAPVIDEOHDR, FAR *LPCAPVIDEOHDR;
  464. // AVIVideoInit - Allocates, and initialize buffers for video capture.
  465. // This routine is also used by MCI capture.
  466. // Returns: 0 on success, otherwise an error code.
  467. UINT AVIVideoInit (LPCAPSTREAM lpcs)
  468. {
  469. int iMaxVideo;
  470. int ii;
  471. LPCAPVIDEOHDR pcvh;
  472. LPVOID pbuf;
  473. DWORD cbVideo;
  474. lpcs->iNumVideo = 0;
  475. lpcs->iNextVideo = 0;
  476. lpcs->dwVideoChunkCount = 0;
  477. lpcs->dwFramesDropped = 0;
  478. lpcs->fBuffersOnHardware = FALSE;
  479. // When performing MCI step capture, buffer array is not used
  480. if (lpcs->sCapParms.fStepMCIDevice)
  481. return 0;
  482. // If the user hasn't specified the number of video buffers to use,
  483. // assume the minimum
  484. if (lpcs->sCapParms.wNumVideoRequested == 0)
  485. lpcs->sCapParms.wNumVideoRequested = MIN_VIDEO_BUFFERS;
  486. cbVideo = ROUNDUPTOSECTORSIZE (lpcs->lpBitsInfo->bmiHeader.biSizeImage
  487. + sizeof(RIFF),
  488. lpcs->dwBytesPerSector)
  489. + lpcs->dwBytesPerSector;
  490. // use the number of video buffers that the user requested
  491. // or the maximum array size in CAPSTREAM
  492. //
  493. iMaxVideo = min (MAX_VIDEO_BUFFERS, lpcs->sCapParms.wNumVideoRequested);
  494. // Post VFW 1.1a, see if the driver can allocate memory
  495. //
  496. #ifdef ALLOW_HW_BUFFERS
  497. if (videoStreamAllocBuffer (lpcs->hVideoIn, (LPVOID *) &pbuf, cbVideo)
  498. == DV_ERR_OK)
  499. {
  500. lpcs->fBuffersOnHardware = TRUE;
  501. videoStreamFreeBuffer (lpcs->hVideoIn, pbuf);
  502. }
  503. else
  504. #endif
  505. {
  506. DWORDLONG dwFreeMem;
  507. DWORDLONG dwUserRequests;
  508. DWORDLONG dwAudioMem;
  509. lpcs->fBuffersOnHardware = FALSE;
  510. // How much actual free physical memory exists?
  511. dwFreeMem = GetFreePhysicalMemory();
  512. dwAudioMem = lpcs->dwWaveSize * lpcs->sCapParms.wNumAudioRequested;
  513. #define FOREVER_FREE 32768L // Always keep this free for swap space
  514. // How much memory will be used if we allocate per the request?
  515. //
  516. dwUserRequests = dwAudioMem
  517. + cbVideo * iMaxVideo
  518. + FOREVER_FREE;
  519. // If request is greater than available memory, force fewer buffers
  520. //
  521. if (dwUserRequests > dwFreeMem)
  522. {
  523. if (dwFreeMem > dwAudioMem)
  524. dwFreeMem -= dwAudioMem;
  525. iMaxVideo = (int)(((dwFreeMem * 8) / 10) / cbVideo);
  526. iMaxVideo = min (MAX_VIDEO_BUFFERS, iMaxVideo);
  527. dprintf("iMaxVideo = %d\n", iMaxVideo);
  528. }
  529. }
  530. pcvh = GlobalAllocPtr (GMEM_MOVEABLE, iMaxVideo * sizeof(CAPVIDEOHDR));
  531. // note: pcvh is freed by referencing through alpVideoHdr[0]
  532. if ( ! pcvh)
  533. return IDS_CAP_VIDEO_ALLOC_ERROR;
  534. AuxDebugEx (3, DEBUGLINE "allocated video headers pcvh=%X\r\n", pcvh);
  535. // Set up the buffers presuming fixed size DIBs and Junk chunks
  536. // These will be modified later if the device provides compressed data
  537. for (ii = 0; ii < iMaxVideo; ++ii)
  538. {
  539. LPVIDEOHDR pvh = NULL;
  540. LPRIFF priff;
  541. #ifdef ALLOW_HW_BUFFERS
  542. //
  543. // for the first buffer, always try to allocate on hardware,
  544. // if that fails, grab virtual memory for the buffer.
  545. // for all but the first buffer, we use whatever worked for
  546. // the first buffer, and if that fails. we stop allocating buffers
  547. //
  548. if ((0 == ii) || lpcs->fBuffersOnHardware)
  549. {
  550. pbuf = NULL;
  551. mmr = videoStreamAllocBuffer (lpcs->hVideoIn, (LPVOID) &pbuf, cbVideo);
  552. if ((mmr != MMSYSERR_NOERROR) || (pbuf == NULL))
  553. {
  554. if (0 == ii)
  555. break;
  556. lpcs->fBuffersOnHardware = FALSE;
  557. pbuf = AllocSectorAlignedMem (cbVideo, lpcs->dwBytesPerSector);
  558. }
  559. else
  560. lpcs->fBuffersOnHardware = TRUE;
  561. }
  562. else
  563. pbuf = AllocSectorAlignedMem (cbVideo, lpcs->dwBytesPerSector);
  564. #else ! dont allow hw buffers
  565. pbuf = AllocSectorAlignedMem (cbVideo, lpcs->dwBytesPerSector);
  566. #endif // ALLOW_HW_BUFFERS
  567. if (pbuf == NULL)
  568. break;
  569. // save the original allocation pointer to the buffer
  570. // in the extra fields of the capture header. also remember
  571. // whether we got the buffer from the driver or not
  572. //
  573. pcvh[ii].pAlloc = pbuf;
  574. pcvh[ii].bHwBuffer = lpcs->fBuffersOnHardware;
  575. lpcs->alpVideoHdr[ii] = pvh = &pcvh[ii].vh;
  576. priff = (LPVOID) ROUNDUPTOSECTORSIZE (pbuf, lpcs->dwBytesPerSector);
  577. // write the riff header for this frame
  578. //
  579. priff->dwType = MAKEAVICKID(cktypeDIBbits, 0);
  580. if (lpcs->lpBitsInfo->bmiHeader.biCompression == BI_RLE8)
  581. priff->dwType = MAKEAVICKID(cktypeDIBcompressed, 0);
  582. priff->dwSize = lpcs->lpBitsInfo->bmiHeader.biSizeImage;
  583. // fill in the video hdr for this frame
  584. //
  585. pvh->lpData = (LPVOID)(priff + 1);
  586. pvh->dwBufferLength = priff->dwSize;
  587. pvh->dwBytesUsed = 0;
  588. pvh->dwTimeCaptured = 0;
  589. pvh->dwUser = 0;
  590. pvh->dwFlags = 0;
  591. AuxDebugEx (4, DEBUGLINE "lpVideoHdr[%d]==%X\r\n", ii, lpcs->alpVideoHdr[ii]);
  592. AuxDebugDump (8, lpcs->alpVideoHdr[ii], sizeof(*pcvh));
  593. }
  594. lpcs->iNumVideo = ii;
  595. lpcs->cbVideoAllocation = cbVideo;
  596. // if we did not create even a single buffer, free the headers
  597. //
  598. if ( ! lpcs->iNumVideo)
  599. GlobalFreePtr (pcvh);
  600. #ifdef ALLOW_HW_BUFFERS
  601. if (lpcs->fBuffersOnHardware)
  602. dprintf("HARDWARE iNumVideo Allocated = %d \n", lpcs->iNumVideo);
  603. else
  604. #endif
  605. dprintf("HIGH iNumVideo Allocated = %d \n", lpcs->iNumVideo);
  606. return lpcs->iNumVideo ? 0 : IDS_CAP_VIDEO_ALLOC_ERROR;
  607. }
  608. void CALLBACK
  609. VideoCallback(
  610. HVIDEO hvideo,
  611. UINT msg,
  612. DWORD dwInstance,
  613. DWORD lParam1,
  614. DWORD lParam2
  615. )
  616. {
  617. LPCAPSTREAM lpcs = (LPCAPSTREAM) dwInstance;
  618. if (lpcs && lpcs->hCaptureEvent) {
  619. SetEvent(lpcs->hCaptureEvent);
  620. } else {
  621. AuxDebugEx(1, DEBUGLINE "VideoCallback with NO instance data\r\n");
  622. }
  623. }
  624. //
  625. // AVIVideoPrepare - Prepares headers and adds buffers to the device
  626. // This routine is also used by MCI capture.
  627. // Returns: 0 on success, otherwise an error code.
  628. UINT AVIVideoPrepare (LPCAPSTREAM lpcs)
  629. {
  630. MMRESULT mmr;
  631. int ii;
  632. // When performing MCI step capture, buffer array is not used
  633. //
  634. if (lpcs->sCapParms.fStepMCIDevice)
  635. return 0;
  636. // Open the video stream, setting the capture rate
  637. //
  638. mmr = videoStreamInit (lpcs->hVideoIn,
  639. lpcs->sCapParms.dwRequestMicroSecPerFrame,
  640. (DWORD) VideoCallback,
  641. (DWORD) lpcs,
  642. CALLBACK_FUNCTION);
  643. if (mmr) {
  644. dprintf("cannot open video device! Error is %d\n", mmr);
  645. return IDS_CAP_VIDEO_OPEN_ERROR;
  646. }
  647. // Prepare (lock) the buffers, and give them to the device
  648. //
  649. for (ii = 0; ii < lpcs->iNumVideo; ++ii)
  650. {
  651. mmr = videoStreamPrepareHeader (lpcs->hVideoIn,
  652. lpcs->alpVideoHdr[ii],
  653. sizeof(VIDEOHDR));
  654. if (mmr)
  655. {
  656. lpcs->iNumVideo = ii;
  657. dprintf("**** could only prepare %d Video!\n", lpcs->iNumVideo);
  658. break;
  659. }
  660. mmr = videoStreamAddBuffer (lpcs->hVideoIn,
  661. lpcs->alpVideoHdr[ii],
  662. sizeof(VIDEOHDR));
  663. if (mmr)
  664. return IDS_CAP_VIDEO_ALLOC_ERROR;
  665. AuxDebugEx(3, DEBUGLINE "Added video buffer %d (%8x)\r\n", ii, lpcs->alpVideoHdr[ii]);
  666. }
  667. return 0;
  668. }
  669. #endif // not chicago
  670. //
  671. // AVI VideoUnPrepare - UnPrepares headers, frees memory, and
  672. // resets the video in device.
  673. // This routine is also used by MCI capture.
  674. // Returns: 0 on success, otherwise an error code.
  675. UINT AVIVideoUnPrepare (LPCAPSTREAM lpcs)
  676. {
  677. // When performing MCI step capture, buffer array is not used
  678. //
  679. if (lpcs->sCapParms.fStepMCIDevice)
  680. return 0;
  681. // Reset the buffers so they can be freed
  682. //
  683. if (lpcs->hVideoIn) {
  684. videoStreamReset(lpcs->hVideoIn);
  685. // unprepare headers
  686. // Unlock and free headers and data
  687. #if defined CHICAGO
  688. vidxFreeHeaders (lpcs->hVideoIn);
  689. ZeroMemory (lpcs->alpVideoHdr, sizeof(lpcs->alpVideoHdr));
  690. #else
  691. {
  692. int ii;
  693. LPCAPVIDEOHDR pcvhAll = (LPVOID)lpcs->alpVideoHdr[0];
  694. for (ii = 0; ii < lpcs->iNumVideo; ++ii)
  695. {
  696. LPCAPVIDEOHDR pcvh = (LPVOID)lpcs->alpVideoHdr[ii];
  697. if (pcvh)
  698. {
  699. if (pcvh->vh.dwFlags & VHDR_PREPARED)
  700. videoStreamUnprepareHeader (lpcs->hVideoIn,
  701. &pcvh->vh,
  702. sizeof(VIDEOHDR));
  703. #ifdef ALLOW_HW_BUFFERS
  704. if (pcvh->bHwBuffer)
  705. {
  706. if (pcvh->pAlloc)
  707. videoStreamFreeBuffer (lpcs->hVideoIn, (LPVOID)pcvh->pAlloc);
  708. }
  709. else
  710. #endif
  711. {
  712. if (pcvh->pAlloc)
  713. FreeSectorAlignedMem (pcvh->pAlloc);
  714. }
  715. lpcs->alpVideoHdr[ii] = NULL;
  716. }
  717. }
  718. // free the array of video headers
  719. //
  720. if (pcvhAll)
  721. GlobalFreePtr (pcvhAll);
  722. }
  723. #endif
  724. // Shut down the video stream
  725. videoStreamFini(lpcs->hVideoIn);
  726. }
  727. return 0;
  728. }
  729. /*
  730. * AVI Fini - undo the mess that AVIInit did.
  731. *
  732. */
  733. void AVIFini(LPCAPSTREAM lpcs)
  734. {
  735. AuxDebugEx (2, "AVIFini(%08x)\r\n", lpcs);
  736. if (lpcs->lpDropFrame) {
  737. FreeSectorAlignedMem (lpcs->lpDropFrame), lpcs->lpDropFrame = NULL;
  738. }
  739. AVIVideoUnPrepare (lpcs); // Free the video device and buffers
  740. AVIAudioUnPrepare (lpcs); // Free the audio device
  741. AVIAudioFini (lpcs); // Free the audio buffers
  742. if (lpcs->hCaptureEvent) {
  743. CloseHandle (lpcs->hCaptureEvent), lpcs->hCaptureEvent = NULL;
  744. }
  745. AuxDebugEx (2, "AVIFini(...) exits\r\n");
  746. }
  747. //
  748. // AVI Init
  749. // This routine does all the non-File initalization for AVICapture.
  750. // Returns: 0 on success, Error string value on failure.
  751. //
  752. UINT AVIInit (LPCAPSTREAM lpcs)
  753. {
  754. UINT wError = 0; // Success
  755. LPBITMAPINFO lpBitsInfoOut; // Possibly compressed output format
  756. // Allocate a DropFrame buffer
  757. if (lpcs->lpDropFrame == NULL) {
  758. assert (lpcs->dwBytesPerSector);
  759. lpcs->lpDropFrame = AllocSectorAlignedMem (lpcs->dwBytesPerSector, lpcs->dwBytesPerSector);
  760. }
  761. /* No special video format given -- use the default */
  762. #ifdef NEW_COMPMAN
  763. if (lpcs->CompVars.hic == NULL)
  764. lpBitsInfoOut = lpcs->lpBitsInfo;
  765. else
  766. lpBitsInfoOut = lpcs->CompVars.lpbiOut;
  767. #else
  768. lpBitsInfoOut = lpcs->lpBitsInfo;
  769. #endif
  770. // -------------------------------------------------------
  771. // figure out buffer sizes
  772. // -------------------------------------------------------
  773. // Init all pointers to NULL
  774. ZeroMemory (lpcs->alpVideoHdr, sizeof(lpcs->alpVideoHdr));
  775. ZeroMemory (lpcs->alpWaveHdr, sizeof(lpcs->alpWaveHdr));
  776. // -------------------------------------------------------
  777. // Init Sound
  778. // -------------------------------------------------------
  779. if (lpcs->sCapParms.fCaptureAudio) {
  780. if (wError = AVIAudioInit (lpcs)) {
  781. dprintf("can't init audio buffers!\n");
  782. goto AVIInitFailed;
  783. }
  784. }
  785. // -------------------------------------------------------
  786. // Init Video
  787. // -------------------------------------------------------
  788. if (wError = AVIVideoInit (lpcs)) {
  789. dprintf("AVIVideoInitFailed (no buffers alloc'd)!\n");
  790. goto AVIInitFailed;
  791. }
  792. // --------------------------------------------------------------
  793. // Prepare audio buffers (lock em down) and give them to the device
  794. // --------------------------------------------------------------
  795. if (lpcs->sCapParms.fCaptureAudio) {
  796. if (wError = AVIAudioPrepare (lpcs)) {
  797. dprintf("can't prepare audio buffers!\n");
  798. goto AVIInitFailed;
  799. }
  800. }
  801. // --------------------------------------------------------------
  802. // Prepare video buffers (lock em down) and give them to the device
  803. // --------------------------------------------------------------
  804. if (wError = AVIVideoPrepare (lpcs)) {
  805. dprintf("can't prepare video buffers!\n");
  806. goto AVIInitFailed;
  807. }
  808. // -------------------------------------------------------
  809. // all done, return success
  810. // -------------------------------------------------------
  811. return (0); // SUCCESS !
  812. // -------------------------------------------------------
  813. // we got a error, return string ID of error message
  814. // -------------------------------------------------------
  815. AVIInitFailed:
  816. AVIFini(lpcs); // Shutdown everything
  817. return wError;
  818. }
  819. // Maintains info chunks which are written to the AVI header
  820. //
  821. BOOL FAR PASCAL SetInfoChunk(LPCAPSTREAM lpcs, LPCAPINFOCHUNK lpcic)
  822. {
  823. DWORD ckid = lpcic->fccInfoID;
  824. LPVOID lpData = lpcic->lpData;
  825. LONG cbData = lpcic->cbData;
  826. LPBYTE lp;
  827. LPBYTE lpw;
  828. LPBYTE lpEnd;
  829. LPBYTE lpNext;
  830. LONG cbSizeThis;
  831. BOOL fOK = FALSE;
  832. // Delete all info chunks?
  833. if (ckid == 0) {
  834. if (lpcs->lpInfoChunks) {
  835. GlobalFreePtr (lpcs->lpInfoChunks);
  836. lpcs->lpInfoChunks = NULL;
  837. lpcs->cbInfoChunks = 0;
  838. }
  839. return TRUE;
  840. }
  841. // Try removing an entry if it already exists...
  842. // Also used if lpData is NULL to just remove an entry
  843. //
  844. lpw = (LPBYTE)lpcs->lpInfoChunks; // always points at fcc
  845. lpEnd = (LPBYTE)lpcs->lpInfoChunks + lpcs->cbInfoChunks;
  846. while (lpw < lpEnd) {
  847. cbSizeThis = ((DWORD UNALIGNED FAR *)lpw)[1];
  848. cbSizeThis += cbSizeThis & 1; // force WORD (16 bit) alignment
  849. lpNext = lpw + cbSizeThis + sizeof (DWORD) * 2;
  850. if ((*(DWORD UNALIGNED FAR *) lpw) == ckid) {
  851. lpcs->cbInfoChunks -= cbSizeThis + sizeof (DWORD) * 2;
  852. if (lpNext <= lpEnd) {
  853. if (lpEnd - lpNext)
  854. CopyMemory (lpw, lpNext, lpEnd - lpNext);
  855. if (lpcs->cbInfoChunks) {
  856. lpcs->lpInfoChunks = (LPBYTE) GlobalReAllocPtr( // shrink it
  857. lpcs->lpInfoChunks,
  858. lpcs->cbInfoChunks,
  859. GMEM_MOVEABLE);
  860. }
  861. else {
  862. if (lpcs->lpInfoChunks)
  863. GlobalFreePtr (lpcs->lpInfoChunks);
  864. lpcs->lpInfoChunks = NULL;
  865. }
  866. fOK = TRUE;
  867. }
  868. break;
  869. }
  870. else
  871. lpw = lpNext;
  872. }
  873. if (lpData == NULL || cbData == 0) // Only deleting, get out
  874. return fOK;
  875. // Add a new entry
  876. cbData += cbData & 1; // force WORD (16 bit) alignment
  877. cbData += sizeof(RIFF); // add sizeof RIFF
  878. if (lpcs->lpInfoChunks)
  879. lp = GlobalReAllocPtr(lpcs->lpInfoChunks, lpcs->cbInfoChunks + cbData, GMEM_MOVEABLE);
  880. else
  881. lp = GlobalAllocPtr(GMEM_MOVEABLE, cbData);
  882. if (!lp)
  883. return FALSE;
  884. // build RIFF chunk in block
  885. //
  886. ((LPRIFF)(lp + lpcs->cbInfoChunks))->dwType = ckid;
  887. ((LPRIFF)(lp + lpcs->cbInfoChunks))->dwSize = lpcic->cbData;
  888. CopyMemory (lp + lpcs->cbInfoChunks + sizeof(RIFF),
  889. lpData,
  890. cbData - sizeof(RIFF));
  891. lpcs->lpInfoChunks = lp;
  892. lpcs->cbInfoChunks += cbData;
  893. return TRUE;
  894. }
  895. /*+ ProcessNextVideoBuffer
  896. *
  897. *-===============================================================*/
  898. STATICFN BOOL _inline ProcessNextVideoBuffer (
  899. LPCAPSTREAM lpcs,
  900. BOOL fStopping,
  901. LPUINT lpuError,
  902. LPVIDEOHDR * plpvhDraw,
  903. LPBOOL lpbPending)
  904. {
  905. LPVIDEOHDR lpvh;
  906. *lpuError = 0;
  907. *plpvhDraw = NULL;
  908. *lpbPending = FALSE;
  909. lpvh = lpcs->alpVideoHdr[lpcs->iNextVideo];
  910. if (!(lpvh->dwFlags & VHDR_DONE)) {
  911. return fStopping;
  912. }
  913. #if defined CHICAGO
  914. {
  915. LPTHKVIDEOHDR lptvh = (LPVOID)lpvh;
  916. #ifdef JMK_HACK_CHECKHDR
  917. if (IsBadWritePtr (lptvh, sizeof(*lptvh)) ||
  918. HIWORD(lptvh->vh.lpData) != HIWORD(lptvh->p16Alloc))
  919. {
  920. OutputDebugStringA(DEBUGLINE "trouble with video hdr\r\n");
  921. AuxDebugEx (0, DEBUGLINE "iNext=%d, ptvh=%X\r\n", lpcs->iNextVideo, lptvh);
  922. AuxDebugDump (0, lptvh, sizeof(*lptvh));
  923. AuxDebugEx (0, DEBUGLINE "alpVideoHdrs=%X\r\n", lpcs->alpVideoHdr);
  924. AuxDebugDump (0, lpcs->alpVideoHdr, sizeof(lpcs->alpVideoHdr[0]) * 8);
  925. INLINE_BREAK;
  926. return TRUE;
  927. }
  928. #endif
  929. // Swap the linear pointer back (was swapped in vidxAddBuffer)
  930. //
  931. lptvh->vh.lpData = (LPVOID)(ROUNDUPTOSECTORSIZE(lptvh->p32Buff, lpcs->dwBytesPerSector) + sizeof(RIFF));
  932. }
  933. #endif
  934. if (lpvh->dwBytesUsed)
  935. {
  936. DWORD dwTime;
  937. DWORD dwBytesUsed = lpvh->dwBytesUsed;
  938. BOOL fKeyFrame = lpvh->dwFlags & VHDR_KEYFRAME;
  939. LPVOID lpData = lpvh->lpData;
  940. // get expected time for this frame in milliseconds
  941. //
  942. dwTime = MulDiv (lpcs->dwVideoChunkCount + 1,
  943. lpcs->sCapParms.dwRequestMicroSecPerFrame,
  944. 1000);
  945. #ifdef NEW_COMPMAN
  946. //
  947. // We are automatically compressing during capture, so
  948. // compress the frame before we pass it on to be written
  949. //
  950. if (lpcs->CompVars.hic)
  951. {
  952. LPRIFF priff;
  953. dwBytesUsed = 0;
  954. lpData = ICSeqCompressFrame(&lpcs->CompVars, 0,
  955. lpvh->lpData,
  956. &fKeyFrame,
  957. &dwBytesUsed);
  958. priff = ((LPRIFF)lpData) -1;
  959. priff->dwType = MAKEAVICKID(cktypeDIBbits, 0);
  960. priff->dwSize = dwBytesUsed;
  961. }
  962. #endif // NEW_COMPMAN
  963. // do video stream callback for this frame
  964. //
  965. if (lpcs->CallbackOnVideoStream)
  966. lpcs->CallbackOnVideoStream (lpcs->hwnd, lpvh);
  967. lpvh->dwFlags &= ~VHDR_DONE;
  968. // if we are not capturing to disk, just increment
  969. // the 'chunk count' (i.e. frame count?) and go on
  970. // otherwise we want to queue the frame up to write
  971. // here
  972. //
  973. if ( ! (lpcs->fCaptureFlags & CAP_fCapturingToDisk))
  974. {
  975. // Warning: Kludge to create frame chunk count when net capture
  976. // follows.
  977. ++lpcs->dwVideoChunkCount;
  978. }
  979. else
  980. {
  981. int nAppendDummyFrames = 0;
  982. // if the expected time for this frame is less than the
  983. // timestamp for the frame. we may have dropped some frames
  984. // before this frame.
  985. //
  986. if (lpcs->dwVideoChunkCount && (dwTime < lpvh->dwTimeCaptured))
  987. {
  988. int nDropCount;
  989. BOOL bPending;
  990. // calculate how many frames have been dropped.
  991. // NOTE: this number may be zero if dwTimeCaptured is just
  992. // a little bit late.
  993. //
  994. nDropCount = MulDiv(lpvh->dwTimeCaptured - dwTime,
  995. 1000,
  996. lpcs->sCapParms.dwRequestMicroSecPerFrame);
  997. #ifdef JMK_HACK_TIMERS
  998. if (pTimerRiff)
  999. pTimerRiff->vchd.dwDropFramesNotAppended += nDropCount;
  1000. #endif
  1001. // If any frames have been dropped, write them out before
  1002. // we get back to writing the current frame.
  1003. //
  1004. if (nDropCount > 0)
  1005. {
  1006. lpcs->dwFramesDropped += nDropCount;
  1007. if (! AVIWriteDummyFrames (lpcs, nDropCount, lpuError, &bPending))
  1008. fStopping = TRUE;
  1009. }
  1010. }
  1011. #ifdef JMK_HACK_TIMERS
  1012. if (pTimerRiff) {
  1013. if (nTimerIndex == CLIPBOARDLOGSIZE)
  1014. nTimerIndex = 0;
  1015. // nTimerIndex will be OK if ((nTimerIndex < CLIPBOARDLOGSIZE) && pTimerStuff)
  1016. if (pTimerStuff)
  1017. {
  1018. pCurTimerStuff = &pTimerStuff[nTimerIndex];
  1019. ++nTimerIndex;
  1020. pCurTimerStuff->nFramesAppended = 0;
  1021. pCurTimerStuff->nDummyFrames = (WORD)lpcs->dwFramesDropped;
  1022. pCurTimerStuff->dwFrameTickTime = dwTime;
  1023. pCurTimerStuff->dwFrameStampTime = lpvh->dwTimeCaptured;
  1024. pCurTimerStuff->dwVideoChunkCount = lpcs->dwVideoChunkCount;
  1025. pCurTimerStuff->dwTimeWritten = pcDeltaTicks(&pctWriteBase);
  1026. pCurTimerStuff->dwTimeToWrite = 0;
  1027. pCurTimerStuff->nVideoIndex = lpcs->iNextVideo;
  1028. pCurTimerStuff->nAudioIndex = lpcs->iNextWave;
  1029. }
  1030. } // fClipboardLogging
  1031. #endif // JMK_HACK_TIMERS
  1032. // look ahead for dummy frames and try to
  1033. // append them to the current frame
  1034. //
  1035. nAppendDummyFrames = 0;
  1036. #define LOOKAHEAD_FOR_DUMMYS 1
  1037. #ifdef LOOKAHEAD_FOR_DUMMYS
  1038. {
  1039. int iNext;
  1040. LPVIDEOHDR lpvhNext;
  1041. iNext = lpcs->iNextVideo+1;
  1042. if (iNext >= lpcs->iNumVideo)
  1043. iNext = 0;
  1044. // is the next frame done already? if so
  1045. // we can append any dropped frames to the end of
  1046. // this frame before we write it out
  1047. //
  1048. lpvhNext = lpcs->alpVideoHdr[iNext];
  1049. if (lpvhNext->dwFlags & VHDR_DONE)
  1050. {
  1051. // Recalculate the current time, which may have
  1052. // changed if dummy frames were inserted above
  1053. dwTime = MulDiv (lpcs->dwVideoChunkCount + 1,
  1054. lpcs->sCapParms.dwRequestMicroSecPerFrame,
  1055. 1000);
  1056. nAppendDummyFrames =
  1057. MulDiv (lpvhNext->dwTimeCaptured - dwTime,
  1058. 1000,
  1059. lpcs->sCapParms.dwRequestMicroSecPerFrame);
  1060. if ((--nAppendDummyFrames) < 0)
  1061. nAppendDummyFrames = 0;
  1062. else {
  1063. AuxDebugEx(3, DEBUGLINE "Appending %d dummy frames", nAppendDummyFrames);
  1064. }
  1065. lpcs->dwFramesDropped += nAppendDummyFrames;
  1066. #ifdef JMK_HACK_TIMERS
  1067. if (pTimerRiff) {
  1068. pTimerRiff->vchd.dwDropFramesAppended += nAppendDummyFrames;
  1069. pCurTimerStuff->nFramesAppended = nAppendDummyFrames;
  1070. }
  1071. #endif
  1072. }
  1073. }
  1074. #endif
  1075. if ( ! AVIWriteVideoFrame (lpcs,
  1076. lpData,
  1077. dwBytesUsed,
  1078. fKeyFrame,
  1079. lpcs->iNextVideo,
  1080. nAppendDummyFrames,
  1081. lpuError, lpbPending))
  1082. fStopping = TRUE;
  1083. #ifdef JMK_HACK_TIMERS
  1084. if (pCurTimerStuff)
  1085. {
  1086. pCurTimerStuff->dwTimeToWrite = pcDeltaTicks(&pctWriteBase);
  1087. pCurTimerStuff->bPending = *lpbPending;
  1088. }
  1089. #endif
  1090. }
  1091. }
  1092. // return lpvh to the caller so that the frame can be
  1093. // drawn (time permitting)
  1094. //
  1095. *plpvhDraw = lpvh;
  1096. // increment the next Video buffer pointer
  1097. //
  1098. if (++lpcs->iNextVideo >= lpcs->iNumVideo)
  1099. lpcs->iNextVideo = 0;
  1100. return fStopping;
  1101. }
  1102. /*+ ProcessAudioBuffers
  1103. *
  1104. *-===============================================================*/
  1105. STATICFN BOOL _inline ProcessAudioBuffers (
  1106. LPCAPSTREAM lpcs,
  1107. BOOL fStopping,
  1108. LPUINT lpuError)
  1109. {
  1110. int iLastWave;
  1111. UINT ii;
  1112. LPWAVEHDR lpwh;
  1113. *lpuError = 0;
  1114. assert (lpcs->sCapParms.fCaptureAudio);
  1115. // if all buffers are done, we have broke audio.
  1116. //
  1117. iLastWave = lpcs->iNextWave == 0 ? lpcs->iNumAudio -1 : lpcs->iNextWave-1;
  1118. if (!fStopping && lpcs->alpWaveHdr[iLastWave]->dwFlags & WHDR_DONE)
  1119. lpcs->fAudioBreak = TRUE;
  1120. // process all done buffers, but no more than iNumAudio at one
  1121. // pass (to avoid getting stuck here forever)
  1122. //
  1123. for (ii = 0; ii < (UINT)lpcs->iNumAudio; ++ii)
  1124. {
  1125. BOOL bPending;
  1126. // if the next buffer is not done, break out of the loop
  1127. // and return to the caller
  1128. //
  1129. lpwh = lpcs->alpWaveHdr[lpcs->iNextWave];
  1130. if (!(lpwh->dwFlags & WHDR_DONE))
  1131. break;
  1132. lpwh->dwFlags &= ~WHDR_DONE;
  1133. // is there any data in the buffer ?
  1134. // if so, do wave stream callback, then write the
  1135. // buffer
  1136. //
  1137. bPending = FALSE;
  1138. if (lpwh->dwBytesRecorded)
  1139. {
  1140. if (lpcs->CallbackOnWaveStream)
  1141. lpcs->CallbackOnWaveStream (lpcs->hwnd, lpwh);
  1142. if ( ! (lpcs->fCaptureFlags & CAP_fCapturingToDisk))
  1143. {
  1144. lpcs->dwWaveChunkCount++;
  1145. lpcs->dwWaveBytes += lpwh->dwBytesRecorded;
  1146. }
  1147. else
  1148. {
  1149. // write the audio buffer, bPending will be true
  1150. // if the write will complete asynchronously
  1151. //
  1152. if ( ! AVIWriteAudio (lpcs, lpwh, lpcs->iNextWave,
  1153. lpuError, &bPending))
  1154. fStopping = TRUE;
  1155. }
  1156. }
  1157. // if we are not writing async, we can put the buffer
  1158. // back on the wave driver's queue now
  1159. //
  1160. if ( ! bPending)
  1161. {
  1162. lpwh->dwBytesRecorded = 0;
  1163. AuxDebugEx(3, DEBUGLINE "Calling waveInAddBuffer for address %8x", lpwh);
  1164. if (waveInAddBuffer(lpcs->hWaveIn, lpwh, sizeof(WAVEHDR)))
  1165. {
  1166. fStopping = TRUE;
  1167. *lpuError = IDS_CAP_WAVE_ADD_ERROR;
  1168. }
  1169. }
  1170. // increment the next wave buffer pointer
  1171. //
  1172. if (++lpcs->iNextWave >= lpcs->iNumAudio)
  1173. lpcs->iNextWave = 0;
  1174. }
  1175. return fStopping;
  1176. }
  1177. /*+ ProcessAsyncIOBuffers
  1178. *
  1179. *-===============================================================*/
  1180. STATICFN BOOL _inline ProcessAsyncIOBuffers (
  1181. LPCAPSTREAM lpcs,
  1182. BOOL fStopping,
  1183. LPUINT lpuError)
  1184. {
  1185. UINT ii;
  1186. struct _avi_async * lpah;
  1187. // if there are no async buffer headers, there is nothing to do!
  1188. //
  1189. *lpuError = 0;
  1190. assert (lpcs->pAsync);
  1191. // process all done buffers, but no more than iNumAsync
  1192. //
  1193. for (ii = 0; ii < lpcs->iNumAsync; ++ii)
  1194. {
  1195. DWORD dwUsed;
  1196. // if this async header has never been used,
  1197. // we are done
  1198. //
  1199. lpah = &lpcs->pAsync[lpcs->iNextAsync];
  1200. assert (lpah->uType);
  1201. AuxDebugEx (2, DEBUGLINE "processing async io buffer %d off=%x\r\n",
  1202. lpcs->iNextAsync, lpah->ovl.Offset);
  1203. // if the next buffer is not done, or failed break
  1204. // out of the loop
  1205. //
  1206. if ( ! GetOverlappedResult (lpcs->hFile, &lpah->ovl, &dwUsed, FALSE))
  1207. {
  1208. if (GetLastError() != ERROR_IO_INCOMPLETE)
  1209. {
  1210. *lpuError = IDS_CAP_FILE_WRITE_ERROR;
  1211. fStopping = TRUE;
  1212. }
  1213. break;
  1214. }
  1215. //#pragma message (SQUAWK "get rid of this hack when GetOverlappedResult is fixed!")
  1216. if (lpah->ovl.Internal != 0) {
  1217. // if internal is non-zero io is still pending
  1218. // NOTE: this needs to be changed as soon as possible.
  1219. // The current state of play means that GetOverlappedResult CAN return
  1220. // something other than ERROR_IO_COMPLETE and the IO will still be
  1221. // pending. This causes us to make the wrong decision.
  1222. break;
  1223. }
  1224. // the buffer is done, so now we need to queue the wave/video
  1225. // buffer back to the wave/video driver
  1226. //
  1227. switch (lpah->uType)
  1228. {
  1229. case ASYNC_BUF_VIDEO:
  1230. {
  1231. LPVIDEOHDR lpvh = lpcs->alpVideoHdr[lpah->uIndex];
  1232. #if defined CHICAGO
  1233. if (vidxAddBuffer(lpcs->hVideoIn, lpvh, sizeof (VIDEOHDR)))
  1234. #else
  1235. AuxDebugEx(3, DEBUGLINE "Queueing video buffer lpvh=%x (index %d)\r\n", lpvh, lpah->uIndex);
  1236. if (videoStreamAddBuffer(lpcs->hVideoIn, lpvh, sizeof (VIDEOHDR)))
  1237. #endif
  1238. {
  1239. fStopping = TRUE;
  1240. *lpuError = IDS_CAP_VIDEO_ADD_ERROR;
  1241. }
  1242. }
  1243. break;
  1244. case ASYNC_BUF_AUDIO:
  1245. {
  1246. LPWAVEHDR lpwh = lpcs->alpWaveHdr[lpah->uIndex];
  1247. lpwh->dwBytesRecorded = 0;
  1248. AuxDebugEx(3, DEBUGLINE "Queueing audio buffer lpwh=%x (index %d)\r\n", lpwh, lpah->uIndex);
  1249. if (waveInAddBuffer (lpcs->hWaveIn, lpwh, sizeof(WAVEHDR)))
  1250. {
  1251. fStopping = TRUE;
  1252. *lpuError = IDS_CAP_WAVE_ADD_ERROR;
  1253. }
  1254. }
  1255. break;
  1256. //case ASYNC_BUF_DROP:
  1257. //{
  1258. //}
  1259. //break;
  1260. }
  1261. lpah->uType = 0;
  1262. lpah->uIndex = 0;
  1263. // increment to the next async io buffer
  1264. //
  1265. if (++lpcs->iNextAsync >= lpcs->iNumAsync)
  1266. lpcs->iNextAsync = 0;
  1267. }
  1268. return fStopping;
  1269. }
  1270. /*+ ShowCompletionStatus
  1271. *
  1272. *-===============================================================*/
  1273. STATICFN void ShowCompletionStatus (
  1274. LPCAPSTREAM lpcs,
  1275. BOOL fCapturedOK)
  1276. {
  1277. // Notify if there was an error while recording
  1278. //
  1279. if ( ! fCapturedOK)
  1280. errorUpdateError (lpcs, IDS_CAP_RECORDING_ERROR);
  1281. // put up completion message on status line
  1282. //
  1283. if (lpcs->fCaptureFlags & CAP_fCapturingToDisk)
  1284. {
  1285. DWORD dw;
  1286. // The muldiv32 doesn't give 0 if numerator is zero
  1287. dw = 0;
  1288. if (lpcs->dwVideoChunkCount)
  1289. dw = muldiv32(lpcs->dwVideoChunkCount,1000000,lpcs->dwTimeElapsedMS);
  1290. if (lpcs->sCapParms.fCaptureAudio)
  1291. {
  1292. // "Captured %d.%03d sec. %ld frames (%ld dropped) (%d.%03d fps). %ld audio bytes (%d.%03d sps)"
  1293. statusUpdateStatus(lpcs, IDS_CAP_STAT_VIDEOAUDIO,
  1294. (UINT)(lpcs->dwTimeElapsedMS/1000),
  1295. (UINT)(lpcs->dwTimeElapsedMS%1000),
  1296. lpcs->dwVideoChunkCount,
  1297. lpcs->dwFramesDropped,
  1298. (UINT)(dw / 1000),
  1299. (UINT)(dw % 1000),
  1300. lpcs->dwWaveBytes,
  1301. (UINT) lpcs->lpWaveFormat->nSamplesPerSec / 1000,
  1302. (UINT) lpcs->lpWaveFormat->nSamplesPerSec % 1000);
  1303. }
  1304. else
  1305. {
  1306. // "Captured %d.%03d sec. %ld frames (%ld dropped) (%d.%03d fps)."
  1307. statusUpdateStatus(lpcs, IDS_CAP_STAT_VIDEOONLY,
  1308. (UINT)(lpcs->dwTimeElapsedMS/1000),
  1309. (UINT)(lpcs->dwTimeElapsedMS%1000),
  1310. lpcs->dwVideoChunkCount,
  1311. lpcs->dwFramesDropped,
  1312. (UINT)(dw / 1000),
  1313. (UINT)(dw % 1000));
  1314. }
  1315. } // endif capturing to disk (no warnings or errors if to net)
  1316. // if capture was successful, warn the user about various abnormal
  1317. // conditions.
  1318. //
  1319. if (fCapturedOK)
  1320. {
  1321. if (lpcs->dwVideoChunkCount == 0)
  1322. {
  1323. // No frames captured, warn user that interrupts are probably not enabled.
  1324. errorUpdateError (lpcs, IDS_CAP_NO_FRAME_CAP_ERROR);
  1325. }
  1326. else if (lpcs->sCapParms.fCaptureAudio && lpcs->dwWaveBytes == 0)
  1327. {
  1328. // No audio captured, warn user audio card is hosed
  1329. errorUpdateError (lpcs, IDS_CAP_NO_AUDIO_CAP_ERROR);
  1330. }
  1331. else if (lpcs->sCapParms.fCaptureAudio && lpcs->fAudioBreak)
  1332. {
  1333. // some of the audio was dropped
  1334. if(lpcs->CompVars.hic) {
  1335. errorUpdateError (lpcs, IDS_CAP_AUDIO_DROP_COMPERROR);
  1336. } else {
  1337. errorUpdateError (lpcs, IDS_CAP_AUDIO_DROP_ERROR);
  1338. }
  1339. }
  1340. else if (lpcs->fCaptureFlags & CAP_fCapturingToDisk)
  1341. {
  1342. DWORD dwPctDropped;
  1343. assert (lpcs->dwVideoChunkCount);
  1344. dwPctDropped = 100 * lpcs->dwFramesDropped / lpcs->dwVideoChunkCount;
  1345. //
  1346. // dropped > 10% (default) of the frames
  1347. //
  1348. if (dwPctDropped > lpcs->sCapParms.wPercentDropForError)
  1349. errorUpdateError (lpcs, IDS_CAP_STAT_FRAMESDROPPED,
  1350. lpcs->dwFramesDropped,
  1351. lpcs->dwVideoChunkCount,
  1352. (UINT)(muldiv32(lpcs->dwFramesDropped,10000,lpcs->dwVideoChunkCount)/100),
  1353. (UINT)(muldiv32(lpcs->dwFramesDropped,10000,lpcs->dwVideoChunkCount)%100)/10
  1354. );
  1355. }
  1356. }
  1357. }
  1358. /*
  1359. * AVI Capture
  1360. * This is the main streaming capture loop for both audio and
  1361. * video. It will first init all buffers and drivers and then go into a
  1362. * loop checking for buffers to be filled. When a buffer is filled then
  1363. * the data for it is written out.
  1364. * Afterwards it cleans up after itself (frees buffers etc...)
  1365. * Returns: 0 on success, else error code
  1366. */
  1367. void FAR PASCAL _LOADDS AVICapture1(LPCAPSTREAM lpcs)
  1368. {
  1369. BOOL fCapturedOK = TRUE;
  1370. BOOL fStopping; // True when finishing capture
  1371. BOOL fStopped; // True if driver notified to stop
  1372. TCHAR ach[128];
  1373. TCHAR achMsg[128];
  1374. UINT wError; // Error String ID
  1375. LPVIDEOHDR lpVidHdr;
  1376. LPWAVEHDR lpWaveHdr;
  1377. DWORD dwTimeStarted; // When did we start in milliseconds
  1378. DWORD dwTimeStopped;
  1379. DWORD dwTimeToStop; // Lesser of MCI capture time or frame limit
  1380. BOOL fTryToPaint = FALSE;
  1381. BOOL fTryToPaintAgain = FALSE;
  1382. HDC hdc;
  1383. HPALETTE hpalT;
  1384. HCURSOR hOldCursor;
  1385. RECT rcDrawRect;
  1386. CAPINFOCHUNK cic;
  1387. DWORD dwOldPrio;
  1388. BOOL bVideoWritePending;
  1389. LPVIDEOHDR lpvhDraw;
  1390. lpcs->fCaptureFlags |= CAP_fCapturingNow;
  1391. lpcs->dwReturn = DV_ERR_OK;
  1392. hOldCursor = SetCursor(lpcs->hWaitCursor);
  1393. statusUpdateStatus(lpcs, IDS_CAP_BEGIN); // Always the first message
  1394. // If not 1 Meg. free, give it up!!!
  1395. if (GetFreePhysicalMemory () < (1024L * 1024L)) {
  1396. errorUpdateError (lpcs, IDS_CAP_OUTOFMEM);
  1397. goto EarlyExit;
  1398. }
  1399. statusUpdateStatus(lpcs, IDS_CAP_STAT_CAP_INIT);
  1400. // Try painting the DIB only if Live window
  1401. fTryToPaintAgain = fTryToPaint = lpcs->fLiveWindow;
  1402. if (fTryToPaint) {
  1403. hdc = GetDC(lpcs->hwnd);
  1404. SetWindowOrgEx(hdc, lpcs->ptScroll.x, lpcs->ptScroll.y, NULL);
  1405. hpalT = DrawDibGetPalette (lpcs->hdd);
  1406. if (hpalT)
  1407. hpalT = SelectPalette( hdc, hpalT, FALSE);
  1408. RealizePalette(hdc);
  1409. if (lpcs->fScale)
  1410. GetClientRect (lpcs->hwnd, &rcDrawRect);
  1411. else
  1412. SetRect (&rcDrawRect, 0, 0, lpcs->dxBits, lpcs->dyBits);
  1413. }
  1414. // -------------------------------------------------------
  1415. // When should capture stop?
  1416. // -------------------------------------------------------
  1417. // If using MCI, capture for the shorter of the MCI period,
  1418. // or the capture limit
  1419. if (lpcs->sCapParms.fLimitEnabled)
  1420. dwTimeToStop = (DWORD) ((DWORD) 1000 * lpcs->sCapParms.wTimeLimit);
  1421. else
  1422. dwTimeToStop = (DWORD) -1L; // very large
  1423. if (lpcs->sCapParms.fMCIControl) {
  1424. DWORD dwTime;
  1425. // if MCI stop time not given, use lpcs->sCapParms.wTimeLimit
  1426. if (lpcs->sCapParms.dwMCIStopTime == lpcs->sCapParms.dwMCIStartTime)
  1427. lpcs->sCapParms.dwMCIStopTime = lpcs->sCapParms.dwMCIStartTime +
  1428. (DWORD) ((DWORD)1000 * lpcs->sCapParms.wTimeLimit);
  1429. dwTime = lpcs->sCapParms.dwMCIStopTime - lpcs->sCapParms.dwMCIStartTime;
  1430. if (lpcs->sCapParms.fLimitEnabled)
  1431. dwTimeToStop = min (dwTime, dwTimeToStop);
  1432. else
  1433. dwTimeToStop = dwTime;
  1434. }
  1435. //
  1436. // never ever try to capture more than the index size!
  1437. //
  1438. if (lpcs->fCaptureFlags & CAP_fCapturingToDisk)
  1439. {
  1440. DWORD dwTime = MulDiv (lpcs->sCapParms.dwIndexSize,
  1441. lpcs->sCapParms.dwRequestMicroSecPerFrame,
  1442. 1000l);
  1443. dwTimeToStop = min (dwTime, dwTimeToStop);
  1444. }
  1445. // if doing MCI capture, initialize MCI device. if init fails
  1446. // go straight to the exit code
  1447. //
  1448. if (lpcs->sCapParms.fMCIControl)
  1449. {
  1450. if ( ! MCIDeviceOpen (lpcs) ||
  1451. ! MCIDeviceSetPosition (lpcs, lpcs->sCapParms.dwMCIStartTime))
  1452. {
  1453. fCapturedOK = FALSE;
  1454. errorUpdateError (lpcs, IDS_CAP_MCI_CONTROL_ERROR);
  1455. statusUpdateStatus(lpcs, 0); // Clear status
  1456. goto EarlyExit;
  1457. }
  1458. }
  1459. //
  1460. // If we're compressing while capturing, warm up the compressor
  1461. //
  1462. #ifdef NEW_COMPMAN
  1463. if (lpcs->CompVars.hic)
  1464. {
  1465. if ( ! ICSeqCompressFrameStart (&lpcs->CompVars, lpcs->lpBitsInfo))
  1466. {
  1467. // !!! We're in trouble here!
  1468. dprintf("ICSeqCompressFrameStart failed !!!\n");
  1469. errorUpdateError (lpcs, IDS_CAP_COMPRESSOR_ERROR);
  1470. goto EarlyExit;
  1471. }
  1472. // Kludge, offset the lpBitsOut ptr
  1473. // Compman allocates the compress buffer too large by
  1474. // 2048 + 16 so we will still have room
  1475. //
  1476. ((LPBYTE)lpcs->CompVars.lpBitsOut) += 8;
  1477. assert(lpcs->CompVars.lpbiOut != NULL);
  1478. }
  1479. #endif
  1480. // -------------------------------------------------------
  1481. // Open the output file
  1482. // -------------------------------------------------------
  1483. if (lpcs->fCaptureFlags & CAP_fCapturingToDisk) {
  1484. if (!CapFileInit(lpcs))
  1485. {
  1486. errorUpdateError (lpcs, IDS_CAP_FILE_OPEN_ERROR);
  1487. goto EarlyExit;
  1488. }
  1489. } else {
  1490. AuxDebugEx (3, DEBUGLINE "Setting dwBytesPerSector to %d\r\n",DEFAULT_BYTESPERSECTOR);
  1491. lpcs->dwBytesPerSector=DEFAULT_BYTESPERSECTOR;
  1492. }
  1493. #ifdef JMK_HACK_TIMERS
  1494. // Allocate memory for logging capture results to the clipboard if requested
  1495. if (GetProfileIntA ("Avicap32", "ClipboardLogging", FALSE))
  1496. {
  1497. AuxDebugEx (2, DEBUGLINE "ClipboardLogging Enabled\r\n");
  1498. InitPerformanceCounters();
  1499. pcBegin(), pctWriteBase = pc.base;
  1500. hMemTimers = GlobalAlloc(GHND | GMEM_ZEROINIT,
  1501. sizeof(struct _timerriff) +
  1502. sizeof(struct _timerstuff) * CLIPBOARDLOGSIZE);
  1503. if (hMemTimers && (pTimerRiff = GlobalLock (hMemTimers)))
  1504. ;
  1505. else if (hMemTimers)
  1506. {
  1507. GlobalFree(hMemTimers);
  1508. pTimerRiff = 0;
  1509. pTimerStuff = 0;
  1510. hMemTimers = 0;
  1511. }
  1512. nTimerIndex = 0;
  1513. nSleepCount = 0;
  1514. } // if ClipboardLogging
  1515. #endif // JMK_HACK_TIMERS
  1516. // Make sure the parent has been repainted
  1517. //
  1518. UpdateWindow(lpcs->hwnd);
  1519. //
  1520. // call AVIInit() to get all the capture memory we will need
  1521. //
  1522. wError = IDS_CAP_AVI_INIT_ERROR;
  1523. lpcs->hCaptureEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1524. if (lpcs->hCaptureEvent)
  1525. {
  1526. #ifdef CHICAGO
  1527. lpcs->hRing0CapEvt = OpenVxDHandle (lpcs->hCaptureEvent);
  1528. if ( ! lpcs->hRing0CapEvt)
  1529. CloseHandle (lpcs->hCaptureEvent), lpcs->hCaptureEvent = NULL;
  1530. else
  1531. #endif
  1532. wError = AVIInit(lpcs);
  1533. }
  1534. // if avifile init failed, cleanup and return error.
  1535. //
  1536. if (wError)
  1537. {
  1538. // Error in initalization - return
  1539. //
  1540. errorUpdateError (lpcs, wError);
  1541. AVIFini(lpcs);
  1542. AVIFileFini(lpcs, TRUE, TRUE);
  1543. statusUpdateStatus(lpcs, 0); // Clear status
  1544. goto EarlyExit;
  1545. }
  1546. // Click OK to capture string (must follow AVIInit)
  1547. //
  1548. LoadString(lpcs->hInst, IDS_CAP_SEQ_MSGSTART, ach, NUMELMS(ach));
  1549. wsprintf(achMsg, ach, (LPBYTE)lpcs->achFile);
  1550. // clear status
  1551. //
  1552. statusUpdateStatus(lpcs, 0);
  1553. // -------------------------------------------------------
  1554. // Ready to go, make the user click OK?
  1555. // -------------------------------------------------------
  1556. if (lpcs->sCapParms.fMakeUserHitOKToCapture && (lpcs->fCaptureFlags & CAP_fCapturingToDisk))
  1557. {
  1558. UINT idBtn;
  1559. idBtn = MessageBox (lpcs->hwnd, achMsg, TEXT(""),
  1560. MB_OKCANCEL | MB_ICONEXCLAMATION);
  1561. if (idBtn == IDCANCEL)
  1562. {
  1563. AVIFini(lpcs);
  1564. AVIFileFini (lpcs, TRUE, TRUE);
  1565. statusUpdateStatus (lpcs, 0);
  1566. goto EarlyExit;
  1567. }
  1568. }
  1569. // update the status, so the user knows how to stop
  1570. //
  1571. statusUpdateStatus(lpcs, IDS_CAP_SEQ_MSGSTOP);
  1572. UpdateWindow(lpcs->hwnd);
  1573. lpcs->fCaptureFlags |= CAP_fCapturingNow;
  1574. // query async key states to 'reset' them to current values
  1575. //
  1576. GetAsyncKeyState(lpcs->sCapParms.vKeyAbort);
  1577. GetAsyncKeyState(VK_ESCAPE);
  1578. GetAsyncKeyState(VK_LBUTTON);
  1579. GetAsyncKeyState(VK_RBUTTON);
  1580. // Insert the digitization time
  1581. // strings written to the file should be ascii, since this is
  1582. // an ascii file format.
  1583. //
  1584. //
  1585. // no point in pulling in the whole C runtime just to get a silly
  1586. // timestamp, so we just cook the system time into ascii right here.
  1587. //
  1588. {
  1589. SYSTEMTIME time;
  1590. static char szDay[] = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0";
  1591. static char szMonth[] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0";
  1592. char sz[30];
  1593. GetLocalTime (&time);
  1594. //example: Fri Apr 29 12:25:12 1994
  1595. wsprintfA(sz, "%s %s %2d %2d:%02d:%02d %4d",
  1596. szDay + time.wDayOfWeek * 4,
  1597. szMonth + time.wMonth * 4,
  1598. time.wDay, time.wHour, time.wMinute, time.wSecond, time.wYear);
  1599. cic.fccInfoID = mmioFOURCC ('I','D','I','T');
  1600. cic.lpData = sz;
  1601. cic.cbData = 26;
  1602. SetInfoChunk (lpcs, &cic);
  1603. }
  1604. // -------------------------------------------------------
  1605. // Start MCI, Audio, and video streams
  1606. // -------------------------------------------------------
  1607. // Callback will preroll, then return on frame accurate postion
  1608. // The 1 indicates recording is about to start
  1609. // Callback can return FALSE to exit without capturing
  1610. //
  1611. if (lpcs->CallbackOnControl &&
  1612. !lpcs->CallbackOnControl(lpcs->hwnd, CONTROLCALLBACK_PREROLL))
  1613. {
  1614. AVIFini(lpcs);
  1615. AVIFileFini(lpcs, TRUE, TRUE);
  1616. statusUpdateStatus(lpcs, 0);
  1617. goto EarlyExit;
  1618. }
  1619. dwOldPrio = GetThreadPriority(GetCurrentThread());
  1620. if (dwOldPrio != THREAD_PRIORITY_HIGHEST)
  1621. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  1622. #ifdef JMK_HACK_TIMERS
  1623. if (pTimerRiff)
  1624. {
  1625. UINT ii;
  1626. pTimerRiff->fccRIFF = RIFFTYPE('RIFF'); //MAKEFOURCC('R','I','F','F');
  1627. pTimerRiff->cbTotal = sizeof(struct _timerriff) - 8 +
  1628. sizeof(struct _timerstuff) * CLIPBOARDLOGSIZE;
  1629. pTimerRiff->fccJMKD = RIFFTYPE('JMKD'); //MAKEFOURCC('J','M','K','D');
  1630. pTimerRiff->fccVCHD = RIFFTYPE('VCHD'); //MAKEFOURCC('V','C','H','D');
  1631. pTimerRiff->cbVCHD = sizeof(struct _vchd);
  1632. pTimerRiff->vchd.nPrio = GetThreadPriority(GetCurrentThread());
  1633. pTimerRiff->vchd.bmih = lpcs->lpBitsInfo->bmiHeader;
  1634. pTimerRiff->vchd.cap = lpcs->sCapParms;
  1635. pTimerRiff->vchd.dwDropFramesAppended = 0;
  1636. pTimerRiff->vchd.dwDropFramesNotAppended = 0;
  1637. pTimerRiff->vchd.dwTimerFrequency = pcGetTickRate();
  1638. for (ii = 0; ii < NUMELMS(pTimerRiff->vchd.atvh); ++ii)
  1639. {
  1640. if (lpcs->alpVideoHdr[ii])
  1641. {
  1642. struct _thkvideohdr * ptvh = (LPVOID)lpcs->alpVideoHdr[ii];
  1643. #ifndef CHICAGO
  1644. assert (sizeof(CAPVIDEOHDR) == sizeof(*ptvh));
  1645. #endif
  1646. pTimerRiff->vchd.atvh[ii] = *ptvh;
  1647. pTimerRiff->vchd.nMaxVideoBuffers = ii;
  1648. }
  1649. }
  1650. pTimerRiff->fccChunk = RIFFTYPE('VCAP'); //MAKEFOURCC('V','C','A','P');
  1651. pTimerRiff->cbChunk = pTimerRiff->cbTotal - sizeof(*pTimerRiff);
  1652. pTimerStuff = (LPVOID)(pTimerRiff + 1);
  1653. pCurTimerStuff = &pTimerStuff[0];
  1654. } // fClipboardLogging
  1655. #endif // JMK_HACK_TIMERS
  1656. // make sure that the fat is loaded before we begin capturing
  1657. //
  1658. AVIPreloadFat (lpcs);
  1659. // start the MCI device
  1660. //
  1661. if (lpcs->sCapParms.fMCIControl)
  1662. MCIDevicePlay (lpcs);
  1663. dwTimeStarted = timeGetTime();
  1664. // start audio & video streams
  1665. //
  1666. if (lpcs->sCapParms.fCaptureAudio)
  1667. waveInStart(lpcs->hWaveIn);
  1668. videoStreamStart(lpcs->hVideoIn);
  1669. // -------------------------------------------------------
  1670. // MAIN CAPTURE LOOP
  1671. // -------------------------------------------------------
  1672. fCapturedOK=TRUE;
  1673. fStopping = FALSE; // TRUE when we need to stop
  1674. fStopped = FALSE; // TRUE if drivers notified we have stopped
  1675. lpcs->dwTimeElapsedMS = 0;
  1676. assert (lpcs->iNextVideo == 0);
  1677. if (lpcs->sCapParms.fCaptureAudio) {
  1678. assert (lpcs->iNextWave == 0);
  1679. lpWaveHdr = lpcs->alpWaveHdr[lpcs->iNextWave];
  1680. // lpWaveHdr is only interesting when we capture audio
  1681. }
  1682. lpVidHdr = lpcs->alpVideoHdr[lpcs->iNextVideo];
  1683. DPF("Start of main capture loop");
  1684. for (;;)
  1685. {
  1686. // The INTEL driver uses the GetError message to
  1687. // process buffers, so call it often...
  1688. // FIX JAYBO videoStreamGetError (lpcs->hVideoIn, &dwStreamError, &dwDriverDropCount);
  1689. // if there are no buffers to process, we either wait
  1690. // or leave the loop forever (depending on whether we expect
  1691. // more buffers to be done in the future)
  1692. //
  1693. if (!(lpVidHdr->dwFlags & VHDR_DONE) &&
  1694. !(lpcs->sCapParms.fCaptureAudio
  1695. && (lpWaveHdr->dwFlags & WHDR_DONE)))
  1696. {
  1697. if (fStopped)
  1698. break;
  1699. #ifdef JMK_HACK_TIMERS
  1700. if (pCurTimerStuff)
  1701. {
  1702. pCurTimerStuff->nSleepCount = ++nSleepCount;
  1703. pCurTimerStuff->dwSleepBegin = pcGetTicks();
  1704. }
  1705. #endif
  1706. AuxDebugEx(2,DEBUGLINE "***** Waiting for something interesting to happen while capturing\r\n");
  1707. WaitForSingleObject (lpcs->hCaptureEvent, 300);
  1708. #ifdef JMK_HACK_TIMERS
  1709. if (pCurTimerStuff)
  1710. {
  1711. pCurTimerStuff->dwSleepEnd = pcGetTicks();
  1712. }
  1713. #endif
  1714. }
  1715. // What time is it?
  1716. lpcs->dwTimeElapsedMS = timeGetTime() - dwTimeStarted;
  1717. // -------------------------------------------------------
  1718. // Is video buffer ready to be written?
  1719. // -------------------------------------------------------
  1720. if (fStopping = ProcessNextVideoBuffer (lpcs,
  1721. fStopping,
  1722. &wError,
  1723. &lpvhDraw, // captured frame to draw if time permits
  1724. &bVideoWritePending)) // TRUE if Write pending on lpvhDraw
  1725. {
  1726. AuxDebugEx (1, DEBUGLINE "ProcessVideo stopping\r\n");
  1727. if (wError)
  1728. {
  1729. AuxDebugEx (1, DEBUGLINE "ProcessVideo return error %d\r\n", wError);
  1730. errorUpdateError (lpcs, wError);
  1731. fCapturedOK = FALSE;
  1732. break;
  1733. }
  1734. }
  1735. lpVidHdr = lpcs->alpVideoHdr[lpcs->iNextVideo];
  1736. // if there is still more time, (or at least every 100 frames)
  1737. // show status if we're not ending the capture
  1738. //
  1739. if (!fStopping &&
  1740. (lpcs->fCaptureFlags & CAP_fCapturingToDisk) &&
  1741. (!(lpVidHdr->dwFlags & VHDR_DONE) ||
  1742. (lpcs->dwVideoChunkCount && (lpcs->dwVideoChunkCount % 100 == 0))))
  1743. {
  1744. // Captured %ld frames (Dropped %ld) %d.%03d sec. Hit Escape to Stop
  1745. //
  1746. statusUpdateStatus(lpcs, IDS_CAP_STAT_VIDEOCURRENT,
  1747. lpcs->dwVideoChunkCount,
  1748. lpcs->dwFramesDropped,
  1749. (UINT)(lpcs->dwTimeElapsedMS/1000),
  1750. (UINT)(lpcs->dwTimeElapsedMS%1000));
  1751. }
  1752. // If the yield callback returns FALSE, abort
  1753. //
  1754. if (lpcs->CallbackOnYield && !lpcs->CallbackOnYield (lpcs->hwnd))
  1755. fStopping = TRUE;
  1756. #if 0 // this is a 16 bit ism??
  1757. // Don't do peekMessage yield for ACM
  1758. if (lpcs->sCapParms.fYield) {
  1759. MSG msg;
  1760. if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  1761. // Kludge to get rid of timers from lpcs->hwnd
  1762. if (msg.message == WM_TIMER && msg.hwnd == lpcs->hwnd)
  1763. ;
  1764. else {
  1765. TranslateMessage(&msg);
  1766. DispatchMessage(&msg);
  1767. }
  1768. }
  1769. }
  1770. #endif
  1771. // Outside routine is handling when to stop
  1772. // The CONTROLCALLBACK_CAPTURING indicates we're asking when to stop
  1773. //
  1774. if (lpcs->CallbackOnControl &&
  1775. !lpcs->CallbackOnControl (lpcs->hwnd, CONTROLCALLBACK_CAPTURING))
  1776. fStopping = TRUE;
  1777. // -------------------------------------------------------
  1778. // Is audio buffer ready to be written?
  1779. // -------------------------------------------------------
  1780. if (lpcs->sCapParms.fCaptureAudio) {
  1781. if (fStopping = ProcessAudioBuffers (lpcs, fStopping, &wError))
  1782. {
  1783. AuxDebugEx (1, DEBUGLINE "ProcessAudio stopping\r\n");
  1784. if (wError)
  1785. {
  1786. AuxDebugEx (1, DEBUGLINE "ProcessAudio return error %d\r\n", wError);
  1787. errorUpdateError (lpcs, wError);
  1788. fCapturedOK = FALSE;
  1789. break;
  1790. }
  1791. }
  1792. lpWaveHdr = lpcs->alpWaveHdr[lpcs->iNextWave];
  1793. }
  1794. // if we are not writing the frame async, we can put the video buffer
  1795. // back on the video driver's queue now
  1796. //
  1797. if (lpvhDraw)
  1798. {
  1799. // if the next video header is not ready yet, and
  1800. // we have no outstanding io buffers (in async mode) draw
  1801. // the current one
  1802. //
  1803. if ( !(lpVidHdr->dwFlags & VHDR_DONE) &&
  1804. (!lpcs->pAsync || (lpcs->iNextAsync == lpcs->iLastAsync)) &&
  1805. lpvhDraw->dwBytesUsed)
  1806. {
  1807. AuxDebugEx (4, DEBUGLINE "time enough to draw!\r\n");
  1808. if (fTryToPaintAgain &&
  1809. lpcs->dwVideoChunkCount &&
  1810. lpvhDraw->dwFlags & VHDR_KEYFRAME)
  1811. {
  1812. fTryToPaintAgain = DrawDibDraw(lpcs->hdd, hdc,
  1813. 0, 0,
  1814. rcDrawRect.right - rcDrawRect.left,
  1815. rcDrawRect.bottom - rcDrawRect.top,
  1816. /*lpcs->dxBits, lpcs->dyBits, */
  1817. (LPBITMAPINFOHEADER)lpcs->lpBitsInfo,
  1818. lpvhDraw->lpData, 0, 0, -1, -1,
  1819. DDF_SAME_HDC | DDF_SAME_DIB | DDF_SAME_SIZE);
  1820. }
  1821. }
  1822. // if there is not a write pending for the draw frame
  1823. // put it back into the video drivers queue now
  1824. //
  1825. if ( ! bVideoWritePending)
  1826. {
  1827. AuxDebugEx(3, DEBUGLINE "Queueing video buffer, lpvh=%8x", lpvhDraw);
  1828. // return the emptied buffer to the que
  1829. //
  1830. #if defined CHICAGO
  1831. if (vidxAddBuffer(lpcs->hVideoIn, lpvhDraw, sizeof (VIDEOHDR)))
  1832. #else
  1833. if (videoStreamAddBuffer(lpcs->hVideoIn, lpvhDraw, sizeof (VIDEOHDR)))
  1834. #endif
  1835. {
  1836. AuxDebugEx (2, DEBUGLINE "Failed to Queue Video buffer %08x\r\n", lpvhDraw);
  1837. errorUpdateError (lpcs, IDS_CAP_VIDEO_ADD_ERROR);
  1838. fCapturedOK = FALSE;
  1839. fStopping = TRUE;
  1840. break;
  1841. }
  1842. }
  1843. }
  1844. // ------------------------------------------------------------
  1845. // Any completed I/O buffers?
  1846. // ------------------------------------------------------------
  1847. if (lpcs->pAsync)
  1848. if (fStopping = ProcessAsyncIOBuffers (lpcs, fStopping, &wError))
  1849. {
  1850. if (wError)
  1851. {
  1852. errorUpdateError (lpcs, wError);
  1853. fCapturedOK = FALSE;
  1854. break;
  1855. }
  1856. }
  1857. // -------------------------------------------------------
  1858. // is there any reason to stop?
  1859. // -------------------------------------------------------
  1860. if (!fStopping)
  1861. {
  1862. if (lpcs->sCapParms.vKeyAbort &&
  1863. (GetAsyncKeyState(lpcs->sCapParms.vKeyAbort & 0x00ff) & 0x0001))
  1864. {
  1865. BOOL fT = TRUE;
  1866. if (lpcs->sCapParms.vKeyAbort & 0x8000) // Ctrl?
  1867. fT = fT && (GetAsyncKeyState(VK_CONTROL) & 0x8000);
  1868. if (lpcs->sCapParms.vKeyAbort & 0x4000) // Shift?
  1869. fT = fT && (GetAsyncKeyState(VK_SHIFT) & 0x8000);
  1870. fStopping = fT; // User aborts
  1871. }
  1872. if (lpcs->sCapParms.fAbortLeftMouse && (GetAsyncKeyState(VK_LBUTTON) & 0x0001))
  1873. fStopping = TRUE; // User aborts
  1874. if (lpcs->sCapParms.fAbortRightMouse && (GetAsyncKeyState(VK_RBUTTON) & 0x0001))
  1875. fStopping = TRUE; // User aborts
  1876. if ((lpcs->fCaptureFlags & CAP_fAbortCapture) || (lpcs->fCaptureFlags & CAP_fStopCapture))
  1877. fStopping = TRUE; // Somebody above wants us to quit
  1878. if (lpcs->dwTimeElapsedMS > dwTimeToStop)
  1879. fStopping = TRUE; // all done
  1880. #ifdef DEBUG
  1881. if (fStopping)
  1882. AuxDebugEx (1, DEBUGLINE "user stop\r\n");
  1883. #endif
  1884. }
  1885. // -------------------------------------------------------
  1886. // Tell all the devices to stop
  1887. // -------------------------------------------------------
  1888. if (fStopping)
  1889. {
  1890. if ( ! fStopped)
  1891. {
  1892. fStopped = TRUE;
  1893. DSTATUS(lpcs, "Stopping....");
  1894. if (lpcs->sCapParms.fCaptureAudio)
  1895. {
  1896. DSTATUS(lpcs, "Stopping Audio");
  1897. waveInStop(lpcs->hWaveIn);
  1898. }
  1899. DSTATUS(lpcs, "Stopping Video");
  1900. videoStreamStop(lpcs->hVideoIn); // Stop everybody
  1901. dwTimeStopped = timeGetTime ();
  1902. if (lpcs->sCapParms.fMCIControl)
  1903. {
  1904. DSTATUS(lpcs, "Stopping MCI");
  1905. MCIDevicePause (lpcs);
  1906. }
  1907. DSTATUS(lpcs, "Stopped");
  1908. // Force cursor back to hourglass
  1909. //
  1910. SetCursor(lpcs->hWaitCursor);
  1911. }
  1912. // "Finished capture, now writing frame %ld"
  1913. //
  1914. if (fCapturedOK)
  1915. statusUpdateStatus(lpcs, IDS_CAP_STAT_CAP_FINI, lpcs->dwVideoChunkCount);
  1916. else
  1917. {
  1918. statusUpdateStatus(lpcs, IDS_CAP_RECORDING_ERROR2);
  1919. break;
  1920. }
  1921. // Wait for all the async IO to complete ??
  1922. //
  1923. }
  1924. // -------------------------------------------------------
  1925. // END OF MAIN CAPTURE LOOP
  1926. // -------------------------------------------------------
  1927. }
  1928. DPF("End of main capture loop");
  1929. // eat any keys that have been pressed
  1930. //
  1931. while(GetKey(FALSE))
  1932. ;
  1933. // flush stuff to disk, close everything etc.
  1934. //
  1935. AVIFini(lpcs);
  1936. AVIFileFini(lpcs, TRUE, !fCapturedOK);
  1937. // This is the corrected capture duration, based on audio samples
  1938. lpcs->dwTimeElapsedMS = lpcs->dwActualMicroSecPerFrame *
  1939. lpcs->dwVideoChunkCount / 1000;
  1940. // update the status line with information about the completed
  1941. // capture, or with erroor information
  1942. //
  1943. ShowCompletionStatus (lpcs, fCapturedOK);
  1944. EarlyExit:
  1945. DPF("at EarlyExit\n");
  1946. //
  1947. // If we we're compressing while capturing, close it down
  1948. //
  1949. #ifdef NEW_COMPMAN
  1950. if (lpcs->CompVars.hic) {
  1951. // Kludge, reset the lpBitsOut pointer
  1952. if (lpcs->CompVars.lpBitsOut)
  1953. ((LPBYTE) lpcs->CompVars.lpBitsOut) -= 8;
  1954. ICSeqCompressFrameEnd(&lpcs->CompVars);
  1955. }
  1956. #endif
  1957. if (fTryToPaint) {
  1958. if (hpalT)
  1959. SelectPalette(hdc, hpalT, FALSE);
  1960. ReleaseDC (lpcs->hwnd, hdc);
  1961. }
  1962. if (lpcs->sCapParms.fMCIControl)
  1963. MCIDeviceClose (lpcs);
  1964. // Let the user see where capture stopped
  1965. if ((!lpcs->fLiveWindow) && (!lpcs->fOverlayWindow))
  1966. videoFrame( lpcs->hVideoIn, &lpcs->VidHdr );
  1967. InvalidateRect( lpcs->hwnd, NULL, TRUE);
  1968. SetThreadPriority (GetCurrentThread(), dwOldPrio);
  1969. SetCursor(hOldCursor);
  1970. lpcs->fCapFileExists = (lpcs->dwReturn == DV_ERR_OK);
  1971. lpcs->fCaptureFlags &= ~CAP_fCapturingNow;
  1972. statusUpdateStatus(lpcs, IDS_CAP_END); // Always the last message
  1973. #ifdef JMK_HACK_TIMERS
  1974. if (pTimerRiff)
  1975. {
  1976. UINT ii;
  1977. UINT kk;
  1978. LPSTR psz;
  1979. HGLOBAL hMem;
  1980. kk = (lpcs->dwVideoChunkCount >= CLIPBOARDLOGSIZE) ?
  1981. CLIPBOARDLOGSIZE : nTimerIndex;
  1982. hMem = GlobalAlloc (GHND, (16 * 5 + 2) * kk + 80);
  1983. if (hMem && (psz = GlobalLock (hMem)))
  1984. {
  1985. pTimerRiff->vchd.dwFramesCaptured = lpcs->dwVideoChunkCount;
  1986. pTimerRiff->vchd.dwFramesDropped = lpcs->dwFramesDropped;
  1987. pTimerRiff->cbTotal = sizeof(struct _timerriff) - 8 +
  1988. sizeof(struct _timerstuff) * nTimerIndex;
  1989. pTimerRiff->cbChunk = pTimerRiff->cbTotal - sizeof(*pTimerRiff);
  1990. lstrcpyA(psz, "Slot#, VideoIndex, ExpectedTime, DriverTime, AccumulatedDummyFrames, CurrentAppendedDummies");
  1991. for (ii = 0; ii < kk; ++ii)
  1992. {
  1993. psz += lstrlenA(psz);
  1994. wsprintfA(psz, "\r\n%d, %ld, %ld, %ld, %d, %d",
  1995. ii,
  1996. pTimerStuff[ii].dwVideoChunkCount,
  1997. pTimerStuff[ii].dwFrameTickTime,
  1998. pTimerStuff[ii].dwFrameStampTime,
  1999. pTimerStuff[ii].nDummyFrames,
  2000. pTimerStuff[ii].nFramesAppended
  2001. );
  2002. }
  2003. GlobalUnlock (hMem);
  2004. GlobalUnlock (hMemTimers);
  2005. if (OpenClipboard (lpcs->hwnd))
  2006. {
  2007. EmptyClipboard ();
  2008. SetClipboardData (CF_RIFF, hMemTimers);
  2009. SetClipboardData (CF_TEXT, hMem);
  2010. CloseClipboard ();
  2011. }
  2012. else
  2013. {
  2014. GlobalFree (hMem);
  2015. GlobalFree (hMemTimers);
  2016. }
  2017. }
  2018. else
  2019. {
  2020. // Failed to allocate or lock hMem. Cleanup.
  2021. //
  2022. if (hMem)
  2023. GlobalFree(hMem);
  2024. // Free off the timer block. (We have not set the
  2025. // clipboard data.)
  2026. //
  2027. if (hMemTimers)
  2028. {
  2029. GlobalUnlock(hMemTimers);
  2030. GlobalFree(hMemTimers);
  2031. }
  2032. }
  2033. hMemTimers = NULL;
  2034. pTimerRiff = NULL;
  2035. pTimerStuff = NULL;
  2036. pCurTimerStuff = NULL;
  2037. }
  2038. #endif
  2039. return;
  2040. }
  2041. // Returns TRUE if the capture task was created, or
  2042. // capture completed OK.
  2043. BOOL AVICapture (LPCAPSTREAM lpcs)
  2044. {
  2045. CAPINFOCHUNK cic;
  2046. TCHAR szSMPTE[40];
  2047. void (WINAPI _LOADDS * pfnCapture) (LPCAPSTREAM lpcs);
  2048. if (lpcs->fCaptureFlags & CAP_fCapturingNow)
  2049. return IDS_CAP_VIDEO_OPEN_ERROR;
  2050. // if there is a previous capture thread, wait for it to finish and
  2051. // clean it up
  2052. // -it has set fCapturingNow to FALSE, so it will end 'soon' !
  2053. if (lpcs->hThreadCapture) {
  2054. WaitForSingleObject(lpcs->hThreadCapture, INFINITE);
  2055. CloseHandle(lpcs->hThreadCapture);
  2056. lpcs->hThreadCapture = NULL;
  2057. }
  2058. // Turn off the STOP and ABORT capture bits
  2059. lpcs->fCaptureFlags &= ~(CAP_fStopCapture | CAP_fAbortCapture);
  2060. lpcs->dwReturn = 0;
  2061. #if DONT_CLEAR_SMPTE_JAYBO
  2062. // Prior to Win95, we always cleared out old SMPTE chunks,
  2063. // but since Adobe may have created a chunk manually, don't
  2064. // zap existing chunks.
  2065. cic.fccInfoID = mmioFOURCC ('I','S','M','T');
  2066. cic.lpData = NULL;
  2067. cic.cbData = 0;
  2068. SetInfoChunk (lpcs, &cic);
  2069. #endif
  2070. // And get ready to write a SMPTE info chunk
  2071. if (lpcs->sCapParms.fMCIControl) {
  2072. // create SMPTE string
  2073. TimeMSToSMPTE (lpcs->sCapParms.dwMCIStartTime, (LPTSTR) szSMPTE);
  2074. cic.lpData = szSMPTE;
  2075. cic.cbData = lstrlen (szSMPTE) + 1;
  2076. cic.fccInfoID = mmioFOURCC ('I','S','M','T');
  2077. SetInfoChunk (lpcs, &cic);
  2078. }
  2079. // set pfnCapture to point to the capture function of choice.
  2080. // Use an MCI device to do step capture capture???
  2081. // assume No MCI device, just a normal streaming capture
  2082. //
  2083. pfnCapture = AVICapture1;
  2084. if (lpcs->sCapParms.fStepMCIDevice && lpcs->sCapParms.fMCIControl)
  2085. pfnCapture = MCIStepCapture;
  2086. // if the fYield flag is true, create a thread to do the
  2087. // capture loop. otherwise do the capture loop inline
  2088. //
  2089. if (lpcs->sCapParms.fYield)
  2090. {
  2091. DWORD tid;
  2092. lpcs->hThreadCapture = CreateThread (NULL,
  2093. 0,
  2094. (LPVOID) pfnCapture,
  2095. lpcs,
  2096. 0,
  2097. &tid);
  2098. // if thread creation failed, turn off the capturing flag
  2099. //
  2100. if ( ! lpcs->hThreadCapture)
  2101. lpcs->fCaptureFlags &= ~CAP_fCapturingNow;
  2102. return (lpcs->hThreadCapture != NULL);
  2103. }
  2104. else
  2105. {
  2106. pfnCapture (lpcs);
  2107. return (0 == lpcs->dwReturn);
  2108. }
  2109. }