Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

809 lines
23 KiB

  1. //==========================================================================;
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. // PURPOSE.
  7. //
  8. // Copyright (c) 1992 - 1999 Microsoft Corporation. All Rights Reserved.
  9. //
  10. //==========================================================================;
  11. #include "strmini.h"
  12. #include "ksmedia.h"
  13. #include "capmain.h"
  14. #include "capdebug.h"
  15. #include "vbixfer.h"
  16. #include "ntstatus.h"
  17. /*
  18. ** VBICaptureRoutine()
  19. **
  20. ** Routine to generate video frames based on a timer.
  21. **
  22. ** Note: Devices capable of using interrupts should always
  23. ** trigger capture on a VSYNC interrupt, and not use a timer.
  24. **
  25. ** Arguments:
  26. **
  27. ** Returns: nothing
  28. **
  29. ** Side Effects: none
  30. */
  31. VOID
  32. STREAMAPI
  33. VBICaptureRoutine(
  34. IN PSTREAMEX pStrmEx
  35. )
  36. {
  37. PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
  38. int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
  39. PKSSTREAM_HEADER pDataPacket;
  40. PKS_VBI_FRAME_INFO pVBIFrameInfo;
  41. // If we're stopped and the timer is still running, just return.
  42. // This will stop the timer.
  43. if (pStrmEx->KSState == KSSTATE_STOP) {
  44. return;
  45. }
  46. // Find out what time it is, if we're using a clock
  47. if (pStrmEx->hMasterClock) {
  48. HW_TIME_CONTEXT TimeContext;
  49. TimeContext.HwDeviceExtension = pHwDevExt;
  50. TimeContext.HwStreamObject = pStrmEx->pStreamObject;
  51. TimeContext.Function = TIME_GET_STREAM_TIME;
  52. StreamClassQueryMasterClockSync (
  53. pStrmEx->hMasterClock,
  54. &TimeContext);
  55. pStrmEx->QST_StreamTime = TimeContext.Time;
  56. pStrmEx->QST_Now = TimeContext.SystemTime;
  57. if (pStrmEx->QST_NextFrame == 0) {
  58. pStrmEx->QST_NextFrame =
  59. pStrmEx->QST_StreamTime
  60. + pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval;
  61. }
  62. #ifdef CREATE_A_FLURRY_OF_TIMING_SPEW
  63. DbgLogTrace(("TestCap: Time=%16lx\n", TimeContext.Time));
  64. DbgLogTrace(("TestCap: SysTime=%16lx\n", TimeContext.SystemTime));
  65. #endif
  66. }
  67. // Only capture in the RUN state
  68. if (pStrmEx->KSState == KSSTATE_RUN) {
  69. //
  70. // Determine if it is time to capture a frame based on
  71. // how much time has elapsed since capture started.
  72. // If there isn't a clock available, then capture immediately.
  73. //
  74. if ((!pStrmEx->hMasterClock) ||
  75. (pStrmEx->QST_StreamTime >= pStrmEx->QST_NextFrame)) {
  76. PHW_STREAM_REQUEST_BLOCK pSrb;
  77. // Increment the picture count (usually this is VSYNC count)
  78. pStrmEx->VBIFrameInfo.PictureNumber++;
  79. //
  80. // Get the next queue SRB (if any)
  81. //
  82. pSrb = VideoQueueRemoveSRB (pHwDevExt, StreamNumber);
  83. if (pSrb) {
  84. pDataPacket = pSrb->CommandData.DataBufferArray;
  85. pVBIFrameInfo = (PKS_VBI_FRAME_INFO)(pDataPacket + 1);
  86. pStrmEx->VBIFrameInfo.dwFrameFlags = 0;
  87. //
  88. // If needed, send out VBIInfoHeader
  89. //
  90. if (!(pStrmEx->SentVBIInfoHeader)) {
  91. pStrmEx->SentVBIInfoHeader = 1;
  92. pStrmEx->VBIFrameInfo.dwFrameFlags |=
  93. KS_VBI_FLAG_VBIINFOHEADER_CHANGE;
  94. pStrmEx->VBIFrameInfo.VBIInfoHeader = StreamFormatVBI.VBIInfoHeader;
  95. }
  96. // Set additional info fields about the data captured such as:
  97. // Frames Captured
  98. // Frames Dropped
  99. // Field Polarity
  100. // Protection status
  101. //
  102. pStrmEx->VBIFrameInfo.ExtendedHeaderSize =
  103. pVBIFrameInfo->ExtendedHeaderSize;
  104. if (pStrmEx->VBIFrameInfo.PictureNumber & 1)
  105. pStrmEx->VBIFrameInfo.dwFrameFlags |= KS_VBI_FLAG_FIELD1;
  106. else
  107. pStrmEx->VBIFrameInfo.dwFrameFlags |= KS_VBI_FLAG_FIELD2;
  108. pStrmEx->VBIFrameInfo.dwFrameFlags |=
  109. pHwDevExt->ProtectionStatus & (KS_VBI_FLAG_MV_PRESENT
  110. |KS_VBI_FLAG_MV_HARDWARE
  111. |KS_VBI_FLAG_MV_DETECTED);
  112. *pVBIFrameInfo = pStrmEx->VBIFrameInfo;
  113. // Copy this into stream header so ring 3 filters can see it
  114. pDataPacket->TypeSpecificFlags = pVBIFrameInfo->dwFrameFlags;
  115. // Init the flags to zero
  116. pDataPacket->OptionsFlags = 0;
  117. // Set the discontinuity flag if frames have been previously
  118. // dropped, and then reset our internal flag
  119. if (pStrmEx->fDiscontinuity) {
  120. pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
  121. pStrmEx->fDiscontinuity = FALSE;
  122. }
  123. //
  124. // Return the timestamp for the frame
  125. //
  126. pDataPacket->PresentationTime.Numerator = 1;
  127. pDataPacket->PresentationTime.Denominator = 1;
  128. pDataPacket->Duration = pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval;
  129. //
  130. // if we have a master clock AND this is a capture stream
  131. //
  132. if (pStrmEx->hMasterClock
  133. && (StreamNumber == STREAM_Capture
  134. || StreamNumber == STREAM_VBI))
  135. {
  136. pDataPacket->PresentationTime.Time = pStrmEx->QST_StreamTime;
  137. pDataPacket->OptionsFlags |=
  138. KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
  139. KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
  140. }
  141. else {
  142. //
  143. // No clock or not a capture stream,
  144. // so just mark the time as unknown
  145. //
  146. pDataPacket->PresentationTime.Time = 0;
  147. // clear the timestamp valid flags
  148. pDataPacket->OptionsFlags &=
  149. ~(KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
  150. KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
  151. }
  152. // Every frame we generate is a key frame (aka SplicePoint)
  153. // Delta frames (B or P) should not set this flag
  154. pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
  155. //
  156. // Call the routine which synthesizes images
  157. //
  158. VBI_ImageSynth(pSrb);
  159. // Output a frame count every 300th frame (~5 sec) in Debug mode
  160. if (pStrmEx->VBIFrameInfo.PictureNumber % 300 == 0) {
  161. DbgLogInfo(("TestCap: Picture %u, Stream=%d\n",
  162. (unsigned int)pStrmEx->VBIFrameInfo.PictureNumber,
  163. StreamNumber));
  164. }
  165. CompleteStreamSRB(pSrb);
  166. } // if we have an SRB
  167. else {
  168. //
  169. // No buffer was available when we should have captured one
  170. // Increment the counter which keeps track of
  171. // dropped frames
  172. pStrmEx->VBIFrameInfo.DropCount++;
  173. // Set the (local) discontinuity flag
  174. // This will cause the next packet processed to have the
  175. // KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY flag set.
  176. pStrmEx->fDiscontinuity = TRUE;
  177. }
  178. // Figure out when to capture the next frame
  179. pStrmEx->QST_NextFrame += pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval;
  180. } // endif time to capture a frame
  181. } // endif we're running
  182. }
  183. /*
  184. ** VBIhwCaptureRoutine()
  185. **
  186. ** Routine to capture video frames based on a timer.
  187. **
  188. ** Notes: * Devices capable of using interrupts should always trigger
  189. ** capture on a VSYNC interrupt, and not use a timer.
  190. ** * This routine is used by VBI streams which do NOT have extended
  191. ** headers, such as CC and NABTS.
  192. **
  193. ** Arguments:
  194. **
  195. ** Returns: nothing
  196. **
  197. ** Side Effects: none
  198. */
  199. VOID
  200. STREAMAPI
  201. VBIhwCaptureRoutine(
  202. IN PSTREAMEX pStrmEx
  203. )
  204. {
  205. PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
  206. int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
  207. PKSSTREAM_HEADER pDataPacket;
  208. // If we're stopped and the timer is still running, just return.
  209. // This will stop the timer.
  210. if (pStrmEx->KSState == KSSTATE_STOP) {
  211. return;
  212. }
  213. // Find out what time it is, if we're using a clock
  214. if (pStrmEx->hMasterClock ) {
  215. HW_TIME_CONTEXT TimeContext;
  216. TimeContext.HwDeviceExtension = pHwDevExt;
  217. TimeContext.HwStreamObject = pStrmEx->pStreamObject;
  218. TimeContext.Function = TIME_GET_STREAM_TIME;
  219. StreamClassQueryMasterClockSync (
  220. pStrmEx->hMasterClock,
  221. &TimeContext);
  222. pStrmEx->QST_StreamTime = TimeContext.Time;
  223. pStrmEx->QST_Now = TimeContext.SystemTime;
  224. if (pStrmEx->QST_NextFrame == 0) {
  225. pStrmEx->QST_NextFrame =
  226. pStrmEx->QST_StreamTime
  227. + pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval;
  228. }
  229. #ifdef CREATE_A_FLURRY_OF_TIMING_SPEW
  230. DbgLogTrace(("TestCap: Time=%16lx\n", TimeContext.Time));
  231. DbgLogTrace(("TestCap: SysTime=%16lx\n", TimeContext.SystemTime));
  232. #endif
  233. }
  234. // Only capture in the RUN state
  235. if (pStrmEx->KSState == KSSTATE_RUN) {
  236. //
  237. // Determine if it is time to capture a frame based on
  238. // how much time has elapsed since capture started.
  239. // If there isn't a clock available, then capture immediately.
  240. //
  241. if ((!pStrmEx->hMasterClock) ||
  242. (pStrmEx->QST_StreamTime >= pStrmEx->QST_NextFrame)) {
  243. PHW_STREAM_REQUEST_BLOCK pSrb;
  244. // Increment the picture count (usually this is VSYNC count)
  245. pStrmEx->VBIFrameInfo.PictureNumber++;
  246. //
  247. // Get the next queue SRB (if any)
  248. //
  249. pSrb = VideoQueueRemoveSRB (pHwDevExt, StreamNumber);
  250. if (pSrb) {
  251. pDataPacket = pSrb->CommandData.DataBufferArray;
  252. // Init the flags to zero
  253. pDataPacket->OptionsFlags = 0;
  254. // Set the discontinuity flag if frames have been previously
  255. // dropped, and then reset our internal flag
  256. if (pStrmEx->fDiscontinuity) {
  257. pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
  258. pStrmEx->fDiscontinuity = FALSE;
  259. }
  260. //
  261. // Return the timestamp for the frame
  262. //
  263. pDataPacket->PresentationTime.Numerator = 1;
  264. pDataPacket->PresentationTime.Denominator = 1;
  265. pDataPacket->Duration = pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval;
  266. //
  267. // if we have a master clock AND this is the capture stream
  268. //
  269. if (pStrmEx->hMasterClock && (StreamNumber == 0)) {
  270. pDataPacket->PresentationTime.Time = pStrmEx->QST_StreamTime;
  271. pDataPacket->OptionsFlags |=
  272. KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
  273. KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
  274. }
  275. else {
  276. //
  277. // No clock or the preview stream,
  278. // so just mark the time as unknown
  279. //
  280. pDataPacket->PresentationTime.Time = 0;
  281. // clear the timestamp valid flags
  282. pDataPacket->OptionsFlags &=
  283. ~(KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
  284. KSSTREAM_HEADER_OPTIONSF_DURATIONVALID);
  285. }
  286. // Every frame we generate is a key frame (aka SplicePoint)
  287. // Delta frames (B or P) should not set this flag
  288. pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;
  289. //
  290. // Call the routine which synthesizes images
  291. //
  292. switch (StreamNumber) {
  293. case STREAM_NABTS:
  294. NABTS_ImageSynth(pSrb);
  295. break;
  296. case STREAM_CC:
  297. CC_ImageSynth(pSrb);
  298. break;
  299. default:
  300. case STREAM_VBI:
  301. DbgLogError(("TestCap::VBIhwCaptureRoutine: Bad stream %d\n", StreamNumber));
  302. break;
  303. }
  304. CompleteStreamSRB (pSrb);
  305. } // if we have an SRB
  306. else {
  307. //
  308. // No buffer was available when we should have captured one
  309. // Increment the counter which keeps track of
  310. // dropped frames
  311. pStrmEx->VBIFrameInfo.DropCount++;
  312. // Set the (local) discontinuity flag
  313. // This will cause the next packet processed to have the
  314. // KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY flag set.
  315. pStrmEx->fDiscontinuity = TRUE;
  316. }
  317. // Figure out when to capture the next frame
  318. pStrmEx->QST_NextFrame += pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval;
  319. } // endif time to capture a frame
  320. } // endif we're running
  321. }
  322. /*
  323. ** VBITimerRoutine()
  324. **
  325. ** A timer has been created based on the requested capture interval.
  326. ** This is the callback routine for this timer event.
  327. **
  328. ** Note: Devices capable of using interrupts should always
  329. ** trigger capture on a VSYNC interrupt, and not use a timer.
  330. **
  331. ** Arguments:
  332. **
  333. ** Context - pointer to the stream extension
  334. **
  335. ** Returns: nothing
  336. **
  337. ** Side Effects: none
  338. */
  339. VOID
  340. STREAMAPI
  341. VBITimerRoutine(
  342. PVOID Context
  343. )
  344. {
  345. PSTREAMEX pStrmEx = ((PSTREAMEX)Context);
  346. PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt;
  347. int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
  348. ULONG interval;
  349. // If we're stopped and the timer is still running, just return.
  350. // This will stop the timer.
  351. if (pStrmEx->KSState == KSSTATE_STOP)
  352. return;
  353. // Calculate next interval
  354. interval = (ULONG)(pStrmEx->pVBIStreamFormat->ConfigCaps.MinFrameInterval / 10);
  355. interval /= 2; // Run at 2x noted rate for accuracy
  356. // Capture a frame if it's time and we have a buffer
  357. switch (StreamNumber) {
  358. case STREAM_NABTS:
  359. VBIhwCaptureRoutine(pStrmEx);
  360. break;
  361. case STREAM_CC:
  362. VBIhwCaptureRoutine(pStrmEx);
  363. break;
  364. default:
  365. case STREAM_VBI:
  366. VBICaptureRoutine(pStrmEx);
  367. break;
  368. }
  369. // Schedule the next timer event
  370. StreamClassScheduleTimer (
  371. pStrmEx->pStreamObject, // StreamObject
  372. pHwDevExt, // HwDeviceExtension
  373. interval, // Microseconds
  374. VBITimerRoutine, // TimerRoutine
  375. pStrmEx); // Context
  376. }
  377. /*
  378. ** VBISetState()
  379. **
  380. ** Sets the current state for a given stream
  381. **
  382. ** Arguments:
  383. **
  384. ** pSrb - pointer to the stream request block for properties
  385. **
  386. ** Returns:
  387. **
  388. ** Side Effects: none
  389. */
  390. VOID
  391. STREAMAPI
  392. VBISetState(PHW_STREAM_REQUEST_BLOCK pSrb)
  393. {
  394. PHW_DEVICE_EXTENSION pHwDevExt = pSrb->HwDeviceExtension;
  395. PSTREAMEX pStrmEx = pSrb->StreamObject->HwStreamExtension;
  396. int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
  397. KSSTATE PreviousState;
  398. //
  399. // Remember the state we're transitioning away from
  400. //
  401. PreviousState = pStrmEx->KSState;
  402. //
  403. // Set the new state
  404. //
  405. pStrmEx->KSState = pSrb->CommandData.StreamState;
  406. switch (pSrb->CommandData.StreamState)
  407. {
  408. case KSSTATE_STOP:
  409. //
  410. // The stream class will cancel all outstanding IRPs for us
  411. // (but only if it is maintaining the queue ie. using Stream Class synchronization)
  412. // Since Testcap is not using Stream Class synchronization, we must clear the queue here
  413. VideoQueueCancelAllSRBs (pStrmEx);
  414. pStrmEx->SentVBIInfoHeader = 0; // Send out a fresh one next RUN
  415. DbgLogInfo(("TestCap: STATE Stopped, Stream=%d\n", StreamNumber));
  416. break;
  417. case KSSTATE_ACQUIRE:
  418. //
  419. // This is a KS only state, that has no correspondence in DirectShow
  420. //
  421. DbgLogInfo(("TestCap: STATE Acquire, Stream=%d\n", StreamNumber));
  422. break;
  423. case KSSTATE_PAUSE:
  424. //
  425. // On a transition to pause from acquire or stop, start our timer running.
  426. //
  427. if (PreviousState == KSSTATE_ACQUIRE || PreviousState == KSSTATE_STOP) {
  428. // Zero the frame counters
  429. pStrmEx->VBIFrameInfo.PictureNumber = 0;
  430. pStrmEx->VBIFrameInfo.DropCount = 0;
  431. pStrmEx->VBIFrameInfo.dwFrameFlags = 0;
  432. // Setup the next timer callback
  433. VBITimerRoutine(pStrmEx);
  434. }
  435. DbgLogInfo(("TestCap: STATE Pause, Stream=%d\n", StreamNumber));
  436. break;
  437. case KSSTATE_RUN:
  438. //
  439. // Begin Streaming.
  440. //
  441. // Reset the discontinuity flag
  442. pStrmEx->fDiscontinuity = FALSE;
  443. // Setting the NextFrame time to zero will cause the value to be
  444. // reset from the stream time
  445. pStrmEx->QST_NextFrame = 0;
  446. DbgLogInfo(("TestCap: STATE Run, Stream=%d\n", StreamNumber));
  447. break;
  448. } // end switch (pSrb->CommandData.StreamState)
  449. }
  450. /*
  451. ** VBIReceiveCtrlPacket()
  452. **
  453. ** Receives packet commands that control all the VBI (VBI/NABTS/CC) streams
  454. **
  455. ** Arguments:
  456. **
  457. ** pSrb - The stream request block for the VBI stream
  458. **
  459. ** Returns: nothing
  460. **
  461. ** Side Effects: none
  462. */
  463. VOID
  464. STREAMAPI
  465. VBIReceiveCtrlPacket(
  466. IN PHW_STREAM_REQUEST_BLOCK pSrb
  467. )
  468. {
  469. PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
  470. PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
  471. int StreamNumber = pStrmEx->pStreamObject->StreamNumber;
  472. BOOL Busy;
  473. //
  474. // make sure we have a device extension and are at passive level
  475. //
  476. DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  477. DEBUG_ASSERT(pHwDevExt != 0);
  478. DbgLogInfo(("TestCap: Receiving %s Stream Control SRB %p, %x\n",
  479. (StreamNumber == STREAM_VBI)? "VBI"
  480. : (StreamNumber == STREAM_NABTS)? "NABTS"
  481. : (StreamNumber == STREAM_CC)? "CC"
  482. : "???",
  483. pSrb,
  484. pSrb->Command));
  485. //
  486. // If we're already processing an SRB, add it to the queue
  487. //
  488. Busy = AddToListIfBusy (
  489. pSrb,
  490. &pHwDevExt->AdapterSpinLock,
  491. &pHwDevExt->ProcessingControlSRB [StreamNumber],
  492. &pHwDevExt->StreamControlSRBList[StreamNumber]);
  493. if (Busy) {
  494. return;
  495. }
  496. do {
  497. //
  498. // Default to success
  499. //
  500. pSrb->Status = STATUS_SUCCESS;
  501. //
  502. // determine the type of packet.
  503. //
  504. switch (pSrb->Command)
  505. {
  506. case SRB_PROPOSE_DATA_FORMAT:
  507. DbgLogInfo(("TestCap: Receiving SRB_PROPOSE_DATA_FORMAT SRB %p, StreamNumber= %d\n", pSrb, StreamNumber));
  508. if (!(AdapterVerifyFormat (
  509. pSrb->CommandData.OpenFormat,
  510. pSrb->StreamObject->StreamNumber)))
  511. {
  512. pSrb->Status = STATUS_NO_MATCH;
  513. }
  514. break;
  515. case SRB_SET_DATA_FORMAT:
  516. DbgLogInfo(("TestCap: SRB_SET_DATA_FORMAT"));
  517. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  518. break;
  519. case SRB_GET_DATA_FORMAT:
  520. DbgLogInfo(("TestCap: SRB_GET_DATA_FORMAT"));
  521. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  522. break;
  523. case SRB_SET_STREAM_STATE:
  524. VBISetState(pSrb);
  525. break;
  526. case SRB_GET_STREAM_STATE:
  527. VideoGetState(pSrb);
  528. break;
  529. case SRB_GET_STREAM_PROPERTY:
  530. VideoGetProperty(pSrb);
  531. break;
  532. case SRB_INDICATE_MASTER_CLOCK:
  533. VideoIndicateMasterClock(pSrb);
  534. break;
  535. default:
  536. //
  537. // invalid / unsupported command. Fail it as such
  538. //
  539. TRAP;
  540. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  541. }
  542. CompleteStreamSRB (pSrb);
  543. //
  544. // See if there's anything else on the queue
  545. //
  546. Busy = RemoveFromListIfAvailable (
  547. &pSrb,
  548. &pHwDevExt->AdapterSpinLock,
  549. &pHwDevExt->ProcessingControlSRB [StreamNumber],
  550. &pHwDevExt->StreamControlSRBList[StreamNumber]);
  551. } while (Busy);
  552. }
  553. /*
  554. ** VBIReceiveDataPacket()
  555. **
  556. ** Receives VBI data packet commands on the output streams
  557. **
  558. ** Arguments:
  559. **
  560. ** pSrb - Stream request block for the VBI stream
  561. **
  562. ** Returns: nothing
  563. **
  564. ** Side Effects: none
  565. */
  566. VOID
  567. STREAMAPI
  568. VBIReceiveDataPacket(
  569. IN PHW_STREAM_REQUEST_BLOCK pSrb
  570. )
  571. {
  572. PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension);
  573. PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension;
  574. int StreamNumber = pSrb->StreamObject->StreamNumber;
  575. //
  576. // make sure we have a device extension and are at passive level
  577. //
  578. DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  579. DEBUG_ASSERT(pHwDevExt != 0);
  580. DbgLogTrace(("'TestCap: Receiving VBI Stream Data SRB %p, %x\n", pSrb, pSrb->Command));
  581. //
  582. // Default to success
  583. //
  584. pSrb->Status = STATUS_SUCCESS;
  585. //
  586. // determine the type of packet.
  587. //
  588. switch (pSrb->Command){
  589. case SRB_READ_DATA:
  590. // Rule:
  591. // Only accept read requests when in either the Pause or Run
  592. // States. If Stopped, immediately return the SRB.
  593. if (pStrmEx->KSState == KSSTATE_STOP) {
  594. CompleteStreamSRB (pSrb);
  595. break;
  596. }
  597. //
  598. // Put this read request on the pending queue
  599. //
  600. VideoQueueAddSRB (pSrb);
  601. // Since another thread COULD HAVE MODIFIED THE STREAM STATE
  602. // in the midst of adding it to the queue, check the stream
  603. // state again, and cancel the SRB if necessary. Note that
  604. // this race condition was NOT handled in the original DDK
  605. // release of testcap!
  606. if (pStrmEx->KSState == KSSTATE_STOP) {
  607. VideoQueueCancelOneSRB (
  608. pStrmEx,
  609. pSrb);
  610. }
  611. break;
  612. default:
  613. //
  614. // invalid / unsupported command. Fail it as such
  615. //
  616. TRAP;
  617. pSrb->Status = STATUS_NOT_IMPLEMENTED;
  618. CompleteStreamSRB (pSrb);
  619. } // switch (pSrb->Command)
  620. }