//==========================================================================; // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. // // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved. // //==========================================================================; #include "strmini.h" #include "ksmedia.h" #include "capmain.h" #include "capdebug.h" #include "ntstatus.h" #ifdef TOSHIBA #include "bert.h" extern ULONG CurrentOSType; #ifdef _FPS_COUNT_ ULONG InterruptCounter = 0; ULONG FrameCounter = 0; #endif//_FPS_COUNT_ #endif//TOSHIBA //==========================================================================; // General queue management routines //==========================================================================; /* ** AddToListIfBusy () ** ** Grabs a spinlock, checks the busy flag, and if set adds an SRB to a queue ** ** Arguments: ** ** pSrb - Stream request block ** ** SpinLock - The spinlock to use when checking the flag ** ** BusyFlag - The flag to check ** ** ListHead - The list onto which the Srb will be added if the busy flag is set ** ** Returns: ** ** The state of the busy flag on entry. This will be TRUE if we're already ** processing an SRB, and FALSE if no SRB is already in progress. ** ** Side Effects: none */ BOOL STREAMAPI AddToListIfBusy ( IN PHW_STREAM_REQUEST_BLOCK pSrb, IN KSPIN_LOCK *SpinLock, IN OUT BOOL *BusyFlag, IN LIST_ENTRY *ListHead ) { KIRQL Irql; PSRB_EXTENSION pSrbExt = (PSRB_EXTENSION)pSrb->SRBExtension; KeAcquireSpinLock (SpinLock, &Irql); // If we're already processing another SRB, add this current request // to the queue and return TRUE if (*BusyFlag == TRUE) { // Save the SRB pointer away in the SRB Extension pSrbExt->pSrb = pSrb; InsertTailList(ListHead, &pSrbExt->ListEntry); KeReleaseSpinLock(SpinLock, Irql); return TRUE; } // Otherwise, set the busy flag, release the spinlock, and return FALSE *BusyFlag = TRUE; KeReleaseSpinLock(SpinLock, Irql); return FALSE; } /* ** RemoveFromListIfAvailable () ** ** Grabs a spinlock, checks for an available SRB, and removes it from the list ** ** Arguments: ** ** &pSrb - where to return the Stream request block if available ** ** SpinLock - The spinlock to use ** ** BusyFlag - The flag to clear if the list is empty ** ** ListHead - The list from which an SRB will be removed if available ** ** Returns: ** ** TRUE if an SRB was removed from the list ** FALSE if the list is empty ** ** Side Effects: none */ BOOL STREAMAPI RemoveFromListIfAvailable ( IN OUT PHW_STREAM_REQUEST_BLOCK *pSrb, IN KSPIN_LOCK *SpinLock, IN OUT BOOL *BusyFlag, IN LIST_ENTRY *ListHead ) { KIRQL Irql; KeAcquireSpinLock (SpinLock, &Irql); // // If the queue is now empty, clear the busy flag, and return // if (IsListEmpty(ListHead)) { *BusyFlag = FALSE; KeReleaseSpinLock(SpinLock, Irql); return FALSE; } // // otherwise extract the SRB // else { PUCHAR ptr; PSRB_EXTENSION pSrbExt; ptr = (PUCHAR)RemoveHeadList(ListHead); *BusyFlag = TRUE; KeReleaseSpinLock(SpinLock, Irql); // Get the SRB out of the SRB extension and return it pSrbExt = (PSRB_EXTENSION) (((PUCHAR) ptr) - FIELDOFFSET(SRB_EXTENSION, ListEntry)); *pSrb = pSrbExt->pSrb; } return TRUE; } //==========================================================================; // Routines for managing the SRB queue on a per stream basis //==========================================================================; /* ** VideoQueueAddSRB () ** ** Adds a stream data SRB to a stream queue. The queue is maintained in a ** first in, first out order. ** ** Arguments: ** ** pSrb - Stream request block for the Video stream ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VideoQueueAddSRB ( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; int StreamNumber = pSrb->StreamObject->StreamNumber; KIRQL oldIrql; KeAcquireSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], &oldIrql); // Save the SRB pointer in the IRP so we can use the IRPs // ListEntry to maintain a doubly linked list of pending // requests pSrb->Irp->Tail.Overlay.DriverContext[0] = pSrb; InsertTailList ( &pHwDevExt->StreamSRBList[StreamNumber], &pSrb->Irp->Tail.Overlay.ListEntry); // Increment the count of outstanding SRBs in this queue pHwDevExt->StreamSRBListSize[StreamNumber]++; KeReleaseSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], oldIrql); } /* ** VideoQueueRemoveSRB () ** ** Removes a stream data SRB from a stream queue ** ** Arguments: ** ** pHwDevExt - Device Extension ** ** StreamNumber - Index of the stream ** ** Returns: SRB or NULL ** ** Side Effects: none */ PHW_STREAM_REQUEST_BLOCK STREAMAPI VideoQueueRemoveSRB ( PHW_DEVICE_EXTENSION pHwDevExt, int StreamNumber ) { PUCHAR ptr; PIRP pIrp; PHW_STREAM_REQUEST_BLOCK pSrb = NULL; KIRQL oldIrql; KeAcquireSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], &oldIrql); // // Get the SRB out of the IRP out of the pending list // if (!IsListEmpty (&pHwDevExt->StreamSRBList[StreamNumber])) { ptr = (PUCHAR) RemoveHeadList( &pHwDevExt->StreamSRBList[StreamNumber]); pIrp = (PIRP) (((PUCHAR) ptr) - FIELDOFFSET(IRP, Tail.Overlay.ListEntry)); pSrb = (PHW_STREAM_REQUEST_BLOCK) pIrp->Tail.Overlay.DriverContext[0]; // Decrement the count of SRBs in this queue pHwDevExt->StreamSRBListSize[StreamNumber]--; } KeReleaseSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], oldIrql); return pSrb; } /* ** VideoQueueCancelAllSRBs() ** ** In case of a client crash, this empties the stream queue when the stream closes ** ** Arguments: ** ** pStrmEx - pointer to the stream extension ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoQueueCancelAllSRBs ( PSTREAMEX pStrmEx ) { PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pStrmEx->pHwDevExt; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; PUCHAR ptr; PIRP pIrp; PHW_STREAM_REQUEST_BLOCK pSrb; KIRQL oldIrql; if (pStrmEx->KSState != KSSTATE_STOP) { KdPrint(("TsbVcap: ERROR Cleanup without being in the stopped state\n")); // May need to force the device to a stopped state here // may need to disable interrupts here ! } // // The stream class will cancel all outstanding IRPs for us // (but only if we've set TurnOffSynchronization = FALSE) // KeAcquireSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], &oldIrql); // // Get the SRB out of the IRP out of the pending list // while (!IsListEmpty (&pHwDevExt->StreamSRBList[StreamNumber])) { ptr = (PUCHAR) RemoveHeadList( &pHwDevExt->StreamSRBList[StreamNumber]); pIrp = (PIRP) (((PUCHAR) ptr) - FIELDOFFSET(IRP, Tail.Overlay.ListEntry)); pSrb = (PHW_STREAM_REQUEST_BLOCK) pIrp->Tail.Overlay.DriverContext[0]; // Decrement the count of SRBs in this queue pHwDevExt->StreamSRBListSize[StreamNumber]--; // // Make the length zero, and status cancelled // pSrb->CommandData.DataBufferArray->DataUsed = 0; pSrb->Status = STATUS_CANCELLED; KdPrint(("TsbVcap: VideoQueueCancelALLSRBs FOUND Srb=%x\n", pSrb)); CompleteStreamSRB (pSrb); } KeReleaseSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], oldIrql); KdPrint(("TsbVcap: VideoQueueCancelAll\n")); } /* ** VideoQueueCancelOneSRB() ** ** Called when cancelling a particular SRB ** ** Arguments: ** ** pStrmEx - pointer to the stream extension ** ** pSRBToCancel - pointer to the SRB ** ** Returns: ** ** TRUE if the SRB was found in this queue ** ** Side Effects: none */ BOOL STREAMAPI VideoQueueCancelOneSRB ( PSTREAMEX pStrmEx, PHW_STREAM_REQUEST_BLOCK pSrbToCancel ) { PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pStrmEx->pHwDevExt; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; KIRQL oldIrql; BOOL Found = FALSE; PIRP pIrp; PHW_STREAM_REQUEST_BLOCK pSrb; PLIST_ENTRY Entry; KeAcquireSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], &oldIrql); Entry = pHwDevExt->StreamSRBList[StreamNumber].Flink; // // Loop through the linked list from the beginning to end, // trying to find the SRB to cancel // while (Entry != &pHwDevExt->StreamSRBList[StreamNumber]) { pIrp = (PIRP) (((PUCHAR) Entry) - FIELDOFFSET(IRP, Tail.Overlay.ListEntry)); pSrb = (PHW_STREAM_REQUEST_BLOCK) pIrp->Tail.Overlay.DriverContext[0]; if (pSrb == pSrbToCancel) { RemoveEntryList(Entry); Found = TRUE; break; } Entry = Entry->Flink; } KeReleaseSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], oldIrql); if (Found) { pHwDevExt->StreamSRBListSize[StreamNumber]--; // // Make the length zero, and status cancelled // pSrbToCancel->CommandData.DataBufferArray->DataUsed = 0; pSrbToCancel->Status = STATUS_CANCELLED; CompleteStreamSRB (pSrbToCancel); KdPrint(("TsbVcap: VideoQueueCancelOneSRB FOUND Srb=%x\n", pSrb)); } KdPrint(("TsbVcap: VideoQueueCancelOneSRB\n")); return Found; } /* ** VideoSetFormat() ** ** Sets the format for a video stream. This happens both when the ** stream is first opened, and also when dynamically switching formats ** on the preview pin. ** ** It is assumed that the format has been verified for correctness before ** this call is made. ** ** Arguments: ** ** pSrb - Stream request block for the Video stream ** ** Returns: ** ** TRUE if the format could be set, else FALSE ** ** Side Effects: none */ BOOL STREAMAPI VideoSetFormat( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); int StreamNumber = pSrb->StreamObject->StreamNumber; UINT nSize; PKSDATAFORMAT pKSDataFormat = pSrb->CommandData.OpenFormat; #ifdef TOSHIBA ULONG ImageSize; ULONG ImageSizeY; ULONG ImageSizeU; ULONG ImageSizeV; ULONG ulFrameRate; DWORD dwAddr; UINT biWidth; UINT biHeight; int Counter; PSTREAMEX pStrmExTmp; #endif//TOSHIBA // ------------------------------------------------------------------- // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER // ------------------------------------------------------------------- if (IsEqualGUID (&pKSDataFormat->Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) { PKS_DATAFORMAT_VIDEOINFOHEADER pVideoInfoHeader = (PKS_DATAFORMAT_VIDEOINFOHEADER) pSrb->CommandData.OpenFormat; PKS_VIDEOINFOHEADER pVideoInfoHdrRequested = &pVideoInfoHeader->VideoInfoHeader; nSize = KS_SIZE_VIDEOHEADER (pVideoInfoHdrRequested); KdPrint(("TsbVcap: New Format\n")); KdPrint(("TsbVcap: pVideoInfoHdrRequested=%x\n", pVideoInfoHdrRequested)); KdPrint(("TsbVcap: KS_VIDEOINFOHEADER size=%d\n", nSize)); KdPrint(("TsbVcap: Width=%d Height=%d BitCount=%d\n", pVideoInfoHdrRequested->bmiHeader.biWidth, pVideoInfoHdrRequested->bmiHeader.biHeight, pVideoInfoHdrRequested->bmiHeader.biBitCount)); KdPrint(("TsbVcap: biSizeImage=%d\n", pVideoInfoHdrRequested->bmiHeader.biSizeImage)); #ifdef TOSHIBA // '98-12-10 Added, for Bug-Report 253563 if ( (pVideoInfoHdrRequested->bmiHeader.biWidth & 0x03) || (pVideoInfoHdrRequested->bmiHeader.biHeight & 0x03) ) { pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } #endif//TOSHIBA #ifdef TOSHIBA for (Counter = 0; Counter < MAX_TSBVCAP_STREAMS; Counter++) { if ( pStrmExTmp = (PSTREAMEX)pHwDevExt->pStrmEx[Counter] ) { // Check other opened stream format if ( pStrmExTmp->pVideoInfoHeader ) { if ( (pStrmExTmp->pVideoInfoHeader->bmiHeader.biWidth != pVideoInfoHdrRequested->bmiHeader.biWidth) || (pStrmExTmp->pVideoInfoHeader->bmiHeader.biHeight != pVideoInfoHdrRequested->bmiHeader.biHeight) || (pStrmExTmp->pVideoInfoHeader->bmiHeader.biBitCount != pVideoInfoHdrRequested->bmiHeader.biBitCount) ) { pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } } } } #endif//TOSHIBA // // If a previous format was in use, release the memory // if (pStrmEx->pVideoInfoHeader) { ExFreePool(pStrmEx->pVideoInfoHeader); pStrmEx->pVideoInfoHeader = NULL; } // Since the VIDEOINFOHEADER is of potentially variable size // allocate memory for it pStrmEx->pVideoInfoHeader = ExAllocatePool(NonPagedPool, nSize); if (pStrmEx->pVideoInfoHeader == NULL) { KdPrint(("TsbVcap: ExAllocatePool failed\n")); pSrb->Status = STATUS_INSUFFICIENT_RESOURCES; return FALSE; } // Copy the VIDEOINFOHEADER requested to our storage RtlCopyMemory( pStrmEx->pVideoInfoHeader, pVideoInfoHdrRequested, nSize); #ifdef TOSHIBA if (pHwDevExt->NeedHWInit) HWInit(pHwDevExt); biWidth = pVideoInfoHdrRequested->bmiHeader.biWidth, biHeight = pVideoInfoHdrRequested->bmiHeader.biHeight, pHwDevExt->ulWidth = biWidth; pHwDevExt->ulHeight = biHeight; ImageSize = biWidth * biHeight; switch (pVideoInfoHdrRequested->bmiHeader.biCompression) { case FOURCC_YUV12: // I420 pHwDevExt->Format = FmtYUV12; pHwDevExt->YoffsetEven = 0; pHwDevExt->UoffsetEven = 0; pHwDevExt->VoffsetEven = 0; pHwDevExt->YoffsetOdd = 0; pHwDevExt->UoffsetOdd = 0; pHwDevExt->VoffsetOdd = 0; pHwDevExt->Ystride = 0; pHwDevExt->Ustride = 0; pHwDevExt->Vstride = 0; if ( CurrentOSType ) { // NT5.0 ImageSizeY = ImageSize; ImageSizeU = ImageSize / 4; ImageSizeV = ImageSize / 4; } else { // Win98 pHwDevExt->pCaptureBufferU = (PUCHAR)pHwDevExt->pCaptureBufferY + ImageSize; pHwDevExt->pCaptureBufferV = (PUCHAR)pHwDevExt->pCaptureBufferU + ImageSize/4; pHwDevExt->pPhysCaptureBufferU.LowPart = pHwDevExt->pPhysCaptureBufferY.LowPart + ImageSize; pHwDevExt->pPhysCaptureBufferV.LowPart = pHwDevExt->pPhysCaptureBufferU.LowPart + ImageSize/4; } ImageSize = ImageSize * 12 / 8; break; case FOURCC_YVU9: // YVU9 pHwDevExt->Format = FmtYUV9; pHwDevExt->YoffsetEven = 0; pHwDevExt->UoffsetEven = 0; pHwDevExt->VoffsetEven = 0; pHwDevExt->YoffsetOdd = 0; pHwDevExt->UoffsetOdd = 0; pHwDevExt->VoffsetOdd = 0; pHwDevExt->Ystride = 0; pHwDevExt->Ustride = 0; pHwDevExt->Vstride = 0; if ( CurrentOSType ) { // NT5.0 ImageSizeY = ImageSize; ImageSizeU = ImageSize / 16; ImageSizeV = ImageSize / 16; } else { // Win98 pHwDevExt->pCaptureBufferV = (PUCHAR)pHwDevExt->pCaptureBufferY + ImageSize; pHwDevExt->pCaptureBufferU = (PUCHAR)pHwDevExt->pCaptureBufferV + ImageSize/16; pHwDevExt->pPhysCaptureBufferV.LowPart = pHwDevExt->pPhysCaptureBufferY.LowPart + ImageSize; pHwDevExt->pPhysCaptureBufferU.LowPart = pHwDevExt->pPhysCaptureBufferV.LowPart + ImageSize/16; } ImageSize = ImageSize * 9 / 8; break; default: pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } if (ImageSize > MAX_CAPTURE_BUFFER_SIZE) { if (pStrmEx->pVideoInfoHeader) { ExFreePool(pStrmEx->pVideoInfoHeader); pStrmEx->pVideoInfoHeader = NULL; } pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } ulFrameRate = pHwDevExt->uiFramePerSecond; if (pHwDevExt->BufferSize != ImageSize) { if ( CurrentOSType ) { // NT5.0 ULONG ulSize; PVOID VirtualAddress; PHYSICAL_ADDRESS LimitAddress; PHYSICAL_ADDRESS PhysicalAddress; pHwDevExt->IsRPSReady = FALSE; if ( pHwDevExt->pCaptureBufferY ) { // free frame buffer MmFreeContiguousMemory(pHwDevExt->pCaptureBufferY); pHwDevExt->pCaptureBufferY = NULL; } if ( pHwDevExt->pCaptureBufferU ) { // free frame buffer MmFreeContiguousMemory(pHwDevExt->pCaptureBufferU); pHwDevExt->pCaptureBufferU = NULL; } if ( pHwDevExt->pCaptureBufferV ) { // free frame buffer MmFreeContiguousMemory(pHwDevExt->pCaptureBufferV); pHwDevExt->pCaptureBufferV = NULL; } // Allocate frame buffer LimitAddress.LowPart = 0xFFFFFFFF; LimitAddress.HighPart = 0; pHwDevExt->BufferSize = ImageSize; VirtualAddress = MmAllocateContiguousMemory(ImageSizeY, LimitAddress); if (VirtualAddress == 0) { pHwDevExt->pPhysCaptureBufferY.LowPart = 0; pHwDevExt->pPhysCaptureBufferY.HighPart = 0; pHwDevExt->pPhysCaptureBufferU.LowPart = 0; pHwDevExt->pPhysCaptureBufferU.HighPart = 0; pHwDevExt->pPhysCaptureBufferV.LowPart = 0; pHwDevExt->pPhysCaptureBufferV.HighPart = 0; pHwDevExt->BufferSize = 0; pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } RtlZeroMemory(VirtualAddress, ImageSizeY); pHwDevExt->pCaptureBufferY = VirtualAddress; PhysicalAddress = MmGetPhysicalAddress(pHwDevExt->pCaptureBufferY); pHwDevExt->pPhysCaptureBufferY = PhysicalAddress; VirtualAddress = MmAllocateContiguousMemory(ImageSizeU, LimitAddress); if (VirtualAddress == 0) { MmFreeContiguousMemory(pHwDevExt->pCaptureBufferY); pHwDevExt->pCaptureBufferY = NULL; pHwDevExt->pPhysCaptureBufferY.LowPart = 0; pHwDevExt->pPhysCaptureBufferY.HighPart = 0; pHwDevExt->pPhysCaptureBufferU.LowPart = 0; pHwDevExt->pPhysCaptureBufferU.HighPart = 0; pHwDevExt->pPhysCaptureBufferV.LowPart = 0; pHwDevExt->pPhysCaptureBufferV.HighPart = 0; pHwDevExt->BufferSize = 0; pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } RtlZeroMemory(VirtualAddress, ImageSizeU); pHwDevExt->pCaptureBufferU = VirtualAddress; PhysicalAddress = MmGetPhysicalAddress(pHwDevExt->pCaptureBufferU); pHwDevExt->pPhysCaptureBufferU = PhysicalAddress; VirtualAddress = MmAllocateContiguousMemory(ImageSizeV, LimitAddress); if (VirtualAddress == 0) { MmFreeContiguousMemory(pHwDevExt->pCaptureBufferY); pHwDevExt->pCaptureBufferY = NULL; MmFreeContiguousMemory(pHwDevExt->pCaptureBufferU); pHwDevExt->pCaptureBufferU = NULL; pHwDevExt->pPhysCaptureBufferY.LowPart = 0; pHwDevExt->pPhysCaptureBufferY.HighPart = 0; pHwDevExt->pPhysCaptureBufferU.LowPart = 0; pHwDevExt->pPhysCaptureBufferU.HighPart = 0; pHwDevExt->pPhysCaptureBufferV.LowPart = 0; pHwDevExt->pPhysCaptureBufferV.HighPart = 0; pHwDevExt->BufferSize = 0; pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } RtlZeroMemory(VirtualAddress, ImageSizeV); pHwDevExt->pCaptureBufferV = VirtualAddress; PhysicalAddress = MmGetPhysicalAddress(pHwDevExt->pCaptureBufferV); pHwDevExt->pPhysCaptureBufferV = PhysicalAddress; ulFrameRate = 15; pHwDevExt->dblBufflag = FALSE; } else { pHwDevExt->IsRPSReady = FALSE; pHwDevExt->BufferSize = ImageSize; if ((ImageSize * 2) > MAX_CAPTURE_BUFFER_SIZE) { ulFrameRate = 15; pHwDevExt->dblBufflag = FALSE; } else { ulFrameRate = 30; Alloc_TriBuffer(pHwDevExt); pHwDevExt->dblBufflag = TRUE; } } } if(!ImageSetInputImageSize(pHwDevExt, &(pHwDevExt->SrcRect))) // Insert 97-04-08(Tue) { pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } if(!ImageSetOutputImageSize(pHwDevExt, pHwDevExt->ulWidth, pHwDevExt->ulHeight)) // Insert 97-04-08(Tue) { pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } if (!BertFifoConfig(pHwDevExt, pHwDevExt->Format)) { pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } if(!ImageSetHueBrightnessContrastSat(pHwDevExt)){ // Insert 97-04-08(Tue) return FALSE; } if ( pHwDevExt->ColorEnable ) { if ( get_AblFilter( pHwDevExt ) ) { set_filtering( pHwDevExt, TRUE ); } else { set_filtering( pHwDevExt, FALSE ); pHwDevExt->ColorEnable = 0; } } else { set_filtering( pHwDevExt, FALSE ); } // // check the bounds for the frame rate // if (pHwDevExt->uiFramePerSecond != ulFrameRate) { pHwDevExt->uiFramePerSecond = ulFrameRate; pHwDevExt->IsRPSReady = FALSE; } if (pHwDevExt->IsRPSReady == FALSE) { dwAddr = (DWORD)pHwDevExt->pPhysRpsDMABuf.LowPart; #if 0 dwAddr = (dwAddr + 0x1FFF) & 0xFFFFE000; #endif pHwDevExt->s_physDmaActiveFlag = dwAddr + 0X1860; if( pHwDevExt->dblBufflag ){ BertTriBuildNodes(pHwDevExt); // Add 97-04-08(Tue) } else{ BertBuildNodes(pHwDevExt); // Add 97-04-08(Tue) } pHwDevExt->IsRPSReady = TRUE; } #endif//TOSHIBA } // ------------------------------------------------------------------- // Specifier FORMAT_AnalogVideo for KS_ANALOGVIDEOINFO // ------------------------------------------------------------------- else if (IsEqualGUID (&pKSDataFormat->Specifier, &KSDATAFORMAT_SPECIFIER_ANALOGVIDEO)) { // // AnalogVideo DataRange == DataFormat! // // For now, don't even cache this // TODO - Save the requested format // PKS_DATARANGE_ANALOGVIDEO pDataFormatAnalogVideo = (PKS_DATARANGE_ANALOGVIDEO) pSrb->CommandData.OpenFormat; } else { // Unknown format pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } return TRUE; } /* ** VideoReceiveDataPacket() ** ** Receives Video data packet commands on the output streams ** ** Arguments: ** ** pSrb - Stream request block for the Video stream ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VideoReceiveDataPacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; int StreamNumber = pSrb->StreamObject->StreamNumber; // // make sure we have a device extension and are at passive level // DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); DEBUG_ASSERT((ULONG)pHwDevExt); KdPrint(("TsbVcap: Receiving Stream Data SRB %8x, %x\n", pSrb, pSrb->Command)); // // Default to success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command){ case SRB_READ_DATA: // Rule: // Only accept read requests when in either the Pause or Run // States. If Stopped, immediately return the SRB. if (pStrmEx->KSState == KSSTATE_STOP) { CompleteStreamSRB (pSrb); break; } #ifdef TOSHIBA if (pHwDevExt->bVideoIn == FALSE) { CompleteStreamSRB (pSrb); break; } #endif//TOSHIBA // // Put this read request on the pending queue // VideoQueueAddSRB (pSrb); break; default: // // invalid / unsupported command. Fail it as such // TRAP pSrb->Status = STATUS_NOT_IMPLEMENTED; CompleteStreamSRB (pSrb); } // switch (pSrb->Command) } /* ** VideoReceiveCtrlPacket() ** ** Receives packet commands that control the Video output streams ** ** Arguments: ** ** pSrb - The stream request block for the Video stream ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VideoReceiveCtrlPacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; BOOL Busy; // // make sure we have a device extension and are at passive level // DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); DEBUG_ASSERT((ULONG)pHwDevExt); KdPrint(("TsbVcap: Receiving Stream Control SRB %8x, %x\n", pSrb, pSrb->Command)); // // If we're already processing an SRB, add it to the queue // Busy = AddToListIfBusy ( pSrb, &pHwDevExt->AdapterSpinLock, &pHwDevExt->ProcessingControlSRB [StreamNumber], &pHwDevExt->StreamControlSRBList[StreamNumber]); if (Busy) { return; } while (TRUE) { // // Default to success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command) { case SRB_PROPOSE_DATA_FORMAT: KdPrint(("TsbVcap: Receiving SRB_PROPOSE_DATA_FORMAT SRB %8x, StreamNumber= %d\n", pSrb, StreamNumber)); if (!(AdapterVerifyFormat ( pSrb->CommandData.OpenFormat, pSrb->StreamObject->StreamNumber))) { pSrb->Status = STATUS_NO_MATCH; KdPrint(("TsbVcap: SRB_PROPOSE_DATA_FORMAT FAILED\n")); } break; case SRB_SET_DATA_FORMAT: KdPrint(("TsbVcap: SRB_SET_DATA_FORMAT\n")); if (!(AdapterVerifyFormat ( pSrb->CommandData.OpenFormat, pSrb->StreamObject->StreamNumber))) { pSrb->Status = STATUS_NO_MATCH; KdPrint(("TsbVcap: SRB_SET_DATA_FORMAT FAILED\n")); } else { VideoSetFormat (pSrb); KdPrint(("TsbVcap: SRB_SET_DATA_FORMAT SUCCEEDED\n")); } break; case SRB_GET_DATA_FORMAT: KdPrint(("TsbVcap: SRB_GET_DATA_FORMAT\n")); pSrb->Status = STATUS_NOT_IMPLEMENTED; break; case SRB_SET_STREAM_STATE: VideoSetState(pSrb); break; case SRB_GET_STREAM_STATE: VideoGetState(pSrb); break; case SRB_GET_STREAM_PROPERTY: VideoGetProperty(pSrb); break; case SRB_SET_STREAM_PROPERTY: VideoSetProperty(pSrb); break; case SRB_INDICATE_MASTER_CLOCK: // // Assigns a clock to a stream // VideoIndicateMasterClock (pSrb); break; default: // // invalid / unsupported command. Fail it as such // pSrb->Status = STATUS_NOT_IMPLEMENTED; } CompleteStreamSRB (pSrb); // // See if there's anything else on the queue // Busy = RemoveFromListIfAvailable ( &pSrb, &pHwDevExt->AdapterSpinLock, &pHwDevExt->ProcessingControlSRB [StreamNumber], &pHwDevExt->StreamControlSRBList[StreamNumber]); if (!Busy) { break; } } } #ifndef TOSHIBA /* ** AnalogVideoReceiveDataPacket() ** ** Receives AnalogVideo data packet commands on the input stream ** ** Arguments: ** ** pSrb - Stream request block for the Analog Video stream. ** This stream receives tuner control packets. ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI AnalogVideoReceiveDataPacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PKSSTREAM_HEADER pDataPacket = pSrb->CommandData.DataBufferArray; // // make sure we have a device extension and are at passive level // DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); DEBUG_ASSERT((ULONG)pHwDevExt); KdPrint(("TsbVcap: Receiving Tuner packet SRB %8x, %x\n", pSrb, pSrb->Command)); // // Default to success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command){ case SRB_WRITE_DATA: // // This data packet contains the channel change information // passed on the AnalogVideoIn stream. Devices which support // VBI data streams need to pass this info on their output pins. // if (pDataPacket->FrameExtent == sizeof (KS_TVTUNER_CHANGE_INFO)) { RtlCopyMemory( &pHwDevExt->TVTunerChangeInfo, pDataPacket->Data, sizeof (KS_TVTUNER_CHANGE_INFO)); } CompleteStreamSRB (pSrb); break; default: // // invalid / unsupported command. Fail it as such // pSrb->Status = STATUS_NOT_IMPLEMENTED; CompleteStreamSRB (pSrb); } // switch (pSrb->Command) } /* ** AnalogVideoReceiveCtrlPacket() ** ** Receives packet commands that control the Analog Video stream ** ** Arguments: ** ** pSrb - The stream request block for the Video stream ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI AnalogVideoReceiveCtrlPacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; BOOL Busy; // // make sure we have a device extension and we are at passive level // DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); DEBUG_ASSERT((ULONG)pHwDevExt); KdPrint(("TsbVcap: Receiving Analog Stream Control SRB %8x, %x\n", pSrb, pSrb->Command)); // // If we're already processing an SRB, add it to the queue // Busy = AddToListIfBusy ( pSrb, &pHwDevExt->AdapterSpinLock, &pHwDevExt->ProcessingControlSRB [StreamNumber], &pHwDevExt->StreamControlSRBList[StreamNumber]); if (Busy) { return; } while (TRUE) { // // Default to success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command) { case SRB_PROPOSE_DATA_FORMAT: KdPrint(("TsbVcap: Receiving SRB_PROPOSE_DATA_FORMAT SRB %8x, StreamNumber= %d\n", pSrb, StreamNumber)); if (!(AdapterVerifyFormat ( pSrb->CommandData.OpenFormat, pSrb->StreamObject->StreamNumber))) { pSrb->Status = STATUS_NO_MATCH; } break; case SRB_SET_STREAM_STATE: // // Don't use VideoSetState, since we don't want to start another // timer running // pStrmEx->KSState = pSrb->CommandData.StreamState; break; case SRB_GET_STREAM_STATE: VideoGetState(pSrb); break; case SRB_GET_STREAM_PROPERTY: VideoGetProperty(pSrb); break; case SRB_INDICATE_MASTER_CLOCK: // // Assigns a clock to a stream // VideoIndicateMasterClock (pSrb); break; default: // // invalid / unsupported command. Fail it as such // pSrb->Status = STATUS_NOT_IMPLEMENTED; } CompleteStreamSRB (pSrb); // // See if there's anything else on the queue // Busy = RemoveFromListIfAvailable ( &pSrb, &pHwDevExt->AdapterSpinLock, &pHwDevExt->ProcessingControlSRB [StreamNumber], &pHwDevExt->StreamControlSRBList[StreamNumber]); if (!Busy) { break; } } } #endif//TOSHIBA /* ** CompleteStreamSRB () ** ** This routine is called when a packet is being completed. ** ** Arguments: ** ** pSrb - pointer to the request packet to be completed ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI CompleteStreamSRB ( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { KdPrint(("TsbVcap: Completing Stream SRB %8x\n", pSrb)); StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb); } /* ** VideoGetProperty() ** ** Routine to process video property requests ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoGetProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; if (IsEqualGUID (&KSPROPSETID_Connection, &pSPD->Property->Set)) { VideoStreamGetConnectionProperty (pSrb); } else if (IsEqualGUID (&PROPSETID_VIDCAP_DROPPEDFRAMES, &pSPD->Property->Set)) { VideoStreamGetDroppedFramesProperty (pSrb); } else { pSrb->Status = STATUS_NOT_IMPLEMENTED; } } /* ** VideoSetProperty() ** ** Routine to process video property requests ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoSetProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { // PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; pSrb->Status = STATUS_NOT_IMPLEMENTED; } #ifdef TOSHIBA #ifdef _FPS_COUNT_ VOID STREAMAPI VideoFpsOutputRoutine( IN PSTREAMEX pStrmEx ) { if (pStrmEx->KSState == KSSTATE_RUN) { DbgPrint("INT = %d FPS = %d\n", InterruptCounter, FrameCounter); InterruptCounter = 0; FrameCounter = 0; } } VOID STREAMAPI VideoTimerRoutine( PVOID Context ) { PSTREAMEX pStrmEx = ((PSTREAMEX)Context); PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; // If we're stopped and the timer is still running, just return. // This will stop the timer. if (pStrmEx->KSState == KSSTATE_STOP) { return; } // Capture a frame if it's time and we have a buffer VideoFpsOutputRoutine(pStrmEx); // Schedule the next timer event // Make it run at 2x the requested capture rate (which is in 100nS units) StreamClassScheduleTimer ( pStrmEx->pStreamObject, // StreamObject pHwDevExt, // HwDeviceExtension (ULONG) 1000000, // Microseconds VideoTimerRoutine, // TimerRoutine pStrmEx); // Context } #endif//_FPS_COUNT_ #else //TOSHIBA /* ** VideoTimerRoutine() ** ** A timer has been created based on the requested capture interval. ** This is the callback routine for this timer event. ** ** Note: Devices capable of using interrupts should always ** trigger capture on a VSYNC interrupt, and not use a timer. ** ** Arguments: ** ** Context - pointer to the stream extension ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VideoTimerRoutine( PVOID Context ) { PSTREAMEX pStrmEx = ((PSTREAMEX)Context); PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; // If we're stopped and the timer is still running, just return. // This will stop the timer. if (pStrmEx->KSState == KSSTATE_STOP) { return; } // Capture a frame if it's time and we have a buffer VideoCaptureRoutine(pStrmEx); // Schedule the next timer event // Make it run at 2x the requested capture rate (which is in 100nS units) StreamClassScheduleTimer ( pStrmEx->pStreamObject, // StreamObject pHwDevExt, // HwDeviceExtension (ULONG) (pStrmEx->pVideoInfoHeader->AvgTimePerFrame / 20), // Microseconds VideoTimerRoutine, // TimerRoutine pStrmEx); // Context } /* ** VideoCaptureRoutine() ** ** Routine to capture video frames based on a timer. ** ** Note: Devices capable of using interrupts should always ** trigger capture on a VSYNC interrupt, and not use a timer. ** ** Arguments: ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VideoCaptureRoutine( IN PSTREAMEX pStrmEx ) { PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; PKSSTREAM_HEADER pDataPacket; PKS_FRAME_INFO pFrameInfo; // If we're stopped and the timer is still running, just return. // This will stop the timer. if (pStrmEx->KSState == KSSTATE_STOP) { return; } // Find out what time it is, if we're using a clock if (pStrmEx->hMasterClock ) { HW_TIME_CONTEXT TimeContext; TimeContext.HwDeviceExtension = pHwDevExt; TimeContext.HwStreamObject = pStrmEx->pStreamObject; TimeContext.Function = TIME_GET_STREAM_TIME; StreamClassQueryMasterClockSync ( pStrmEx->hMasterClock, &TimeContext); pStrmEx->QST_StreamTime = TimeContext.Time; pStrmEx->QST_Now = TimeContext.SystemTime; if (pStrmEx->QST_NextFrame == 0) { pStrmEx->QST_NextFrame = pStrmEx->QST_StreamTime + pStrmEx->pVideoInfoHeader->AvgTimePerFrame; } #ifdef CREATE_A_FLURRY_OF_TIMING_SPEW KdPrint(("TsbVcap: Time=%16lx\n", TimeContext.Time)); KdPrint(("TsbVcap: SysTime=%16lx\n", TimeContext.SystemTime)); #endif } // Only capture in the RUN state if (pStrmEx->KSState == KSSTATE_RUN) { // // Determine if it is time to capture a frame based on // how much time has elapsed since capture started. // If there isn't a clock available, then capture immediately. // if ((!pStrmEx->hMasterClock) || (pStrmEx->QST_StreamTime >= pStrmEx->QST_NextFrame)) { PHW_STREAM_REQUEST_BLOCK pSrb; // Increment the picture count (usually this is VSYNC count) pStrmEx->FrameInfo.PictureNumber++; // // Get the next queue SRB (if any) // pSrb = VideoQueueRemoveSRB ( pHwDevExt, StreamNumber); if (pSrb) { pDataPacket = pSrb->CommandData.DataBufferArray; pFrameInfo = (PKS_FRAME_INFO) (pDataPacket + 1); // // Call the routine which synthesizes images // ImageSynth (pSrb, pHwDevExt->VideoInputConnected, pStrmEx->VideoControlMode & KS_VideoControlFlag_FlipHorizontal); // Set additional info fields about the data captured such as: // Frames Captured // Frames Dropped // Field Polarity pStrmEx->FrameInfo.ExtendedHeaderSize = pFrameInfo->ExtendedHeaderSize; *pFrameInfo = pStrmEx->FrameInfo; // Init the flags to zero pDataPacket->OptionsFlags = 0; // Set the discontinuity flag if frames have been previously // dropped, and then reset our internal flag if (pStrmEx->fDiscontinuity) { pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY; pStrmEx->fDiscontinuity = FALSE; } // // Return the timestamp for the frame // pDataPacket->PresentationTime.Numerator = 1; pDataPacket->PresentationTime.Denominator = 1; pDataPacket->Duration = pStrmEx->pVideoInfoHeader->AvgTimePerFrame; // // if we have a master clock AND this is the capture stream // if (pStrmEx->hMasterClock && (StreamNumber == 0)) { pDataPacket->PresentationTime.Time = pStrmEx->QST_StreamTime; pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID; } else { // // no clock or the preview stream, so just mark the time as unknown // pDataPacket->PresentationTime.Time = 0; // clear the timestamp valid flags pDataPacket->OptionsFlags &= ~(KSSTREAM_HEADER_OPTIONSF_TIMEVALID | KSSTREAM_HEADER_OPTIONSF_DURATIONVALID); } // Every frame we generate is a key frame (aka SplicePoint) // Delta frames (B or P) should not set this flag pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT; CompleteStreamSRB (pSrb); } // if we have an SRB else { // // No buffer was available when we should have captured one // Increment the counter which keeps track of // dropped frames pStrmEx->FrameInfo.DropCount++; // Set the (local) discontinuity flag // This will cause the next packet processed to have the // KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY flag set. pStrmEx->fDiscontinuity = TRUE; } // Figure out when to capture the next frame pStrmEx->QST_NextFrame += pStrmEx->pVideoInfoHeader->AvgTimePerFrame; } // endif time to capture a frame } // endif we're running } #endif//TOSHIBA /* ** VideoSetState() ** ** Sets the current state for a given stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoSetState( PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; int StreamNumber = pStrmEx->pStreamObject->StreamNumber; KSSTATE PreviousState; // // For each stream, the following states are used: // // Stop: Absolute minimum resources are used. No outstanding IRPs. // Acquire: KS only state that has no DirectShow correpondence // Acquire needed resources. // Pause: Getting ready to run. Allocate needed resources so that // the eventual transition to Run is as fast as possible. // Read SRBs will be queued at either the Stream class // or in your driver (depending on when you send "ReadyForNext") // and whether you're using the Stream class for synchronization // Run: Streaming. // // Moving to Stop to Run always transitions through Pause. // // But since a client app could crash unexpectedly, drivers should handle // the situation of having outstanding IRPs cancelled and open streams // being closed WHILE THEY ARE STREAMING! // // Note that it is quite possible to transition repeatedly between states: // Stop -> Pause -> Stop -> Pause -> Run -> Pause -> Run -> Pause -> Stop // // // Remember the state we're transitioning away from // PreviousState = pStrmEx->KSState; // // Set the new state // pStrmEx->KSState = pSrb->CommandData.StreamState; switch (pSrb->CommandData.StreamState) { case KSSTATE_STOP: // // The stream class will cancel all outstanding IRPs for us // (but only if it is maintaining the queue ie. using Stream Class synchronization) // Since TsbVcap is not using Stream Class synchronization, we must clear the queue here #ifdef TOSHIBA if (pHwDevExt->bVideoIn == TRUE) { // disable the RPS_INT and field interrupts BertInterruptEnable(pHwDevExt, FALSE); BertDMAEnable(pHwDevExt, FALSE); // wait for the current data xfer to complete // if (!BertIsCAPSTATReady(pHwDevExt)) return FALSE; pHwDevExt->bVideoIn = FALSE; } #endif//TOSHIBA VideoQueueCancelAllSRBs (pStrmEx); KdPrint(("TsbVcap: STATE Stopped, Stream=%d\n", StreamNumber)); break; case KSSTATE_ACQUIRE: // // This is a KS only state, that has no correspondence in DirectShow // KdPrint(("TsbVcap: STATE Acquire, Stream=%d\n", StreamNumber)); break; case KSSTATE_PAUSE: // // On a transition to pause from acquire or stop, start our timer running. // if (PreviousState == KSSTATE_ACQUIRE || PreviousState == KSSTATE_STOP) { // Zero the frame counters pStrmEx->FrameInfo.PictureNumber = 0; pStrmEx->FrameInfo.DropCount = 0; pStrmEx->FrameInfo.dwFrameFlags = 0; #ifdef TOSHIBA #ifdef _FPS_COUNT_ FrameCounter = 0; InterruptCounter = 0; StreamClassScheduleTimer ( pSrb->StreamObject, // StreamObject pHwDevExt, // HwDeviceExtension (ULONG) 1000000, // Microseconds VideoTimerRoutine, // TimerRoutine pStrmEx); // Context #endif//_FPS_COUNT_ if (!BertIsLocked(pHwDevExt)) { pHwDevExt->NeedHWInit = TRUE; } pHwDevExt->bVideoIn = TRUE; // enable the RPS_INT and field interrupts BertInterruptEnable(pHwDevExt, TRUE); BertDMAEnable(pHwDevExt, TRUE); } else { // disable the RPS_INT and field interrupts BertInterruptEnable(pHwDevExt, FALSE); BertDMAEnable(pHwDevExt, FALSE); // wait for the current data xfer to complete // if (!BertIsCAPSTATReady(pHwDevExt)) return FALSE; pHwDevExt->bVideoIn = FALSE; #else //TOSHIBA // Setup the next timer callback // Make it run at 2x the requested capture rate (which is in 100nS units) StreamClassScheduleTimer ( pSrb->StreamObject, // StreamObject pHwDevExt, // HwDeviceExtension (ULONG) (pStrmEx->pVideoInfoHeader->AvgTimePerFrame / 20), // Microseconds VideoTimerRoutine, // TimerRoutine pStrmEx); // Context #endif//TOSHIBA } KdPrint(("TsbVcap: STATE Pause, Stream=%d\n", StreamNumber)); break; case KSSTATE_RUN: // // Begin Streaming. // // Reset the discontinuity flag pStrmEx->fDiscontinuity = FALSE; // Setting the NextFrame time to zero will cause the value to be // reset from the stream time pStrmEx->QST_NextFrame = 0; #ifdef TOSHIBA if (pHwDevExt->bVideoIn == FALSE) { if (!BertIsLocked(pHwDevExt)) { pHwDevExt->NeedHWInit = TRUE; } pHwDevExt->bVideoIn = TRUE; // enable the RPS_INT and field interrupts BertInterruptEnable(pHwDevExt, TRUE); BertDMAEnable(pHwDevExt, TRUE); } #endif//TOSHIBA KdPrint(("TsbVcap: STATE Run, Stream=%d\n", StreamNumber)); break; } // end switch (pSrb->CommandData.StreamState) } /* ** VideoGetState() ** ** Gets the current state of the requested stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoGetState( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; pSrb->CommandData.StreamState = pStrmEx->KSState; pSrb->ActualBytesTransferred = sizeof (KSSTATE); // A very odd rule: // When transitioning from stop to pause, DShow tries to preroll // the graph. Capture sources can't preroll, and indicate this // by returning VFW_S_CANT_CUE in user mode. To indicate this // condition from drivers, they must return STATUS_NO_DATA_DETECTED if (pStrmEx->KSState == KSSTATE_PAUSE) { pSrb->Status = STATUS_NO_DATA_DETECTED; } } /* ** VideoStreamGetConnectionProperty() ** ** Gets the properties for a stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoStreamGetConnectionProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; ULONG Id = pSPD->Property->Id; // index of the property switch (Id) { // This property describes the allocator requirements for the stream case KSPROPERTY_CONNECTION_ALLOCATORFRAMING: if (pStrmEx->pVideoInfoHeader) { PKSALLOCATOR_FRAMING Framing = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo; Framing->RequirementsFlags = KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER | KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY; Framing->PoolType = PagedPool; Framing->Frames = 1; Framing->FrameSize = pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage; Framing->FileAlignment = 0; // FILE_LONG_ALIGNMENT???; Framing->Reserved = 0; pSrb->ActualBytesTransferred = sizeof (KSALLOCATOR_FRAMING); } else { pSrb->Status = STATUS_INVALID_PARAMETER; } break; default: break; } } /* ** VideoStreamGetDroppedFramesProperty() ** ** Gets dynamic information about the progress of the capture process. ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoStreamGetDroppedFramesProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; ULONG Id = pSPD->Property->Id; // index of the property switch (Id) { case KSPROPERTY_DROPPEDFRAMES_CURRENT: { PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames = (PKSPROPERTY_DROPPEDFRAMES_CURRENT_S) pSPD->PropertyInfo; pDroppedFrames->PictureNumber = pStrmEx->FrameInfo.PictureNumber; pDroppedFrames->DropCount = pStrmEx->FrameInfo.DropCount; pDroppedFrames->AverageFrameSize = pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage; pSrb->ActualBytesTransferred = sizeof (KSPROPERTY_DROPPEDFRAMES_CURRENT_S); } break; default: break; } } //==========================================================================; // Clock Handling Routines //==========================================================================; /* ** VideoIndicateMasterClock () ** ** If this stream is not being used as the master clock, this function ** is used to provide us with a handle to the clock to use when ** requesting the current stream time. ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID STREAMAPI VideoIndicateMasterClock( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; pStrmEx->hMasterClock = pSrb->CommandData.MasterClockHandle; } /* ** GetSystemTime () ** ** Returns the system time in 100 nS units ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ ULONGLONG STREAMAPI VideoGetSystemTime( ) { ULONGLONG ticks; ULONGLONG rate; ticks = (ULONGLONG)KeQueryPerformanceCounter((PLARGE_INTEGER)&rate).QuadPart; // // convert from ticks to 100ns clock // ticks = (ticks & 0xFFFFFFFF00000000) / rate * 10000000 + (ticks & 0x00000000FFFFFFFF) * 10000000 / rate; return(ticks); }