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.

2320 lines
68 KiB

  1. //
  2. // Created 31-Jul-96 [JonT]
  3. // PhilF-: This needs to be rewritten. You should have two classes
  4. // (CVfWCap & WDMCap) that derive from the same capture class instead
  5. // of those C-like functions...
  6. #include "Precomp.h"
  7. #ifndef WIDTHBYTES
  8. #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4)
  9. #endif
  10. #ifdef _DEBUG
  11. static PTCHAR _rgZonesCap[] = {
  12. TEXT("dcap"),
  13. TEXT("Init"),
  14. TEXT("Streaming"),
  15. TEXT("Callback"),
  16. TEXT("Dialogs"),
  17. TEXT("Trace")
  18. };
  19. #endif
  20. #ifndef __NT_BUILD__
  21. extern "C" {
  22. // Special thunk prototype
  23. BOOL thk_ThunkConnect32(LPSTR pszDll16, LPSTR pszDll32,
  24. HINSTANCE hInst, DWORD dwReason);
  25. //; Magic Function code values for DeviceIOControl code.
  26. //DCAPVXD_THREADTIMESERVICE equ 101h
  27. //DCAPVXD_R0THREADIDSERVICE equ 102h
  28. #define DCAPVXD_THREADTIMESERVICE 0x101
  29. #define DCAPVXD_R0THREADIDSERVICE 0x102
  30. // KERNEL32 prototypes (not in headers but are exported by name on Win95)
  31. void* WINAPI MapSL(DWORD dw1616Ptr);
  32. HANDLE WINAPI OpenVxDHandle(HANDLE h);
  33. }
  34. #endif
  35. // Helper function prototypes
  36. BOOL initializeCaptureDeviceList(void);
  37. HVIDEO openVideoChannel(DWORD dwDeviceID, DWORD dwFlags);
  38. BOOL allocateBuffers(HCAPDEV hcd, int nBuffers);
  39. void freeBuffers(HCAPDEV hcd);
  40. // Globals
  41. HINSTANCE g_hInst;
  42. int g_cDevices;
  43. LPINTERNALCAPDEV g_aCapDevices[DCAP_MAX_DEVICES];
  44. BOOL g_fInitCapDevList;
  45. #define INIT_CAP_DEV_LIST() if (g_fInitCapDevList) { initializeCaptureDeviceList(); }
  46. #ifndef __NT_BUILD__
  47. HANDLE s_hVxD = NULL;
  48. #endif //__NT_BUILD__
  49. // Strings
  50. #ifdef __NT_BUILD__
  51. char g_szVFWRegKey[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32";
  52. char g_szVFWRegDescKey[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\drivers.desc";
  53. char g_szDriverName[] = "MSVIDEOx";
  54. #ifndef SHOW_VFW2WDM_MAPPER
  55. char g_szVfWToWDMMapperDescription[] = "WDM Video For Windows Capture Driver (Win32)";
  56. char g_szVfWToWDMMapperName[] = "VfWWDM32.dll";
  57. #endif
  58. #else
  59. char g_szVFWRegKey[] = "SYSTEM\\CurrentControlSet\\Control\\MediaResources\\msvideo";
  60. char g_szRegDescription[] = "Description";
  61. char g_szRegName[] = "Driver";
  62. char g_szRegDisabled[] = "Disabled";
  63. char g_szDevNode[] = "DevNode";
  64. char g_szSystemIni[] = "system.ini";
  65. char g_szDriverSection[] = "drivers";
  66. char g_szDriverKey[] = "MSVIDEOx";
  67. #ifndef SHOW_VFW2WDM_MAPPER
  68. char g_szVfWToWDMMapperDescription[] = "VfW MM 16bit Driver for WDM V. Cap. Devices";
  69. char g_szVfWToWDMMapperName[] = "vfwwdm.drv";
  70. #endif
  71. #endif
  72. char g_szMSOfficeCamcorderDescription[] = "Screen Capture Device Driver for AVI";
  73. char g_szMSOfficeCamcorderName[] = "Gdicap97.drv";
  74. char g_szVerQueryForDesc[] = "\\StringFileInfo\\040904E4\\FileDescription";
  75. void DoClose(HCAPDEV hcd);
  76. #define ENTER_DCAP(hcd) InterlockedIncrement(&(hcd)->busyCount);
  77. #define LEAVE_DCAP(hcd) if (InterlockedDecrement(&(hcd)->busyCount) == 0) DoClose((hcd));
  78. // DllEntryPoint
  79. extern "C" BOOL
  80. DllEntryPoint(
  81. HINSTANCE hInst,
  82. DWORD dwReason,
  83. LPVOID lpReserved
  84. )
  85. {
  86. static int s_nProcesses = 0;
  87. FX_ENTRY("DllEntryPoint");
  88. #ifndef __NT_BUILD__
  89. // We want to load the VxD even before initializing the thunks
  90. // because the 16-bit half initializes the VxD during the thk_ThunkConnect32 call
  91. if (!s_hVxD)
  92. {
  93. s_hVxD = CreateFile("\\\\.\\DCAPVXD.VXD", 0,0,0,0, FILE_FLAG_DELETE_ON_CLOSE, 0);
  94. if (s_hVxD == INVALID_HANDLE_VALUE)
  95. {
  96. ERRORMESSAGE(("%s: Failure loading VxD - Fatal\r\n", _fx_));
  97. return FALSE;
  98. }
  99. }
  100. // Initialize the thunks
  101. if (!(thk_ThunkConnect32("DCAP16.DLL", "DCAP32.DLL", hInst, dwReason)))
  102. {
  103. ERRORMESSAGE(("%s: thk_ThunkConnect32 failed!\r\n", _fx_));
  104. return FALSE;
  105. }
  106. #endif
  107. switch (dwReason)
  108. {
  109. case DLL_PROCESS_ATTACH:
  110. // Save global hinst
  111. g_hInst = hInst;
  112. // Only initialize on the first DLL load
  113. if (s_nProcesses++ == 0)
  114. {
  115. DBGINIT(&ghDbgZoneCap, _rgZonesCap);
  116. DBG_INIT_MEMORY_TRACKING(hInst);
  117. g_fInitCapDevList = TRUE;
  118. }
  119. else
  120. return FALSE; // fail to load multiple instances
  121. break;
  122. case DLL_PROCESS_DETACH:
  123. if (--s_nProcesses == 0) // Are we going away?
  124. {
  125. #ifndef __NT_BUILD__
  126. CloseHandle(s_hVxD);
  127. s_hVxD = NULL;
  128. #endif
  129. DBG_CHECK_MEMORY_TRACKING(hInst);
  130. DBGDEINIT(&ghDbgZoneCap);
  131. }
  132. break;
  133. }
  134. return TRUE;
  135. }
  136. void GetVersionData (LPINTERNALCAPDEV lpcd)
  137. {
  138. int j;
  139. DWORD dwVerInfoSize;
  140. LPSTR lpstrInfo;
  141. LPSTR lpDesc;
  142. // Version number
  143. // You must find the size first before getting any file info
  144. dwVerInfoSize = GetFileVersionInfoSize(lpcd->szDeviceName, NULL);
  145. if (dwVerInfoSize && (lpstrInfo = (LPSTR)LocalAlloc(LPTR, dwVerInfoSize))) {
  146. // Read from the file into our block
  147. if (GetFileVersionInfo(lpcd->szDeviceName, 0L, dwVerInfoSize, lpstrInfo)) {
  148. lpDesc = NULL;
  149. if (VerQueryValue(lpstrInfo, g_szVerQueryForDesc, (LPVOID *)&lpDesc, (PUINT)&j) && lpDesc) {
  150. lstrcpyn(lpcd->szDeviceDescription, lpDesc, j);
  151. wsprintf(lpcd->szDeviceVersion, TEXT("Version: %d.%d.%d.%d"),
  152. HIWORD(((VS_VERSION *)lpstrInfo)->vffInfo.dwFileVersionMS), LOWORD(((VS_VERSION *)lpstrInfo)->vffInfo.dwFileVersionMS),
  153. HIWORD(((VS_VERSION *)lpstrInfo)->vffInfo.dwFileVersionLS), LOWORD(((VS_VERSION *)lpstrInfo)->vffInfo.dwFileVersionLS));
  154. }
  155. }
  156. LocalFree(lpstrInfo);
  157. }
  158. }
  159. #ifdef __NT_BUILD__
  160. // initializeCaptureDeviceList
  161. // Sets up our static array of available capture devices from the registry
  162. // Returns FALSE iff there are no video devices.
  163. BOOL
  164. initializeCaptureDeviceList(void)
  165. {
  166. HKEY hkeyVFW, hkeyVFWdesc;
  167. DWORD dwType;
  168. DWORD dwSize;
  169. int i;
  170. LPINTERNALCAPDEV lpcd;
  171. HCAPDEV hCapDev;
  172. FX_ENTRY("initializeCaptureDeviceList");
  173. // Clear the entire array and start with zero devices
  174. g_cDevices = 0;
  175. ZeroMemory(g_aCapDevices, sizeof (g_aCapDevices));
  176. // Open the reg key in question
  177. if (RegOpenKey(HKEY_LOCAL_MACHINE, g_szVFWRegKey, &hkeyVFW) == ERROR_SUCCESS)
  178. {
  179. if (RegOpenKey(HKEY_LOCAL_MACHINE, g_szVFWRegDescKey, &hkeyVFWdesc) != ERROR_SUCCESS)
  180. hkeyVFWdesc = 0;
  181. lpcd = (LPINTERNALCAPDEV)LocalAlloc(LPTR, sizeof (INTERNALCAPDEV));
  182. if (lpcd)
  183. {
  184. // Loop through all possible VFW drivers in registry
  185. for (i = 0 ; i < DCAP_MAX_VFW_DEVICES ; i++)
  186. {
  187. // Create the key name
  188. if (i == 0)
  189. g_szDriverName[sizeof (g_szDriverName) - 2] = 0;
  190. else
  191. g_szDriverName[sizeof (g_szDriverName) - 2] = (BYTE)i + '0';
  192. // Name
  193. dwSize = sizeof(lpcd->szDeviceName);
  194. if (RegQueryValueEx(hkeyVFW, g_szDriverName, NULL, &dwType, (LPBYTE)lpcd->szDeviceName, &dwSize) == ERROR_SUCCESS)
  195. {
  196. // Description
  197. if (hkeyVFWdesc)
  198. {
  199. dwSize = sizeof(lpcd->szDeviceDescription);
  200. RegQueryValueEx(hkeyVFWdesc, lpcd->szDeviceName, NULL, &dwType, (LPBYTE)lpcd->szDeviceDescription, &dwSize);
  201. }
  202. else
  203. lstrcpy (lpcd->szDeviceDescription, lpcd->szDeviceName);
  204. // Devnode
  205. lpcd->dwDevNode = 0;
  206. lpcd->nDeviceIndex = g_cDevices;
  207. GetVersionData(lpcd);
  208. #ifndef SHOW_VFW2WDM_MAPPER
  209. // Remove bogus Camcorder capture device from list of devices shown to the user
  210. // The Camcorder driver is a fake capture device used by the MS Office Camcorder
  211. // to capture screen activity to an AVI file. This not a legit capture device driver
  212. // and is extremely buggy.
  213. // We also remove the VfW to WDM mapper if we are on NT5.
  214. if (lstrcmp(lpcd->szDeviceDescription, g_szMSOfficeCamcorderDescription) && lstrcmp(lpcd->szDeviceName, g_szMSOfficeCamcorderName) && lstrcmp(lpcd->szDeviceDescription, g_szVfWToWDMMapperDescription) && lstrcmp(lpcd->szDeviceName, g_szVfWToWDMMapperName))
  215. {
  216. #endif
  217. g_aCapDevices[g_cDevices] = lpcd;
  218. g_aCapDevices[g_cDevices]->nDeviceIndex = g_cDevices;
  219. g_cDevices++;
  220. #ifndef SHOW_VFW2WDM_MAPPER
  221. }
  222. else
  223. LocalFree(lpcd);
  224. #endif
  225. lpcd = (LPINTERNALCAPDEV)LocalAlloc(LPTR, sizeof (INTERNALCAPDEV));
  226. if (!lpcd)
  227. {
  228. ERRORMESSAGE(("%s: Failed to allocate an INTERNALCAPDEV buffer\r\n", _fx_));
  229. break; // break out of the FOR loop
  230. }
  231. }
  232. }
  233. }
  234. else
  235. {
  236. ERRORMESSAGE(("%s: Failed to allocate an INTERNALCAPDEV buffer\r\n", _fx_));
  237. }
  238. if (lpcd)
  239. LocalFree (lpcd); // free the extra buffer
  240. RegCloseKey(hkeyVFW);
  241. if (hkeyVFWdesc)
  242. RegCloseKey(hkeyVFWdesc);
  243. }
  244. #ifndef HIDE_WDM_DEVICES
  245. WDMGetDevices();
  246. #endif
  247. g_fInitCapDevList = FALSE;
  248. return TRUE;
  249. }
  250. #else //__NT_BUILD__
  251. // initializeCaptureDeviceList
  252. // Sets up our static array of available capture devices from the registry and
  253. // from SYSTEM.INI.
  254. // Returns FALSE iff there are no video devices.
  255. BOOL
  256. initializeCaptureDeviceList(void)
  257. {
  258. int i, j, index;
  259. HKEY hkeyVFW;
  260. HKEY hkeyEnum;
  261. DWORD dwType;
  262. DWORD dwSize;
  263. LPINTERNALCAPDEV lpcd;
  264. char szEnumName[MAX_PATH];
  265. char szDisabled[3];
  266. HCAPDEV hCapDev;
  267. OSVERSIONINFO osvInfo = {0};
  268. FX_ENTRY("initializeCaptureDeviceList");
  269. // Clear the entire array and start with zero devices
  270. g_cDevices = 0;
  271. ZeroMemory(g_aCapDevices, sizeof (g_aCapDevices));
  272. // If we are on a version on Win95 (OSRx) use the mapper to talk to WDM devices.
  273. // The WDM drivers used on OSR2 are not stream class minidrivers so we fail
  274. // to handle them properly. Let the mapper do this for us.
  275. osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  276. GetVersionEx(&osvInfo);
  277. // Open the reg key in question
  278. if (RegOpenKey(HKEY_LOCAL_MACHINE, g_szVFWRegKey, &hkeyVFW) == ERROR_SUCCESS)
  279. {
  280. // Loop through all possible VFW drivers in registry
  281. for (i = 0 ; i < DCAP_MAX_VFW_DEVICES ; i++)
  282. {
  283. // See if the key is there and if not, we're done. Note that registry
  284. // keys have to be sequential, no holes allowed since the only way
  285. // to query is sequential...
  286. if (RegEnumKey(hkeyVFW, i, szEnumName, MAX_PATH) != ERROR_SUCCESS ||
  287. RegOpenKey(hkeyVFW, szEnumName, &hkeyEnum) != ERROR_SUCCESS)
  288. break;
  289. lpcd = (LPINTERNALCAPDEV)LocalAlloc(LPTR, sizeof (INTERNALCAPDEV));
  290. if (!lpcd)
  291. {
  292. ERRORMESSAGE(("%s: Failed to allocate an INTERNALCAPDEV buffer\r\n", _fx_));
  293. break; // break from the FOR loop
  294. }
  295. // Description
  296. dwSize = sizeof (lpcd->szDeviceDescription);
  297. RegQueryValueEx(hkeyEnum, g_szRegDescription, NULL, &dwType, (LPBYTE)lpcd->szDeviceDescription, &dwSize);
  298. // Name
  299. dwSize = sizeof (lpcd->szDeviceName);
  300. RegQueryValueEx(hkeyEnum, g_szRegName, NULL, &dwType, (LPBYTE)lpcd->szDeviceName, &dwSize);
  301. // Disabled
  302. dwSize = sizeof (szDisabled);
  303. if (RegQueryValueEx(hkeyEnum, g_szRegDisabled, NULL, &dwType, (LPBYTE)szDisabled, &dwSize) == ERROR_SUCCESS &&
  304. szDisabled[0] == '1')
  305. lpcd->dwFlags |= CAPTURE_DEVICE_DISABLED;
  306. // Devnode
  307. dwSize = sizeof (DWORD);
  308. RegQueryValueEx(hkeyEnum, g_szDevNode, NULL, &dwType, (BYTE*)&lpcd->dwDevNode, &dwSize);
  309. GetVersionData(lpcd);
  310. #ifndef SHOW_VFW2WDM_MAPPER
  311. // Remove bogus Camcorder capture device from list of devices shown to the user
  312. // The Camcorder driver is a fake capture device used by the MS Office Camcorder
  313. // to capture screen activity to an AVI file. This not a legit capture device driver
  314. // and is extremely buggy.
  315. // We also remove the VfW to WDM mapper if we are on Win98. On Win95 we still use
  316. // it to get access to USB devices developed for OSR2.
  317. if ((lstrcmp(lpcd->szDeviceDescription, g_szMSOfficeCamcorderDescription) && lstrcmp(lpcd->szDeviceName, g_szMSOfficeCamcorderName)) && (((osvInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && (osvInfo.dwMinorVersion == 0)) || lstrcmp(lpcd->szDeviceDescription, g_szVfWToWDMMapperDescription) && lstrcmp(lpcd->szDeviceName, g_szVfWToWDMMapperName)))
  318. {
  319. #endif
  320. g_aCapDevices[g_cDevices] = lpcd;
  321. g_aCapDevices[g_cDevices]->nDeviceIndex = g_cDevices;
  322. g_cDevices++;
  323. #ifndef SHOW_VFW2WDM_MAPPER
  324. }
  325. else
  326. LocalFree(lpcd);
  327. #endif
  328. RegCloseKey(hkeyEnum);
  329. }
  330. RegCloseKey(hkeyVFW);
  331. }
  332. // Now get the rest from system.ini, if any
  333. for (i = 0 ; i < DCAP_MAX_VFW_DEVICES ; i++)
  334. {
  335. // Create the key name
  336. if (i == 0)
  337. g_szDriverKey[sizeof (g_szDriverKey) - 2] = 0;
  338. else
  339. g_szDriverKey[sizeof (g_szDriverKey) - 2] = (BYTE)i + '0';
  340. // See if there's a profile string
  341. if (GetPrivateProfileString(g_szDriverSection, g_szDriverKey, "",
  342. szEnumName, MAX_PATH, g_szSystemIni))
  343. {
  344. // First check to see if this is a dupe. If it is, go no further.
  345. if (g_cDevices)
  346. {
  347. for (j = 0 ; j < g_cDevices ; j++)
  348. if (!lstrcmpi(g_aCapDevices[j]->szDeviceName, szEnumName))
  349. goto NextDriver;
  350. }
  351. lpcd = (LPINTERNALCAPDEV)LocalAlloc(LPTR, sizeof (INTERNALCAPDEV));
  352. if (!lpcd)
  353. {
  354. ERRORMESSAGE(("%s: Failed to allocate an INTERNALCAPDEV buffer\r\n", _fx_));
  355. break; // break from the FOR loop
  356. }
  357. // We have a unique name, copy in the driver name and find the description
  358. // by reading the driver's versioninfo resource.
  359. lstrcpy(lpcd->szDeviceName, szEnumName);
  360. GetVersionData(lpcd);
  361. #ifndef SHOW_VFW2WDM_MAPPER
  362. // Remove bogus Camcorder capture device from list of devices shown to the user
  363. // The Camcorder driver is a fake capture device used by the MS Office Camcorder
  364. // to capture screen activity to an AVI file. This not a legit capture device driver
  365. // and is extremely buggy.
  366. // We also remove the VfW to WDM mapper if we are on Win98. On Win95 we still use
  367. // it to get access to USB devices developed for OSR2.
  368. if ((lstrcmp(lpcd->szDeviceDescription, g_szMSOfficeCamcorderDescription) && lstrcmp(lpcd->szDeviceName, g_szMSOfficeCamcorderName)) && (((osvInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) && (osvInfo.dwMinorVersion == 0)) || lstrcmp(lpcd->szDeviceDescription, g_szVfWToWDMMapperDescription) && lstrcmp(lpcd->szDeviceName, g_szVfWToWDMMapperName)))
  369. {
  370. #endif
  371. g_aCapDevices[g_cDevices] = lpcd;
  372. g_aCapDevices[g_cDevices]->nDeviceIndex = g_cDevices;
  373. g_cDevices++;
  374. #ifndef SHOW_VFW2WDM_MAPPER
  375. }
  376. else
  377. LocalFree(lpcd);
  378. #endif
  379. }
  380. NextDriver: ;
  381. }
  382. #ifndef HIDE_WDM_DEVICES
  383. WDMGetDevices();
  384. #endif
  385. g_fInitCapDevList = FALSE;
  386. return TRUE;
  387. }
  388. #endif //__NT_BUILD__
  389. // GetNumCaptureDevice
  390. // Returns the number of *ENABLED* capture devices
  391. /****************************************************************************
  392. * @doc EXTERNAL DCAP32
  393. *
  394. * @func int DCAPI | GetNumCaptureDevices | This function returns the number
  395. * of *ENABLED* capture devices.
  396. *
  397. * @rdesc Returns the number of *ENABLE* capture devices.
  398. ***************************************************************************/
  399. int
  400. DCAPI
  401. GetNumCaptureDevices()
  402. {
  403. int nNumCapDevices = 0;
  404. int nDeviceIndex = 0;
  405. INIT_CAP_DEV_LIST();
  406. while (nDeviceIndex < g_cDevices)
  407. if (!(g_aCapDevices[nDeviceIndex++]->dwFlags & CAPTURE_DEVICE_DISABLED))
  408. nNumCapDevices++;
  409. return nNumCapDevices;
  410. }
  411. // FindFirstCaptureDevice
  412. // Returns the first capture device available that matches the string
  413. // or the first one registered if szDeviceDescription is NULL
  414. BOOL
  415. DCAPI
  416. FindFirstCaptureDevice(
  417. IN OUT FINDCAPTUREDEVICE* lpfcd,
  418. char* szDeviceDescription
  419. )
  420. {
  421. int i;
  422. static HCAPDEV hcap = NULL;
  423. INIT_CAP_DEV_LIST();
  424. // Validate size
  425. if (lpfcd->dwSize != sizeof (FINDCAPTUREDEVICE))
  426. {
  427. SetLastError(ERROR_INVALID_PARAMETER);
  428. return FALSE;
  429. }
  430. // hack to avoid quickcam driver problem when hardware not installed
  431. if (g_cDevices && !hcap) {
  432. for (i = 0; ((i < g_cDevices) && (g_aCapDevices[i]->dwFlags & CAPTURE_DEVICE_DISABLED)); i++);
  433. if ((i < g_cDevices) && (hcap = OpenCaptureDevice(i))) {
  434. CloseCaptureDevice (hcap);
  435. }
  436. else {
  437. if (i < g_cDevices) {
  438. g_aCapDevices[i]->dwFlags |= CAPTURE_DEVICE_DISABLED;
  439. #ifdef _DEBUG
  440. OutputDebugString((i == 0) ? "DCAP32: 1st capture device fails to open!\r\n" : (i == 1) ? "DCAP32: 2nd capture device fails to open!\r\n" : (i == 2) ? "DCAP32: 3rd capture device fails to open!\r\n" : "DCAP32: 4th capture device fails to open!\r\n");
  441. #endif
  442. }
  443. }
  444. }
  445. // Search if necessary
  446. if (szDeviceDescription)
  447. {
  448. for (i = 0 ; i < g_cDevices ; i++)
  449. if (!lstrcmpi(g_aCapDevices[i]->szDeviceDescription, szDeviceDescription) &&
  450. !(g_aCapDevices[i]->dwFlags & CAPTURE_DEVICE_DISABLED))
  451. break;
  452. }
  453. else
  454. for (i = 0; ((i < g_cDevices) && (g_aCapDevices[i]->dwFlags & CAPTURE_DEVICE_DISABLED)); i++);
  455. // Return the info
  456. if (i == g_cDevices)
  457. {
  458. SetLastError(ERROR_FILE_NOT_FOUND);
  459. return FALSE;
  460. }
  461. else {
  462. lpfcd->nDeviceIndex = i;
  463. lstrcpy(lpfcd->szDeviceName, g_aCapDevices[lpfcd->nDeviceIndex]->szDeviceName);
  464. lstrcpy(lpfcd->szDeviceDescription, g_aCapDevices[i]->szDeviceDescription);
  465. lstrcpy(lpfcd->szDeviceVersion, g_aCapDevices[i]->szDeviceVersion);
  466. return TRUE;
  467. }
  468. }
  469. // FindFirstCaptureDeviceByIndex
  470. // Returns the device with the specified index.
  471. BOOL
  472. DCAPI
  473. FindFirstCaptureDeviceByIndex(
  474. IN OUT FINDCAPTUREDEVICE* lpfcd,
  475. int nDeviceIndex
  476. )
  477. {
  478. INIT_CAP_DEV_LIST();
  479. // Validate size and index
  480. if (lpfcd->dwSize != sizeof (FINDCAPTUREDEVICE) ||
  481. nDeviceIndex >= g_cDevices || (nDeviceIndex < 0) ||
  482. (g_aCapDevices[nDeviceIndex]->dwFlags & CAPTURE_DEVICE_DISABLED))
  483. {
  484. SetLastError(ERROR_INVALID_PARAMETER);
  485. return FALSE;
  486. }
  487. // Return the info
  488. lpfcd->nDeviceIndex = nDeviceIndex;
  489. lstrcpy(lpfcd->szDeviceName, g_aCapDevices[lpfcd->nDeviceIndex]->szDeviceName);
  490. lstrcpy(lpfcd->szDeviceDescription, g_aCapDevices[nDeviceIndex]->szDeviceDescription);
  491. lstrcpy(lpfcd->szDeviceVersion, g_aCapDevices[nDeviceIndex]->szDeviceVersion);
  492. return TRUE;
  493. }
  494. // FindNextCaptureDevice
  495. // Returns the next capture device in list.
  496. BOOL
  497. DCAPI
  498. FindNextCaptureDevice(
  499. IN OUT FINDCAPTUREDEVICE* lpfcd
  500. )
  501. {
  502. HCAPDEV hcap = NULL;
  503. INIT_CAP_DEV_LIST();
  504. // Parameter validate the passed in structure
  505. if (lpfcd->dwSize != sizeof (FINDCAPTUREDEVICE))
  506. {
  507. SetLastError(ERROR_INVALID_PARAMETER);
  508. return FALSE;
  509. }
  510. while (++lpfcd->nDeviceIndex < g_cDevices)
  511. {
  512. if ((!(g_aCapDevices[lpfcd->nDeviceIndex]->dwFlags & CAPTURE_DEVICE_DISABLED)))
  513. {
  514. if (g_aCapDevices[lpfcd->nDeviceIndex]->dwFlags & CAPTURE_DEVICE_OPEN)
  515. break;
  516. else
  517. {
  518. if (hcap = OpenCaptureDevice(lpfcd->nDeviceIndex))
  519. {
  520. CloseCaptureDevice (hcap);
  521. break;
  522. }
  523. else
  524. g_aCapDevices[lpfcd->nDeviceIndex]->dwFlags |= CAPTURE_DEVICE_DISABLED;
  525. }
  526. }
  527. }
  528. // See if we're at the end
  529. if (lpfcd->nDeviceIndex >= g_cDevices)
  530. {
  531. SetLastError(ERROR_NO_MORE_FILES);
  532. return FALSE;
  533. }
  534. // Otherwise, fill in the info for the next one
  535. lstrcpy(lpfcd->szDeviceName, g_aCapDevices[lpfcd->nDeviceIndex]->szDeviceName);
  536. lstrcpy(lpfcd->szDeviceDescription, g_aCapDevices[lpfcd->nDeviceIndex]->szDeviceDescription);
  537. lstrcpy(lpfcd->szDeviceVersion, g_aCapDevices[lpfcd->nDeviceIndex]->szDeviceVersion);
  538. return TRUE;
  539. }
  540. // OpenCaptureDevice
  541. HCAPDEV
  542. DCAPI
  543. OpenCaptureDevice(
  544. int nDeviceIndex
  545. )
  546. {
  547. LPINTERNALCAPDEV hcd;
  548. LPBITMAPINFOHEADER lpbmih = NULL;
  549. DWORD err, dwLen;
  550. BOOL fl;
  551. FX_ENTRY("OpenCaptureDevice");
  552. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  553. INIT_CAP_DEV_LIST();
  554. // Validate the device index
  555. if ((unsigned)nDeviceIndex >= (unsigned)g_cDevices ||
  556. (g_aCapDevices[nDeviceIndex]->dwFlags & (CAPTURE_DEVICE_DISABLED | CAPTURE_DEVICE_OPEN))) {
  557. SetLastError(ERROR_INVALID_PARAMETER);
  558. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  559. return NULL;
  560. }
  561. hcd = g_aCapDevices[nDeviceIndex];
  562. hcd->busyCount = 1; // we start at 1 to say that we're open
  563. // DoClose happens when count goes to 0
  564. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  565. {
  566. #ifndef __NT_BUILD__
  567. // Allocate some memory we can lock for the LOCKEDINFO structure
  568. hcd->wselLockedInfo = _AllocateLockableBuffer(sizeof (LOCKEDINFO));
  569. if (!hcd->wselLockedInfo) {
  570. err = ERROR_OUTOFMEMORY;
  571. goto Error;
  572. }
  573. // Do our own thunking so we can track the selector for this buffer
  574. hcd->lpli = (LPLOCKEDINFO)MapSL(((DWORD)hcd->wselLockedInfo) << 16);
  575. #endif
  576. // Open the necessary video channels
  577. if (!(hcd->hvideoIn = openVideoChannel(nDeviceIndex, VIDEO_IN)) ||
  578. !(hcd->hvideoCapture = openVideoChannel(nDeviceIndex, VIDEO_EXTERNALIN)))
  579. {
  580. ERRORMESSAGE(("%s: Couldn't open video channel(s)\r\n", _fx_));
  581. if (hcd->hvideoIn)
  582. _CloseDriver((HDRVR)hcd->hvideoIn, 0, 0);
  583. SetLastError(ERROR_DCAP_DEVICE_IN_USE);
  584. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  585. return FALSE;
  586. }
  587. #ifdef USE_VIDEO_OVERLAY
  588. if (hcd->hvideoOverlay = openVideoChannel(nDeviceIndex, VIDEO_EXTERNALOUT))
  589. {
  590. DEBUGMSG(ZONE_INIT, ("%s: Capture device supports overlay!\r\n", _fx_));
  591. }
  592. else
  593. {
  594. DEBUGMSG(ZONE_INIT, ("%s: Capture device does not support overlay\r\n", _fx_));
  595. }
  596. #endif
  597. }
  598. else
  599. {
  600. if (!WDMOpenDevice(nDeviceIndex))
  601. {
  602. ERRORMESSAGE(("%s: Couldn't open WDM device\r\n", _fx_));
  603. SetLastError(ERROR_DCAP_DEVICE_IN_USE);
  604. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  605. return FALSE;
  606. }
  607. }
  608. hcd->dwFlags |= CAPTURE_DEVICE_OPEN;
  609. // Get the initial format and set the values
  610. dwLen = GetCaptureDeviceFormatHeaderSize(hcd);
  611. if (lpbmih = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, dwLen)) {
  612. lpbmih->biSize = dwLen;
  613. fl = GetCaptureDeviceFormat(hcd, lpbmih);
  614. //If we can't get a format, or height and/or width are 0, don't use this device
  615. if (!fl || lpbmih->biWidth == 0 || lpbmih->biHeight == 0) {
  616. ERRORMESSAGE(("%s: GetCaptureDeviceFormat failed\r\n", _fx_));
  617. err = ERROR_DCAP_NO_DRIVER_SUPPORT;
  618. goto Error;
  619. }
  620. fl = SetCaptureDeviceFormat(hcd, lpbmih, 0, 0);
  621. if (!fl) {
  622. ERRORMESSAGE(("%s: SetCaptureDeviceFormat failed\r\n", _fx_));
  623. err = ERROR_DCAP_NO_DRIVER_SUPPORT;
  624. goto Error;
  625. }
  626. #if 0
  627. _SetCaptureRect(hcd->hvideoIn, DVM_DST_RECT, 0, 0, lpbmih->biWidth, lpbmih->biHeight);
  628. _SetCaptureRect(hcd->hvideoCapture, DVM_SRC_RECT, 0, 0, lpbmih->biWidth, lpbmih->biHeight);
  629. _SetCaptureRect(hcd->hvideoCapture, DVM_DST_RECT, 0, 0, lpbmih->biWidth, lpbmih->biHeight);
  630. #endif
  631. LocalFree((HANDLE)lpbmih);
  632. } else {
  633. err = ERROR_OUTOFMEMORY;
  634. goto Error;
  635. }
  636. // Keep a stream running all the time on EXTERNALIN (capture->frame buffer).
  637. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  638. {
  639. #ifdef USE_VIDEO_OVERLAY
  640. if (hcd->hvideoOverlay)
  641. _InitializeExternalVideoStream(hcd->hvideoOverlay);
  642. #else
  643. _InitializeExternalVideoStream(hcd->hvideoCapture);
  644. #endif
  645. #ifndef __NT_BUILD__
  646. // Lock our structure so it can be touched at interrupt time
  647. _LockBuffer(hcd->wselLockedInfo);
  648. #endif
  649. }
  650. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  651. return hcd;
  652. Error:
  653. hcd->dwFlags &= ~CAPTURE_DEVICE_OPEN;
  654. if (lpbmih) {
  655. LocalFree((HANDLE)lpbmih);
  656. lpbmih = NULL;
  657. }
  658. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  659. {
  660. if (hcd->hvideoIn) {
  661. _CloseDriver((HDRVR)hcd->hvideoIn, 0, 0);
  662. hcd->hvideoIn = NULL;
  663. }
  664. if (hcd->hvideoCapture) {
  665. _CloseDriver((HDRVR)hcd->hvideoCapture, 0, 0);
  666. hcd->hvideoCapture = NULL;
  667. }
  668. #ifdef USE_VIDEO_OVERLAY
  669. if (hcd->hvideoOverlay) {
  670. _CloseDriver((HDRVR)hcd->hvideoOverlay, 0, 0);
  671. hcd->hvideoOverlay = NULL;
  672. }
  673. #endif
  674. }
  675. else
  676. {
  677. WDMCloseDevice(nDeviceIndex);
  678. }
  679. SetLastError(err);
  680. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  681. return NULL;
  682. }
  683. void
  684. DoClose(
  685. HCAPDEV hcd
  686. )
  687. {
  688. FX_ENTRY("DoClose");
  689. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  690. // Clean up streaming on main channel, including freeing all buffers
  691. if (hcd->dwFlags & HCAPDEV_STREAMING_INITIALIZED)
  692. UninitializeStreaming(hcd);
  693. // Stop streaming on the capture channel
  694. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  695. {
  696. #ifdef USE_VIDEO_OVERLAY
  697. if (hcd->hvideoOverlay) {
  698. _SendDriverMessage((HDRVR)hcd->hvideoOverlay, DVM_STREAM_FINI, 0L, 0L);
  699. _CloseDriver((HDRVR)hcd->hvideoOverlay, 0, 0);
  700. hcd->hvideoOverlay = NULL;
  701. }
  702. #else
  703. _SendDriverMessage((HDRVR)hcd->hvideoCapture, DVM_STREAM_FINI, 0L, 0L);
  704. #endif
  705. #ifdef USE_VIDEO_OVERLAY
  706. if (hcd->hvideoOverlay) {
  707. _CloseDriver((HDRVR)hcd->hvideoOverlay, 0, 0);
  708. hcd->hvideoOverlay = NULL;
  709. }
  710. #endif
  711. // Close the driver channels
  712. if (!_CloseDriver((HDRVR)hcd->hvideoCapture, 0, 0) ||
  713. !_CloseDriver((HDRVR)hcd->hvideoIn, 0, 0))
  714. {
  715. SetLastError(ERROR_DCAP_NONSPECIFIC);
  716. ERRORMESSAGE(("%s: Couldn't close channel, error unknown\r\n", _fx_));
  717. // with delayed close this is catastrophic, we can't just return that the device is still
  718. // open, but we can't get the device to close either, so we'll have to just leave it in this
  719. // hung open state - hopefully this never happens...
  720. }
  721. hcd->hvideoCapture = NULL;
  722. hcd->hvideoIn = NULL;
  723. #ifndef __NT_BUILD__
  724. // Free the LOCKEDINFO structure
  725. _FreeLockableBuffer(hcd->wselLockedInfo);
  726. hcd->wselLockedInfo = 0;
  727. #endif
  728. }
  729. else
  730. {
  731. WDMCloseDevice(hcd->nDeviceIndex);
  732. }
  733. hcd->dwFlags &= ~CAPTURE_DEVICE_OPEN;
  734. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  735. }
  736. BOOL
  737. DCAPI
  738. CloseCaptureDevice(
  739. HCAPDEV hcd
  740. )
  741. {
  742. FX_ENTRY("CloseCaptureDevice");
  743. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  744. INIT_CAP_DEV_LIST();
  745. VALIDATE_CAPDEV(hcd);
  746. hcd->dwFlags &= ~CAPTURE_DEVICE_OPEN; // clear flag to disable other API's
  747. LEAVE_DCAP(hcd); // dec our enter count, if no other thread is in a DCAP
  748. // service, then this dec will go to 0 and we'll call
  749. // DoClose; else we won't call DoClose until the other
  750. // active service dec's the count to 0
  751. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  752. return TRUE;
  753. }
  754. DWORD
  755. DCAPI
  756. GetCaptureDeviceFormatHeaderSize(
  757. HCAPDEV hcd
  758. )
  759. {
  760. DWORD res;
  761. INIT_CAP_DEV_LIST();
  762. VALIDATE_CAPDEV(hcd);
  763. ENTER_DCAP(hcd);
  764. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  765. res = _GetVideoFormatSize(reinterpret_cast<HDRVR>(hcd->hvideoIn));
  766. else
  767. res = WDMGetVideoFormatSize(hcd->nDeviceIndex);
  768. LEAVE_DCAP(hcd);
  769. return res;
  770. }
  771. BOOL
  772. DCAPI
  773. GetCaptureDeviceFormat(
  774. HCAPDEV hcd,
  775. LPBITMAPINFOHEADER lpbmih
  776. )
  777. {
  778. BOOL fRes;
  779. FX_ENTRY("GetCaptureDeviceFormat");
  780. INIT_CAP_DEV_LIST();
  781. VALIDATE_CAPDEV(hcd);
  782. ENTER_DCAP(hcd);
  783. // Call the driver to get the bitmap information
  784. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  785. fRes = _GetVideoFormat(hcd->hvideoIn, lpbmih);
  786. else
  787. fRes = WDMGetVideoFormat(hcd->nDeviceIndex, lpbmih);
  788. if (!fRes)
  789. {
  790. // This is DOOM if the driver doesn't support this.
  791. // It might be useful have some sort of fallback code here,
  792. // or else we should try this when the connection is made and
  793. // fail it unless this call works.
  794. ERRORMESSAGE(("%s: Failed to get video format\r\n", _fx_));
  795. SetLastError(ERROR_NOT_SUPPORTED);
  796. LEAVE_DCAP(hcd);
  797. return FALSE;
  798. }
  799. if (lpbmih->biCompression == BI_RGB)
  800. lpbmih->biSizeImage = WIDTHBYTES(lpbmih->biWidth * lpbmih->biBitCount) * lpbmih->biHeight;
  801. // Keep track of current buffer size needed
  802. hcd->dwcbBuffers = sizeof(CAPBUFFERHDR) + lpbmih->biSizeImage;
  803. LEAVE_DCAP(hcd);
  804. return TRUE;
  805. }
  806. BOOL
  807. DCAPI
  808. SetCaptureDeviceFormat(
  809. HCAPDEV hcd,
  810. LPBITMAPINFOHEADER lpbmih,
  811. LONG srcwidth,
  812. LONG srcheight
  813. )
  814. {
  815. BOOL fRes;
  816. #ifdef USE_VIDEO_OVERLAY
  817. RECT rect;
  818. #endif
  819. INIT_CAP_DEV_LIST();
  820. VALIDATE_CAPDEV(hcd);
  821. // Don't allow this if streaming
  822. if (hcd->dwFlags & HCAPDEV_STREAMING)
  823. {
  824. SetLastError(ERROR_DCAP_NOT_WHILE_STREAMING);
  825. return FALSE;
  826. }
  827. ENTER_DCAP(hcd);
  828. // Call the driver to set the format
  829. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  830. {
  831. fRes = _SetVideoFormat(hcd->hvideoCapture, hcd->hvideoIn, lpbmih);
  832. #ifdef USE_VIDEO_OVERLAY
  833. if (fRes && hcd->hvideoOverlay)
  834. {
  835. // Get the current rectangles
  836. _SendDriverMessage((HDRVR)hcd->hvideoOverlay, DVM_DST_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_GET);
  837. DEBUGMSG(ZONE_INIT, ("%s: Current overlay dst rect is rect.left=%ld, rect.top=%ld, rect.right=%ld, rect.bottom=%ld\r\n", _fx_, rect.left, rect.top, rect.right, rect.bottom));
  838. _SendDriverMessage((HDRVR)hcd->hvideoOverlay, DVM_SRC_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_GET);
  839. DEBUGMSG(ZONE_INIT, ("%s: Current overlay src rect is rect.left=%ld, rect.top=%ld, rect.right=%ld, rect.bottom=%ld\r\n", _fx_, rect.left, rect.top, rect.right, rect.bottom));
  840. // Set the rectangles
  841. rect.left = rect.top = 0;
  842. rect.right = (WORD)lpbmih->biWidth;
  843. rect.bottom = (WORD)lpbmih->biHeight;
  844. _SendDriverMessage((HDRVR)hcd->hvideoOverlay, DVM_DST_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_SET);
  845. _SendDriverMessage((HDRVR)hcd->hvideoOverlay, DVM_SRC_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_SET);
  846. if (hcd->hvideoOverlay)
  847. _InitializeExternalVideoStream(hcd->hvideoOverlay);
  848. }
  849. #endif
  850. }
  851. else
  852. fRes = WDMSetVideoFormat(hcd->nDeviceIndex, lpbmih);
  853. if (!fRes)
  854. {
  855. SetLastError(ERROR_DCAP_FORMAT_NOT_SUPPORTED);
  856. LEAVE_DCAP(hcd);
  857. return FALSE;
  858. }
  859. // Cache the bitmap size we're dealing with now
  860. if (lpbmih->biCompression == BI_RGB)
  861. hcd->dwcbBuffers = sizeof (CAPBUFFERHDR) + lpbmih->biWidth * lpbmih->biHeight * lpbmih->biBitCount / 8;
  862. else
  863. hcd->dwcbBuffers = sizeof (CAPBUFFERHDR) + lpbmih->biSizeImage;
  864. LEAVE_DCAP(hcd);
  865. return TRUE;
  866. }
  867. // GetCaptureDevicePalette
  868. // Gets the current palette from the capture device. The entries are returned to
  869. // the caller who normally calls CreatePalette on the structure. It may, however,
  870. // want to translate the palette entries into some preexisting palette or identity
  871. // palette before calling CreatePalette, hence the need for passing back the entries.
  872. BOOL
  873. DCAPI
  874. GetCaptureDevicePalette(
  875. HCAPDEV hcd,
  876. CAPTUREPALETTE* lpcp
  877. )
  878. {
  879. BOOL fRes;
  880. FX_ENTRY("GetCaptureDevicePalette");
  881. INIT_CAP_DEV_LIST();
  882. VALIDATE_CAPDEV(hcd);
  883. ENTER_DCAP(hcd);
  884. // The caller doesn't have to initialize the structure.
  885. // The driver should fill it in, but it may want it preininitialized so we do that here.
  886. lpcp->wVersion = 0x0300;
  887. lpcp->wcEntries = 256;
  888. // Get the palette entries from the driver and return to the user
  889. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  890. fRes = _GetVideoPalette(hcd->hvideoIn, lpcp, sizeof (CAPTUREPALETTE));
  891. else
  892. fRes = WDMGetVideoPalette(hcd->nDeviceIndex, lpcp, sizeof (CAPTUREPALETTE));
  893. if (!fRes)
  894. {
  895. ERRORMESSAGE(("%s: No palette returned from driver\r\n", _fx_));
  896. SetLastError(ERROR_DCAP_NO_DRIVER_SUPPORT);
  897. LEAVE_DCAP(hcd);
  898. return FALSE;
  899. }
  900. LEAVE_DCAP(hcd);
  901. return TRUE;
  902. }
  903. void
  904. TerminateStreaming(
  905. HCAPDEV hcd
  906. )
  907. {
  908. DWORD dwTicks;
  909. LPCAPBUFFER lpcbuf;
  910. DWORD_PTR dwlpvh;
  911. BOOL fRes;
  912. FX_ENTRY("TerminateStreaming");
  913. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  914. StopStreaming(hcd);
  915. if (!(hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB)) {
  916. hcd->dwFlags |= HCAPDEV_STREAMING_PAUSED;
  917. // Make sure we aren't streaming
  918. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  919. {
  920. #ifndef __NT_BUILD__
  921. hcd->lpli->dwFlags |= LIF_STOPSTREAM;
  922. #endif
  923. _SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_RESET, 0, 0);
  924. }
  925. else
  926. WDMVideoStreamReset(hcd->nDeviceIndex);
  927. dwTicks = GetTickCount();
  928. lpcbuf = hcd->lpcbufList;
  929. while (lpcbuf && GetTickCount() < dwTicks + 1000) {
  930. dwlpvh = (DWORD_PTR)lpcbuf->vh.lpData - sizeof(CAPBUFFERHDR);
  931. // 16:16 ptr to vh = 16:16 ptr to data - sizeof(CAPBUFFERHDR)
  932. // 32bit ptr to vh = 32bit ptr to data - sizeof(CAPBUFFERHDR)
  933. if (!(lpcbuf->vh.dwFlags & VHDR_DONE)) {
  934. if (WaitForSingleObject(hcd->hevWait, 500) == WAIT_TIMEOUT) {
  935. ERRORMESSAGE(("%s: Timeout waiting for all buffers done after DVM_STREAM_RESET\r\n", _fx_));
  936. break; // looks like it isn't going to happen, so quit waiting
  937. }
  938. //else recheck done bit on current buffer
  939. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE) && (lpcbuf->vh.dwFlags & VHDR_DONE) && (lpcbuf->vh.dwFlags & VHDR_PREPARED))
  940. {
  941. // AVICap32 clears the prepared flag even if the driver failed the operation - do the same thing
  942. _SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_UNPREPAREHEADER, dwlpvh, sizeof(VIDEOHDR));
  943. lpcbuf->vh.dwFlags &= ~VHDR_PREPARED;
  944. }
  945. }
  946. else
  947. {
  948. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE) && (lpcbuf->vh.dwFlags & VHDR_PREPARED))
  949. {
  950. // AVICap32 clears the prepared flag even if the driver failed the operation - do the same thing
  951. _SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_UNPREPAREHEADER, dwlpvh, sizeof(VIDEOHDR));
  952. lpcbuf->vh.dwFlags &= ~VHDR_PREPARED;
  953. }
  954. lpcbuf = (LPCAPBUFFER)lpcbuf->vh.dwUser; // next buffer
  955. }
  956. }
  957. DEBUGMSG(ZONE_STREAMING, ("%s: Done trying to clear buffers\r\n", _fx_));
  958. // Clean up flags in order to reuse buffers - drivers do not like to be
  959. // given buffers with a dirty dwFlags at the start of streaming...
  960. for (lpcbuf = hcd->lpcbufList ; lpcbuf ; lpcbuf = (LPCAPBUFFER)lpcbuf->vh.dwUser)
  961. lpcbuf->vh.dwFlags = 0;
  962. // Terminate streaming with the driver
  963. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  964. fRes = _UninitializeVideoStream(hcd->hvideoIn);
  965. else
  966. fRes = WDMUnInitializeVideoStream(hcd->nDeviceIndex);
  967. if (!fRes)
  968. {
  969. ERRORMESSAGE(("%s: Error returned from XXXUninitializeVideoStream\r\n", _fx_));
  970. }
  971. }
  972. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  973. }
  974. BOOL
  975. ReinitStreaming(
  976. HCAPDEV hcd
  977. )
  978. {
  979. LPCAPBUFFER lpcbuf;
  980. DWORD_PTR dwlpvh;
  981. BOOL fRes;
  982. FX_ENTRY("ReinitStreaming");
  983. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  984. if (!(hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB)) {
  985. // Tell the driver to prepare for streaming. This sets up the callback
  986. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  987. #ifdef __NT_BUILD__
  988. fRes = _InitializeVideoStream(hcd->hvideoIn, hcd->dw_usecperframe, (DWORD_PTR)hcd);
  989. #else
  990. fRes = _InitializeVideoStream(hcd->hvideoIn, hcd->dw_usecperframe, (DWORD)hcd->wselLockedInfo << 16);
  991. #endif
  992. else
  993. fRes = WDMInitializeVideoStream(hcd, hcd->nDeviceIndex, hcd->dw_usecperframe);
  994. if (!fRes)
  995. {
  996. ERRORMESSAGE(("%s: Error returned from XXXInitializeVideoStream\r\n", _fx_));
  997. SetLastError(ERROR_DCAP_BAD_FRAMERATE);
  998. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  999. return FALSE;
  1000. }
  1001. // Sleep (10);
  1002. hcd->dwFlags &= ~HCAPDEV_STREAMING_PAUSED;
  1003. // If any buffers are not marked DONE, then give them back to the driver; let all
  1004. // DONE buffers get processed by the app first
  1005. for (lpcbuf = hcd->lpcbufList ; lpcbuf ; lpcbuf = (LPCAPBUFFER)lpcbuf->vh.dwUser) {
  1006. if (!(lpcbuf->vh.dwFlags & VHDR_DONE)) {
  1007. dwlpvh = (DWORD_PTR)lpcbuf->vh.lpData - sizeof(CAPBUFFERHDR);
  1008. // 16:16 ptr to vh = 16:16 ptr to data - sizeof(CAPBUFFERHDR)
  1009. // 32bit ptr to vh = 32bit ptr to data - sizeof(CAPBUFFERHDR)
  1010. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1011. {
  1012. // AVICap32 sets the prepared flag even if the driver failed the operation - do the same thing
  1013. _SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_PREPAREHEADER, dwlpvh, sizeof(VIDEOHDR));
  1014. lpcbuf->vh.dwFlags |= VHDR_PREPARED;
  1015. fRes = (_SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_ADDBUFFER, dwlpvh, sizeof(VIDEOHDR)) == DV_ERR_OK);
  1016. }
  1017. else
  1018. fRes = WDMVideoStreamAddBuffer(hcd->nDeviceIndex, (PVOID)dwlpvh);
  1019. if (!fRes)
  1020. {
  1021. DEBUGMSG(ZONE_STREAMING, ("%s: Failed with lpcbuf=0x%08lX, lpcbuf->vh.lpData=0x%08lX, dwlpvh=0x%08lX\r\n", _fx_, lpcbuf, lpcbuf->vh.lpData, dwlpvh));
  1022. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1023. return FALSE;
  1024. }
  1025. else
  1026. {
  1027. DEBUGMSG(ZONE_STREAMING, ("%s: Succeeded with lpcbuf=0x%08lX, lpcbuf->vh.lpData=0x%08lX, dwlpvh=0x%08lX\r\n", _fx_, lpcbuf, lpcbuf->vh.lpData, dwlpvh));
  1028. }
  1029. }
  1030. }
  1031. }
  1032. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1033. return TRUE;
  1034. }
  1035. // CaptureDeviceDialog
  1036. // Puts up one of the driver's dialogs for the user to twiddle.
  1037. // If I can figure out ANY way to avoid this, I will.
  1038. BOOL DCAPI
  1039. CaptureDeviceDialog(
  1040. HCAPDEV hcd,
  1041. HWND hwndParent,
  1042. DWORD dwFlags,
  1043. LPBITMAPINFOHEADER lpbmih //OPTIONAL
  1044. )
  1045. {
  1046. DWORD dwDriverFlags = 0;
  1047. HVIDEO hvid;
  1048. DWORD dwSize;
  1049. LPBITMAPINFOHEADER lpbmihCur;
  1050. #ifdef _DEBUG
  1051. LPBITMAPINFOHEADER lpbmihPre = NULL;
  1052. #endif
  1053. BOOL res = TRUE;
  1054. FX_ENTRY("CaptureDeviceDialog");
  1055. INIT_CAP_DEV_LIST();
  1056. VALIDATE_CAPDEV(hcd);
  1057. if (hcd->dwFlags & HCAPDEV_IN_DRIVER_DIALOG)
  1058. return FALSE; // don't allow re-entering
  1059. ENTER_DCAP(hcd);
  1060. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1061. {
  1062. // See if we are just querying the driver for existence
  1063. if (dwFlags & CAPDEV_DIALOG_QUERY)
  1064. dwDriverFlags |= VIDEO_DLG_QUERY;
  1065. // Select the correct channel to query
  1066. if (dwFlags & CAPDEV_DIALOG_SOURCE) {
  1067. hvid = hcd->hvideoCapture;
  1068. if (!(dwFlags & CAPDEV_DIALOG_QUERY)) {
  1069. dwDriverFlags |= VIDEO_DLG_QUERY;
  1070. if (_SendDriverMessage((HDRVR)hvid, DVM_DIALOG, (DWORD_PTR)hwndParent, dwDriverFlags) == DV_ERR_NOTSUPPORTED) {
  1071. hvid = hcd->hvideoIn;
  1072. }
  1073. dwDriverFlags &= ~VIDEO_DLG_QUERY;
  1074. }
  1075. }
  1076. else
  1077. hvid = hcd->hvideoIn;
  1078. // Don't stop streaming. This make the source dialog totally useless
  1079. // if the user can't see what is going on.
  1080. #ifdef _DEBUG
  1081. if (!lpbmih) {
  1082. dwSize = GetCaptureDeviceFormatHeaderSize(hcd);
  1083. if (lpbmihPre = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, dwSize)) {
  1084. lpbmihPre->biSize = dwSize;
  1085. GetCaptureDeviceFormat(hcd, lpbmihPre);
  1086. }
  1087. lpbmih = lpbmihPre;
  1088. }
  1089. #endif
  1090. // Call the driver
  1091. hcd->dwFlags |= HCAPDEV_IN_DRIVER_DIALOG;
  1092. if (_SendDriverMessage((HDRVR)hvid, DVM_DIALOG, (DWORD_PTR)hwndParent, dwDriverFlags)) {
  1093. SetLastError(ERROR_DCAP_NO_DRIVER_SUPPORT);
  1094. res = FALSE; // restart still ok
  1095. }
  1096. else if (lpbmih) {
  1097. dwSize = GetCaptureDeviceFormatHeaderSize(hcd);
  1098. if (lpbmihCur = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, dwSize)) {
  1099. lpbmihCur->biSize = dwSize;
  1100. GetCaptureDeviceFormat(hcd, lpbmihCur);
  1101. if (lpbmih->biSize != lpbmihCur->biSize ||
  1102. lpbmih->biWidth != lpbmihCur->biWidth ||
  1103. lpbmih->biHeight != lpbmihCur->biHeight ||
  1104. lpbmih->biBitCount != lpbmihCur->biBitCount ||
  1105. lpbmih->biCompression != lpbmihCur->biCompression)
  1106. {
  1107. ERRORMESSAGE(("%s: Format changed in dialog!!\r\n", _fx_));
  1108. #ifdef _DEBUG
  1109. DebugBreak();
  1110. #endif
  1111. // dialog changed format, so try to set it back
  1112. if (!SetCaptureDeviceFormat(hcd, lpbmih, 0, 0)) {
  1113. SetLastError (ERROR_DCAP_DIALOG_FORMAT);
  1114. res = FALSE;
  1115. }
  1116. }
  1117. LocalFree ((HANDLE)lpbmihCur);
  1118. }
  1119. #ifdef _DEBUG
  1120. if (lpbmih == lpbmihPre) {
  1121. LocalFree ((HANDLE)lpbmihPre);
  1122. lpbmih = NULL;
  1123. lpbmihPre = NULL;
  1124. }
  1125. #endif
  1126. }
  1127. hcd->dwFlags &= ~HCAPDEV_IN_DRIVER_DIALOG;
  1128. if (hcd->dwFlags & HCAPDEV_STREAMING) {
  1129. // The Intel Smart Video Recorder Pro stops streaming
  1130. // on exit from the source dialog (!?!?). Make sure
  1131. // we reset the streaming on any kind of device right
  1132. // after we exit the source dialog. I verified this on
  1133. // the CQC, ISVR Pro, Video Stinger and Video Blaster SE100.
  1134. // They all seem to take this pretty well...
  1135. TerminateStreaming(hcd);
  1136. if (ReinitStreaming(hcd))
  1137. StartStreaming(hcd);
  1138. else {
  1139. SetLastError(ERROR_DCAP_DIALOG_STREAM);
  1140. res = FALSE;
  1141. ERRORMESSAGE(("%s: Couldn't reinit streaming after dialog!\r\n", _fx_));
  1142. }
  1143. }
  1144. }
  1145. else
  1146. {
  1147. // See if we are just querying the driver for existence
  1148. if (dwFlags & CAPDEV_DIALOG_QUERY)
  1149. {
  1150. // We only expose a settings dialog
  1151. if (dwFlags & CAPDEV_DIALOG_IMAGE)
  1152. {
  1153. SetLastError(ERROR_DCAP_NO_DRIVER_SUPPORT);
  1154. res = FALSE;
  1155. ERRORMESSAGE(("%s: Driver does not support this dialog!\r\n", _fx_));
  1156. }
  1157. }
  1158. else
  1159. {
  1160. if (!WDMShowSettingsDialog(hcd->nDeviceIndex, hwndParent))
  1161. {
  1162. SetLastError(ERROR_DCAP_NO_DRIVER_SUPPORT);
  1163. res = FALSE;
  1164. ERRORMESSAGE(("%s: Driver does not support this dialog!\r\n", _fx_));
  1165. }
  1166. }
  1167. hcd->dwFlags &= ~HCAPDEV_IN_DRIVER_DIALOG;
  1168. // No need to restart streaming on WDM devices tested so far
  1169. // Will add this feature if problems come up
  1170. }
  1171. LEAVE_DCAP(hcd);
  1172. return res;
  1173. }
  1174. // InitializeStreaming
  1175. // Allocates all memory and other objects necessary for streaming.
  1176. BOOL
  1177. DCAPI
  1178. InitializeStreaming(
  1179. HCAPDEV hcd,
  1180. CAPSTREAM* lpcs,
  1181. DWORD flags
  1182. )
  1183. {
  1184. LPCAPBUFFER lpcbuf;
  1185. DWORD dwRound;
  1186. LPBITMAPINFOHEADER lpbmih;
  1187. BOOL bHaveBuffers = FALSE;
  1188. FX_ENTRY("InitializeStreaming");
  1189. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1190. INIT_CAP_DEV_LIST();
  1191. VALIDATE_CAPDEV(hcd);
  1192. // It doesn't make sense to stream with less than 2 buffers
  1193. if (lpcs->ncCapBuffers < MIN_STREAMING_CAPTURE_BUFFERS ||
  1194. flags & 0xfffffffe ||
  1195. hcd->dwFlags & HCAPDEV_STREAMING_INITIALIZED)
  1196. {
  1197. SetLastError(ERROR_INVALID_PARAMETER);
  1198. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1199. return FALSE;
  1200. }
  1201. ENTER_DCAP(hcd);
  1202. hcd->dwFlags &= ~(HCAPDEV_STREAMING | HCAPDEV_STREAMING_INITIALIZED |
  1203. HCAPDEV_STREAMING_FRAME_GRAB | HCAPDEV_STREAMING_FRAME_TIME | HCAPDEV_STREAMING_PAUSED);
  1204. // Before allocating, make sure we have the current format.
  1205. // This sets our idea of the current size we need for the buffer by
  1206. // setting hcd->dwcbBuffers as a side effect
  1207. dwRound = GetCaptureDeviceFormatHeaderSize(hcd);
  1208. if (lpbmih = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, dwRound)) {
  1209. lpbmih->biSize = dwRound;
  1210. GetCaptureDeviceFormat(hcd, lpbmih);
  1211. LocalFree ((HANDLE)lpbmih);
  1212. } else {
  1213. SetLastError(ERROR_OUTOFMEMORY);
  1214. goto Error;
  1215. }
  1216. // BUGBUG - add logic to determine if we should automatically use FRAME_GRAB mode
  1217. // Try allocating the number asked for
  1218. if (flags & STREAMING_PREFER_FRAME_GRAB) {
  1219. hcd->dwFlags |= HCAPDEV_STREAMING_FRAME_GRAB;
  1220. }
  1221. if (!allocateBuffers(hcd, lpcs->ncCapBuffers))
  1222. {
  1223. SetLastError(ERROR_OUTOFMEMORY);
  1224. goto Error;
  1225. }
  1226. // Create the event we need so we can signal at interrupt time
  1227. if (!(hcd->hevWait = CreateEvent(NULL, FALSE, FALSE, NULL))) {
  1228. ERRORMESSAGE(("%s: CreateEvent failed!\r\n", _fx_));
  1229. SetLastError(ERROR_OUTOFMEMORY);
  1230. goto Error;
  1231. }
  1232. // Init CS used to serialize buffer list management
  1233. InitializeCriticalSection(&hcd->bufferlistCS);
  1234. // We were given frames per second times 100. Converting this to
  1235. // usec per frame is 1/fps * 1,000,000 * 100. Here, do 1/fps * 1,000,000,000
  1236. // to give us an extra digit to do rounding on, then do a final / 10
  1237. hcd->dw_usecperframe = (unsigned)1000000000 / (unsigned)lpcs->nFPSx100;
  1238. dwRound = hcd->dw_usecperframe % 10; // Could have done with one less divide,
  1239. hcd->dw_usecperframe /= 10; // but this is clearer, and this is just
  1240. // an init call...
  1241. if (dwRound >= 5)
  1242. hcd->dw_usecperframe++;
  1243. hcd->lpCurrent = NULL;
  1244. hcd->lpHead = NULL;
  1245. hcd->lpTail = NULL;
  1246. if (hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB) {
  1247. #ifndef __NT_BUILD__
  1248. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1249. hcd->lpli->pevWait = 0;
  1250. #endif
  1251. // link the buffers into the available list
  1252. // start with empty list
  1253. hcd->lpHead = (LPCAPBUFFER)(((LPBYTE)&hcd->lpHead) - sizeof(VIDEOHDR)); // fake CAPBUFFERHDR
  1254. hcd->lpTail = (LPCAPBUFFER)(((LPBYTE)&hcd->lpHead) - sizeof(VIDEOHDR)); // fake CAPBUFFERHDR
  1255. // now insert the buffers
  1256. for (lpcbuf = hcd->lpcbufList ; lpcbuf ; lpcbuf = (LPCAPBUFFER)lpcbuf->vh.dwUser) {
  1257. lpcbuf->lpPrev = hcd->lpTail;
  1258. hcd->lpTail = lpcbuf;
  1259. lpcbuf->lpNext = lpcbuf->lpPrev->lpNext;
  1260. lpcbuf->lpPrev->lpNext = lpcbuf;
  1261. lpcbuf->vh.dwFlags |= VHDR_INQUEUE;
  1262. }
  1263. }
  1264. else
  1265. {
  1266. #ifndef __NT_BUILD__
  1267. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1268. {
  1269. hcd->lpli->pevWait = (DWORD)OpenVxDHandle(hcd->hevWait);
  1270. // Lock down the LOCKEDINFO structure
  1271. if (!_LockBuffer(hcd->wselLockedInfo))
  1272. {
  1273. SetLastError(ERROR_OUTOFMEMORY);
  1274. goto Error;
  1275. }
  1276. hcd->lpli->lp1616Head = 0;
  1277. hcd->lpli->lp1616Tail = 0;
  1278. hcd->lpli->lp1616Current = 0;
  1279. }
  1280. #endif
  1281. if (!ReinitStreaming(hcd))
  1282. goto Error;
  1283. }
  1284. lpcs->hevWait = hcd->hevWait;
  1285. // Flag that streaming is initialized
  1286. hcd->dwFlags |= HCAPDEV_STREAMING_INITIALIZED;
  1287. LEAVE_DCAP(hcd);
  1288. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1289. return TRUE;
  1290. Error:
  1291. freeBuffers(hcd);
  1292. if (hcd->hevWait)
  1293. {
  1294. CloseHandle(hcd->hevWait);
  1295. #ifndef __NT_BUILD__
  1296. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE) && hcd->lpli->pevWait)
  1297. _CloseVxDHandle(hcd->lpli->pevWait);
  1298. #endif
  1299. }
  1300. LEAVE_DCAP(hcd);
  1301. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1302. return FALSE;
  1303. }
  1304. // SetStreamFrameRate
  1305. // Changes the frame rate of a stream initialized channel.
  1306. // PhilF-: This call is not used by NMCAP and NAC. So remove it or
  1307. // start using it.
  1308. BOOL
  1309. DCAPI
  1310. SetStreamFrameRate(
  1311. HCAPDEV hcd,
  1312. int nFPSx100
  1313. )
  1314. {
  1315. DWORD dwNew, dwRound;
  1316. BOOL restart;
  1317. BOOL res = TRUE;
  1318. INIT_CAP_DEV_LIST();
  1319. VALIDATE_CAPDEV(hcd);
  1320. if (!(hcd->dwFlags & HCAPDEV_STREAMING_INITIALIZED))
  1321. {
  1322. // must already have the channel initialized for streaming
  1323. SetLastError(ERROR_INVALID_PARAMETER);
  1324. return FALSE;
  1325. }
  1326. ENTER_DCAP(hcd);
  1327. restart = (hcd->dwFlags & HCAPDEV_STREAMING);
  1328. // We were given frames per second times 100. Converting this to
  1329. // usec per frame is 1/fps * 1,000,000 * 100. Here, do 1/fps * 1,000,000,000
  1330. // to give us an extra digit to do rounding on, then do a final / 10
  1331. dwNew = (unsigned)1000000000 / (unsigned)nFPSx100;
  1332. dwRound = dwNew % 10; // Could have done with one less divide,
  1333. dwNew /= 10; // but this is clearer, and this is just an init call...
  1334. if (dwRound >= 5)
  1335. dwNew++;
  1336. if (dwNew != hcd->dw_usecperframe) {
  1337. TerminateStreaming(hcd);
  1338. hcd->dw_usecperframe = dwNew;
  1339. res = ReinitStreaming(hcd);
  1340. if (restart && res)
  1341. StartStreaming(hcd);
  1342. }
  1343. LEAVE_DCAP(hcd);
  1344. return res;
  1345. }
  1346. // UninitializeStreaming
  1347. // Frees all memory and objects associated with streaming.
  1348. BOOL
  1349. DCAPI
  1350. UninitializeStreaming(
  1351. HCAPDEV hcd
  1352. )
  1353. {
  1354. DWORD dwTicks;
  1355. LPCAPBUFFER lpcbuf;
  1356. FX_ENTRY("UninitializeStreaming");
  1357. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1358. INIT_CAP_DEV_LIST();
  1359. VALIDATE_CAPDEV(hcd);
  1360. if (!(hcd->dwFlags & HCAPDEV_STREAMING_INITIALIZED)) {
  1361. SetLastError(ERROR_INVALID_PARAMETER);
  1362. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1363. return FALSE;
  1364. }
  1365. ENTER_DCAP(hcd);
  1366. TerminateStreaming(hcd);
  1367. #ifndef __NT_BUILD__
  1368. if (!(hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB) && !(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1369. {
  1370. // Unlock our locked structure
  1371. _UnlockBuffer(hcd->wselLockedInfo);
  1372. // Free the event
  1373. _CloseVxDHandle(hcd->lpli->pevWait);
  1374. }
  1375. #endif
  1376. DeleteCriticalSection(&hcd->bufferlistCS);
  1377. CloseHandle(hcd->hevWait);
  1378. // BUGBUG - what about app still owning buffers
  1379. // Loop through freeing all the buffers
  1380. freeBuffers(hcd);
  1381. hcd->dwFlags &= ~(HCAPDEV_STREAMING_INITIALIZED + HCAPDEV_STREAMING_PAUSED);
  1382. LEAVE_DCAP(hcd);
  1383. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1384. return TRUE;
  1385. }
  1386. void
  1387. CALLBACK
  1388. TimeCallback(
  1389. UINT uID,
  1390. UINT uMsg,
  1391. HCAPDEV hcd,
  1392. DWORD dw1,
  1393. DWORD dw2
  1394. )
  1395. {
  1396. hcd->dwFlags |= HCAPDEV_STREAMING_FRAME_TIME; // flag time for a new frame
  1397. SetEvent (hcd->hevWait); // signal client to initiate frame grab
  1398. }
  1399. // StartStreaming
  1400. // Begins streaming.
  1401. BOOL
  1402. DCAPI
  1403. StartStreaming(
  1404. HCAPDEV hcd
  1405. )
  1406. {
  1407. BOOL fRet;
  1408. DWORD dwRet;
  1409. FX_ENTRY("StartStreaming");
  1410. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1411. INIT_CAP_DEV_LIST();
  1412. VALIDATE_CAPDEV(hcd);
  1413. ENTER_DCAP(hcd);
  1414. if (hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB) {
  1415. fRet = ((hcd->timerID = timeSetEvent(hcd->dw_usecperframe/1000, 5,
  1416. (LPTIMECALLBACK)&TimeCallback,
  1417. (DWORD_PTR)hcd, TIME_PERIODIC)) != 0);
  1418. } else {
  1419. int i;
  1420. fRet = FALSE;
  1421. #ifndef __NT_BUILD__
  1422. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1423. hcd->lpli->dwFlags &= ~LIF_STOPSTREAM;
  1424. #endif
  1425. for (i = 0; i < 5; i++) {
  1426. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1427. {
  1428. dwRet = (DWORD)_SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_START, 0, 0);
  1429. fRet = (dwRet == DV_ERR_OK);
  1430. if (dwRet)
  1431. {
  1432. ERRORMESSAGE(("%s: DVM_STREAM_START failed, return code was %ld\r\n", _fx_, dwRet));
  1433. }
  1434. }
  1435. else
  1436. fRet = WDMVideoStreamStart(hcd->nDeviceIndex);
  1437. if (fRet)
  1438. break;
  1439. else if (i > 1)
  1440. Sleep(10);
  1441. }
  1442. }
  1443. if (fRet)
  1444. hcd->dwFlags |= HCAPDEV_STREAMING;
  1445. LEAVE_DCAP(hcd);
  1446. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1447. return fRet;
  1448. }
  1449. // StopStreaming
  1450. // Stops streaming but doesn't free any memory associated with streaming
  1451. // so that it can be restarted with StartStreaming.
  1452. BOOL
  1453. DCAPI
  1454. StopStreaming(
  1455. HCAPDEV hcd
  1456. )
  1457. {
  1458. BOOL fRet;
  1459. FX_ENTRY("StopStreaming");
  1460. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1461. INIT_CAP_DEV_LIST();
  1462. VALIDATE_CAPDEV(hcd);
  1463. ENTER_DCAP(hcd);
  1464. if (hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB) {
  1465. timeKillEvent(hcd->timerID);
  1466. hcd->dwFlags &= ~HCAPDEV_STREAMING;
  1467. // grab CS to ensure that no frame grab is in progress
  1468. EnterCriticalSection(&hcd->bufferlistCS);
  1469. LeaveCriticalSection(&hcd->bufferlistCS);
  1470. fRet = TRUE;
  1471. }
  1472. else
  1473. {
  1474. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1475. fRet = (_SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_STOP, 0, 0) == DV_ERR_OK);
  1476. else
  1477. fRet = WDMVideoStreamStop(hcd->nDeviceIndex);
  1478. }
  1479. if (fRet)
  1480. hcd->dwFlags &= ~HCAPDEV_STREAMING;
  1481. LEAVE_DCAP(hcd);
  1482. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1483. return fRet;
  1484. }
  1485. // GetNextReadyBuffer
  1486. // Called by the app to find the next buffer that has been marked as
  1487. // done by the driver and has data to be displayed.
  1488. LPSTR
  1489. DCAPI
  1490. GetNextReadyBuffer(
  1491. HCAPDEV hcd,
  1492. CAPFRAMEINFO* lpcfi
  1493. )
  1494. {
  1495. LPCAPBUFFER lpcbuf;
  1496. DWORD_PTR dwlpvh;
  1497. BOOL fRet;
  1498. FX_ENTRY("GetNextReadyBuffer");
  1499. INIT_CAP_DEV_LIST();
  1500. ENTER_DCAP(hcd);
  1501. if (hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB) {
  1502. lpcbuf = (LPCAPBUFFER)hcd->lpHead;
  1503. if ((hcd->dwFlags & HCAPDEV_STREAMING_FRAME_TIME) &&
  1504. (lpcbuf != (LPCAPBUFFER)(((LPBYTE)&hcd->lpHead) - sizeof(VIDEOHDR)))) /* fake CAPBUFFERHDR */
  1505. {
  1506. // remove buffer from list
  1507. EnterCriticalSection(&hcd->bufferlistCS);
  1508. hcd->dwFlags &= ~HCAPDEV_STREAMING_FRAME_TIME;
  1509. lpcbuf->lpPrev->lpNext = lpcbuf->lpNext;
  1510. lpcbuf->lpNext->lpPrev = lpcbuf->lpPrev;
  1511. lpcbuf->vh.dwFlags &= ~VHDR_INQUEUE;
  1512. lpcbuf->vh.dwFlags |= VHDR_DONE;
  1513. LeaveCriticalSection(&hcd->bufferlistCS);
  1514. dwlpvh = (DWORD_PTR)lpcbuf->vh.lpData - sizeof(CAPBUFFERHDR);
  1515. // 16:16 ptr to vh = 16:16 ptr to data - sizeof(CAPBUFFERHDR)
  1516. // 32bit ptr to vh = 32bit ptr to data - sizeof(CAPBUFFERHDR)
  1517. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1518. fRet = (SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_FRAME, dwlpvh, sizeof(VIDEOHDR)) == DV_ERR_OK);
  1519. else
  1520. fRet = WDMGetFrame(hcd->nDeviceIndex, (PVOID)dwlpvh);
  1521. if (!fRet)
  1522. {
  1523. // put buffer back into list
  1524. EnterCriticalSection(&hcd->bufferlistCS);
  1525. lpcbuf->lpPrev = hcd->lpTail;
  1526. hcd->lpTail = lpcbuf;
  1527. lpcbuf->lpNext = lpcbuf->lpPrev->lpNext;
  1528. lpcbuf->lpPrev->lpNext = lpcbuf;
  1529. lpcbuf->vh.dwFlags |= VHDR_INQUEUE;
  1530. LeaveCriticalSection(&hcd->bufferlistCS);
  1531. lpcbuf = NULL;
  1532. }
  1533. } else
  1534. lpcbuf = NULL;
  1535. } else {
  1536. #ifdef __NT_BUILD__
  1537. // If the current pointer is NULL, there is no frame ready so bail
  1538. if (!hcd->lpCurrent)
  1539. lpcbuf = NULL;
  1540. else {
  1541. // Get the linear address of the buffer
  1542. lpcbuf = hcd->lpCurrent;
  1543. // Move to the next ready buffer
  1544. hcd->lpCurrent = lpcbuf->lpPrev;
  1545. }
  1546. #else
  1547. //--------------------
  1548. // Buffer ready queue:
  1549. // We maintain a doubly-linked list of our buffers so that we can buffer up
  1550. // multiple ready frames when the app isn't ready to handle them. Two things
  1551. // complicate what ought to be a very simple thing: (1) Thunking issues: the pointers
  1552. // used on the 16-bit side are 16:16 (2) Interrupt time issues: the FrameCallback
  1553. // gets called at interrupt time. GetNextReadyBuffer must handle the fact that
  1554. // buffers get added to the list asynchronously.
  1555. //
  1556. // To handle this, the scheme implemented here is to have a double-linked list
  1557. // of buffers with all insertions and deletions happening in FrameCallback
  1558. // (interrupt time). This allows the GetNextReadyBuffer routine to simply
  1559. // find the previous block on the list any time it needs a new buffer without
  1560. // fear of getting tromped (as would be the case if it had to dequeue buffers).
  1561. // The FrameCallback routine is responsible to dequeue blocks that GetNextReadyBuffer
  1562. // is done with. Dequeueing is simple since we don't need to unlink the blocks:
  1563. // no code ever walks the list! All we have to do is move the tail pointer back up
  1564. // the list. All the pointers, head, tail, next, prev, are all 16:16 pointers
  1565. // since all the list manipulation is on the 16-bit side AND because MapSL is
  1566. // much more efficient and safer than MapLS since MapLS has to allocate selectors.
  1567. //--------------------
  1568. // If the current pointer is NULL, there is no frame ready so bail
  1569. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1570. {
  1571. if (!hcd->lpli->lp1616Current)
  1572. lpcbuf = NULL;
  1573. else {
  1574. // Get the linear address of the buffer
  1575. lpcbuf = (LPCAPBUFFER)MapSL(hcd->lpli->lp1616Current);
  1576. // Move to the next ready buffer
  1577. hcd->lpli->lp1616Current = lpcbuf->lp1616Prev;
  1578. }
  1579. }
  1580. else
  1581. {
  1582. // If the current pointer is NULL, there is no frame ready so bail
  1583. if (!hcd->lpCurrent)
  1584. lpcbuf = NULL;
  1585. else {
  1586. // Get the linear address of the buffer
  1587. lpcbuf = hcd->lpCurrent;
  1588. // Move to the next ready buffer
  1589. hcd->lpCurrent = lpcbuf->lpPrev;
  1590. }
  1591. }
  1592. #endif
  1593. }
  1594. if (!lpcbuf) {
  1595. lpcfi->lpData = NULL;
  1596. DEBUGMSG(ZONE_STREAMING, ("\r\n { %s: Fails with lpcbuf=NULL\r\n", _fx_));
  1597. LEAVE_DCAP(hcd);
  1598. return NULL;
  1599. }
  1600. // Build the CAPFRAMEINFO from the VIDEOHDR information
  1601. lpcfi->lpData = ((LPSTR)lpcbuf) + sizeof(CAPBUFFERHDR);
  1602. lpcfi->dwcbData = lpcbuf->vh.dwBytesUsed;
  1603. lpcfi->dwTimestamp = lpcbuf->vh.dwTimeCaptured;
  1604. lpcfi->dwFlags = 0;
  1605. lpcbuf->lpNext = NULL;
  1606. DEBUGMSG(ZONE_STREAMING, ("\r\n { %s: Succeeded with lpcbuf=0x%08lX\r\n lpcbuf->vh.lpData=0x%08lX\r\n lpcbuf->vh.dwBufferLength=%ld\r\n", _fx_, lpcbuf, lpcbuf->vh.lpData, lpcbuf->vh.dwBufferLength));
  1607. DEBUGMSG(ZONE_STREAMING, (" lpcbuf->vh.dwBytesUsed=%ld\r\n lpcbuf->vh.dwTimeCaptured=%ld\r\n lpcbuf->vh.dwFlags=0x%08lX\r\n", lpcbuf->vh.dwBytesUsed, lpcbuf->vh.dwTimeCaptured, lpcbuf->vh.dwFlags));
  1608. LEAVE_DCAP(hcd);
  1609. return lpcfi->lpData;
  1610. }
  1611. // PutBufferIntoStream
  1612. // When the app is finished using a buffer, it must allow it to be requeued
  1613. // by calling this API.
  1614. BOOL
  1615. DCAPI
  1616. PutBufferIntoStream(
  1617. HCAPDEV hcd,
  1618. BYTE* lpBits
  1619. )
  1620. {
  1621. LPCAPBUFFER lpcbuf;
  1622. DWORD_PTR dwlpvh;
  1623. BOOL res;
  1624. FX_ENTRY("PutBufferIntoStream");
  1625. INIT_CAP_DEV_LIST();
  1626. ENTER_DCAP(hcd);
  1627. // From the CAPFRAMEINFO, find the appropriate CAPBUFFER pointer
  1628. lpcbuf = (LPCAPBUFFER)(lpBits - sizeof(CAPBUFFERHDR));
  1629. DEBUGMSG(ZONE_STREAMING, ("\r\n%s: Returning buffer lpcbuf=0x%08lX\r\n", _fx_, lpcbuf));
  1630. lpcbuf->vh.dwFlags &= ~VHDR_DONE; // mark that app no longer owns buffer
  1631. if (hcd->dwFlags & HCAPDEV_STREAMING_FRAME_GRAB) {
  1632. EnterCriticalSection(&hcd->bufferlistCS);
  1633. lpcbuf->lpPrev = hcd->lpTail;
  1634. hcd->lpTail = lpcbuf;
  1635. lpcbuf->lpNext = lpcbuf->lpPrev->lpNext;
  1636. lpcbuf->lpPrev->lpNext = lpcbuf;
  1637. lpcbuf->vh.dwFlags |= VHDR_INQUEUE;
  1638. res = TRUE;
  1639. LeaveCriticalSection(&hcd->bufferlistCS);
  1640. }
  1641. else if (!(hcd->dwFlags & HCAPDEV_STREAMING_PAUSED)) {
  1642. // if streaming is paused, then just return with the busy bit cleared, we'll add the
  1643. // buffer into the stream in ReinitStreaming
  1644. //
  1645. // if streaming isn't paused, then call the driver to add the buffer
  1646. dwlpvh = (DWORD_PTR)lpcbuf->vh.lpData - sizeof(CAPBUFFERHDR);
  1647. // 16:16 ptr to vh = 16:16 ptr to data - sizeof(CAPBUFFERHDR)
  1648. // 32bit ptr to vh = 32bit ptr to data - sizeof(CAPBUFFERHDR)
  1649. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1650. res = (_SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_STREAM_ADDBUFFER, dwlpvh, sizeof(VIDEOHDR)) == DV_ERR_OK);
  1651. else
  1652. res = WDMVideoStreamAddBuffer(hcd->nDeviceIndex, (PVOID)dwlpvh);
  1653. if (res)
  1654. {
  1655. DEBUGMSG(ZONE_STREAMING, (" } %s: Succeeded with lpcbuf=0x%08lX\r\n lpcbuf->vh.lpData=0x%08lX\r\n dwlpvh=0x%08lX\r\n", _fx_, lpcbuf, lpcbuf->vh.lpData, dwlpvh));
  1656. }
  1657. else
  1658. {
  1659. DEBUGMSG(ZONE_STREAMING, (" } %s: Failed with lpcbuf=0x%08lX\r\n lpcbuf->vh.lpData=0x%08lX\r\n dwlpvh=0x%08lX\r\n", _fx_, lpcbuf, lpcbuf->vh.lpData, dwlpvh));
  1660. }
  1661. }
  1662. LEAVE_DCAP(hcd);
  1663. return res;
  1664. }
  1665. // CaptureFrame
  1666. LPBYTE
  1667. DCAPI
  1668. CaptureFrame(
  1669. HCAPDEV hcd,
  1670. HFRAMEBUF hbuf
  1671. )
  1672. {
  1673. DWORD_PTR dwlpvh;
  1674. LPBYTE lpbuf;
  1675. BOOL fRet;
  1676. FX_ENTRY("CaptureFrame");
  1677. INIT_CAP_DEV_LIST();
  1678. VALIDATE_CAPDEV(hcd);
  1679. ENTER_DCAP(hcd);
  1680. dwlpvh = (DWORD_PTR)hbuf->vh.lpData - sizeof(CAPBUFFERHDR);
  1681. // 16:16 ptr to vh = 16:16 ptr to data - sizeof(CAPBUFFERHDR)
  1682. // 32bit ptr to vh = 32bit ptr to data - sizeof(CAPBUFFERHDR)
  1683. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1684. fRet = (_SendDriverMessage((HDRVR)hcd->hvideoIn, DVM_FRAME, dwlpvh, sizeof(VIDEOHDR)) == DV_ERR_OK);
  1685. else
  1686. fRet = WDMGetFrame(hcd->nDeviceIndex, (PVOID)dwlpvh);
  1687. if (!fRet)
  1688. {
  1689. ERRORMESSAGE(("%s: DVM_FRAME failed!\r\n", _fx_));
  1690. lpbuf = NULL;
  1691. }
  1692. else
  1693. lpbuf = ((LPBYTE)hbuf) + sizeof(CAPBUFFERHDR); // return ptr to buffer immediately following hdr
  1694. LEAVE_DCAP(hcd);
  1695. return lpbuf;
  1696. }
  1697. LPBYTE
  1698. DCAPI
  1699. GetFrameBufferPtr(
  1700. HCAPDEV hcd,
  1701. HFRAMEBUF hbuf
  1702. )
  1703. {
  1704. INIT_CAP_DEV_LIST();
  1705. if (hbuf)
  1706. return ((LPBYTE)hbuf) + sizeof(CAPBUFFERHDR); // return ptr to buffer immediately following hdr
  1707. else
  1708. return NULL;
  1709. }
  1710. HFRAMEBUF
  1711. DCAPI
  1712. AllocFrameBuffer(
  1713. HCAPDEV hcd
  1714. )
  1715. {
  1716. LPCAPBUFFER hbuf = NULL;
  1717. DWORD_PTR dpBuf;
  1718. INIT_CAP_DEV_LIST();
  1719. ENTER_DCAP(hcd);
  1720. #ifdef __NT_BUILD__
  1721. if (dpBuf = (DWORD_PTR)LocalAlloc(LPTR, hcd->dwcbBuffers)) {
  1722. hbuf = (LPCAPBUFFER)dpBuf;
  1723. #else
  1724. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1725. {
  1726. dpBuf = (DWORD)_AllocateLockableBuffer(hcd->dwcbBuffers) << 16;
  1727. hbuf = (LPCAPBUFFER)MapSL(dpBuf);
  1728. }
  1729. else
  1730. {
  1731. dpBuf = (DWORD)LocalAlloc(LPTR, hcd->dwcbBuffers);
  1732. hbuf = (LPCAPBUFFER)dpBuf;
  1733. }
  1734. if (dpBuf) {
  1735. #endif
  1736. // Initialize the VIDEOHDR structure
  1737. hbuf->vh.lpData = (LPBYTE)(dpBuf + sizeof(CAPBUFFERHDR));
  1738. hbuf->vh.dwBufferLength = hcd->dwcbBuffers - sizeof(CAPBUFFERHDR);
  1739. hbuf->vh.dwFlags = 0UL;
  1740. }
  1741. LEAVE_DCAP(hcd);
  1742. return (HFRAMEBUF)hbuf;
  1743. }
  1744. VOID
  1745. DCAPI
  1746. FreeFrameBuffer(
  1747. HCAPDEV hcd,
  1748. HFRAMEBUF hbuf
  1749. )
  1750. {
  1751. INIT_CAP_DEV_LIST();
  1752. if (hbuf)
  1753. {
  1754. ENTER_DCAP(hcd);
  1755. #ifdef __NT_BUILD__
  1756. LocalFree((HANDLE)hbuf);
  1757. #else
  1758. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1759. _FreeLockableBuffer(HIWORD((DWORD)hbuf->vh.lpData));
  1760. else
  1761. LocalFree((HANDLE)hbuf);
  1762. #endif
  1763. LEAVE_DCAP(hcd);
  1764. }
  1765. }
  1766. //=====================================================================
  1767. // Helper functions
  1768. HVIDEO
  1769. openVideoChannel(
  1770. DWORD dwDeviceID,
  1771. DWORD dwFlags
  1772. )
  1773. {
  1774. HVIDEO hvidRet = NULL;
  1775. VIDEO_OPEN_PARMS vop;
  1776. #ifdef __NT_BUILD__
  1777. WCHAR devName[MAX_PATH];
  1778. #else
  1779. #define LPWSTR LPSTR
  1780. #define devName g_aCapDevices[dwDeviceID]->szDeviceName
  1781. #endif
  1782. FX_ENTRY("openVideoChannel");
  1783. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1784. // Validate parameters
  1785. if (!g_cDevices)
  1786. {
  1787. SetLastError(ERROR_DCAP_BAD_INSTALL);
  1788. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1789. return NULL;
  1790. }
  1791. if (dwDeviceID > (DWORD)g_cDevices)
  1792. {
  1793. SetLastError(ERROR_INVALID_PARAMETER);
  1794. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1795. return NULL;
  1796. }
  1797. // Prepare to call the driver
  1798. vop.dwSize = sizeof (VIDEO_OPEN_PARMS);
  1799. vop.fccType = OPEN_TYPE_VCAP;
  1800. vop.fccComp = 0L;
  1801. vop.dwVersion = VIDEOAPIVERSION;
  1802. vop.dwFlags = dwFlags; // In, Out, External In, External Out
  1803. vop.dwError = 0;
  1804. vop.dnDevNode = g_aCapDevices[dwDeviceID]->dwDevNode;
  1805. #ifdef __NT_BUILD__
  1806. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)&(g_aCapDevices[dwDeviceID]->szDeviceName),
  1807. -1, (LPWSTR)devName, MAX_PATH);
  1808. #endif
  1809. hvidRet = (HVIDEO)_OpenDriver((LPWSTR)devName, NULL, (LONG_PTR)&vop);
  1810. #ifndef NO_DRIVER_HACKS
  1811. if (!hvidRet) {
  1812. // backward compatibility hack
  1813. // Some drivers fail to open because of the extra fields that were added to
  1814. // VIDEO_OPEN_PARAMS struct for Win95. Therefore, if the open fails, try
  1815. // decrementing the dwSize field back to VFW1.1 size and try again. Also try
  1816. // decrementing the API version field.
  1817. vop.dwSize -= sizeof(DWORD) + sizeof(LPVOID)*2;
  1818. #if 0
  1819. while (--vop.dwVersion > 2 && !hvidRet)
  1820. #endif
  1821. while (--vop.dwVersion > 0 && !hvidRet)
  1822. hvidRet = (HVIDEO)_OpenDriver((LPWSTR)devName, NULL, (LONG_PTR)&vop);
  1823. }
  1824. #endif //NO_DRIVER_HACKS
  1825. // BUGBUG [JonT] 31-Jul-96
  1826. // Translate error values from DV_ERR_* values
  1827. if (!hvidRet)
  1828. SetLastError(vop.dwError);
  1829. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1830. return hvidRet;
  1831. }
  1832. // allocateBuffers
  1833. BOOL
  1834. allocateBuffers(
  1835. HCAPDEV hcd,
  1836. int nBuffers
  1837. )
  1838. {
  1839. int i;
  1840. LPCAPBUFFER lpcbuf;
  1841. DWORD_PTR dpBuf;
  1842. FX_ENTRY("allocateBuffers");
  1843. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1844. // Try to allocate all they ask for
  1845. for (i = 0 ; i < nBuffers ; i++)
  1846. {
  1847. #ifdef __NT_BUILD__
  1848. if (!(dpBuf = (DWORD_PTR)LocalAlloc(LPTR, hcd->dwcbBuffers)))
  1849. goto Error;
  1850. else
  1851. lpcbuf = (LPCAPBUFFER)dpBuf;
  1852. #else
  1853. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1854. {
  1855. if (!(dpBuf = (DWORD)_AllocateLockableBuffer(hcd->dwcbBuffers) << 16) || !_LockBuffer((WORD)(dpBuf >> 16)))
  1856. goto Error;
  1857. else
  1858. lpcbuf = (LPCAPBUFFER)MapSL(dpBuf);
  1859. }
  1860. else
  1861. {
  1862. if (!(dpBuf = (DWORD)LocalAlloc(LPTR, hcd->dwcbBuffers)))
  1863. goto Error;
  1864. else
  1865. lpcbuf = (LPCAPBUFFER)dpBuf;
  1866. }
  1867. #endif
  1868. // Initialize the VIDEOHDR structure
  1869. lpcbuf->vh.lpData = (LPBYTE)(dpBuf + sizeof(CAPBUFFERHDR));
  1870. lpcbuf->vh.dwUser = (DWORD_PTR)hcd->lpcbufList;
  1871. hcd->lpcbufList = lpcbuf;
  1872. lpcbuf->vh.dwBufferLength = hcd->dwcbBuffers - sizeof(CAPBUFFERHDR);
  1873. lpcbuf->vh.dwFlags = 0UL;
  1874. }
  1875. #ifdef _DEBUG
  1876. // Show buffer map
  1877. DEBUGMSG(ZONE_STREAMING, ("%s: Streaming Buffer map:\r\n", _fx_));
  1878. DEBUGMSG(ZONE_STREAMING, ("Root: hcd->lpcbufList=0x%08lX\r\n", hcd->lpcbufList));
  1879. for (i = 0, lpcbuf=hcd->lpcbufList ; i < nBuffers ; i++, lpcbuf=(LPCAPBUFFER)lpcbuf->vh.dwUser)
  1880. {
  1881. DEBUGMSG(ZONE_STREAMING, ("Buffer[%ld]: lpcbuf=0x%08lX\r\n lpcbuf->vh.lpData=0x%08lX\r\n", i, lpcbuf, lpcbuf->vh.lpData));
  1882. DEBUGMSG(ZONE_STREAMING, (" lpcbuf->vh.dwBufferLength=%ld\r\n lpcbuf->vh.dwBytesUsed=%ld\r\n", lpcbuf->vh.dwBufferLength, lpcbuf->vh.dwBytesUsed));
  1883. DEBUGMSG(ZONE_STREAMING, (" lpcbuf->vh.dwTimeCaptured=%ld\r\n lpcbuf->vh.dwUser=0x%08lX\r\n", lpcbuf->vh.dwTimeCaptured, lpcbuf->vh.dwUser));
  1884. }
  1885. #endif
  1886. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1887. return TRUE;
  1888. // In the error case, we have to get rid of this page locked memory
  1889. Error:
  1890. freeBuffers(hcd);
  1891. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1892. return FALSE;
  1893. }
  1894. // freeBuffers
  1895. void
  1896. freeBuffers(
  1897. HCAPDEV hcd
  1898. )
  1899. {
  1900. LPCAPBUFFER lpcbuf;
  1901. FX_ENTRY("freeBuffers");
  1902. DEBUGMSG(ZONE_CALLS, ("%s() - Begin\r\n", _fx_));
  1903. while (hcd->lpcbufList)
  1904. {
  1905. lpcbuf = hcd->lpcbufList;
  1906. hcd->lpcbufList = (LPCAPBUFFER)lpcbuf->vh.dwUser;
  1907. #ifdef __NT_BUILD__
  1908. LocalFree((HANDLE)lpcbuf);
  1909. #else
  1910. if (!(hcd->dwFlags & WDM_CAPTURE_DEVICE))
  1911. {
  1912. _UnlockBuffer(HIWORD((DWORD)lpcbuf->vh.lpData));
  1913. _FreeLockableBuffer(HIWORD((DWORD)lpcbuf->vh.lpData));
  1914. }
  1915. else
  1916. LocalFree((HANDLE)lpcbuf);
  1917. #endif
  1918. }
  1919. DEBUGMSG(ZONE_CALLS, ("%s() - End\r\n", _fx_));
  1920. }