//==========================================================================; // // 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 #include #include "kskludge.h" #include "codmain.h" #include "coddebug.h" #include #include "defaults.h" #include "ccdecode.h" #include "ccformatcodes.h" #ifdef PERFTEST extern enum STREAM_DEBUG_LEVEL _CDebugLevel; enum STREAM_DEBUG_LEVEL OldLevel; ULONGLONG PerfThreshold = 250; #endif // PERFTEST //==========================================================================; // Routines for processing VBI streams //==========================================================================; void CheckResultsArray( PHW_DEVICE_EXTENSION pHwDevExt, unsigned int StartLine, unsigned int EndLine ) { PDSPRESULT new; // // (Re)size the results array if needed // if( 0 == pHwDevExt->DSPResult || EndLine > pHwDevExt->DSPResultEndLine || StartLine < pHwDevExt->DSPResultStartLine ) { if (StartLine > pHwDevExt->DSPResultStartLine) StartLine = pHwDevExt->DSPResultStartLine; if (EndLine < pHwDevExt->DSPResultEndLine) EndLine = pHwDevExt->DSPResultEndLine; new = ( PDSPRESULT ) ExAllocatePool( NonPagedPool, sizeof( DSPRESULT ) * ( EndLine - StartLine + 1 ) ); if( new ) { if (pHwDevExt->DSPResult) ExFreePool( pHwDevExt->DSPResult ); pHwDevExt->DSPResult = new; pHwDevExt->DSPResultStartLine = StartLine; pHwDevExt->DSPResultEndLine = EndLine; CDebugPrint( DebugLevelInfo, (CODECNAME ": Resized results array\n" )); } else { CDebugPrint( DebugLevelInfo, (CODECNAME ": Resize results array failed\n" )); CASSERT( new ); pHwDevExt->Statistics.Common.InternalErrors++; } } } /* ** CheckNewVBIInfo ** ** Checks for a new VBIInfoHeader ** ** Here's a little trickery to save having separate builds for the infinite pin ** tee and MSTee filters. IPT, being Ring3, doesn't pass VBIInfoHeaders, but it ** does pass the flags to show they've changed. We only make a copy if the ** data is good, otherwise we stick with the default header we started with. ** ** Arguments: ** ** PHW_DEVICE_EXTENSION pHwDevExt ** PSTREAMEX pInStrmEx ** PKS_VBI_FRAME_INFO pInVBIFrameInfo ** PKSSTREAM_HEADER pInStreamHeader ** ** Returns: nothing ** ** Side Effects: none */ int CheckNewVBIInfo( PHW_DEVICE_EXTENSION pHwDevExt, PSTREAMEX pInStrmEx, PKS_VBI_FRAME_INFO pInVBIFrameInfo ) { PKS_VBIINFOHEADER pVBIInfoHeader = &pInStrmEx->CurrentVBIInfoHeader; PVBICODECFILTERING_STATISTICS_CC Stats = &pHwDevExt->Statistics; if( 0 == pInVBIFrameInfo->VBIInfoHeader.StartLine || 0 == pInVBIFrameInfo->VBIInfoHeader.EndLine || 0 == pInVBIFrameInfo->VBIInfoHeader.ActualLineStartTime ) { return 0; } CDebugPrint( DebugLevelInfo, (CODECNAME ": VBIInfoHeader Change\n" )); Stats->Common.VBIHeaderChanges++; // // Resize the results array if needed // CheckResultsArray(pHwDevExt, pInVBIFrameInfo->VBIInfoHeader.StartLine, pInVBIFrameInfo->VBIInfoHeader.EndLine); // // Copy new VBI info header over old // RtlCopyMemory( pVBIInfoHeader, &pInVBIFrameInfo->VBIInfoHeader, sizeof( KS_VBIINFOHEADER )); //pVBIInfoHeader->ActualLineStartTime = 780; RtlZeroMemory( &pInStrmEx->ScanlinesDiscovered, sizeof( pInStrmEx->ScanlinesDiscovered )); RtlZeroMemory( &pInStrmEx->SubstreamsDiscovered, sizeof( pInStrmEx->SubstreamsDiscovered )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->StartLine %lu\n", pVBIInfoHeader->StartLine )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->EndLine %lu\n", pVBIInfoHeader->EndLine )); //CDebugPrint( DebugLevelVerbose, // ( CODECNAME ": VBIInfoHeader->SamplingFrequency %lu\n", // pVBIInfoHeader->SamplingFrequency )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->MinLineStartTime %lu\n", pVBIInfoHeader->MinLineStartTime )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->MaxLineStartTime %lu\n", pVBIInfoHeader->MaxLineStartTime )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->ActualLineStartTime %lu\n", pVBIInfoHeader->ActualLineStartTime )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->ActualLineEndTime %lu\n", pVBIInfoHeader->ActualLineEndTime )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->VideoStandard %lu\n", pVBIInfoHeader->VideoStandard )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->SamplesPerLine %lu\n", pVBIInfoHeader->SamplesPerLine )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->StrideInBytes %lu\n", pVBIInfoHeader->StrideInBytes )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": VBIInfoHeader->BufferSize %lu\n", pVBIInfoHeader->BufferSize )); return 1; } /* ** ProcessChannelChange ** ** Handles a VBI_FLAG_TVTUNER_CHANGE event ** ** Arguments: ** ** PHW_DEVICE_EXTENSION pHwDevExt ** PSTREAMEX pInStrmEx ** PKS_VBI_FRAME_INFO pInVBIFrameInfo ** PKSSTREAM_HEADER pInStreamHeader ** ** Returns: nothing ** ** Side Effects: none */ int ProcessChannelChange( PHW_DEVICE_EXTENSION pHwDevExt, PSTREAMEX pInStrmEx, PKS_VBI_FRAME_INFO pInVBIFrameInfo, PKSSTREAM_HEADER pInStreamHeader ) { PKS_VBIINFOHEADER pVBIInfoHeader = &pInStrmEx->CurrentVBIInfoHeader; PVBICODECFILTERING_STATISTICS_CC Stats = &pHwDevExt->Statistics; PKS_TVTUNER_CHANGE_INFO pChangeInfo = &pInVBIFrameInfo->TvTunerChangeInfo; ULONG CurrentStrmEx; ULONG i; if( pChangeInfo->dwFlags & KS_TVTUNER_CHANGE_BEGIN_TUNE ) { CDebugPrint( DebugLevelInfo, (CODECNAME ": TVTuner Change START\n" )); pHwDevExt->fTunerChange = TRUE; } else if( pChangeInfo->dwFlags & KS_TVTUNER_CHANGE_END_TUNE ) { Stats->Common.TvTunerChanges++; pHwDevExt->fTunerChange = FALSE; CDebugPrint( DebugLevelInfo, (CODECNAME ": TVTuner Change END\n" )); RtlZeroMemory( &pInStrmEx->ScanlinesDiscovered, sizeof( pInStrmEx->ScanlinesDiscovered )); RtlZeroMemory( &pInStrmEx->SubstreamsDiscovered, sizeof( pInStrmEx->SubstreamsDiscovered )); CurrentStrmEx = 0; // // Flag a discontuity. This is passed to outgoing SRBs and will force // the downstream Line 21 decoder to clear its current CC data off the // screen. // for( i = 0; i < pHwDevExt->ActualInstances[STREAM_CC]; i++ ) { PSTREAMEX pOutStrmEx; PHW_STREAM_REQUEST_BLOCK pOutSrb; PVBICODECFILTERING_STATISTICS_CC_PIN PinStats; do { CASSERT( CurrentStrmEx < MAX_PIN_INSTANCES ); pOutStrmEx = pHwDevExt->pStrmEx[STREAM_CC][CurrentStrmEx++]; }while( !pOutStrmEx ); PinStats = &pOutStrmEx->PinStats; // // Get the next output stream SRB if it's available. // if( QueueRemove( &pOutSrb, &pOutStrmEx->StreamDataSpinLock, &pOutStrmEx->StreamDataQueue ) ) { PKSSTREAM_HEADER pOutStreamHeader = pOutSrb->CommandData.DataBufferArray; PKS_VBI_FRAME_INFO pOutVBIFrameInfo = (PKS_VBI_FRAME_INFO)(pOutStreamHeader+1); PUCHAR pOutData = (PUCHAR)pOutStreamHeader->Data; if( pOutStreamHeader->FrameExtent < CCSamples ) { CDebugPrint( DebugLevelError, ( CODECNAME ": Outgoing Data SRB buffer is too small %u\n", pOutStreamHeader->FrameExtent )); PinStats->Common.InternalErrors++; Stats->Common.OutputFailures++; pOutStreamHeader->DataUsed = 0; } else { PinStats->Common.SRBsProcessed++; Stats->Common.OutputSRBsProcessed++; CDebugPrint( DebugLevelInfo, (CODECNAME ": Propagating data discontinuity, instance %u\n", i )); pOutData[0] = 0; pOutData[1] = 0; pOutStreamHeader->DataUsed = 2; pOutStreamHeader->OptionsFlags = pInStreamHeader->OptionsFlags | KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY; CDebugPrint( DebugLevelInfo, (CODECNAME ": OptionsFlags %x\n", pOutStreamHeader->OptionsFlags )); CDebugPrint( DebugLevelInfo, ("" "Time %x Num %x Denom %x\n", pInStreamHeader->PresentationTime.Time, pInStreamHeader->PresentationTime.Numerator, pInStreamHeader->PresentationTime.Denominator )); RtlCopyMemory( &pOutStreamHeader->PresentationTime, &pInStreamHeader->PresentationTime, sizeof( pOutStreamHeader->PresentationTime )); pOutStreamHeader->Duration = pInStreamHeader->Duration; } CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Releasing Output SRB %x\n", pOutSrb )); // Complete the output SRB StreamClassStreamNotification( StreamRequestComplete, pOutSrb->StreamObject, pOutSrb ); pOutStrmEx->fDiscontinuity = FALSE; PinStats->Common.BytesOutput += pOutStreamHeader->DataUsed; Stats->Common.BytesOutput += pOutStreamHeader->DataUsed; } else { pOutStrmEx->fDiscontinuity = TRUE; Stats->Common.OutputSRBsMissing++; } } return 1; } return 0; } void DebugPrintSubStreamMode( DWORD dwMode ) { #ifdef DEBUG if ( dwMode & KS_CC_SUBSTREAM_SERVICE_XDS ) { CDebugPrint( DebugLevelWarning, ( "\n[XDS]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_CC1 ) { CDebugPrint( DebugLevelWarning, ( "\n[CC1]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_CC2 ) { CDebugPrint( DebugLevelWarning, ( "\n[CC2]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_CC3 ) { CDebugPrint( DebugLevelWarning, ( "\n[CC3]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_CC4 ) { CDebugPrint( DebugLevelWarning, ( "\n[CC4]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_T1 ) { CDebugPrint( DebugLevelWarning, ( "\n[T1]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_T2 ) { CDebugPrint( DebugLevelWarning, ( "\n[T2]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_T3 ) { CDebugPrint( DebugLevelWarning, ( "\n[T3]" )); } if ( dwMode & KS_CC_SUBSTREAM_SERVICE_T4 ) { CDebugPrint( DebugLevelWarning, ( "\n[T4]" )); } #endif } // Get the substream mode for the current data sample - optionally change the substream mode // The following "protocol" is loosely defined by FCC 91-119, FCC 92-157 and EIA 608 // Be advised that EIA 608 describes clearly which (few) byte pairs change the substream mode DWORD GetSubStreamMode( DWORD dwFrameFlags, LPDWORD pdwCurrentSubStreamMode, PDSPRESULT pDSPResult ) { DWORD dwSubStreamMode = *pdwCurrentSubStreamMode; DWORD dwDataChannel = 0; dwFrameFlags &= (KS_VBI_FLAG_FIELD1 | KS_VBI_FLAG_FIELD2); if ( pDSPResult->Confidence >= 75 ) { // Inspect the first byte(minus parity) to see what substream this might be switch ( pDSPResult->Decoded[0] & 0x7F ) { case CC_XDS_START_CURRENT: case CC_XDS_CONTINUE_CURRENT: case CC_XDS_START_FUTURE: case CC_XDS_CONTINUE_FUTURE: case CC_XDS_START_CHANNEL: case CC_XDS_CONTINUE_CHANNEL: case CC_XDS_START_MISC: case CC_XDS_CONTINUE_MISC: case CC_XDS_START_PUBLIC_SERVICE: case CC_XDS_CONTINUE_PUBLIC_SERVICE: case CC_XDS_START_RESERVED: case CC_XDS_CONTINUE_RESERVED: case CC_XDS_START_UNDEFINED: case CC_XDS_CONTINUE_UNDEFINED: case CC_XDS_END: // Set the substream mode as XDS from here on out dwSubStreamMode = ( dwFrameFlags | KS_CC_SUBSTREAM_SERVICE_XDS); DebugPrintSubStreamMode( dwSubStreamMode ); *pdwCurrentSubStreamMode = dwSubStreamMode; break; case CC_MCC_FIELD1_DC1: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_CC1; break; case CC_MCC_FIELD1_DC2: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_CC2; break; case CC_MCC_FIELD2_DC1: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_CC3; break; case CC_MCC_FIELD2_DC2: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_CC4; break; } // If we found a data channel escape, inspect the second byte(minus parity) to see what substream may be. if ( dwDataChannel ) { switch ( pDSPResult->Decoded[1] & 0x7F ) { case CC_MCC_RCL: case CC_MCC_RU2: case CC_MCC_RU3: case CC_MCC_RU4: case CC_MCC_RDC: case CC_MCC_EOC: // The mode is good for this data pair and thereafter dwSubStreamMode = (dwFrameFlags | dwDataChannel); DebugPrintSubStreamMode( dwSubStreamMode ); *pdwCurrentSubStreamMode = dwSubStreamMode; break; case CC_MCC_TR: case CC_MCC_RTD: // The mode is TEXT rather CC, map to the text channel ids switch ( dwDataChannel ) { case KS_CC_SUBSTREAM_SERVICE_CC1: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_T1; break; case KS_CC_SUBSTREAM_SERVICE_CC2: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_T2; break; case KS_CC_SUBSTREAM_SERVICE_CC3: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_T3; break; case KS_CC_SUBSTREAM_SERVICE_CC4: dwDataChannel = KS_CC_SUBSTREAM_SERVICE_T4; break; } // The mode is good for this data byte pair and thereafter dwSubStreamMode = (dwFrameFlags | dwDataChannel); DebugPrintSubStreamMode( dwSubStreamMode ); *pdwCurrentSubStreamMode = dwSubStreamMode; break; case CC_MCC_EDM: case CC_MCC_ENM: // The mode is only good for this data byte pair. Reverts back thereafter dwSubStreamMode = (dwFrameFlags | dwDataChannel); DebugPrintSubStreamMode( dwSubStreamMode ); DebugPrintSubStreamMode( *pdwCurrentSubStreamMode ); break; } } } return dwSubStreamMode; } /* ** OutputCC ** ** Outputs just-decoded/received CC to any interested pins ** ** Arguments: ** ** PHW_DEVICE_EXTENSION pHwDevExt ** PSTREAMEX pInStrmEx ** PKS_VBI_FRAME_INFO pInVBIFrameInfo ** PKSSTREAM_HEADER pInStreamHeader ** ** Returns: nothing ** ** Side Effects: none */ void OutputCC( PHW_DEVICE_EXTENSION pHwDevExt, PSTREAMEX pInStrmEx, DWORD dwOriginalFrameFlags, PKSSTREAM_HEADER pInStreamHeader ) { ULONG i, ScanlineCount, CurrentStrmEx = 0; PKS_VBIINFOHEADER pVBIInfoHeader = &pInStrmEx->CurrentVBIInfoHeader; PVBICODECFILTERING_STATISTICS_CC Stats = 0; #ifdef PERFTEST ULONGLONG PerfStartTime = 0, PerfPreDownstreamCompletion = 0, PerfPostDownstreamCompletion = 0; LARGE_INTEGER PerfFrequency; PerfStartTime = KeQueryPerformanceCounter( &PerfFrequency ).QuadPart; OldLevel = _CDebugLevel; _CDebugLevel = DebugLevelFatal; #endif // PERFTEST CASSERT(pHwDevExt); CASSERT(pInStrmEx); Stats = &pHwDevExt->Statistics; CDebugPrint( DebugLevelInfo, ( "*" )); CDebugPrint( DebugLevelTrace, ( CODECNAME ": --->OutputCC\n" )); // If this substream is requested by anybody (field or cc data channel) if(( pInStrmEx->SubstreamsRequested.SubstreamMask )) { // Loop through all pending outbound requests and fill each irp with the requested data then complete the IO for( ScanlineCount = pVBIInfoHeader->StartLine; ScanlineCount <= pVBIInfoHeader->EndLine; ScanlineCount++ ) { DWORD dwSubStreams = 0; DWORD dwFieldIndex = dwOriginalFrameFlags & KS_VBI_FLAG_FIELD1 ? 0 : 1; DWORD dwScanLineIndex = ScanlineCount - pHwDevExt->DSPResultStartLine; if( !TESTBIT( pInStrmEx->ScanlinesRequested.DwordBitArray, ScanlineCount )) continue; dwSubStreams = GetSubStreamMode( dwOriginalFrameFlags, &pHwDevExt->SubStreamState[dwScanLineIndex][dwFieldIndex], &pHwDevExt->DSPResult[dwScanLineIndex] ); CDebugPrint( DebugLevelWarning, ( "%c%c", pHwDevExt->DSPResult[dwScanLineIndex].Decoded[0] & 0x7f, pHwDevExt->DSPResult[dwScanLineIndex].Decoded[1] & 0x7f )); CDebugPrint( DebugLevelInfo, (CODECNAME ": F%u %luus L%u %u%% %02x %02x\n", dwSubStreams & pInStrmEx->SubstreamsRequested.SubstreamMask, pVBIInfoHeader->ActualLineStartTime, ScanlineCount, pHwDevExt->DSPResult[dwScanLineIndex].Confidence, pHwDevExt->DSPResult[dwScanLineIndex].Decoded[0] & 0xff, pHwDevExt->DSPResult[dwScanLineIndex].Decoded[1] & 0xff )); CurrentStrmEx = 0; for( i = 0; i < pHwDevExt->ActualInstances[STREAM_CC]; i++ ) { PSTREAMEX pOutStrmEx; PHW_STREAM_REQUEST_BLOCK pOutSrb; PVBICODECFILTERING_STATISTICS_CC_PIN PinStats; do { CASSERT( CurrentStrmEx < MAX_PIN_INSTANCES ); if( CurrentStrmEx == MAX_PIN_INSTANCES ) Stats->Common.InternalErrors++; pOutStrmEx = pHwDevExt->pStrmEx[STREAM_CC][CurrentStrmEx++]; }while( !pOutStrmEx ); if( !TESTBIT( pOutStrmEx->ScanlinesRequested.DwordBitArray, ScanlineCount ) || !( pOutStrmEx->SubstreamsRequested.SubstreamMask & dwSubStreams )) continue; PinStats = &pOutStrmEx->PinStats; // // Update the average confidence for this pin // PinStats->Common.LineConfidenceAvg = ( PinStats->Common.LineConfidenceAvg + pHwDevExt->DSPResult[dwScanLineIndex].Confidence ) / 2; if( pHwDevExt->DSPResult[dwScanLineIndex].Confidence >= 75 ) { SETBIT( pInStrmEx->ScanlinesDiscovered.DwordBitArray, ScanlineCount ); SETBIT( pOutStrmEx->ScanlinesDiscovered.DwordBitArray, ScanlineCount ); SETBIT( pHwDevExt->ScanlinesDiscovered.DwordBitArray, ScanlineCount ); pInStrmEx->SubstreamsDiscovered.SubstreamMask |= dwSubStreams; pOutStrmEx->SubstreamsDiscovered.SubstreamMask |= dwSubStreams; pHwDevExt->SubstreamsDiscovered.SubstreamMask |= dwSubStreams; } else { Stats->Common.DSPFailures++; PinStats->Common.SRBsIgnored++; if(( dwSubStreams & KS_CC_SUBSTREAM_ODD ) && TESTBIT( pInStrmEx->LastOddScanlinesDiscovered.DwordBitArray, ScanlineCount )) pOutStrmEx->fDiscontinuity = TRUE; if(( dwSubStreams & KS_CC_SUBSTREAM_EVEN ) && TESTBIT( pInStrmEx->LastEvenScanlinesDiscovered.DwordBitArray, ScanlineCount )) pOutStrmEx->fDiscontinuity = TRUE; if( !pOutStrmEx->fDiscontinuity ) continue; } // Only process the output streams which have an SRB ready if( QueueRemove( &pOutSrb, &pOutStrmEx->StreamDataSpinLock, &pOutStrmEx->StreamDataQueue )) { PKSSTREAM_HEADER pOutStreamHeader = pOutSrb->CommandData.DataBufferArray; PKS_VBI_FRAME_INFO pOutVBIFrameInfo = (PKS_VBI_FRAME_INFO)(pOutStreamHeader+1); PUCHAR pOutData = (PUCHAR)pOutStreamHeader->Data; PinStats->Common.SRBsProcessed++; Stats->Common.OutputSRBsProcessed++; if( pOutStreamHeader->FrameExtent < pOutStrmEx->MatchedFormat.SampleSize ) { CDebugPrint( DebugLevelError, ( CODECNAME ": Outgoing Data SRB buffer is too small %u\n", pOutStreamHeader->FrameExtent )); PinStats->Common.InternalErrors++; Stats->Common.OutputFailures++; pOutStreamHeader->DataUsed = 0; } // Check on inbound & outbound data formats to decide // whether to copy or decode the inbound data // Figure out how much of the decoded data was requested pOutStreamHeader->Size = pInStreamHeader->Size; pOutStreamHeader->OptionsFlags = pInStreamHeader->OptionsFlags; pOutStreamHeader->Duration = pInStreamHeader->Duration; RtlCopyMemory( &pOutStreamHeader->PresentationTime, &pInStreamHeader->PresentationTime, sizeof( pOutStreamHeader->PresentationTime )); // pOutData is the output location. ASSERT( pOutStreamHeader->FrameExtent >= CCSamples ); pOutStreamHeader->DataUsed = 2; // // If we have a discontinity to go out then send it // instead of the data // if( pOutStrmEx->fDiscontinuity ) { PinStats->Common.Discontinuities++; pOutData[0] = 0xff; pOutData[1] = 0xff; pOutStreamHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY; pOutStrmEx->fDiscontinuity = FALSE; } else { pOutData[0] = pHwDevExt->DSPResult[ScanlineCount - pHwDevExt->DSPResultStartLine].Decoded[0]; pOutData[1] = pHwDevExt->DSPResult[ScanlineCount - pHwDevExt->DSPResultStartLine].Decoded[1]; } CDebugPrint( DebugLevelInfo, (CODECNAME ": OptionsFlags %x\n", pOutStreamHeader->OptionsFlags )); CDebugPrint( DebugLevelInfo, ("" "Time %x Num %x Denom %x\n", pInStreamHeader->PresentationTime.Time, pInStreamHeader->PresentationTime.Numerator, pInStreamHeader->PresentationTime.Denominator )); //CDebugPrint( DebugLevelWarning, ( "" "%d%", i )); Stats->Common.BytesOutput += pOutStreamHeader->DataUsed; PinStats->Common.BytesOutput += pOutStreamHeader->DataUsed; CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Releasing Output SRB %x\n", pOutSrb )); // Complete the output SRB #ifdef PERFTEST if( i == 0 ) PerfPreDownstreamCompletion = KeQueryPerformanceCounter( NULL ).QuadPart; #endif // PERFTEST StreamClassStreamNotification( StreamRequestComplete, pOutSrb->StreamObject, pOutSrb ); #ifdef PERFTEST if( i == 0 ) PerfPostDownstreamCompletion = KeQueryPerformanceCounter( NULL ).QuadPart; #endif // PERFTEST } else { PinStats->Common.SRBsMissing++; Stats->Common.OutputSRBsMissing++; } } } } // // Remember the streams we discovered so that if they aren't discovered next // time we know we have to send a single discontinuity. // if(( dwOriginalFrameFlags & KS_CC_SUBSTREAM_EVEN ) == KS_CC_SUBSTREAM_EVEN ) RtlCopyMemory( &pInStrmEx->LastEvenScanlinesDiscovered, &pInStrmEx->ScanlinesDiscovered, sizeof( pInStrmEx->LastEvenScanlinesDiscovered )); if(( dwOriginalFrameFlags & KS_CC_SUBSTREAM_ODD ) == KS_CC_SUBSTREAM_ODD ) RtlCopyMemory( &pInStrmEx->LastOddScanlinesDiscovered, &pInStrmEx->ScanlinesDiscovered, sizeof( pInStrmEx->LastOddScanlinesDiscovered )); #ifdef PERFTEST PerfFrequency.QuadPart /= 1000000L; // Convert to ticks/us if( PerfPreDownstreamCompletion ) { PerfPreDownstreamCompletion -= PerfStartTime; PerfPreDownstreamCompletion /= PerfFrequency.QuadPart; } if( PerfPostDownstreamCompletion ) { PerfPostDownstreamCompletion -= PerfStartTime; PerfPostDownstreamCompletion /= PerfFrequency.QuadPart; } // // Complain if anything takes more than threshold // if( PerfPreDownstreamCompletion > PerfThreshold ) CDebugPrint( DebugLevelFatal, ( CODECNAME ": PerfPreDownstreamCompletion %luus\n", PerfPreDownstreamCompletion )); if( PerfPostDownstreamCompletion > PerfThreshold ) CDebugPrint( DebugLevelFatal, ( CODECNAME ": PerfPostDownstreamCompletion %luus\n", PerfPostDownstreamCompletion )); _CDebugLevel = OldLevel; #endif // PERFTEST CDebugPrint( DebugLevelTrace, ( CODECNAME ": <---OutputCC\n" )); } /* ** VBIDecode ** ** Decodes an incoming SRB. SRB is already removed from queue. ** ** Arguments: ** ** PHW_DEVICE_EXTENSION pHwDevExt ** PSTREAMEX pInStrmEx ** IN PHW_STREAM_REQUEST_BLOCK pInSrb ** ** Returns: ** ** Side Effects: none */ #ifdef DEBUG short CCskipDecode = 0; #endif /*DEBUG*/ void VBIDecode( PHW_DEVICE_EXTENSION pHwDevExt, PSTREAMEX pInStrmEx, PHW_STREAM_REQUEST_BLOCK pInSrb, BOOL OkToHold ) { PKSSTREAM_HEADER pInStreamHeader = pInSrb->CommandData.DataBufferArray; KSSTREAM_HEADER InStreamHeaderCopy; PKS_VBI_FRAME_INFO pInVBIFrameInfo = (PKS_VBI_FRAME_INFO)(pInStreamHeader+1); DWORD dwFrameFlags; PUCHAR pInData = (PUCHAR)pInStreamHeader->Data; ULONG i, j, ScanlineCount, DSPStatus, CurrentStrmEx = 0; CCLineStats DSPStatistics; PKS_VBIINFOHEADER pVBIInfoHeader = &pInStrmEx->CurrentVBIInfoHeader; PVBICODECFILTERING_STATISTICS_CC Stats = 0; CASSERT(KeGetCurrentIrql() <= APC_LEVEL); #ifdef PERFTEST ULONGLONG PerfStartTime = 0, PerfPreUpstreamCompletion = 0, PerfPostUpstreamCompletion = 0; LARGE_INTEGER PerfFrequency; PerfStartTime = KeQueryPerformanceCounter( &PerfFrequency ).QuadPart; OldLevel = _CDebugLevel; _CDebugLevel = DebugLevelFatal; #endif // PERFTEST CASSERT(pHwDevExt); CASSERT(pInStrmEx); Stats = &pHwDevExt->Statistics; CDebugPrint( DebugLevelTrace, ( CODECNAME ": --->VBIDecode\n" )); #ifdef CCINPUTPIN if (!OkToHold) goto GoodToGo; // We've already processed discontinuties & stuff below #endif // CCINPUTPIN CDebugPrint( DebugLevelInfo, ( "*" )); Stats->Common.InputSRBsProcessed++; // // If DataUsed == 0 then don't bother // if( pInStreamHeader->DataUsed < 1 #ifdef DEBUG || CCskipDecode #endif /*DEBUG*/ ) { Stats->Common.SRBsIgnored++; #ifdef DEBUG if (!CCskipDecode) #endif /*DEBUG*/ CDebugPrint( DebugLevelError, ( CODECNAME ": DataUsed == 0, abandoning\n" )); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } // // Test for dropped fields // if( pInStrmEx->LastPictureNumber ) { LONGLONG Dropped = pInVBIFrameInfo->PictureNumber - pInStrmEx->LastPictureNumber - 1; if( Dropped > 0 ) { if( Dropped < 60*60*60 ) // One hour worth of video fields Stats->Common.InputSRBsMissing += (DWORD)Dropped; else Stats->Common.InputSRBsMissing++; // Some improbable number of fields got dropped, indicate a single lost field. CDebugPrint( DebugLevelWarning, ( "$" )); } } pInStrmEx->LastPictureNumber = pInVBIFrameInfo->PictureNumber; CDebugPrint( DebugLevelVerbose, ( CODECNAME ": pInVBIFrameInfo->ExtendedHeaderSize %d\n", pInVBIFrameInfo->ExtendedHeaderSize )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": pInVBIFrameInfo->dwFrameFlags %x\n", pInVBIFrameInfo->dwFrameFlags )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": pInVBIFrameInfo->PictureNumber %lu\n", pInVBIFrameInfo->PictureNumber )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": pInVBIFrameInfo->DropCount %lu\n", pInVBIFrameInfo->DropCount )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": pInVBIFrameInfo->dwSamplingFrequency %lu\n", pInVBIFrameInfo->dwSamplingFrequency )); CDebugPrint( DebugLevelVerbose, ( CODECNAME ": pInStreamHeader->FrameExtent %d\n", pInStreamHeader->FrameExtent )); // // Update stats // if( ( pInStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY ) || ( pInStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY ) ) Stats->Common.InputDiscontinuities++; // // Check for a new VBIINFOHEADER // if( pInVBIFrameInfo->dwFrameFlags & KS_VBI_FLAG_VBIINFOHEADER_CHANGE ) { CheckNewVBIInfo( pHwDevExt, pInStrmEx, pInVBIFrameInfo ); } // // Check for a channel change // if( pInVBIFrameInfo->dwFrameFlags & KS_VBI_FLAG_TVTUNER_CHANGE ) { if( ProcessChannelChange( pHwDevExt, pInStrmEx, pInVBIFrameInfo, pInStreamHeader )) { StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } } // // pHwDevExt->fTunerChange is set while the TV tuner is changing channels. // SRBs are junk until the channel change completes so complete. // if( pHwDevExt->fTunerChange) { CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Completing, channel change in progress\n" )); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } // Clear the current scanline & substream request masks RtlZeroMemory( &pInStrmEx->ScanlinesRequested, sizeof(pInStrmEx->ScanlinesRequested) ); RtlZeroMemory( &pInStrmEx->SubstreamsRequested, sizeof(pInStrmEx->SubstreamsRequested) ); // // Calculate the current request from union of the output pins w/pending SRBs that are // interested in this substream. // CurrentStrmEx = 0; for( i = 0; i < pHwDevExt->ActualInstances[STREAM_CC]; i++ ) { PSTREAMEX pOutStrmEx; do { CASSERT( CurrentStrmEx < MAX_PIN_INSTANCES ); pOutStrmEx = pHwDevExt->pStrmEx[STREAM_CC][CurrentStrmEx++]; }while( !pOutStrmEx ); if ( pInVBIFrameInfo->dwFrameFlags & KS_VBI_FLAG_TVTUNER_CHANGE ) pOutStrmEx->fDiscontinuity = TRUE; // // For actual processing, just include the scanlines of the clients who are // interested in this particular substream. // if ( ( ( pInVBIFrameInfo->dwFrameFlags & KS_CC_SUBSTREAM_ODD ) && ( pOutStrmEx->SubstreamsRequested.SubstreamMask & (KS_CC_SUBSTREAM_ODD|KS_CC_SUBSTREAM_FIELD1_MASK) ) ) || ( ( pInVBIFrameInfo->dwFrameFlags & KS_CC_SUBSTREAM_EVEN ) && ( pOutStrmEx->SubstreamsRequested.SubstreamMask & (KS_CC_SUBSTREAM_EVEN|KS_CC_SUBSTREAM_FIELD2_MASK) ) ) ) { for( j = 0; j < SIZEOF_ARRAY( pInStrmEx->ScanlinesRequested.DwordBitArray ); j++ ) pInStrmEx->ScanlinesRequested.DwordBitArray[j] |= pOutStrmEx->ScanlinesRequested.DwordBitArray[j]; // Create the union of all the requested substreams pInStrmEx->SubstreamsRequested.SubstreamMask |= pOutStrmEx->SubstreamsRequested.SubstreamMask; } } // Decode the union of all the pending decode requests into a local decode buffer. #ifdef CCINPUTPIN GoodToGo: // Whoever gets there first (VBI pin vs. HW pin) supplies CC data ExAcquireFastMutex(&pHwDevExt->LastPictureMutex); if (pInStrmEx->LastPictureNumber <= pHwDevExt->LastPictureNumber) { // HW pin beat us to it ExReleaseFastMutex(&pHwDevExt->LastPictureMutex); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } // Is the HW stream open? if (OkToHold && pHwDevExt->ActualInstances[STREAM_CCINPUT] > 0) { KIRQL Irql; // We're going to give the HW pin a chance to catch up ExReleaseFastMutex(&pHwDevExt->LastPictureMutex); KeAcquireSpinLock(&pInStrmEx->VBIOnHoldSpinLock, &Irql); CASSERT(NULL == pInStrmEx->pVBISrbOnHold); pInStrmEx->pVBISrbOnHold = pInSrb; KeReleaseSpinLock(&pInStrmEx->VBIOnHoldSpinLock, Irql); return; } // HW input pin not open or too late; we'll process this SRB pHwDevExt->LastPictureNumber = pInStrmEx->LastPictureNumber; ExReleaseFastMutex(&pHwDevExt->LastPictureMutex); #endif // CCINPUTPIN CDebugPrint( DebugLevelTrace, ( CODECNAME ": Requested SubstreamMask %x\n", pInStrmEx->SubstreamsRequested.SubstreamMask )); CDebugPrint( DebugLevelTrace, ( CODECNAME ": Requested Scanlines %08x%08x\n", pInStrmEx->ScanlinesRequested.DwordBitArray[1], pInStrmEx->ScanlinesRequested.DwordBitArray[0] )); RtlZeroMemory( pHwDevExt->DSPResult, sizeof( DSPRESULT ) * ( pHwDevExt->DSPResultEndLine - pHwDevExt->DSPResultStartLine + 1 )); // If this substream is requested by anybody, AND there is no discontinuity set if ( ( ( ( pInVBIFrameInfo->dwFrameFlags & KS_CC_SUBSTREAM_ODD ) && ( pInStrmEx->SubstreamsRequested.SubstreamMask & (KS_CC_SUBSTREAM_ODD|KS_CC_SUBSTREAM_FIELD1_MASK) ) || ( ( pInVBIFrameInfo->dwFrameFlags & KS_CC_SUBSTREAM_EVEN ) && ( pInStrmEx->SubstreamsRequested.SubstreamMask & (KS_CC_SUBSTREAM_EVEN|KS_CC_SUBSTREAM_FIELD2_MASK) ) ) ) && !pInStrmEx->fDiscontinuity )) { // Flag this as discovered // pInStrmEx->SubstreamsDiscovered.SubstreamMask |= ( pInVBIFrameInfo->dwFrameFlags & // pInStrmEx->SubstreamsRequested.SubstreamMask ); // pHwDevExt->SubstreamsDiscovered.SubstreamMask |= pInStrmEx->SubstreamsDiscovered.SubstreamMask; // loop for each requested scanline CDebugPrint( DebugLevelVerbose, ( "" "\n" )); for( ScanlineCount = pVBIInfoHeader->StartLine; ScanlineCount <= pVBIInfoHeader->EndLine; ScanlineCount++ ) { if( !TESTBIT( pInStrmEx->ScanlinesRequested.DwordBitArray, ScanlineCount )) continue; CDebugPrint( DebugLevelTrace, ( CODECNAME ": Scanning %u\n", ScanlineCount )); CASSERT( ( ScanlineCount - pVBIInfoHeader->StartLine) * pVBIInfoHeader->StrideInBytes < pVBIInfoHeader->BufferSize ); DSPStatistics.nSize = sizeof( DSPStatistics ); DSPStatus = CCDecodeLine( pHwDevExt->DSPResult[ScanlineCount - pHwDevExt->DSPResultStartLine].Decoded, &DSPStatistics, &pInData[( ScanlineCount - pVBIInfoHeader->StartLine ) * pVBIInfoHeader->StrideInBytes], &pInStrmEx->State, pVBIInfoHeader ); CASSERT( DSPStatus == CC_OK ); if( DSPStatus == CC_OK ) { pHwDevExt->DSPResult[ScanlineCount - pHwDevExt->DSPResultStartLine].Confidence = DSPStatistics.nConfidence; Stats->Common.LineConfidenceAvg = ( Stats->Common.LineConfidenceAvg + DSPStatistics.nConfidence ) / 2; } else Stats->Common.InternalErrors++; } } else Stats->Common.SRBsIgnored++; // // Copy the input stream header info for later reference // InStreamHeaderCopy = *pInStreamHeader; dwFrameFlags = pInVBIFrameInfo->dwFrameFlags; #ifdef PERFTEST PerfPreUpstreamCompletion = KeQueryPerformanceCounter( NULL ).QuadPart; #endif // PERFTEST // // Complete the upstream SRB. // StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); #ifdef PERFTEST PerfPostUpstreamCompletion = KeQueryPerformanceCounter( NULL ).QuadPart; #endif // PERFTEST // // Lose all references to the just completed SRB // pInSrb = 0; pInStreamHeader = 0; pInVBIFrameInfo = 0; pInData = 0; #ifdef PERFTEST PerfFrequency.QuadPart /= 1000000L; // Convert to ticks/us PerfPreUpstreamCompletion -= PerfStartTime; PerfPreUpstreamCompletion /= PerfFrequency.QuadPart; PerfPostUpstreamCompletion -= PerfStartTime; PerfPostUpstreamCompletion /= PerfFrequency.QuadPart; // // Complain if anything takes more than threshold // if( PerfPreUpstreamCompletion > PerfThreshold ) CDebugPrint( DebugLevelFatal, ( CODECNAME ": PerfPreUpstreamCompletion %luus\n", PerfPreUpstreamCompletion )); if( PerfPostUpstreamCompletion > PerfThreshold ) CDebugPrint( DebugLevelFatal, ( CODECNAME ": PerfPostUpstreamCompletion %luus\n", PerfPostUpstreamCompletion )); _CDebugLevel = OldLevel; #endif // PERFTEST // // Now output to anyone interested // OutputCC(pHwDevExt, pInStrmEx, dwFrameFlags, &InStreamHeaderCopy); CDebugPrint( DebugLevelTrace, ( CODECNAME ": <---VBIDecode\n" )); } /* ** VBIhwDecode ** ** Handles an incoming CCINPUT SRB. SRB is already removed from queue. ** ** Arguments: ** ** PHW_DEVICE_EXTENSION pHwDevExt ** PSTREAMEX pInStrmEx ** IN PHW_STREAM_REQUEST_BLOCK pInSrb ** ** Returns: ** ** Side Effects: none */ #ifdef CCINPUTPIN #ifdef DEBUG short CCskipHwDecode = 0; #endif /*DEBUG*/ #ifdef NEWCCINPUTFORMAT void VBIhwDecode( PHW_DEVICE_EXTENSION pHwDevExt, PSTREAMEX pInStrmEx, PHW_STREAM_REQUEST_BLOCK pInSrb ) { PKSSTREAM_HEADER pInStreamHeader = pInSrb->CommandData.DataBufferArray; KSSTREAM_HEADER InStreamHeaderCopy; PCC_HW_FIELD pCCin = (PCC_HW_FIELD)pInStreamHeader->Data; ULONG CurrentStrmEx = 0; PVBICODECFILTERING_STATISTICS_CC Stats = 0; int line, start, end; int hidx; int didx; DWORD fields; CASSERT(KeGetCurrentIrql() <= APC_LEVEL); CASSERT(pHwDevExt); CASSERT(pInStrmEx); Stats = &pHwDevExt->Statistics; CDebugPrint( DebugLevelInfo, ( "*" )); CDebugPrint( DebugLevelTrace, ( CODECNAME ": --->VBIhwDecode\n" )); Stats->Common.InputSRBsProcessed++; // // If DataUsed == 0 then don't bother // if( pInStreamHeader->DataUsed < sizeof (CC_HW_FIELD) #ifdef DEBUG || CCskipHwDecode #endif /*DEBUG*/ ) { #ifdef DEBUG if (!CCskipHwDecode) #endif /*DEBUG*/ { Stats->Common.SRBsIgnored++; CDebugPrint( DebugLevelError, ( CODECNAME ": DataUsed is too small, abandoning\n" )); } StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } pInStrmEx->LastPictureNumber = pCCin->PictureNumber; // // Update stats // if( ( pInStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY ) || ( pInStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY ) ) Stats->Common.InputDiscontinuities++; // // pHwDevExt->fTunerChange is set while the TV tuner is changing channels. // SRBs are junk until the channel change completes so complete. // if( pHwDevExt->fTunerChange ) { CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Completing, channel change in progress\n" )); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } #ifdef CCINPUTPIN // Check to see if this field has been decoded already (are we too late?) ExAcquireFastMutex(&pHwDevExt->LastPictureMutex); if (pInStrmEx->LastPictureNumber <= pHwDevExt->LastPictureNumber) { ExReleaseFastMutex(&pHwDevExt->LastPictureMutex); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } // Nope, we're not too late. Stow the data. pHwDevExt->LastPictureNumber = pInStrmEx->LastPictureNumber; ExReleaseFastMutex(&pHwDevExt->LastPictureMutex); #endif // CCINPUTPIN // figure out where hardware decoding starts and ends for( start = 1; start < 1024; ++start ) { if( TESTBIT( pCCin->ScanlinesRequested.DwordBitArray, start )) break; } for( end = 1023; end > start; --end ) { if( TESTBIT( pCCin->ScanlinesRequested.DwordBitArray, end )) break; } if (1024 == start) { StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } CASSERT(start <= end); // Resize Result array if needed CheckResultsArray(pHwDevExt, start, end); // loop for each scanline CDebugPrint( DebugLevelVerbose, ( "" "\n" )); hidx = 0; for( line = start; line <= end && hidx < CC_MAX_HW_DECODE_LINES; ++line ) { if( !TESTBIT( pCCin->ScanlinesRequested.DwordBitArray, line )) continue; CDebugPrint( DebugLevelTrace, ( CODECNAME ": Scanning %u\n", line )); didx = line - pHwDevExt->DSPResultStartLine; pHwDevExt->DSPResult[didx].Decoded[0] = pCCin->Lines[hidx].Decoded[0]; pHwDevExt->DSPResult[didx].Decoded[1] = pCCin->Lines[hidx].Decoded[1]; ++hidx; pHwDevExt->DSPResult[didx].Confidence = 99; // HW decoded Stats->Common.LineConfidenceAvg = (Stats->Common.LineConfidenceAvg + 99) / 2; } // // Copy the input stream header & other info for later reference // InStreamHeaderCopy = *pInStreamHeader; fields = pCCin->fieldFlags & (KS_VBI_FLAG_FIELD1|KS_VBI_FLAG_FIELD2); // // Complete the upstream SRB. // StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); // // Lose all references to the just completed SRB // pInSrb = 0; pInStreamHeader = 0; pCCin = 0; OutputCC(pHwDevExt, pInStrmEx, fields, &InStreamHeaderCopy); CDebugPrint( DebugLevelTrace, ( CODECNAME ": <---VBIhwDecode\n" )); } #else //NEWCCINPUTFORMAT void VBIhwDecode( PHW_DEVICE_EXTENSION pHwDevExt, PSTREAMEX pInStrmEx, PHW_STREAM_REQUEST_BLOCK pInSrb ) { PKSSTREAM_HEADER pInStreamHeader = pInSrb->CommandData.DataBufferArray; KSSTREAM_HEADER InStreamHeaderCopy; PUCHAR pInData = (PUCHAR)pInStreamHeader->Data; ULONG CurrentStrmEx = 0; PVBICODECFILTERING_STATISTICS_CC Stats = 0; CASSERT((ULONG)pHwDevExt); CASSERT((ULONG)pInStrmEx); Stats = &pHwDevExt->Statistics; CDebugPrint( DebugLevelInfo, ( "*" )); CDebugPrint( DebugLevelTrace, ( CODECNAME ": --->VBIhwDecode\n" )); Stats->Common.InputSRBsProcessed++; // // If DataUsed == 0 then don't bother // if( pInStreamHeader->DataUsed < 2 #ifdef DEBUG || CCskipHwDecode #endif /*DEBUG*/ ) { #ifdef DEBUG if (!CCskipDecode) #endif /*DEBUG*/ Stats->Common.SRBsIgnored++; CDebugPrint( DebugLevelError, ( CODECNAME ": DataUsed is too small, abandoning\n" )); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } // // Update stats // if( ( pInStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY ) || ( pInStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEDISCONTINUITY ) ) Stats->Common.InputDiscontinuities++; // // pHwDevExt->fTunerChange is set while the TV tuner is changing channels. // SRBs are junk until the channel change completes so complete. // if( pHwDevExt->fTunerChange ) { CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Completing, channel change in progress\n" )); StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); return; } // loop for each requested scanline CDebugPrint( DebugLevelVerbose, ( "" "\n" )); pHwDevExt->DSPResult[21-10].Decoded[0] = pInData[0]; pHwDevExt->DSPResult[21-10].Decoded[1] = pInData[1]; pHwDevExt->DSPResult[21-10].Confidence = 95; Stats->Common.LineConfidenceAvg = ( Stats->Common.LineConfidenceAvg + pHwDevExt->DSPResult[21-10].Confidence ) / 2; // // Copy the input stream header for later reference // InStreamHeaderCopy = *pInStreamHeader; // // Complete the upstream SRB. // StreamClassStreamNotification( StreamRequestComplete, pInSrb->StreamObject, pInSrb ); // // Lose all references to the just completed SRB // pInSrb = 0; pInStreamHeader = 0; pInData = 0; // // Now output to anyone interested // OutputCC(pHwDevExt, pInStrmEx, KS_VBI_FLAG_FIELD1, &InStreamHeaderCopy); CDebugPrint( DebugLevelTrace, ( CODECNAME ": <---VBIhwDecode\n" )); } #endif //NEWCCINPUTFORMAT #endif //CCINPUTPIN /* ** VBIReceiveDataPacket() ** ** Receives Video data packet commands ** ** Arguments: ** ** pSrb - Stream request block for the Video stream ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VBIReceiveDataPacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = (PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension; PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; int ThisStreamNr = (int)pSrb->StreamObject->StreamNumber; #ifdef DEBUG static int QdepthReportFreq = 0; static unsigned int QDRCount = 0; #endif // DEBUG // // make sure we have a device extension // CASSERT(pHwDevExt); CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VBIReceiveDataPacket(pSrb=%x)\n", pSrb)); // // Default to success // pSrb->Status = STATUS_SUCCESS; // // Disable timeout // pSrb->TimeoutCounter = 0; // // determine the type of packet. // // Rule: // Only accept read requests when in either the Pause or Run // States. If Stopped, immediately return the SRB. if (pStrmEx->KSState == KSSTATE_STOP) { StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb ); return; } switch (pSrb->Command) { #ifdef DRIVER_DEBUGGING_TEST case SRB_READ_DATA: case SRB_WRITE_DATA: // When initially bringing up a driver, it is useful to just // try immediately completing the SRB, thus verifying // the streaming process independent of really accessing // your hardware. StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb ); break; #else // DRIVER_DEBUGGING_TEST case SRB_READ_DATA: if( ThisStreamNr != STREAM_CC ) { CDebugPrint( DebugLevelError, ( CODECNAME ": Read Stream # Bad\n" )); CDEBUG_BREAK(); pSrb->Status = STATUS_NOT_IMPLEMENTED; } else { CDebugPrint( DebugLevelTrace, ( CODECNAME ": Stream %u Instance %u\n", ThisStreamNr, pStrmEx->StreamInstance )); if( pStrmEx->StreamInstance != 0 ) CDebugPrint( DebugLevelTrace, ( CODECNAME ": Stream %u Instance %u\n", ThisStreamNr, pStrmEx->StreamInstance )); QueueAdd( pSrb, &pStrmEx->StreamDataSpinLock, &pStrmEx->StreamDataQueue ); // Since another thread COULD HAVE MODIFIED THE STREAM STATE // in the midst of adding it to the queue, check the stream // state again, and cancel the SRB if necessary. // Note that this race condition was NOT handled in the // original DDK release of testcap! if (pStrmEx->KSState == KSSTATE_STOP) CodecCancelPacket(pSrb); } break; case SRB_WRITE_DATA: if( STREAM_VBI == ThisStreamNr) { #ifdef DEBUG static int MaxVBIqDepth = 0; static int AvgVBIqDepth = 1000; // 1.000 int qDepth = 0; #endif // DEBUG CDebugPrint( DebugLevelTrace, ( CODECNAME ": Stream VBI Writing\n")); if( QueueAddIfNotEmpty( pSrb, &pStrmEx->StreamDataSpinLock, &pStrmEx->StreamDataQueue )) break; do { #ifdef CCINPUTPIN KIRQL Irql; #endif // CCINPUTPIN #ifdef DEBUG ++qDepth; ++QDRCount; #endif // DEBUG #ifdef CCINPUTPIN KeAcquireSpinLock(&pStrmEx->VBIOnHoldSpinLock, &Irql); if (NULL != pStrmEx->pVBISrbOnHold) { PHW_STREAM_REQUEST_BLOCK pTempSrb; pTempSrb = pStrmEx->pVBISrbOnHold; pStrmEx->pVBISrbOnHold = NULL; KeReleaseSpinLock(&pStrmEx->VBIOnHoldSpinLock, Irql); VBIDecode( pHwDevExt, pStrmEx, pTempSrb, 0 ); } else KeReleaseSpinLock(&pStrmEx->VBIOnHoldSpinLock, Irql); #endif // CCINPUTPIN VBIDecode( pHwDevExt, pStrmEx, pSrb, 1 ); }while( QueueRemove( &pSrb, &pStrmEx->StreamDataSpinLock, &pStrmEx->StreamDataQueue )); #ifdef DEBUG if (qDepth > MaxVBIqDepth) MaxVBIqDepth = qDepth; AvgVBIqDepth = (AvgVBIqDepth * 7 / 8) + (qDepth * 1000 / 8); if (QdepthReportFreq > 0 && 0 == QDRCount % QdepthReportFreq) { CDebugPrint( 0, (CODECNAME ": Max VBI Q depth = %3d, Avg VBI Q depth = %3d.%03d\n", MaxVBIqDepth, AvgVBIqDepth / 1000, AvgVBIqDepth % 1000)); } #endif // DEBUG } #ifdef CCINPUTPIN else if (STREAM_CCINPUT == ThisStreamNr) { #ifdef DEBUG static int MaxCCINqDepth = 0; static int AvgCCINqDepth = 1000; // 1.000 int qDepth = 0; #endif // DEBUG CDebugPrint( DebugLevelTrace, (CODECNAME ": Stream CCINPUT Writing\n")); if( QueueAddIfNotEmpty( pSrb, &pStrmEx->StreamDataSpinLock, &pStrmEx->StreamDataQueue )) break; do { #ifdef DEBUG ++qDepth; ++QDRCount; #endif // DEBUG VBIhwDecode( pHwDevExt, pStrmEx, pSrb ); }while( QueueRemove( &pSrb, &pStrmEx->StreamDataSpinLock, &pStrmEx->StreamDataQueue )); #ifdef DEBUG if (qDepth > MaxCCINqDepth) MaxCCINqDepth = qDepth; AvgCCINqDepth = (AvgCCINqDepth * 7 / 8) + (qDepth * 1000 / 8); if (QdepthReportFreq > 0 && 0 == QDRCount % QdepthReportFreq) { CDebugPrint( 0, (CODECNAME ": Max CCIN Q depth = %3d, Avg CCIN Q depth = %3d.%03d\n", MaxCCINqDepth, AvgCCINqDepth / 1000, AvgCCINqDepth % 1000)); } #endif // DEBUG } #endif // CCINPUTPIN else { CDebugPrint( DebugLevelError, ( CODECNAME, ": Write Stream # Bad (%u)\n", ThisStreamNr )); CDEBUG_BREAK(); pSrb->Status = STATUS_NOT_IMPLEMENTED; } break; #endif // DRIVER_DEBUGGING_TEST break; default: // // invalid / unsupported command. Fail it as such // CDEBUG_BREAK(); pSrb->Status = STATUS_NOT_IMPLEMENTED; StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb ); } // switch (pSrb->Command) CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VBIReceiveDataPacket(pSrb=%x)\n", pSrb)); } /* ** VBIReceiveCtrlPacket() ** ** Receives packet commands that control the Video stream ** ** Arguments: ** ** pSrb - The stream request block for the Video stream ** ** Returns: nothing ** ** Side Effects: none */ VOID STREAMAPI VBIReceiveCtrlPacket( IN PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VBIReceiveCtrlPacket(pSrb=%x)\n", pSrb)); CASSERT(pHwDevExt); // // Default to success // pSrb->Status = STATUS_SUCCESS; if( QueueAddIfNotEmpty( pSrb, &pStrmEx->StreamControlSpinLock, &pStrmEx->StreamControlQueue )) return; do { // // determine the type of packet. // switch (pSrb->Command) { case SRB_PROPOSE_DATA_FORMAT: if ( !CodecVerifyFormat( pSrb->CommandData.OpenFormat, pSrb->StreamObject->StreamNumber, NULL ) ) { pSrb->Status = STATUS_NO_MATCH; } 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 // CDEBUG_BREAK(); pSrb->Status = STATUS_NOT_IMPLEMENTED; } StreamClassStreamNotification( StreamRequestComplete, pSrb->StreamObject, pSrb ); }while( QueueRemove( &pSrb, &pStrmEx->StreamControlSpinLock, &pStrmEx->StreamControlQueue )); CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VBIReceiveCtrlPacket(pSrb=%x)\n", pSrb)); } /* ** VideoGetProperty() ** ** Routine to process video property requests ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoGetProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; int StreamNumber = (int)pSrb->StreamObject->StreamNumber; CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VideoGetProperty(pSrb=%x)\n", pSrb)); if (IsEqualGUID (&KSPROPSETID_Connection, &pSPD->Property->Set)) { VideoStreamGetConnectionProperty( pSrb ); } else if (IsEqualGUID (&KSPROPSETID_VBICodecFiltering, &pSPD->Property->Set)) { VideoStreamGetVBIFilteringProperty (pSrb); } else { CDebugPrint( DebugLevelTrace, ( CODECNAME ": Unsupported Property Set\n" )); pSrb->Status = STATUS_NOT_IMPLEMENTED; } CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VideoGetProperty(pSrb=%x)\n", pSrb)); } /* ** VideoSetProperty() ** ** Routine to process video property requests ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoSetProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VideoSetProperty(pSrb=%x)\n", pSrb)); if (IsEqualGUID (&KSPROPSETID_VBICodecFiltering, &pSPD->Property->Set)) { VideoStreamSetVBIFilteringProperty (pSrb); } else if( IsEqualGUID( &KSPROPSETID_Stream, &pSPD->Property->Set )) { pSrb->Status = STATUS_SUCCESS; } else { pSrb->Status = STATUS_NOT_IMPLEMENTED; } CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VideoSetProperty(pSrb=%x)\n", pSrb)); } /* ** VideoSetState() ** ** Sets the current state of the requested stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoSetState( PHW_STREAM_REQUEST_BLOCK pSrb ) { PHW_DEVICE_EXTENSION pHwDevExt = ((PHW_DEVICE_EXTENSION)pSrb->HwDeviceExtension); PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PHW_STREAM_REQUEST_BLOCK pCurrentSrb; int StreamNumber = (int)pSrb->StreamObject->StreamNumber; CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VideoSetState(pSrb=%x)\n", pSrb)); // // 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") // 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 // switch (pSrb->CommandData.StreamState) { case KSSTATE_STOP: // // If transitioning to the stopped state, then complete any outstanding IRPs // while( QueueRemove( &pCurrentSrb, &pStrmEx->StreamDataSpinLock, &pStrmEx->StreamDataQueue )) { CDebugPrint(DebugLevelVerbose,( CODECNAME ": Cancelling %X\n", pCurrentSrb )); pCurrentSrb->Status = STATUS_CANCELLED; pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0; StreamClassStreamNotification( StreamRequestComplete, pCurrentSrb->StreamObject, pCurrentSrb ); } CDebugPrint( DebugLevelTrace, ( CODECNAME ": KSSTATE_STOP %u\n", StreamNumber )); break; case KSSTATE_ACQUIRE: // // This is a KS only state, that has no correspondence in DirectShow // CDebugPrint( DebugLevelTrace, ( CODECNAME ": KSSTATE_ACQUIRE %u\n", StreamNumber )); break; case KSSTATE_PAUSE: // // On a transition to pause from acquire, start our timer running. // if (pStrmEx->KSState == KSSTATE_ACQUIRE || pStrmEx->KSState == KSSTATE_STOP) { // Remember the time at which the clock was started pHwDevExt->QST_Start = VideoGetSystemTime(); // And initialize the last frame timestamp pHwDevExt->QST_Now = pHwDevExt->QST_Start; // Fireup the codec HERE in preparation for receiving data & requests. // INSERT CODE HERE } CDebugPrint( DebugLevelTrace, ( CODECNAME ": KSSTATE_PAUSE %u\n", StreamNumber )); break; case KSSTATE_RUN: // // Begin Streaming. // // Remember the time at which the clock was started pHwDevExt->QST_Start = VideoGetSystemTime(); // Zero the frame info, it should be reset when the first sample arrives. RtlZeroMemory (&pStrmEx->FrameInfo, sizeof (pStrmEx->FrameInfo)); // Zero the last known picture numbers pStrmEx->LastPictureNumber = 0; pHwDevExt->LastPictureNumber = 0; // Reset the discontinuity flag pStrmEx->fDiscontinuity = FALSE; CDebugPrint( DebugLevelTrace, ( CODECNAME ": KSSTATE_RUN %u\n", StreamNumber )); break; default: CDebugPrint( DebugLevelError, ( CODECNAME ": UNKNOWN STATE %u\n", StreamNumber )); CDEBUG_BREAK(); break; } // end switch (pSrb->CommandData.StreamState) // // Remember the state of this stream // pStrmEx->KSState = pSrb->CommandData.StreamState; CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VideoSetState(pSrb=%x)\n", pSrb)); } /* ** VideoGetState() ** ** Gets the current state of the requested stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoGetState( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; CDebugPrint(DebugLevelTrace,(CODECNAME ":--->VideoGetState(pSrb=%x)\n", pSrb)); 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 ERROR_NO_DATA_DETECTED if (pStrmEx->KSState == KSSTATE_PAUSE) { pSrb->Status = STATUS_NO_DATA_DETECTED; } CDebugPrint(DebugLevelTrace,(CODECNAME ":<---VideoGetState(pSrb=%x)=%d\n", pSrb, pStrmEx->KSState)); } /* ** VideoStreamGetConnectionProperty() ** ** Gets the current state of the requested stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoStreamGetConnectionProperty( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; PHW_DEVICE_EXTENSION pHwDevExt = pStrmEx->pHwDevExt; PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo; ULONG Id = pSPD->Property->Id; // index of the property int StreamNumber = ( int )pSrb->StreamObject->StreamNumber; CDebugPrint(DebugLevelTrace, ( CODECNAME ":--->VideoStreamGetConnectionProperty(pSrb=%x)\n", pSrb)); pSrb->ActualBytesTransferred = 0; switch (Id) { case KSPROPERTY_CONNECTION_ALLOCATORFRAMING: { PKSALLOCATOR_FRAMING Framing = (PKSALLOCATOR_FRAMING) pSPD->PropertyInfo; // PKS_DATARANGE_VIDEO_VBI pVBIFormat; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetConnectionProperty : KSPROPERTY_CONNECTION_ALLOCATORFRAMING %u\n", StreamNumber)); Framing->RequirementsFlags = KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY | KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY | KSALLOCATOR_REQUIREMENTF_INPLACE_MODIFIER; Framing->PoolType = NonPagedPool; Framing->FileAlignment = 0; // None OR FILE_QUAD_ALIGNMENT OR PAGE_SIZE - 1; Framing->Reserved = 0; switch( StreamNumber ) { case STREAM_VBI: Framing->Frames = 8; Framing->FrameSize = pStrmEx->OpenedFormat.SampleSize; break; case STREAM_CC: if( CodecCompareGUIDsAndFormatSize( &pStrmEx->OpenedFormat, pHwDevExt->Streams[STREAM_CC].hwStreamInfo.StreamFormatsArray[0], FALSE )) { Framing->Frames = 60; Framing->FrameSize = CCSamples; } else if( CodecCompareGUIDsAndFormatSize( &pStrmEx->OpenedFormat, pHwDevExt->Streams[STREAM_CC].hwStreamInfo.StreamFormatsArray[1], FALSE )) { Framing->Frames = 8; Framing->FrameSize = pStrmEx->OpenedFormat.SampleSize; } else { CDebugPrint( DebugLevelError, ( CODECNAME ": VideoStreamGetConnectionProperty: Invalid Format\n" )); CDEBUG_BREAK(); } break; #ifdef CCINPUTPIN case STREAM_CCINPUT: Framing->Frames = 60; Framing->FrameSize = CCSamples; break; #endif // CCINPUTPIN default: CDebugPrint( DebugLevelError, ( CODECNAME ": VideoStreamGetConnectionProperty: Invalid Stream #\n" )); CDEBUG_BREAK(); } CDebugPrint( DebugLevelVerbose, ( CODECNAME ": Negotiated sample size is %d\n", Framing->FrameSize )); pSrb->ActualBytesTransferred = sizeof (KSALLOCATOR_FRAMING); break; } default: pSrb->Status = STATUS_NOT_IMPLEMENTED; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetConnectionProperty : Unknown Property Id=%d\n", Id)); CDEBUG_BREAK(); break; } CDebugPrint(DebugLevelTrace, ( CODECNAME ":<---VideoStreamGetConnectionProperty(pSrb=%x)\n", pSrb)); } /* ** VideoStreamGetVBIFilteringProperty() ** ** Gets the current state of the requested stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoStreamGetVBIFilteringProperty( 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 LONG nBytes = pSPD->PropertyOutputSize - sizeof(KSPROPERTY); // size of data supplied CDebugPrint(DebugLevelTrace, ( CODECNAME ":--->VideoStreamGetVBIFilteringProperty(pSrb=%x)\n", pSrb)); ASSERT (nBytes >= sizeof (LONG)); pSrb->ActualBytesTransferred = 0; switch (Id) { case KSPROPERTY_VBICODECFILTERING_SCANLINES_REQUESTED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_SCANLINES_S Property = (PKSPROPERTY_VBICODECFILTERING_SCANLINES_S) pSPD->PropertyInfo; nBytes = min( nBytes, sizeof( pStrmEx->ScanlinesRequested ) ); RtlCopyMemory( &Property->Scanlines, &pStrmEx->ScanlinesRequested, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SCANLINES_REQUESTED_BIT_ARRAY\n")); break; } case KSPROPERTY_VBICODECFILTERING_SCANLINES_DISCOVERED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_SCANLINES_S Property = (PKSPROPERTY_VBICODECFILTERING_SCANLINES_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SCANLINES_DISCOVERED_BIT_ARRAY\n")); nBytes = min( nBytes, sizeof( pStrmEx->ScanlinesDiscovered ) ); RtlCopyMemory( &Property->Scanlines, &pStrmEx->ScanlinesDiscovered, nBytes ); // Clear the data after the read so that it's always "fresh" RtlZeroMemory( &pStrmEx->ScanlinesDiscovered, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } case KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_REQUESTED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S Property = (PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S) pSPD->PropertyInfo; nBytes = min( nBytes, sizeof( pStrmEx->SubstreamsRequested ) ); RtlCopyMemory( &Property->Substreams, &pStrmEx->SubstreamsRequested, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); CDebugPrint(DebugLevelInfo, ( CODECNAME ": VideoStreamGetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_REQUESTED_BIT_ARRAY %08x\n", Property->Substreams )); break; } case KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_DISCOVERED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S Property = (PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_DISCOVERED_BIT_ARRAY\n")); nBytes = min( nBytes, sizeof( pStrmEx->SubstreamsDiscovered ) ); RtlCopyMemory( &Property->Substreams, &pStrmEx->SubstreamsDiscovered, nBytes ); // Clear the data after the read so that it's always "fresh" RtlZeroMemory( &pStrmEx->SubstreamsDiscovered, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } case KSPROPERTY_VBICODECFILTERING_STATISTICS: { PKSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S Property = (PKSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S\n")); nBytes = min( nBytes, sizeof( pStrmEx->PinStats ) ); RtlCopyMemory( &Property->Statistics, &pStrmEx->PinStats, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } default: pSrb->Status = STATUS_NOT_IMPLEMENTED; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamGetVBIFilteringProperty : Unknown Property Id=%d\n", Id)); CDEBUG_BREAK(); break; } CDebugPrint(DebugLevelTrace, ( CODECNAME ":<---VideoStreamGetVBIFilteringProperty(pSrb=%x)\n", pSrb)); } /* ** VideoStreamSetVBIFilteringProperty() ** ** Sets the current state of the requested stream ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoStreamSetVBIFilteringProperty( 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 ULONG nBytes = pSPD->PropertyOutputSize - sizeof(KSPROPERTY); // size of data supplied ASSERT (nBytes >= sizeof (LONG)); CDebugPrint(DebugLevelTrace, ( CODECNAME ":--->VideoStreamSetVBIFilteringProperty(pSrb=%x)\n", pSrb)); pSrb->ActualBytesTransferred = 0; switch (Id) { case KSPROPERTY_VBICODECFILTERING_SCANLINES_REQUESTED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_SCANLINES_S Property = (PKSPROPERTY_VBICODECFILTERING_SCANLINES_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamSetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SCANLINES_REQUESTED_BIT_ARRAY\n")); nBytes = min( nBytes, sizeof( pStrmEx->ScanlinesRequested ) ); RtlCopyMemory( &pStrmEx->ScanlinesRequested, &Property->Scanlines, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } #ifdef SETDISCOVERED case KSPROPERTY_VBICODECFILTERING_SCANLINES_DISCOVERED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_SCANLINES_S Property = (PKSPROPERTY_VBICODECFILTERING_SCANLINES_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamSetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SCANLINES_DISCOVERED_BIT_ARRAY\n")); nBytes = min( nBytes, sizeof(pStrmEx->ScanlinesDiscovered ) ); RtlCopyMemory( &pStrmEx->ScanlinesDiscovered, &Property->Scanlines, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } #endif // SETDISCOVERED case KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_REQUESTED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S Property = (PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S) pSPD->PropertyInfo; nBytes = min( nBytes, sizeof(pStrmEx->SubstreamsRequested ) ); RtlCopyMemory( &pStrmEx->SubstreamsRequested, &Property->Substreams, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); CDebugPrint(DebugLevelInfo, ( CODECNAME ": VideoStreamSetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_REQUESTED_BIT_ARRAY %08x\n", pStrmEx->SubstreamsRequested.SubstreamMask)); break; } #ifdef SETDISCOVERED case KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_DISCOVERED_BIT_ARRAY: { PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S Property = (PKSPROPERTY_VBICODECFILTERING_CC_SUBSTREAMS_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamSetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_SUBSTREAMS_DISCOVERED_BIT_ARRAY\n")); nBytes = min( nBytes, sizeof(pStrmEx->SubstreamsDiscovered ) ); RtlCopyMemory( &pStrmEx->SubstreamsDiscovered, &Property->Substreams, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } #endif // SETDISCOVERED case KSPROPERTY_VBICODECFILTERING_STATISTICS: { PKSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S Property = (PKSPROPERTY_VBICODECFILTERING_STATISTICS_CC_PIN_S) pSPD->PropertyInfo; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamSetVBIFilteringProperty : KSPROPERTY_VBICODECFILTERING_STATISTICS\n")); nBytes = min( nBytes, sizeof( pStrmEx->PinStats ) ); RtlCopyMemory( &pStrmEx->PinStats, &Property->Statistics, nBytes ); pSrb->ActualBytesTransferred = nBytes + sizeof(KSPROPERTY); break; } default: pSrb->Status = STATUS_NOT_IMPLEMENTED; CDebugPrint(DebugLevelVerbose, ( CODECNAME ": VideoStreamSetVBIFilteringProperty : Unknown Property Id=%d\n", Id)); CDEBUG_BREAK(); break; } CDebugPrint(DebugLevelTrace, ( CODECNAME ":<---VideoStreamSetVBIFilteringProperty(pSrb=%x)\n", pSrb)); } /* ** GetSystemTime () ** ** Returns the system time in 100 nS units ** ** Arguments: ** ** Returns: ** ** Side Effects: none */ ULONGLONG VideoGetSystemTime() { ULONGLONG ticks; ULONGLONG rate; CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VideoGetSystemTime()\n")); ticks = (ULONGLONG)KeQueryPerformanceCounter((PLARGE_INTEGER)&rate).QuadPart; // // convert from ticks to 100ns clock // ticks = (ticks & 0xFFFFFFFF00000000) / rate * 10000000 + (ticks & 0x00000000FFFFFFFF) * 10000000 / rate; CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VideoGetSystemTime()\n")); return(ticks); } //==========================================================================; // Clock Handling Routines //==========================================================================; /* ** VideoIndicateMasterClock () ** ** This function is used to provide us with a handle to the clock to use. ** ** Arguments: ** ** pSrb - pointer to the stream request block for properties ** ** Returns: ** ** Side Effects: none */ VOID VideoIndicateMasterClock( PHW_STREAM_REQUEST_BLOCK pSrb ) { PSTREAMEX pStrmEx = (PSTREAMEX)pSrb->StreamObject->HwStreamExtension; CDebugPrint(DebugLevelTrace,( CODECNAME ":--->VideoIndicateMasterClock(pSrb=%x)\n", pSrb)); pStrmEx->hClock = pSrb->CommandData.MasterClockHandle; CDebugPrint(DebugLevelTrace,( CODECNAME ":<---VideoIndicateMasterClock(pSrb=%x)\n", pSrb)); }