📄 video.cpp
字号:
/**************************************************************************
AVStream Filter-Centric Sample
Copyright (c) 1999 - 2001, Microsoft Corporation
File:
video.cpp
Abstract:
This file contains the video capture pin implementation.
History:
created 6/11/01
**************************************************************************/
#include "avssamp.h"
/**************************************************************************
PAGEABLE CODE
**************************************************************************/
#ifdef ALLOC_PRAGMA
#pragma code_seg("PAGE")
#endif // ALLOC_PRAGMA
NTSTATUS
CVideoCapturePin::
DispatchCreate (
IN PKSPIN Pin,
IN PIRP Irp
)
/*++
Routine Description:
Create a new video capture pin. This is the creation dispatch for
the video capture pin.
Arguments:
Pin -
The pin being created
Irp -
The creation Irp
Return Value:
Success / Failure
--*/
{
PAGED_CODE();
NTSTATUS Status = STATUS_SUCCESS;
CVideoCapturePin *CapPin = new (NonPagedPool) CVideoCapturePin (Pin);
CCapturePin *BasePin = static_cast <CCapturePin *> (CapPin);
if (!CapPin) {
//
// Return failure if we couldn't create the pin.
//
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
//
// Add the item to the object bag if we we were successful.
// Whenever the pin closes, the bag is cleaned up and we will be
// freed.
//
Status = KsAddItemToObjectBag (
Pin -> Bag,
reinterpret_cast <PVOID> (BasePin),
reinterpret_cast <PFNKSFREE> (CCapturePin::BagCleanup)
);
if (!NT_SUCCESS (Status)) {
delete CapPin;
} else {
Pin -> Context = reinterpret_cast <PVOID> (BasePin);
}
}
//
// If we succeeded so far, stash the video info header away and change
// our allocator framing to reflect the fact that only now do we know
// the framing requirements based on the connection format.
//
PKS_VIDEOINFOHEADER VideoInfoHeader = NULL;
if (NT_SUCCESS (Status)) {
VideoInfoHeader = CapPin -> CaptureVideoInfoHeader ();
if (!VideoInfoHeader) {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
if (NT_SUCCESS (Status)) {
//
// We need to edit the descriptor to ensure we don't mess up any other
// pins using the descriptor or touch read-only memory.
//
Status = KsEdit (Pin, &Pin -> Descriptor, 'aChS');
if (NT_SUCCESS (Status)) {
Status = KsEdit (
Pin,
&(Pin -> Descriptor -> AllocatorFraming),
'aChS'
);
}
//
// If the edits proceeded without running out of memory, adjust
// the framing based on the video info header.
//
if (NT_SUCCESS (Status)) {
//
// We've KsEdit'ed this... I'm safe to cast away constness as
// long as the edit succeeded.
//
PKSALLOCATOR_FRAMING_EX Framing =
const_cast <PKSALLOCATOR_FRAMING_EX> (
Pin -> Descriptor -> AllocatorFraming
);
Framing -> FramingItem [0].Frames = 2;
//
// The physical and optimal ranges must be biSizeImage. We only
// support one frame size, precisely the size of each capture
// image.
//
Framing -> FramingItem [0].PhysicalRange.MinFrameSize =
Framing -> FramingItem [0].PhysicalRange.MaxFrameSize =
Framing -> FramingItem [0].FramingRange.Range.MinFrameSize =
Framing -> FramingItem [0].FramingRange.Range.MaxFrameSize =
VideoInfoHeader -> bmiHeader.biSizeImage;
Framing -> FramingItem [0].PhysicalRange.Stepping =
Framing -> FramingItem [0].FramingRange.Range.Stepping =
0;
}
}
if (NT_SUCCESS (Status)) {
//
// Adjust the stream header size. The video packets have extended
// header info (KS_FRAME_INFO).
//
Pin -> StreamHeaderSize = sizeof (KSSTREAM_HEADER) +
sizeof (KS_FRAME_INFO);
}
return Status;
}
/*************************************************/
PKS_VIDEOINFOHEADER
CVideoCapturePin::
CaptureVideoInfoHeader (
)
/*++
Routine Description:
Capture the video info header out of the connection format. This
is what we use to base synthesized images off.
Arguments:
None
Return Value:
The captured video info header or NULL if there is insufficient
memory.
--*/
{
PAGED_CODE();
PKS_VIDEOINFOHEADER ConnectionHeader =
&((reinterpret_cast <PKS_DATAFORMAT_VIDEOINFOHEADER>
(m_Pin -> ConnectionFormat)) ->
VideoInfoHeader);
m_VideoInfoHeader = reinterpret_cast <PKS_VIDEOINFOHEADER> (
ExAllocatePool (
NonPagedPool,
KS_SIZE_VIDEOHEADER (ConnectionHeader)
)
);
if (!m_VideoInfoHeader)
return NULL;
//
// Bag the newly allocated header space. This will get cleaned up
// automatically when the pin closes.
//
NTSTATUS Status =
KsAddItemToObjectBag (
m_Pin -> Bag,
reinterpret_cast <PVOID> (m_VideoInfoHeader),
NULL
);
if (!NT_SUCCESS (Status)) {
ExFreePool (m_VideoInfoHeader);
return NULL;
} else {
//
// Copy the connection format video info header into the newly
// allocated "captured" video info header.
//
RtlCopyMemory (
m_VideoInfoHeader,
ConnectionHeader,
KS_SIZE_VIDEOHEADER (ConnectionHeader)
);
}
return m_VideoInfoHeader;
}
/*************************************************/
NTSTATUS
CVideoCapturePin::
IntersectHandler (
IN PKSFILTER Filter,
IN PIRP Irp,
IN PKSP_PIN PinInstance,
IN PKSDATARANGE CallerDataRange,
IN PKSDATARANGE DescriptorDataRange,
IN ULONG BufferSize,
OUT PVOID Data OPTIONAL,
OUT PULONG DataSize
)
/*++
Routine Description:
This routine handles video pin intersection queries by determining the
intersection between two data ranges.
Arguments:
Filter -
Contains a void pointer to the filter structure.
Irp -
Contains a pointer to the data intersection property request.
PinInstance -
Contains a pointer to a structure indicating the pin in question.
CallerDataRange -
Contains a pointer to one of the data ranges supplied by the client
in the data intersection request. The format type, subtype and
specifier are compatible with the DescriptorDataRange.
DescriptorDataRange -
Contains a pointer to one of the data ranges from the pin descriptor
for the pin in question. The format type, subtype and specifier are
compatible with the CallerDataRange.
BufferSize -
Contains the size in bytes of the buffer pointed to by the Data
argument. For size queries, this value will be zero.
Data -
Optionally contains a pointer to the buffer to contain the data
format structure representing the best format in the intersection
of the two data ranges. For size queries, this pointer will be
NULL.
DataSize -
Contains a pointer to the location at which to deposit the size
of the data format. This information is supplied by the function
when the format is actually delivered and in response to size
queries.
Return Value:
STATUS_SUCCESS if there is an intersection and it fits in the supplied
buffer, STATUS_BUFFER_OVERFLOW for successful size queries,
STATUS_NO_MATCH if the intersection is empty, or
STATUS_BUFFER_TOO_SMALL if the supplied buffer is too small.
--*/
{
PAGED_CODE();
const GUID VideoInfoSpecifier =
{STATICGUIDOF(KSDATAFORMAT_SPECIFIER_VIDEOINFO)};
ASSERT(Filter);
ASSERT(Irp);
ASSERT(PinInstance);
ASSERT(CallerDataRange);
ASSERT(DescriptorDataRange);
ASSERT(DataSize);
ULONG DataFormatSize;
//
// Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
//
if (IsEqualGUID(CallerDataRange->Specifier, VideoInfoSpecifier) &&
CallerDataRange->FormatSize >= sizeof (KS_DATARANGE_VIDEO)) {
PKS_DATARANGE_VIDEO callerDataRange =
reinterpret_cast <PKS_DATARANGE_VIDEO> (CallerDataRange);
PKS_DATARANGE_VIDEO descriptorDataRange =
reinterpret_cast <PKS_DATARANGE_VIDEO> (DescriptorDataRange);
PKS_DATAFORMAT_VIDEOINFOHEADER FormatVideoInfoHeader;
//
// Check that the other fields match
//
if ((callerDataRange->bFixedSizeSamples !=
descriptorDataRange->bFixedSizeSamples) ||
(callerDataRange->bTemporalCompression !=
descriptorDataRange->bTemporalCompression) ||
(callerDataRange->StreamDescriptionFlags !=
descriptorDataRange->StreamDescriptionFlags) ||
(callerDataRange->MemoryAllocationFlags !=
descriptorDataRange->MemoryAllocationFlags) ||
(RtlCompareMemory (&callerDataRange->ConfigCaps,
&descriptorDataRange->ConfigCaps,
sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) !=
sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)))
{
return STATUS_NO_MATCH;
}
//
// KS_SIZE_VIDEOHEADER() below is relying on bmiHeader.biSize from
// the caller's data range. This **MUST** be validated; the
// extended bmiHeader size (biSize) must not extend past the end
// of the range buffer. Possible arithmetic overflow is also
// checked for.
//
{
ULONG VideoHeaderSize = KS_SIZE_VIDEOHEADER (
&callerDataRange->VideoInfoHeader
);
ULONG DataRangeSize =
FIELD_OFFSET (KS_DATARANGE_VIDEO, VideoInfoHeader) +
VideoHeaderSize;
//
// Check that biSize does not extend past the buffer. The
// first two checks are for arithmetic overflow on the
// operations to compute the alleged size. (On unsigned
// math, a+b < a iff an arithmetic overflow occurred).
//
if (
VideoHeaderSize < callerDataRange->
VideoInfoHeader.bmiHeader.biSize ||
DataRangeSize < VideoHeaderSize ||
DataRangeSize > callerDataRange -> DataRange.FormatSize
) {
return STATUS_INVALID_PARAMETER;
}
}
DataFormatSize =
sizeof (KSDATAFORMAT) +
KS_SIZE_VIDEOHEADER (&callerDataRange->VideoInfoHeader);
//
// If the passed buffer size is 0, it indicates that this is a size
// only query. Return the size of the intersecting data format and
// pass back STATUS_BUFFER_OVERFLOW.
//
if (BufferSize == 0) {
*DataSize = DataFormatSize;
return STATUS_BUFFER_OVERFLOW;
}
//
// Verify that the provided structure is large enough to
// accept the result.
//
if (BufferSize < DataFormatSize)
{
return STATUS_BUFFER_TOO_SMALL;
}
//
// Copy over the KSDATAFORMAT, followed by the actual VideoInfoHeader
//
*DataSize = DataFormatSize;
FormatVideoInfoHeader = PKS_DATAFORMAT_VIDEOINFOHEADER( Data );
//
// Copy over the KSDATAFORMAT. This is precisely the same as the
// KSDATARANGE (it's just the GUIDs, etc... not the format information
// following any data format.
//
RtlCopyMemory (
&FormatVideoInfoHeader->DataFormat,
DescriptorDataRange,
sizeof (KSDATAFORMAT));
FormatVideoInfoHeader->DataFormat.FormatSize = DataFormatSize;
//
// Copy over the callers requested VIDEOINFOHEADER
//
RtlCopyMemory (
&FormatVideoInfoHeader->VideoInfoHeader,
&callerDataRange->VideoInfoHeader,
KS_SIZE_VIDEOHEADER (&callerDataRange->VideoInfoHeader)
);
//
// Calculate biSizeImage for this request, and put the result in both
// the biSizeImage field of the bmiHeader AND in the SampleSize field
// of the DataFormat.
//
// Note that for compressed sizes, this calculation will probably not
// be just width * height * bitdepth
//
FormatVideoInfoHeader->VideoInfoHeader.bmiHeader.biSizeImage =
FormatVideoInfoHeader->DataFormat.SampleSize =
KS_DIBSIZE (FormatVideoInfoHeader->VideoInfoHeader.bmiHeader);
//
// REVIEW - Perform other validation such as cropping and scaling checks
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -