⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 capture.cpp

📁 实现avstream流的驱动程序
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    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
        // 
        
        return STATUS_SUCCESS;
        
    } // End of VIDEOINFOHEADER specifier
    
    return STATUS_NO_MATCH;
}

/*************************************************/

BOOL
MultiplyCheckOverflow (
    ULONG a,
    ULONG b,
    ULONG *pab
    )

/*++

Routine Description:

    Perform a 32 bit unsigned multiplication and check for arithmetic overflow.

Arguments:

    a -
        First operand

    b -
        Second operand

    pab -
        Result

Return Value:

    TRUE -
        no overflow

    FALSE -
        overflow occurred

--*/

{

    *pab = a * b;
    if ((a == 0) || (((*pab) / a) == b)) {
        return TRUE;
    }
    return FALSE;
}

/*************************************************/


NTSTATUS
CCapturePin::
DispatchSetFormat (
    IN PKSPIN Pin,
    IN PKSDATAFORMAT OldFormat OPTIONAL,
    IN PKSMULTIPLE_ITEM OldAttributeList OPTIONAL,
    IN const KSDATARANGE *DataRange,
    IN const KSATTRIBUTE_LIST *AttributeRange OPTIONAL
    )

/*++

Routine Description:

    This is the set data format dispatch for the capture pin.  It is called
    in two circumstances.

        1: before Pin's creation dispatch has been made to verify that
           Pin -> ConnectionFormat is an acceptable format for the range
           DataRange.  In this case OldFormat is NULL.

        2: after Pin's creation dispatch has been made and an initial format
           selected in order to change the format for the pin.  In this case,
           OldFormat will not be NULL.

    Validate that the format is acceptible and perform the actions necessary
    to change format if appropriate.

Arguments:

    Pin -
        The pin this format is being set on.  The format itself will be in
        Pin -> ConnectionFormat.

    OldFormat -
        The previous format used on this pin.  If this is NULL, it is an
        indication that Pin's creation dispatch has not yet been made and
        that this is a request to validate the initial format and not to
        change formats.

    OldAttributeList -
        The old attribute list for the prior format

    DataRange -
        A range out of our list of data ranges which was determined to be
        at least a partial match for Pin -> ConnectionFormat.  If the format
        there is unacceptable for the range, STATUS_NO_MATCH should be
        returned.

    AttributeRange -
        The attribute range

Return Value:

    Success / Failure

        STATUS_SUCCESS -
            The format is acceptable / the format has been changed

        STATUS_NO_MATCH -
            The format is not-acceptable / the format has not been changed

--*/

{

    PAGED_CODE();

    NTSTATUS Status = STATUS_NO_MATCH;

    const GUID VideoInfoSpecifier = 
        {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_VIDEOINFO)};

    CCapturePin *CapPin = NULL;

    //
    // Find the pin, if it exists yet.  OldFormat will be an indication of 
    // this.  If we're changing formats, OldFormat will be non-NULL.
    //
    // You cannot use Pin -> Context to make the determination.  AVStream
    // preinitializes this to the filter's context.
    //
    if (OldFormat) {
        CapPin = reinterpret_cast <CCapturePin *> (Pin -> Context);
    }

    if (IsEqualGUID (Pin -> ConnectionFormat -> Specifier,
            VideoInfoSpecifier) &&
        Pin -> ConnectionFormat -> FormatSize >=
            sizeof (KS_DATAFORMAT_VIDEOINFOHEADER)) {

        PKS_DATAFORMAT_VIDEOINFOHEADER ConnectionFormat =
            reinterpret_cast <PKS_DATAFORMAT_VIDEOINFOHEADER> 
                (Pin -> ConnectionFormat);

        //
        // DataRange comes out of OUR data range list.  I know the range
        // is valid as such.
        //
        const KS_DATARANGE_VIDEO *VIRange =
            reinterpret_cast <const KS_DATARANGE_VIDEO *>
                (DataRange);

        //
        // Check that bmiHeader.biSize is valid since we use it later.
        //
        ULONG VideoHeaderSize = KS_SIZE_VIDEOHEADER (
            &ConnectionFormat -> VideoInfoHeader
            );

        ULONG DataFormatSize = FIELD_OFFSET (
            KS_DATAFORMAT_VIDEOINFOHEADER, VideoInfoHeader
            ) + VideoHeaderSize;

        if (
            VideoHeaderSize < ConnectionFormat->
                VideoInfoHeader.bmiHeader.biSize ||
            DataFormatSize < VideoHeaderSize ||
            DataFormatSize > ConnectionFormat -> DataFormat.FormatSize
            ) {

            Status = STATUS_INVALID_PARAMETER;

        }

        //
        // Check that the format is a match for the selected range. 
        //
        else if (
            (ConnectionFormat -> VideoInfoHeader.bmiHeader.biWidth !=
                VIRange -> VideoInfoHeader.bmiHeader.biWidth) ||

            (ConnectionFormat -> VideoInfoHeader.bmiHeader.biHeight !=
                VIRange -> VideoInfoHeader.bmiHeader.biHeight) ||

            (ConnectionFormat -> VideoInfoHeader.bmiHeader.biCompression !=
                VIRange -> VideoInfoHeader.bmiHeader.biCompression) 

            ) {

            Status = STATUS_NO_MATCH;

        } else {

            //
            // Compute the minimum size of our buffers to validate against.
            // The image synthesis routines synthesize |biHeight| rows of
            // biWidth pixels in either RGB24 or UYVY.  In order to ensure
            // safe synthesis into the buffer, we need to know how large an
            // image this will produce.
            //
            // I do this explicitly because of the method that the data is
            // synthesized.  A variation of this may or may not be necessary
            // depending on the mechanism the driver in question fills the 
            // capture buffers.  The important thing is to ensure that they
            // aren't overrun during capture.
            //
            ULONG ImageSize;

            if (!MultiplyCheckOverflow (
                (ULONG)ConnectionFormat->VideoInfoHeader.bmiHeader.biWidth,
                (ULONG)abs (ConnectionFormat->
                    VideoInfoHeader.bmiHeader.biHeight),
                &ImageSize
                )) {

                Status = STATUS_INVALID_PARAMETER;
            }

            //
            // We only support KS_BI_RGB (24) and KS_BI_YUV422 (16), so
            // this is valid for those formats.
            //
            else if (!MultiplyCheckOverflow (
                ImageSize,
                (ULONG)(ConnectionFormat->
                    VideoInfoHeader.bmiHeader.biBitCount / 8),
                &ImageSize
                )) {

                Status = STATUS_INVALID_PARAMETER;

            }

            //
            // Valid for the formats we use.  Otherwise, this would be
            // checked later.
            //
            else if (ConnectionFormat->VideoInfoHeader.bmiHeader.biSizeImage <
                    ImageSize) {

                Status = STATUS_INVALID_PARAMETER;

            } else {

                //
                // We can accept the format. 
                //
                Status = STATUS_SUCCESS;

                //
                // OldFormat is an indication that this is a format change.  
                // Since I do not implement the 
                // KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT, by default, I do 
                // not handle dynamic format changes.
                //
                // If something changes while we're in the stop state, we're 
                // fine to handle it since we haven't "configured the hardware"
                // yet.
                //

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -