diff options
| author | karlf <[email protected]> | 2016-08-11 13:28:13 -0700 |
|---|---|---|
| committer | karlf <[email protected]> | 2016-08-11 13:28:13 -0700 |
| commit | 96eb96dfb613e4c745db6bd1f53a92fe7e2290fc (patch) | |
| tree | ad5f3ede5cbcd6b598677ce41bcf8318471bdd92 /AVStream/avscamera/sys/Sensor.cpp | |
| parent | 687b274aa38fd05c8c26e3068932121876d7f745 (diff) | |
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'AVStream/avscamera/sys/Sensor.cpp')
| -rw-r--r-- | AVStream/avscamera/sys/Sensor.cpp | 1365 |
1 files changed, 1365 insertions, 0 deletions
diff --git a/AVStream/avscamera/sys/Sensor.cpp b/AVStream/avscamera/sys/Sensor.cpp new file mode 100644 index 00000000..cb310dcc --- /dev/null +++ b/AVStream/avscamera/sys/Sensor.cpp @@ -0,0 +1,1365 @@ +/************************************************************************** + + A/V Stream Camera Sample + + Copyright (c) 2014, Microsoft Corporation. + + File: + + Sensor.cpp + + Abstract: + + Base Sensor class implementation. + + This class also controls access to the pin simulations. Most cameras + have a limited set of ISP resources and can only instantiate a fixed + number of pins. This class grants access to those resources. + + History: + + created 5/5/2014 + +**************************************************************************/ + +#include "Common.h" + +/************************************************************************** + + PAGEABLE CODE + +**************************************************************************/ + +#ifdef ALLOC_PRAGMA +#pragma code_seg("PAGE") +#endif // ALLOC_PRAGMA + + +CSensor::CSensor( + _In_ CCaptureDevice *Device, + _In_ ULONG PinCount +) + : m_Device(Device) + , m_PinCount(PinCount) + , m_HardwareSimulation(nullptr) + , m_Synthesizer(nullptr) + , m_CapturePin(nullptr) + , m_VideoInfoHeader(nullptr) + , m_InterruptTime(nullptr) + , m_LastMappingsCompleted(nullptr) + , m_PreviewMask(INVALID_PIN_MASK) + , m_StillMask(INVALID_PIN_MASK) + , m_VideoMask(INVALID_PIN_MASK) + , m_FilterInstanceCount(0) + , m_pIspSettings(nullptr) + , m_PfsFrameLimit(0) + , m_PfsLoopLimit(0) + , m_MountingOrientation(AcpiPldRotation0) +{ + PAGED_CODE(); + NT_ASSERT(Device); + NT_ASSERT(PinCount); +} + + +CSensor::~CSensor() +{ + PAGED_CODE(); + for(ULONG i=0; i < m_PinCount; i++) + { + if( m_HardwareSimulation) + { + SAFE_DELETE( m_HardwareSimulation[i] ); + } + if( m_Synthesizer ) + { + SAFE_DELETE( m_Synthesizer[i] ); + } + if( m_CapturePin ) + { + m_CapturePin[i] = nullptr; + } + if( m_VideoInfoHeader ) + { + SAFE_DELETE( m_VideoInfoHeader[i] ); + } + } + + SAFE_DELETE_ARRAY( m_pIspSettings ); + SAFE_DELETE_ARRAY( m_HardwareSimulation ); + SAFE_DELETE_ARRAY( m_Synthesizer ); + SAFE_DELETE_ARRAY( m_CapturePin ); + SAFE_DELETE_ARRAY( m_VideoInfoHeader ); + SAFE_DELETE_ARRAY( m_InterruptTime ); + SAFE_DELETE_ARRAY( m_LastMappingsCompleted); +} + + +NTSTATUS +CSensor:: +AddFilter(PKSFILTER pFilter) +{ + PAGED_CODE(); + + // If your sensor object needs to keep track of the Filters that are + // attached to it, you would do that here. We only want to keep an + // outstanding filter count so we know when to reset our defaults. + UNREFERENCED_PARAMETER(pFilter); + + LONG Count = IncrementFilterCount(); + NTSTATUS Status= STATUS_SUCCESS; + + // If this is the first filter, reprogram the sensor. + if( Count==1 ) + { + Status = ProgramDefaults(); + if( !NT_SUCCESS(Status) ) + { + Count = DecrementFilterCount(); + } + } + DBG_LEAVE("(Count=%d)=0x%08X", Count, Status); + return Status; +} + +NTSTATUS +CSensor:: +RemoveFilter(PKSFILTER pFilter) +{ + PAGED_CODE(); + + // If your sensor object needs to keep track of the Filters that are + // attached to it, you would clean up here. We only want to keep an + // outstanding filter count so we know when to reset our defaults. + UNREFERENCED_PARAMETER(pFilter); + + LONG Count = DecrementFilterCount(); + NT_ASSERT( Count>=0 ); + + NTSTATUS Status = Count>=0 ? STATUS_SUCCESS : STATUS_INVALID_DEVICE_STATE; + + DBG_LEAVE("(Count=%d)=0x%08X", Count, Status); + return Status; +} + +NTSTATUS +CSensor:: +ProgramDefaults() +{ + PAGED_CODE(); + return STATUS_SUCCESS; +} + +NTSTATUS +CSensor:: +Initialize() +{ + PAGED_CODE(); + + m_HardwareSimulation = new (NonPagedPoolNx, 'sneS') CHardwareSimulation *[m_PinCount]; + m_Synthesizer = new (NonPagedPoolNx, 'sneS') CSynthesizer *[m_PinCount]; + m_CapturePin = new (NonPagedPoolNx, 'sneS') ICapturePin *[m_PinCount]; + m_VideoInfoHeader = new (NonPagedPoolNx, 'sneS') PKS_VIDEOINFOHEADER[m_PinCount]; + m_InterruptTime = new (NonPagedPoolNx, 'sneS') ULONG[m_PinCount]; + m_LastMappingsCompleted = new (NonPagedPoolNx, 'sneS') ULONG[m_PinCount]; + + if( !m_HardwareSimulation || + !m_Synthesizer || + !m_CapturePin || + !m_VideoInfoHeader || + !m_InterruptTime || + !m_LastMappingsCompleted ) + { + SAFE_DELETE_ARRAY( m_HardwareSimulation ); + SAFE_DELETE_ARRAY( m_Synthesizer ); + SAFE_DELETE_ARRAY( m_CapturePin ); + SAFE_DELETE_ARRAY( m_VideoInfoHeader ); + SAFE_DELETE_ARRAY( m_InterruptTime ); + SAFE_DELETE_ARRAY( m_LastMappingsCompleted); + return STATUS_INSUFFICIENT_RESOURCES; + } + + for(ULONG i=0; i<m_PinCount; i++) + { + m_HardwareSimulation[i] = nullptr; + m_Synthesizer[i] = nullptr; + m_CapturePin[i] = nullptr; + m_VideoInfoHeader[i] = nullptr; + m_InterruptTime[i] = 0; + m_LastMappingsCompleted[i] = 0; + } + return STATUS_SUCCESS; +} + +void +CSensor:: +Interrupt( + _In_ LONG PinIndex +) + +/*++ + +Routine Description: + + This is the "faked" interrupt service routine for this device. It + is called at dispatch level by the hardware simulation. + +Arguments: + + PinIndex - + +Return Value: + + None + +--*/ +{ + PAGED_CODE(); + + if( IsValidIndex((ULONG)PinIndex) ) + { + DBG_ENTER("(PinIndex=%d): m_LastMappingsCompleted[%d]=%d", PinIndex, + PinIndex, m_LastMappingsCompleted[PinIndex]); + + m_InterruptTime[PinIndex]++; + + // + // Realistically, we'd do some hardware manipulation here and then queue + // a DPC. Since this is fake hardware, we do what's necessary here. This + // is pretty much what the DPC would look like short of the access + // of hardware registers (ReadNumberOfMappingsCompleted) which would likely + // be done in the ISR. + // + ULONG LastMappingCompleted = m_LastMappingsCompleted[PinIndex]; + if( !IsStillIndex(PinIndex) ) + { + while( LastMappingCompleted < + m_HardwareSimulation[PinIndex]->ReadNumberOfMappingsCompleted() ) + { + // Complete a frame. + if( !NT_SUCCESS(m_CapturePin[PinIndex]->CompleteMapping()) ) + { + break; + } + LastMappingCompleted++; + } + } + else + { + CImageHardwareSimulation *pImageHw = (CImageHardwareSimulation *) m_HardwareSimulation[PinIndex]; + PKSSTREAM_POINTER pClone = pImageHw->m_pClone; + + // Just make sure the image pin actually generate a frame. + if( pClone ) + { + // Emit a photo confirmation image (we don't send off a copy of this image), + // but only if we need one for this photo and if the timestamp is valid. + if( pImageHw->m_PhotoConfirmationInfo.isRequired() && + (pClone->StreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID) ) + { + // Generate a photo confirmation on any running preview pins. + for( ULONG Index=0; IsValidIndex(Index); Index++ ) + { + if( IsPreviewIndex(Index) ) + { + m_HardwareSimulation[Index]-> + GeneratePhotoConfirmation( + pImageHw->m_PhotoConfirmationInfo.getIndex(), + pImageHw->m_PhotoConfirmationInfo.getTime() + ); + } + } + } + + // + // Inform the capture pin that a given number of scatter / gather + // mappings have completed. + // + if( NT_SUCCESS(m_CapturePin[PinIndex]->CompleteMapping(pClone)) ) + { + LastMappingCompleted++; + } + + pImageHw->m_pClone = NULL; + } + pImageHw->m_PhotoConfirmationInfo = PHOTOCONFIRMATION_INFO(); + } + + m_LastMappingsCompleted[PinIndex] = LastMappingCompleted; + DBG_LEAVE("(PinIndex=%d): LastMappingCompleted=%d", PinIndex, LastMappingCompleted); + } +} + + +NTSTATUS +CSensor:: +CreateSynthesizer( + _In_ PKSPIN Pin, + _In_ PKS_VIDEOINFOHEADER VideoInfoHeader + ) +// +// Create the necessary type of image synthesizer. +// +{ + NTSTATUS Status = STATUS_SUCCESS; + LONG Width = VideoInfoHeader->bmiHeader.biWidth; + LONG Height = VideoInfoHeader->bmiHeader.biHeight; + + if( VideoInfoHeader->bmiHeader.biBitCount == 24 && + VideoInfoHeader->bmiHeader.biCompression == KS_BI_RGB ) + { + // + // If we're RGB24, create a new RGB24 synth. RGB24 surfaces + // can be in either orientation. The origin is lower left if + // height < 0. Otherwise, it's upper left. + // + m_Synthesizer[ Pin->Id ] = new (NonPagedPoolNx, 'RysI') + CRGB24Synthesizer( Width, Height ); + DBG_TRACE( "Creating CRGB24Synthesizer..." ); + } + else if( VideoInfoHeader->bmiHeader.biBitCount == 32 && + VideoInfoHeader->bmiHeader.biCompression == KS_BI_RGB ) + { + // + // If we're RGB32, create a new RGB32 synth. RGB32 surfaces + // can be in either orientation. The origin is lower left if + // height < 0. Otherwise, it's upper left. + // + m_Synthesizer[ Pin->Id ] = new (NonPagedPoolNx, '23RI') + CXRGBSynthesizer( Width, Height ); + DBG_TRACE( "Creating CXRGBSynthesizer..." ); + } + else if( VideoInfoHeader->bmiHeader.biBitCount == 16 && + (VideoInfoHeader->bmiHeader.biCompression == FOURCC_YUY2) ) + { + // + // If we're YUY2, create the YUY2 synth. + // + m_Synthesizer[ Pin->Id ] = new(NonPagedPoolNx, 'YysI') CYUY2Synthesizer( Width, Height ); + DBG_TRACE( "Creating CYUY2Synthesizer..." ); + + } + else if( VideoInfoHeader->bmiHeader.biBitCount == 12 && + (VideoInfoHeader->bmiHeader.biCompression == FOURCC_NV12) ) + { + + m_Synthesizer[ Pin->Id ] = new(NonPagedPoolNx, 'Nv12') CNV12Synthesizer( Width, Height ); + DBG_TRACE( "Creating CNV12Synthesizer..." ); + + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + + if( NT_SUCCESS( Status ) ) + { + DBG_TRACE( "Setting Mounting Orientation to %d�", DbgRotation2Degrees(m_MountingOrientation) ) + m_Synthesizer[ Pin->Id ]->SetRotation( m_MountingOrientation ); + } + + return Status; +} + +NTSTATUS +CSensor:: +AcquireHardwareResources( + _In_ PKSPIN Pin, + _In_ ICapturePin *CapturePin, + _In_ PKS_VIDEOINFOHEADER VideoInfoHeader, + _Out_ CHardwareSimulation **pSim +) + +/*++ + +Routine Description: + + Acquire hardware resources for the capture hardware. If the + resources are already acquired, this will return an error. + The hardware configuration must be passed as a VideoInfoHeader. + +Arguments: + + Pin - + The pin to acquire. + + CapturePin - + The capture pin attempting to acquire resources. When scatter / + gather mappings are completed, the capture pin specified here is + what is notified of the completions. + + VideoInfoHeader - + Information about the capture stream. This **MUST** remain + stable until the caller releases hardware resources. Note + that this could also be guaranteed by bagging it in the device + object bag as well. + + pSim - + A location to store a pointer to the simulation object for this pin. + +Return Value: + + Success / Failure + +--*/ + +{ + PAGED_CODE(); + + DBG_ENTER( "(Pin=%d, CapturePin=%p, VideoInfoHeader=%p)", Pin->Id, CapturePin, VideoInfoHeader ); + + NTSTATUS Status = STATUS_SUCCESS; + LONG lPindex = Pin->Id; + // + // If we're the first pin to go into acquire (remember we can have + // a filter in another graph going simultaneously), grab the resources for Preview + // + if( InterlockedCompareExchangePointer( + (PVOID *) &m_CapturePin[lPindex], + CapturePin, + nullptr) == nullptr) + { + m_VideoInfoHeader[lPindex] = VideoInfoHeader; + + // + // If there's an old hardware simulation sitting around for some + // reason, blow it away. + // + SAFE_DELETE( m_Synthesizer[lPindex] ); + + DBG_TRACE( "biBitCount =%d", VideoInfoHeader->bmiHeader.biBitCount ); + DBG_TRACE( "biWidth =%d", VideoInfoHeader->bmiHeader.biWidth ); + DBG_TRACE( "biHeight =%d", VideoInfoHeader->bmiHeader.biHeight ); + DBG_TRACE( "biCompression=0x%08X", VideoInfoHeader->bmiHeader.biCompression ); + DBG_TRACE( "biCompression='%04s'", (PSTR) &VideoInfoHeader->bmiHeader.biCompression ); + DBG_TRACE( "AvgTimePerFrame=%lld", VideoInfoHeader->AvgTimePerFrame ); + + Status = CreateSynthesizer( Pin, + VideoInfoHeader ); + + if (NT_SUCCESS(Status) && !m_Synthesizer[lPindex]) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS (Status)) + { + // + // If everything has succeeded thus far, set the capture pin. + // + m_CapturePin[lPindex] = CapturePin; + *pSim = m_HardwareSimulation[lPindex]; + + } + else + { + // + // If anything failed in here, we release the resources we've + // acquired. + // + ReleaseHardwareResources(Pin); + } + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + DBG_LEAVE( "(Pin=%d, CapturePin=%p, VideoInfoHeader=%p) = 0x%08X", Pin->Id, CapturePin, VideoInfoHeader, Status ); + + return Status; + +} + +/*************************************************/ + + +NTSTATUS +CSensor:: +Start ( + _In_ PKSPIN Pin +) + +/*++ + +Routine Description: + + Start the capture device based on the video info header we were told + about when resources were acquired. + +Arguments: + + Pin - + The pin to start + +Return Value: + + Success / Failure + +--*/ + +{ + PAGED_CODE(); + + DBG_ENTER( "( Pin=%d )\n", Pin->Id ) ; + + LONG lPindex = Pin->Id; + + m_LastMappingsCompleted[lPindex] = 0; + m_InterruptTime[lPindex] = 0; + + NT_ASSERT( m_VideoInfoHeader[lPindex] != nullptr ); + if( !m_VideoInfoHeader[lPindex] ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + // Ideally we'd do this when the filter is constructed; but the + // simulation is constructed first and these values aren't used until + // we call start. + + if( !IsStillIndex(lPindex) ) + { + return + m_HardwareSimulation[lPindex] -> Start ( + m_Synthesizer[lPindex], + m_VideoInfoHeader[lPindex] -> AvgTimePerFrame, + m_VideoInfoHeader[lPindex] -> bmiHeader.biWidth, + ABS (m_VideoInfoHeader[lPindex] -> bmiHeader.biHeight), + m_VideoInfoHeader[lPindex] -> bmiHeader.biSizeImage + ); + } + else + { + CImageHardwareSimulation *pHwSim = (CImageHardwareSimulation *) m_HardwareSimulation[lPindex] ; + + // The following is necessary if Per-Frame Settings are active. + if( IsVPSActive() ) + { + // Program the simulation with our settings + pHwSim->SetPFS( m_pIspSettings, m_PfsFrameLimit, m_PfsLoopLimit ); + } + else + { + // Clear out any previous settings, if they still exist. + pHwSim->SetPFS(nullptr, 0, 0); + } + + // Init to the default frame rate. + LONGLONG TimePerFrame = m_VideoInfoHeader[lPindex]->AvgTimePerFrame; + DBG_TRACE("Image Pin's AvgTimePerFrame=%lld", TimePerFrame); + + // Query our control for the max frame rate and convert it into a "PERFORMACE TIME". + CExtendedProperty MaxFrameRate; + GetPhotoMaxFrameRate( &MaxFrameRate ); + LARGE_INTEGER PerformanceTime = { MaxFrameRate.m_Value.Value.ratio.LowPart }; + LONGLONG Frequency = MaxFrameRate.m_Value.Value.ratio.HighPart; + + // Handle an user-specified frame-rate override. + if( Frequency != 0 ) + { + DBG_TRACE( "MaxFrameRate = %lld/%lld", PerformanceTime.QuadPart, Frequency ); + + SetPhotoFrameRate( + lPindex, + KSCONVERT_PERFORMANCE_TIME( Frequency, PerformanceTime ) + ); + } + + CExtendedPhotoMode Mode; + GetPhotoMode( &Mode ); + + NTSTATUS status = pHwSim -> Start ( + m_Synthesizer[lPindex], + m_VideoInfoHeader[lPindex] -> bmiHeader.biWidth, + ABS (m_VideoInfoHeader[lPindex] -> bmiHeader.biHeight), + m_VideoInfoHeader[lPindex] -> bmiHeader.biSizeImage, + (Mode.Flags == 0 ? PinNormalMode : PinBurstMode) + ); + + if(NT_SUCCESS(status)) + { + status = pHwSim -> SetClock(Pin); + } + + DBG_LEAVE( "( Pin=%d )=0x%08X\n", Pin->Id, status ); + + return status; + } +} + +/*************************************************/ + + +NTSTATUS +CSensor:: +Pause ( + _In_ PKSPIN Pin, + _In_ BOOLEAN Pausing +) + +/*++ + +Routine Description: + + Pause or unpause the hardware simulation. This is an effective start + or stop without resetting counters and formats. Note that this can + only be called to transition from started -> paused -> started. Calling + this without starting the hardware with Start() does nothing. + +Arguments: + + Pin - + The pin to pause. + + Pausing - + An indicatation of whether we are pausing or unpausing + + TRUE - + Pause the hardware simulation + + FALSE - + Unpause the hardware simulation + +Return Value: + + Success / Failure + +--*/ + +{ + + PAGED_CODE(); + + return + m_HardwareSimulation[Pin->Id]->Pause(Pausing); +} + +/*************************************************/ + + +NTSTATUS +CSensor:: +Stop ( + _In_ PKSPIN Pin +) + +/*++ + +Routine Description: + + Stop the capture device. + +Arguments: + + None + +Return Value: + + Success / Failure + +--*/ + +{ + + PAGED_CODE(); + + LONG lPindex = Pin->Id; + CHardwareSimulation *pHwSim = m_HardwareSimulation[lPindex]; + + if( !pHwSim ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + NTSTATUS Status = pHwSim->Stop(); + + if( IsStillIndex(lPindex) ) + { + // Clear out any previous Per Frame Settings, if they still exist. + ((CImageHardwareSimulation *)pHwSim)->SetPFS(nullptr, 0, 0) ; + } + + return Status; +} + +NTSTATUS +CSensor:: +Reset( + _In_ PKSPIN Pin +) +{ + PAGED_CODE(); + + if( !IsValidIndex( Pin->Id ) ) + { + return STATUS_INVALID_PARAMETER; + } + + if( !IsStillIndex(Pin->Id) ) + { + return STATUS_SUCCESS; + } + + if( !m_HardwareSimulation[Pin->Id] ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + CHardwareSimulation *pHwSim = m_HardwareSimulation[Pin->Id]; + NTSTATUS Status = pHwSim->Reset(); + + m_LastMappingsCompleted[Pin->Id] = pHwSim->ReadNumberOfMappingsCompleted(); + return Status; +} + +//Resets both filter's first PIN +NTSTATUS +CSensor:: +Reset( +) +{ + PAGED_CODE(); + + NTSTATUS Status=STATUS_SUCCESS; + + for( ULONG Index=GetNextStillIndex(); IsValidIndex(Index) && NT_SUCCESS( Status ); Index=GetNextStillIndex(Index) ) + { + if( !m_HardwareSimulation[Index] ) + { + Status = STATUS_INVALID_DEVICE_STATE; + } + else + { + CHardwareSimulation *pHwSim = m_HardwareSimulation[Index]; + + Status = pHwSim->Reset(); + m_LastMappingsCompleted[Index] = pHwSim->ReadNumberOfMappingsCompleted(); + } + } + + for( ULONG i=0; i<m_PinCount; i++ ) + { + DBG_TRACE("m_LastMappingsCompleted[%d] = %d", i, m_LastMappingsCompleted[i] ); + } + return Status; +} + + +NTSTATUS +CSensor:: +Trigger ( + _In_ ULONG PinId, + _In_ LONG mode +) +/*++ + +Routine Description: + + For a photo pin, take a picture or begin or end a photo sequence. + +Arguments: + + PinId - + This must be a photo pin. + + mode - + The trigger mode, ie: normal or start/stop sequence. + +Return Value: + + Success / Failure + +--*/ +{ + + PAGED_CODE(); + + if( !IsStillIndex(PinId) || + !m_HardwareSimulation[PinId] || + m_HardwareSimulation[PinId]->GetState() != PinRunning ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + return + ((CImageHardwareSimulation *)m_HardwareSimulation[PinId])->Trigger(mode); + +} + +LONG +CSensor:: +GetTriggerMode( + _In_ ULONG PinId +) +/*++ + + Routine Description: + + For a photo pin, take a picture or begin or end a photo sequence. + + Arguments: + + PinId - + This must be a photo pin. + + mode - + The trigger mode, ie: normal or start/stop sequence. + + Return Value: + + Success / Failure + +--*/ +{ + + PAGED_CODE(); + + if( !IsStillIndex(PinId) || + !m_HardwareSimulation[PinId] || + m_HardwareSimulation[PinId]->GetState() != PinRunning ) + { + return 0; + } + + return + ((CImageHardwareSimulation *)m_HardwareSimulation[PinId])->GetTriggerMode(); + +} + + +NTSTATUS +CSensor:: +SetPhotoFrameRate( + _In_ ULONG StillIndex, + _In_ ULONGLONG TimePerFrame +) +/*++ + +Routine Description: + + For a photo pin, set the desired frame rate. + +Arguments: + + TimePerFrame - + Time in 100ns between each frame. + +Return Value: + + Success / Failure + +--*/ +{ + PAGED_CODE(); + + // For now, we only handle 1 photo pin. + + if( !IsValidIndex(StillIndex) || + !m_VideoInfoHeader[StillIndex] || + !m_HardwareSimulation[StillIndex] ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + ULONGLONG AvgTimePerFrame = + (ULONGLONG) m_VideoInfoHeader[StillIndex]->AvgTimePerFrame; + + DBG_TRACE( "TimePerFrame=%lld, AvgTimePerFrame=%lld", TimePerFrame, AvgTimePerFrame ); + + // Handle a reset back to the standard frame rate. + if( TimePerFrame == 0 ) + { + TimePerFrame = AvgTimePerFrame; + } + // Handle an user-specified frame-rate override. + else + { + // It is unrealistic to allow a frame rate faster than the rate specified for this format. + TimePerFrame = max( TimePerFrame, AvgTimePerFrame ); + } + + DBG_TRACE( "Setting new TimePerFrame=%lld", TimePerFrame ); + + return + ((CImageHardwareSimulation *) m_HardwareSimulation[StillIndex])->SetPhotoFrameRate( TimePerFrame ); +} + +ULONGLONG +CSensor:: +GetPhotoFrameRate( + _In_ ULONG StillIndex +) +/*++ + +Routine Description: + + Get the desired frame rate for a photo pin. + +Arguments: + + None + +Return Value: + + Time in 100ns between each frame. + +--*/ +{ + PAGED_CODE(); + + if( !IsStillIndex(StillIndex) || + !m_HardwareSimulation[StillIndex] ) + { + NT_ASSERT(FALSE); + return 0; + } + + CImageHardwareSimulation *pSim = (CImageHardwareSimulation *) (m_HardwareSimulation[StillIndex]); + return pSim->GetPhotoFrameRate( ); +} + +NTSTATUS +CSensor:: +SetFlashStatus( + _In_ ULONGLONG ulFlashStatus +) +{ + PAGED_CODE(); + + NTSTATUS Status = STATUS_SUCCESS; + + for( ULONG StillIndex = GetNextStillIndex(); + IsValidIndex( StillIndex ) && NT_SUCCESS(Status); + StillIndex = GetNextStillIndex( StillIndex ) ) + { + if( !m_HardwareSimulation[ StillIndex ] ) + { + NT_ASSERT(FALSE); + return STATUS_INVALID_DEVICE_STATE; + } + Status = ((CImageHardwareSimulation *) m_HardwareSimulation[StillIndex])->SetFlashStatus (ulFlashStatus); + } + + return Status; +} + +/*************************************************/ + + +NTSTATUS +CSensor:: +SetPinMode( + _In_ ULONG StillIndex, + _In_ ULONGLONG Flags, + _In_ ULONG PastBuffers +) +{ + PAGED_CODE(); + + if( !IsStillIndex(StillIndex) || + !m_HardwareSimulation[StillIndex] ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + return + ((CImageHardwareSimulation *) m_HardwareSimulation[StillIndex])-> + SetMode( Flags, PastBuffers ); +} + +NTSTATUS +CSensor:: +GetQPC( + _In_ ULONG StillIndex, + _Out_ PULONGLONG TriggerTime +) +{ + PAGED_CODE(); + + if( !IsStillIndex(StillIndex) || + !m_HardwareSimulation[StillIndex] ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + *TriggerTime = + ((CImageHardwareSimulation *) m_HardwareSimulation[StillIndex])-> + GetTriggerTime(); + + return STATUS_SUCCESS; +} + +NTSTATUS +CSensor:: +SetQPC( + _In_ ULONG StillIndex, + _In_ ULONGLONG TriggerTime +) +{ + PAGED_CODE(); + + if( !IsStillIndex(StillIndex) || + !m_HardwareSimulation[StillIndex] ) + { + return STATUS_INVALID_DEVICE_STATE; + } + + ((CImageHardwareSimulation *) m_HardwareSimulation[StillIndex])-> + SetTriggerTime( TriggerTime ); + + return STATUS_SUCCESS; +} + +// +// Program the Per Frame Settings for simulation +// We do it before calling start so we can be ready +// to program our simulation's hardware. +// +// Note: We make a local copy. +// +NTSTATUS +CSensor:: +SetPFS( + _In_ ISP_FRAME_SETTINGS *pIspSettings, + _In_ ULONG FrameLimit, + _In_ ULONG LoopLimit +) +/*++ + +Routine Description: + + Program the Per Frame Settings for simulation + We do it before calling start so we can be ready + to program our simulation's hardware. + + Note: We make a local copy. + +Arguments: + + pIspSettings - + The Per-Frame Settings to use. + + FrameLimit - + The number of frames to capture. + + LoopLimit - + The number of times to loop over the sequence. + +Return Value: + + Success / Failure. + +--*/ +{ + PAGED_CODE(); + KScopedMutex Lock(m_SensorMutex); + + // Set the current ISP settings and free any prior. + // This has to be done at simulation start or stop or we have + // a synchronization problem. + SAFE_DELETE_ARRAY( m_pIspSettings ); + + if( pIspSettings ) + { + m_pIspSettings = new (NonPagedPoolNx) ISP_FRAME_SETTINGS[FrameLimit]; + if( !m_pIspSettings ) + { + m_PfsFrameLimit = 0; + m_PfsLoopLimit = 0; + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory( m_pIspSettings, pIspSettings, FrameLimit*sizeof(ISP_FRAME_SETTINGS) ); + m_PfsLoopLimit = LoopLimit; + m_PfsFrameLimit = FrameLimit; + } + else + { + m_PfsFrameLimit = 0; + m_PfsLoopLimit = 0; + } + + return STATUS_SUCCESS; +} + +/*************************************************/ + + +void +CSensor:: +ReleaseHardwareResources ( + _In_ PKSPIN Pin +) + +/*++ + +Routine Description: + + Release hardware resources. This should only be called by + an object which has acquired them. + +Arguments: + + Pin - + The pin to acquire. + +Return Value: + + None + +--*/ + +{ + + PAGED_CODE(); + + DBG_ENTER( "( Pin=%d )\n", Pin->Id ) ; + + LONG lPindex = Pin->Id; + // + // Blow away the image synth. + // + m_HardwareSimulation[lPindex]->Reset(); + + SAFE_DELETE( m_Synthesizer[lPindex] ); + m_VideoInfoHeader[lPindex] = NULL; + + // + // Release our "lock" on hardware resources. This will allow another + // pin (perhaps in another graph) to acquire them. + // + InterlockedExchangePointer( + (PVOID *) &(m_CapturePin[lPindex]), + nullptr + ); + + DBG_LEAVE( "( Pin=%d )\n", Pin->Id ) ; +} + +ULONG +CSensor:: +ProgramScatterGatherMappings ( + _In_ PKSPIN Pin, + _In_ PKSSTREAM_POINTER *Clone, + _In_ PUCHAR *Buffer, + _In_ PKSMAPPING Mappings, + _In_ ULONG MappingsCount +) + +/*++ + +Routine Description: + + Program the scatter / gather mappings for the "fake" hardware. + + Punts the request to the H/W simulation (CHardwareSimulation) object for + that pin. + +Arguments: + + Pin - + The pin to program. + + Clone - + A stream pointer. + + Buffer - + Points to a pointer to the virtual address of the topmost + scatter / gather chunk. The pointer will be updated as the + device "programs" mappings. Reason for this is that we get + the physical addresses and sizes, but must calculate the virtual + addresses... This is used as scratch space for that. + + Mappings - + An array of mappings to program + + MappingsCount - + The count of mappings in the array + +Return Value: + + The number of mappings successfully programmed + +--*/ + +{ + PAGED_CODE(); + + return + m_HardwareSimulation[Pin->Id]->ProgramScatterGatherMappings ( + Clone, + Buffer, + Mappings, + MappingsCount, + sizeof (KSMAPPING) + ); +} + +// Expose a pointer to the global ISP_FRAME_SETTINGS +ISP_FRAME_SETTINGS * +CSensor:: +GetGlobalIspSettings() +{ + PAGED_CODE(); + return &m_GlobalIspSettings; +} + +void +CSensor:: +UpdateZoom(void) +{ + PAGED_CODE(); +} + +// +// This "Null" definition fails the request as if it doesn't exist in the +// automation table. This is the default behavior for most properties in +// CSensor. +// +#define DEFINE_NULL_PROPERTY_FUNC( _sal_, type, func ) \ +NTSTATUS \ +func( \ + _sal_ type *Value \ + ) \ +{ \ + PAGED_CODE(); \ + UNREFERENCED_PARAMETER(Value); \ + DBG_OUT("DEFINE_NULL_PROPERTY_FUNC defined %s - STATUS_NOT_FOUND(0x%x)", #func, STATUS_NOT_FOUND);\ + return STATUS_NOT_FOUND; \ +} + +#define DEFINE_NULL_SIZEOF_FUNC( func ) \ +ULONG \ +func() \ +{ \ + PAGED_CODE(); \ + DBG_OUT("DEFINE_NULL_SIZEOF_FUNC defined %s - STATUS_SUCCESS(0x%x)", #func, 0);\ + return 0; \ +} + +#define DEFINE_NULL_PROPERTY_GET( T, type, name ) \ + DEFINE_NULL_PROPERTY_FUNC( _Inout_, type, T::Get##name ) + +#define DEFINE_NULL_PROPERTY_SET( T, type, name ) \ + DEFINE_NULL_PROPERTY_FUNC( _In_, type, T::Set##name ) + +#define DEFINE_NULL_PROPERTY( T, type, name ) \ + DEFINE_NULL_PROPERTY_GET( T, type, name ) \ + DEFINE_NULL_PROPERTY_SET( T, type, name ) + +#define DEFINE_NULL_PROPERTY_ASYNC( T, type, name ) \ + DEFINE_NULL_PROPERTY_GET( T, type, name ) \ + \ +NTSTATUS \ +T:: \ +Set##name##Async( \ + _In_ type *pProperty, \ + _In_ CNotifier *Notifier \ + ) \ +{ \ + PAGED_CODE(); \ + UNREFERENCED_PARAMETER(pProperty); \ + UNREFERENCED_PARAMETER(Notifier); \ + DBG_OUT("Set##name##Async defined null property for Set%sAsync - STATUS_NOT_FOUND(0x%x)", #name, STATUS_NOT_FOUND);\ + return STATUS_NOT_FOUND; \ +} \ + \ +NTSTATUS \ +T:: \ +Cancel##name() \ +{ \ + PAGED_CODE(); \ + DBG_OUT("Cancel##name defined null property for Cancel%s - STATUS_UNSUCCESSFUL(0x%x)", #name, STATUS_UNSUCCESSFUL);\ + return STATUS_UNSUCCESSFUL; \ +} + +#define DEFINE_NULL_PROPERTY_VARSIZE_ASYNC( T, type, name ) \ + DEFINE_NULL_PROPERTY_ASYNC( T, type, name ) \ + \ +ULONG \ +T:: \ +SizeOf##name() \ +{ \ + PAGED_CODE(); \ + DBG_OUT("SizeOf##name defined null property for SizeOf%s - STATUS_SUCCESS(0x%x)", #name, STATUS_SUCCESS);\ + return 0; \ +} + +// +// Define a bunch of "not implemented" function stubs. +// +DEFINE_NULL_PROPERTY_ASYNC(CSensor, KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S, FocusRect) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedPhotoMode, PhotoMode) + +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOCONTROL_MODE_S, VideoControlMode) +DEFINE_NULL_PROPERTY_GET(CSensor, KSPROPERTY_VIDEOCONTROL_CAPS_S, VideoControlCaps) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_FLASH_S, Flash) +DEFINE_NULL_PROPERTY_GET(CSensor, KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S, PinDependence) + +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, TriggerTime) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, TorchMode) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, ExtendedFlash) + +DEFINE_NULL_PROPERTY_GET(CSensor, CExtendedProperty, PhotoFrameRate) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedProperty, PhotoMaxFrameRate) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedProperty, WarmStart) +DEFINE_NULL_PROPERTY(CSensor, CExtendedMaxVideoFpsForPhotoRes, MaxVideoFpsForPhotoRes) +DEFINE_NULL_PROPERTY_GET(CSensor, CExtendedFieldOfView, FieldOfView) +DEFINE_NULL_PROPERTY_GET(CSensor, CExtendedCameraAngleOffset, CameraAngleOffset) +DEFINE_NULL_PROPERTY_GET(CSensor, KSCAMERA_EXTENDEDPROP_FOCUSSTATE, FocusState) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedVidProcSetting, Focus) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedProperty, Iso) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedVidProcSetting, IsoAdvanced) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedEvCompensation, EvCompensation) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedVidProcSetting, WhiteBalance) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedVidProcSetting, Exposure) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedProperty, SceneMode) +DEFINE_NULL_PROPERTY_ASYNC(CSensor, CExtendedProperty, Thumbnail) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, PhotoConfirmation) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, FocusPriority) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, VideoHDR) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, VFR) +DEFINE_NULL_PROPERTY(CSensor, CExtendedVidProcSetting, Zoom) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, VideoStabilization) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, Histogram) +DEFINE_NULL_PROPERTY(CSensor, CExtendedMetadata, Metadata) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, OpticalImageStabilization) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, OptimizationHint) +DEFINE_NULL_PROPERTY(CSensor, CExtendedProperty, AdvancedPhoto) +DEFINE_NULL_PROPERTY(CSensor, CExtendedVidProcSetting, FaceDetection) + +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S, VideoStabMode) + +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, Exposure) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, Focus) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, Zoom) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, ZoomRelative) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, Pan) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, Roll) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_S, Tilt) +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S, FocalLength) + +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOPROCAMP_S, BacklightCompensation); +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOPROCAMP_S, Brightness); +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOPROCAMP_S, Contrast); +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOPROCAMP_S, Hue); +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOPROCAMP_S, WhiteBalance); +DEFINE_NULL_PROPERTY(CSensor, KSPROPERTY_VIDEOPROCAMP_S, PowerlineFreq); + +DEFINE_NULL_PROPERTY_GET(CSensor, CRoiConfig, RoiConfigCaps); +DEFINE_NULL_PROPERTY_VARSIZE_ASYNC(CSensor, CRoiProperty, Roi); + +_Success_(return == 0) +NTSTATUS +CSensor:: +GetPfsCaps( + _Inout_opt_ KSCAMERA_PERFRAMESETTING_CAP_HEADER *Caps, + _Inout_ ULONG *Size +) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(Caps); + *Size = 0; + return STATUS_NOT_FOUND; +} |
