windows-nt/Source/XPSP1/NT/drivers/wdm/vbi/cc/codvideo.c
2020-09-26 16:20:57 +08:00

2336 lines
79 KiB
C

//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
//
//==========================================================================;
#include <strmini.h>
#include <ksmedia.h>
#include "kskludge.h"
#include "codmain.h"
#include "coddebug.h"
#include <ntstatus.h>
#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));
}