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.

531 lines
14 KiB

  1. // DCAP16.C
  2. //
  3. // Created 31-Jul-96 [JonT]
  4. #include <windows.h>
  5. #define NODRAWDIB
  6. #define NOCOMPMAN
  7. #define NOAVIFILE
  8. #define NOMSACM
  9. #define NOAVIFMT
  10. #define NOMCIWND
  11. #define NOAVICAP
  12. #include <vfw.h>
  13. #include "..\inc\idcap.h"
  14. #include "..\inc\msviddrv.h"
  15. #define FP_SEG(fp) (*((unsigned *)&(fp) + 1))
  16. #define FP_OFF(fp) (*((unsigned *)&(fp)))
  17. // Equates
  18. #define DCAP16API __far __pascal __loadds
  19. #define DCAP16LOCAL __near __pascal
  20. #define DLL_PROCESS_ATTACH 1 // Not in 16-bit windows.h
  21. #ifdef DEBUG_SPEW_VERBOSE
  22. #define DEBUGSPEW(str) DebugSpew((str))
  23. #else
  24. #define DEBUGSPEW(str)
  25. #endif
  26. // Structures thunked down
  27. typedef struct _CAPTUREPALETTE
  28. {
  29. WORD wVersion;
  30. WORD wcEntries;
  31. PALETTEENTRY pe[256];
  32. } CAPTUREPALETTE, FAR* LPCAPTUREPALETTE;
  33. // Special thunking prototypes
  34. BOOL DCAP16API __export DllEntryPoint(DWORD dwReason,
  35. WORD hInst, WORD wDS, WORD wHeapSize, DWORD dwReserved1,
  36. WORD wReserved2);
  37. BOOL __far __pascal thk_ThunkConnect16(LPSTR pszDll16, LPSTR pszDll32,
  38. WORD hInst, DWORD dwReason);
  39. // Helper functions
  40. WORD DCAP16LOCAL ReturnSel(BOOL fCS);
  41. DWORD DCAP16LOCAL GetVxDEntrypoint(void);
  42. int DCAP16LOCAL SetWin32Event(DWORD dwEvent);
  43. void DCAP16API FrameCallback(HVIDEO hvideo, WORD wMsg, LPLOCKEDINFO lpli,
  44. LPVIDEOHDR lpvh, DWORD dwParam2);
  45. void DCAP16LOCAL ZeroMemory(LPSTR lp, WORD wSize);
  46. // Globals
  47. HANDLE g_hInst;
  48. DWORD g_dwEntrypoint;
  49. LPLOCKEDINFO g_lpli;
  50. // LibMain
  51. int
  52. CALLBACK
  53. LibMain(
  54. HINSTANCE hinst,
  55. WORD wDataSeg,
  56. WORD cbHeapSize,
  57. LPSTR lpszCmdLine
  58. )
  59. {
  60. // Save global hinst
  61. g_hInst = hinst;
  62. // Still necessary?
  63. if (cbHeapSize)
  64. UnlockData(wDataSeg);
  65. return TRUE;
  66. }
  67. // DllEntryPoint
  68. BOOL
  69. __far __pascal __export __loadds
  70. DllEntryPoint(
  71. DWORD dwReason,
  72. WORD hInst,
  73. WORD wDS,
  74. WORD wHeapSize,
  75. DWORD dwReserved1,
  76. WORD wReserved2
  77. )
  78. {
  79. if (!thk_ThunkConnect16("DCAP16.DLL", "DCAP32.DLL", hInst, dwReason))
  80. {
  81. DebugSpew("DllEntrypoint: thk_ThunkConnect16 failed!");
  82. return FALSE;
  83. }
  84. switch (dwReason)
  85. {
  86. case DLL_PROCESS_ATTACH:
  87. g_dwEntrypoint = GetVxDEntrypoint();
  88. break;
  89. }
  90. return TRUE;
  91. }
  92. // APIs
  93. // _InitializeExternalVideoStream
  94. // Initializes a video stream for the external channel. We don't
  95. // have to deal with locking or ever set a callback on this channel.
  96. BOOL
  97. DCAP16API
  98. _InitializeExternalVideoStream(
  99. HANDLE hvideo
  100. )
  101. {
  102. VIDEO_STREAM_INIT_PARMS vsip;
  103. vsip.dwMicroSecPerFrame = 0; // Ignored by driver for this channel
  104. vsip.dwCallback = NULL; // No callback for now
  105. vsip.dwCallbackInst = NULL;
  106. vsip.dwFlags = 0;
  107. vsip.hVideo = (DWORD)hvideo;
  108. return !SendDriverMessage(hvideo, DVM_STREAM_INIT,
  109. (DWORD) (LPVIDEO_STREAM_INIT_PARMS) &vsip,
  110. (DWORD) sizeof (VIDEO_STREAM_INIT_PARMS));
  111. }
  112. void
  113. DCAP16API
  114. FrameCallback(
  115. HVIDEO hvideo,
  116. WORD wMsg,
  117. LPLOCKEDINFO lpli, // Note that this is our instance data
  118. LPVIDEOHDR lpvh,
  119. DWORD dwParam2
  120. )
  121. {
  122. LPCAPBUFFER lpcbuf;
  123. if (!lpli) {
  124. // Connectix hack: driver doesn't pass our instance data, so we keep it global
  125. lpli = g_lpli;
  126. }
  127. // The client can put us in shutdown mode. This means that we will not queue
  128. // any more buffers onto the ready queue, even if they were ready.
  129. // This keeps the buffers from being given back to the driver, so it will eventually
  130. // stop streaming. Of course, it will spew errors, but we just ignore these.
  131. // Shutdown mode is defined when there is no event ready to signal.
  132. if (!lpli->pevWait)
  133. return;
  134. // If it's not a data ready message, just set the event and get out.
  135. // The reason we do this is that if we get behind and start getting a stream
  136. // of MM_DRVM_ERROR messages (usually because we're stopped in the debugger),
  137. // we want to make sure we are getting events so we get restarted to handle
  138. // the frames that are 'stuck.'
  139. if (wMsg != MM_DRVM_DATA)
  140. {
  141. DEBUGSPEW("Setting hcd->hevWait - no data\r\n");
  142. SetWin32Event(lpli->pevWait);
  143. return;
  144. }
  145. //--------------------
  146. // Buffer ready queue:
  147. // We maintain a doubly-linked list of our buffers so that we can buffer up
  148. // multiple ready frames when the app isn't ready to handle them. Two things
  149. // complicate what ought to be a very simple thing: (1) Thunking issues: the pointers
  150. // used on the 16-bit side are 16:16 (2) Interrupt time issues: the FrameCallback
  151. // gets called at interrupt time. GetNextReadyBuffer must handle the fact that
  152. // buffers get added to the list asynchronously.
  153. //
  154. // To handle this, the scheme implemented here is to have a double-linked list
  155. // of buffers with all insertions and deletions happening in FrameCallback
  156. // (interrupt time). This allows the GetNextReadyBuffer routine to simply
  157. // find the previous block on the list any time it needs a new buffer without
  158. // fear of getting tromped (as would be the case if it had to dequeue buffers).
  159. // The FrameCallback routine is responsible to dequeue blocks that GetNextReadyBuffer
  160. // is done with. Dequeueing is simple since we don't need to unlink the blocks:
  161. // no code ever walks the list! All we have to do is move the tail pointer back up
  162. // the list. All the pointers, head, tail, next, prev, are all 16:16 pointers
  163. // since all the list manipulation is on the 16-bit side AND because MapSL is
  164. // much more efficient and safer than MapLS since MapLS has to allocate selectors.
  165. //--------------------
  166. // Move the tail back to skip all buffers already used.
  167. // Note that there is no need to actually unhook the buffer pointers since no one
  168. // ever walks the list!
  169. // This makes STRICT assumptions that the current pointer will always be earlier in
  170. // the list than the tail and that the tail will never be NULL unless the
  171. // current pointer is too.
  172. while (lpli->lp1616Tail != lpli->lp1616Current)
  173. lpli->lp1616Tail = lpli->lp1616Tail->lp1616Prev;
  174. // If all buffers have been used, then the tail pointer will fall off the list.
  175. // This is normal and the most common code path. In this event, just set the head
  176. // to NULL as the list is now empty.
  177. if (!lpli->lp1616Tail)
  178. lpli->lp1616Head = NULL;
  179. // Add the new buffer to the ready queue
  180. lpcbuf = (LPCAPBUFFER)((LPBYTE)lpvh - ((LPBYTE)&lpcbuf->vh - (LPBYTE)lpcbuf));
  181. lpcbuf->lp1616Next = lpli->lp1616Head;
  182. lpcbuf->lp1616Prev = NULL;
  183. if (lpli->lp1616Head)
  184. lpli->lp1616Head->lp1616Prev = lpcbuf;
  185. else
  186. lpli->lp1616Tail = lpcbuf;
  187. lpli->lp1616Head = lpcbuf;
  188. #if 1
  189. if (lpli->lp1616Current) {
  190. if (!(lpli->dwFlags & LIF_STOPSTREAM)) {
  191. // if client hasn't consumed last frame, then release it
  192. lpvh = &lpli->lp1616Current->vh;
  193. lpli->lp1616Current = lpli->lp1616Current->lp1616Prev;
  194. DEBUGSPEW("Sending DVM_STREAM_ADDBUFFER");
  195. // Signal that the application is done with the buffer
  196. lpvh->dwFlags &= ~VHDR_DONE;
  197. if (SendDriverMessage(hvideo, DVM_STREAM_ADDBUFFER, *((DWORD*)&lpvh), sizeof(VIDEOHDR)) != 0)
  198. DebugSpew("attempt to reuse unconsumed buffer failed");
  199. }
  200. }
  201. else {
  202. #else
  203. if (!lpli->lp1616Current) {
  204. // If there was no current buffer before, we have one now, so set it to the end.
  205. #endif
  206. lpli->lp1616Current = lpli->lp1616Tail;
  207. }
  208. // Now set the event saying it's time to process the ready frame
  209. DEBUGSPEW("Setting hcd->hevWait - some data\r\n");
  210. SetWin32Event(lpli->pevWait);
  211. }
  212. // _InitializeVideoStream
  213. // Initializes a driver's video stream for the video in channel.
  214. // This requires us to pagelock the memory for everything that will
  215. // be touched at interrupt time.
  216. BOOL
  217. DCAP16API
  218. _InitializeVideoStream(
  219. HANDLE hvideo,
  220. DWORD dwMicroSecPerFrame,
  221. LPLOCKEDINFO lpli
  222. )
  223. {
  224. DWORD dwRet;
  225. WORD wsel;
  226. VIDEO_STREAM_INIT_PARMS vsip;
  227. ZeroMemory((LPSTR)&vsip, sizeof (VIDEO_STREAM_INIT_PARMS));
  228. vsip.dwMicroSecPerFrame = dwMicroSecPerFrame;
  229. vsip.dwCallback = (DWORD)FrameCallback;
  230. vsip.dwCallbackInst = (DWORD)lpli; // LOCKEDINFO* is instance data for callback
  231. vsip.dwFlags = CALLBACK_FUNCTION;
  232. vsip.hVideo = (DWORD)hvideo;
  233. g_lpli = lpli;
  234. dwRet = SendDriverMessage(hvideo, DVM_STREAM_INIT,
  235. (DWORD) (LPVIDEO_STREAM_INIT_PARMS) &vsip,
  236. (DWORD) sizeof (VIDEO_STREAM_INIT_PARMS));
  237. // If we succeeded, we now lock down our code and data
  238. if (dwRet == 0)
  239. {
  240. // Lock CS
  241. wsel = ReturnSel(TRUE);
  242. GlobalSmartPageLock(wsel);
  243. // Lock DS
  244. wsel = ReturnSel(FALSE);
  245. GlobalSmartPageLock(wsel);
  246. return TRUE;
  247. }
  248. return FALSE;
  249. }
  250. // _UninitializeVideoStream
  251. // Tells the driver we are done streaming. It also unlocks the memory
  252. // we locked for interrupt time access.
  253. BOOL
  254. DCAP16API
  255. _UninitializeVideoStream(
  256. HANDLE hvideo
  257. )
  258. {
  259. DWORD dwRet;
  260. WORD wsel;
  261. dwRet = SendDriverMessage(hvideo, DVM_STREAM_FINI, 0L, 0L);
  262. // Unlock our code and data
  263. if (dwRet == 0)
  264. {
  265. // Unlock CS
  266. wsel = ReturnSel(TRUE);
  267. GlobalSmartPageUnlock(wsel);
  268. // Unlock DS
  269. wsel = ReturnSel(FALSE);
  270. GlobalSmartPageUnlock(wsel);
  271. return TRUE;
  272. }
  273. return FALSE;
  274. }
  275. // _GetVideoPalette
  276. // Get the current palette from the driver
  277. HPALETTE
  278. DCAP16API
  279. _GetVideoPalette(
  280. HANDLE hvideo,
  281. LPCAPTUREPALETTE lpcp,
  282. DWORD dwcbSize
  283. )
  284. {
  285. VIDEOCONFIGPARMS vcp;
  286. vcp.lpdwReturn = NULL;
  287. vcp.lpData1 = (LPVOID)lpcp;
  288. vcp.dwSize1 = dwcbSize;
  289. vcp.lpData2 = NULL;
  290. vcp.dwSize2 = 0;
  291. return !SendDriverMessage(hvideo, DVM_PALETTE,
  292. (DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT),
  293. (DWORD)(LPVIDEOCONFIGPARMS)&vcp);
  294. }
  295. // _GetVideoFormatSize
  296. // Gets the current format header size required by driver
  297. DWORD
  298. DCAP16API
  299. _GetVideoFormatSize(
  300. HANDLE hvideo
  301. )
  302. {
  303. DWORD bufsize;
  304. VIDEOCONFIGPARMS vcp;
  305. vcp.lpdwReturn = &bufsize;
  306. vcp.lpData1 = NULL;
  307. vcp.dwSize1 = 0L;
  308. vcp.lpData2 = NULL;
  309. vcp.dwSize2 = 0L;
  310. #if 0
  311. // it makes sense to query if DVM_FORMAT is available, but not all drivers support it!
  312. if (SendDriverMessage(hvideo, DVM_FORMAT,
  313. (LPARAM)(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERY),
  314. (LPARAM)(LPVOID)&vcp) == DV_ERR_OK) {
  315. #endif
  316. SendDriverMessage(hvideo, DVM_FORMAT,
  317. (LPARAM)(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_QUERYSIZE),
  318. (LPARAM)(LPVOID)&vcp);
  319. if (!bufsize)
  320. bufsize = sizeof(BITMAPINFOHEADER);
  321. return bufsize;
  322. #if 0
  323. } else
  324. return sizeof(BITMAPINFOHEADER);
  325. #endif
  326. }
  327. // _GetVideoFormat
  328. // Gets the current format (dib header) the capture device is blting to
  329. BOOL
  330. DCAP16API
  331. _GetVideoFormat(
  332. HANDLE hvideo,
  333. LPBITMAPINFOHEADER lpbmih
  334. )
  335. {
  336. BOOL res;
  337. VIDEOCONFIGPARMS vcp;
  338. if (!lpbmih->biSize)
  339. lpbmih->biSize = sizeof (BITMAPINFOHEADER);
  340. vcp.lpdwReturn = NULL;
  341. vcp.lpData1 = lpbmih;
  342. vcp.dwSize1 = lpbmih->biSize;
  343. vcp.lpData2 = NULL;
  344. vcp.dwSize2 = 0L;
  345. res = !SendDriverMessage(hvideo, DVM_FORMAT,
  346. (LPARAM)(DWORD)(VIDEO_CONFIGURE_GET | VIDEO_CONFIGURE_CURRENT),
  347. (LPARAM)(LPVOID)&vcp);
  348. if (res) {
  349. // hack for Connectix QuickCam - set format needs to be called
  350. // to set internal globals so that streaming can be enabled
  351. SendDriverMessage(hvideo, DVM_FORMAT, (LPARAM)(DWORD)VIDEO_CONFIGURE_SET,
  352. (LPARAM)(LPVOID)&vcp);
  353. }
  354. return res;
  355. }
  356. // _SetVideoFormat
  357. // Sets the format (dib header) the capture device is blting to.
  358. BOOL
  359. DCAP16API
  360. _SetVideoFormat(
  361. HANDLE hvideoExtIn,
  362. HANDLE hvideoIn,
  363. LPBITMAPINFOHEADER lpbmih
  364. )
  365. {
  366. RECT rect;
  367. VIDEOCONFIGPARMS vcp;
  368. vcp.lpdwReturn = NULL;
  369. vcp.lpData1 = lpbmih;
  370. vcp.dwSize1 = lpbmih->biSize;
  371. vcp.lpData2 = NULL;
  372. vcp.dwSize2 = 0L;
  373. // See if the driver likes the format
  374. if (SendDriverMessage(hvideoIn, DVM_FORMAT, (LPARAM)(DWORD)VIDEO_CONFIGURE_SET,
  375. (LPARAM)(LPVOID)&vcp))
  376. return FALSE;
  377. // Set the rectangles
  378. rect.left = rect.top = 0;
  379. rect.right = (WORD)lpbmih->biWidth;
  380. rect.bottom = (WORD)lpbmih->biHeight;
  381. SendDriverMessage(hvideoExtIn, DVM_DST_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_SET);
  382. SendDriverMessage(hvideoIn, DVM_SRC_RECT, (LPARAM)(LPVOID)&rect, VIDEO_CONFIGURE_SET);
  383. return TRUE;
  384. }
  385. // _AllocateLockableBuffer
  386. // Allocates memory that can be page locked. Just returns the selector.
  387. WORD
  388. DCAP16API
  389. _AllocateLockableBuffer(
  390. DWORD dwSize
  391. )
  392. {
  393. return GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, dwSize);
  394. }
  395. // _LockBuffer
  396. // Page locks (if necessary) a buffer allocated with _AllocateLockableBuffer.
  397. BOOL
  398. DCAP16API
  399. _LockBuffer(
  400. WORD wBuffer
  401. )
  402. {
  403. return GlobalSmartPageLock(wBuffer);
  404. }
  405. // _UnlockBuffer
  406. // Unlocks a buffer locked with _LockBuffer.
  407. void
  408. DCAP16API
  409. _UnlockBuffer(
  410. WORD wBuffer
  411. )
  412. {
  413. GlobalSmartPageUnlock(wBuffer);
  414. }
  415. // _FreeLockableBuffer
  416. // Frees a buffer allocated with _AllocateLockableBuffer.
  417. void
  418. DCAP16API
  419. _FreeLockableBuffer(
  420. WORD wBuffer
  421. )
  422. {
  423. GlobalFree(wBuffer);
  424. }
  425. // _SendDriverMessage
  426. // Sends a generic, dword only parameters, message to the driver channel of choice
  427. DWORD
  428. DCAP16API
  429. _SendDriverMessage(
  430. HVIDEO hvideo,
  431. DWORD wMessage,
  432. DWORD param1,
  433. DWORD param2
  434. )
  435. {
  436. return SendDriverMessage(hvideo, (WORD)wMessage, param1, param2);
  437. }