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.

1109 lines
35 KiB

  1. //==========================================================================;
  2. //
  3. // CWDMCaptureStream - Capture Stream base class implementation
  4. //
  5. // $Date: 22 Feb 1999 15:13:58 $
  6. // $Revision: 1.1 $
  7. // $Author: KLEBANOV $
  8. //
  9. // $Copyright: (c) 1997 - 1998 ATI Technologies Inc. All Rights Reserved. $
  10. //
  11. //==========================================================================;
  12. extern "C"
  13. {
  14. #include "strmini.h"
  15. #include "ksmedia.h"
  16. #include "ddkmapi.h"
  17. }
  18. #include "wdmvdec.h"
  19. #include "wdmdrv.h"
  20. #include "aticonfg.h"
  21. #include "capdebug.h"
  22. #include "defaults.h"
  23. #include "winerror.h"
  24. void CWDMCaptureStream::TimeoutPacket(IN OUT PHW_STREAM_REQUEST_BLOCK pSrb)
  25. {
  26. if (m_KSState == KSSTATE_STOP || !m_pVideoDecoder->PreEventOccurred())
  27. {
  28. DBGTRACE(("Attempting to complete Srbs.\n"));
  29. EmptyIncomingDataSrbQueue();
  30. }
  31. }
  32. void CWDMCaptureStream::Startup(PUINT puiErrorCode)
  33. {
  34. KIRQL Irql;
  35. DBGTRACE(("CWDMCaptureStream::Startup()\n"));
  36. KeInitializeEvent(&m_specialEvent, SynchronizationEvent, FALSE);
  37. KeInitializeEvent(&m_stateTransitionEvent, SynchronizationEvent, FALSE);
  38. KeInitializeEvent(&m_SrbAvailableEvent, SynchronizationEvent, FALSE);
  39. KeInitializeSpinLock(&m_streamDataLock);
  40. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  41. InitializeListHead(&m_incomingDataSrbQueue);
  42. InitializeListHead(&m_waitQueue);
  43. InitializeListHead(&m_reversalQueue);
  44. KeReleaseSpinLock(&m_streamDataLock, Irql);
  45. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  46. ASSERT(m_stateChange == Initializing);
  47. m_stateChange = Starting;
  48. HANDLE threadHandle;
  49. NTSTATUS status = PsCreateSystemThread(&threadHandle,
  50. (ACCESS_MASK) 0L,
  51. NULL,
  52. NULL,
  53. NULL,
  54. (PKSTART_ROUTINE) ThreadStart,
  55. (PVOID) this);
  56. if (status != STATUS_SUCCESS)
  57. {
  58. DBGERROR(("CreateStreamThread failed\n"));
  59. *puiErrorCode = WDMMINI_ERROR_MEMORYALLOCATION;
  60. return;
  61. }
  62. // Don't need this for anything, so might as well close it now.
  63. // The thread will call PsTerminateThread on itself when it
  64. // is done.
  65. ZwClose(threadHandle);
  66. KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
  67. ASSERT(m_stateChange == ChangeComplete);
  68. DBGTRACE(("SrbOpenStream got notification that thread started\n"));
  69. *puiErrorCode = WDMMINI_NOERROR;
  70. }
  71. void CWDMCaptureStream::Shutdown()
  72. {
  73. KIRQL Irql;
  74. DBGTRACE(("CWDMCaptureStream::Shutdown()\n"));
  75. if ( m_stateChange != Initializing )
  76. {
  77. ASSERT(m_stateChange == ChangeComplete);
  78. m_stateChange = Closing;
  79. KeResetEvent(&m_specialEvent);
  80. KeSetEvent(&m_stateTransitionEvent, 0, TRUE);
  81. KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
  82. ASSERT(m_stateChange == ChangeComplete);
  83. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  84. if (!IsListEmpty(&m_incomingDataSrbQueue))
  85. {
  86. TRAP();
  87. }
  88. if (!IsListEmpty(&m_waitQueue))
  89. {
  90. TRAP();
  91. }
  92. KeReleaseSpinLock(&m_streamDataLock, Irql);
  93. }
  94. ReleaseCaptureHandle();
  95. }
  96. void CWDMCaptureStream::ThreadProc()
  97. {
  98. PHW_STREAM_REQUEST_BLOCK pCurrentSrb = NULL;
  99. PSRB_DATA_EXTENSION pSrbExt = NULL;
  100. KEVENT DummyEvent;
  101. const int numEvents = 3;
  102. NTSTATUS status;
  103. // Wo unto you if you overrun this array
  104. PVOID eventArray[numEvents];
  105. KeInitializeEvent(&DummyEvent, SynchronizationEvent, FALSE);
  106. ASSERT(m_stateChange == Starting);
  107. // Indicates to SrbOpenStream() to continue
  108. m_stateChange = ChangeComplete;
  109. KeSetEvent(&m_specialEvent, 0, FALSE);
  110. // These should remain constant the whole time
  111. eventArray[0] = &m_stateTransitionEvent;
  112. eventArray[1] = &m_SrbAvailableEvent;
  113. // eventArray[2] changes, so it is set below
  114. // This runs until the thread terminates itself
  115. // inside of HandleStateTransition
  116. while (1)
  117. {
  118. // May not be necessary
  119. #define ENABLE_TIMEOUT
  120. #ifdef ENABLE_TIMEOUT
  121. LARGE_INTEGER i;
  122. #endif
  123. if (pCurrentSrb == NULL)
  124. {
  125. pSrbExt = (PSRB_DATA_EXTENSION)ExInterlockedRemoveHeadList(&m_waitQueue, &m_streamDataLock);
  126. if (pSrbExt)
  127. {
  128. pCurrentSrb = pSrbExt->pSrb;
  129. eventArray[2] = &pSrbExt->bufferDoneEvent;
  130. }
  131. else
  132. {
  133. #ifdef DEBUG
  134. if (m_KSState == KSSTATE_RUN &&
  135. m_stateChange == ChangeComplete &&
  136. m_pVideoDecoder->PreEventOccurred() == FALSE)
  137. {
  138. static int j;
  139. // Indicates that we are starved for buffers. Probably
  140. // a higher level is not handing them to us in a timely
  141. // fashion for some reason
  142. DBGPRINTF((" S "));
  143. if ((++j % 10) == 0)
  144. {
  145. DBGPRINTF(("\n"));
  146. }
  147. }
  148. #endif
  149. pCurrentSrb = NULL;
  150. eventArray[2] = &DummyEvent;
  151. }
  152. }
  153. #ifdef ENABLE_TIMEOUT
  154. // This is meant mainly as a failsafe measure.
  155. i.QuadPart = -2000000; // 200 ms
  156. #endif
  157. status = KeWaitForMultipleObjects( numEvents, // count
  158. eventArray, // DispatcherObjectArray
  159. WaitAny, // WaitType
  160. Executive, // WaitReason
  161. KernelMode, // WaitMode
  162. FALSE, // Alertable
  163. #ifdef ENABLE_TIMEOUT
  164. &i, // Timeout (Optional)
  165. #else
  166. NULL,
  167. #endif
  168. NULL); // WaitBlockArray (Optional)
  169. switch (status)
  170. {
  171. // State transition. May including killing this very thread
  172. case 0:
  173. if ( pCurrentSrb )
  174. {
  175. ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
  176. pCurrentSrb = NULL;
  177. }
  178. HandleStateTransition();
  179. break;
  180. // New Srb available
  181. case 1:
  182. if ( pCurrentSrb )
  183. {
  184. ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
  185. pCurrentSrb = NULL;
  186. }
  187. if (m_KSState == KSSTATE_RUN && m_stateChange == ChangeComplete)
  188. {
  189. AddBuffersToDirectDraw();
  190. }
  191. break;
  192. // Busmaster complete
  193. case 2:
  194. if ( pCurrentSrb )
  195. {
  196. HandleBusmasterCompletion(pCurrentSrb);
  197. pCurrentSrb = NULL;
  198. }
  199. break;
  200. #ifdef ENABLE_TIMEOUT
  201. // If we timeout in the RUN state, this is our chance to try again
  202. // to add buffers. May not be necessary, since currently, we go
  203. // through a state transition for DOS boxes, etc.
  204. case STATUS_TIMEOUT:
  205. if ( pCurrentSrb )
  206. {
  207. ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
  208. pCurrentSrb = NULL;
  209. }
  210. if (m_KSState == KSSTATE_RUN &&
  211. m_stateChange == ChangeComplete &&
  212. m_pVideoDecoder->PreEventOccurred() == FALSE)
  213. {
  214. AddBuffersToDirectDraw();
  215. }
  216. break;
  217. #endif
  218. default:
  219. TRAP();
  220. break;
  221. }
  222. }
  223. }
  224. VOID STREAMAPI CWDMCaptureStream::VideoReceiveDataPacket(IN PHW_STREAM_REQUEST_BLOCK pSrb)
  225. {
  226. KIRQL Irql;
  227. PSRB_DATA_EXTENSION pSrbExt;
  228. ASSERT(pSrb->Irp->MdlAddress);
  229. DBGINFO(("Receiving SD---- SRB=%x\n", pSrb));
  230. pSrb->Status = STATUS_SUCCESS;
  231. switch (pSrb->Command) {
  232. case SRB_READ_DATA:
  233. // Rule:
  234. // Only accept read requests when in either the Pause or Run
  235. // States. If Stopped, immediately return the SRB.
  236. if ( (m_KSState == KSSTATE_STOP) || ( m_stateChange == Initializing ) ) {
  237. StreamClassStreamNotification( StreamRequestComplete,
  238. pSrb->StreamObject,
  239. pSrb);
  240. break;
  241. }
  242. pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
  243. RtlZeroMemory (pSrbExt, sizeof (SRB_DATA_EXTENSION));
  244. pSrbExt->pSrb = pSrb;
  245. KeInitializeEvent(&pSrbExt->bufferDoneEvent, SynchronizationEvent, FALSE);
  246. DBGINFO(("Adding 0x%x to data queue\n", pSrb));
  247. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  248. InsertTailList(&m_incomingDataSrbQueue, &pSrbExt->srbListEntry);
  249. KeReleaseSpinLock(&m_streamDataLock, Irql);
  250. KeSetEvent(&m_SrbAvailableEvent, 0, FALSE);
  251. break;
  252. default:
  253. //
  254. // invalid / unsupported command. Fail it as such
  255. //
  256. TRAP();
  257. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  258. StreamClassStreamNotification( StreamRequestComplete,
  259. pSrb->StreamObject,
  260. pSrb);
  261. break;
  262. }
  263. }
  264. /*
  265. ** VideoGetProperty()
  266. **
  267. ** Routine to process video property requests
  268. **
  269. ** Arguments:
  270. **
  271. ** pSrb - pointer to the stream request block for properties
  272. **
  273. ** Returns:
  274. **
  275. ** Side Effects: none
  276. */
  277. VOID CWDMCaptureStream::VideoGetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
  278. {
  279. PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
  280. if (IsEqualGUID (KSPROPSETID_Connection, pSPD->Property->Set)) {
  281. VideoStreamGetConnectionProperty (pSrb);
  282. }
  283. else if (IsEqualGUID (PROPSETID_VIDCAP_DROPPEDFRAMES, pSPD->Property->Set)) {
  284. VideoStreamGetDroppedFramesProperty (pSrb);
  285. }
  286. else {
  287. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  288. }
  289. }
  290. /*
  291. ** VideoSetState()
  292. **
  293. ** Sets the current state of the requested stream
  294. **
  295. ** Arguments:
  296. **
  297. ** pSrb - pointer to the stream request block for properties
  298. ** BOOL bVPVBIConnected
  299. ** BOOL bVPConnected
  300. **
  301. ** Returns:
  302. **
  303. ** Side Effects: none
  304. */
  305. VOID CWDMCaptureStream::VideoSetState(PHW_STREAM_REQUEST_BLOCK pSrb, BOOL bVPConnected, BOOL bVPVBIConnected)
  306. {
  307. //
  308. // For each stream, the following states are used:
  309. //
  310. // Stop: Absolute minimum resources are used. No outstanding IRPs.
  311. // Pause: Getting ready to run. Allocate needed resources so that
  312. // the eventual transition to Run is as fast as possible.
  313. // SRBs will be queued at either the Stream class or in your
  314. // driver.
  315. // Run: Streaming.
  316. //
  317. // Moving to Stop or Run ALWAYS transitions through Pause, so that ONLY
  318. // the following transitions are possible:
  319. //
  320. // Stop -> Pause
  321. // Pause -> Run
  322. // Run -> Pause
  323. // Pause -> Stop
  324. //
  325. // Note that it is quite possible to transition repeatedly between states:
  326. // Stop -> Pause -> Stop -> Pause -> Run -> Pause -> Run -> Pause -> Stop
  327. //
  328. BOOL bStreamCondition;
  329. DBGINFO(("CWDMCaptureStream::VideoSetState for stream %d\n", pSrb->StreamObject->StreamNumber));
  330. pSrb->Status = STATUS_SUCCESS;
  331. switch (pSrb->CommandData.StreamState)
  332. {
  333. case KSSTATE_STOP:
  334. DBGINFO((" state KSSTATE_STOP"));
  335. ASSERT(m_stateChange == ChangeComplete);
  336. m_stateChange = Stopping;
  337. FlushBuffers();
  338. KeResetEvent(&m_specialEvent);
  339. KeSetEvent(&m_stateTransitionEvent, 0, TRUE);
  340. KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
  341. ASSERT(m_stateChange == ChangeComplete);
  342. break;
  343. case KSSTATE_ACQUIRE:
  344. DBGINFO((" state KSSTATE_ACQUIRE"));
  345. ASSERT(m_KSState == KSSTATE_STOP);
  346. break;
  347. case KSSTATE_PAUSE:
  348. DBGINFO((" state KSSTATE_PAUSE"));
  349. switch( pSrb->StreamObject->StreamNumber)
  350. {
  351. case STREAM_VideoCapture:
  352. bStreamCondition = bVPConnected;
  353. break;
  354. case STREAM_VBICapture:
  355. bStreamCondition = bVPVBIConnected;
  356. break;
  357. default:
  358. bStreamCondition = FALSE;
  359. break;
  360. }
  361. if( !bStreamCondition)
  362. {
  363. pSrb->Status = STATUS_UNSUCCESSFUL;
  364. }
  365. else
  366. if (m_pVideoDecoder->PreEventOccurred() &&
  367. (m_KSState == KSSTATE_STOP || m_KSState == KSSTATE_ACQUIRE))
  368. {
  369. pSrb->Status = STATUS_UNSUCCESSFUL;
  370. }
  371. else if (m_KSState == KSSTATE_STOP || m_KSState == KSSTATE_ACQUIRE)
  372. {
  373. ResetFrameCounters();
  374. ResetFieldNumber();
  375. if (!GetCaptureHandle())
  376. pSrb->Status = STATUS_UNSUCCESSFUL;
  377. }
  378. else if (m_KSState == KSSTATE_RUN)
  379. {
  380. // Transitioning from run to pause
  381. ASSERT(m_stateChange == ChangeComplete);
  382. m_stateChange = Pausing;
  383. FlushBuffers();
  384. KeResetEvent(&m_specialEvent);
  385. KeSetEvent(&m_stateTransitionEvent, 0, TRUE);
  386. KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
  387. ASSERT(m_stateChange == ChangeComplete);
  388. }
  389. break;
  390. case KSSTATE_RUN:
  391. DBGINFO((" state KSSTATE_RUN"));
  392. ASSERT(m_KSState == KSSTATE_ACQUIRE || m_KSState == KSSTATE_PAUSE);
  393. if (m_pVideoDecoder->PreEventOccurred())
  394. {
  395. pSrb->Status = STATUS_UNSUCCESSFUL;
  396. }
  397. else
  398. {
  399. ResetFieldNumber();
  400. // Transitioning from pause to run
  401. ASSERT(m_stateChange == ChangeComplete);
  402. m_stateChange = Running;
  403. KeResetEvent(&m_specialEvent);
  404. KeSetEvent(&m_stateTransitionEvent, 0, TRUE);
  405. KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
  406. ASSERT(m_stateChange == ChangeComplete);
  407. }
  408. break;
  409. }
  410. if (pSrb->Status == STATUS_SUCCESS) {
  411. m_KSState = pSrb->CommandData.StreamState;
  412. DBGINFO((" entered\n"));
  413. }
  414. else
  415. DBGINFO((" NOT entered ***\n"));
  416. }
  417. VOID CWDMCaptureStream::VideoStreamGetConnectionProperty (PHW_STREAM_REQUEST_BLOCK pSrb)
  418. {
  419. PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
  420. PKSALLOCATOR_FRAMING Framing = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo;
  421. ASSERT(pSPD->Property->Id == KSPROPERTY_CONNECTION_ALLOCATORFRAMING);
  422. if (pSPD->Property->Id == KSPROPERTY_CONNECTION_ALLOCATORFRAMING) {
  423. RtlZeroMemory(Framing, sizeof(KSALLOCATOR_FRAMING));
  424. Framing->RequirementsFlags =
  425. KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY |
  426. KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER |
  427. KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY;
  428. Framing->PoolType = NonPagedPool;
  429. Framing->Frames = NumBuffers;
  430. Framing->FrameSize = GetFrameSize();
  431. Framing->FileAlignment = 0;//FILE_QUAD_ALIGNMENT;// PAGE_SIZE - 1;
  432. pSrb->ActualBytesTransferred = sizeof(KSALLOCATOR_FRAMING);
  433. }
  434. else {
  435. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  436. }
  437. }
  438. /*
  439. ** VideoStreamGetDroppedFramesProperty
  440. **
  441. ** Gets dropped frame information
  442. **
  443. ** Arguments:
  444. **
  445. ** pSrb - pointer to the stream request block for properties
  446. **
  447. ** Returns:
  448. **
  449. ** Side Effects: none
  450. */
  451. VOID CWDMCaptureStream::VideoStreamGetDroppedFramesProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
  452. {
  453. PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;
  454. PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames =
  455. (PKSPROPERTY_DROPPEDFRAMES_CURRENT_S) pSPD->PropertyInfo;
  456. ASSERT(pSPD->Property->Id == KSPROPERTY_DROPPEDFRAMES_CURRENT);
  457. if (pSPD->Property->Id == KSPROPERTY_DROPPEDFRAMES_CURRENT) {
  458. RtlCopyMemory(pDroppedFrames, pSPD->Property, sizeof(KSPROPERTY)); // initialize the unused portion
  459. GetDroppedFrames(pDroppedFrames);
  460. DBGINFO(("PictNumber: 0x%x; DropCount: 0x%x; BufSize: 0x%x\n",
  461. (ULONG) pDroppedFrames->PictureNumber,
  462. (ULONG) pDroppedFrames->DropCount,
  463. (ULONG) pDroppedFrames->AverageFrameSize));
  464. pSrb->ActualBytesTransferred = sizeof (KSPROPERTY_DROPPEDFRAMES_CURRENT_S);
  465. }
  466. else {
  467. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  468. }
  469. }
  470. VOID CWDMCaptureStream::CloseCapture()
  471. {
  472. DBGTRACE(("DDNOTIFY_CLOSECAPTURE; stream = %d\n", m_pStreamObject->StreamNumber));
  473. m_hCapture = 0;
  474. }
  475. VOID CWDMCaptureStream::EmptyIncomingDataSrbQueue()
  476. {
  477. KIRQL Irql;
  478. PKSSTREAM_HEADER pDataPacket;
  479. if ( m_stateChange == Initializing )
  480. {
  481. return; // queue not setup yet, so we can return knowing that nothing is in the queue
  482. }
  483. // Think about replacing with ExInterlockedRemoveHeadList.
  484. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  485. while (!IsListEmpty(&m_incomingDataSrbQueue))
  486. {
  487. PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)RemoveHeadList(&m_incomingDataSrbQueue);
  488. PHW_STREAM_REQUEST_BLOCK pSrb = pSrbExt->pSrb;
  489. pSrb->Status = STATUS_SUCCESS;
  490. pDataPacket = pSrb->CommandData.DataBufferArray;
  491. pDataPacket->DataUsed = 0;
  492. KeReleaseSpinLock(&m_streamDataLock, Irql);
  493. DBGINFO(("Completing Srb 0x%x in STATE_STOP\n", pSrb));
  494. StreamClassStreamNotification( StreamRequestComplete,
  495. pSrb->StreamObject,
  496. pSrb);
  497. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  498. }
  499. KeReleaseSpinLock(&m_streamDataLock, Irql);
  500. }
  501. BOOL CWDMCaptureStream::ReleaseCaptureHandle()
  502. {
  503. int streamNumber = m_pStreamObject->StreamNumber;
  504. DWORD ddOut = DD_OK;
  505. DDCLOSEHANDLE ddClose;
  506. if (m_hCapture != 0)
  507. {
  508. DBGTRACE(("Stream %d releasing capture handle\n", streamNumber));
  509. ddClose.hHandle = m_hCapture;
  510. DxApi(DD_DXAPI_CLOSEHANDLE, &ddClose, sizeof(ddClose), &ddOut, sizeof(ddOut));
  511. if (ddOut != DD_OK)
  512. {
  513. DBGERROR(("DD_DXAPI_CLOSEHANDLE failed.\n"));
  514. TRAP();
  515. return FALSE;
  516. }
  517. m_hCapture = 0;
  518. }
  519. return TRUE;
  520. }
  521. VOID CWDMCaptureStream::HandleBusmasterCompletion(PHW_STREAM_REQUEST_BLOCK pCurrentSrb)
  522. {
  523. int streamNumber = m_pStreamObject->StreamNumber;
  524. PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pCurrentSrb->SRBExtension;
  525. KIRQL Irql;
  526. // This function is called as a result of DD completing a BM. That means
  527. // m_stateChange will not be in the Initializing state for sure
  528. // First handle case where we get a Busmaster completion
  529. // indication while we are trying to pause or stop
  530. if (m_stateChange == Pausing || m_stateChange == Stopping)
  531. {
  532. PUCHAR ptr;
  533. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  534. // Put it at the head of the temporary 'reversal' queue.
  535. InsertHeadList(&m_reversalQueue, &pSrbExt->srbListEntry);
  536. if (IsListEmpty(&m_waitQueue))
  537. {
  538. // if there is nothing left in the wait queue we can now
  539. // proceed to move everything back to the incoming queue.
  540. // This whole ugly ordeal is to
  541. // make sure that they end up in the original order
  542. while (!IsListEmpty(&m_reversalQueue))
  543. {
  544. ptr = (PUCHAR)RemoveHeadList(&m_reversalQueue);
  545. InsertHeadList(&m_incomingDataSrbQueue, (PLIST_ENTRY) ptr);
  546. }
  547. KeReleaseSpinLock(&m_streamDataLock, Irql);
  548. if (m_stateChange == Stopping)
  549. {
  550. EmptyIncomingDataSrbQueue();
  551. }
  552. // Indicate that we have successfully completed this part
  553. // of the transition to the pause state.
  554. m_stateChange = ChangeComplete;
  555. KeSetEvent(&m_specialEvent, 0, FALSE);
  556. return;
  557. }
  558. KeReleaseSpinLock(&m_streamDataLock, Irql);
  559. return;
  560. }
  561. // else it is a regular busmaster completion while in the run state
  562. else
  563. {
  564. ASSERT (pCurrentSrb);
  565. PKSSTREAM_HEADER pDataPacket = pCurrentSrb->CommandData.DataBufferArray;
  566. pDataPacket->OptionsFlags = 0;
  567. pSrbExt = (PSRB_DATA_EXTENSION)pCurrentSrb->SRBExtension;
  568. DBGINFO(("FieldNum: %d; ddRVal: 0x%x; polarity: 0x%x\n",
  569. pSrbExt->ddCapBuffInfo.dwFieldNumber,
  570. pSrbExt->ddCapBuffInfo.ddRVal,
  571. pSrbExt->ddCapBuffInfo.bPolarity));
  572. // It's possible that the srb got cancelled while we were waiting.
  573. // Currently, this status is reset below
  574. if (pCurrentSrb->Status == STATUS_CANCELLED)
  575. {
  576. DBGINFO(("pCurrentSrb 0x%x was cancelled while we were waiting\n", pCurrentSrb));
  577. pDataPacket->DataUsed = 0;
  578. }
  579. // It's also possible that there was a problem in DD-land
  580. else if (pSrbExt->ddCapBuffInfo.ddRVal != DD_OK)
  581. {
  582. // Two cases of which I am aware.
  583. // 1) flushed buffers
  584. if (pSrbExt->ddCapBuffInfo.ddRVal == E_FAIL)
  585. {
  586. DBGINFO(("ddRVal = 0x%x. Assuming we flushed\n", pSrbExt->ddCapBuffInfo.ddRVal));
  587. pDataPacket->DataUsed = 0;
  588. }
  589. // 2) something else
  590. else
  591. {
  592. DBGERROR(("= 0x%x. Problem in Busmastering?\n", pSrbExt->ddCapBuffInfo.ddRVal));
  593. pDataPacket->DataUsed = 0;
  594. }
  595. }
  596. // There is also the remote possibility that everything is OK
  597. else
  598. {
  599. SetFrameInfo(pCurrentSrb);
  600. TimeStampSrb(pCurrentSrb);
  601. pDataPacket->DataUsed = pDataPacket->FrameExtent;
  602. }
  603. DBGINFO(("StreamRequestComplete for SRB 0x%x\n", pCurrentSrb));
  604. // Always return success. Failure
  605. // is indicated by setting DataUsed to 0.
  606. pCurrentSrb->Status = STATUS_SUCCESS;
  607. ASSERT(pCurrentSrb->Irp->MdlAddress);
  608. StreamClassStreamNotification( StreamRequestComplete,
  609. pCurrentSrb->StreamObject,
  610. pCurrentSrb);
  611. }
  612. }
  613. void CWDMCaptureStream::AddBuffersToDirectDraw()
  614. {
  615. KIRQL Irql;
  616. BOOL fAdded;
  617. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  618. while (!IsListEmpty(&m_incomingDataSrbQueue))
  619. {
  620. // So if we've reached this point, we are in the run state, and
  621. // we have an SRB on our incoming queue, and we are holding the
  622. // the stream lock
  623. PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)RemoveHeadList(&m_incomingDataSrbQueue);
  624. PHW_STREAM_REQUEST_BLOCK pSrb = pSrbExt->pSrb;
  625. // Calls to DXAPI must be at Passive level, so release the spinlock temporarily
  626. KeReleaseSpinLock(&m_streamDataLock, Irql);
  627. DBGINFO(("Removed 0x%x from data queue\n", pSrb));
  628. fAdded = AddBuffer(pSrb);
  629. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  630. if (fAdded)
  631. {
  632. DBGINFO(("Adding 0x%x to wait queue\n", pSrb));
  633. InsertTailList(&m_waitQueue, &pSrbExt->srbListEntry);
  634. }
  635. else
  636. {
  637. DBGINFO(("Adding 0x%x back to dataqueue\n", pSrb));
  638. // put it back where it was
  639. InsertHeadList(&m_incomingDataSrbQueue, &pSrbExt->srbListEntry);
  640. break;
  641. }
  642. }
  643. KeReleaseSpinLock(&m_streamDataLock, Irql);
  644. }
  645. BOOL CWDMCaptureStream::AddBuffer(PHW_STREAM_REQUEST_BLOCK pSrb)
  646. {
  647. DDADDVPCAPTUREBUFF ddAddVPCaptureBuffIn;
  648. DWORD ddOut = DD_OK;
  649. PIRP irp = pSrb->Irp;
  650. PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
  651. DBGINFO(("In AddBuffer. pSrb: 0x%x.\n", pSrb));
  652. // For handling full-screen DOS, res changes, etc.
  653. if (m_hCapture == 0)
  654. {
  655. if (!GetCaptureHandle())
  656. {
  657. return FALSE;
  658. }
  659. }
  660. ddAddVPCaptureBuffIn.hCapture = m_hCapture;
  661. ddAddVPCaptureBuffIn.dwFlags = DDADDBUFF_SYSTEMMEMORY;
  662. ddAddVPCaptureBuffIn.pMDL = irp->MdlAddress;
  663. ddAddVPCaptureBuffIn.lpBuffInfo = &pSrbExt->ddCapBuffInfo;
  664. ddAddVPCaptureBuffIn.pKEvent = &pSrbExt->bufferDoneEvent;
  665. DxApi(DD_DXAPI_ADDVPCAPTUREBUFFER, &ddAddVPCaptureBuffIn, sizeof(ddAddVPCaptureBuffIn), &ddOut, sizeof(ddOut));
  666. if (ddOut != DD_OK)
  667. {
  668. // Not necessarily an error.
  669. DBGINFO(("DD_DXAPI_ADDVPCAPTUREBUFFER failed.\n"));
  670. // TRAP();
  671. return FALSE;
  672. }
  673. return TRUE;
  674. }
  675. VOID CWDMCaptureStream::HandleStateTransition()
  676. {
  677. KIRQL Irql;
  678. switch (m_stateChange)
  679. {
  680. case Running:
  681. AddBuffersToDirectDraw();
  682. m_stateChange = ChangeComplete;
  683. KeSetEvent(&m_specialEvent, 0, FALSE);
  684. break;
  685. case Pausing:
  686. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  687. if (IsListEmpty(&m_waitQueue))
  688. {
  689. KeReleaseSpinLock(&m_streamDataLock, Irql);
  690. m_stateChange = ChangeComplete;
  691. KeSetEvent(&m_specialEvent, 0, FALSE);
  692. }
  693. else
  694. {
  695. KeReleaseSpinLock(&m_streamDataLock, Irql);
  696. }
  697. break;
  698. case Stopping:
  699. KeAcquireSpinLock(&m_streamDataLock, &Irql);
  700. if (IsListEmpty(&m_waitQueue))
  701. {
  702. KeReleaseSpinLock(&m_streamDataLock, Irql);
  703. EmptyIncomingDataSrbQueue();
  704. m_stateChange = ChangeComplete;
  705. KeSetEvent(&m_specialEvent, 0, FALSE);
  706. }
  707. else
  708. {
  709. KeReleaseSpinLock(&m_streamDataLock, Irql);
  710. }
  711. break;
  712. case Closing:
  713. m_stateChange = ChangeComplete;
  714. KeSetEvent(&m_specialEvent, 0, FALSE);
  715. DBGTRACE(("StreamThread exiting\n"));
  716. PsTerminateSystemThread(STATUS_SUCCESS);
  717. DBGERROR(("Shouldn't get here\n"));
  718. TRAP();
  719. break;
  720. case ChangeComplete:
  721. DBGTRACE(("Must have completed transition in HandleBusMasterCompletion\n"));
  722. break;
  723. default:
  724. TRAP();
  725. break;
  726. }
  727. }
  728. BOOL CWDMCaptureStream::ResetFieldNumber()
  729. {
  730. int streamNumber = m_pStreamObject->StreamNumber;
  731. DDSETFIELDNUM ddSetFieldNum;
  732. DWORD ddOut;
  733. ASSERT(streamNumber == STREAM_VideoCapture || streamNumber == STREAM_VBICapture);
  734. if (m_pVideoPort->GetDirectDrawHandle() == 0) {
  735. DBGERROR(("Didn't expect ring0DirectDrawHandle to be zero.\n"));
  736. TRAP();
  737. return FALSE;
  738. }
  739. if (m_pVideoPort->GetVideoPortHandle() == 0) {
  740. DBGERROR(("Didn't expect ring0VideoPortHandle to be zero.\n"));
  741. TRAP();
  742. return FALSE;
  743. }
  744. RtlZeroMemory(&ddSetFieldNum, sizeof(ddSetFieldNum));
  745. RtlZeroMemory(&ddOut, sizeof(ddOut));
  746. KSPROPERTY_DROPPEDFRAMES_CURRENT_S DroppedFrames;
  747. GetDroppedFrames(&DroppedFrames);
  748. ddSetFieldNum.hDirectDraw = m_pVideoPort->GetDirectDrawHandle();
  749. ddSetFieldNum.hVideoPort = m_pVideoPort->GetVideoPortHandle();
  750. ddSetFieldNum.dwFieldNum = ((ULONG)DroppedFrames.PictureNumber + 1) * GetFieldInterval();
  751. DxApi(DD_DXAPI_SET_VP_FIELD_NUMBER, &ddSetFieldNum, sizeof(ddSetFieldNum), &ddOut, sizeof(ddOut));
  752. if (ddOut != DD_OK)
  753. {
  754. DBGERROR(("DD_DXAPI_SET_VP_FIELD_NUMBER failed.\n"));
  755. TRAP();
  756. return FALSE;
  757. }
  758. else
  759. {
  760. #ifdef DEBUG
  761. DBGINFO(("PictureNumber: %d; ", DroppedFrames.PictureNumber));
  762. DBGINFO(("DropCount: %d\n", DroppedFrames.DropCount));
  763. DBGINFO(("AverageFrameSize: %d\n", DroppedFrames.AverageFrameSize));
  764. #endif
  765. return TRUE;
  766. }
  767. }
  768. BOOL CWDMCaptureStream::FlushBuffers()
  769. {
  770. DWORD ddOut = DD_OK;
  771. // commented out the trap because it is possible that capture handle is closed in DD before flushbuffer is called during mode switch
  772. if (m_hCapture == NULL) {
  773. //DBGERROR(("m_hCapture === NULL in FlushBuffers.\n"));
  774. //TRAP();
  775. return FALSE;
  776. }
  777. DxApi(DD_DXAPI_FLUSHVPCAPTUREBUFFERS, &m_hCapture, sizeof(HANDLE), &ddOut, sizeof(ddOut));
  778. if (ddOut != DD_OK)
  779. {
  780. DBGERROR(("DD_DXAPI_FLUSHVPCAPTUREBUFFERS failed.\n"));
  781. TRAP();
  782. return FALSE;
  783. }
  784. else
  785. {
  786. return TRUE;
  787. }
  788. }
  789. VOID CWDMCaptureStream::TimeStampSrb(PHW_STREAM_REQUEST_BLOCK pSrb)
  790. {
  791. PKSSTREAM_HEADER pDataPacket = pSrb->CommandData.DataBufferArray;
  792. PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
  793. pDataPacket->Duration = GetFieldInterval() * NTSCFieldDuration;
  794. pDataPacket->OptionsFlags |=
  795. KSSTREAM_HEADER_OPTIONSF_DURATIONVALID |
  796. KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
  797. // Find out what time it is, if we're using a clock
  798. if (m_hMasterClock) {
  799. LARGE_INTEGER Delta;
  800. HW_TIME_CONTEXT TimeContext;
  801. // TimeContext.HwDeviceExtension = pHwDevExt;
  802. TimeContext.HwDeviceExtension = (struct _HW_DEVICE_EXTENSION *)m_pVideoDecoder;
  803. TimeContext.HwStreamObject = m_pStreamObject;
  804. TimeContext.Function = TIME_GET_STREAM_TIME;
  805. StreamClassQueryMasterClockSync (
  806. m_hMasterClock,
  807. &TimeContext);
  808. // This calculation should result in the stream time WHEN the buffer
  809. // was filled.
  810. Delta.QuadPart = TimeContext.SystemTime -
  811. pSrbExt->ddCapBuffInfo.liTimeStamp.QuadPart;
  812. // Be safe, just use the current stream time, without the correction for when
  813. // DDraw actually returned the buffer to us.
  814. pDataPacket->PresentationTime.Time = TimeContext.Time;
  815. #ifdef THIS_SHOULD_WORK_BUT_IT_DOESNT
  816. if (TimeContext.Time > (ULONGLONG) Delta.QuadPart)
  817. {
  818. pDataPacket->PresentationTime.Time = TimeContext.Time - Delta.QuadPart;
  819. }
  820. else
  821. {
  822. // There's a bug in Ks or Stream after running for 2 hours
  823. // that makes this hack necessary. Will be fixed soon...
  824. pDataPacket->PresentationTime.Time = TimeContext.Time;
  825. }
  826. #endif
  827. #ifdef DEBUG
  828. ULONG *tmp1, *tmp2;
  829. tmp1 = (ULONG *)&pDataPacket->PresentationTime.Time;
  830. tmp2 = (ULONG *)&TimeContext.Time;
  831. DBGINFO(("PT: 0x%x%x; ST: 0x%x%x\n", tmp1[1], tmp1[0], tmp2[1], tmp2[0]));
  832. #endif
  833. pDataPacket->PresentationTime.Numerator = 1;
  834. pDataPacket->PresentationTime.Denominator = 1;
  835. pDataPacket->OptionsFlags |=
  836. KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
  837. }
  838. else
  839. {
  840. pDataPacket->OptionsFlags &=
  841. ~KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
  842. }
  843. }
  844. void CWDMCaptureStream::CancelPacket( PHW_STREAM_REQUEST_BLOCK pSrbToCancel)
  845. {
  846. PHW_STREAM_REQUEST_BLOCK pCurrentSrb;
  847. KIRQL Irql;
  848. PLIST_ENTRY Entry;
  849. BOOL bFound = FALSE;
  850. if ( m_stateChange == Initializing ) // Stream not completely setup, so nothing in the queue
  851. {
  852. DBGINFO(( "Bt829: Didn't find Srb 0x%x\n", pSrbToCancel));
  853. return;
  854. }
  855. KeAcquireSpinLock( &m_streamDataLock, &Irql);
  856. Entry = m_incomingDataSrbQueue.Flink;
  857. //
  858. // Loop through the linked list from the beginning to end,
  859. // trying to find the SRB to cancel
  860. //
  861. while( Entry != &m_incomingDataSrbQueue)
  862. {
  863. PSRB_DATA_EXTENSION pSrbExt;
  864. pSrbExt = ( PSRB_DATA_EXTENSION)Entry;
  865. pCurrentSrb = pSrbExt->pSrb;
  866. if( pCurrentSrb == pSrbToCancel)
  867. {
  868. RemoveEntryList( Entry);
  869. bFound = TRUE;
  870. break;
  871. }
  872. Entry = Entry->Flink;
  873. }
  874. KeReleaseSpinLock( &m_streamDataLock, Irql);
  875. if( bFound)
  876. {
  877. pCurrentSrb->Status = STATUS_CANCELLED;
  878. pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0;
  879. DBGINFO(( "Bt829: Cancelled Srb 0x%x\n", pCurrentSrb));
  880. StreamClassStreamNotification( StreamRequestComplete,
  881. pCurrentSrb->StreamObject,
  882. pCurrentSrb);
  883. }
  884. else
  885. {
  886. // If this is a DATA_TRANSFER and a STREAM_REQUEST SRB,
  887. // then it must be in the waitQueue, being filled by DDraw.
  888. // If so, mark it cancelled, and it will
  889. // be returned when DDraw is finished with it.
  890. if(( pSrbToCancel->Flags & (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST)) ==
  891. (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST))
  892. {
  893. pSrbToCancel->Status = STATUS_CANCELLED;
  894. DBGINFO(( "Bt829: Cancelled Srb on waitQueue 0x%x\n", pSrbToCancel));
  895. }
  896. else
  897. {
  898. DBGINFO(( "Bt829: Didn't find Srb 0x%x\n", pSrbToCancel));
  899. }
  900. }
  901. }