Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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