VOID STREAMAPI AdapterStreamInfo ( PHW_STREAM_REQUEST_BLOCK pSrb ) { int j; PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); // // pick up the pointer to header which preceeds the stream info structs // PHW_STREAM_HEADER pstrhdr = (PHW_STREAM_HEADER)&(pSrb->CommandData.StreamBuffer->StreamHeader); // // pick up the pointer to the array of stream information data structures // PHW_STREAM_INFORMATION pstrinfo = (PHW_STREAM_INFORMATION)&(pSrb->CommandData.StreamBuffer->StreamInfo); DbgLogInfo(("TestCap: Enter AdapterStreamInfo\n")); // // verify that the buffer is large enough to hold our return data // DEBUG_ASSERT (pSrb->NumberOfBytesToTransfer >= sizeof (HW_STREAM_HEADER) + sizeof (HW_STREAM_INFORMATION) * DRIVER_STREAM_COUNT); // // Set the header // StreamHeader.NumDevPropArrayEntries = NUMBER_OF_ADAPTER_PROPERTY_SETS; StreamHeader.DevicePropertiesArray = (PKSPROPERTY_SET) AdapterPropertyTable; *pstrhdr = StreamHeader; // // stuff the contents of each HW_STREAM_INFORMATION struct // for (j = 0; j < DRIVER_STREAM_COUNT; j++) { *pstrinfo++ = Streams[j].hwStreamInfo; } DbgLogInfo(("TestCap: Leave AdapterStreamInfo\n")); }
VOID STREAMAPI AdapterCancelPacket( PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension; PSTREAMEX pStrmEx; int StreamNumber; BOOL Found = FALSE; // // Run through all the streams the driver has available // for (StreamNumber = 0; !Found && (StreamNumber < DRIVER_STREAM_COUNT); StreamNumber++) { // // Check to see if the stream is in use // if (pStrmEx = (PSTREAMEX) pHwDevExt->pStrmEx[StreamNumber]) { Found = VideoQueueCancelOneSRB ( pStrmEx, pSrb ); } // if the stream is open } // for all streams DbgLogInfo(("TestCap: Cancelling SRB %8x Succeeded=%d\n", pSrb, Found)); }
VOID STREAMAPI AdapterGetProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; DbgLogInfo(("TestCap: Enter AdapterGetProperty\n")); if (IsEqualGUID(&PROPSETID_VIDCAP_VIDEOPROCAMP, &pSPD->Property->Set)) { AdapterGetVideoProcAmpProperty (pSrb); } else if (IsEqualGUID(&PROPSETID_VIDCAP_CAMERACONTROL, &pSPD->Property->Set)) { AdapterGetCameraControlProperty (pSrb); } else if (IsEqualGUID(&PROPSETID_VIDCAP_VIDEOCONTROL, &pSPD->Property->Set)) { AdapterGetVideoControlProperty (pSrb); } else if (IsEqualGUID (&PROPSETID_VIDCAP_VIDEOCOMPRESSION, &pSPD->Property->Set)) { AdapterGetVideoCompressionProperty (pSrb); } else { // // We should never get here // TRAP; pSrb->Status = STATUS_NOT_IMPLEMENTED; } }
ULONG DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { HW_INITIALIZATION_DATA HwInitData; ULONG ReturnValue; DbgLogInfo(("TestCap: DriverEntry\n")); RtlZeroMemory(&HwInitData, sizeof(HwInitData)); HwInitData.HwInitializationDataSize = sizeof(HwInitData); // // Set the Adapter entry points for the driver // HwInitData.HwInterrupt = NULL; // HwInterrupt; HwInitData.HwReceivePacket = AdapterReceivePacket; HwInitData.HwCancelPacket = AdapterCancelPacket; HwInitData.HwRequestTimeoutHandler = AdapterTimeoutPacket; HwInitData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); HwInitData.PerRequestExtensionSize = sizeof(SRB_EXTENSION); HwInitData.FilterInstanceExtensionSize = 0; HwInitData.PerStreamExtensionSize = sizeof(STREAMEX); HwInitData.BusMasterDMA = FALSE; HwInitData.Dma24BitAddresses = FALSE; HwInitData.BufferAlignment = 3; HwInitData.DmaBufferSize = 0; // Don't rely on the stream class using raised IRQL to synchronize // execution. This single paramter most affects the overall structure // of the driver. HwInitData.TurnOffSynchronization = TRUE; ReturnValue = StreamClassRegisterAdapter(DriverObject, RegistryPath, &HwInitData); DbgLogInfo(("Testcap: StreamClassRegisterAdapter = %x\n", ReturnValue)); return ReturnValue; }
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(pHwDevExt!=NULL); DbgLogInfo(("TestCap: Receiving Tuner packet SRB %p, %x\n", pSrb, pSrb->Command)); // // Default to success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command){ case SRB_WRITE_DATA: CompleteStreamSRB (pSrb); break; default: // // invalid / unsupported command. Fail it as such // TRAP; pSrb->Status = STATUS_NOT_IMPLEMENTED; CompleteStreamSRB (pSrb); } // switch (pSrb->Command) }
void DbgLogMediaTypeInfo(DWORD type, DWORD level, const CMediaType* pmt) { DbgLogInfo(type, level, TEXT(" MediaType Info : %s %s %s %s SampleSize=%ld"), FindName(g_MediaTypes, &pmt->majortype), FindName(g_MediaSubTypes, &pmt->subtype), (pmt->bFixedSizeSamples ? TEXT("FixedSamples") : TEXT("NotFixedSamples")), (pmt->bTemporalCompression ? TEXT("TemporalCompression") : TEXT("NotTemporalCompression")), pmt->lSampleSize); }
VOID STREAMAPI AdapterTimeoutPacket( PHW_STREAM_REQUEST_BLOCK pSrb ) { // // Unlike most devices, we need to hold onto data SRBs indefinitely, // since the graph could be in a pause state indefinitely // DbgLogInfo(("TestCap: Timeout Adapter SRB %8x\n", pSrb)); pSrb->TimeoutCounter = pSrb->TimeoutOriginal; }
VOID STREAMAPI AdapterCloseStream ( 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; PKSDATAFORMAT pKSDataFormat = pSrb->CommandData.OpenFormat; KS_VIDEOINFOHEADER *pVideoInfoHdr = pStrmEx->pVideoInfoHeader; DbgLogInfo(("TestCap: -------- ADAPTERCLOSESTREAM ------ StreamNumber=%d\n", StreamNumber)); if (pHwDevExt->StreamSRBListSize > 0) { VideoQueueCancelAllSRBs (pStrmEx); DbgLogError(("TestCap: Outstanding SRBs at stream close!!!\n")); } pHwDevExt->ActualInstances[StreamNumber]--; ASSERT (pHwDevExt->pStrmEx [StreamNumber] != 0); pHwDevExt->pStrmEx [StreamNumber] = 0; // // the minidriver should free any resources that were allocate at // open stream time etc. // // Free the variable length VIDEOINFOHEADER if (pVideoInfoHdr) { ExFreePool(pVideoInfoHdr); pStrmEx->pVideoInfoHeader = NULL; } // Make sure we no longer reference the clock pStrmEx->hMasterClock = NULL; // Make sure the state is reset to stopped, pStrmEx->KSState = KSSTATE_STOP; }
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(pHwDevExt!=NULL); DbgLogTrace(("TestCap: Receiving Stream Control SRB %p, %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: DbgLogInfo(("TestCap: Receiving SRB_PROPOSE_DATA_FORMAT SRB %p, StreamNumber= %d\n", pSrb, StreamNumber)); if (!(AdapterVerifyFormat ( pSrb->CommandData.OpenFormat, pSrb->StreamObject->StreamNumber))) { pSrb->Status = STATUS_NO_MATCH; DbgLogInfo(("TestCap: SRB_PROPOSE_DATA_FORMAT FAILED\n")); } // KS support for dynamic format changes is BROKEN right now, // so we prevent these from happening by saying they ALL fail. // If this is ever fixed, the next line must be removed. pSrb->Status = STATUS_NO_MATCH; // prevent dynamic format changes break; case SRB_SET_DATA_FORMAT: DbgLogInfo(("TestCap: SRB_SET_DATA_FORMAT\n")); if (!(AdapterVerifyFormat ( pSrb->CommandData.OpenFormat, pSrb->StreamObject->StreamNumber))) { pSrb->Status = STATUS_NO_MATCH; DbgLogInfo(("TestCap: SRB_SET_DATA_FORMAT FAILED\n")); } else { VideoSetFormat (pSrb); DbgLogInfo(("TestCap: SRB_SET_DATA_FORMAT SUCCEEDED\n")); } break; case SRB_GET_DATA_FORMAT: DbgLogInfo(("TestCap: 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 // TRAP; 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; } } }
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; // ------------------------------------------------------------------- // 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); DbgLogInfo(("TestCap: New Format\n")); DbgLogInfo(("TestCap: pVideoInfoHdrRequested=%p\n", pVideoInfoHdrRequested)); DbgLogInfo(("TestCap: KS_VIDEOINFOHEADER size=%d\n", nSize)); DbgLogInfo(("TestCap: Width=%d Height=%d BitCount=%d\n", pVideoInfoHdrRequested->bmiHeader.biWidth, pVideoInfoHdrRequested->bmiHeader.biHeight, pVideoInfoHdrRequested->bmiHeader.biBitCount)); DbgLogInfo(("TestCap: biSizeImage=%d\n", pVideoInfoHdrRequested->bmiHeader.biSizeImage)); // // 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) { DbgLogError(("TestCap: ExAllocatePool failed\n")); pSrb->Status = STATUS_INSUFFICIENT_RESOURCES; return FALSE; } // Copy the VIDEOINFOHEADER requested to our storage RtlCopyMemory( pStrmEx->pVideoInfoHeader, pVideoInfoHdrRequested, nSize); // A renderer may be switching formats, and in this case, the AvgTimePerFrame // will be zero. Don't overwrite a previously set framerate. if (pStrmEx->pVideoInfoHeader->AvgTimePerFrame) { pStrmEx->AvgTimePerFrame = pStrmEx->pVideoInfoHeader->AvgTimePerFrame; } } else { // Unknown format pSrb->Status = STATUS_INVALID_PARAMETER; return FALSE; } return TRUE; }
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); DbgLogInfo(("TestCap: VideoQueueCancelOneSRB FOUND Srb=%p, Stream=%d\n", pSrb, StreamNumber)); } DbgLogInfo(("TestCap: VideoQueueCancelOneSRB Completed Stream=%d\n", StreamNumber)); return Found; }
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) { DbgLogInfo(("TestCap: VideoQueueCancelAllSRBs 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; DbgLogInfo(("TestCap: VideoQueueCancelALLSRBs FOUND Srb=%p, Stream=%d\n", pSrb, StreamNumber)); CompleteStreamSRB (pSrb); } KeReleaseSpinLock (&pHwDevExt->StreamSRBSpinLock[StreamNumber], oldIrql); DbgLogInfo(("TestCap: VideoQueueCancelAll Completed\n")); }
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 Testcap is not using Stream Class synchronization, we must clear the queue here VideoQueueCancelAllSRBs (pStrmEx); DbgLogInfo(("TestCap: STATE Stopped, Stream=%d\n", StreamNumber)); break; case KSSTATE_ACQUIRE: // // This is a KS only state, that has no correspondence in DirectShow // DbgLogInfo(("TestCap: 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; // Setup the next timer callback(s) VideoTimerRoutine(pStrmEx); } DbgLogInfo(("TestCap: 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; DbgLogInfo(("TestCap: STATE Run, Stream=%d\n", StreamNumber)); break; } // end switch (pSrb->CommandData.StreamState) }
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->AvgTimePerFrame; } #ifdef CREATE_A_FLURRY_OF_TIMING_SPEW DbgLogTrace(("TestCap: Time=%6d mS at SystemTime=%I64d\n", (LONG) ((LONGLONG) TimeContext.Time / 10000), 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, IMAGE_XFER_GRAY_INCREASING, 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->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; // Output a frame count every 100th frame in Debug mode if (pStrmEx->FrameInfo.PictureNumber % 100 == 0) { DbgLogInfo(("TestCap: Picture %u, Stream=%d\n", (unsigned int)pStrmEx->FrameInfo.PictureNumber, StreamNumber)); } 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->AvgTimePerFrame; } // endif time to capture a frame } // endif we're running }
void DbgLogMediaFormatInfo(DWORD type, DWORD level, const CMediaType* pmt) { DbgLogInfo(type, level, TEXT(" Format Info : %s FormatSize=%ld"), FindName(g_MediaFormats, &pmt->formattype), pmt->cbFormat); if (pmt->formattype == FORMAT_VideoInfo) { if (pmt->pbFormat == NULL || pmt->cbFormat < sizeof(VIDEOINFOHEADER)) { DbgLogInfo(type, level, TEXT(" !! INVALID FORMAT !!")); return; } VIDEOINFOHEADER* pvh = (VIDEOINFOHEADER*)pmt->pbFormat; DbgLogInfo(type, level, TEXT(" Source : %ld, %ld, %ld, %ld"), pvh->rcSource.left, pvh->rcSource.top, pvh->rcSource.right, pvh->rcSource.bottom); DbgLogInfo(type, level, TEXT(" Target : %ld, %ld, %ld, %ld"), pvh->rcTarget.left, pvh->rcTarget.top, pvh->rcTarget.right, pvh->rcTarget.bottom); DbgLogInfo(type, level, TEXT(" BitRate / BitErrorRate : %lu / %lu"), pvh->dwBitRate, pvh->dwBitErrorRate); DbgLogInfo(type, level, TEXT(" AvgTimePerFrame : %lld"), pvh->AvgTimePerFrame); DbgLogInfo(type, level, TEXT(" Header Size=%lu"), pvh->bmiHeader.biSize); DbgLogInfo(type, level, TEXT(" Width x Height = %ld x %ld"), pvh->bmiHeader.biWidth, pvh->bmiHeader.biHeight); DbgLogInfo(type, level, TEXT(" Planes, BitCount = %u, %u"), pvh->bmiHeader.biPlanes, pvh->bmiHeader.biBitCount); DbgLogInfo(type, level, TEXT(" Compression = %lu"), pvh->bmiHeader.biCompression); DbgLogInfo(type, level, TEXT(" SizeImage = %lu"), pvh->bmiHeader.biSizeImage); DbgLogInfo(type, level, TEXT(" PelsPerMeter = %ld x %ld"), pvh->bmiHeader.biXPelsPerMeter, pvh->bmiHeader.biYPelsPerMeter); DbgLogInfo(type, level, TEXT(" ColorUsed(Important) = %lu(%lu)"), pvh->bmiHeader.biClrUsed, pvh->bmiHeader.biClrImportant); } else if (pmt->formattype == FORMAT_VideoInfo2) { if (pmt->pbFormat == NULL || pmt->cbFormat < sizeof(VIDEOINFOHEADER2)) { DbgLogInfo(type, level, TEXT(" !! INVALID FORMAT !!")); return; } VIDEOINFOHEADER2* pvh = (VIDEOINFOHEADER2*)pmt->pbFormat; DbgLogInfo(type, level, TEXT(" Source : %ld, %ld, %ld, %ld"), pvh->rcSource.left, pvh->rcSource.top, pvh->rcSource.right, pvh->rcSource.bottom); DbgLogInfo(type, level, TEXT(" Target : %ld, %ld, %ld, %ld"), pvh->rcTarget.left, pvh->rcTarget.top, pvh->rcTarget.right, pvh->rcTarget.bottom); DbgLogInfo(type, level, TEXT(" BitRate / BitErrorRate : %lu / %lu"), pvh->dwBitRate, pvh->dwBitErrorRate); DbgLogInfo(type, level, TEXT(" AvgTimePerFrame : %lld"), pvh->AvgTimePerFrame); DbgLogInfo(type, level, TEXT(" InterlaceFlags : 0x%08x"), pvh->dwInterlaceFlags); DbgLogInfo(type, level, TEXT(" CopyProtectFlags : 0x%08x"), pvh->dwCopyProtectFlags); DbgLogInfo(type, level, TEXT(" PictAspectRatio : %lu x %lu"), pvh->dwPictAspectRatioX, pvh->dwPictAspectRatioY); DbgLogInfo(type, level, TEXT(" ControlFlags : 0x%08x"), pvh->dwControlFlags); DbgLogInfo(type, level, TEXT(" Header Size=%lu"), pvh->bmiHeader.biSize); DbgLogInfo(type, level, TEXT(" Width x Height = %ld x %ld"), pvh->bmiHeader.biWidth, pvh->bmiHeader.biHeight); DbgLogInfo(type, level, TEXT(" Planes, BitCount = %u, %u"), pvh->bmiHeader.biPlanes, pvh->bmiHeader.biBitCount); DbgLogInfo(type, level, TEXT(" Compression = %lu"), pvh->bmiHeader.biCompression); DbgLogInfo(type, level, TEXT(" SizeImage = %lu"), pvh->bmiHeader.biSizeImage); DbgLogInfo(type, level, TEXT(" PelsPerMeter = %ld x %ld"), pvh->bmiHeader.biXPelsPerMeter, pvh->bmiHeader.biYPelsPerMeter); DbgLogInfo(type, level, TEXT(" ColorUsed(Important) = %lu(%lu)"), pvh->bmiHeader.biClrUsed, pvh->bmiHeader.biClrImportant); } else if (pmt->formattype == FORMAT_WaveFormatEx) { if (pmt->pbFormat == NULL || sizeof(WAVEFORMATEX) < pmt->cbFormat) { DbgLogInfo(type, level, TEXT(" !! INVALID FORMAT !!")); return; } WAVEFORMATEX * pvh = (WAVEFORMATEX *)pmt->pbFormat; DbgLogInfo(type, level, TEXT(" FormatTag : %u"), pvh->wFormatTag); DbgLogInfo(type, level, TEXT(" Channels : %u"), pvh->nChannels); DbgLogInfo(type, level, TEXT(" SamplesPerSec : %lu"), pvh->nSamplesPerSec); DbgLogInfo(type, level, TEXT(" AvgBytesPerSec : %lu"), pvh->nAvgBytesPerSec); DbgLogInfo(type, level, TEXT(" BlockAlign : %u"), pvh->nBlockAlign); DbgLogInfo(type, level, TEXT(" BitsPerSample : %u"), pvh->wBitsPerSample); DbgLogInfo(type, level, TEXT(" Size : %u"), pvh->cbSize); } if (pmt->formattype == FORMAT_MPEGVideo) { if (pmt->pbFormat == NULL || sizeof(MPEG1VIDEOINFO) < pmt->cbFormat) { DbgLogInfo(type, level, TEXT(" !! INVALID FORMAT !!")); return; } MPEG1VIDEOINFO* pvh = (MPEG1VIDEOINFO*)pmt->pbFormat; DbgLogInfo(type, level, TEXT(" Source : %ld, %ld, %ld, %ld"), pvh->hdr.rcSource.left, pvh->hdr.rcSource.top, pvh->hdr.rcSource.right, pvh->hdr.rcSource.bottom); DbgLogInfo(type, level, TEXT(" Target : %ld, %ld, %ld, %ld"), pvh->hdr.rcTarget.left, pvh->hdr.rcTarget.top, pvh->hdr.rcTarget.right, pvh->hdr.rcTarget.bottom); DbgLogInfo(type, level, TEXT(" BitRate / BitErrorRate : %lu / %lu"), pvh->hdr.dwBitRate, pvh->hdr.dwBitErrorRate); DbgLogInfo(type, level, TEXT(" AvgTimePerFrame : %lld"), pvh->hdr.AvgTimePerFrame); DbgLogInfo(type, level, TEXT(" Header Size=%lu"), pvh->hdr.bmiHeader.biSize); DbgLogInfo(type, level, TEXT(" Width x Height = %ld x %ld"), pvh->hdr.bmiHeader.biWidth, pvh->hdr.bmiHeader.biHeight); DbgLogInfo(type, level, TEXT(" Planes, BitCount = %u, %u"), pvh->hdr.bmiHeader.biPlanes, pvh->hdr.bmiHeader.biBitCount); DbgLogInfo(type, level, TEXT(" Compression = %lu"), pvh->hdr.bmiHeader.biCompression); DbgLogInfo(type, level, TEXT(" SizeImage = %lu"), pvh->hdr.bmiHeader.biSizeImage); DbgLogInfo(type, level, TEXT(" PelsPerMeter = %ld x %ld"), pvh->hdr.bmiHeader.biXPelsPerMeter, pvh->hdr.bmiHeader.biYPelsPerMeter); DbgLogInfo(type, level, TEXT(" ColorUsed(Important) = %lu(%lu)"), pvh->hdr.bmiHeader.biClrUsed, pvh->hdr.bmiHeader.biClrImportant); DbgLogInfo(type, level, TEXT(" StartTimeCode = %lu"), pvh->dwStartTimeCode); DbgLogInfo(type, level, TEXT(" SequenceHeader = %lu"), pvh->cbSequenceHeader); } // TODO:残りのフォーマット対応 // FORMAT_MPEGStreams // FORMAT_DvInfo // FORMAT_525WSS // FORMAT_AnalogVideo }
BOOL STREAMAPI AdapterFormatFromRange( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAM_DATA_INTERSECT_INFO IntersectInfo; PKSDATARANGE DataRange; BOOL OnlyWantsSize; BOOL MatchFound = FALSE; ULONG FormatSize; ULONG StreamNumber; ULONG j; ULONG NumberOfFormatArrayEntries; PKSDATAFORMAT *pAvailableFormats; DbgLogInfo(("TestCap: Enter AdapterFormatFromRange\n")); IntersectInfo = pSrb->CommandData.IntersectInfo; StreamNumber = IntersectInfo->StreamNumber; DataRange = IntersectInfo->DataRange; // // Check that the stream number is valid // if (StreamNumber >= DRIVER_STREAM_COUNT) { pSrb->Status = STATUS_NOT_IMPLEMENTED; TRAP; return FALSE; } NumberOfFormatArrayEntries = Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries; // // Get the pointer to the array of available formats // pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray; // // Is the caller trying to get the format, or the size of the format? // OnlyWantsSize = (IntersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG)); // // Walk the formats supported by the stream searching for a match // of the three GUIDs which together define a DATARANGE // for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) { if (!AdapterCompareGUIDsAndFormatSize( DataRange, *pAvailableFormats, TRUE /* CompareFormatSize */)) { continue; } // // Now that the three GUIDs match, do a further type-specific check // // ------------------------------------------------------------------- // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER // ------------------------------------------------------------------- if (IsEqualGUID (&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) { PKS_DATARANGE_VIDEO DataRangeVideoToVerify = (PKS_DATARANGE_VIDEO) DataRange; PKS_DATARANGE_VIDEO DataRangeVideo = (PKS_DATARANGE_VIDEO) *pAvailableFormats; PKS_DATAFORMAT_VIDEOINFOHEADER DataFormatVideoInfoHeaderOut; // // Check that the other fields match // if ((DataRangeVideoToVerify->bFixedSizeSamples != DataRangeVideo->bFixedSizeSamples) || (DataRangeVideoToVerify->bTemporalCompression != DataRangeVideo->bTemporalCompression) || (DataRangeVideoToVerify->StreamDescriptionFlags != DataRangeVideo->StreamDescriptionFlags) || (DataRangeVideoToVerify->MemoryAllocationFlags != DataRangeVideo->MemoryAllocationFlags) || (RtlCompareMemory (&DataRangeVideoToVerify->ConfigCaps, &DataRangeVideo->ConfigCaps, sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) != sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))) { continue; } // MATCH FOUND! MatchFound = TRUE; if(MatchFound) { DbgLogInfo(("TestCap: MatchFound!!!!\n")); } FormatSize = sizeof (KSDATAFORMAT) + KS_SIZE_VIDEOHEADER (&DataRangeVideoToVerify->VideoInfoHeader); if (OnlyWantsSize) { break; } // Caller wants the full data format if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) { pSrb->Status = STATUS_BUFFER_TOO_SMALL; return FALSE; } // Copy over the KSDATAFORMAT, followed by the // actual VideoInfoHeader DataFormatVideoInfoHeaderOut = (PKS_DATAFORMAT_VIDEOINFOHEADER) IntersectInfo->DataFormatBuffer; // Copy over the KSDATAFORMAT RtlCopyMemory( &DataFormatVideoInfoHeaderOut->DataFormat, &DataRangeVideoToVerify->DataRange, sizeof (KSDATARANGE)); DataFormatVideoInfoHeaderOut->DataFormat.FormatSize = FormatSize; // Copy over the callers requested VIDEOINFOHEADER RtlCopyMemory( &DataFormatVideoInfoHeaderOut->VideoInfoHeader, &DataRangeVideoToVerify->VideoInfoHeader, KS_SIZE_VIDEOHEADER (&DataRangeVideoToVerify->VideoInfoHeader)); // Calculate biSizeImage for this request, and put the result in both // the biSizeImage field of the bmiHeader AND in the SampleSize field // of the DataFormat. // // Note that for compressed sizes, this calculation will probably not // be just width * height * bitdepth DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader.biSizeImage = DataFormatVideoInfoHeaderOut->DataFormat.SampleSize = KS_DIBSIZE(DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader); // // Perform other validation such as cropping and scaling checks // break; } // End of VIDEOINFOHEADER specifier // ------------------------------------------------------------------- // Specifier FORMAT_AnalogVideo for KS_ANALOGVIDEOINFO // ------------------------------------------------------------------- else if (IsEqualGUID (&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_ANALOGVIDEO)) { // // For analog video, the DataRange and DataFormat // are identical, so just copy the whole structure // PKS_DATARANGE_ANALOGVIDEO DataRangeVideo = (PKS_DATARANGE_ANALOGVIDEO) *pAvailableFormats; // MATCH FOUND! MatchFound = TRUE; FormatSize = sizeof (KS_DATARANGE_ANALOGVIDEO); if (OnlyWantsSize) { break; } // Caller wants the full data format if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) { pSrb->Status = STATUS_BUFFER_TOO_SMALL; return FALSE; } RtlCopyMemory( IntersectInfo->DataFormatBuffer, DataRangeVideo, sizeof (KS_DATARANGE_ANALOGVIDEO)); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; break; } // End of KS_ANALOGVIDEOINFO specifier // ------------------------------------------------------------------- // Specifier FORMAT_VBI for KS_VIDEO_VBI // ------------------------------------------------------------------- else if (IsEqualGUID (&DataRange->Specifier, &KSDATAFORMAT_SPECIFIER_VBI)) { PKS_DATARANGE_VIDEO_VBI pDataRangeVBI = (PKS_DATARANGE_VIDEO_VBI)*pAvailableFormats; PKS_DATAFORMAT_VBIINFOHEADER InterVBIHdr = (PKS_DATAFORMAT_VBIINFOHEADER)IntersectInfo->DataFormatBuffer; // MATCH FOUND! MatchFound = TRUE; FormatSize = sizeof (KS_DATAFORMAT_VBIINFOHEADER); // Is the caller trying to get the format, or the size of it? if (OnlyWantsSize) break; // Verify that there is enough room in the supplied buffer // for the whole thing if (IntersectInfo->SizeOfDataFormatBuffer < FormatSize) { if (IntersectInfo->SizeOfDataFormatBuffer > 0) { DbgLogError( ("Testcap::AdapterFormatFromRange: " "Specifier==VBI, Buffer too small=%d vs. %d\n", IntersectInfo->SizeOfDataFormatBuffer, FormatSize)); } pSrb->Status = STATUS_BUFFER_TOO_SMALL; return FALSE; } // If there is room, go ahead... RtlCopyMemory(&InterVBIHdr->DataFormat, &pDataRangeVBI->DataRange, sizeof (KSDATARANGE)); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; RtlCopyMemory(&InterVBIHdr->VBIInfoHeader, &pDataRangeVBI->VBIInfoHeader, sizeof(KS_VBIINFOHEADER)); break; } // End of KS_VIDEO_VBI specifier // ------------------------------------------------------------------- // Type FORMAT_NABTS for NABTS pin // ------------------------------------------------------------------- else if (IsEqualGUID (&DataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_NABTS)) { PKSDATARANGE pDataRange = (PKSDATARANGE)*pAvailableFormats; // MATCH FOUND! MatchFound = TRUE; FormatSize = sizeof (KSDATAFORMAT); // Is the caller trying to get the format, or the size of it? if (OnlyWantsSize) break; // Verify that there is enough room in the supplied buffer // for the whole thing if (IntersectInfo->SizeOfDataFormatBuffer >= FormatSize) { RtlCopyMemory(IntersectInfo->DataFormatBuffer, pDataRange, FormatSize); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; } else { if (IntersectInfo->SizeOfDataFormatBuffer > 0) { DbgLogError( ("Testcap::AdapterFormatFromRange: " "SubFormat==NABTS, Buffer too small=%d vs. %d\n", IntersectInfo->SizeOfDataFormatBuffer, FormatSize)); } pSrb->Status = STATUS_BUFFER_TOO_SMALL; return FALSE; } break; } // End of KS_SUBTYPE_NABTS // ------------------------------------------------------------------- // for CC pin // ------------------------------------------------------------------- else if (IsEqualGUID (&DataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_CC)) { PKSDATARANGE pDataRange = (PKSDATARANGE)*pAvailableFormats; // MATCH FOUND! MatchFound = TRUE; FormatSize = sizeof (KSDATAFORMAT); // Is the caller trying to get the format, or the size of it? if (OnlyWantsSize) break; // Verify that there is enough room in the supplied buffer // for the whole thing if (IntersectInfo->SizeOfDataFormatBuffer >= FormatSize) { RtlCopyMemory(IntersectInfo->DataFormatBuffer, pDataRange, FormatSize); ((PKSDATAFORMAT)IntersectInfo->DataFormatBuffer)->FormatSize = FormatSize; } else { if (IntersectInfo->SizeOfDataFormatBuffer > 0) { DbgLogError( ("Testcap::AdapterFormatFromRange: " "SubFormat==CC, Buffer too small=%d vs. %d\n", IntersectInfo->SizeOfDataFormatBuffer, FormatSize)); } pSrb->Status = STATUS_BUFFER_TOO_SMALL; return FALSE; } break; } // End of CC pin format check else { pSrb->Status = STATUS_NO_MATCH; return FALSE; } } // End of loop on all formats for this stream if (!MatchFound) { pSrb->Status = STATUS_NO_MATCH; return FALSE; } if (OnlyWantsSize) { *(PULONG) IntersectInfo->DataFormatBuffer = FormatSize; FormatSize = sizeof(ULONG); } pSrb->ActualBytesTransferred = FormatSize; return TRUE; }
BOOLEAN STREAMAPI HwInitialize ( IN OUT PHW_STREAM_REQUEST_BLOCK pSrb ) { STREAM_PHYSICAL_ADDRESS adr; ULONG Size; PUCHAR pDmaBuf; int j; PPORT_CONFIGURATION_INFORMATION ConfigInfo = pSrb->CommandData.ConfigInfo; PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)ConfigInfo->HwDeviceExtension; DbgLogInfo(("Testcap: HwInitialize()\n")); if (ConfigInfo->NumberOfAccessRanges != 0) { DbgLogError(("Testcap: illegal config info\n")); pSrb->Status = STATUS_NO_SUCH_DEVICE; return (FALSE); } DbgLogInfo(("TestCap: Number of access ranges = %lx\n", ConfigInfo->NumberOfAccessRanges)); DbgLogInfo(("TestCap: Memory Range = %lx\n", pHwDevExt->ioBaseLocal)); DbgLogInfo(("TestCap: IRQ = %lx\n", ConfigInfo->BusInterruptLevel)); if (ConfigInfo->NumberOfAccessRanges != 0) { pHwDevExt->ioBaseLocal = (PULONG)(ULONG_PTR) (ConfigInfo->AccessRanges[0].RangeStart.LowPart); } pHwDevExt->Irq = (USHORT)(ConfigInfo->BusInterruptLevel); ConfigInfo->StreamDescriptorSize = sizeof (HW_STREAM_HEADER) + DRIVER_STREAM_COUNT * sizeof (HW_STREAM_INFORMATION); pDmaBuf = StreamClassGetDmaBuffer(pHwDevExt); adr = StreamClassGetPhysicalAddress(pHwDevExt, NULL, pDmaBuf, DmaBuffer, &Size); // Init VideoProcAmp properties pHwDevExt->Brightness = BrightnessDefault; pHwDevExt->BrightnessFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO; pHwDevExt->Contrast = ContrastDefault; pHwDevExt->ContrastFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO; pHwDevExt->ColorEnable = ColorEnableDefault; pHwDevExt->ColorEnableFlags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL; // Init CameraControl properties pHwDevExt->Focus = FocusDefault; pHwDevExt->FocusFlags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO; pHwDevExt->Zoom = ZoomDefault; pHwDevExt->ZoomFlags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO; // Init VideoControl properties pHwDevExt->VideoControlMode = 0; // Init VideoCompression properties pHwDevExt->CompressionSettings.CompressionKeyFrameRate = 15; pHwDevExt->CompressionSettings.CompressionPFramesPerKeyFrame = 3; pHwDevExt->CompressionSettings.CompressionQuality = 5000; pHwDevExt->PDO = ConfigInfo->RealPhysicalDeviceObject; DbgLogInfo(("TestCap: Physical Device Object = %lx\n", pHwDevExt->PDO)); for (j = 0; j < MAX_TESTCAP_STREAMS; j++){ // For each stream, maintain a separate queue for data and control InitializeListHead (&pHwDevExt->StreamSRBList[j]); InitializeListHead (&pHwDevExt->StreamControlSRBList[j]); KeInitializeSpinLock (&pHwDevExt->StreamSRBSpinLock[j]); pHwDevExt->StreamSRBListSize[j] = 0; } // Init ProtectionStatus pHwDevExt->ProtectionStatus = 0; // The following allows multiple instance of identical hardware // to be installed. GlobalDriverMediumInstanceCount is set in the Medium.Id field. pHwDevExt->DriverMediumInstanceCount = GlobalDriverMediumInstanceCount++; DbgLogInfo(("TestCap: Exit, HwInitialize()\n")); pSrb->Status = STATUS_SUCCESS; return (TRUE); }
VOID STREAMAPI AdapterOpenStream ( PHW_STREAM_REQUEST_BLOCK pSrb ) { // // the stream extension structure is allocated by the stream class driver // PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); int StreamNumber = pSrb->StreamObject->StreamNumber; PKSDATAFORMAT pKSDataFormat = pSrb->CommandData.OpenFormat; RtlZeroMemory(pStrmEx, sizeof(STREAMEX)); DbgLogInfo(("TestCap: ------- ADAPTEROPENSTREAM ------- StreamNumber=%d\n", StreamNumber)); // // check that the stream index requested isn't too high // or that the maximum number of instances hasn't been exceeded // if (StreamNumber >= DRIVER_STREAM_COUNT || StreamNumber < 0) { pSrb->Status = STATUS_INVALID_PARAMETER; return; } // // Check that we haven't exceeded the instance count for this stream // if (pHwDevExt->ActualInstances[StreamNumber] >= Streams[StreamNumber].hwStreamInfo.NumberOfPossibleInstances) { pSrb->Status = STATUS_INVALID_PARAMETER; return; } // // Check the validity of the format being requested // if (!AdapterVerifyFormat (pKSDataFormat, StreamNumber)) { pSrb->Status = STATUS_INVALID_PARAMETER; return; } // // And set the format for the stream // if (!VideoSetFormat (pSrb)) { return; } ASSERT (pHwDevExt->pStrmEx [StreamNumber] == NULL); // Maintain an array of all the StreamEx structures in the HwDevExt // so that we can cancel IRPs from any stream pHwDevExt->pStrmEx [StreamNumber] = (PSTREAMX) pStrmEx; // Set up pointers to the handlers for the stream data and control handlers pSrb->StreamObject->ReceiveDataPacket = (PVOID) Streams[StreamNumber].hwStreamObject.ReceiveDataPacket; pSrb->StreamObject->ReceiveControlPacket = (PVOID) Streams[StreamNumber].hwStreamObject.ReceiveControlPacket; // // The DMA flag must be set when the device will be performing DMA directly // to the data buffer addresses passed in to the ReceiceDataPacket routines. // pSrb->StreamObject->Dma = Streams[StreamNumber].hwStreamObject.Dma; // // The PIO flag must be set when the mini driver will be accessing the data // buffers passed in using logical addressing // pSrb->StreamObject->Pio = Streams[StreamNumber].hwStreamObject.Pio; // // How many extra bytes will be passed up from the driver for each frame? // pSrb->StreamObject->StreamHeaderMediaSpecific = Streams[StreamNumber].hwStreamObject.StreamHeaderMediaSpecific; pSrb->StreamObject->StreamHeaderWorkspace = Streams[StreamNumber].hwStreamObject.StreamHeaderWorkspace; // // Indicate the clock support available on this stream // pSrb->StreamObject->HwClockObject = Streams[StreamNumber].hwStreamObject.HwClockObject; // // Increment the instance count on this stream // pHwDevExt->ActualInstances[StreamNumber]++; // Retain a private copy of the HwDevExt and StreamObject in the stream extension // so we can use a timer pStrmEx->pHwDevExt = pHwDevExt; // For timer use pStrmEx->pStreamObject = pSrb->StreamObject; // For timer use // Initialize the compression settings // These may have been changed from the default values in the HwDevExt // before the stream was opened pStrmEx->CompressionSettings.CompressionKeyFrameRate = pHwDevExt->CompressionSettings.CompressionKeyFrameRate; pStrmEx->CompressionSettings.CompressionPFramesPerKeyFrame = pHwDevExt->CompressionSettings.CompressionPFramesPerKeyFrame; pStrmEx->CompressionSettings.CompressionQuality = pHwDevExt->CompressionSettings.CompressionQuality; // Init VideoControl properties pStrmEx->VideoControlMode = pHwDevExt->VideoControlMode; // Init VBI variables pStrmEx->SentVBIInfoHeader = 0; DbgLogInfo(("TestCap: AdapterOpenStream Exit\n")); }
VOID STREAMAPI AdapterReceivePacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); BOOL Busy; DEBUG_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); DbgLogTrace(("TestCap: Receiving Adapter SRB %8x, %x\n", pSrb, pSrb->Command)); // The very first time through, we need to initialize the adapter spinlock // and queue if (!pHwDevExt->AdapterQueueInitialized) { InitializeListHead (&pHwDevExt->AdapterSRBList); KeInitializeSpinLock (&pHwDevExt->AdapterSpinLock); pHwDevExt->AdapterQueueInitialized = TRUE; pHwDevExt->ProcessingAdapterSRB = FALSE; } // // If we're already processing an SRB, add it to the queue // Busy = AddToListIfBusy ( pSrb, &pHwDevExt->AdapterSpinLock, &pHwDevExt->ProcessingAdapterSRB, &pHwDevExt->AdapterSRBList); if (Busy) { return; } // // This will run until the queue is empty // while (TRUE) { // // Assume success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command) { case SRB_INITIALIZE_DEVICE: // open the device HwInitialize(pSrb); break; case SRB_UNINITIALIZE_DEVICE: // close the device. HwUnInitialize(pSrb); break; case SRB_OPEN_STREAM: // open a stream AdapterOpenStream(pSrb); break; case SRB_CLOSE_STREAM: // close a stream AdapterCloseStream(pSrb); break; case SRB_GET_STREAM_INFO: // // return a block describing all the streams // AdapterStreamInfo(pSrb); break; case SRB_GET_DATA_INTERSECTION: // // Return a format, given a range // AdapterFormatFromRange(pSrb); break; case SRB_OPEN_DEVICE_INSTANCE: case SRB_CLOSE_DEVICE_INSTANCE: // // We should never get these since this is a single instance device // TRAP; pSrb->Status = STATUS_NOT_IMPLEMENTED; break; case SRB_GET_DEVICE_PROPERTY: // // Get adapter wide properties // AdapterGetProperty (pSrb); break; case SRB_SET_DEVICE_PROPERTY: // // Set adapter wide properties // AdapterSetProperty (pSrb); break; case SRB_PAGING_OUT_DRIVER: // // The driver is being paged out // Disable Interrupts if you have them! // DbgLogInfo(("'Testcap: Receiving SRB_PAGING_OUT_DRIVER -- SRB=%x\n", pSrb)); break; case SRB_CHANGE_POWER_STATE: // // Changing the device power state, D0 ... D3 // DbgLogInfo(("'Testcap: Receiving SRB_CHANGE_POWER_STATE ------ SRB=%x\n", pSrb)); AdapterPowerState(pSrb); break; case SRB_INITIALIZATION_COMPLETE: // // Stream class has finished initialization. // Now create DShow Medium interface BLOBs. // This needs to be done at low priority since it uses the registry // DbgLogInfo(("'Testcap: Receiving SRB_INITIALIZATION_COMPLETE-- SRB=%x\n", pSrb)); break; case SRB_UNKNOWN_DEVICE_COMMAND: default: // // this is a request that we do not understand. Indicate invalid // command and complete the request // pSrb->Status = STATUS_NOT_IMPLEMENTED; } // // Indicate back to the Stream Class that we're done with this SRB // CompleteDeviceSRB (pSrb); // // See if there's anything else on the queue // Busy = RemoveFromListIfAvailable ( &pSrb, &pHwDevExt->AdapterSpinLock, &pHwDevExt->ProcessingAdapterSRB, &pHwDevExt->AdapterSRBList); if (!Busy) { break; } } // end of while there's anything in the queue }
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(pHwDevExt!=NULL); DbgLogTrace(("TestCap: Receiving Analog Stream Control SRB %p, %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; } do { // // Default to success // pSrb->Status = STATUS_SUCCESS; // // determine the type of packet. // switch (pSrb->Command) { case SRB_PROPOSE_DATA_FORMAT: DbgLogInfo(("TestCap: Receiving SRB_PROPOSE_DATA_FORMAT SRB %p, 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; DbgLogInfo(("TestCap: STATE=%d, Stream=%d\n", pStrmEx->KSState, StreamNumber)); 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 // TRAP; 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]); } while ( Busy ); }
BOOL STREAMAPI AdapterVerifyFormat( PKSDATAFORMAT pKSDataFormatToVerify, int StreamNumber ) { BOOL fOK = FALSE; ULONG j; ULONG NumberOfFormatArrayEntries; PKSDATAFORMAT *pAvailableFormats; // // Check that the stream number is valid // if (StreamNumber >= DRIVER_STREAM_COUNT) { TRAP; return FALSE; } NumberOfFormatArrayEntries = Streams[StreamNumber].hwStreamInfo.NumberOfFormatArrayEntries; // // Get the pointer to the array of available formats // pAvailableFormats = Streams[StreamNumber].hwStreamInfo.StreamFormatsArray; DbgLogInfo(("TestCap: AdapterVerifyFormat, Stream=%d\n", StreamNumber)); DbgLogInfo(("TestCap: FormatSize=%d\n", pKSDataFormatToVerify->FormatSize)); DbgLogInfo(("TestCap: MajorFormat=%x\n", pKSDataFormatToVerify->MajorFormat)); // // Walk the formats supported by the stream // for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) { // Check for a match on the three GUIDs and format size if (!AdapterCompareGUIDsAndFormatSize( pKSDataFormatToVerify, *pAvailableFormats, FALSE /* CompareFormatSize */ )) { continue; } // // Now that the three GUIDs match, switch on the Specifier // to do a further type-specific check // // ------------------------------------------------------------------- // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER // ------------------------------------------------------------------- if (IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO)) { PKS_DATAFORMAT_VIDEOINFOHEADER pDataFormatVideoInfoHeader = (PKS_DATAFORMAT_VIDEOINFOHEADER) pKSDataFormatToVerify; PKS_VIDEOINFOHEADER pVideoInfoHdrToVerify = (PKS_VIDEOINFOHEADER) &pDataFormatVideoInfoHeader->VideoInfoHeader; PKS_DATARANGE_VIDEO pKSDataRangeVideo = (PKS_DATARANGE_VIDEO) *pAvailableFormats; KS_VIDEO_STREAM_CONFIG_CAPS *pConfigCaps = &pKSDataRangeVideo->ConfigCaps; RECT rcImage; DbgLogInfo(("TestCap: AdapterVerifyFormat\n")); DbgLogInfo(("TestCap: pVideoInfoHdrToVerify=%x\n", pVideoInfoHdrToVerify)); DbgLogInfo(("TestCap: KS_VIDEOINFOHEADER size=%d\n", KS_SIZE_VIDEOHEADER (pVideoInfoHdrToVerify))); DbgLogInfo(("TestCap: Width=%d Height=%d BitCount=%d\n", pVideoInfoHdrToVerify->bmiHeader.biWidth, pVideoInfoHdrToVerify->bmiHeader.biHeight, pVideoInfoHdrToVerify->bmiHeader.biBitCount)); DbgLogInfo(("TestCap: biSizeImage=%d\n", pVideoInfoHdrToVerify->bmiHeader.biSizeImage)); /* ** HOW BIG IS THE IMAGE REQUESTED (pseudocode follows) ** ** if (IsRectEmpty (&rcTarget) { ** SetRect (&rcImage, 0, 0, ** BITMAPINFOHEADER.biWidth, BITMAPINFOHEADER.biHeight); ** } ** else { ** // Probably rendering to a DirectDraw surface, ** // where biWidth is used to expressed the "stride" ** // in units of pixels (not bytes) of the destination surface. ** // Therefore, use rcTarget to get the actual image size ** ** rcImage = rcTarget; ** } */ if ((pVideoInfoHdrToVerify->rcTarget.right - pVideoInfoHdrToVerify->rcTarget.left <= 0) || (pVideoInfoHdrToVerify->rcTarget.bottom - pVideoInfoHdrToVerify->rcTarget.top <= 0)) { rcImage.left = rcImage.top = 0; rcImage.right = pVideoInfoHdrToVerify->bmiHeader.biWidth; rcImage.bottom = pVideoInfoHdrToVerify->bmiHeader.biHeight; } else { rcImage = pVideoInfoHdrToVerify->rcTarget; } // // Perform all other verification tests here!!! // // // HOORAY, the format passed all of the tests, so we support it // fOK = TRUE; break; } // End of VIDEOINFOHEADER specifier // ------------------------------------------------------------------- // Specifier FORMAT_AnalogVideo for KS_ANALOGVIDEOINFO // ------------------------------------------------------------------- else if (IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_ANALOGVIDEO)) { // // For analog video, the DataRange and DataFormat // are identical, so just copy the whole structure // PKS_DATARANGE_ANALOGVIDEO DataRangeVideo = (PKS_DATARANGE_ANALOGVIDEO) *pAvailableFormats; // // Perform all other verification tests here!!! // fOK = TRUE; break; } // End of KS_ANALOGVIDEOINFO specifier // ------------------------------------------------------------------- // Specifier FORMAT_VBI for KS_VIDEO_VBI // ------------------------------------------------------------------- else if (IsEqualGUID (&pKSDataFormatToVerify->Specifier, &KSDATAFORMAT_SPECIFIER_VBI)) { // // Do some VBI-specific tests // PKS_DATAFORMAT_VBIINFOHEADER pKSVBIDataFormat; DbgLogInfo(("Testcap: This is a VBIINFOHEADER format pin.\n" )); pKSVBIDataFormat = (PKS_DATAFORMAT_VBIINFOHEADER)pKSDataFormatToVerify; // // Check VideoStandard, we only support NTSC_M // if (KS_AnalogVideo_NTSC_M == pKSVBIDataFormat->VBIInfoHeader.VideoStandard) { fOK = TRUE; break; } else { DbgLogError( ("Testcap: AdapterVerifyFormat : VideoStandard(%d) != NTSC_M\n", pKSVBIDataFormat->VBIInfoHeader.VideoStandard)); } } // ------------------------------------------------------------------- // Type FORMAT_NABTS for NABTS pin // ------------------------------------------------------------------- else if (IsEqualGUID (&pKSDataFormatToVerify->SubFormat, &KSDATAFORMAT_SUBTYPE_NABTS)) { fOK = TRUE; break; } // ------------------------------------------------------------------- // for CC pin // ------------------------------------------------------------------- else if (IsEqualGUID (&pKSDataFormatToVerify->SubFormat, &KSDATAFORMAT_SUBTYPE_CC)) { fOK = TRUE; break; } } // End of loop on all formats for this stream return fOK; }