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.

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