📄 capture.cpp
字号:
PAGED_CODE();
PKSSTREAM_POINTER Clone = KsPinGetFirstCloneStreamPointer (m_Pin);
PKSSTREAM_POINTER NextClone = NULL;
//
// Walk through the clones, deleting them, and setting DataUsed to
// zero since we didn't use any data!
//
while (Clone) {
NextClone = KsStreamPointerGetNextClone (Clone);
Clone -> StreamHeader -> DataUsed = 0;
KsStreamPointerDelete (Clone);
Clone = NextClone;
}
return STATUS_SUCCESS;
}
/*************************************************/
NTSTATUS
CCapturePin::
SetState (
IN KSSTATE ToState,
IN KSSTATE FromState
)
/*++
Routine Description:
This is called when the caputre pin transitions state. The routine
attempts to acquire / release any hardware resources and start up
or shut down capture based on the states we are transitioning to
and away from.
Arguments:
ToState -
The state we're transitioning to
FromState -
The state we're transitioning away from
Return Value:
Success / Failure
--*/
{
PAGED_CODE();
NTSTATUS Status = STATUS_SUCCESS;
switch (ToState) {
case KSSTATE_STOP:
//
// First, stop the hardware if we actually did anything to it.
//
if (m_HardwareState != HardwareStopped) {
Status = m_Device -> Stop ();
ASSERT (NT_SUCCESS (Status));
m_HardwareState = HardwareStopped;
}
//
// We've stopped the "fake hardware". It has cleared out
// it's scatter / gather tables and will no longer be
// completing clones. We had locks on some frames that were,
// however, in hardware. This will clean them up. An
// alternative location would be in the reset dispatch.
// Note, however, that the reset dispatch can occur in any
// state and this should be understood.
//
// Some hardware may fill all S/G mappings before stopping...
// in this case, you may not have to do this. The
// "fake hardware" here simply stops filling mappings and
// cleans its scatter / gather tables out on the Stop call.
//
Status = CleanupReferences ();
//
// Release any hardware resources related to this pin.
//
if (m_AcquiredResources) {
//
// If we got an interface to the clock, we must release it.
//
if (m_Clock) {
m_Clock -> Release ();
m_Clock = NULL;
}
m_Device -> ReleaseHardwareResources (
);
m_AcquiredResources = FALSE;
}
break;
case KSSTATE_ACQUIRE:
//
// Acquire any hardware resources related to this pin. We should
// only acquire them here -- **NOT** at filter create time.
// This means we do not fail creation of a filter because of
// limited hardware resources.
//
if (FromState == KSSTATE_STOP) {
Status = m_Device -> AcquireHardwareResources (
this,
m_TransportInfo
);
if (NT_SUCCESS (Status)) {
m_AcquiredResources = TRUE;
//
// Attempt to get an interface to the master clock.
// This will fail if one has not been assigned. Since
// one must be assigned while the pin is still in
// KSSTATE_STOP, this is a guranteed method of getting
// the clock should one be assigned.
//
if (!NT_SUCCESS (
KsPinGetReferenceClockInterface (
m_Pin,
&m_Clock
)
)) {
//
// If we could not get an interface to the clock,
// don't use one.
//
m_Clock = NULL;
}
} else {
m_AcquiredResources = FALSE;
}
} else {
//
// Standard transport pins will always receive transitions in
// +/- 1 manner. This means we'll always see a PAUSE->ACQUIRE
// transition before stopping the pin.
//
// The below is done because on DirectX 8.0, when the pin gets
// a message to stop, the queue is inaccessible. The reset
// which comes on every stop happens after this (at which time
// the queue is inaccessible also). So, for compatibility with
// DirectX 8.0, I am stopping the "fake" hardware at this
// point and cleaning up all references we have on frames. See
// the comments above regarding the CleanupReferences call.
//
// If this sample were targeting XP only, the below code would
// not be here. Again, I only do this so the sample does not
// hang when it is stopped running on a configuration such as
// Win2K + DX8.
//
if (m_HardwareState != HardwareStopped) {
Status = m_Device -> Stop ();
ASSERT (NT_SUCCESS (Status));
m_HardwareState = HardwareStopped;
}
Status = CleanupReferences ();
}
break;
case KSSTATE_PAUSE:
//
// Stop the hardware simulation if we're coming down from run.
//
if (FromState == KSSTATE_RUN) {
Status = m_Device -> Pause (TRUE);
if (NT_SUCCESS (Status)) {
m_HardwareState = HardwarePaused;
}
}
break;
case KSSTATE_RUN:
//
// Start the hardware simulation or unpause it depending on
// whether we're initially running or we've paused and restarted.
//
if (m_HardwareState == HardwarePaused) {
Status = m_Device -> Pause (FALSE);
} else {
Status = m_Device -> Start ();
}
if (NT_SUCCESS (Status)) {
m_HardwareState = HardwareRunning;
}
break;
}
return Status;
}
/**************************************************************************
LOCKED CODE
**************************************************************************/
#ifdef ALLOC_PRAGMA
#pragma code_seg()
#endif // ALLOC_PRAGMA
void
CCapturePin::
CompleteMappings (
IN ULONG NumMappings
)
/*++
Routine Description:
Called to notify the pin that a given number of scatter / gather
mappings have completed. Let the buffers go if possible.
We're called at DPC.
Arguments:
NumMappings -
The number of mappings that have completed.
Return Value:
None
--*/
{
ULONG MappingsRemaining = NumMappings;
//
// Walk through the clones list and delete clones whose time has come.
// The list is guaranteed to be kept in the order they were cloned.
//
PKSSTREAM_POINTER Clone = KsPinGetFirstCloneStreamPointer (m_Pin);
while (MappingsRemaining && Clone) {
PKSSTREAM_POINTER NextClone = KsStreamPointerGetNextClone (Clone);
//
// Count up the number of bytes we've completed and mark this
// in the Stream Header. In mapped queues
// (KSPIN_FLAG_GENERATE_MAPPINGS), this is the responsibility of
// the minidriver. In non-mapped queues, AVStream performs this.
//
ULONG MappingsToCount =
(MappingsRemaining > Clone -> OffsetOut.Remaining) ?
Clone -> OffsetOut.Remaining :
MappingsRemaining;
//
// Update DataUsed according to the mappings.
//
for (ULONG CurMapping = 0; CurMapping < MappingsToCount; CurMapping++) {
Clone -> StreamHeader -> DataUsed +=
Clone -> OffsetOut.Mappings [CurMapping].ByteCount;
}
//
// If we have completed all remaining mappings in this clone, it
// is an indication that the clone is ready to be deleted and the
// buffer released. Set anything required in the stream header which
// has not yet been set. If we have a clock, we can timestamp the
// sample.
//
if (MappingsRemaining >= Clone -> OffsetOut.Remaining) {
Clone -> StreamHeader -> Duration =
m_TransportInfo -> AvgTimePerFrame;
Clone -> StreamHeader -> PresentationTime.Numerator =
Clone -> StreamHeader -> PresentationTime.Denominator = 1;
//
// If a clock has been assigned, timestamp the packets with the
// time shown on the clock.
//
if (m_Clock) {
LONGLONG ClockTime = m_Clock -> GetTime ();
Clone -> StreamHeader -> PresentationTime.Time = ClockTime;
Clone -> StreamHeader -> OptionsFlags =
KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
} else {
//
// If there is no clock, don't time stamp the packets.
//
Clone -> StreamHeader -> PresentationTime.Time = 0;
}
//
// If all of the mappings in this clone have been completed,
// delete the clone. We've already updated DataUsed above.
//
MappingsRemaining -= Clone -> OffsetOut.Remaining;
KsStreamPointerDelete (Clone);
} else {
//
// If only part of the mappings in this clone have been completed,
// update the pointers. Since we're guaranteed this won't advance
// to a new frame by the check above, it won't fail.
//
KsStreamPointerAdvanceOffsets (
Clone,
0,
MappingsRemaining,
FALSE
);
MappingsRemaining = 0;
}
//
// Go to the next clone.
//
Clone = NextClone;
}
//
// If we've used all the mappings in hardware and pended, we can kick
// processing to happen again if we've completed mappings.
//
if (m_PendIo) {
m_PendIo = TRUE;
KsPinAttemptProcessing (m_Pin, TRUE);
}
}
/**************************************************************************
DISPATCH AND DESCRIPTOR LAYOUT
**************************************************************************/
#define TS_PAYLOAD 188
#define TS_PACKETS_PER_BUFFER 312
//
// This is the data range description of the capture output pin.
//
const
KSDATARANGE FormatCaptureOut =
{
// insert the KSDATARANGE and KSDATAFORMAT here
{
sizeof( KSDATARANGE), // FormatSize
0, // Flags - (N/A)
TS_PACKETS_PER_BUFFER * TS_PAYLOAD, // SampleSize
0, // Reserved
{ STATIC_KSDATAFORMAT_TYPE_STREAM }, // MajorFormat
{ STATIC_KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT },// SubFormat
{ STATIC_KSDATAFORMAT_SPECIFIER_NONE } // Specifier
}
};
//
// This is the data range description of the capture input pin.
//
const
KS_DATARANGE_BDA_TRANSPORT FormatCaptureIn =
{
// insert the KSDATARANGE and KSDATAFORMAT here
{
sizeof( KS_DATARANGE_BDA_TRANSPORT), // FormatSize
0, // Flags - (N/A)
0, // SampleSize - (N/A)
0, // Reserved
{ STATIC_KSDATAFORMAT_TYPE_STREAM }, // MajorFormat
{ STATIC_KSDATAFORMAT_TYPE_MPEG2_TRANSPORT }, // SubFormat
{ STATIC_KSDATAFORMAT_SPECIFIER_BDA_TRANSPORT } // Specifier
},
// insert the BDA_TRANSPORT_INFO here
{
TS_PAYLOAD, // ulcbPhyiscalPacket
TS_PACKETS_PER_BUFFER * TS_PAYLOAD, // ulcbPhyiscalFrame
0, // ulcbPhyiscalFrameAlignment (no requirement)
0 // AvgTimePerFrame (not known)
}
};
//
// CapturePinDispatch:
//
// This is the dispatch table for the capture pin. It provides notifications
// about creation, closure, processing, data formats, etc...
//
const
KSPIN_DISPATCH
CapturePinDispatch = {
CCapturePin::DispatchCreate, // Pin Create
NULL, // Pin Close
CCapturePin::DispatchProcess, // Pin Process
NULL, // Pin Reset
NULL, // Pin Set Data Format
CCapturePin::DispatchSetState, // Pin Set Device State
NULL, // Pin Connect
NULL, // Pin Disconnect
NULL, // Clock Dispatch
NULL // Allocator Dispatch
};
//
// InputPinDispatch:
//
// This is the dispatch table for the capture pin. It provides notifications
// about creation, closure, processing, data formats, etc...
//
const
KSPIN_DISPATCH
InputPinDispatch = {
CCapturePin::DispatchCreate, // Pin Create
NULL, // Pin Close
NULL, // Pin Process
NULL, // Pin Reset
NULL, // Pin Set Data Format
NULL, // Pin Set Device State
NULL, // Pin Connect
NULL, // Pin Disconnect
NULL, // Clock Dispatch
NULL // Allocator Dispatch
};
//
// CapturePinAllocatorFraming:
//
// This is the simple framing structure for the capture pin. Note that this
// will be modified via KsEdit when the actual capture format is determined.
//
DECLARE_SIMPLE_FRAMING_EX (
CapturePinAllocatorFraming, // FramingExName
STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED), // MemoryType
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY, // Flags
8, // Frames
0, // Alignment
188 * 312, // MinFrameSize
188 * 312 // MaxFrameSize
);
//
// CaptureOutPinDataRanges:
//
// This is the list of data ranges supported on the capture output pin.
//
const
PKSDATARANGE
CaptureOutPinDataRanges [CAPTURE_OUT_PIN_DATA_RANGE_COUNT] = {
(PKSDATARANGE) &FormatCaptureOut
};
//
// CaptureInPinDataRanges:
//
// This is the list of data ranges supported on the capture input pin.
//
const
PKSDATARANGE
CaptureInPinDataRanges [CAPTURE_IN_PIN_DATA_RANGE_COUNT] = {
(PKSDATARANGE) &FormatCaptureIn
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -