📄 basepin.cpp
字号:
/*+++ *******************************************************************\
*
* Copyright and Disclaimer:
*
* ---------------------------------------------------------------
* This software is provided "AS IS" without warranty of any kind,
* either expressed or implied, including but not limited to the
* implied warranties of noninfringement, merchantability and/or
* fitness for a particular purpose.
* ---------------------------------------------------------------
*
* Copyright (c) 2008 Conexant Systems, Inc.
* All rights reserved.
*
\******************************************************************* ---*/
#include "BasePin.h"
#include "Device.h"
#include "cpprt.h"
#include "debug.h"
BasePin::BasePin(PKSPIN p_ks_pin):
_picture_num(0),
_dropped_cnt(0),
_p_ks_pin(p_ks_pin),
_p_device(NULL),
_p_clock(NULL),
_discontinuity(FALSE),
_frame_size(0),
_duration(0)
{
}
BasePin::~BasePin()
{
if(_p_ks_pin->ClientState != KSSTATE_STOP)
{
DbgLogError(("BasePin: ~BasePin: client state is not set to STOP yet..\n"));
}
if(_p_clock)
{
_p_clock->Release();
_p_clock = NULL;
}
//Make sure we aren't holding resources
if(_p_device)
{
_p_device->releaseResources(this);
_p_device = NULL;
}
}
NTSTATUS BasePin::dispatchClose(PKSPIN p_ks_pin, PIRP p_irp)
{
delete reinterpret_cast<BasePin*>(p_ks_pin->Context);
p_ks_pin->Context = NULL;
return STATUS_SUCCESS;
}
NTSTATUS BasePin::dispatchProcess(PKSPIN p_ks_pin)
{
return STATUS_PENDING;
}
NTSTATUS BasePin::dispatchSetState(
PKSPIN p_ks_pin,
KSSTATE to_state,
KSSTATE from_state)
{
return (reinterpret_cast<BasePin*>(p_ks_pin->Context))->
setState(to_state, from_state);
}
NTSTATUS BasePin::getDroppedFrames(
PIRP p_irp,
PKSPROPERTY p_in,
PKSPROPERTY_DROPPEDFRAMES_CURRENT_S p_out)
{
PKSPIN p_ks_pin = KsGetPinFromIrp(p_irp);
if(p_ks_pin)
{
BasePin* p_pin = (BasePin*)p_ks_pin->Context;
p_out->PictureNumber = p_pin->_picture_num;
p_out->DropCount = p_pin->_dropped_cnt;
p_out->AverageFrameSize = p_pin->_frame_size;
return STATUS_SUCCESS;
}
else
return STATUS_UNSUCCESSFUL;
}
NTSTATUS BasePin::init(
ULONG frames_to_cycle,
ULONG frame_size,
LONGLONG duration)
{
_frame_size = frame_size;
_duration = duration;
PKSDEVICE p_ks_dev = KsPinGetDevice(_p_ks_pin);
_p_device = static_cast<Device*>(p_ks_dev->Context);
// We need to KsEdit the descriptor to ensure we don't mess up
// any other pins using the descriptor or touch read-only memory.
NTSTATUS status = KsEdit( _p_ks_pin, &_p_ks_pin->Descriptor, 'TXNC');
if(NT_SUCCESS(status))
{
status = KsEdit(
_p_ks_pin,
&_p_ks_pin->Descriptor->AllocatorFraming,
'TXNC');
}
// If the KsEdits proceeded without running out of memory,
// adjust the framing based on the video info header.
if(NT_SUCCESS(status))
{
// It is safe to cast away constness as
// long as the KsEdit succeeded.
KSALLOCATOR_FRAMING_EX *p_framing =
const_cast<KSALLOCATOR_FRAMING_EX*>
( _p_ks_pin->Descriptor->AllocatorFraming );
// Indicate how many frames we what to cycle through.
p_framing->FramingItem[0].Frames = frames_to_cycle;
// We only support one frame size, the size of each capture image.
p_framing->FramingItem[0].PhysicalRange.MinFrameSize =
p_framing->FramingItem[0].PhysicalRange.MaxFrameSize =
p_framing->FramingItem[0].FramingRange.Range.MinFrameSize =
p_framing->FramingItem[0].FramingRange.Range.MaxFrameSize =
_frame_size;
p_framing->FramingItem[0].PhysicalRange.Stepping =
p_framing->FramingItem[0].FramingRange.Range.Stepping = 0;
//make a different to video render, that will lead color convert insert auto
p_framing->FramingItem[0].MemoryFlags = KSALLOCATOR_REQUIREMENTF_MUST_ALLOCATE;
}
return status;
}
VOID BasePin::timeStamp(
PKSSTREAM_HEADER p_strm_hdr,
LONGLONG time,
BOOLEAN time_is_valid,
FIELD_TYPE field_type)
{
p_strm_hdr->Duration = _duration;
p_strm_hdr->PresentationTime.Numerator = 1;
p_strm_hdr->PresentationTime.Denominator = 1;
p_strm_hdr->PresentationTime.Time = time_is_valid ? time : 0;
p_strm_hdr->OptionsFlags = 0;
p_strm_hdr->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
if( time_is_valid )
p_strm_hdr->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
if( _discontinuity )
{
p_strm_hdr->OptionsFlags |=
KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY;
_discontinuity = false;
}
// Call into derived calls to set the frame info members.
fillFrameInfo(p_strm_hdr, field_type);
}
//////////////////////////////////////////////////////////////////////////////////
//AudioPin::getNextBuffer
//
// This function is called by the RiscEngine class when it is ready to add a
// program for a buffer.
//
// This function always returns a pointer to the next buffer in the queue.
//
// A note on AVStream buffering:
// In order to DMA to a buffer, the buffer needs to have a least one locked
// pointer pointing to it. The leading edge pointer may be acquired in a locked
// state, but it will be unlocked as soon as the pointer is advanced. So, in
// order to maintain several buffers in a locked state for the RISC engine, we
// need to create clone pointers, and keep them locked until the RISC engine
// finishes processing the buffer. AVStream pins already have a queue for clone
// pointers that allows accessing the pointers in the same order in which they
// were cloned. When the RISC engine completes a buffer, it calls onBufferComplete.
// this will then timestamp the buffer, unlock it and delete the clone pointer.
// Buffers must be completed in the same order they were retreived by calling this
// function.
//
PKSSTREAM_POINTER BasePin::getNextBuffer()
{
if (!_p_ks_pin||_p_ks_pin->ClientState != KSSTATE_RUN)
{
return NULL;
}
//Get the leading edge buffer pointer.
PKSSTREAM_POINTER p_leading_edge = KsPinGetLeadingEdgeStreamPointer(
_p_ks_pin,
KSSTREAM_POINTER_STATE_LOCKED);
if(!p_leading_edge)
{
return NULL;
}
//Create a clone of the leading edge pointer
//We need to create a clone of every pointer we are using so that the
// pointer will remain locked after we advance the leading edge pointer.
// We don't need to save the clone pointer. AVStream does that for us.
PKSSTREAM_POINTER p_clone = NULL;
NTSTATUS status = KsStreamPointerClone(
p_leading_edge,
NULL, //For now, clones aren't cancelable.
0, //No context
&p_clone);
//Unlock the leading edge pointer. The clone is still in locked status
KsStreamPointerUnlock(p_leading_edge, FALSE);
//If we failed to create the clone, return
if(!NT_SUCCESS(status))
{
return NULL;
}
//Advance the leading edge pointer so it points to the next buffer for next time.
//(Always succeeds when the pointer is not locked)
KsStreamPointerAdvance(p_leading_edge);
return p_clone;
}
VOID BasePin::onBufferComplete(FIELD_TYPE field_type)
{
//Get the first clone pointer.
PKSSTREAM_POINTER p_clone = KsPinGetFirstCloneStreamPointer(_p_ks_pin);
if(!p_clone)
{
//No buffer was available to complete.
return;
}
LONGLONG system_time;
timeStamp(
p_clone->StreamHeader,
_p_clock ? _p_clock->GetCorrelatedTime(&system_time) : 0,
_p_clock ? true : false,
field_type);
processCompletedBuffer(p_clone);
//Unlock the clone pointer
KsStreamPointerUnlock(p_clone, FALSE);
//Delete the clone pointer
KsStreamPointerDelete(p_clone);
}
VOID BasePin::releaseClones()
{
PKSSTREAM_POINTER p_next_clone = NULL;
PKSSTREAM_POINTER p_clone = KsPinGetFirstCloneStreamPointer(_p_ks_pin);
// Walk through the clones, deleting them, and setting
// DataUsed to zero since we didn't dma any data.
while(p_clone)
{
// Free the memory allocated by createRiscProg()
p_clone->Context = NULL;
p_next_clone = KsStreamPointerGetNextClone( p_clone );
p_clone->StreamHeader->DataUsed = 0;
KsStreamPointerDelete( p_clone );
p_clone = p_next_clone;
}
}
NTSTATUS BasePin::setState(KSSTATE to_state, KSSTATE from_state)
{
NTSTATUS status = STATUS_SUCCESS;
switch(to_state)
{
case KSSTATE_STOP:
status = _p_device->stop(this);
_p_device->releaseResources(this);
releaseClones();
if( _p_clock )
{
_p_clock->Release();
_p_clock = NULL;
}
break;
case KSSTATE_ACQUIRE:
// We should only acquire hardware resources here, not at
// pin create time. This means we do not fail creation
// of a pin because of limited hardware resources.
if(!_p_device->acquireResources(this))
{
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
if( from_state == KSSTATE_STOP )
{
if( NT_SUCCESS( status ) )
{
KsPinGetReferenceClockInterface(_p_ks_pin, &_p_clock);
}
//We are supposed to reset the picture count when transitioning from stop to run
// (If we do it when transitioning between pause and run,
// we get a direct x assertion failure)
resetCounters();
}
break;
case KSSTATE_PAUSE:
if( from_state == KSSTATE_RUN )
{
status = _p_device->stop(this);
releaseClones();
}
break;
case KSSTATE_RUN:
_discontinuity = TRUE;
start();
//We'll fail to start only if we did not acquire the resources
status = _p_device->start(this);
break;
}
return status;
}
VOID BasePin::resetCounters()
{
_picture_num = 0;
_dropped_cnt = 0;
_discontinuity = FALSE;
}
VOID BasePin::droppedFrame()
{
_picture_num++;
_dropped_cnt++;
_discontinuity = TRUE;
}
DECLARE_SIMPLE_FRAMING_EX
(
PIN_ALLOCATOR_FRAMING,
STATICGUIDOF( KSMEMORY_TYPE_KERNEL_NONPAGED ),
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY,
2,
0,
2 * PAGE_SIZE,
2 * PAGE_SIZE
);
const
KSPROPERTY_ITEM
PIN_DROPPED_FRAMES_PROPERTIES[] =
{
DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_DROPPEDFRAMES_CURRENT,
BasePin::getDroppedFrames, // GetSupported or Handler
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),// MinProperty
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),// MinData
NULL, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
0 // SerializedSize
)
};
const
KSPROPERTY_SET
PIN_PROPERTIES[] =
{
DEFINE_KSPROPERTY_SET
(
&PROPSETID_VIDCAP_DROPPEDFRAMES, // Set
SIZEOF_ARRAY( PIN_DROPPED_FRAMES_PROPERTIES ),// PropertiesCount
PIN_DROPPED_FRAMES_PROPERTIES, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
)
};
const
KSAUTOMATION_TABLE
PIN_AUTOMATION_TABLE =
{
DEFINE_KSAUTOMATION_PROPERTIES( PIN_PROPERTIES ),
DEFINE_KSAUTOMATION_METHODS_NULL,
DEFINE_KSAUTOMATION_EVENTS_NULL
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -