📄 filter.cpp
字号:
/**************************************************************************
AVStream Filter-Centric Sample
Copyright (c) 1999 - 2001, Microsoft Corporation
File:
filter.cpp
Abstract:
This file contails the capture filter implementation (including
frame synthesis) for the fake capture filter.
History:
created 5/31/01
**************************************************************************/
#include "avssamp.h"
/**************************************************************************
PAGEABLE CODE
**************************************************************************/
#ifdef ALLOC_PRAGMA
#pragma code_seg("PAGE")
#endif // ALLOC_PRAGMA
CCaptureFilter::
CCaptureFilter (
IN PKSFILTER Filter
) :
m_Filter (Filter)
/*++
Routine Description:
This is the constructor for the capture filter. It initializes all the
structures necessary to kick off timer DPC's for capture.
Arguments:
Filter -
The AVStream filter being created.
Return Value:
None
--*/
{
//
// Initialize the DPC's, timers, and events necessary to cause a
// capture trigger to happen.
//
KeInitializeDpc (
&m_TimerDpc,
reinterpret_cast <PKDEFERRED_ROUTINE> (
CCaptureFilter::TimerRoutine
),
this
);
KeInitializeEvent (
&m_StopDPCEvent,
SynchronizationEvent,
FALSE
);
KeInitializeTimer (&m_Timer);
}
/*************************************************/
NTSTATUS
CCaptureFilter::
DispatchCreate (
IN PKSFILTER Filter,
IN PIRP Irp
)
/*++
Routine Description:
This is the creation dispatch for the capture filter. It creates
the CCaptureFilter object, associates it with the AVStream filter
object, and bag the CCaptureFilter for later cleanup.
Arguments:
Filter -
The AVStream filter being created
Irp -
The creation Irp
Return Value:
Success / failure
--*/
{
PAGED_CODE();
NTSTATUS Status = STATUS_SUCCESS;
CCaptureFilter *CapFilter = new (NonPagedPool) CCaptureFilter (Filter);
if (!CapFilter) {
//
// Return failure if we couldn't create the filter.
//
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
//
// Add the item to the object bag if we we were successful.
// Whenever the filter closes, the bag is cleaned up and we will be
// freed.
//
Status = KsAddItemToObjectBag (
Filter -> Bag,
reinterpret_cast <PVOID> (CapFilter),
reinterpret_cast <PFNKSFREE> (CCaptureFilter::Cleanup)
);
if (!NT_SUCCESS (Status)) {
delete CapFilter;
} else {
Filter -> Context = reinterpret_cast <PVOID> (CapFilter);
}
}
//
// Create the wave reader. We need it at this point because the data
// ranges exposed on the audio pin need to change dynamically right
// now.
//
if (NT_SUCCESS (Status)) {
CapFilter -> m_WaveObject =
new (NonPagedPool, 'evaW') CWaveObject (
L"\\DosDevices\\c:\\avssamp.wav"
);
if (!CapFilter -> m_WaveObject) {
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
Status = CapFilter -> m_WaveObject -> ParseAndRead ();
//
// If the file cannot be found, don't fail to create the filter.
// This simply means that audio cannot be synthesized.
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
Status == STATUS_ACCESS_DENIED) {
delete CapFilter -> m_WaveObject;
CapFilter -> m_WaveObject = NULL;
Status = STATUS_SUCCESS;
}
}
}
if (NT_SUCCESS (Status) && CapFilter -> m_WaveObject) {
//
// Add the wave object to the filter's bag for auto-cleanup.
//
Status = KsAddItemToObjectBag (
Filter -> Bag,
reinterpret_cast <PVOID> (CapFilter -> m_WaveObject),
reinterpret_cast <PFNKSFREE> (CWaveObject::Cleanup)
);
if (!NT_SUCCESS (Status)) {
delete CapFilter -> m_WaveObject;
CapFilter -> m_WaveObject = NULL;
} else {
Status = CapFilter -> BindAudioToWaveObject ();
}
}
return Status;
}
/*************************************************/
NTSTATUS
CCaptureFilter::
BindAudioToWaveObject (
)
/*++
Routine Description:
Create an audio pin directly bound to m_WaveObject (aka: it only exposes
the format (channels, frequency, etc...) that m_WaveObject represents.
This will actually create a pin on the filter dynamically.
Arguments:
None
Return Value:
Success / Failure
--*/
{
PAGED_CODE();
ASSERT (m_WaveObject);
NTSTATUS Status = STATUS_SUCCESS;
//
// Build a pin descriptor from the template. This descriptor is
// temporary scratch space because the call to AVStream to create the
// pin will actually duplicate the descriptor.
//
KSPIN_DESCRIPTOR_EX PinDescriptor = AudioPinDescriptorTemplate;
//
// The data range must be dynamically created since we're basing it
// on dynamic reading of a wave file!
//
PKSDATARANGE_AUDIO DataRangeAudio =
reinterpret_cast <PKSDATARANGE_AUDIO> (
ExAllocatePool (PagedPool, sizeof (KSDATARANGE_AUDIO))
);
PKSDATARANGE_AUDIO *DataRanges =
reinterpret_cast <PKSDATARANGE_AUDIO *> (
ExAllocatePool (PagedPool, sizeof (PKSDATARANGE_AUDIO))
);
PKSALLOCATOR_FRAMING_EX Framing =
reinterpret_cast <PKSALLOCATOR_FRAMING_EX> (
ExAllocatePool (PagedPool, sizeof (KSALLOCATOR_FRAMING_EX))
);
if (DataRangeAudio && DataRanges && Framing) {
DataRangeAudio -> DataRange.FormatSize = sizeof (KSDATARANGE_AUDIO);
DataRangeAudio -> DataRange.Flags = 0;
DataRangeAudio -> DataRange.SampleSize = 0;
DataRangeAudio -> DataRange.Reserved = 0;
DataRangeAudio -> DataRange.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
DataRangeAudio -> DataRange.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
DataRangeAudio -> DataRange.Specifier =
KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
m_WaveObject -> WriteRange (DataRangeAudio);
*DataRanges = DataRangeAudio;
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
if (NT_SUCCESS (Status)) {
//
// Bag the newly created range information in the filter's bag since
// this will be alive for the lifetime of the filter.
//
Status = KsAddItemToObjectBag (
m_Filter -> Bag,
DataRangeAudio,
NULL
);
if (!NT_SUCCESS (Status)) {
ExFreePool (DataRangeAudio);
ExFreePool (DataRanges);
ExFreePool (Framing);
}
}
if (NT_SUCCESS (Status)) {
Status = KsAddItemToObjectBag (
m_Filter -> Bag,
DataRanges,
NULL
);
if (!NT_SUCCESS (Status)) {
ExFreePool (DataRanges);
ExFreePool (Framing);
}
}
if (NT_SUCCESS (Status)) {
Status = KsAddItemToObjectBag (
m_Filter -> Bag,
Framing,
NULL
);
if (!NT_SUCCESS (Status)) {
ExFreePool (Framing);
}
}
if (NT_SUCCESS (Status)) {
//
// The physical and optimal ranges must block aligned and
// the size of 1/(fps) * bytes_per_sec in size. It's true
// that we don't know the frame rate at this point due
// to the fact that the video pin doesn't exist yet; however, that
// would also be true if this were edited at audio pin creation.
//
// Thus, we instead adjust the allocator for the minimum frame rate
// we support (which is 1/30 of a second).
//
*Framing = *PinDescriptor.AllocatorFraming;
Framing -> FramingItem [0].PhysicalRange.MinFrameSize =
Framing -> FramingItem [0].PhysicalRange.MaxFrameSize =
Framing -> FramingItem [0].FramingRange.Range.MinFrameSize =
Framing -> FramingItem [0].FramingRange.Range.MaxFrameSize =
((DataRangeAudio -> MaximumSampleFrequency *
DataRangeAudio -> MaximumBitsPerSample *
DataRangeAudio -> MaximumChannels) + 29) / 30;
Framing -> FramingItem [0].PhysicalRange.Stepping =
Framing -> FramingItem [0].FramingRange.Range.Stepping =
0;
PinDescriptor.AllocatorFraming = Framing;
PinDescriptor.PinDescriptor.DataRangesCount = 1;
PinDescriptor.PinDescriptor.DataRanges =
reinterpret_cast <const PKSDATARANGE *> (DataRanges);
//
// Create the actual pin. We need to save the pin id returned. It
// is how we refer to the audio pin in the future.
//
Status = KsFilterCreatePinFactory (
m_Filter,
&PinDescriptor,
&m_AudioPinId
);
}
return Status;
}
/*************************************************/
void
CCaptureFilter::
StartDPC (
IN LONGLONG TimerInterval
)
/*++
Routine Description:
This routine starts the timer DPC running at a specified interval. The
specified interval is the amount of time between triggering frame captures.
Once this routine returns, the timer DPC should be running and attempting
to trigger processing on the capture filter as a whole.
Arguments:
TimerInterval -
The amount of time between timer DPC's. This is the amount of delay
between one frame and the next. Since the DPC is driven off the
video capture pin, this should be an amount of time specified by
the video info header.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -