summaryrefslogtreecommitdiff
path: root/AVStream/avscamera/sys
diff options
context:
space:
mode:
authorkarlf <[email protected]>2016-08-11 13:28:13 -0700
committerkarlf <[email protected]>2016-08-11 13:28:13 -0700
commit96eb96dfb613e4c745db6bd1f53a92fe7e2290fc (patch)
treead5f3ede5cbcd6b598677ce41bcf8318471bdd92 /AVStream/avscamera/sys
parent687b274aa38fd05c8c26e3068932121876d7f745 (diff)
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'AVStream/avscamera/sys')
-rw-r--r--AVStream/avscamera/sys/AvsCamera.cpp108
-rw-r--r--AVStream/avscamera/sys/AvsCamera.rc21
-rw-r--r--AVStream/avscamera/sys/AvsCamera.vcxproj247
-rw-r--r--AVStream/avscamera/sys/AvsCamera.vcxproj.Filters106
-rw-r--r--AVStream/avscamera/sys/AvsCameraDevice.cpp99
-rw-r--r--AVStream/avscamera/sys/AvsCameraDevice.h73
-rw-r--r--AVStream/avscamera/sys/AvsCameraFilter.cpp588
-rw-r--r--AVStream/avscamera/sys/AvsCameraFilter.h57
-rw-r--r--AVStream/avscamera/sys/CameraProfile.h54
-rw-r--r--AVStream/avscamera/sys/Capture.cpp2086
-rw-r--r--AVStream/avscamera/sys/Capture.h305
-rw-r--r--AVStream/avscamera/sys/Common.h703
-rw-r--r--AVStream/avscamera/sys/Dbg.h81
-rw-r--r--AVStream/avscamera/sys/Device.cpp966
-rw-r--r--AVStream/avscamera/sys/Device.h450
-rw-r--r--AVStream/avscamera/sys/ExtendedCameraAngleOffset.h67
-rw-r--r--AVStream/avscamera/sys/ExtendedEVComp.h105
-rw-r--r--AVStream/avscamera/sys/ExtendedFieldOfView.h67
-rw-r--r--AVStream/avscamera/sys/ExtendedMaxVideoFpsForPhotoRes.h91
-rw-r--r--AVStream/avscamera/sys/ExtendedMetadata.h68
-rw-r--r--AVStream/avscamera/sys/ExtendedPhotoMode.h73
-rw-r--r--AVStream/avscamera/sys/ExtendedProperty.h142
-rw-r--r--AVStream/avscamera/sys/ExtendedVidProcSetting.h164
-rw-r--r--AVStream/avscamera/sys/Mutex.cpp70
-rw-r--r--AVStream/avscamera/sys/Mutex.h81
-rw-r--r--AVStream/avscamera/sys/NV12Synthesizer.cpp183
-rw-r--r--AVStream/avscamera/sys/NV12Synthesizer.h73
-rw-r--r--AVStream/avscamera/sys/NonCopyable.h48
-rw-r--r--AVStream/avscamera/sys/PreviewHwSim.cpp263
-rw-r--r--AVStream/avscamera/sys/PreviewHwSim.h57
-rw-r--r--AVStream/avscamera/sys/RGB24Synthesizer.cpp133
-rw-r--r--AVStream/avscamera/sys/RGB24Synthesizer.h69
-rw-r--r--AVStream/avscamera/sys/Ref.h185
-rw-r--r--AVStream/avscamera/sys/Roi.cpp629
-rw-r--r--AVStream/avscamera/sys/Roi.h279
-rw-r--r--AVStream/avscamera/sys/Sensor.cpp1365
-rw-r--r--AVStream/avscamera/sys/Sensor.h605
-rw-r--r--AVStream/avscamera/sys/SensorSimulation.cpp3537
-rw-r--r--AVStream/avscamera/sys/SensorSimulation.h281
-rw-r--r--AVStream/avscamera/sys/Sources.dep1
-rw-r--r--AVStream/avscamera/sys/Synthesizer.cpp1558
-rw-r--r--AVStream/avscamera/sys/Synthesizer.h521
-rw-r--r--AVStream/avscamera/sys/Timer.cpp172
-rw-r--r--AVStream/avscamera/sys/Timer.h199
-rw-r--r--AVStream/avscamera/sys/Util.cpp491
-rw-r--r--AVStream/avscamera/sys/Util.h298
-rw-r--r--AVStream/avscamera/sys/VideoCapture.cpp130
-rw-r--r--AVStream/avscamera/sys/VideoCapture.h34
-rw-r--r--AVStream/avscamera/sys/VideoHwSim.cpp66
-rw-r--r--AVStream/avscamera/sys/VideoHwSim.h42
-rw-r--r--AVStream/avscamera/sys/Waitable.cpp69
-rw-r--r--AVStream/avscamera/sys/Waitable.h58
-rw-r--r--AVStream/avscamera/sys/WorkItem.cpp167
-rw-r--r--AVStream/avscamera/sys/WorkItem.h63
-rw-r--r--AVStream/avscamera/sys/XRGBSynthesizer.cpp247
-rw-r--r--AVStream/avscamera/sys/XRGBSynthesizer.h97
-rw-r--r--AVStream/avscamera/sys/YUVSynthesizer.cpp150
-rw-r--r--AVStream/avscamera/sys/YUVSynthesizer.h69
-rw-r--r--AVStream/avscamera/sys/YUY2Synthesizer.cpp137
-rw-r--r--AVStream/avscamera/sys/YUY2Synthesizer.h68
-rw-r--r--AVStream/avscamera/sys/avscamera.infbin0 -> 26814 bytes
-rw-r--r--AVStream/avscamera/sys/filter.cpp4080
-rw-r--r--AVStream/avscamera/sys/filter.h483
-rw-r--r--AVStream/avscamera/sys/formats.cpp390
-rw-r--r--AVStream/avscamera/sys/formats.h137
-rw-r--r--AVStream/avscamera/sys/hwsim.cpp1409
-rw-r--r--AVStream/avscamera/sys/hwsim.h316
-rw-r--r--AVStream/avscamera/sys/imagecapture.cpp155
-rw-r--r--AVStream/avscamera/sys/imagecapture.h44
-rw-r--r--AVStream/avscamera/sys/imagehwsim.cpp1509
-rw-r--r--AVStream/avscamera/sys/imagehwsim.h205
71 files changed, 27944 insertions, 0 deletions
diff --git a/AVStream/avscamera/sys/AvsCamera.cpp b/AVStream/avscamera/sys/AvsCamera.cpp
new file mode 100644
index 00000000..3742e69d
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCamera.cpp
@@ -0,0 +1,108 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ AvsCamera.cpp
+
+ Abstract:
+
+ Sample Camera driver initialization.
+
+ History:
+
+ created 5/15/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ DESCRIPTOR AND DISPATCH LAYOUT
+
+**************************************************************************/
+
+//
+// CaptureDeviceDispatch:
+//
+// This is the dispatch table for the capture device. Plug and play
+// notifications as well as power management notifications are dispatched
+// through this table.
+//
+DEFINE_CAMERA_KSDEVICE_DISPATCH( AvsCameraDispatch, CAvsCameraDevice );
+
+//
+// CaptureDeviceDescriptor:
+//
+// This is the device descriptor for the capture device. It points to the
+// dispatch table and contains a list of filter descriptors that describe
+// filter-types that this device supports. Note that the filter-descriptors
+// can be created dynamically and the factories created via
+// KsCreateFilterFactory as well.
+//
+const
+KSDEVICE_DESCRIPTOR
+AvsCameraDeviceDescriptor =
+{
+ &AvsCameraDispatch,
+ 0,
+ NULL
+};
+
+/**************************************************************************
+
+ INITIALIZATION CODE
+
+**************************************************************************/
+
+
+extern "C" DRIVER_INITIALIZE DriverEntry;
+
+extern "C"
+NTSTATUS
+DriverEntry (
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+)
+
+/*++
+
+Routine Description:
+
+ Driver entry point. Pass off control to the AVStream initialization
+ function (KsInitializeDriver) and return the status code from it.
+
+Arguments:
+
+ DriverObject -
+ The WDM driver object for our driver
+
+ RegistryPath -
+ The registry path for our registry info
+
+Return Value:
+
+ As from KsInitializeDriver
+
+--*/
+
+{
+ //
+ // Simply pass the device descriptor and parameters off to AVStream
+ // to initialize us. This will cause filter factories to be set up
+ // at add & start. Everything is done based on the descriptors passed
+ // here.
+ //
+ return
+ KsInitializeDriver (
+ DriverObject,
+ RegistryPath,
+ &AvsCameraDeviceDescriptor
+ );
+
+}
+
diff --git a/AVStream/avscamera/sys/AvsCamera.rc b/AVStream/avscamera/sys/AvsCamera.rc
new file mode 100644
index 00000000..25131b0a
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCamera.rc
@@ -0,0 +1,21 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+//
+// Copyright (C) Microsoft Corporation, 2015
+//
+// File: AvsCam.rc
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "A/V Stream Camera Simulator"
+#define VER_INTERNALNAME_STR "AvsCam.sys"
+#define VER_ORIGINALFILENAME_STR "AvsCam.sys"
+
+#include "common.ver"
diff --git a/AVStream/avscamera/sys/AvsCamera.vcxproj b/AVStream/avscamera/sys/AvsCamera.vcxproj
new file mode 100644
index 00000000..d46c7277
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCamera.vcxproj
@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <SupportsPackaging>false</SupportsPackaging>
+ <RequiresPackageProject>true</RequiresPackageProject>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{7F43971C-9E5A-46A0-B925-AFE3282E014C}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>AvsCamera</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>AvsCamera</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>AvsCamera</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>AvsCamera</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\cng.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\cng.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\cng.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib;$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\cng.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\common;$(SDK_INC_PATH)\ks</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <NTDDI_VERSION>NTDDI_WINTHRESHOLD</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <NTDDI_VERSION>NTDDI_WINTHRESHOLD</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <NTDDI_VERSION>NTDDI_WINTHRESHOLD</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <NTDDI_VERSION>NTDDI_WINTHRESHOLD</NTDDI_VERSION>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Link>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="AvsCamera.cpp" />
+ <ClCompile Include="AvsCameraDevice.cpp" />
+ <ClCompile Include="AvsCameraFilter.cpp" />
+ <ClCompile Include="capture.cpp" />
+ <ClCompile Include="device.cpp" />
+ <ClCompile Include="filter.cpp" />
+ <ClCompile Include="formats.cpp" />
+ <ClCompile Include="hwsim.cpp" />
+ <ClCompile Include="imagecapture.cpp" />
+ <ClCompile Include="ImagehwSim.cpp" />
+ <ClCompile Include="Mutex.cpp" />
+ <ClCompile Include="NV12Synthesizer.cpp" />
+ <ClCompile Include="PreviewHwSim.cpp" />
+ <ClCompile Include="RGB24Synthesizer.cpp" />
+ <ClCompile Include="Roi.cpp" />
+ <ClCompile Include="Sensor.cpp" />
+ <ClCompile Include="SensorSimulation.cpp" />
+ <ClCompile Include="Synthesizer.cpp" />
+ <ClCompile Include="Timer.cpp" />
+ <ClCompile Include="util.cpp" />
+ <ClCompile Include="videocapture.cpp" />
+ <ClCompile Include="VideoHwSim.cpp" />
+ <ClCompile Include="Waitable.cpp" />
+ <ClCompile Include="WorkItem.cpp" />
+ <ClCompile Include="XRGBSynthesizer.cpp" />
+ <ClCompile Include="YUVSynthesizer.cpp" />
+ <ClCompile Include="YUY2Synthesizer.cpp" />
+ <ResourceCompile Include="AvsCamera.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/AVStream/avscamera/sys/AvsCamera.vcxproj.Filters b/AVStream/avscamera/sys/AvsCamera.vcxproj.Filters
new file mode 100644
index 00000000..8d9ec469
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCamera.vcxproj.Filters
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{1E6E0D75-6064-4AA6-9EED-9795A14A9565}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{673D2600-D125-46B1-886A-679ED918CAE3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{4E7C2C4D-E0C2-4719-8255-3A104085149B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{39B99289-64B8-4EB7-808C-3AFE1DEF2048}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="AvsCamera.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AvsCameraDevice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AvsCameraFilter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="capture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="device.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="hwsim.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="imagecapture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ImagehwSim.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Mutex.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="NV12Synthesizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PreviewHwSim.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="RGB24Synthesizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Roi.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Sensor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SensorSimulation.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Synthesizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Timer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="util.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="videocapture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="VideoHwSim.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Waitable.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WorkItem.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="XRGBSynthesizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="YUVSynthesizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="YUY2Synthesizer.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="AvsCamera.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/avscamera/sys/AvsCameraDevice.cpp b/AVStream/avscamera/sys/AvsCameraDevice.cpp
new file mode 100644
index 00000000..8916e2ef
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCameraDevice.cpp
@@ -0,0 +1,99 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2015, Microsoft Corporation.
+
+ File:
+
+ AvsCameraDevice.cpp
+
+ Abstract:
+
+ Device class implementation. Derived from CCaptureDevice.
+ This class overloads our base device class implementation.
+
+ History:
+
+ created 02/24/2015
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+//
+// DispatchCreate():
+//
+// This is the Add Device dispatch for the capture device. It creates
+// the CCaptureDevice and associates it with the device via the bag.
+//
+NTSTATUS
+CAvsCameraDevice::
+DispatchCreate (
+ _In_ PKSDEVICE Device
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ CAvsCameraDevice *CapDevice = new (NonPagedPoolNx, 'eviD') CAvsCameraDevice (Device);
+ if( !CapDevice)
+ {
+ //
+ // Return failure if we couldn't create the device.
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NTSTATUS Status = CapDevice->Prepare();
+ if (!NT_SUCCESS (Status))
+ {
+ // Init failure.
+ delete CapDevice;
+ }
+
+ DBG_LEAVE("()");
+ return Status;
+}
+
+NTSTATUS
+CAvsCameraDevice::
+Initialize()
+{
+ PAGED_CODE();
+
+ static
+ CSensorContext Context[] =
+ {
+ { L"RFC", &AvsCameraFilterDescriptor, AcpiPldPanelBack, AcpiPldRotation0 },
+ { L"FFC", &AvsCameraFilterDescriptorFFC, AcpiPldPanelFront, AcpiPldRotation90 }
+ };
+
+ m_FilterDescriptorCount = SIZEOF_ARRAY(Context);
+ m_Context = Context;
+
+ return CCaptureDevice::Initialize();
+}
+
+CSensor *
+CAvsCameraDevice::
+CreateSensor(
+ _In_ const KSFILTER_DESCRIPTOR *Descriptors
+)
+{
+ PAGED_CODE();
+
+ return new (NonPagedPoolNx, 'sneS') CSensorSimulation( this, Descriptors );
+}
+
diff --git a/AVStream/avscamera/sys/AvsCameraDevice.h b/AVStream/avscamera/sys/AvsCameraDevice.h
new file mode 100644
index 00000000..ec98e892
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCameraDevice.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2015, Microsoft Corporation.
+
+ File:
+
+ AvsCameraDevice.h
+
+ Abstract:
+
+ Device class implementation. Derived from CCaptureDevice.
+ This class overloads our base device class implementation.
+
+ History:
+
+ created 02/24/2015
+
+**************************************************************************/
+
+#pragma once
+
+class CAvsCameraDevice : public CCaptureDevice
+{
+public:
+ //
+ // DispatchCreate():
+ //
+ // This is the Add Device dispatch for the capture device. It creates
+ // the CCaptureDevice and associates it with the device via the bag.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ _In_ PKSDEVICE Device
+ );
+
+public:
+ //
+ // CCaptureDevice():
+ //
+ // The capture device class constructor. Since everything should have
+ // been zero'ed by the new operator, don't bother setting anything to
+ // zero or NULL. Only initialize non-NULL, non-0 fields.
+ //
+ CAvsCameraDevice(
+ _In_ PKSDEVICE Device
+ )
+ : CCaptureDevice( Device )
+ {}
+
+ virtual
+ NTSTATUS
+ Initialize();
+
+protected:
+ virtual
+ CSensor *
+ CreateSensor(
+ _In_ const KSFILTER_DESCRIPTOR *Descriptors
+ );
+
+};
+
+// {B27E3887-AD10-4A4E-BFB8-D6765ADD0E38}
+#define STATIC_FrontCamera_Filter \
+ 0xb27e3887, 0xad10, 0x4a4e, 0xbf, 0xb8, 0xd6, 0x76, 0x5a, 0xdd, 0xe, 0x38
+
+// {4EE16166-F358-4F10-8889-93107806B7A7}
+#define STATIC_RearCamera_Filter \
+ 0x4ee16166, 0xf358, 0x4f10, 0x88, 0x89, 0x93, 0x10, 0x78, 0x6, 0xb7, 0xa7
+
diff --git a/AVStream/avscamera/sys/AvsCameraFilter.cpp b/AVStream/avscamera/sys/AvsCameraFilter.cpp
new file mode 100644
index 00000000..bff6466f
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCameraFilter.cpp
@@ -0,0 +1,588 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2015, Microsoft Corporation.
+
+ File:
+
+ AvsCameraFilter.cpp
+
+ Abstract:
+
+ Filter class implementation. Derived from CCaptureFilter.
+ This class overrides the default implementation.
+
+ History:
+
+ created 02/24/2015
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+CAvsCameraFilter::
+CAvsCameraFilter(
+ _In_ PKSFILTER Filter
+)
+ : CCaptureFilter( Filter )
+{
+ PAGED_CODE();
+}
+
+//
+// ~CCaptureFilter():
+//
+// The capture filter destructor.
+//
+CAvsCameraFilter::
+~CAvsCameraFilter()
+{
+ PAGED_CODE();
+}
+
+
+NTSTATUS
+CAvsCameraFilter::
+DispatchCreate (
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp
+)
+
+/*++
+
+Routine Description:
+
+ This is the creation dispatch for the capture filter. It creates
+ the CCaptureFilter object.
+
+Arguments:
+
+ Filter -
+ The AVStream filter being created
+
+ Irp -
+ The creation Irp
+
+Return Value:
+
+ Success / failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(Filter=0x%p)", Filter);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CAvsCameraFilter *CapFilter = new (NonPagedPoolNx, 'rtlf') CAvsCameraFilter(Filter);
+
+ if (!CapFilter)
+ {
+ //
+ // Return failure if we couldn't create the filter.
+ //
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+ else
+ {
+ // Allocate memory or whatever.
+ Status = CapFilter->Initialize();
+
+ if (!NT_SUCCESS (Status))
+ {
+ delete CapFilter;
+ }
+ else
+ {
+ Filter -> Context = reinterpret_cast <PVOID> (CapFilter);
+ }
+ }
+
+ DBG_LEAVE( "()=0x%08X", Status );
+ return Status;
+}
+
+// Get KSPROPERTY_CUSTOMCONTROL_DUMMY.
+NTSTATUS
+CAvsCameraFilter::
+GetCustomDummy(
+ _Inout_ ULONG *pDummy
+)
+{
+ PAGED_CODE();
+
+ *pDummy = m_CustomValue;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CUSTOMCONTROL_DUMMY.
+NTSTATUS
+CAvsCameraFilter::
+SetCustomDummy(
+ _In_ ULONG *pDummy
+)
+{
+ PAGED_CODE();
+
+ m_CustomValue = *pDummy;
+ return STATUS_SUCCESS;
+}
+
+/**************************************************************************
+
+ DESCRIPTOR AND DISPATCH LAYOUT
+
+**************************************************************************/
+
+GUID g_PINNAME_VIDEO_CAPTURE = {STATIC_PINNAME_VIDEO_CAPTURE};
+GUID g_PINNAME_VIDEO_PREVIEW = {STATIC_PINNAME_VIDEO_PREVIEW};
+GUID g_PINNAME_IMAGE_CAPTURE = {STATIC_PINNAME_IMAGE};
+
+//
+// CaptureFilterCategories:
+//
+// The list of category GUIDs for the capture filter.
+//
+const
+GUID
+FilterCategories [CAPTURE_FILTER_CATEGORIES_COUNT] =
+{
+ STATICGUIDOF (KSCATEGORY_VIDEO_CAMERA),
+ STATICGUIDOF (KSCATEGORY_VIDEO),
+ STATICGUIDOF (KSCATEGORY_CAPTURE)
+};
+
+DEFINE_KSPROPERTY_TABLE(FocusPropertyItems)
+{
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID, KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S, FocusRect )
+};
+
+DEFINE_KSPROPERTY_TABLE(VideoStabPropertyItems)
+{
+ DEFINE_PROP_ITEM( CCaptureFilter, 0, KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S, VideoStabMode )
+};
+
+DEFINE_KSPROPERTY_TABLE(FlashPropertyItems)
+{
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_FLASH_PROPERTY_ID, KSPROPERTY_CAMERACONTROL_FLASH_S, Flash )
+};
+
+DEFINE_KSPROPERTY_TABLE(PinDependencePropertyItems)
+{
+ // This control only requires a getter.
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_PROPERTY_ID, KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S,
+ PinDependence )
+};
+
+DEFINE_KSPROPERTY_TABLE(ExtendedPropertyItems)
+{
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE, CExtendedPhotoMode, PhotoMode ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE, CExtendedProperty, PhotoFrameRate ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE, CExtendedProperty, PhotoMaxFrameRate ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME, CExtendedProperty, TriggerTime ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART, CExtendedProperty, WarmStart ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES, CExtendedMaxVideoFpsForPhotoRes, MaxVideoFpsForPhotoRes ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE, CExtendedProperty, SceneMode ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_TORCHMODE, CExtendedProperty, TorchMode ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FLASHMODE, CExtendedProperty, ExtendedFlash ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_OPTIMIZATIONHINT, CExtendedProperty, OptimizationHint ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE, CExtendedVidProcSetting, WhiteBalance ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE, CExtendedVidProcSetting, Exposure ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE, CExtendedVidProcSetting, Focus ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ISO, CExtendedProperty, Iso ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FIELDOFVIEW, CExtendedFieldOfView, FieldOfView ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION, CExtendedEvCompensation, EvCompensation ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_CAMERAANGLEOFFSET, CExtendedCameraAngleOffset, CameraAngleOffset ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOCONFIRMATION, CExtendedProperty, PhotoConfirmation ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_METADATA, CExtendedMetadata, Metadata ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSSTATE, CExtendedProperty, FocusState ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSPRIORITY, CExtendedProperty, FocusPriority ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FACEDETECTION, CExtendedVidProcSetting, FaceDetection ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_CONFIGCAPS, CRoiConfig, RoiConfigCaps ),
+ DEFINE_KSPROPERTY_ITEM(
+ KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL,
+ CCaptureFilter::GetRoiIspControl,
+ sizeof(KSPROPERTY),
+ 0,
+ CCaptureFilter::SetRoiIspControl,
+ NULL, 0, NULL, NULL, 0
+ ),
+ DEFINE_PROP_ITEM(CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ZOOM, CExtendedVidProcSetting, Zoom),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOHDR, CExtendedProperty, VideoHDR ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_VFR, CExtendedProperty, VFR ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED, CExtendedVidProcSetting, IsoAdvanced ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOSTABILIZATION, CExtendedProperty, VideoStabilization),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_HISTOGRAM, CExtendedProperty, Histogram ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_OIS, CExtendedProperty, OpticalImageStabilization ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ADVANCEDPHOTO, CExtendedProperty, AdvancedPhoto ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE, CExtendedProfile, CameraProfile )
+};
+
+// Front-facing cameras often have limited capabilities. One way to express that is to use a restricted automation table such as this one.
+DEFINE_KSPROPERTY_TABLE(ExtendedPropertyItemsFFC)
+{
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE, CExtendedPhotoMode, PhotoMode ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE, CExtendedProperty, PhotoFrameRate ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE, CExtendedProperty, PhotoMaxFrameRate ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME, CExtendedProperty, TriggerTime ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART, CExtendedProperty, WarmStart ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES, CExtendedMaxVideoFpsForPhotoRes, MaxVideoFpsForPhotoRes ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE, CExtendedProperty, SceneMode ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_TORCHMODE, CExtendedProperty, TorchMode ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_OPTIMIZATIONHINT, CExtendedProperty, OptimizationHint ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE, CExtendedVidProcSetting, WhiteBalance ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE, CExtendedVidProcSetting, Exposure ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ISO, CExtendedProperty, Iso ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FIELDOFVIEW, CExtendedFieldOfView, FieldOfView ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION, CExtendedEvCompensation, EvCompensation ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_CAMERAANGLEOFFSET, CExtendedCameraAngleOffset, CameraAngleOffset ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOCONFIRMATION, CExtendedProperty, PhotoConfirmation ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_METADATA, CExtendedMetadata, Metadata ),
+ DEFINE_PROP_ITEM(CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ZOOM, CExtendedVidProcSetting, Zoom),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_FACEDETECTION, CExtendedVidProcSetting, FaceDetection ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED, CExtendedVidProcSetting, IsoAdvanced ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOSTABILIZATION, CExtendedProperty, VideoStabilization ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_ADVANCEDPHOTO, CExtendedProperty, AdvancedPhoto ),
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE, CExtendedProfile, CameraProfile )
+};
+
+//--------------------------------------------------------------
+// Legacy Camera Contorl properties
+DEFINE_KSPROPERTY_TABLE(CameraControlPropertyTable)
+{
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_EXPOSURE, KSPROPERTY_CAMERACONTROL_S, Exposure, &ExposureValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_FOCUS, KSPROPERTY_CAMERACONTROL_S, Focus, &FocusValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_ZOOM, KSPROPERTY_CAMERACONTROL_S, Zoom, &ZoomValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_ZOOM_RELATIVE, KSPROPERTY_CAMERACONTROL_S, ZoomRelative, &ZoomRelativeValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_PAN, KSPROPERTY_CAMERACONTROL_S, Pan, &PanValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_ROLL, KSPROPERTY_CAMERACONTROL_S, Roll, &RollValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_TILT, KSPROPERTY_CAMERACONTROL_S, Tilt, &TiltValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH, KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S, FocalLength, NULL)
+};
+
+DEFINE_KSPROPERTY_TABLE(PFSPropertyTable)
+{
+ DEFINE_KSPROPERTY_ITEM(
+ KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_CAPABILITY,
+ CCaptureFilter::GetPFSCaps, // GetSupported or Handler
+ sizeof(KSPROPERTY), // MinProperty
+ 0, // MinData
+ NULL, // SetSupported or Handler
+ NULL, // Values
+ 0, // RelationsCount
+ NULL, // Relations
+ NULL, // SupportHandler
+ 0 // SerializedSize
+ ),
+ DEFINE_KSPROPERTY_ITEM(
+ KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_SET,
+ CCaptureFilter::GetPerFrameSettings, // GetSupported or Handler
+ sizeof(KSPROPERTY), // MinProperty
+ 0, // MinData
+ CCaptureFilter::SetPerFrameSettings, // SetSupported or Handler
+ NULL, // Values
+ 0, // RelationsCount
+ NULL, // Relations
+ NULL, // SupportHandler
+ 0 // SerializedSize
+ ),
+ DEFINE_KSPROPERTY_ITEM(
+ KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_CLEAR,
+ NULL, // GetSupported or Handler
+ sizeof(KSPROPERTY), // MinProperty
+ 0, // MinData
+ CCaptureFilter::ClearPerFrameSettings, // SetSupported or Handler
+ NULL, // Values
+ 0, // RelationsCount
+ NULL, // Relations
+ NULL, // SupportHandler
+ 0 // SerializedSize
+ )
+};
+
+DEFINE_KSPROPERTY_TABLE(FilterVidcapPropertyTable)
+{
+ DEFINE_PROP_ITEM( CCaptureFilter, KSPROPERTY_VIDEOCONTROL_MODE, KSPROPERTY_VIDEOCONTROL_MODE_S, VideoControlMode ),
+ DEFINE_PROP_ITEM_NO_SET( CCaptureFilter, KSPROPERTY_VIDEOCONTROL_CAPS, KSPROPERTY_VIDEOCONTROL_CAPS_S, VideoControlCaps )
+};
+
+DEFINE_KSPROPERTY_TABLE( VideoProcampPropertyTable )
+{
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION, KSPROPERTY_VIDEOPROCAMP_S, BacklightCompensation,
+ &BacklightCompensationValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS, KSPROPERTY_VIDEOPROCAMP_S, Brightness, &BrightnessValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_VIDEOPROCAMP_CONTRAST, KSPROPERTY_VIDEOPROCAMP_S, Contrast, &ContrastValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_VIDEOPROCAMP_HUE, KSPROPERTY_VIDEOPROCAMP_S, Hue, &HueValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE, KSPROPERTY_VIDEOPROCAMP_S, WhiteBalance, &WhiteBalanceValues),
+ DEFINE_PROP_ITEM_WITH_VALUES(CCaptureFilter, KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, KSPROPERTY_VIDEOPROCAMP_S, PowerlineFreq, &PLFValues)
+};
+
+DEFINE_KSPROPERTY_TABLE( CustomPropertyTable )
+{
+ DEFINE_PROP_ITEM(CAvsCameraFilter, KSPROPERTY_CUSTOMCONTROL_DUMMY, ULONG, CustomDummy)
+};
+
+DEFINE_KSEVENT_TABLE(VidCapRoiEventTable)
+{
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID)
+};
+
+DEFINE_KSEVENT_TABLE(ExtendedPropertyEventTable)
+{
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_ISO),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED),
+ DEFINE_STD_EVENT_ITEM(KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE)
+};
+
+DEFINE_KSPROPERTY_SET_TABLE(PropertySets)
+{
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CAMERACONTROL_REGION_OF_INTEREST, FocusPropertyItems ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CAMERACONTROL_FLASH, FlashPropertyItems ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CAMERACONTROL_VIDEO_STABILIZATION, VideoStabPropertyItems ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_VIDEOCONTROL, FilterVidcapPropertyTable ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CAMERACONTROL_IMAGE_PIN_CAPABILITY, PinDependencePropertyItems ),
+ DEFINE_STD_PROPERTY_SET( KSPROPERTYSETID_ExtendedCameraControl, ExtendedPropertyItems ),
+ DEFINE_STD_PROPERTY_SET( KSPROPERTYSETID_PerFrameSettingControl, PFSPropertyTable ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CAMERACONTROL, CameraControlPropertyTable ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_VIDEOPROCAMP, VideoProcampPropertyTable ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CUSTOMCONTROL, CustomPropertyTable )
+};
+
+DEFINE_KSEVENT_SET_TABLE(EventSets)
+{
+ DEFINE_KSEVENT_SET
+ (
+ &KSEVENTSETID_ExtendedCameraControl,
+ SIZEOF_ARRAY(ExtendedPropertyEventTable),
+ ExtendedPropertyEventTable
+ ),
+ DEFINE_KSEVENT_SET
+ (
+ &EVENTSETID_VIDCAP_CAMERACONTROL_REGION_OF_INTEREST,
+ SIZEOF_ARRAY(VidCapRoiEventTable),
+ VidCapRoiEventTable
+ )
+};
+
+DEFINE_KSAUTOMATION_TABLE(AvsCameraFilterAutomationTable)
+{
+ DEFINE_KSAUTOMATION_PROPERTIES(PropertySets),
+ DEFINE_KSAUTOMATION_METHODS_NULL,
+ DEFINE_KSAUTOMATION_EVENTS(EventSets)
+};
+
+//FFC
+DEFINE_KSPROPERTY_SET_TABLE(PropertySetsFFC)
+{
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_VIDEOCONTROL, FilterVidcapPropertyTable ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CAMERACONTROL_IMAGE_PIN_CAPABILITY, PinDependencePropertyItems ),
+ DEFINE_STD_PROPERTY_SET( KSPROPERTYSETID_ExtendedCameraControl, ExtendedPropertyItemsFFC ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_VIDEOPROCAMP, VideoProcampPropertyTable ),
+ DEFINE_STD_PROPERTY_SET( PROPSETID_VIDCAP_CUSTOMCONTROL, CustomPropertyTable )
+};
+
+DEFINE_KSEVENT_SET_TABLE(EventSetsFFC)
+{
+ DEFINE_KSEVENT_SET
+ (
+ &KSEVENTSETID_ExtendedCameraControl,
+ SIZEOF_ARRAY(ExtendedPropertyEventTable),
+ ExtendedPropertyEventTable
+ )
+};
+
+DEFINE_KSAUTOMATION_TABLE(AvsCameraFilterAutomationTableFFC)
+{
+ DEFINE_KSAUTOMATION_PROPERTIES(PropertySetsFFC),
+ DEFINE_KSAUTOMATION_METHODS_NULL,
+ DEFINE_KSAUTOMATION_EVENTS(EventSetsFFC)
+};
+
+//
+// CaptureFilterPinDescriptors:
+//
+// The list of pin descriptors on the capture filter.
+//
+const
+KSPIN_DESCRIPTOR_EX
+PinDescriptors[] =
+{
+ //
+ // Video Capture Pin
+ //
+ {
+ &VideoCapturePinDispatch,
+ NULL,
+ {
+ 0, // Interfaces (NULL, 0 == default)
+ NULL,
+ 0, // Mediums (NULL, 0 == default)
+ NULL,
+ SIZEOF_ARRAY(VideoCapturePinDataRanges),// Range Count
+ VideoCapturePinDataRanges, // Ranges
+ KSPIN_DATAFLOW_OUT, // Dataflow
+ KSPIN_COMMUNICATION_BOTH, // Communication
+ &PIN_CATEGORY_CAPTURE, // Category
+ &g_PINNAME_VIDEO_CAPTURE, // Name
+ 0 // Reserved
+ },
+ KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY,
+ 1, // Instances Possible
+ 0, // Instances Necessary
+ &VideoCapturePinAllocatorFraming, // Allocator Framing
+ reinterpret_cast <PFNKSINTERSECTHANDLEREX>
+ (CVideoCapturePin::IntersectHandler)
+ },
+ //
+ // Video Preview Pin
+ //
+ {
+ &VideoCapturePinDispatch,
+ NULL,
+ {
+ 0,
+ NULL,
+ 0,
+ NULL,
+ SIZEOF_ARRAY(VideoPreviewPinDataRanges),// Range Count
+ VideoPreviewPinDataRanges, // Ranges
+ KSPIN_DATAFLOW_OUT, // Dataflow
+ KSPIN_COMMUNICATION_BOTH, // Communication
+ &PIN_CATEGORY_PREVIEW, // Category
+ &g_PINNAME_VIDEO_PREVIEW, // Name
+ 0 // Reserved
+ },
+ KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY,
+ 1, // Instances Possible
+ 0, // Instances Necessary
+ &VideoCapturePinAllocatorFraming, // Allocator Framing
+ reinterpret_cast <PFNKSINTERSECTHANDLEREX>
+ (CVideoCapturePin::IntersectHandler)
+ },
+ //
+ // Image Capture Pin
+ //
+ {
+ &ImageCapturePinDispatch,
+ NULL,
+ {
+ 0, // Interfaces (NULL, 0 == default)
+ NULL,
+ 0, // Mediums (NULL, 0 == default)
+ NULL,
+ SIZEOF_ARRAY(ImageCapturePinDataRanges),// Range Count
+ ImageCapturePinDataRanges, // Ranges
+ KSPIN_DATAFLOW_OUT, // Dataflow
+ KSPIN_COMMUNICATION_BOTH, // Communication
+ &PINNAME_IMAGE, // Category
+ &g_PINNAME_IMAGE_CAPTURE, // Name
+ 0 // Reserved
+ },
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+ KSPIN_FLAG_INITIATE_PROCESSING_ON_EVERY_ARRIVAL |
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+ KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY,
+ 1, // Instances Possible
+ 0, // Instances Necessary
+ &ImageCapturePinAllocatorFraming, // Allocator Framing
+ reinterpret_cast <PFNKSINTERSECTHANDLEREX>
+ (CImageCapturePin::IntersectHandler)
+ }
+};
+
+//
+// CaptureFilterDispatch:
+//
+// This is the dispatch table for the capture filter. It provides notification
+// of creation, closure, processing (for filter-centrics, not for the capture
+// filter), and resets (for filter-centrics, not for the capture filter).
+//
+const
+KSFILTER_DISPATCH
+AvsCameraFilterDispatch =
+{
+ CAvsCameraFilter::DispatchCreate, // Filter Create
+ CCaptureFilter::DispatchClose, // Filter Close
+ NULL, // Filter Process
+ NULL // Filter Reset
+};
+
+// {B27E3887-AD10-4A4E-BFB8-D6765ADD0E38}
+const
+GUID
+AvsCam_FrontCamera_Filter = {STATIC_FrontCamera_Filter};
+
+// {4EE16166-F358-4F10-8889-93107806B7A7}
+const
+GUID
+AvsCam_RearCamera_Filter = {STATIC_RearCamera_Filter};
+
+//
+// AvsCameraFilterDescriptor:
+//
+// The descriptor for the capture filter. We don't specify any topology
+// since there's only one pin on the filter. Realistically, there would
+// be some topological relationships here because there would be input
+// pins from crossbars and the like.
+//
+const
+KSFILTER_DESCRIPTOR
+AvsCameraFilterDescriptor =
+{
+ &AvsCameraFilterDispatch, // Dispatch Table
+ &AvsCameraFilterAutomationTable, // Automation Table
+ KSFILTER_DESCRIPTOR_VERSION, // Version
+ KSFILTER_FLAG_PRIORITIZE_REFERENCEGUID, // Flags
+ &AvsCam_RearCamera_Filter, // Reference GUID
+ DEFINE_KSFILTER_PIN_DESCRIPTORS(PinDescriptors),
+ DEFINE_KSFILTER_CATEGORIES(FilterCategories),
+ 0,
+ sizeof (KSNODE_DESCRIPTOR),
+ NULL,
+ 0,
+ NULL,
+ NULL // Component ID
+};
+
+const
+KSFILTER_DESCRIPTOR
+AvsCameraFilterDescriptorFFC =
+{
+ &AvsCameraFilterDispatch, // Dispatch Table
+ &AvsCameraFilterAutomationTableFFC, // Automation Table
+ KSFILTER_DESCRIPTOR_VERSION, // Version
+ KSFILTER_FLAG_PRIORITIZE_REFERENCEGUID, // Flags
+ &AvsCam_FrontCamera_Filter, // Reference GUID
+ DEFINE_KSFILTER_PIN_DESCRIPTORS(PinDescriptors),
+ DEFINE_KSFILTER_CATEGORIES(FilterCategories),
+ 0,
+ sizeof (KSNODE_DESCRIPTOR),
+ NULL,
+ 0,
+ NULL,
+ NULL // Component ID
+};
+
diff --git a/AVStream/avscamera/sys/AvsCameraFilter.h b/AVStream/avscamera/sys/AvsCameraFilter.h
new file mode 100644
index 00000000..ce81cede
--- /dev/null
+++ b/AVStream/avscamera/sys/AvsCameraFilter.h
@@ -0,0 +1,57 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2015, Microsoft Corporation.
+
+ File:
+
+ AvsCameraFilter.h
+
+ Abstract:
+
+ Filter class implementation. Derived from CCapturefilter.
+ This class overloads basic filter behavior for our device.
+
+ History:
+
+ created 02/24/2015
+
+**************************************************************************/
+
+class CAvsCameraFilter : public CCaptureFilter
+{
+public:
+ //
+ // Ctor
+ //
+ CAvsCameraFilter(
+ _In_ PKSFILTER Filter
+ );
+
+ //
+ // Dtor
+ //
+ virtual
+ ~CAvsCameraFilter ();
+
+ //
+ // DispatchCreate():
+ //
+ // This is the filter creation dispatch for the capture filter. It
+ // creates the CCaptureFilter object, associates it with the AVStream
+ // object, and bags it for easy cleanup later.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp
+ );
+
+ // Example of adding a new, custom property.
+ DECLARE_PROPERTY_HANDLERS( ULONG, CustomDummy )
+
+protected:
+ DWORD m_CustomValue;
+};
diff --git a/AVStream/avscamera/sys/CameraProfile.h b/AVStream/avscamera/sys/CameraProfile.h
new file mode 100644
index 00000000..1a2aca8a
--- /dev/null
+++ b/AVStream/avscamera/sys/CameraProfile.h
@@ -0,0 +1,54 @@
+/**************************************************************************
+
+ AvsCam - An AVStream Simulated Camera Device.
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ CameraProfile.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedProfile.
+
+ History:
+
+ created 3/19/2015
+
+**************************************************************************/
+
+//
+// Helper class for CameraProfile
+//
+class CExtendedProfile : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_PROFILE m_Profile;
+
+public:
+ CExtendedProfile( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedProfile( flags, result )
+ {
+ Size = sizeof(*this);
+ m_Profile.ProfileId = KSCAMERAPROFILE_Legacy;
+ m_Profile.Index = 0;
+ m_Profile.Reserved = 0;
+ }
+
+ CExtendedProfile( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ m_Profile.ProfileId = KSCAMERAPROFILE_Legacy;
+ m_Profile.Index = 0;
+ m_Profile.Reserved = 0;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() && (Size >= sizeof(*this));
+ }
+};
+
+
diff --git a/AVStream/avscamera/sys/Capture.cpp b/AVStream/avscamera/sys/Capture.cpp
new file mode 100644
index 00000000..764052b3
--- /dev/null
+++ b/AVStream/avscamera/sys/Capture.cpp
@@ -0,0 +1,2086 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ capture.cpp
+
+ Abstract:
+
+ This is the implementation of the CCapturePin class.
+
+ CCapturePin wraps a PKSPIN object and does:
+ 1. Object construction and cleanup,
+ 2. State management,
+ 3. Accepts new frame buffers for filling,
+ 4. Completes frame buffers delivered by the simulation,
+ 5. Negotiates for and sets new formats / data ranges, and
+ 6. Manages allocator framing.
+
+ History:
+
+ created 3/8/2001
+
+**************************************************************************/
+
+#include "Common.h"
+#include <ksmedia.h>
+#include "ntintsafe.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+CCapturePin::
+CCapturePin (
+ _In_ PKSPIN Pin
+)
+ : m_Pin (Pin)
+ , m_PinState(PinStopped)
+ , m_Clock(nullptr)
+ , m_PendIo(FALSE)
+ , m_AcquiredResources(FALSE)
+ , m_VideoInfoHeader(nullptr)
+ , m_pBitmapInfoHeader(nullptr)
+ , m_PreviousStreamPointer(nullptr)
+ , m_PresentationTime(0)
+ , m_FrameNumber(0)
+ , m_DroppedFrames(0)
+ , m_DesiredFrames(2)
+/*++
+
+Routine Description:
+
+ Construct a new capture pin.
+
+Arguments:
+
+ Pin -
+ The AVStream pin object corresponding to the capture pin
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ NT_ASSERT(Pin);
+
+ PKSDEVICE Device = KsPinGetDevice (Pin);
+
+ NT_ASSERT(Device);
+
+ //
+ // Set up our device pointer. This gives us access to "hardware I/O"
+ // during the capture routines.
+ //
+ m_Device = CCaptureDevice::Recast(Device);
+
+ NT_ASSERT( m_Device );
+
+ m_Sensor = m_Device->GetSensor( KsPinGetParentFilter(Pin ) );
+
+ NT_ASSERT( m_Sensor );
+}
+
+CCapturePin::
+~CCapturePin()
+{
+ PAGED_CODE();
+
+ SAFE_FREE( m_pBitmapInfoHeader );
+ SAFE_FREE( m_VideoInfoHeader );
+}
+
+/*************************************************/
+
+NTSTATUS
+CCapturePin::
+ReleaseAllFrames()
+
+/*++
+
+Routine Description:
+
+ Clean up any references we're holding on frames after we abruptly
+ stop the hardware.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ PKSSTREAM_POINTER Clone = KsPinGetFirstCloneStreamPointer (m_Pin);
+ PKSSTREAM_POINTER NextClone = NULL;
+
+ //
+ // Walk through the clones, deleting them, and setting DataUsed to
+ // zero since we didn't use any data!
+ //
+ while (Clone)
+ {
+
+ NextClone = KsStreamPointerGetNextClone (Clone);
+
+ Clone->StreamHeader->DataUsed = 0;
+ KsStreamPointerDelete (Clone);
+
+ Clone = NextClone;
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+NTSTATUS
+CCapturePin::
+Initialize()
+/*++
+
+Routine Description:
+
+ Post construction initialization:
+ 1. Add us to the Pin's bag,
+ 2. Capture information about the image/video format, and
+ 3. Update the allocator's framing to match.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(Pin=%d)", m_Pin->Id);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if( !m_Sensor )
+ {
+ // Fail if we couldn't find the sensor.
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ 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 (
+ m_Pin->Bag,
+ this,
+ reinterpret_cast<PFNKSFREE> (Cleanup)
+ );
+
+ if( NT_SUCCESS(Status) )
+ {
+ m_Pin->Context = this;
+ }
+ }
+
+ //
+ // 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.
+ //
+ if (NT_SUCCESS (Status))
+ {
+ Status = CaptureBitmapInfoHeader();
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ //
+ // Edit the framing descriptors to match our pin's requirements given the current format.
+ //
+ Status = UpdateAllocatorFraming();
+ }
+
+ DBG_LEAVE("(Pin=%d)=0x%08X", m_Pin->Id, Status);
+ return Status;
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCapturePin::
+CaptureBitmapInfoHeader()
+/*++
+
+Routine Description:
+
+ Capture information about the image/video format for the pin.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ const GUID ImageInfoSpecifier ={ STATICGUIDOF( KSDATAFORMAT_SPECIFIER_IMAGE ) };
+ const GUID VideoInfoSpecifier ={ STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ) };
+
+ // Free any previous copy of these header.
+ SAFE_FREE(m_pBitmapInfoHeader);
+ SAFE_FREE(m_VideoInfoHeader);
+
+ m_pBitmapInfoHeader = reinterpret_cast <PKS_BITMAPINFOHEADER> (
+ ExAllocatePoolWithTag (
+ NonPagedPoolNx,
+ sizeof(KS_BITMAPINFOHEADER),
+ AVSHWS_POOLTAG
+ )
+ );
+ if( !m_pBitmapInfoHeader )
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if( IsEqualGUID( m_Pin->ConnectionFormat->Specifier, ImageInfoSpecifier ) &&
+ m_Pin->ConnectionFormat->FormatSize >= sizeof (KS_DATAFORMAT_IMAGEINFO) )
+ {
+
+ PKS_BITMAPINFOHEADER ConnectionHeader =
+ &((reinterpret_cast <PKS_DATAFORMAT_IMAGEINFO>
+ (m_Pin->ConnectionFormat))->ImageInfoHeader);
+
+ //
+ // Copy the connection format video info header into the newly
+ // allocated "captured" video info header.
+ //
+ *m_pBitmapInfoHeader = *ConnectionHeader;
+
+ m_VideoInfoHeader = reinterpret_cast <PKS_VIDEOINFOHEADER> (
+ ExAllocatePoolWithTag (
+ NonPagedPoolNx,
+ sizeof(KS_VIDEOINFOHEADER),
+ AVSHWS_POOLTAG
+ )
+ );
+ if( !m_VideoInfoHeader )
+ {
+ SAFE_FREE( m_pBitmapInfoHeader );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Copy the connection format video info header into the newly
+ // allocated "captured" video info header.
+ //
+ m_VideoInfoHeader->bmiHeader = *ConnectionHeader;
+
+ // If we don't have a known bit-depth (compressed formats), assume the worse-case.
+ if( m_pBitmapInfoHeader->biBitCount==0 )
+ {
+ m_pBitmapInfoHeader->biBitCount=32;
+ }
+
+ // Estimate the image size. The derived pin can chose to override this value.
+ m_VideoInfoHeader->bmiHeader.biSizeImage =
+ (m_pBitmapInfoHeader->biWidth*m_pBitmapInfoHeader->biHeight*m_pBitmapInfoHeader->biBitCount)/8;
+
+ // Estimate a frame rate. The derived pin can chose to override this value.
+ m_VideoInfoHeader->AvgTimePerFrame = ONESECOND/30;
+ }
+ else
+ if( IsEqualGUID( m_Pin->ConnectionFormat->Specifier, VideoInfoSpecifier ) &&
+ m_Pin->ConnectionFormat->FormatSize >= sizeof (KS_DATAFORMAT_VIDEOINFOHEADER) )
+ {
+ PKS_VIDEOINFOHEADER ConnectionHeader =
+ &((reinterpret_cast <PKS_DATAFORMAT_VIDEOINFOHEADER>
+ (m_Pin->ConnectionFormat))->
+ VideoInfoHeader);
+
+ m_VideoInfoHeader = reinterpret_cast <PKS_VIDEOINFOHEADER> (
+ ExAllocatePoolWithTag (
+ NonPagedPoolNx,
+ KS_SIZE_VIDEOHEADER (ConnectionHeader),
+ AVSHWS_POOLTAG
+ )
+ );
+ if( !m_VideoInfoHeader )
+ {
+ SAFE_FREE( m_pBitmapInfoHeader );
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // Copy the connection format video info header into the newly
+ // allocated "captured" video info header.
+ //
+ RtlCopyMemory (
+ m_VideoInfoHeader,
+ ConnectionHeader,
+ KS_SIZE_VIDEOHEADER (ConnectionHeader)
+ );
+
+ //
+ // Copy the connection format video info header into the newly
+ // allocated "captured" video info header.
+ //
+ *m_pBitmapInfoHeader = m_VideoInfoHeader->bmiHeader;
+ }
+
+ DBG_TRACE( "+++ AvgTimePerFrame = %lld +++", m_VideoInfoHeader->AvgTimePerFrame );
+
+ return STATUS_SUCCESS;
+}
+
+/*************************************************/
+
+NTSTATUS
+CCapturePin::
+SetState (
+ _In_ KSSTATE ToState,
+ _In_ KSSTATE FromState
+)
+
+/*++
+
+Routine Description:
+
+ This is called when the caputre pin transitions state. The routine
+ attempts to acquire / release any hardware resources and start up
+ or shut down capture based on the states we are transitioning to
+ and away from.
+
+Arguments:
+
+ ToState -
+ The state we're transitioning to
+
+ FromState -
+ The state we're transitioning away from
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DBG_ENTER( "( Pin=%d, ToState=%s, FromState=%s )\n",
+ m_Pin->Id, KSStateToStateName(ToState), KSStateToStateName(FromState) ) ;
+
+ switch (ToState)
+ {
+
+ case KSSTATE_STOP:
+
+ //
+ // First, stop the hardware if we actually did anything to it.
+ //
+ if (m_PinState != PinStopped)
+ {
+ Status = m_Sensor->Stop(m_Pin);
+ NT_ASSERT (NT_SUCCESS (Status));
+
+ m_PinState = PinStopped;
+ }
+
+ //
+ // We've stopped the "fake hardware". It has cleared out
+ // it's scatter / gather tables and will no longer be
+ // completing clones. We had locks on some frames that were,
+ // however, in hardware. This will clean them up. An
+ // alternative location would be in the reset dispatch.
+ // Note, however, that the reset dispatch can occur in any
+ // state and this should be understood.
+ //
+ // Some hardware may fill all S/G mappings before stopping...
+ // in this case, you may not have to do this. The
+ // "fake hardware" here simply stops filling mappings and
+ // cleans its scatter / gather tables out on the Stop call.
+ //
+ Status = ReleaseAllFrames ();
+
+ //
+ // Release any hardware resources related to this pin.
+ //
+ if (m_AcquiredResources)
+ {
+ //
+ // If we got an interface to the clock, we must release it.
+ //
+ if (m_Clock)
+ {
+ m_Clock->Release ();
+ m_Clock = NULL;
+ }
+
+ m_Sensor->ReleaseHardwareResources (m_Pin);
+
+ m_AcquiredResources = FALSE;
+ }
+
+ break;
+
+ case KSSTATE_ACQUIRE:
+ //
+ // Acquire any hardware resources related to this pin. We should
+ // only acquire them here -- **NOT** at filter create time.
+ // This means we do not fail creation of a filter because of
+ // limited hardware resources.
+ //
+ // TODO: Move this to a derived CCapturePin class - one
+ // specifically for testing, not as a sample.
+ if(GetAcquireFailureKey())
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (FromState == KSSTATE_STOP)
+ {
+ Status =
+ m_Sensor->
+ AcquireHardwareResources (
+ m_Pin,
+ this,
+ m_VideoInfoHeader,
+ &m_HardwareSimulation
+ );
+
+ if (NT_SUCCESS (Status))
+ {
+ m_AcquiredResources = TRUE;
+
+ //
+ // Attempt to get an interface to the master clock.
+ // This will fail if one has not been assigned. Since
+ // one must be assigned while the pin is still in
+ // KSSTATE_STOP, this is a guranteed method of getting
+ // the clock should one be assigned.
+ //
+ if (!NT_SUCCESS (
+ KsPinGetReferenceClockInterface (
+ m_Pin,
+ &m_Clock
+ )
+ ))
+ {
+ //
+ // If we could not get an interface to the clock,
+ // don't use one.
+ //
+ m_Clock = NULL;
+ }
+ }
+ else
+ {
+ m_AcquiredResources = FALSE;
+ }
+
+ }
+
+ //
+ // Standard transport pins will always receive transitions in
+ // +/- 1 manner. This means we'll always see a PAUSE->ACQUIRE
+ // transition before stopping the pin.
+ //
+
+ m_FrameNumber = 0;
+ m_DroppedFrames = 0;
+ break;
+
+ case KSSTATE_PAUSE:
+ //
+ // Stop the hardware simulation if we're coming down from run.
+ //
+ if (FromState == KSSTATE_RUN)
+ {
+ m_PresentationTime = 0;
+ Status = m_Sensor->Pause (m_Pin, TRUE);
+
+ if (NT_SUCCESS (Status))
+ {
+ m_PinState = PinPaused;
+ }
+ }
+ m_FrameNumber = 0;
+ break;
+
+ case KSSTATE_RUN:
+ //
+ // Start the hardware simulation or unpause it depending on
+ // whether we're initially running or we've paused and restarted.
+ //
+ if (FromState == KSSTATE_PAUSE && m_PinState == PinPaused)
+ {
+ Status = m_Sensor->Pause (m_Pin, FALSE);
+ }
+ else
+ {
+ Status = m_Sensor->Start (m_Pin);
+ }
+
+ if (NT_SUCCESS (Status))
+ {
+ m_PinState = PinRunning;
+ }
+ break;
+
+ }
+
+ DBG_LEAVE( "( Pin=%d, ToState=%s, FromState=%s ) = 0x%08X\n",
+ m_Pin->Id, KSStateToStateName(ToState), KSStateToStateName(FromState), Status ) ;
+
+ return Status;
+
+}
+
+NTSTATUS
+CCapturePin::
+Process()
+
+/*++
+
+Routine Description:
+
+ The process dispatch for the pin bridges to this location.
+ We handle setting up scatter gather mappings, etc...
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE( );
+
+ DBG_ENTER( "( Pin=%d )", m_Pin->Id );
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PKSSTREAM_POINTER Leading;
+
+ Leading = KsPinGetLeadingEdgeStreamPointer( m_Pin, KSSTREAM_POINTER_STATE_LOCKED );
+
+ while( NT_SUCCESS( Status ) && Leading )
+ {
+
+ PKSSTREAM_POINTER ClonePointer;
+ PSTREAM_POINTER_CONTEXT SPContext = NULL;
+
+ //
+ // If no data is present in the Leading edge stream pointer, just
+ // move on to the next frame
+ //
+ if( NULL == Leading->StreamHeader->Data )
+ {
+ Status = KsStreamPointerAdvance( Leading );
+ continue;
+ }
+ //
+ // For optimization sake in this particular sample, I will only keep
+ // one clone stream pointer per frame. This complicates the logic
+ // here but simplifies the completions.
+ //
+ // I'm also choosing to do this since I need to keep track of the
+ // virtual addresses corresponding to each mapping since I'm faking
+ // DMA. It simplifies that too.
+ //
+ if( !m_PreviousStreamPointer )
+ {
+ //
+ // First thing we need to do is clone the leading edge. This allows
+ // us to keep reference on the frames while they're in DMA.
+ //
+ Status = KsStreamPointerClone(
+ Leading,
+ NULL,
+ sizeof (STREAM_POINTER_CONTEXT),
+ &ClonePointer
+ );
+
+ //
+ // I use this for easy chunking of the buffer. We're not really
+ // dealing with physical addresses. This keeps track of what
+ // virtual address in the buffer the current scatter / gather
+ // mapping corresponds to for the fake hardware.
+ //
+ if( NT_SUCCESS( Status ) )
+ {
+ //
+ // Set the stream header data used to 0. We update this
+ // in the DMA completions. For queues with DMA, we must
+ // update this field ourselves.
+ //
+ ClonePointer->StreamHeader->DataUsed = 0;
+
+ SPContext = reinterpret_cast <PSTREAM_POINTER_CONTEXT>
+ (ClonePointer->Context);
+
+ SPContext->BufferVirtual =
+ reinterpret_cast <PUCHAR> (
+ ClonePointer->StreamHeader->Data
+ );
+ }
+ }
+ else
+ {
+ ClonePointer = m_PreviousStreamPointer;
+ SPContext = reinterpret_cast <PSTREAM_POINTER_CONTEXT>
+ (ClonePointer->Context);
+ }
+
+ //
+ // If the clone failed, likely we're out of resources. Break out
+ // of the loop for now. We may end up starving DMA.
+ //
+ if( !NT_SUCCESS( Status ) )
+ {
+ KsStreamPointerUnlock( Leading, FALSE );
+ break;
+ }
+
+ //
+ // Program the fake hardware. I would use Clone->OffsetOut.*, but
+ // because of the optimization of one stream pointer per frame, it
+ // doesn't make complete sense.
+ //
+ ULONG MappingsUsed =
+ m_Sensor->ProgramScatterGatherMappings(
+ m_Pin,
+ &ClonePointer,
+ &(SPContext->BufferVirtual),
+ Leading->OffsetOut.Mappings,
+ Leading->OffsetOut.Remaining
+ );
+
+ //
+ // In order to keep one clone per frame and simplify the fake DMA
+ // logic, make a check to see if we completely used the mappings in
+ // the leading edge. Set a flag.
+ //
+ if( MappingsUsed == Leading->OffsetOut.Remaining )
+ {
+ m_PreviousStreamPointer = NULL;
+ }
+ else
+ {
+ m_PreviousStreamPointer = ClonePointer;
+ }
+
+ if( MappingsUsed )
+ {
+ //
+ // If any mappings were added to scatter / gather queues,
+ // advance the leading edge by that number of mappings. If
+ // we run off the end of the queue, Status will be
+ // STATUS_DEVICE_NOT_READY. Otherwise, the leading edge will
+ // point to a new frame. The previous one will not have been
+ // dismissed (unless "DMA" completed) since there's a clone
+ // pointer referencing the frames.
+ //
+ Status =
+ KsStreamPointerAdvanceOffsets(
+ Leading,
+ 0,
+ MappingsUsed,
+ FALSE
+ );
+ }
+ else
+ {
+ //
+ // The hardware was incapable of adding more entries. The S/G
+ // table is full.
+ //
+ Status = STATUS_PENDING;
+ break;
+ }
+ }
+
+ //
+ // If the leading edge failed to lock (this is always possible, remember
+ // that locking CAN occassionally fail), don't blow up passing NULL
+ // into KsStreamPointerUnlock. Also, set m_PendIo to kick us later...
+ //
+ if( !Leading )
+ {
+ m_PendIo = TRUE;
+
+ //
+ // If the lock failed, there's no point in getting called back
+ // immediately. The lock could fail due to insufficient memory,
+ // etc... In this case, we don't want to get called back immediately.
+ // Return pending. The m_PendIo flag will cause us to get kicked
+ // later.
+ //
+ Status = STATUS_PENDING;
+ }
+
+ //
+ // If we didn't run the leading edge off the end of the queue, unlock it.
+ //
+ if( NT_SUCCESS( Status ) && Leading )
+ {
+ KsStreamPointerUnlock( Leading, FALSE );
+ }
+ else
+ {
+ //
+ // DEVICE_NOT_READY indicates that the advancement ran off the end
+ // of the queue. We couldn't lock the leading edge.
+ //
+ if( Status == STATUS_DEVICE_NOT_READY )
+ {
+ Status = STATUS_SUCCESS;
+ }
+ }
+
+ //
+ // If we failed with something that requires pending, set the pending I/O
+ // flag so we know we need to start it again.
+ //
+ if( !NT_SUCCESS( Status ) || Status == STATUS_PENDING )
+ {
+ m_PendIo = TRUE;
+ }
+
+ DBG_LEAVE( "( Pin=%d )=0x%08X", m_Pin->Id, Status );
+
+ return Status;
+}
+
+//
+// Emit metadata here for video or preview pin.
+//
+// This function gives us one last chance to tack metadata onto the sample.
+//
+void
+CCapturePin::
+EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+)
+{
+ PAGED_CODE();
+
+ NT_ASSERT(pStreamHeader);
+}
+
+
+NTSTATUS
+CCapturePin::
+CompleteMapping(
+ _In_ PKSSTREAM_POINTER Clone
+ )
+
+/*++
+
+Routine Description:
+
+ Called to notify the pin that a given number of scatter / gather
+ mappings have completed. Let the buffers go if possible.
+
+Arguments:
+
+ Clone -
+ The stream pointer for the frame to complete.
+ If Clone is null, use the head of the queue.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(Clone=%p)", Clone);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if( !Clone )
+ {
+ Clone = KsPinGetFirstCloneStreamPointer(m_Pin);
+ }
+
+ //
+ // If we have completed all remaining mappings in this clone, it
+ // is an indication that the clone is ready to be deleted and the
+ // buffer released. Set anything required in the stream header which
+ // has not yet been set. If we have a clock, we can timestamp the
+ // sample.
+ //
+ if( Clone )
+ {
+ if( Clone->StreamHeader->DataUsed >= Clone->OffsetOut.Remaining )
+ {
+ Clone->StreamHeader->Duration =
+ m_VideoInfoHeader->AvgTimePerFrame;
+
+ Clone->StreamHeader->OptionsFlags |=
+ KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
+
+ //
+ // Increment the frame number. This is the total count of frames which
+ // have attempted capture.
+ //
+ m_FrameNumber++;
+ DBG_TRACE( "m_FrameNumber=%lld", m_FrameNumber );
+
+ //
+ // Double check the Stream Header size. AVStream makes no guarantee
+ // that because StreamHeaderSize is set to a specific size that you
+ // will get that size. If the proper data type handlers are not
+ // installed, the stream header will be of default size.
+ //
+ if ( Clone->StreamHeader->Size >= sizeof (KSSTREAM_HEADER) +
+ sizeof (KS_FRAME_INFO))
+ {
+ PKS_FRAME_INFO FrameInfo = reinterpret_cast <PKS_FRAME_INFO> (
+ Clone->StreamHeader + 1
+ );
+
+ FrameInfo->ExtendedHeaderSize = sizeof (KS_FRAME_INFO);
+ FrameInfo->dwFrameFlags = KS_VIDEO_FLAG_FRAME;
+ FrameInfo->PictureNumber = (LONGLONG)m_FrameNumber;
+
+ // I don't really have a way to tell if the device has dropped a frame
+ // or was not able to send a frame on time.
+ FrameInfo->DropCount = (LONGLONG)m_DroppedFrames;
+ }
+
+ KsStreamPointerDelete (Clone);
+ }
+ else
+ {
+ //
+ // If only part of the mappings in this clone have been completed,
+ // update the pointers. Since we're guaranteed this won't advance
+ // to a new frame by the check above, it won't fail.
+ //
+ Status =
+ KsStreamPointerAdvanceOffsets(
+ Clone,
+ 0,
+ Clone->StreamHeader->DataUsed,
+ FALSE
+ );
+ }
+ }
+ else
+ {
+ // We had nothing to process.
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // If we've used all the mappings in hardware and pended, we can kick
+ // processing to happen again if we've completed mappings.
+ //
+ if (m_PendIo)
+ {
+ KsPinAttemptProcessing (m_Pin, TRUE);
+ m_PendIo = FALSE;
+ }
+
+ DBG_LEAVE("(Clone=%p)=0x%08X", Clone, Status);
+ return Status;
+}
+
+
+bool
+CCapturePin::
+GetAcquireFailureKey()
+{
+ NTSTATUS ntstatus;
+ bool acquireFailure = false;
+ UNICODE_STRING RegistryKeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE handleRegKey = NULL;
+ PKEY_VALUE_FULL_INFORMATION pKeyInfo = NULL;
+ ULONG ulKeyInfoSizeNeeded = 0;
+ UNICODE_STRING ValueName = {0};
+
+
+ PAGED_CODE();
+
+ // Get the Registry key
+ RtlInitUnicodeString(&RegistryKeyName, L"\\Registry\\Machine\\Software\\Microsoft\\wtt\\MachineConfig");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &RegistryKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL, // handle
+ NULL);
+
+ ntstatus = ZwOpenKey(&handleRegKey, KEY_READ, &ObjectAttributes);
+ // If we can't open the key, we're done. Worst case, we cannot stream.
+ if(NT_SUCCESS(ntstatus))
+ {
+ // Get the location from the registry key
+ RtlInitUnicodeString(&ValueName, L"AcquireFailure");
+
+ // Figure out how big keyInfo needs to be
+ ntstatus = ZwQueryValueKey(handleRegKey,
+ &ValueName,
+ KeyValueFullInformation,
+ pKeyInfo,
+ 0,
+ &ulKeyInfoSizeNeeded );
+
+ // We expect one of these errors
+ if( (ntstatus == STATUS_BUFFER_TOO_SMALL) || (ntstatus == STATUS_BUFFER_OVERFLOW) )
+ {
+ // Allocate the memory needed for the key
+ pKeyInfo = (PKEY_VALUE_FULL_INFORMATION) new (NonPagedPoolNx) BYTE[ulKeyInfoSizeNeeded];
+ RtlZeroMemory(pKeyInfo, ulKeyInfoSizeNeeded);
+
+ // Now get the actual key data
+ ntstatus = ZwQueryValueKey( handleRegKey,
+ &ValueName,
+ KeyValueFullInformation,
+ pKeyInfo,
+ ulKeyInfoSizeNeeded,
+ &ulKeyInfoSizeNeeded );
+
+ if(ntstatus == STATUS_SUCCESS)
+ {
+ acquireFailure = true;
+ }
+
+ delete[] pKeyInfo;
+ }
+ }
+
+ // All done with the registry
+ if (NULL != handleRegKey)
+ {
+ ZwClose(handleRegKey);
+ }
+
+ return acquireFailure;
+}
+
+
+NTSTATUS
+CCapturePin::
+DispatchClose(
+ _In_ PKSPIN Pin,
+ _In_ PIRP Irp
+)
+/*++
+
+Routine Description:
+
+ Static thunking function to forward Close
+
+Arguments:
+
+ Pin -
+ Our pin
+ Irp -
+ The IRP the request came in on.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ NT_ASSERT( Pin );
+ NT_ASSERT( Pin->Context );
+ if( Pin && Pin->Context )
+ {
+ CCapturePin *pPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+ Status = pPin->Close( Irp );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+NTSTATUS
+CCapturePin::
+DispatchSetState(
+ _In_ PKSPIN Pin,
+ _In_ KSSTATE ToState,
+ _In_ KSSTATE FromState
+)
+/*++
+
+Routine Description:
+
+ Static thunking function to forward SetState
+
+Arguments:
+
+ Pin -
+ Our pin
+ Irp -
+ The IRP the request came in on.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ NT_ASSERT( Pin );
+ NT_ASSERT( Pin->Context );
+ if( Pin && Pin->Context )
+ {
+ CCapturePin *pPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+ Status = pPin->SetState( ToState, FromState );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+NTSTATUS
+CCapturePin::
+DispatchSetFormat(
+ _In_ PKSPIN Pin,
+ _In_opt_ PKSDATAFORMAT OldFormat,
+ _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
+ _In_ const KSDATARANGE *DataRange,
+ _In_opt_ const KSATTRIBUTE_LIST *AttributeRange
+)
+
+/*++
+
+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( );
+
+ DBG_ENTER( "(Pin->Id=%d)", Pin->Id );
+
+ NTSTATUS Status = STATUS_NO_MATCH;
+ const GUID ImageInfoSpecifier = { STATICGUIDOF( KSDATAFORMAT_SPECIFIER_IMAGE ) };
+ const GUID VideoInfoSpecifier = { STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ) };
+
+ //
+ // 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.
+ //
+ CCapturePin *CapPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+
+ // For debugging...
+ UNICODE_STRING NewFormat;
+ UNICODE_STRING RefFormat;
+ RtlStringFromGUID( Pin->ConnectionFormat->SubFormat, &NewFormat );
+ RtlStringFromGUID( DataRange->SubFormat, &RefFormat );
+
+ if( IsEqualGUID( Pin->ConnectionFormat->Specifier, ImageInfoSpecifier ) &&
+ Pin->ConnectionFormat->FormatSize >= sizeof (KS_DATAFORMAT_IMAGEINFO) )
+ {
+ PKS_DATAFORMAT_IMAGEINFO ConnectionFormat = reinterpret_cast <PKS_DATAFORMAT_IMAGEINFO> (Pin->ConnectionFormat);
+
+ //
+ // DataRange comes out of OUR data range list. I know the range
+ // is valid as such.
+ //
+ const KS_DATARANGE_IMAGE *VIRange = reinterpret_cast <const KS_DATARANGE_IMAGE *> (DataRange);
+
+ //
+ // Check that bmiHeader.biSize is valid since we use it later.
+ //
+ ULONG ImageHeaderSize = ConnectionFormat->ImageInfoHeader.biSize;
+ ULONG DataFormatSize = sizeof (KSDATAFORMAT) +sizeof(KS_BITMAPINFOHEADER);
+
+ if( ImageHeaderSize < ConnectionFormat->ImageInfoHeader.biSize ||
+ DataFormatSize < ImageHeaderSize ||
+ DataFormatSize > ConnectionFormat->DataFormat.FormatSize )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Check that the format is a match for the selected range.
+ //
+ else if( (ConnectionFormat->ImageInfoHeader.biWidth != VIRange->ImageInfoHeader.biWidth) ||
+ (ConnectionFormat->ImageInfoHeader.biHeight != VIRange->ImageInfoHeader.biHeight) ||
+ !IsEqualGUID( Pin->ConnectionFormat->SubFormat, DataRange->SubFormat ) )
+ {
+ Status = STATUS_NO_MATCH;
+ }
+ else
+ {
+
+ ULONG ImageSize;
+
+ if( !MultiplyCheckOverflow( (ULONG) ConnectionFormat->ImageInfoHeader.biWidth, (ULONG) abs( ConnectionFormat->ImageInfoHeader.biHeight ), &ImageSize ) )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ else if( !MultiplyCheckOverflow( ImageSize, (ULONG) (ConnectionFormat->ImageInfoHeader.biBitCount/8), &ImageSize ) )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Valid for the formats we use. Otherwise, this would be
+ // checked later.
+ //
+ else if( ConnectionFormat->ImageInfoHeader.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.
+ //
+ if( OldFormat && CapPin )
+ {
+ //
+ // If we're in the stop state, we can handle just about any
+ // change. We don't support dynamic format changes.
+ //
+ if( Pin->DeviceState == KSSTATE_STOP )
+ {
+ Status = CapPin->CaptureBitmapInfoHeader();
+ }
+ else
+ {
+ //
+ // Because we don't accept dynamic format changes, we
+ // should never get here. Just being over-protective.
+ //
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ }
+ }
+ }
+
+ else 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) ||
+ !IsEqualGUID( Pin->ConnectionFormat->SubFormat, DataRange->SubFormat ) )
+ {
+ DBG_TRACE("FAILED: Height=(%d,%d), Width=(%d,%d), SubFormat=(%wZ,%wZ)",
+ ConnectionFormat->VideoInfoHeader.bmiHeader.biWidth,
+ VIRange->VideoInfoHeader.bmiHeader.biWidth,
+ ConnectionFormat->VideoInfoHeader.bmiHeader.biHeight,
+ VIRange->VideoInfoHeader.bmiHeader.biHeight,
+ &NewFormat, &RefFormat );
+ Status = STATUS_NO_MATCH;
+ }
+ else
+ {
+ DBG_TRACE("MATCH: Height=(%d,%d), Width=(%d,%d), SubFormat=(%wZ,%wZ)",
+ ConnectionFormat->VideoInfoHeader.bmiHeader.biWidth,
+ VIRange->VideoInfoHeader.bmiHeader.biWidth,
+ ConnectionFormat->VideoInfoHeader.bmiHeader.biHeight,
+ VIRange->VideoInfoHeader.bmiHeader.biHeight,
+ &NewFormat, &RefFormat );
+
+ //
+ // 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.
+ //
+ if( OldFormat && CapPin )
+ {
+ //
+ // If we're in the stop state, we can handle just about any
+ // change. We don't support dynamic format changes.
+ //
+ if( Pin->DeviceState == KSSTATE_STOP )
+ {
+ if( !CapPin->CaptureBitmapInfoHeader( ) )
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ //
+ // Because we don't accept dynamic format changes, we
+ // should never get here. Just being over-protective.
+ //
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+ }
+ }
+ }
+
+ RtlFreeUnicodeString(&NewFormat);
+ RtlFreeUnicodeString(&RefFormat);
+
+ DBG_LEAVE( "(Pin->Id=%d)=0x%08X", Pin->Id, Status );
+ return Status;
+}
+
+NTSTATUS
+CCapturePin::
+IntersectHandler(
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp,
+ _In_ PKSP_PIN PinInstance,
+ _In_ PKSDATARANGE CallerDataRange,
+ _In_ PKSDATARANGE DescriptorDataRange,
+ _In_ ULONG BufferSize,
+ _Out_opt_ 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 ImageInfoSpecifier = { STATICGUIDOF( KSDATAFORMAT_SPECIFIER_IMAGE ) };
+ const GUID VideoInfoSpecifier = { STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ) };
+ ULONG DataFormatSize;
+
+ NT_ASSERT( Filter );
+ NT_ASSERT( Irp );
+ NT_ASSERT( PinInstance );
+ NT_ASSERT( CallerDataRange );
+ NT_ASSERT( DescriptorDataRange );
+ NT_ASSERT( DataSize );
+
+ //
+ // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
+ //
+ if( IsEqualGUID( CallerDataRange->Specifier, ImageInfoSpecifier ) &&
+ CallerDataRange->FormatSize >= sizeof (KS_DATARANGE_IMAGE) )
+ {
+
+ PKS_DATARANGE_IMAGE callerDataRange =
+ reinterpret_cast <PKS_DATARANGE_IMAGE> (CallerDataRange);
+
+ PKS_DATARANGE_IMAGE descriptorDataRange =
+ reinterpret_cast <PKS_DATARANGE_IMAGE> (DescriptorDataRange);
+
+ //
+ // Check that the other fields match
+ //
+ if( (RtlCompareMemory( &callerDataRange->ConfigCaps, &descriptorDataRange->ConfigCaps, sizeof (KS_VIDEO_STREAM_CONFIG_CAPS) )
+ != sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) )
+ {
+ return STATUS_NO_MATCH;
+ }
+
+ {
+ ULONG ImageHeaderSize = ((PKS_DATARANGE_IMAGE) callerDataRange)->ImageInfoHeader.biSize;
+ ULONG DataRangeSize = FIELD_OFFSET( KS_DATARANGE_IMAGE, ImageInfoHeader ) + ImageHeaderSize;
+
+ if( ImageHeaderSize < callerDataRange->ImageInfoHeader.biSize ||
+ DataRangeSize < ImageHeaderSize ||
+ DataRangeSize > callerDataRange->DataRange.FormatSize )
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ DataFormatSize = sizeof (KSDATAFORMAT) +sizeof(KS_BITMAPINFOHEADER);
+ //
+ // 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;
+
+ PKS_DATAFORMAT_IMAGEINFO pFormatImageInfoHeader = PKS_DATAFORMAT_IMAGEINFO( 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( pFormatImageInfoHeader, DescriptorDataRange, sizeof (KSDATAFORMAT) );
+ pFormatImageInfoHeader->DataFormat.FormatSize = DataFormatSize;
+
+ //
+ // Copy over the callers requested KS_BITMAPINFOHEADER
+ //
+ RtlCopyMemory( &pFormatImageInfoHeader->ImageInfoHeader, &callerDataRange->ImageInfoHeader, sizeof(KS_BITMAPINFOHEADER) );
+ return STATUS_SUCCESS;
+ }
+ else 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;
+}
+
+NTSTATUS
+CCapturePin::
+DispatchProcess(
+ _In_ PKSPIN Pin
+)
+/*++
+
+Routine Description:
+
+ Static thunking function to forward Process
+
+Arguments:
+
+ Pin -
+ Our pin
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ NT_ASSERT( Pin );
+ NT_ASSERT( Pin->Context );
+ if( Pin && Pin->Context )
+ {
+ CCapturePin *pPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+ Status = pPin->Process();
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+void
+CCapturePin::
+DispatchReset(
+ _In_ PKSPIN Pin
+)
+/*++
+
+Routine Description:
+
+ Static thunking function to forward Reset
+
+Arguments:
+
+ Pin -
+ Our pin
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ DBG_ENTER("()");
+
+ NT_ASSERT( Pin );
+ NT_ASSERT( Pin->Context );
+ if( Pin && Pin->Context )
+ {
+ CCapturePin *pPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+ pPin->Reset( );
+ }
+ DBG_LEAVE("()");
+}
+
+NTSTATUS
+CCapturePin::
+DispatchConnect(
+ _In_ PKSPIN Pin
+)
+/*++
+
+Routine Description:
+
+ Static thunking function to forward Reset
+
+Arguments:
+
+ Pin -
+ Our pin
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ NT_ASSERT( Pin );
+ NT_ASSERT( Pin->Context );
+ if( Pin && Pin->Context )
+ {
+ CCapturePin *pPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+ Status = pPin->Connect( );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+void
+CCapturePin::
+DispatchDisconnect(
+ _In_ PKSPIN Pin
+)
+/*++
+
+Routine Description:
+
+ Static thunking function to forward Disconnect
+
+Arguments:
+
+ Pin -
+ Our pin
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ DBG_ENTER("()");
+
+ NT_ASSERT( Pin );
+ NT_ASSERT( Pin->Context );
+ if( Pin && Pin->Context )
+ {
+ CCapturePin *pPin = reinterpret_cast <CCapturePin *> (Pin->Context);
+ pPin->Disconnect( );
+ }
+ DBG_LEAVE("()");
+}
+
+
+NTSTATUS
+CCapturePin::
+Close(
+ _In_ PIRP Irp
+)
+/*++
+
+Routine Description:
+
+ Close handler.
+
+ Replace or overload if you need special handling.
+
+Arguments:
+
+ Irp -
+ The IRP the request came in on.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ // Some reasonable default behavior.
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CCapturePin::
+SetFormat(
+ _In_opt_ PKSDATAFORMAT OldFormat,
+ _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
+ _In_ const KSDATARANGE *DataRange,
+ _In_opt_ const KSATTRIBUTE_LIST *AttributeRange
+)
+/*++
+
+Routine Description:
+
+ SetFormat handler.
+
+ Replace or overload if you need special handling.
+
+Arguments:
+
+ 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
+
+--*/
+{
+ PAGED_CODE( );
+
+ // Some reasonable default behavior here.
+ return STATUS_SUCCESS;
+}
+
+void
+CCapturePin::
+Reset()
+/*++
+
+Routine Description:
+
+ Reset handler.
+
+ Replace or overload if you need special handling.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PAGED_CODE( );
+
+ // Some reasonable default behavior here.
+ m_Sensor->Reset(m_Pin);
+}
+
+NTSTATUS
+CCapturePin::
+Connect()
+/*++
+
+Routine Description:
+
+ Connect handler.
+
+ Replace or overload if you need special handling.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ // Some reasonable default behavior here.
+ return STATUS_SUCCESS;
+}
+
+void
+CCapturePin::
+Disconnect()
+/*++
+
+Routine Description:
+
+ Disconnect handler.
+
+ Replace or overload if you need special handling.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PAGED_CODE( );
+
+ // Some reasonable default behavior here.
+}
+
+// Update the Pin's Allocator Framing
+NTSTATUS
+CCapturePin::
+UpdateAllocatorFraming()
+{
+ PAGED_CODE();
+
+ // Acquire the lock and update the Pin's allocator framing.
+ NTSTATUS Status =
+ KsEdit( m_Pin, &m_Pin->Descriptor, AVSHWS_POOLTAG);
+
+ if( NT_SUCCESS( Status ) )
+ {
+ //
+ // If the edits proceeded without running out of memory, adjust
+ // the framing based on the video info header.
+ //
+ Status = KsEdit( m_Pin, &m_Pin->Descriptor->AllocatorFraming, AVSHWS_POOLTAG );
+
+ 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> (
+ m_Pin->Descriptor->AllocatorFraming
+ );
+
+ Framing->FramingItem[0].Frames = m_DesiredFrames;
+ Framing->FramingItem[0].PhysicalRange.MinFrameSize = m_VideoInfoHeader->bmiHeader.biSizeImage;
+ Framing->FramingItem[0].PhysicalRange.MaxFrameSize = m_VideoInfoHeader->bmiHeader.biSizeImage;
+ Framing->FramingItem [0].FramingRange.Range.MinFrameSize = m_VideoInfoHeader->bmiHeader.biSizeImage;
+ Framing->FramingItem [0].FramingRange.Range.MaxFrameSize = m_VideoInfoHeader->bmiHeader.biSizeImage;
+
+ Framing->FramingItem [0].PhysicalRange.Stepping = 0;
+ Framing->FramingItem [0].FramingRange.Range.Stepping = 0;
+
+ DBG_TRACE( "Advertising Frame requirement: %d", m_DesiredFrames );
+ DBG_TRACE("Image size estimate of: %d bytes", m_VideoInfoHeader->bmiHeader.biSizeImage );
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X",Status);
+ return Status;
+}
+
diff --git a/AVStream/avscamera/sys/Capture.h b/AVStream/avscamera/sys/Capture.h
new file mode 100644
index 00000000..0fd87101
--- /dev/null
+++ b/AVStream/avscamera/sys/Capture.h
@@ -0,0 +1,305 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ capture.h
+
+ Abstract:
+
+ This file contains header for the base capture pin class for a filter.
+ The camera sample performs "fake" DMA directly into the capture
+ buffers. Common buffer DMA will work slightly differently.
+
+ For common buffer DMA, the general technique would be DPC schedules
+ processing with KsPinAttemptProcessing. The processing routine grabs
+ the leading edge, copies data out of the common buffer and advances.
+ Cloning would not be necessary with this technique. It would be
+ similiar to the way "AVSSamp" works, but it would be pin-centric.
+
+ History:
+
+ created 3/8/2001
+
+**************************************************************************/
+
+#pragma once
+#include <initguid.h>
+
+#define DMAX_X 640
+#define DMAX_Y 480
+#define D_X 320
+#define D_Y 240
+
+#define DMAX_X_OS 728
+#define DMAX_Y_OS 576
+#define D_X_OS 384
+#define D_Y_OS 240
+
+///////////////////////////////////////////////////////////////////////////////
+// GUID for primary and FFC cameras
+///////////////////////////////////////////////////////////////////////////////
+// {9D9A0F5E-CDE9-49f5-B464-BF13429DDEB5}
+DEFINE_GUID(PRIMARY_CAMERA_GUID,
+ 0x9d9a0f5e, 0xcde9, 0x49f5, 0xb4, 0x64, 0xbf, 0x13, 0x42, 0x9d, 0xde, 0xb5);
+
+// {75D53C4E-963E-4415-AA88-89107F08D1EE}
+DEFINE_GUID(FRONT_FACING_CAMERA_GUID,
+ 0x75d53c4e, 0x963e, 0x4415, 0xaa, 0x88, 0x89, 0x10, 0x7f, 0x8, 0xd1, 0xee);
+
+/*
+#define Mpx12_X 4160
+#define Mpx12_Y 3120
+#define Mpx5_X 2592
+#define Mpx5_Y 1944
+#define Mpx8_X 3264
+#define Mpx8_Y 2448
+*/
+//
+// STREAM_POINTER_CONTEXT:
+//
+// This is the context structure we associate with all clone stream pointers.
+// It allows the mapping code to rip apart the buffer into chunks the same
+// size as the scatter/gather mappings in order to fake scatter / gather
+// bus-master DMA.
+//
+typedef struct _STREAM_POINTER_CONTEXT
+{
+
+ PUCHAR BufferVirtual;
+
+} STREAM_POINTER_CONTEXT, *PSTREAM_POINTER_CONTEXT;
+
+//
+// CCapturePin:
+//
+// The video capture pin class.
+//
+class CCapturePin :
+ public ICapturePin,
+ public CNonCopyable
+{
+protected:
+ PKSPIN m_Pin; // The AVStream pin we're associated with.
+ CCaptureDevice *m_Device; // Pointer to the internal device object for our capture device.
+ CSensor *m_Sensor; // The h/w sensor simulation for the filter.
+ CHardwareSimulation *m_HardwareSimulation; // The h/w isp simulation for this pin, if the pin has been through KSSTATE_ACQUIRE.
+ PIN_STATE m_PinState; // The state we've put the hardware into.
+ PIKSREFERENCECLOCK m_Clock; // The clock we've been assigned.
+ BOOLEAN m_PendIo; // An indication of whether or not we pended I/O for some reason.
+ BOOLEAN m_AcquiredResources; // An indication of whether or not this pin has acquired the necessary hardware resources to operate.
+ PKS_VIDEOINFOHEADER m_VideoInfoHeader;
+ PKS_BITMAPINFOHEADER m_pBitmapInfoHeader; // Optional info for image formats.
+
+ //
+ // If we are unable to insert all of the mappings in a stream pointer into
+ // the "fake" hardware's scatter / gather table, we set this to the
+ // stream pointer that's incomplete. This is done both to make the
+ // relasing easier and to make it easier to fake the scatter / gather
+ // hardware.
+ //
+ PKSSTREAM_POINTER m_PreviousStreamPointer;
+ LONGLONG m_PresentationTime;
+ LONGLONG m_FrameNumber;
+ LONGLONG m_DroppedFrames;
+
+ ULONG m_DesiredFrames;
+
+ //
+ // ReleaseAllFrames():
+ //
+ // Clean up any references we hold on frames in the queue. This is called
+ // when we abruptly stop the fake hardware.
+ //
+ NTSTATUS
+ ReleaseAllFrames ();
+
+ static
+ void
+ Cleanup (
+ _In_ CCapturePin *Pin)
+ {
+ delete Pin;
+ }
+
+ //
+ // Emit metadata here for video or preview pin.
+ //
+ virtual
+ void
+ EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+ );
+
+ // Helper function for finding our filter object.
+ CCaptureFilter *
+ GetFilter()
+ {
+ return reinterpret_cast <CCaptureFilter *>
+ (KsPinGetParentFilter(m_Pin)->Context);
+ }
+
+ virtual
+ NTSTATUS
+ Close(
+ _In_ PIRP Irp
+ );
+
+ // Intended to give the pin an opportunity to do something extra with the selected format.
+ virtual
+ NTSTATUS
+ SetFormat(
+ _In_opt_ PKSDATAFORMAT OldFormat,
+ _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
+ _In_ const KSDATARANGE *DataRange,
+ _In_opt_ const KSATTRIBUTE_LIST *AttributeRange
+ );
+
+ virtual
+ NTSTATUS
+ Process( );
+
+ virtual
+ NTSTATUS
+ SetState(
+ _In_ KSSTATE ToState,
+ _In_ KSSTATE FromState
+ );
+
+ virtual
+ void
+ Reset();
+
+ virtual
+ NTSTATUS
+ Connect(); // Pin Connect
+
+ virtual
+ void
+ Disconnect(); // Pin Disconnect
+
+ virtual
+ NTSTATUS
+ CaptureBitmapInfoHeader( );
+
+ virtual
+ NTSTATUS
+ Initialize();
+
+public:
+ //
+ // CCapturePin():
+ //
+ // The capture pin's constructor. Initialize any non-0, non-NULL fields
+ // (since new will have zero'ed the memory anyway) and set up our
+ // device level pointers for access during capture routines.
+ //
+ CCapturePin( _In_ PKSPIN Pin);
+
+ //
+ // ~CCapturePin():
+ //
+ // The capture pin's destructor.
+ //
+ virtual
+ ~CCapturePin();
+
+ //
+ // ICapturePin::CompleteMapping()
+ //
+ // This is the capture pin notification mechanism for mapping completion.
+ // When the device detects that frames have been completed by the fake
+ // hardware, it informs the capture sink through this method.
+ //
+ virtual
+ NTSTATUS
+ CompleteMapping(
+ _In_ PKSSTREAM_POINTER Clone=nullptr
+ );
+
+ void
+ SetDesiredFrames( ULONG n )
+ {
+ m_DesiredFrames = n;
+ }
+
+ // Update the Pin's Allocator Framing
+ virtual
+ NTSTATUS
+ UpdateAllocatorFraming();
+
+ // TEST: Move this to a derived CCapturePin class - one
+ // specifically for testing, not as a sample.
+ static
+ bool
+ GetAcquireFailureKey();
+
+ PIN_STATE GetState() const
+ {
+ return m_PinState;
+ }
+
+ static
+ NTSTATUS
+ DispatchClose(
+ _In_ PKSPIN Pin,
+ _In_ PIRP Irp
+ );
+ static NTSTATUS DispatchSetState(
+ _In_ PKSPIN Pin,
+ _In_ KSSTATE ToState,
+ _In_ KSSTATE FromState
+ );
+
+ static NTSTATUS DispatchSetFormat(
+ _In_ PKSPIN Pin,
+ _In_opt_ PKSDATAFORMAT OldFormat,
+ _In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
+ _In_ const KSDATARANGE *DataRange,
+ _In_opt_ const KSATTRIBUTE_LIST *AttributeRange
+ );
+
+ static NTSTATUS DispatchProcess( _In_ PKSPIN Pin );
+
+ static void DispatchReset( _In_ PKSPIN );
+ static NTSTATUS DispatchConnect( _In_ PKSPIN Pin ); // Pin Connect
+ static void DispatchDisconnect( _In_ PKSPIN Pin ); // Pin Disconnect
+
+ static
+ NTSTATUS
+ IntersectHandler(
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp,
+ _In_ PKSP_PIN PinInstance,
+ _In_ PKSDATARANGE CallerDataRange,
+ _In_ PKSDATARANGE DescriptorDataRange,
+ _In_ ULONG BufferSize,
+ _Out_opt_ PVOID Data OPTIONAL,
+ _Out_ PULONG DataSize
+ );
+};
+
+//
+// Define a dispatch table for a capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc. using naming
+// conventions shared by all CCapturePin derived classes.
+//
+#define DEFINE_CAMERA_KSPIN_DISPATCH( Table, Class ) \
+const \
+KSPIN_DISPATCH \
+Table ={ \
+ Class::DispatchCreate, /* Pin Create */ \
+ Class::DispatchClose, /* Pin Close */ \
+ Class::DispatchProcess, /* Pin Process */ \
+ Class::DispatchReset, /* Pin Reset */ \
+ Class::DispatchSetFormat, /* Pin Set Data Format */ \
+ Class::DispatchSetState, /* Pin Set Device State */ \
+ Class::DispatchConnect, /* Pin Connect */ \
+ Class::DispatchDisconnect, /* Pin Disconnect */ \
+ NULL, /* Clock Dispatch */ \
+ NULL /* Allocator Dispatch */ \
+};
+
diff --git a/AVStream/avscamera/sys/Common.h b/AVStream/avscamera/sys/Common.h
new file mode 100644
index 00000000..deb6bf4c
--- /dev/null
+++ b/AVStream/avscamera/sys/Common.h
@@ -0,0 +1,703 @@
+
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2015, Microsoft Corporation.
+
+ File:
+
+ Common.h
+
+ Abstract:
+
+ Common project header.
+
+ History:
+
+ created 02/18/2015
+
+**************************************************************************/
+
+#pragma once
+
+#define _NO_SYS_GUID_OPERATOR_EQ_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <wdm.h>
+#include <windef.h>
+#include <unknown.h>
+#include <ks.h>
+#include <ksmedia.h>
+#include <kcom.h>
+#include <stdunk.h>
+#include <ntstrsafe.h>
+#define NOBITMAP
+#include <mmreg.h>
+#undef NOBITMAP
+#include <acpitabl.h>
+
+#include "MetadataInternal.h"
+#include "CustomProperties.h"
+#include "Dbg.h"
+
+/*************************************************
+
+ Add definitions that are missing for C++14.
+
+*************************************************/
+
+/*++
+
+Routine Description:
+
+ Array new() operator for creating objects with a specified allocation tag.
+
+Arguments:
+
+ iSize -
+ The size of the entire allocation.
+
+ poolType -
+ The type of allocation. Ex: PagedPool or NonPagedPoolNx
+
+ tag -
+ A 4-byte allocation identifier.
+
+Return Value:
+
+ None
+
+--*/
+inline
+PVOID
+operator new[](
+ size_t iSize,
+ _When_((poolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+ POOL_TYPE poolType,
+ ULONG tag
+)
+{
+ PVOID result = ExAllocatePoolWithTag(poolType, iSize, tag);
+
+ if (result)
+ {
+ RtlZeroMemory(result, iSize);
+ }
+
+ return result;
+}
+
+/*++
+
+Routine Description:
+
+ Array delete() operator.
+
+Arguments:
+
+ pVoid -
+ The memory to free.
+
+Return Value:
+
+ None
+
+--*/
+inline
+void
+__cdecl
+operator delete[](
+ PVOID pVoid
+)
+{
+ if (pVoid)
+ {
+ ExFreePool(pVoid);
+ }
+}
+
+/*++
+
+Routine Description:
+
+ Sized delete() operator.
+
+Arguments:
+
+ pVoid -
+ The memory to free.
+
+ size -
+ The size of the memory to free.
+
+Return Value:
+
+ None
+
+--*/
+inline void __cdecl operator delete
+(
+ void *pVoid,
+ size_t /*size*/
+)
+{
+ if (pVoid)
+ {
+ ExFreePool(pVoid);
+ }
+}
+
+/*++
+
+Routine Description:
+
+ Sized delete[]() operator.
+
+Arguments:
+
+ pVoid -
+ The memory to free.
+
+ size -
+ The size of the memory to free.
+
+Return Value:
+
+ None
+
+--*/
+inline void __cdecl operator delete[]
+(
+ void *pVoid,
+ size_t /*size*/
+)
+{
+ if (pVoid)
+ {
+ ExFreePool(pVoid);
+ }
+}
+
+/*************************************************
+
+ Misc Definitions
+
+*************************************************/
+#pragma warning (disable : 4100 4127 4131 4189 4701 4706)
+#define STR_MODULENAME "AvsCamera: "
+
+#define IFFAILED_EXIT(status) \
+ if (!NT_SUCCESS( Status = (status) )) \
+ { \
+ goto done; \
+ }
+
+#define IFNULL_EXIT(exp) \
+ if ( (exp) == nullptr ) \
+ { \
+ Status = STATUS_INSUFFICIENT_RESOURCES; \
+ goto done; \
+ }
+
+//
+// Number of 100ns in one second
+//
+#define ONESECOND 10000000
+
+#define ABS(x) ((x) < 0 ? (-(x)) : (x))
+
+#ifndef mmioFOURCC
+#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
+ ( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \
+ ( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) )
+#endif
+
+#define FOURCC_YUY2 mmioFOURCC('Y', 'U', 'Y', '2')
+#define FOURCC_NV12 mmioFOURCC('N', 'V', '1', '2')
+
+// RGB24
+#define STATIC_KSDATAFORMAT_SUBTYPE_RGB24\
+ 0xe436eb7d, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70
+DEFINE_GUIDSTRUCT("e436eb7d-524f-11ce-9f53-0020af0ba770", KSDATAFORMAT_SUBTYPE_RGB24);
+#define KSDATAFORMAT_SUBTYPE_RGB24 DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_RGB24)
+
+// RGB32
+#define STATIC_KSDATAFORMAT_SUBTYPE_RGB32\
+ 0xe436eb7e, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70
+DEFINE_GUIDSTRUCT("e436eb7e-524f-11ce-9f53-0020af0ba770", KSDATAFORMAT_SUBTYPE_RGB32);
+#define KSDATAFORMAT_SUBTYPE_RGB32 DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_RGB32)
+
+// NV12
+#define STATIC_KSDATAFORMAT_SUBTYPE_NV12\
+ 0x3231564E, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+DEFINE_GUIDSTRUCT("3231564E-0000-0010-8000-00AA00389B71", KSDATAFORMAT_SUBTYPE_NV12);
+#define KSDATAFORMAT_SUBTYPE_NV12 DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_NV12)
+
+// YUY2
+#define STATIC_KSDATAFORMAT_SUBTYPE_YUY2\
+ 0x32595559, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+DEFINE_GUIDSTRUCT("32595559-0000-0010-8000-00AA00389B71", KSDATAFORMAT_SUBTYPE_YUY2);
+#define KSDATAFORMAT_SUBTYPE_YUY2 DEFINE_GUIDNAMED(KSDATAFORMAT_SUBTYPE_YUY2)
+
+#define CAPTURE_FILTER_COUNT 2
+
+//filter index
+#define CAPTURE_FILTER_RFC 0
+#define CAPTURE_FILTER_FFC 1
+
+//Arbitrary Maximum faces
+#define MAX_FACES 15
+
+//
+// CAPTURE_PIN_DATA_RANGE_COUNT:(formats)
+//
+// The number of ranges supported on the capture pin.
+//
+#define IMAGE_CAPTURE_PIN_DATA_RANGE_COUNT 2
+#define VIDEO_CAPTURE_PIN_DATA_RANGE_COUNT 30
+#define VIDEO_PREVIEW_PIN_DATA_RANGE_COUNT 15
+
+//
+// Define the number of frames needed in the queue for each pin.
+//
+#define IMAGE_CAPTURE_PIN_MINIMUM_FRAMES 3
+#define VIDEO_CAPTURE_PIN_MINIMUM_FRAMES 4
+#define PREVIEW_PIN_MINIMUM_FRAMES 6
+#define IMAGE_CAPTURE_PIN_MAXIMUM_FRAMES 20
+#define IMAGE_CAPTURE_PIN_MAXIMUM_HISTORY_FRAMES 10
+
+//
+// CAPTURE_FILTER_CATEGORIES_COUNT:
+//
+// The number of categories for the capture filter.
+//
+#define CAPTURE_FILTER_CATEGORIES_COUNT 3
+
+#define AVSHWS_POOLTAG 'hSVA'
+
+//
+// Focal length definitions
+//
+
+// These are the definitions found in MSDN for the legacy zoom controls.
+//
+//#define FOCALLENGTH_OCULAR 50
+//#define FOCALLENGTH_OPTICAL_MIN 10
+//#define FOCALLENGTH_OPTICAL_MAX 600
+
+//#define FOCALLENGTH_OCULAR 50
+//#define FOCALLENGTH_OPTICAL_MIN 10
+//#define FOCALLENGTH_OPTICAL_MAX 600
+
+// Note: Despite what MSDN says, they are NOT limits as far as the
+// pipeline is conerned. You should supply values here that are
+// appropriate to your hardware - whatever that may be.
+//
+// Also note that since both optical and ocular focal length are
+// nomally measured in millimeters, and since the optical length is
+// always the numerator and ocular is used as the denominator, the
+// units (millimeters) cancel out. This means you can stick any set
+// of values you like here that can be used to represent the min and
+// maximum zoom value of your hardware as a simple rational number.
+//
+// Again, the rational number is: (Objective length / Ocular length)
+//
+// We use the following definitions in this simulation in order to have the
+// values produced and used in the legacy control be the same as the ones
+// in the new extended zoom control.
+//
+#define FOCALLENGTH_OCULAR (1<<16) // Denominator of 2^16 makes this the same as Q16 format in extended.
+#define FOCALLENGTH_OPTICAL_MIN (FOCALLENGTH_OCULAR/16) // Allow a wide-field view of 1/16th.
+#define FOCALLENGTH_OPTICAL_MAX (FOCALLENGTH_OCULAR*32) // Allow a zoom-in view of 32x.
+
+// Values for Power Line Frequency
+#define POWERLINEFREQ_DISABLED 0
+#define POWERLINEFREQ_50HZ 1
+#define POWERLINEFREQ_60HZ 2
+#define POWERLINEFREQ_AUTO 3
+#define POWERLINEFREQ_DEFAULT POWERLINEFREQ_DISABLED
+
+
+//
+// Q-format definitions.
+//
+#define BASE_Q(n) (((ULONGLONG)1)<<n)
+#define TO_Q31(_x_) (LONGLONG)( (_x_) * BASE_Q(31) )
+#define TO_Q16(_x_) (LONGLONG)( (_x_) * BASE_Q(16) )
+#define FROM_Q16(_x_, _denominator_) ((LONG)( (LONGLONG)(_x_) / ( TO_Q16(1) / (LONGLONG)(_denominator_)) ))
+
+#define MULT_Q16(_x_, _y_) (LONGLONG)((((LONGLONG)(_x_) * (LONGLONG)(_y_)) + (BASE_Q(15)))>>16)
+#define DIV_Q16(_x_, _y_) (LONGLONG)((((LONGLONG)(_x_)<<16)+(_y_/2))/(LONGLONG)(_y_))
+
+#define MAKEWORD(a, b) ((WORD)(((BYTE)(((DWORD_PTR)(a)) & 0xff)) | ((WORD)((BYTE)(((DWORD_PTR)(b)) & 0xff))) << 8))
+#define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16))
+
+//
+// Copy of histogram channel bitmask definitions from mfapi.h (not available in wdk).
+//
+#define MF_HISTOGRAM_CHANNEL_Y 0x00000001
+#define MF_HISTOGRAM_CHANNEL_R 0x00000002
+#define MF_HISTOGRAM_CHANNEL_G 0x00000004
+#define MF_HISTOGRAM_CHANNEL_B 0x00000008
+#define MF_HISTOGRAM_CHANNEL_Cb 0x00000010
+#define MF_HISTOGRAM_CHANNEL_Cr 0x00000020
+
+/*************************************************
+
+ Externed information
+
+*************************************************/
+//
+// filter.cpp externs:
+//
+extern
+const
+KSFILTER_DISPATCH
+AvsCameraFilterDispatch;
+
+extern
+const
+KSFILTER_DESCRIPTOR
+AvsCameraFilterDescriptor;
+
+extern
+const
+KSFILTER_DESCRIPTOR
+AvsCameraFilterDescriptorFFC;
+
+extern
+const
+GUID
+AvsCameraFilterCategories [CAPTURE_FILTER_CATEGORIES_COUNT];
+
+//
+// capture.cpp externs:
+//
+extern
+const
+KSALLOCATOR_FRAMING_EX
+VideoCapturePinAllocatorFraming;
+
+extern
+const
+KSALLOCATOR_FRAMING_EX
+ImageCapturePinAllocatorFraming;
+
+extern
+const
+KSPIN_DISPATCH
+VideoCapturePinDispatch;
+
+extern
+const
+KSPIN_DISPATCH
+ImageCapturePinDispatch;
+
+/*************************************************
+
+ Enums / Typedefs
+
+*************************************************/
+
+typedef enum _PIN_STATE
+{
+
+ PinStopped = 0,
+ PinPaused,
+ PinRunning
+
+} PIN_STATE, *PPIN_STATE;
+
+typedef enum _PIN_MODE
+{
+
+ PinNormalMode = 0,
+ PinBurstMode
+
+} PIN_MODE, *PPIN_MODE;
+
+//Panel surface bits 115:118
+enum AcpiPldRotation
+{
+ AcpiPldRotation0 = 0,
+ AcpiPldRotation45 = 1,
+ AcpiPldRotation90 = 2,
+ AcpiPldRotation135 = 3,
+ AcpiPldRotation180 = 4,
+ AcpiPldRotation225 = 5,
+ AcpiPldRotation270 = 6,
+ AcpiPldRotation315 = 7,
+};
+
+
+/*************************************************
+
+ Class Definitions
+
+*************************************************/
+
+struct ISP_FRAME_SETTINGS
+{
+ ULONGLONG ISOMode;
+ ULONG ISOValue; // for Manual ISO settings.
+ KSCAMERA_EXTENDEDPROP_EVCOMPENSATION EVCompensation;
+ ULONGLONG WhiteBalanceMode;
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING WhiteBalanceSetting;
+ ULONGLONG ExposureMode;
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING ExposureSetting;
+ ULONGLONG FocusMode;
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING FocusSetting;
+ ULONGLONG FocusPriority;
+ ULONGLONG FlashMode;
+ ULONG FlashValue; // Adjustable power setting (0-100)
+ BOOLEAN bPhotoConfirmation;
+} ;
+
+struct SOC_CAP_WITH_STEPPING
+{
+ KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER Hdr;
+ KSPROPERTY_STEPPING_LONG Stepping;
+} ;
+
+struct SOC_CAP_WITH_STEPPING_LONGLONG
+{
+ KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER Hdr;
+ KSPROPERTY_STEPPING_LONGLONG Stepping;
+} ;
+
+//
+// ICapturePin:
+//
+// This is a capture pin interface. The device level calls back the
+// CompleteMapping method passing the number of completed mappings for
+// the capture pin.
+//
+class ICapturePin
+{
+
+public:
+
+ virtual
+ NTSTATUS
+ CompleteMapping(
+ _In_ PKSSTREAM_POINTER Clone=nullptr
+ ) = 0;
+
+};
+
+class LockDevice
+{
+public:
+
+ LockDevice(PKSDEVICE device) : m_device(device)
+ {
+ NT_ASSERT(m_device);
+ KsAcquireDevice(m_device);
+ }
+
+ ~LockDevice()
+ {
+ KsReleaseDevice(m_device);
+ }
+private:
+ PKSDEVICE m_device;
+};
+
+class LockFilter
+{
+public:
+
+ LockFilter(PKSFILTER filter) : m_filter(filter)
+ {
+ NT_ASSERT(m_filter);
+ KsFilterAcquireControl(m_filter);
+ }
+
+ ~LockFilter()
+ {
+ KsFilterReleaseControl(m_filter);
+ }
+private:
+ PKSFILTER m_filter;
+};
+
+// The following class definitions and ctors are used solely
+// to simplify initialization of the parent metadata structures.
+// They are not here for any other purpose.
+
+template <class T, class U>
+class CMetaRational : public U
+{
+public:
+ CMetaRational( T Num=1, T Denom=1 )
+ {
+ Set=TRUE;
+ Numerator = Num;
+ Denominator = Denom;
+ }
+};
+
+typedef CMetaRational<UINT32, METADATA_RATIONAL> CMetadataRational;
+typedef CMetaRational<INT32, METADATA_SRATIONAL> CMetadataSRational;
+
+template <class T, class U>
+class CMetaPrimative : public U
+{
+public:
+ CMetaPrimative( T n )
+ {
+ Set = TRUE;
+ Value = n;
+ }
+};
+
+typedef CMetaPrimative<UINT16, METADATA_UINT16> CMetadataShort;
+typedef CMetaPrimative<UINT32, METADATA_UINT32> CMetadataLong;
+typedef CMetaPrimative<INT64, METADATA_INT64> CMetadataLongLong;
+typedef CMetaPrimative<UINT64, METADATA_UINT64> CMetadataULongLong;
+
+class CMetadataShortString : public METADATA_SHORTSTRING
+{
+public:
+ CMetadataShortString(
+ _In_z_ const CHAR *str
+ )
+ {
+ Length = (UINT32) min(strlen(str), sizeof(String));
+ strncpy_s( String, str, Length );
+ }
+};
+
+class CMetadataEVCompensation : public METADATA_EVCOMP
+{
+public:
+ CMetadataEVCompensation(
+ _In_ UINT64 flags,
+ _In_ UINT32 value
+ )
+ {
+ Set = TRUE;
+ Flags = flags;
+ Value = value;
+ }
+};
+
+typedef struct
+{
+ LONG Value;
+ ULONG Flags;
+ ULONG Capabilities;
+} VIDCAP_PROPERTY, *PVIDCAP_PROPERTY;
+
+typedef struct
+{
+ LONG lOcularFocalLength;
+ LONG lObjectiveFocalLengthMin;
+ LONG lObjectiveFocalLengthMax;
+} FOCAL_LENGTH_PROPERTY, *PFOCAL_LENGTH_PROPERTY;
+
+const ULONG KSCAMERA_EXTENDEDPROP_VERSION = 1;
+
+//
+// Note: I cannot simplify this down to just the FrameIndex.
+// Past frames and non-VPS photos can have a photo confirmation set
+// and those images will not have an index associated with them.
+//
+class PHOTOCONFIRMATION_INFO
+{
+public:
+ PHOTOCONFIRMATION_INFO(
+ _In_ ULONG FrameIndex,
+ _In_ LONGLONG Time
+ )
+ : m_Index( FrameIndex )
+ , m_Time(Time)
+ , m_bRequired(TRUE)
+ {}
+
+ PHOTOCONFIRMATION_INFO()
+ : m_Index(0)
+ , m_Time(0)
+ , m_bRequired( FALSE )
+ {}
+
+ BOOL
+ isRequired()
+ {
+ return m_bRequired;
+ }
+
+ ULONG
+ getIndex()
+ {
+ return m_Index;
+ }
+
+ LONGLONG
+ getTime()
+ {
+ return m_Time;
+ }
+
+private:
+ BOOL m_bRequired;
+ ULONG m_Index;
+ LONGLONG m_Time;
+};
+
+/*************************************************
+
+ Global Functions
+
+*************************************************/
+
+/*************************************************
+
+ Internal Includes
+
+*************************************************/
+
+#include "util.h"
+#include "NonCopyable.h"
+#include "ref.h"
+#include "Mutex.h"
+#include "Waitable.h"
+#include "WorkItem.h"
+#include "Timer.h"
+#include "ExtendedProperty.h"
+#include "ExtendedVidProcSetting.h"
+#include "ExtendedEvComp.h"
+#include "ExtendedMetadata.h"
+#include "ExtendedPhotoMode.h"
+#include "ExtendedMaxVideoFpsForPhotoRes.h"
+#include "ExtendedFieldOfView.h"
+#include "ExtendedCameraAngleOffset.h"
+#include "CameraProfile.h"
+#include "Synthesizer.h"
+#include "XRGBSynthesizer.h"
+#include "RGB24Synthesizer.h"
+#include "YUVSynthesizer.h"
+#include "YUY2Synthesizer.h"
+#include "NV12Synthesizer.h"
+#include "hwsim.h"
+#include "ImageHwSim.h"
+#include "PreviewHwSim.h"
+#include "VideoHwSim.h"
+#include "device.h"
+#include "AvsCameraDevice.h"
+#include "Roi.h"
+#include "Sensor.h"
+#include "SensorSimulation.h"
+#include "filter.h"
+#include "AvsCameraFilter.h"
+#include "capture.h"
+#include "videocapture.h"
+#include "imagecapture.h"
+#include "formats.h"
+#include <uuids.h>
+#include <devpkey.h>
diff --git a/AVStream/avscamera/sys/Dbg.h b/AVStream/avscamera/sys/Dbg.h
new file mode 100644
index 00000000..b0bc6e80
--- /dev/null
+++ b/AVStream/avscamera/sys/Dbg.h
@@ -0,0 +1,81 @@
+/**************************************************************************
+
+ AVStream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ Dbg.h
+
+ Abstract:
+
+ Debug definitions.
+
+ History:
+
+ created 2/18/2015
+
+**************************************************************************/
+
+#pragma once
+
+#define DEBUGLVL_VERBOSE 2
+#define DEBUGLVL_TERSE 1
+#define DEBUGLVL_ERROR 0
+
+const int DebugLevel = DEBUGLVL_TERSE;
+
+#if (DBG)
+#define _DbgPrintF(lvl, strings) \
+{ \
+ if (lvl <= DebugLevel) {\
+ DbgPrint(STR_MODULENAME);\
+ DbgPrint##strings;\
+ DbgPrint("\n");\
+ if ((lvl) == DEBUGLVL_ERROR) {\
+ NT_ASSERT(0);\
+ } \
+ }\
+}
+#else // !DBG
+#define _DbgPrintF(lvl, strings)
+#endif // !DBG
+
+// This is for debug output; but we're going to leave it in the
+// driver for now. We can always turn off the Windbg output at
+// the debugger.
+// Enable via debugger: ed Kd_IHVSTREAMING_Mask 0xFFFFFFFF
+#define ENABLE_TRACING 1
+#if ENABLE_TRACING
+
+#define DBG_OUT( FMT, ... ) \
+ { \
+ LARGE_INTEGER SysTime; \
+ LARGE_INTEGER LocalTime; \
+ TIME_FIELDS TimeFields; \
+ \
+ KeQuerySystemTimePrecise( &SysTime ); \
+ ExSystemTimeToLocalTime( &SysTime, &LocalTime ); \
+ RtlTimeToTimeFields( &LocalTime, &TimeFields ); \
+ DbgPrintEx( DPFLTR_IHVSTREAMING_ID, DPFLTR_MASK|DPFLTR_TRACE_LEVEL, \
+ "%02d:%02d:%02d.%03d [%p] " ## FMT ## "\n", \
+ TimeFields.Hour, TimeFields.Minute, TimeFields.Second, TimeFields.Milliseconds, \
+ KeGetCurrentThread(), __VA_ARGS__ ); \
+ }
+
+#define DBG_ENTER( FMT, ... ) \
+ DBG_OUT( "Entering: " __FUNCTION__ ## FMT, __VA_ARGS__ );
+
+#define DBG_LEAVE( FMT, ... ) \
+ DBG_OUT( " Leaving: " __FUNCTION__ ## FMT, __VA_ARGS__ );
+
+#define DBG_TRACE( FMT, ... ) \
+ DBG_OUT( " In: " __FUNCTION__ ## " " ## FMT, __VA_ARGS__ );
+
+#else // !ENABLE_TRACING
+#define DBG_ENTER( ... )
+#define DBG_LEAVE( ... )
+#define DBG_TRACE( ... )
+#endif // !ENABLE_TRACING
+
diff --git a/AVStream/avscamera/sys/Device.cpp b/AVStream/avscamera/sys/Device.cpp
new file mode 100644
index 00000000..107cdafc
--- /dev/null
+++ b/AVStream/avscamera/sys/Device.cpp
@@ -0,0 +1,966 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ device.cpp
+
+ Abstract:
+
+ This file contains the implementation of CCaptureDevice.
+
+ CCaptureDevice is the base device class object. It handles basic PnP
+ requests and constructs the filter factories.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+/////
+/// Structures...
+//// Profile 0
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile0_PreviewMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+};
+
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile0_RecordMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 3840, 2160 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1920, 1080 }, { 120, 1 }, 0, 0, 0, 0, 0 },
+ { { 1920, 1080 }, { 90, 1 }, 0, 0, 0, 0, 0 },
+ { { 1920, 1080 }, { 60, 1 }, 0, 0, 0, 0, 0 },
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+};
+
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile0_PhotoMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 }
+};
+
+
+//// Profile 1
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile1_PreviewMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 }
+};
+
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile1_PhotoMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 7680, 4320 }, { 0, 1 }, 0, 0, 0, 0, 0 },
+ { { 3840, 2160 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 }
+};
+
+//// Profile 2
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile2_PreviewMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 }
+};
+
+static KSCAMERA_PROFILE_MEDIAINFO s_Profile2_RecordMediaInfo[] =
+{
+ //{ resolution }, { fps }, Flags, Data0, Data1, Data2, Data 3
+ { { 1920, 1080 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 1280, 720 }, { 30, 1 }, 0, 0, 0, 0, 0 },
+ { { 640, 360 }, { 30, 1 }, 0, 0, 0, 0, 0 }
+};
+
+static KSCAMERA_PROFILE_PININFO s_Profile0_PinInfo[] =
+{
+ { {STATIC_PINNAME_VIDEO_PREVIEW}, 0,0, ARRAYSIZE(s_Profile0_PreviewMediaInfo), s_Profile0_PreviewMediaInfo },
+ { {STATIC_PINNAME_VIDEO_CAPTURE}, 0,0, ARRAYSIZE(s_Profile0_RecordMediaInfo), s_Profile0_RecordMediaInfo },
+ { {STATIC_PINNAME_IMAGE}, 0,0, ARRAYSIZE(s_Profile0_PhotoMediaInfo), s_Profile0_PhotoMediaInfo }
+};
+
+static KSCAMERA_PROFILE_PININFO s_Profile1_PinInfo[] =
+{
+ { {STATIC_PINNAME_VIDEO_PREVIEW}, 0,0, ARRAYSIZE(s_Profile1_PreviewMediaInfo), s_Profile1_PreviewMediaInfo },
+ { {STATIC_PINNAME_IMAGE}, 0,0, ARRAYSIZE(s_Profile1_PhotoMediaInfo), s_Profile1_PhotoMediaInfo }
+};
+
+static KSCAMERA_PROFILE_PININFO s_Profile2_PinInfo[] =
+{
+ { {STATIC_PINNAME_VIDEO_PREVIEW}, 0,0, ARRAYSIZE(s_Profile2_PreviewMediaInfo), s_Profile2_PreviewMediaInfo },
+ { {STATIC_PINNAME_VIDEO_CAPTURE}, 0,0, ARRAYSIZE(s_Profile2_RecordMediaInfo), s_Profile2_RecordMediaInfo }
+};
+
+static KSCAMERA_PROFILE_INFO s_Profiles[] =
+{
+ { {STATIC_KSCAMERAPROFILE_BalancedVideoAndPhoto}, 0, ARRAYSIZE(s_Profile0_PinInfo), s_Profile0_PinInfo },
+ { {STATIC_KSCAMERAPROFILE_HighQualityPhoto}, 0, ARRAYSIZE(s_Profile1_PinInfo), s_Profile1_PinInfo },
+ { {STATIC_KSCAMERAPROFILE_VideoRecording}, 0, ARRAYSIZE(s_Profile2_PinInfo), s_Profile2_PinInfo }
+};
+
+// The front camera is concurrent with the rear camera, so the front camera concurrency
+// has the back camera's reference GUID and vice versa.
+static KSCAMERA_PROFILE_CONCURRENCYINFO s_Profile2_ConcurrencyInfoFront[] =
+{
+ { {STATIC_RearCamera_Filter}, 0, 1, &s_Profiles[2] }
+};
+
+static KSCAMERA_PROFILE_CONCURRENCYINFO s_Profile2_ConcurrencyInfoBack[] =
+{
+ { {STATIC_FrontCamera_Filter}, 0, 1, &s_Profiles[2] }
+};
+
+const UINT32 s_ProfileCount = 3;
+
+UINT32
+InitializeDeviceProfiles(
+ _In_ BOOL fFrontCamera,
+ _Outptr_result_maybenull_
+ PKSDEVICE_PROFILE_INFO *ppDeviceProfiles
+)
+{
+ UINT32 uiProfileCount = 0;
+ PKSDEVICE_PROFILE_INFO pDeviceProfiles = NULL;
+
+ pDeviceProfiles = (PKSDEVICE_PROFILE_INFO)ExAllocatePoolWithTag( PagedPool, sizeof(KSDEVICE_PROFILE_INFO) * ARRAYSIZE(s_Profiles) , 'fpSC');
+ if( !pDeviceProfiles )
+ {
+ // Can't publish, we're out of memory, silently fail here.
+ *ppDeviceProfiles = nullptr;
+ goto Exit;
+ }
+
+ for (UINT32 i = 0; i < ARRAYSIZE(s_Profiles); i++)
+ {
+ pDeviceProfiles[i].Type = KSDEVICE_PROFILE_TYPE_CAMERA;
+ pDeviceProfiles[i].Size = sizeof(KSDEVICE_PROFILE_INFO);
+ pDeviceProfiles[i].Camera.Info = s_Profiles[i];
+ pDeviceProfiles[i].Camera.Reserved = 0;
+ pDeviceProfiles[i].Camera.ConcurrencyCount = 0;
+ pDeviceProfiles[i].Camera.Concurrency = NULL;
+ }
+
+ pDeviceProfiles[2].Camera.ConcurrencyCount = 1;
+ if (fFrontCamera)
+ {
+ pDeviceProfiles[2].Camera.Concurrency = (PKSCAMERA_PROFILE_CONCURRENCYINFO)&s_Profile2_ConcurrencyInfoFront;
+ }
+ else
+ {
+ pDeviceProfiles[2].Camera.Concurrency = (PKSCAMERA_PROFILE_CONCURRENCYINFO)&s_Profile2_ConcurrencyInfoBack;
+ }
+
+ uiProfileCount = ARRAYSIZE(s_Profiles);
+ *ppDeviceProfiles = pDeviceProfiles;
+ pDeviceProfiles = NULL;
+
+Exit:
+ return uiProfileCount;
+}
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+CCaptureDevice::
+CCaptureDevice (
+ _In_ PKSDEVICE Device
+)
+ : m_Device (Device)
+ , m_FilterDescriptorCount(0)
+ , m_Sensor(nullptr)
+ , m_Context(nullptr)
+{
+ PAGED_CODE();
+}
+
+CCaptureDevice::
+~CCaptureDevice()
+{
+ PAGED_CODE();
+
+ if( m_Sensor )
+ {
+ for( size_t i=0; i<m_FilterDescriptorCount; i++ )
+ {
+ SAFE_DELETE( m_Sensor[i] );
+ }
+
+ SAFE_DELETE_ARRAY( m_Sensor );
+ }
+}
+
+NTSTATUS
+CCaptureDevice::
+Initialize()
+{
+ PAGED_CODE();
+
+ m_Sensor = new (NonPagedPoolNx, 'iveD') CSensor *[m_FilterDescriptorCount];
+
+ if( !m_Sensor )
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ return STATUS_SUCCESS;
+}
+
+ULONG
+CCaptureDevice::
+GetFilterIndex(PKSFILTER Filter)
+{
+ PAGED_CODE();
+ ULONG i;
+
+ for( i=0; i<m_FilterDescriptorCount; i++ )
+ {
+ if( Filter->Descriptor->ReferenceGuid &&
+ IsEqualGUID(*(m_Context[i].Descriptor->ReferenceGuid), *Filter->Descriptor->ReferenceGuid))
+ {
+ break;
+ }
+ }
+
+ // This is a complete failure. We really need to bail.
+ NT_ASSERT(i<m_FilterDescriptorCount);
+
+ return i;
+}
+
+NTSTATUS
+CCaptureDevice::
+Prepare()
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = Initialize();
+
+ if( !NT_SUCCESS(Status) )
+ {
+ return Status;
+ }
+
+ //
+ // Add the item to the object bag if we were successful.
+ // Whenever the device goes away, the bag is cleaned up and
+ // we will be freed.
+ //
+ // For backwards compatibility with DirectX 8.0, we must grab
+ // the device mutex before doing this. For Windows XP, this is
+ // not required, but it is still safe.
+ //
+ PKSDEVICE Device = m_Device;
+ LockDevice Lock(Device);
+
+ Status = KsAddItemToObjectBag (
+ Device -> Bag,
+ reinterpret_cast <PVOID> (this),
+ reinterpret_cast <PFNKSFREE> (CCaptureDevice::Cleanup)
+ );
+
+ if( NT_SUCCESS (Status) )
+ {
+ Device->Context=this;
+ }
+ return Status;
+}
+
+NTSTATUS
+CCaptureDevice::
+DispatchCreate (
+ _In_ PKSDEVICE Device
+)
+
+/*++
+
+Routine Description:
+
+ Create the capture device. This is the creation dispatch for the
+ capture device.
+
+Arguments:
+
+ Device -
+ The AVStream device being created.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ CCaptureDevice *CapDevice = new (NonPagedPoolNx, 'eviD') CCaptureDevice (Device);
+ if( !CapDevice)
+ {
+ //
+ // Return failure if we couldn't create the device.
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ NTSTATUS Status = CapDevice->Prepare();
+ if (!NT_SUCCESS (Status))
+ {
+ // Init failure.
+ delete CapDevice;
+ }
+
+ DBG_LEAVE("()");
+ return Status;
+}
+
+//
+// DispatchStart():
+//
+// This is the Pnp Start dispatch for the capture device. It simply
+// bridges to PnpStart() in the context of the CCaptureDevice.
+//
+NTSTATUS
+CCaptureDevice::
+DispatchStart (
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _In_ PCM_RESOURCE_LIST TranslatedResourceList,
+ _In_ PCM_RESOURCE_LIST UntranslatedResourceList
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ NTSTATUS Status =
+ Recast(Device)->
+ PnpStart (
+ TranslatedResourceList,
+ UntranslatedResourceList
+ );
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+//
+// DispatchStop():
+//
+// This is the Pnp stop dispatch for the capture device. It simply
+// bridges to PnpStop() in the context of the CCaptureDevice.
+//
+void
+CCaptureDevice::
+DispatchStop (
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+ Recast(Device)->PnpStop(Irp);
+ DBG_LEAVE("()");
+}
+
+NTSTATUS
+CCaptureDevice::
+DispatchPostStart(
+ _In_ PKSDEVICE Device
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ NTSTATUS Status =
+ Recast(Device)->PnpPostStart();
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+NTSTATUS
+CCaptureDevice::
+DispatchQueryStop(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ NTSTATUS Status =
+ Recast(Device)->PnpQueryStop(Irp);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+void
+CCaptureDevice::
+DispatchCancelStop(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+ Recast(Device)->PnpCancelStop(Irp);
+ DBG_LEAVE("()");
+}
+
+NTSTATUS
+CCaptureDevice::
+DispatchQueryRemove(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ NTSTATUS Status =
+ Recast(Device)->PnpQueryRemove(Irp);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+void
+CCaptureDevice::
+DispatchCancelRemove(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+ Recast(Device)->PnpCancelRemove(Irp);
+ DBG_LEAVE("()");
+}
+
+void
+CCaptureDevice::
+DispatchRemove(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+ Recast(Device)->PnpRemove(Irp);
+ DBG_LEAVE("()");
+}
+
+void
+CCaptureDevice::
+DispatchSurpriseRemoval(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+ Recast(Device)->PnpSurpriseRemoval(Irp);
+ DBG_LEAVE("()");
+}
+
+NTSTATUS
+CCaptureDevice::
+DispatchQueryCapabilities(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _Inout_ PDEVICE_CAPABILITIES Capabilities
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ NTSTATUS Status =
+ Recast(Device)->
+ PnpQueryCapabilities( Irp, Capabilities );
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+
+// Make Power callbacks non-pageable.
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+CCaptureDevice::
+DispatchQueryPower(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE DeviceTo,
+ _In_ DEVICE_POWER_STATE DeviceFrom,
+ _In_ SYSTEM_POWER_STATE SystemTo,
+ _In_ SYSTEM_POWER_STATE SystemFrom,
+ _In_ POWER_ACTION Action
+)
+{
+ // If this device supports the the DO_POWER_INRUSH flag, this function
+ // can be called at DISPATCH.
+
+ DBG_ENTER("()");
+ NTSTATUS Status =
+ Recast(Device)->
+ PnpQueryPower(
+ Irp,
+ DeviceTo,
+ DeviceFrom,
+ SystemTo,
+ SystemFrom,
+ Action );
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+void
+CCaptureDevice::
+DispatchSetPower(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE To,
+ _In_ DEVICE_POWER_STATE From
+)
+{
+ // If this device supports the the DO_POWER_INRUSH flag, this function
+ // can be called at DISPATCH.
+
+ DBG_ENTER("()");
+ Recast(Device)->
+ PnpSetPower( Irp, To, From );
+ DBG_LEAVE("()");
+}
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+CCaptureDevice::
+DispatchQueryInterface(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ NTSTATUS Status =
+ Recast(Device)->
+ PnpQueryInterface(Irp);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+
+/*************************************************/
+
+
+NTSTATUS
+CCaptureDevice::
+PnpStart (
+ _In_ PCM_RESOURCE_LIST TranslatedResourceList,
+ _In_ PCM_RESOURCE_LIST UntranslatedResourceList
+)
+
+/*++
+
+Routine Description:
+
+ Called at Pnp start. We start up our hardware simulation.
+
+Arguments:
+
+ TranslatedResourceList -
+ The translated resource list from Pnp
+
+ UntranslatedResourceList -
+ The untranslated resource list from Pnp
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ //
+ // Normally, we'd do things here like parsing the resource lists and
+ // connecting our interrupt. Since this is a simulation, there isn't
+ // much to parse. The parsing and connection should be the same as
+ // any WDM driver. The sections that will differ are illustrated below
+ // in setting up a simulated DMA.
+ //
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ //
+ // By PnP, it's possible to receive multiple starts without an intervening
+ // stop (to reevaluate resources, for example). Thus, we only perform
+ // creations of the simulation on the initial start and ignore any
+ // subsequent start. Hardware drivers with resources should evaluate
+ // resources and make changes on 2nd start.
+ //
+ // Walk the list of descriptors and enumerate the h/w sims described.
+ //
+
+ if (!m_Device -> Started)
+ {
+ // Create the Filter for the device
+ for( size_t i=0; i<m_FilterDescriptorCount; i++ )
+ {
+ PKSFILTERFACTORY FilterFactory=nullptr;
+ IFFAILED_EXIT(
+ KsCreateFilterFactory( m_Device->FunctionalDeviceObject,
+ m_Context[i].Descriptor,
+ m_Context[i].Name,
+ NULL,
+ KSCREATE_ITEM_FREEONSTOP,
+ NULL,
+ NULL,
+ &FilterFactory )
+ );
+
+ // Set primary camera to its interface, this allows device to be queried by GUID
+ if( FilterFactory )
+ {
+ PKSDEVICE_PROFILE_INFO pDeviceProfiles = nullptr;
+ UINT32 uiProfileCount = 0;
+ PUNICODE_STRING SymbolicLinkName = KsFilterFactoryGetSymbolicLink(FilterFactory);
+ BOOL fFrontCamera = FALSE;
+ ACPI_PLD_V2_BUFFER pld = {0};
+ pld.Revision = 2;
+ pld.Panel = m_Context[i].AcpiPosition;
+ pld.Rotation = m_Context[i].AcpiRotation;
+ static
+ const
+ GUID FFC_Filter = {STATIC_FrontCamera_Filter};
+
+ IFFAILED_EXIT(
+ IoSetDeviceInterfacePropertyData(SymbolicLinkName,
+ &DEVPKEY_Device_PhysicalDeviceLocation,
+ LOCALE_NEUTRAL,
+ PLUGPLAY_PROPERTY_PERSISTENT,
+ DEVPROP_TYPE_BINARY,
+ sizeof(ACPI_PLD_BUFFER),
+ (PVOID)&pld)
+ );
+
+ if( m_Context[i].Descriptor->ReferenceGuid &&
+ IsEqualGUID(*(m_Context[i].Descriptor->ReferenceGuid), FFC_Filter))
+ {
+ fFrontCamera = TRUE;
+ }
+
+ // Publish our profile here.
+ uiProfileCount = InitializeDeviceProfiles(fFrontCamera, &pDeviceProfiles);
+ if( uiProfileCount > 0 )
+ {
+ if( NT_SUCCESS(KsInitializeDeviceProfile(FilterFactory)) )
+ {
+ for( UINT32 j=0; j<uiProfileCount; j++ )
+ {
+ if( !NT_SUCCESS(KsPublishDeviceProfile(FilterFactory, &pDeviceProfiles[j])) )
+ {
+ // Bail...
+ break;
+ }
+ }
+ if( !NT_SUCCESS(KsPersistDeviceProfile(FilterFactory)) )
+ {
+ // Trace here?
+ }
+ }
+
+ ExFreePool(pDeviceProfiles);
+ pDeviceProfiles = NULL;
+ }
+ }
+
+ // On a real device this object would be constructed whenever the sensor hardware is ready...
+ m_Sensor[i] = CreateSensor( m_Context[i].Descriptor );
+ if( !m_Sensor[i] )
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ IFFAILED_EXIT(m_Sensor[i]->Initialize());
+
+ m_Sensor[i]->SetMountingOrientation( m_Context[i].AcpiRotation );
+ }
+ }
+
+done:
+ if( !NT_SUCCESS(Status) )
+ {
+ // Free any sensor objects we created during this failed attempt.
+ for( size_t i=0; i<m_FilterDescriptorCount; i++ )
+ {
+ SAFE_DELETE( m_Sensor[i] );
+ }
+ }
+ return Status;
+}
+
+CSensor *
+CCaptureDevice::
+CreateSensor(
+ _In_ const KSFILTER_DESCRIPTOR *Descriptors
+)
+{
+ PAGED_CODE();
+
+ return new (NonPagedPoolNx, 'sneS') CSensorSimulation( this, Descriptors );
+}
+
+PDEVICE_OBJECT
+CCaptureDevice::
+GetDeviceObject()
+/*++
+
+Routine Description:
+
+ Return the pointer to the FDO for our device.
+
+Arguments:
+
+ [none]
+
+Return Value:
+
+ PDEVICE_OBJECT
+
+--*/
+{
+ PAGED_CODE();
+
+ return m_Device->FunctionalDeviceObject;
+}
+
+/*************************************************/
+
+
+void
+CCaptureDevice::
+PnpStop (
+ _In_ PIRP Irp
+)
+
+/*++
+
+Routine Description:
+
+ This is the pnp stop dispatch for the capture device. It releases any
+ adapter object previously allocated by IoGetDmaAdapter during Pnp Start.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Irp);
+ PAGED_CODE();
+
+ if (m_DmaAdapterObject)
+ {
+ //
+ // Return the DMA adapter back to the system.
+ //
+ m_DmaAdapterObject -> DmaOperations ->
+ PutDmaAdapter (m_DmaAdapterObject);
+
+ m_DmaAdapterObject = NULL;
+ }
+}
+
+NTSTATUS
+CCaptureDevice::
+PnpPostStart()
+{
+ PAGED_CODE();
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CCaptureDevice::
+PnpQueryStop(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+ return STATUS_SUCCESS;
+}
+
+void
+CCaptureDevice::
+PnpCancelStop(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+}
+
+NTSTATUS
+CCaptureDevice::
+PnpQueryRemove(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+ return STATUS_SUCCESS;
+}
+
+void
+CCaptureDevice::
+PnpCancelRemove(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+}
+
+void
+CCaptureDevice::
+PnpRemove(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+}
+
+void
+CCaptureDevice::
+PnpSurpriseRemoval(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+}
+
+NTSTATUS
+CCaptureDevice::
+PnpQueryCapabilities(
+ _In_ PIRP Irp,
+ _Inout_ PDEVICE_CAPABILITIES Capabilities
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+ UNREFERENCED_PARAMETER(Capabilities);
+ return STATUS_SUCCESS;
+}
+
+// Make Power callbacks non-pageable.
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+CCaptureDevice::
+PnpQueryPower(
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE DeviceTo,
+ _In_ DEVICE_POWER_STATE DeviceFrom,
+ _In_ SYSTEM_POWER_STATE SystemTo,
+ _In_ SYSTEM_POWER_STATE SystemFrom,
+ _In_ POWER_ACTION Action
+)
+{
+ UNREFERENCED_PARAMETER(Irp);
+ UNREFERENCED_PARAMETER(DeviceTo);
+ UNREFERENCED_PARAMETER(DeviceFrom);
+ UNREFERENCED_PARAMETER(SystemTo);
+ UNREFERENCED_PARAMETER(SystemFrom);
+ UNREFERENCED_PARAMETER(Action);
+ return STATUS_SUCCESS;
+}
+
+void
+CCaptureDevice::
+PnpSetPower(
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE To,
+ _In_ DEVICE_POWER_STATE From
+)
+{
+ UNREFERENCED_PARAMETER(Irp);
+ UNREFERENCED_PARAMETER(To);
+ UNREFERENCED_PARAMETER(From);
+}
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+CCaptureDevice::
+PnpQueryInterface(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(Irp);
+ return STATUS_SUCCESS;
+}
+
+/*************************************************/
+
diff --git a/AVStream/avscamera/sys/Device.h b/AVStream/avscamera/sys/Device.h
new file mode 100644
index 00000000..6a3133d6
--- /dev/null
+++ b/AVStream/avscamera/sys/Device.h
@@ -0,0 +1,450 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ device.h
+
+ Abstract:
+
+ This file contains the declaration of CCaptureDevice.
+
+ CCaptureDevice is the base device class object. It handles basic PnP
+ requests and constructs the filter factories.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+//
+// Forward references...
+//
+class CSensor;
+
+struct CSensorContext
+{
+ PWSTR Name; // What to call this class of filter.
+ const KSFILTER_DESCRIPTOR *Descriptor; // The description of the filter.
+ AcpiPldPanel AcpiPosition; // Where the device is located.
+ AcpiPldRotation AcpiRotation; // How the device is oriented with respect to the panel.
+};
+
+class CCaptureDevice
+{
+protected:
+
+ //
+ // The AVStream device we're associated with.
+ //
+ PKSDEVICE m_Device;
+
+ //
+ // Since we don't have physical hardware, this provides the hardware
+ // simulation. m_HardwareSimulation provides the fake ISR, fake DPC,
+ // etc... m_Synthesizer provides RGB24 and UYVY image synthesis and
+ // overlay in software.
+ //
+
+ //
+ // Number of pins with resources acquired. This is used as a locking
+ // mechanism for resource acquisition on the device.
+ //
+
+ // The capture pin. When we complete scatter / gather mappings, we
+ // notify the capture pin.
+ //
+
+ // Number of Filter descriptors & filter factories.
+ size_t m_FilterDescriptorCount;
+
+ // Pointer to an array of filter descriptor pointers.
+ // Typically it's one sensor for each filter factory.
+ CSensorContext *m_Context;
+
+ // The sensor state for each camera.
+ CSensor **m_Sensor;
+
+ //
+ // The Dma adapter object we acquired through IoGetDmaAdapter() during
+ // Pnp start. This must be initialized with AVStream in order to perform
+ // Dma directly into the capture buffers.
+ //
+ PADAPTER_OBJECT m_DmaAdapterObject;
+
+ //
+ // The number of map registers returned from IoGetDmaAdapter().
+ //
+ ULONG m_NumberOfMapRegisters;
+
+ //
+ // Cleanup():
+ //
+ // This is the free callback for the bagged capture device. Not providing
+ // one will call ExFreePool, which is not what we want for a constructed
+ // C++ object. This simply deletes the capture device.
+ //
+ static
+ void
+ Cleanup (
+ _In_ CCaptureDevice *CapDevice
+ )
+ {
+ delete CapDevice;
+ }
+
+ //
+ // Prepare():
+ //
+ // Called by CCaptureDevice::DispatchCreate to finish AddDevice processing,
+ // once the object is created.
+ //
+ // This is a seperate helper function to allow the derived DispatchCreate
+ // implementation to be as simple as is feasible.
+ //
+ NTSTATUS
+ Prepare();
+
+public:
+ //
+ // DispatchCreate():
+ //
+ // This is the Add Device dispatch for the capture device. It creates
+ // the CCaptureDevice and associates it with the device via the bag.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ _In_ PKSDEVICE Device
+ );
+
+ //
+ // DispatchStart():
+ //
+ // This is the Pnp Start dispatch for the capture device. It simply
+ // bridges to PnpStart() in the context of the CCaptureDevice.
+ //
+ static
+ NTSTATUS
+ DispatchStart (
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _In_ PCM_RESOURCE_LIST TranslatedResourceList,
+ _In_ PCM_RESOURCE_LIST UntranslatedResourceList
+ );
+
+ //
+ // DispatchStop():
+ //
+ // This is the Pnp stop dispatch for the capture device. It simply
+ // bridges to PnpStop() in the context of the CCaptureDevice.
+ //
+ static
+ void
+ DispatchStop(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ NTSTATUS
+ DispatchPostStart(
+ _In_ PKSDEVICE Device
+ );
+
+ static
+ NTSTATUS
+ DispatchQueryStop(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ void
+ DispatchCancelStop(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ NTSTATUS
+ DispatchQueryRemove(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ void
+ DispatchCancelRemove(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ void
+ DispatchRemove(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ void
+ DispatchSurpriseRemoval(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+ static
+ NTSTATUS
+ DispatchQueryCapabilities(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _Inout_ PDEVICE_CAPABILITIES Capabilities
+ );
+
+ static
+ NTSTATUS
+ DispatchQueryPower(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE DeviceTo,
+ _In_ DEVICE_POWER_STATE DeviceFrom,
+ _In_ SYSTEM_POWER_STATE SystemTo,
+ _In_ SYSTEM_POWER_STATE SystemFrom,
+ _In_ POWER_ACTION Action
+ );
+
+ static
+ void
+ DispatchSetPower(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE To,
+ _In_ DEVICE_POWER_STATE From
+ );
+
+ static
+ NTSTATUS
+ DispatchQueryInterface(
+ _In_ PKSDEVICE Device,
+ _In_ PIRP Irp
+ );
+
+protected:
+ //
+ // PnpStart():
+ //
+ // This is the Pnp start routine for our simulated hardware. Note that
+ // DispatchStart bridges to here in the context of the CCaptureDevice.
+ //
+ virtual
+ NTSTATUS
+ PnpStart (
+ _In_ PCM_RESOURCE_LIST TranslatedResourceList,
+ _In_ PCM_RESOURCE_LIST UntranslatedResourceList
+ );
+
+ //
+ // PnpStop():
+ //
+ // This is the Pnp stop routine for our simulated hardware. Note that
+ // DispatchStop bridges to here in the context of the CCaptureDevice.
+ //
+ virtual
+ void
+ PnpStop (
+ _In_ PIRP Irp
+ );
+
+ virtual
+ NTSTATUS
+ PnpPostStart();
+
+ virtual
+ NTSTATUS
+ PnpQueryStop(
+ _In_ PIRP Irp
+ );
+
+ virtual
+ void
+ PnpCancelStop(
+ _In_ PIRP Irp
+ );
+
+ virtual
+ NTSTATUS
+ PnpQueryRemove(
+ _In_ PIRP Irp
+ );
+
+ virtual
+ void
+ PnpCancelRemove(
+ _In_ PIRP Irp
+ );
+
+ virtual
+ void
+ PnpRemove(
+ _In_ PIRP Irp
+ );
+
+ virtual
+ void
+ PnpSurpriseRemoval(
+ _In_ PIRP Irp
+ );
+
+ virtual
+ NTSTATUS
+ PnpQueryCapabilities(
+ _In_ PIRP Irp,
+ _Inout_ PDEVICE_CAPABILITIES Capabilities
+ );
+
+ virtual
+ NTSTATUS
+ PnpQueryPower(
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE DeviceTo,
+ _In_ DEVICE_POWER_STATE DeviceFrom,
+ _In_ SYSTEM_POWER_STATE SystemTo,
+ _In_ SYSTEM_POWER_STATE SystemFrom,
+ _In_ POWER_ACTION Action
+ );
+
+ virtual
+ void
+ PnpSetPower(
+ _In_ PIRP Irp,
+ _In_ DEVICE_POWER_STATE To,
+ _In_ DEVICE_POWER_STATE From
+ );
+
+ virtual
+ NTSTATUS
+ PnpQueryInterface(
+ _In_ PIRP Irp
+ );
+
+protected:
+ virtual
+ CSensor *
+ CreateSensor(
+ _In_ const KSFILTER_DESCRIPTOR *Descriptors
+ );
+
+public:
+ //
+ // CCaptureDevice():
+ //
+ // The capture device class constructor. Since everything should have
+ // been zero'ed by the new operator, don't bother setting anything to
+ // zero or NULL. Only initialize non-NULL, non-0 fields.
+ //
+ CCaptureDevice (
+ _In_ PKSDEVICE Device
+ );
+
+ //
+ // ~CCaptureDevice():
+ //
+ // The capture device destructor.
+ //
+ virtual
+ ~CCaptureDevice();
+
+ virtual
+ NTSTATUS
+ Initialize();
+
+ //
+ // Recast():
+ //
+ // Helper function. Used to convert from a PKSDEVICE to a CCaptureDevice *
+ //
+ static
+ inline
+ CCaptureDevice *
+ Recast(
+ _In_ PKSDEVICE Device
+ )
+ {
+ return reinterpret_cast <CCaptureDevice *> (Device -> Context);
+ }
+
+ //
+ // QueryInterruptTime():
+ //
+ // Determine the frame number that this frame corresponds to.
+ //
+ ULONG
+ QueryInterruptTime (LONG ID,
+ _In_ PKSPIN Pin
+ );
+
+ virtual
+ PDEVICE_OBJECT
+ GetDeviceObject();
+
+ PKSDEVICE
+ GetKsDevice()
+ {
+ return m_Device;
+ }
+
+ ULONG
+ GetFilterIndex(PKSFILTER Filter);
+
+ ULONG
+ GetFilterCount()
+ {
+ return (ULONG) m_FilterDescriptorCount;
+ }
+
+ PCWSTR
+ GetFilterName(ULONG FilterIndex)
+ {
+ return (FilterIndex < m_FilterDescriptorCount) ? m_Context[FilterIndex].Name : nullptr;
+ }
+
+ CSensor *
+ GetSensor( PKSFILTER Filter )
+ {
+ ULONG Index = GetFilterIndex(Filter);
+
+ return ( Index < m_FilterDescriptorCount ) ? m_Sensor[ Index ] : nullptr;
+ }
+
+};
+
+//
+// Define a dispatch table for a capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc...
+//
+#define DEFINE_CAMERA_KSDEVICE_DISPATCH( Table, Class ) \
+const \
+KSDEVICE_DISPATCH \
+Table = \
+{ \
+ Class::DispatchCreate, /* Pnp Add Device */ \
+ Class::DispatchStart, /* Pnp Start */ \
+ Class::DispatchPostStart, /* Post-Start */ \
+ Class::DispatchQueryStop, /* Pnp Query Stop */ \
+ Class::DispatchCancelStop, /* Pnp Cancel Stop */ \
+ Class::DispatchStop, /* Pnp Stop */ \
+ Class::DispatchQueryRemove, /* Pnp Query Remove */ \
+ Class::DispatchCancelRemove, /* Pnp Cancel Remove */ \
+ Class::DispatchRemove, /* Pnp Remove */ \
+ Class::DispatchQueryCapabilities, /* Pnp Query Capabilities */ \
+ Class::DispatchSurpriseRemoval, /* Pnp Surprise Removal */ \
+ Class::DispatchQueryPower, /* Power Query Power */ \
+ Class::DispatchSetPower, /* Power Set Power */ \
+ Class::DispatchQueryInterface /* Pnp Query Interface */ \
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedCameraAngleOffset.h b/AVStream/avscamera/sys/ExtendedCameraAngleOffset.h
new file mode 100644
index 00000000..dca18ee1
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedCameraAngleOffset.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ExtendedCameraAngleOffset.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedCameraAngleOffset.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_CAMERAOFFSET.
+
+ History:
+
+ created 11/26/2014
+
+**************************************************************************/
+
+//
+// Helper class for Extended Camera Angle Offset.
+//
+class CExtendedCameraAngleOffset
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_CAMERAOFFSET m_Params;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedCameraAngleOffset( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Params, sizeof(m_Params) );
+ }
+
+ CExtendedCameraAngleOffset( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Params, sizeof(m_Params) );
+ }
+
+ // Access functions let you more easily fetch the embedded field.
+ LONG &
+ PitchAngle()
+ {
+ return m_Params.PitchAngle;
+ }
+
+ LONG &
+ YawAngle()
+ {
+ return m_Params.YawAngle;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedEVComp.h b/AVStream/avscamera/sys/ExtendedEVComp.h
new file mode 100644
index 00000000..31f7916b
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedEVComp.h
@@ -0,0 +1,105 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ExtendedEvComp.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedEvCompensation.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_EVCOMPENSATION.
+
+ History:
+
+ created 6/3/2014
+
+**************************************************************************/
+
+//
+// Helper class for Extended Properties.
+//
+class CExtendedEvCompensation
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_EVCOMPENSATION m_EvComp;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedEvCompensation( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ :CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_EvComp, sizeof(m_EvComp) );
+ }
+
+ CExtendedEvCompensation( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_EvComp, sizeof(m_EvComp) );
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+
+ // Access operators let you fetch the value from the value field.
+ operator LONG()
+ {
+ return m_EvComp.Value;
+ }
+
+ // Assignment operators let you assign a value to the property.
+ CExtendedEvCompensation &
+ operator =( LONG x )
+ {
+ Value() = x;
+ return *this;
+ }
+
+ CExtendedEvCompensation &
+ operator =( const KSCAMERA_EXTENDEDPROP_EVCOMPENSATION &x )
+ {
+ m_EvComp = x;
+ return *this;
+ }
+
+ LONG &
+ Min()
+ {
+ return m_EvComp.Min;
+ }
+
+ LONG &
+ Max()
+ {
+ return m_EvComp.Max;
+ }
+
+ ULONG &
+ Mode()
+ {
+ return m_EvComp.Mode;
+ }
+
+ LONG &
+ Value()
+ {
+ return m_EvComp.Value;
+ }
+
+ LONG &
+ GetLONG()
+ {
+ return m_EvComp.Value;
+ }
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedFieldOfView.h b/AVStream/avscamera/sys/ExtendedFieldOfView.h
new file mode 100644
index 00000000..388356a6
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedFieldOfView.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ExtendedFieldOfView.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedFieldOfView.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_FIELDOFVIEW.
+
+ History:
+
+ created 11/26/2014
+
+**************************************************************************/
+
+//
+// Helper class for Extended Field of View.
+//
+class CExtendedFieldOfView
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_FIELDOFVIEW m_Params;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedFieldOfView( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Params, sizeof(m_Params) );
+ }
+
+ CExtendedFieldOfView( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Params, sizeof(m_Params) );
+ }
+
+ // Access functions let you more easily fetch the embedded field.
+ ULONG &
+ NormalizedFocalLengthX()
+ {
+ return m_Params.NormalizedFocalLengthX;
+ }
+
+ ULONG &
+ NormalizedFocalLengthY()
+ {
+ return m_Params.NormalizedFocalLengthY;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedMaxVideoFpsForPhotoRes.h b/AVStream/avscamera/sys/ExtendedMaxVideoFpsForPhotoRes.h
new file mode 100644
index 00000000..29013c82
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedMaxVideoFpsForPhotoRes.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ExtendedMaxVideoFpsForPhotoRes.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedMaxVideoFpsForPhotoRes.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_MAXVIDEOFPS_FORPHOTORES.
+
+ History:
+
+ created 11/26/2014
+
+**************************************************************************/
+
+//
+// Helper class for Extended Max Video Fps for Photo Resolution.
+//
+class CExtendedMaxVideoFpsForPhotoRes
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_MAXVIDEOFPS_FORPHOTORES m_Params;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedMaxVideoFpsForPhotoRes( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Params, sizeof(m_Params) );
+ }
+
+ CExtendedMaxVideoFpsForPhotoRes( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Params, sizeof(m_Params) );
+ }
+
+ // Access functions let you more easily fetch the embedded field.
+ ULONG &
+ PhotoResWidth()
+ {
+ return m_Params.PhotoResWidth;
+ }
+
+ ULONG &
+ PhotoResHeight()
+ {
+ return m_Params.PhotoResHeight;
+ }
+
+ ULONG &
+ PreviewFPSNum()
+ {
+ return m_Params.PreviewFPSNum;
+ }
+
+ ULONG &
+ PreviewFPSDenom()
+ {
+ return m_Params.PreviewFPSDenom;
+ }
+
+ ULONG &
+ CaptureFPSNum()
+ {
+ return m_Params.CaptureFPSNum;
+ }
+
+ ULONG &
+ CaptureFPSDenom()
+ {
+ return m_Params.CaptureFPSDenom;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedMetadata.h b/AVStream/avscamera/sys/ExtendedMetadata.h
new file mode 100644
index 00000000..27ef4a79
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedMetadata.h
@@ -0,0 +1,68 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ExtendedMetadata.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedMetadata.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_METADATAINFO.
+
+ History:
+
+ created 6/20/2014
+
+**************************************************************************/
+
+//
+// Helper class for Extended Metadata.
+//
+class CExtendedMetadata
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_METADATAINFO m_Info;
+
+ // Maximum metadata required ... except for Histogram
+ static const ULONG METADATA_MAX=4096;
+
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedMetadata(
+ _In_ ULONG pinId=0, // Just so we have a default ctor.
+ _In_ ULONG size=METADATA_MAX,
+ _In_ ULONG align=KSCAMERA_EXTENDEDPROP_MetadataAlignment_32,
+ _In_ ULONGLONG flags=(KSCAMERA_EXTENDEDPROP_METADATA_ALIGNMENTREQUIRED | KSCAMERA_EXTENDEDPROP_METADATA_SYSTEMMEMORY),
+ _In_ ULONG result=STATUS_SUCCESS
+ )
+ : CExtendedHeader( flags, result )
+ {
+ PinId = pinId;
+ Size = sizeof(*this);
+ m_Info.BufferAlignment = align;
+ m_Info.MaxMetadataBufferSize= size;
+ }
+
+ // Used to modify the metadata allocation size.
+ CExtendedMetadata &
+ operator =( ULONG x )
+ {
+ m_Info.MaxMetadataBufferSize = x;
+ return *this;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size == sizeof(*this)) &&
+ ((Flags & ~(KSCAMERA_EXTENDEDPROP_METADATA_SYSTEMMEMORY | KSCAMERA_EXTENDEDPROP_METADATA_ALIGNMENTREQUIRED)) == 0) && // Only valid flags
+ ((m_Info.BufferAlignment-1) & m_Info.BufferAlignment); // Not more than 1 bit set.
+ }
+
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedPhotoMode.h b/AVStream/avscamera/sys/ExtendedPhotoMode.h
new file mode 100644
index 00000000..daa7c127
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedPhotoMode.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ExtendedPhotoMode.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedPhotoMode.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_PHOTOMODE.
+
+ History:
+
+ created 11/20/2014
+
+**************************************************************************/
+
+//
+// Helper class for Extended Photo Mode.
+//
+class CExtendedPhotoMode
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_PHOTOMODE m_PhotoMode;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedPhotoMode( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_PhotoMode, sizeof(m_PhotoMode) );
+ }
+
+ CExtendedPhotoMode( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_PhotoMode, sizeof(m_PhotoMode) );
+ }
+
+ // Access functions let you more easily fetch the embedded field.
+ ULONG &
+ RequestedHistoryFrames()
+ {
+ return m_PhotoMode.RequestedHistoryFrames;
+ }
+
+ ULONG &
+ MaxHistoryFrames()
+ {
+ return m_PhotoMode.MaxHistoryFrames;
+ }
+
+ ULONG &
+ SubMode()
+ {
+ return m_PhotoMode.SubMode;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedProperty.h b/AVStream/avscamera/sys/ExtendedProperty.h
new file mode 100644
index 00000000..32affaa6
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedProperty.h
@@ -0,0 +1,142 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ ExtendedProperty.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedProperty and the coommon
+ base class CExtendedHeader.
+
+ CExtendedHeader provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_HEADER.
+
+ CExtendedProperty provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_VALUE.
+
+ CExtendedProperty also combines KSCAMERA_EXTENDEDPROP_HEADER and
+ KSCAMERA_EXTENDEDPROP_VALUE into a single object for use in the
+ macros and templates used by our filter and sensor classes.
+
+ History:
+
+ created 5/21/2013
+
+**************************************************************************/
+
+//
+// Helper class for Extended Properties.
+//
+class CExtendedHeader
+ : public KSCAMERA_EXTENDEDPROP_HEADER
+{
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedHeader( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ {
+ Version = KSCAMERA_EXTENDEDPROP_VERSION;
+ PinId = KSCAMERA_EXTENDEDPROP_FILTERSCOPE;
+ Size = sizeof(*this);
+ Result = result;
+ Capability = 0;
+ Flags = flags;
+ }
+
+ CExtendedHeader( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : KSCAMERA_EXTENDEDPROP_HEADER(hdr)
+ {
+ Size = sizeof(*this);
+ }
+
+ bool isValid()
+ {
+ return Version == KSCAMERA_EXTENDEDPROP_VERSION;
+ }
+};
+
+class CExtendedProperty
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_VALUE m_Value;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedProperty( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ m_Value.Value.ull = 0;
+ }
+
+ CExtendedProperty( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ m_Value.Value.ull = 0;
+ }
+
+ // Access operators let you fetch the value from the value field.
+ operator LONG()
+ {
+ return m_Value.Value.l;
+ }
+ operator ULONG()
+ {
+ return m_Value.Value.ul;
+ }
+ operator LONGLONG()
+ {
+ return m_Value.Value.ll;
+ }
+ operator ULONGLONG()
+ {
+ return m_Value.Value.ull;
+ }
+ operator KSCAMERA_EXTENDEDPROP_VALUE()
+ {
+ return m_Value;
+ }
+
+ // Assignment operators let you assign a value to the property.
+ CExtendedProperty &
+ operator =( LONG x )
+ {
+ m_Value.Value.l = x;
+ return *this;
+ }
+
+ CExtendedProperty &
+ operator =( LONGLONG x )
+ {
+ m_Value.Value.ll = x;
+ return *this;
+ }
+
+ CExtendedProperty &
+ operator =( ULONG x )
+ {
+ m_Value.Value.ul = x;
+ return *this;
+ }
+
+ CExtendedProperty &
+ operator =( ULONGLONG x )
+ {
+ m_Value.Value.ull = x;
+ return *this;
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+
+};
+
diff --git a/AVStream/avscamera/sys/ExtendedVidProcSetting.h b/AVStream/avscamera/sys/ExtendedVidProcSetting.h
new file mode 100644
index 00000000..11c22caa
--- /dev/null
+++ b/AVStream/avscamera/sys/ExtendedVidProcSetting.h
@@ -0,0 +1,164 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ ExtendedProperty.h
+
+ Abstract:
+
+ This file contains the helper class CExtendedVidProcSetting.
+ The class is provides initialization and accessor functions for
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING.
+
+ History:
+
+ created 5/21/2013
+
+**************************************************************************/
+
+//
+// Helper class for Extended Properties KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING.
+//
+class CExtendedVidProcSetting
+ : public CExtendedHeader
+{
+public:
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING m_Setting;
+
+public:
+ // Standardized ctors to help ensure a consistant definition.
+ CExtendedVidProcSetting( ULONGLONG flags=0, ULONG result=STATUS_SUCCESS )
+ : CExtendedHeader( flags, result )
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Setting, sizeof(m_Setting) );
+ }
+
+ CExtendedVidProcSetting( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : CExtendedHeader(hdr)
+ {
+ Size = sizeof(*this);
+ RtlZeroMemory( &m_Setting, sizeof(m_Setting) );
+ }
+
+ bool isValid()
+ {
+ return CExtendedHeader::isValid() &&
+ (Size >= sizeof(*this)) ;
+ }
+
+ template<class T>
+ NTSTATUS
+ BoundsCheck( T Value )
+ {
+ return ::BoundsCheck( Value, m_Setting );
+ }
+
+ // Access operators let you fetch the value from the value field.
+ operator LONG()
+ {
+ return m_Setting.VideoProc.Value.l;
+ }
+ operator ULONG()
+ {
+ return m_Setting.VideoProc.Value.ul;
+ }
+ operator LONGLONG()
+ {
+ return m_Setting.VideoProc.Value.ll;
+ }
+ operator ULONGLONG()
+ {
+ return m_Setting.VideoProc.Value.ull;
+ }
+
+ // Assignment operators let you assign a value to the property.
+ CExtendedVidProcSetting &
+ operator =( LONG x )
+ {
+ m_Setting.VideoProc.Value.l = x;
+ return *this;
+ }
+
+ CExtendedVidProcSetting &
+ operator =( LONGLONG x )
+ {
+ m_Setting.VideoProc.Value.ll = x;
+ return *this;
+ }
+
+ CExtendedVidProcSetting &
+ operator =( ULONG x )
+ {
+ m_Setting.VideoProc.Value.ul = x;
+ return *this;
+ }
+
+ CExtendedVidProcSetting &
+ operator =( ULONGLONG x )
+ {
+ m_Setting.VideoProc.Value.ull = x;
+ return *this;
+ }
+
+ CExtendedVidProcSetting &
+ operator =( const KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING &x )
+ {
+ m_Setting = x;
+ return *this;
+ }
+
+ LONG &
+ Min()
+ {
+ return m_Setting.Min;
+ }
+
+ LONG &
+ Max()
+ {
+ return m_Setting.Max;
+ }
+
+ LONG &
+ Step()
+ {
+ return m_Setting.Step;
+ }
+
+ ULONG &
+ Mode()
+ {
+ return m_Setting.Mode;
+ }
+
+ LONG &
+ GetLONG()
+ {
+ return m_Setting.VideoProc.Value.l;
+ }
+
+ LONGLONG &
+ GetLONGLONG()
+ {
+ return m_Setting.VideoProc.Value.ll;
+ }
+
+ ULONG &
+ GetULONG()
+ {
+ return m_Setting.VideoProc.Value.ul;
+ }
+
+ ULONGLONG &
+ GetULONGLONG()
+ {
+ return m_Setting.VideoProc.Value.ull;
+ }
+
+};
+
diff --git a/AVStream/avscamera/sys/Mutex.cpp b/AVStream/avscamera/sys/Mutex.cpp
new file mode 100644
index 00000000..1dd3d88c
--- /dev/null
+++ b/AVStream/avscamera/sys/Mutex.cpp
@@ -0,0 +1,70 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ Mutex.cpp
+
+ Abstract:
+
+ This file provides the implementation of KMutex and KScopedMutex.
+
+ KMutex provides a wrapper around a KMUTEX object. KScopedMutex is
+ provided as a helper class to ensure all exits release the lock.
+
+ History:
+
+ created 7/16/2013
+
+**************************************************************************/
+
+#include "Common.h"
+
+//
+// Dummy dtor. Required because the dtor is virtual.
+//
+KMutex::~KMutex()
+{}
+
+//
+// Preferred lock method.
+//
+_IRQL_requires_min_(PASSIVE_LEVEL)
+_When_((Timeout==NULL || Timeout->QuadPart!=0), _IRQL_requires_max_(APC_LEVEL))
+_When_((Timeout!=NULL &&Timeout->QuadPart==0), _IRQL_requires_max_(DISPATCH_LEVEL))
+NTSTATUS
+KMutex::Lock(
+ _In_opt_ PLARGE_INTEGER Timeout
+)
+{
+ //DBG_ENTER(": Thread Owner = %p", m_Lock.OwnerThread);
+
+ NTSTATUS status =
+ KeWaitForSingleObject(
+ &m_Lock,
+ Executive,
+ KernelMode,
+ FALSE,
+ Timeout );
+
+ //DBG_LEAVE(": Status = %d Thread Owner = %p", status, m_Lock.OwnerThread);
+
+ return status;
+}
+
+//
+// Preferred unlock method.
+//
+_IRQL_requires_max_(DISPATCH_LEVEL)
+void
+KMutex::Unlock()
+{
+ //DBG_ENTER(": Thread Owner = %p", m_Lock.OwnerThread);
+
+ KeReleaseMutex( &m_Lock, FALSE );
+
+ //DBG_LEAVE(": Thread Owner = %p", m_Lock.OwnerThread);
+}
diff --git a/AVStream/avscamera/sys/Mutex.h b/AVStream/avscamera/sys/Mutex.h
new file mode 100644
index 00000000..a8157da5
--- /dev/null
+++ b/AVStream/avscamera/sys/Mutex.h
@@ -0,0 +1,81 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ Mutex.h
+
+ Abstract:
+
+ This file provides the declaration of KMutex and KScopedMutex.
+
+ KMutex provides a wrapper around a KMUTEX object. KScopedMutex is
+ provided as a helper class to ensure all exits release the lock.
+
+ History:
+
+ created 7/16/2013
+
+**************************************************************************/
+#pragma once
+
+//
+// Specialized class for KMUTEX
+//
+class KMutex : CNonCopyable
+{
+ KMUTEX m_Lock;
+
+public:
+ KMutex()
+ {
+ KeInitializeMutex( &m_Lock, 0 );
+ }
+
+ virtual ~KMutex();
+
+ //
+ // Preferred lock method.
+ //
+ _IRQL_requires_min_(PASSIVE_LEVEL)
+ _When_((Timeout==NULL || Timeout->QuadPart!=0), _IRQL_requires_max_(APC_LEVEL))
+ _When_((Timeout!=NULL &&Timeout->QuadPart==0), _IRQL_requires_max_(DISPATCH_LEVEL))
+ NTSTATUS
+ Lock(
+ _In_opt_ PLARGE_INTEGER Timeout=nullptr
+ );
+
+ //
+ // Preferred unlock method.
+ //
+ _IRQL_requires_max_(DISPATCH_LEVEL)
+ void
+ Unlock();
+};
+
+//
+// Use this class to hold a spinlock through a particular scope
+//
+class KScopedMutex : CNonCopyable
+{
+ KMutex &m_Lock;
+
+public:
+ _IRQL_requires_min_(PASSIVE_LEVEL)
+ _IRQL_requires_max_(APC_LEVEL)
+ KScopedMutex( KMutex &lock )
+ : m_Lock(lock)
+ {
+ m_Lock.Lock();
+ }
+
+ _IRQL_requires_max_(DISPATCH_LEVEL)
+ ~KScopedMutex(void)
+ {
+ m_Lock.Unlock();
+ }
+};
+
diff --git a/AVStream/avscamera/sys/NV12Synthesizer.cpp b/AVStream/avscamera/sys/NV12Synthesizer.cpp
new file mode 100644
index 00000000..2cdbf71b
--- /dev/null
+++ b/AVStream/avscamera/sys/NV12Synthesizer.cpp
@@ -0,0 +1,183 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ CNV12Synthesizer.h
+
+ Abstract:
+
+ This file contains the implementation of CNV12Synthesizer.
+
+ CNV12Synthesizer is derived from CYUVSynthesizer. It uses the YUV color
+ space and defines a Commit() function that reformats pixels into the
+ NV12 format. From MSDN:
+
+ A format in which all Y samples are found first in memory as an
+ array of unsigned char with an even number of lines (possibly with
+ a larger stride for memory alignment). This is followed immediately
+ by an array of unsigned char containing interleaved Cb and Cr
+ samples. If these samples are addressed as a little-endian WORD
+ type, Cb would be in the least significant bits and Cr would be in
+ the most significant bits with the same total stride as the Y
+ samples. NV12 is the preferred 4:2:0 pixel format.
+
+ A visual representation of the layout:
+ YYYY
+ YYYY
+ UVUV
+
+
+ History:
+ created 4/14/2013
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+// suppressed due to Esp:773
+#pragma warning (push)
+#pragma warning( disable:26015 ) // Suppress OACR error. Seems nonsensical. TODO: Must revisit.
+#pragma warning( disable:26019 )
+_Success_(return > 0)
+ULONG
+CNV12Synthesizer::
+Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+)
+/*++
+
+Routine Description:
+
+ Copy (and reformat, if necessary) pixels from the internal scratch
+ buffer. If the output format decimates chrominance, do it here.
+
+Arguments:
+
+ Buffer -
+ The output buffer to fill.
+
+ Size -
+ The size of the output buffer in bytes.
+
+ Stride -
+ The length of a row in bytes.
+
+Return Value:
+
+ Number of bytes copied into Buffer.
+
+--*/
+{
+ // We assume the output stride is the same as the original width here.
+ UNREFERENCED_PARAMETER(Stride);
+
+ // The code actually handles this gracefully. It rounds down.
+ NT_ASSERT( (m_Width&1) == 0 );
+ NT_ASSERT( (m_Height&1) == 0 );
+
+ // These are impossible conditions.
+ if( !( Buffer &&
+ m_Buffer &&
+ (Size%6)==0 && // Should be evenly divisible by 1 macropixel
+ Size>=6 // At least 1 macropixel
+ ) )
+ {
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+
+ ULONG MacroPixelsWide = m_Width/2;
+
+ // Impossible.
+ if( MacroPixelsWide==0 )
+ {
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+
+ // At most, 2/3rds of the available space is used by the Y plane.
+ // Notice that we limit the number of macro pixel rows to what will
+ // fit in the space available, no matter what is in the original.
+ ULONG Y_limit = (Size /3) * 2;
+ ULONG MacroPixelsHigh = min( m_Height, Y_limit/m_Width)/2;
+
+ // Impossible.
+ if( MacroPixelsHigh==0 )
+ {
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+
+ // Now we work back to arrive at the Y & UV plane sizes.
+ ULONG UV_size = MacroPixelsWide * MacroPixelsHigh *2;
+ ULONG Y_size = MacroPixelsWide * MacroPixelsHigh *4;
+ ULONG YUV_size = Y_size + UV_size;
+
+ // Impossible.
+ if( Size < YUV_size )
+ {
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+
+ PWORD pY = (PWORD) Buffer;
+ PWORD pUV = (PWORD) (Buffer + Y_size);
+
+ for(ULONG row = 0; row < MacroPixelsHigh; row++)
+ {
+ PKS_RGBQUAD pSrc = (PKS_RGBQUAD) GetImageLocation(0, row*2);
+ for(ULONG col = 0; col < MacroPixelsWide; col++)
+ {
+ KS_RGBQUAD TL = pSrc[0];
+ KS_RGBQUAD TR = pSrc[1];
+ KS_RGBQUAD BL = pSrc[m_Width+0];
+ KS_RGBQUAD BR = pSrc[m_Width+1];
+ pSrc += 2;
+
+ // Copy luma first
+ pY[0] = MAKEWORD(TL.rgbGreen, TR.rgbGreen);
+ pY[MacroPixelsWide] = MAKEWORD(BL.rgbGreen, BR.rgbGreen);
+ pY++;
+
+ LONG
+ tU = TL.rgbBlue; //top left
+ tU += BL.rgbBlue; //bottom left
+ tU += TR.rgbBlue; //top right
+ tU += BR.rgbBlue; //bottom right
+
+ LONG
+ tV = TL.rgbRed; //top left
+ tV += BL.rgbRed; //bottom left
+ tV += TR.rgbRed; //top right
+ tV += BR.rgbRed; //bottom right
+
+ // Copy decimated chroma
+ *pUV++ = MAKEWORD(((tU+2)>>2), ((tV+2)>>2));
+ }
+ // Skip a scan line, since we've already copied it.
+ pY += MacroPixelsWide;
+ }
+
+ return (ULONG) (((PUCHAR) pUV) - Buffer);
+}
+// suppressed due to Esp:773
+#pragma warning (pop)
+
diff --git a/AVStream/avscamera/sys/NV12Synthesizer.h b/AVStream/avscamera/sys/NV12Synthesizer.h
new file mode 100644
index 00000000..27bc6ccb
--- /dev/null
+++ b/AVStream/avscamera/sys/NV12Synthesizer.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ CNV12Synthesizer.h
+
+ Abstract:
+
+ This file defines a class that implements NV12 image synthesis.
+
+ CNV12Synthesis is derived from CYUVSynthesis. It uses the YUV color
+ space and defines a Commit() function that reformats pixels into the
+ NV12 format. From MSDN:
+
+ A format in which all Y samples are found first in memory as an
+ array of unsigned char with an even number of lines (possibly with
+ a larger stride for memory alignment). This is followed immediately
+ by an array of unsigned char containing interleaved Cb and Cr
+ samples. If these samples are addressed as a little-endian WORD
+ type, Cb would be in the least significant bits and Cr would be in
+ the most significant bits with the same total stride as the Y
+ samples. NV12 is the preferred 4:2:0 pixel format.
+
+ A visual representation of the layout:
+ YYYY
+ YYYY
+ UVUV
+
+
+ History:
+ created 4/16/2013
+
+**************************************************************************/
+
+#pragma once
+
+class CNV12Synthesizer :
+ public CYUVSynthesizer
+{
+public:
+ //
+ // DEFAULT CONSTRUCTOR
+ //
+ CNV12Synthesizer (
+ ULONG Width=0,
+ ULONG Height=0
+ ) :
+ CYUVSynthesizer("NV12", Width, Height)
+ {
+ NT_ASSERT( ( Width % 2 ) == 0 );
+ NT_ASSERT( ( Height % 2 ) == 0 );
+ }
+
+ //
+ // Commit
+ //
+ // Copy (and reformat, if necessary) pixels from the internal scratch
+ // buffer. If the output format decimates chrominance, do it here.
+ //
+ virtual
+ _Success_(return > 0)
+ ULONG
+ Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+ );
+}; \ No newline at end of file
diff --git a/AVStream/avscamera/sys/NonCopyable.h b/AVStream/avscamera/sys/NonCopyable.h
new file mode 100644
index 00000000..98d7bad4
--- /dev/null
+++ b/AVStream/avscamera/sys/NonCopyable.h
@@ -0,0 +1,48 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ NonCopyable.h
+
+ Abstract:
+
+ Simple base class that hides the copy ctor and assignment operators.
+
+ Derive from this class any time its not safe (or reasonable) to
+ permit copies of an object.
+
+ History:
+
+ created 5/8/2013
+
+**************************************************************************/
+#pragma once
+
+//
+// General base class for noncopyable objects
+//
+class CNonCopyable
+{
+protected:
+ CNonCopyable() {}
+ ~CNonCopyable() {}
+
+private:
+ CNonCopyable(
+ _In_ const CNonCopyable &
+ )
+ {}
+
+ const CNonCopyable &
+ operator =(
+ _In_ const CNonCopyable &
+ )
+ {
+ return *this;
+ }
+};
+
diff --git a/AVStream/avscamera/sys/PreviewHwSim.cpp b/AVStream/avscamera/sys/PreviewHwSim.cpp
new file mode 100644
index 00000000..dfe2dc1a
--- /dev/null
+++ b/AVStream/avscamera/sys/PreviewHwSim.cpp
@@ -0,0 +1,263 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ PreviewHwSim.cpp
+
+ Abstract:
+
+ This file contains the implementation of the CPreviewHardwareSimulation
+ class.
+
+ This is a specialization of CHardwareSimulation that provides preview-
+ specific metadata.
+
+ History:
+
+ created 5/28/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+CPreviewHardwareSimulation::CPreviewHardwareSimulation(
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+)
+ : CHardwareSimulation( Sensor, PinID )
+{
+ PAGED_CODE();
+}
+
+
+CPreviewHardwareSimulation::~CPreviewHardwareSimulation()
+{
+ PAGED_CODE();
+}
+
+void
+CPreviewHardwareSimulation::
+FakeHardware()
+/*++
+
+Routine Description:
+
+ Simulate an interrupt and what the hardware would have done in the
+ time since the previous interrupt.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ // Do normal timer handling.
+ CHardwareSimulation::FakeHardware();
+
+ // Update the zoom.
+ m_Sensor->UpdateZoom();
+}
+
+//
+// Helper function that collects the current ISP settings into our metadata
+// structure.
+//
+METADATA_PREVIEWAGGREGATION
+CPreviewHardwareSimulation::
+GetMetadata()
+{
+ PAGED_CODE();
+
+ METADATA_PREVIEWAGGREGATION Metadata;
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+
+ // Wipe the metadata so all settings will default to "Not Set".
+ RtlZeroMemory( &Metadata, sizeof(Metadata) );
+
+ // FocusState;
+ m_Sensor->GetFocusState( (KSCAMERA_EXTENDEDPROP_FOCUSSTATE *) &Metadata.FocusState );
+
+ // ExposureTime;
+ Metadata.ExposureTime =
+ CMetadataLongLong( GetCurrentExposureTime() );
+
+ // EVCompensation;
+ Metadata.EVCompensation = CMetadataEVCompensation(pSettings->EVCompensation.Mode, pSettings->EVCompensation.Value);
+
+ // ISOSpeed;
+ Metadata.ISOSpeed = CMetadataLong(GetCurrentISOSpeed());
+ DBG_TRACE("ISO=%d, ISO Flags=0x%016llX", Metadata.ISOSpeed.Value, pSettings->ISOMode);
+
+ // LensPosition;
+ Metadata.LensPosition = CMetadataLong( pSettings->FocusSetting.VideoProc.Value.ul );
+
+ // FlashOn;
+ Metadata.FlashOn = CMetadataLong((ULONG) pSettings->FlashMode);
+
+ // WhiteBalanceMode;
+ Metadata.WhiteBalanceMode = CMetadataLong((ULONG) pSettings->WhiteBalanceMode);
+
+ // IsoGains;
+ Metadata.IsoAnalogGain =
+ CMetadataSRational( GetRandom( (LONG)5000, (LONG)20000 ), (LONG)10000 ); // Some number from 0.5 to 2.0 - for testing.
+ Metadata.IsoDigitalGain =
+ CMetadataSRational( GetRandom( (LONG)5000, (LONG)20000 ), (LONG)10000 ); // Some number from 0.5 to 2.0 - for testing.
+
+ // SensorFrameRate;
+ ULARGE_INTEGER FrameRate;
+ FrameRate.LowPart = 60 * 60 *24;
+ FrameRate.HighPart = (ULONG) ((ONESECOND * FrameRate.LowPart) / m_TimePerFrame); // compute number of frames per day.
+ Metadata.SensorFrameRate = CMetadataULongLong( FrameRate.QuadPart );
+
+ // WhiteBalanceGains;
+ Metadata.WhiteBalanceGain_R = // MF_CAPTURE_METADATA_WHITEBALANCE_GAINS
+ CMetadataSRational( GetRandom( (LONG)5000, (LONG)20000 ), (LONG)10000 ); // Some number from 0.5 to 2.0 - for testing.
+ Metadata.WhiteBalanceGain_G = // MF_CAPTURE_METADATA_WHITEBALANCE_GAINS
+ CMetadataSRational( GetRandom( (LONG)5000, (LONG)20000 ), (LONG)10000 ); // Some number from 0.5 to 2.0 - for testing.
+ Metadata.WhiteBalanceGain_B = // MF_CAPTURE_METADATA_WHITEBALANCE_GAINS
+ CMetadataSRational( GetRandom( (LONG)5000, (LONG)20000 ), (LONG)10000 ); // Some number from 0.5 to 2.0 - for testing.
+
+ return Metadata;
+}
+
+//
+// Emit metadata here for preview pin.
+//
+void
+CPreviewHardwareSimulation::
+EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+)
+/*++
+
+Routine Description:
+
+ Emit metadata for a photo.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE();
+
+ NT_ASSERT(pStreamHeader);
+
+ // Add the normal frame info to the metadata
+ // Note: This call ensures the KSSTREAM_METADATA_INFO is properly initialized.
+ CHardwareSimulation::EmitMetadata( pStreamHeader );
+
+ if (0 != (pStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_METADATA))
+ {
+ PKS_FRAME_INFO pFrameInfo = (PKS_FRAME_INFO)(pStreamHeader + 1);
+ PKSSTREAM_METADATA_INFO pMetadata = (PKSSTREAM_METADATA_INFO) (pFrameInfo + 1);
+ ULONG BytesLeft = pMetadata->BufferSize - pMetadata->UsedSize;
+
+ if(m_PhotoConfirmationEntry.isRequired())
+ {
+ if(BytesLeft < sizeof(KSCAMERA_METADATA_PHOTOCONFIRMATION))
+ {
+ //Fatal driver error, should never come here.
+ NT_ASSERT(FALSE);
+ return;
+ }
+ PKSCAMERA_METADATA_PHOTOCONFIRMATION pPhotoConfirmation =
+ (PKSCAMERA_METADATA_PHOTOCONFIRMATION) (((PBYTE)pMetadata->SystemVa) + pMetadata->UsedSize);
+ pPhotoConfirmation->Header.MetadataId = MetadataId_PhotoConfirmation;
+ pPhotoConfirmation->Header.Size = sizeof(*pPhotoConfirmation);
+ pPhotoConfirmation->PhotoConfirmationIndex = m_PhotoConfirmationEntry.getIndex();
+ pMetadata->UsedSize += sizeof(*pPhotoConfirmation);
+ BytesLeft -= sizeof(*pPhotoConfirmation);
+
+ DBG_TRACE("PhotoConfirmation Header.MetadataId = %u", pPhotoConfirmation->Header.MetadataId);
+ DBG_TRACE("PhotoConfirmation Header.Size = %u", pPhotoConfirmation->Header.Size);
+ DBG_TRACE("PhotoConfirmation Index = %u", pPhotoConfirmation->PhotoConfirmationIndex);
+ }
+ else
+ {
+ DBG_TRACE("Normal frame; no photo confirmation metadata.");
+ }
+
+ if( BytesLeft >= sizeof(CAMERA_METADATA_PREVIEWAGGREGATION) )
+ {
+ PCAMERA_METADATA_PREVIEWAGGREGATION pPreviewAggregation =
+ (PCAMERA_METADATA_PREVIEWAGGREGATION) (((PBYTE)pMetadata->SystemVa) + pMetadata->UsedSize);
+ pPreviewAggregation->Header.MetadataId = (ULONG) MetadataId_Custom_PreviewAggregation;
+ pPreviewAggregation->Header.Size = sizeof(*pPreviewAggregation);
+ pPreviewAggregation->Data = GetMetadata();
+ pMetadata->UsedSize += sizeof(*pPreviewAggregation);
+ BytesLeft -= sizeof(*pPreviewAggregation);
+ }
+
+ // MF_CAPTURE_METADATA_HISTOGRAM
+ //
+ // Generate the entire Histogram metadata blob here.
+ //
+ if( BytesLeft >= sizeof(CAMERA_METADATA_HISTOGRAM) )
+ {
+ PCAMERA_METADATA_HISTOGRAM pHistogram =
+ (PCAMERA_METADATA_HISTOGRAM) (((PBYTE)pMetadata->SystemVa) + pMetadata->UsedSize);
+ ULONG ChannelMask = m_Synthesizer->GetChannelMask();
+ CExtendedProperty Setting;
+
+ m_Sensor->GetHistogram( &Setting );
+ if( Setting.Flags & KSCAMERA_EXTENDEDPROP_HISTOGRAM_ON &&
+ ChannelMask != 0 )
+ {
+ // Just checking to see if we messed something up here.
+ NT_ASSERT( pMetadata->BufferSize >= CExtendedMetadata::METADATA_MAX + sizeof(CAMERA_METADATA_HISTOGRAM) );
+
+ pHistogram->Header.MetadataId = (ULONG) MetadataId_Custom_Histogram;
+ pHistogram->Header.Size = sizeof(*pHistogram);
+
+ // Acquire the data for every channel.
+ pHistogram->Data.ChannelMask = ChannelMask;
+ pHistogram->Data.Height = m_Height;
+ pHistogram->Data.Width = m_Width;
+ pHistogram->Data.FourCC = m_Sensor->GetFourCC( m_PinID );
+ m_Synthesizer->Histogram( pHistogram->Data.P0Data, pHistogram->Data.P1Data, pHistogram->Data.P2Data );
+ pMetadata->UsedSize += sizeof(*pHistogram);
+ BytesLeft -= sizeof(*pHistogram);
+ }
+ }
+
+ CExtendedVidProcSetting FaceDetect;
+ m_Sensor->GetFaceDetection(&FaceDetect);
+
+ if( FaceDetect.Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_PREVIEW )
+ {
+ DBG_TRACE("PREVIEW");
+ EmitFaceMetadata(
+ pStreamHeader,
+ FaceDetect.GetULONG(),
+ FaceDetect.Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_ADVANCED_MASK);
+ }
+ }
+}
+
diff --git a/AVStream/avscamera/sys/PreviewHwSim.h b/AVStream/avscamera/sys/PreviewHwSim.h
new file mode 100644
index 00000000..92d3eae7
--- /dev/null
+++ b/AVStream/avscamera/sys/PreviewHwSim.h
@@ -0,0 +1,57 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ PreviewHwSim.h
+
+ Abstract:
+
+ This file contains the definition of the CPreviewHardwareSimulation class.
+
+ This is a specialization of CHardwareSimulation that provides preview-
+ specific metadata.
+
+ History:
+
+ created 5/28/2014
+
+**************************************************************************/
+
+#pragma once
+
+// forward references
+struct ISP_FRAME_SETTINGS;
+
+class CPreviewHardwareSimulation :
+ public CHardwareSimulation
+{
+public:
+ CPreviewHardwareSimulation(
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+ );
+
+ virtual ~CPreviewHardwareSimulation();
+
+ virtual
+ void
+ FakeHardware();
+
+protected:
+ METADATA_PREVIEWAGGREGATION
+ CPreviewHardwareSimulation::
+ GetMetadata();
+
+ // Inject preview pin-specific metadata.
+ virtual
+ void
+ EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+ );
+
+};
+
diff --git a/AVStream/avscamera/sys/RGB24Synthesizer.cpp b/AVStream/avscamera/sys/RGB24Synthesizer.cpp
new file mode 100644
index 00000000..21c6e054
--- /dev/null
+++ b/AVStream/avscamera/sys/RGB24Synthesizer.cpp
@@ -0,0 +1,133 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ RGB24Synthesizer.cpp
+
+ Abstract:
+
+ This file contains the implementation of CRGB24Synthesizer.
+
+ CRGB24Synthesizer is derived from CRGBSynthesizer. It uses the RGB
+ color space and defines a Commit() function that reformats pixels into
+ the RGB24 format. RGB24 uses 8 bits per primary and 3 bytes per pixel
+ in a single plane.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+// suppressed due to Esp:773
+#pragma warning (push)
+#pragma warning( disable:26015 ) // Suppress OACR error. Seems nonsensical. TODO: Must revisit.
+#pragma warning( disable:26019 )
+_Success_(return > 0)
+ULONG
+CRGB24Synthesizer::
+Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+)
+/*++
+
+Routine Description:
+
+ Copy (and reformat, if necessary) pixels from the internal scratch
+ buffer. If the output format decimates chrominance, do it here.
+
+Arguments:
+
+ Buffer -
+ The output buffer to fill.
+
+ Size -
+ The size of the output buffer in bytes.
+
+ Stride -
+ The length of a row in bytes.
+
+Return Value:
+
+ Number of bytes copied into Buffer.
+
+--*/
+{
+ // In case stride isn't initialized.
+ if( Stride==0 )
+ {
+ Stride = m_OutputStride;
+ }
+
+ // These are impossible conditions.
+ if( !( Buffer &&
+ m_Buffer &&
+ (Size&3)==0 && // the rows are dword aligned, so the size must be too.
+ Size>3 && // there must be room for at least 1 pixel
+ (Stride&3)==0 && // rows should be DWORD aligned
+ Stride>3 && // rows should contain at least 1 pixel
+ m_Height>0 &&
+ m_Width>0
+ ) )
+ {
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+
+ ULONG limit = min( Size/Stride, m_Height );
+ for( ULONG row=0; row<limit; row++ )
+ {
+ PDWORD pSrc = (PDWORD) GetImageLocation( 0, m_FlipVertical ? (m_Height - row -1) : row );
+ PUCHAR pDst = Buffer + (row * Stride);
+ ULONG col = min( m_Width, Stride/3 );
+
+ while( col )
+ {
+ // This optimizes the copy fairly well on most machines.
+ if( col>=4 )
+ {
+ DWORD P0 = pSrc[0];
+ DWORD P1 = pSrc[1];
+ DWORD P2 = pSrc[2];
+ DWORD P3 = pSrc[3];
+ ((PDWORD) pDst)[0] = ((P0 ) & 0x00FFFFFF) | (P1 << 24);
+ ((PDWORD) pDst)[1] = ((P1 >> 8) & 0x0000FFFF) | (P2 << 16);
+ ((PDWORD) pDst)[2] = ((P2 >> 16) & 0x000000FF) | (P3 << 8);
+ pDst += 4 * 3;
+ pSrc += 4;
+ col -= 4;
+ }
+ else
+ {
+ DWORD P0 = *pSrc++;
+ *pDst++ = (UCHAR) (P0);
+ *pDst++ = (UCHAR) (P0 >> 8);
+ *pDst++ = (UCHAR) (P0 >> 16);
+ col--;
+ }
+ }
+ }
+
+ return limit * Stride;
+}
+// suppressed due to Esp:773
+#pragma warning (pop)
diff --git a/AVStream/avscamera/sys/RGB24Synthesizer.h b/AVStream/avscamera/sys/RGB24Synthesizer.h
new file mode 100644
index 00000000..5a5d8f70
--- /dev/null
+++ b/AVStream/avscamera/sys/RGB24Synthesizer.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ RGB24Synthesizer.h
+
+ Abstract:
+
+ This file contains the definition of CRGB24Synthesizer.
+
+ CRGB24Synthesizer is derived from CXRGBSynthesizer. It uses the RGB
+ color space and defines a Commit() function that reformats pixels into
+ the RGB24 format. RGB24 uses 8 bits per primary and 3 bytes per pixel
+ in a single plane.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+/*************************************************
+
+ CRGB24Synthesizer
+
+ Image synthesizer for RGB24 format.
+
+*************************************************/
+
+class CRGB24Synthesizer
+ : public CXRGBSynthesizer
+{
+public:
+
+ //
+ // Default constructor
+ //
+ CRGB24Synthesizer(
+ LONG Width=0,
+ LONG Height=0
+ )
+ : CXRGBSynthesizer(Width, Height)
+ {
+ // Round up to the next full dword for a row on output.
+ m_OutputStride = (( Width * 3 ) + 3) & ((LONG) ~3);
+ m_FormatName = "RGB24";
+ }
+
+ //
+ // Commit
+ //
+ // Copy (and reformat, if necessary) pixels from the internal scratch
+ // buffer. If the output format decimates chrominance, do it here.
+ //
+ virtual
+ _Success_(return > 0)
+ ULONG
+ Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+ );
+};
+
diff --git a/AVStream/avscamera/sys/Ref.h b/AVStream/avscamera/sys/Ref.h
new file mode 100644
index 00000000..c2c4d76c
--- /dev/null
+++ b/AVStream/avscamera/sys/Ref.h
@@ -0,0 +1,185 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ ref.h
+
+ Abstract:
+
+ Implement a reference counting base class. Also implement something
+ similar to ComPtr<>, called a CRefPtr<>. The implementation may not
+ be as robust as ComPtr<>, but it should do the job here.
+
+ History:
+
+ created 12/8/2014
+
+**************************************************************************/
+
+#pragma once
+
+class CRef : public CNonCopyable
+{
+private:
+ EX_RUNDOWN_REF m_Rundown;
+
+public:
+ // Initialize.
+ CRef()
+ {
+ Reset();
+ }
+
+ // Prevent deletion until the last reference is gone.
+ ~CRef()
+ {
+ Wait();
+ }
+
+ // Increment the reference.
+ BOOLEAN
+ Acquire()
+ {
+ return ExAcquireRundownProtection( &m_Rundown );
+ }
+
+ // Decrement the reference.
+ void
+ Release()
+ {
+ return ExReleaseRundownProtection( &m_Rundown );
+ }
+
+ // Wait for the last reference to go away.
+ // Note: This must be called by the child object's destructor.
+ void
+ Wait()
+ {
+ ExWaitForRundownProtectionRelease( &m_Rundown );
+ }
+
+ // Reinitialize to reuse the associated object.
+ void
+ Reset()
+ {
+ ExInitializeRundownProtection( &m_Rundown );
+ }
+};
+
+template<class T>
+class CRefPtr
+{
+private:
+ T *m_ptr;
+
+public:
+ CRefPtr()
+ : m_ptr(nullptr)
+ {}
+
+ // Copy constructor.
+ CRefPtr( const CRefPtr<T> &ptr )
+ : m_ptr(nullptr)
+ {
+ // Make an initial assignment.
+ if( ptr && ptr->Acquire() )
+ {
+ m_ptr = ptr;
+ }
+ }
+
+ // Initial construction with a T object.
+ CRefPtr( T *ptr )
+ : m_ptr(nullptr)
+ {
+ // Make an initial assignment.
+ if( ptr && ptr->Acquire() )
+ {
+ m_ptr = ptr;
+ }
+ }
+
+ // Decrement the reference on destruction.
+ ~CRefPtr()
+ {
+ // Free any ptr.
+ if( m_ptr )
+ {
+ m_ptr->Release();
+ }
+ }
+
+ // Assignment
+ CRefPtr<T> &
+ operator = ( T *ptr )
+ {
+ if( m_ptr )
+ {
+ m_ptr->Release();
+ }
+
+ if( ptr )
+ {
+ ptr->Acquire();
+ }
+
+ m_ptr = ptr;
+ return *this;
+ }
+
+ // Assignment
+ CRefPtr<T> &
+ operator = ( CRefPtr<T> &ptr )
+ {
+ return
+ (*this = ptr.m_ptr);
+ }
+
+ // Dereference the pointer.
+ T *
+ operator -> ()
+ {
+ return m_ptr;
+ }
+
+ // Test for nullptr.
+ operator bool()
+ {
+ return m_ptr != nullptr;
+ }
+
+ // Test for !nullptr.
+ bool
+ operator !()
+ {
+ return !m_ptr;
+ }
+
+ // Test for equality.
+ bool
+ operator ==( T *ptr )
+ {
+ return m_ptr == ptr;
+ }
+
+ // Unsafe accessor. Use sparingly.
+ T *
+ get()
+ {
+ return m_ptr;
+ }
+};
+
+// Test for equality.
+template <class T>
+inline
+bool
+operator ==( T *ptr1, CRefPtr<T> &ptr2 )
+{
+ return ptr2 == ptr1;
+}
+
diff --git a/AVStream/avscamera/sys/Roi.cpp b/AVStream/avscamera/sys/Roi.cpp
new file mode 100644
index 00000000..e1118996
--- /dev/null
+++ b/AVStream/avscamera/sys/Roi.cpp
@@ -0,0 +1,629 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ Roi.cpp
+
+ Abstract:
+
+ This file contains the implemention of CRoiConfig, CRoiProperty and
+ related classes used in the filter to implement ROI handling.
+
+ History:
+
+ created 6/27/2013
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+// Helper function to diff ptrs.
+inline
+UINT_PTR
+ByteDiffPtrs( PVOID pBase, PVOID pCurrent )
+{
+ PAGED_CODE();
+
+ return reinterpret_cast<PBYTE>(pCurrent) - reinterpret_cast<PBYTE>(pBase) ;
+}
+
+// Helper function to get the size of an ROI control based just on the ID.
+static
+ULONG
+GetSizeOfRoiInfo( ULONG ControlId )
+{
+ PAGED_CODE();
+
+ switch( ControlId )
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE:
+ return sizeof(KSCAMERA_EXTENDEDPROP_ROI_WHITEBALANCE);
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE:
+ return sizeof(KSCAMERA_EXTENDEDPROP_ROI_EXPOSURE);
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE:
+ return sizeof(KSCAMERA_EXTENDEDPROP_ROI_FOCUS);
+ break;
+
+ default:
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+}
+
+// Helper function to get the size of an ROI control.
+static
+ULONG
+GetSize(
+ _In_ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pCtrl
+)
+{
+ PAGED_CODE();
+
+ // This actually needs to return the type based on the ROI_INFO size
+ ULONG RoiInfoSize = GetSizeOfRoiInfo( pCtrl->ControlId );
+
+ if( RoiInfoSize )
+ {
+ return
+ sizeof(KSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL) +
+ (pCtrl->ROICount * RoiInfoSize);
+ }
+ else
+ {
+ NT_ASSERTMSG("GetSizeOfRoiInfo( pCtrl->ControlId ) returned 0! Should never happen!", FALSE);
+ return 0;
+ }
+}
+
+// Helper function to walk to the next ROI control.
+static
+PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL
+NextCtrl(
+ _In_ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pCtrl
+)
+{
+ PAGED_CODE();
+
+ ULONG Size = GetSize( pCtrl );
+
+ if( Size )
+ {
+ return
+ reinterpret_cast<PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL>
+ (((PBYTE) pCtrl) + Size);
+ }
+ else
+ {
+ NT_ASSERTMSG("GetSize( pCtrl ) returned 0! Should never happen!", FALSE);
+ return nullptr;
+ }
+}
+
+PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL
+CRoiProperty::
+Find(
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Property
+)
+/*++
+
+Routine Description:
+
+ Search this ROI property for a property ID.
+
+Arguments:
+
+ Property -
+ Which control to find.
+
+Return Value:
+
+ A pointer to the ROI control structure.
+
+--*/
+{
+ PAGED_CODE();
+
+ // We assume the controls have been validated first.
+ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pIspCtrl =
+ reinterpret_cast<PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL> (this+1);
+
+ // Loop thru the controls.
+ for( ULONG i=0; i<m_Hdr.ControlCount; i++ )
+ {
+ if( pIspCtrl->ControlId == (ULONG) Property )
+ {
+ return pIspCtrl;
+ }
+
+ // Advance to the next control.
+ pIspCtrl = NextCtrl( pIspCtrl );
+ }
+
+ return nullptr;
+}
+
+PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL
+CRoiProperty::
+Add(
+ _In_ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pCtrl
+)
+/*++
+
+Routine Description:
+
+ Add a control to the end of this header.
+
+ Note: This function does not reallocate memory. Be careful to ensure
+ there is space available.
+
+Arguments:
+
+ pCtrl -
+ An ROI control to append.
+
+Return Value:
+
+ A pointer to the appended ROI control structure.
+
+--*/
+{
+ PAGED_CODE();
+
+ // Only bother to add if there are ROIs.
+ if( pCtrl->ROICount > 0 )
+ {
+ // We assume the controls have been validated first.
+ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pIspCtrl =
+ reinterpret_cast<PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL> (this+1);
+
+ // Loop thru all the controls.
+ for( ULONG i=0; i<m_Hdr.ControlCount; i++ )
+ {
+ // Advance to the next control.
+ pIspCtrl = NextCtrl( pIspCtrl );
+ }
+
+ ULONG SizeToCopy = ::GetSize(pCtrl);
+
+ memcpy( pIspCtrl,
+ pCtrl,
+ SizeToCopy ) ;
+
+ Size += SizeToCopy ; // Adjust our size.
+ m_Hdr.Size += SizeToCopy ;
+ m_Hdr.ControlCount++ ; // Add one to the control count.
+ }
+ return nullptr;
+}
+
+bool
+CRoiProperty::
+isValid()
+/*++
+
+Routine Description:
+
+ Parse the current ROI Property list and make sure all the control
+ structures are self-consistent.
+
+ Note: This is a very non-trivial problem.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ A pointer to the appended ROI control structure.
+
+--*/
+{
+ PAGED_CODE();
+
+ DBG_ENTER( "()" );
+
+ ULONGLONG FocusFlags = 0;
+ ULONGLONG ExposureFlags = 0;
+ ULONGLONG WhiteBalanceFlags = 0;
+
+ if( Version < KSCAMERA_EXTENDEDPROP_VERSION ||
+ PinId != KSCAMERA_EXTENDEDPROP_FILTERSCOPE ||
+ (Capability & ~(KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_CAPS_CANCELLABLE)) != 0 ||
+ (Flags & ~KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION) != 0 || // Allow cancellation of ROI.
+ Size < sizeof(*this) )
+ {
+ //NT_ASSERT(FALSE);
+ if( Version < KSCAMERA_EXTENDEDPROP_VERSION )
+ {
+ DBG_TRACE( "Failed: Verison=%d", Version );
+ }
+ if( PinId != KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ DBG_TRACE( "Failed: PinId=%d", PinId );
+ }
+ if( (Capability & ~(KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_CAPS_CANCELLABLE)) != 0 )
+ {
+ DBG_TRACE( "Failed: Capability=0x%016llX", Capability );
+ }
+ if( (Flags & ~KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION) != 0 )
+ {
+ DBG_TRACE( "Failed: Flags=0x%016llX", Flags );
+ }
+ if( Size < sizeof(*this) )
+ {
+ DBG_TRACE( "Failed(0): Size=%d, should be at least %Iu", Size, sizeof(*this) );
+ }
+
+ DBG_LEAVE( "()=false" );
+ return false;
+ }
+
+ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pIspCtrl =
+ reinterpret_cast<PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL> (this+1);
+
+ // Loop thru the controls.
+ for( ULONG i=0; i<m_Hdr.ControlCount; i++ )
+ {
+ // Make sure there is room to inspect this control
+ if( Size < ByteDiffPtrs( this, pIspCtrl+1 ) ||
+ m_Hdr.Size < ByteDiffPtrs( &m_Hdr, pIspCtrl+1 ) )
+ {
+ //NT_ASSERT(FALSE);
+ DBG_TRACE( "Failed(1): Size=%d, should be at least %Iu", Size, ByteDiffPtrs( this, pIspCtrl+1 ) );
+ DBG_TRACE( " Or: m_Hdr.Size=%d, should be at least %Iu", m_Hdr.Size, ByteDiffPtrs( &m_Hdr, pIspCtrl+1 ) );
+ DBG_LEAVE( "()=false" );
+ return false;
+ }
+
+ // Make sure the control is of a known type
+ switch( pIspCtrl->ControlId )
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE:
+ break;
+
+ default:
+ //NT_ASSERT(FALSE);
+ DBG_LEAVE( "()=false : Invalid ControlId = 0x%08X", pIspCtrl->ControlId );
+ return false;
+ }
+
+ // Make sure there is room for the # of ROIs reported
+ if( Size < ByteDiffPtrs( this, NextCtrl(pIspCtrl) ) ||
+ m_Hdr.Size < ByteDiffPtrs( &m_Hdr, NextCtrl(pIspCtrl) ) )
+ {
+ //NT_ASSERT(FALSE);
+ DBG_TRACE( "Failed(2): Size=%d, should be at least %Iu", Size, ByteDiffPtrs( this, NextCtrl(pIspCtrl) ) );
+ DBG_TRACE( " Or: m_Hdr.Size=%d, should be at least %Iu", m_Hdr.Size, ByteDiffPtrs( &m_Hdr, NextCtrl(pIspCtrl) ) );
+ DBG_LEAVE( "()=false" );
+ return false;
+ }
+
+ // Validate the ROIs
+ for( ULONG j=0; j<pIspCtrl->ROICount; j++ )
+ {
+ // Index into to the control's ROI list. Get the equivilent of "pIspCtrl->RoiInfo[j]"
+ PKSCAMERA_EXTENDEDPROP_ROI_INFO pRoiInfo =
+ reinterpret_cast<PKSCAMERA_EXTENDEDPROP_ROI_INFO>
+ (((PBYTE) (pIspCtrl+1)) + (j * GetSizeOfRoiInfo(pIspCtrl->ControlId) ));
+
+ // Validate the cooridinates
+ if( pRoiInfo->Region.top < (LONG) TO_Q31(0) ||
+ pRoiInfo->Region.bottom < (LONG) TO_Q31(0) ||
+ pRoiInfo->Region.left < (LONG) TO_Q31(0) ||
+ pRoiInfo->Region.right < (LONG) TO_Q31(0) )
+ {
+ //NT_ASSERT(FALSE);
+ DBG_TRACE( "Failed: Region out of range." );
+ DBG_TRACE( " (top=0x%08X, left=0x%08X, bottom=0x%08X, right=0x%08X)"
+ , pRoiInfo->Region.top
+ , pRoiInfo->Region.bottom
+ , pRoiInfo->Region.left
+ , pRoiInfo->Region.right );
+ DBG_LEAVE( "()=false" );
+ return false;
+ }
+
+ // Validate the RegionOfInterestType
+ switch( pRoiInfo->RegionOfInterestType )
+ {
+ case KSCAMERA_EXTENDEDPROP_ROITYPE_UNKNOWN:
+ case KSCAMERA_EXTENDEDPROP_ROITYPE_FACE:
+ break;
+ default:
+ //NT_ASSERT(FALSE);
+ DBG_LEAVE( "()=false Failed: RegionOfInterestType=%d", pRoiInfo->RegionOfInterestType );
+ return false;
+ }
+
+ // Validate the Weight
+ if( pRoiInfo->Weight > 100 )
+ {
+ //NT_ASSERT(FALSE);
+ DBG_LEAVE( "()=false Failed: Weight=%d", pRoiInfo->Weight );
+ return false;
+ }
+
+ // Validate the Flags.
+ // Note: the driver doesn't allow mis-matched ROI Flags.
+ ULONGLONG RoiFlags = pRoiInfo->Flags & ~KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION;
+
+ switch( pIspCtrl->ControlId )
+ {
+ // Exposure & WhiteBalance only support Auto, Manual & Lock.
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE:
+ if( j!=0 )
+ {
+ if( RoiFlags != ExposureFlags )
+ {
+ DBG_LEAVE( "()=false : Mismatched Exposure Flags" );
+ return false;
+ }
+ }
+ else
+ {
+ switch( RoiFlags &
+ (KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO|
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK) )
+ {
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO + KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ case 0:
+ break;
+ default:
+ DBG_LEAVE( "()=false : Invalid Exposure Flags" );
+ return false;
+ }
+ ExposureFlags = RoiFlags;
+ }
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE:
+ if( j!=0 )
+ {
+ if( RoiFlags != WhiteBalanceFlags )
+ {
+ DBG_LEAVE( "()=false : Mismatched WhiteBalance Flags" );
+ return false;
+ }
+ }
+ else
+ {
+ switch( RoiFlags &
+ (KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO|
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK) )
+ {
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO + KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ case 0:
+ break;
+ default:
+ DBG_LEAVE( "()=false : Invalid WhiteBalance Flags" );
+ return false;
+ }
+ WhiteBalanceFlags = RoiFlags;
+ }
+ break;
+
+ // Focus supports additional flags...
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE:
+ if( j!=0 )
+ {
+ if( RoiFlags != FocusFlags )
+ {
+ DBG_LEAVE( "()=false : Mismatched Focus Flags" );
+ return false;
+ }
+ }
+ else
+ {
+ switch( RoiFlags &
+ (KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK) )
+ {
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO + KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS + KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK:
+ case 0:
+ break;
+ default:
+ DBG_LEAVE( "()=false : Invalid Focus Flags" );
+ return false;
+ }
+
+ switch( RoiFlags & KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MASK )
+ {
+ case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MACRO:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_NORMAL:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE:
+ // Depreciated cases are not supported:
+ //case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_INFINITY:
+ //case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_HYPERFOCAL:
+ case 0:
+ break;
+ default:
+ DBG_LEAVE( "()=false : Invalid Focus Range" );
+ return false;
+ }
+ FocusFlags = RoiFlags;
+ }
+ break;
+ }
+ }
+
+ // Advance to the next control.
+ pIspCtrl = NextCtrl( pIspCtrl ) ;
+ }
+
+ DBG_LEAVE( "()=true" );
+ return true;
+}
+
+// Log to the debug output.
+void
+CRoiProperty::
+Log()
+{
+ PAGED_CODE();
+
+ DBG_TRACE("Version=%d, PinId=%d, Capability=0x%016llX, Flags=0x%016llX, Size=%d",
+ Version, PinId, Capability, Flags, Size );
+
+ CRoiIspControl *pIspCtrl = reinterpret_cast<CRoiIspControl *> (this+1);
+
+ // Loop thru the controls.
+ for( ULONG i=0; i<m_Hdr.ControlCount; i++ )
+ {
+ pIspCtrl->Log();
+
+ // Advance to the next control.
+ pIspCtrl = reinterpret_cast<CRoiIspControl *>( NextCtrl( pIspCtrl ) ) ;
+ }
+}
+
+//
+// Initialize a block of memory from another ROI control
+//
+// Note: This function assumes enough ROI_INFO structures follow
+// such that this copy will not overrun.
+//
+BOOL
+CRoiIspControl::
+Init(
+ _In_ CRoiProperty *pRoiProperty,
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Property
+)
+/*++
+
+Routine Description:
+
+ Initialize a block of memory from another ROI control
+
+ Note: This function assumes enough ROI_INFO structures follow
+ such that this copy will not overrun.
+
+Arguments:
+
+ pRoiProperty -
+ The extended ROI control payload.
+
+ Property -
+ Which ISP control to copy from the payload.
+
+Return Value:
+
+ TRUE - The ROI was set.
+ FALSE - The ROI was cleared.
+
+--*/
+{
+ PAGED_CODE();
+
+ CRoiIspControl *
+ pCtrl = reinterpret_cast<CRoiIspControl *> (pRoiProperty->Find( Property ));
+
+ if( pCtrl )
+ {
+ memcpy( this,
+ pCtrl,
+ pCtrl->GetSize() );
+ return TRUE;
+ }
+
+ ControlId = Property;
+ ROICount = 0;
+ return FALSE;
+}
+
+// Log to the debug output.
+void
+CRoiIspControl::
+Log()
+{
+ PAGED_CODE();
+
+ switch( ControlId )
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE:
+ DBG_TRACE("WhiteBalance");
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE:
+ DBG_TRACE("Exposure");
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE:
+ DBG_TRACE("Focus");
+ break;
+
+ default:
+ DBG_TRACE("[Unknown]");
+ NT_ASSERT(FALSE);
+ break;
+ }
+
+ DBG_TRACE("Result=0x%08X", Result);
+
+ for( ULONG i=0; i<ROICount; i++ )
+ {
+ // Index into to the control's ROI list. Get the equivilent of "pIspCtrl->RoiInfo[j]"
+ PKSCAMERA_EXTENDEDPROP_ROI_INFO pRoiInfo =
+ reinterpret_cast<PKSCAMERA_EXTENDEDPROP_ROI_INFO>
+ (((PBYTE) (this+1)) + (i * GetSizeOfRoiInfo(ControlId) ));
+
+ DBG_TRACE(" | Flags=0x%016llX [Top=0x%08X, Left=0x%08X, Bottom=0x%08X, Right=0x%08X]",
+ pRoiInfo->Flags,
+ pRoiInfo->Region.top,
+ pRoiInfo->Region.left,
+ pRoiInfo->Region.bottom,
+ pRoiInfo->Region.right );
+ }
+}
+
+//
+// Initialize a block of memory with an empty control list.
+//
+CRoiIspControl::
+CRoiIspControl(
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Property
+)
+{
+ PAGED_CODE();
+
+ ControlId = Property;
+ ROICount = 0;
+ Result = 0;
+ Reserved = 0;
+}
+
+ULONG
+CRoiIspControl::
+GetSize()
+{
+ PAGED_CODE();
+
+ return (ROICount>0) ? ::GetSize( this ) : 0;
+}
+
diff --git a/AVStream/avscamera/sys/Roi.h b/AVStream/avscamera/sys/Roi.h
new file mode 100644
index 00000000..5149bf24
--- /dev/null
+++ b/AVStream/avscamera/sys/Roi.h
@@ -0,0 +1,279 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ Roi.h
+
+ Abstract:
+
+ This file contains the definition of CRoiConfig, CRoiProperty and
+ related classes used in the filter to implement ROI handling.
+
+ History:
+
+ created 6/27/2013
+
+**************************************************************************/
+
+const ULONG MAX_ROI = 4;
+
+class CRoiIspControl ;
+
+class CRoiConfigCaps : public KSCAMERA_EXTENDEDPROP_ROI_CONFIGCAPS
+{
+public:
+ CRoiConfigCaps(
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Id,
+ _In_ ULONG MaxROI,
+ _In_ ULONGLONG Caps=0
+ )
+ {
+ ControlId = Id;
+ MaxNumberOfROIs = MaxROI;
+ Capability = Caps;
+ }
+
+ static const ULONGLONG FOCUS_CAPS =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MACRO |
+ KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_NORMAL |
+ KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+
+ static const ULONGLONG EXPOSURE_CAPS =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+
+ static const ULONGLONG WHITEBALANCE_CAPS =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+};
+
+class CRoiConfigCapsHdr : public KSCAMERA_EXTENDEDPROP_ROI_CONFIGCAPSHEADER
+{
+ CRoiConfigCaps FocusCaps;
+ CRoiConfigCaps ExposureCaps;
+ CRoiConfigCaps WhiteBalanceCaps;
+
+public:
+ CRoiConfigCapsHdr()
+ : FocusCaps(
+ KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE,
+ MAX_ROI,
+ CRoiConfigCaps::FOCUS_CAPS)
+ , ExposureCaps(
+ KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE,
+ MAX_ROI,
+ CRoiConfigCaps::EXPOSURE_CAPS )
+ , WhiteBalanceCaps(
+ KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE,
+ MAX_ROI,
+ CRoiConfigCaps::WHITEBALANCE_CAPS )
+ {
+ ConfigCapCount = 3;
+ Reserved = 0;
+ Size = sizeof(*this);
+ }
+};
+
+class CRoiConfig : public KSCAMERA_EXTENDEDPROP_HEADER
+{
+ CRoiConfigCapsHdr CapsHdr;
+public:
+ CRoiConfig()
+ {
+ Version = 1;
+ PinId = KSCAMERA_EXTENDEDPROP_FILTERSCOPE;
+ Size = sizeof(*this);
+ Result = 0;
+ Capability = 0;
+ Flags = 0;
+ }
+ CRoiConfig( KSCAMERA_EXTENDEDPROP_HEADER &hdr )
+ : KSCAMERA_EXTENDEDPROP_HEADER(hdr)
+ {
+ Size = sizeof(*this);
+ }
+
+ bool isValid()
+ {
+ return (Version == KSCAMERA_EXTENDEDPROP_VERSION) &&
+ (Size >= sizeof(*this)) ;
+ }
+};
+
+//
+// A wrapper for the KSCAMERA_EXTENDEDPROP_ROI payload
+//
+// The payload extends beyond the end of this class definition. However the
+// payload is variable in length, so this class definition contains member
+// functions that can be used to access and append items to the payload.
+//
+class CRoiProperty : public KSCAMERA_EXTENDEDPROP_HEADER
+{
+ KSCAMERA_EXTENDEDPROP_ROI_ISPCONTROLHEADER m_Hdr;
+
+public:
+ // Default ctor - used to init the buffer when returning ROI info.
+ CRoiProperty()
+ {
+ Version = KSCAMERA_EXTENDEDPROP_VERSION;
+ PinId = KSCAMERA_EXTENDEDPROP_FILTERSCOPE;
+ Size = sizeof(*this);
+ Result = 0;
+ Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_CAPS_CANCELLABLE;
+ Flags = 0;
+
+ m_Hdr.ControlCount = 0;
+ m_Hdr.Size = sizeof(m_Hdr);
+ m_Hdr.Reserved = 0;
+ }
+
+ // Validate the CRoiProperty
+ bool
+ isValid();
+
+ // Get Size attribute.
+ ULONG
+ GetSize()
+ {
+ return Size;
+ }
+
+ // Get number of controls. (1-3)
+ ULONG
+ GetControlCount()
+ {
+ return m_Hdr.ControlCount;
+ }
+
+ // Find a given control after the property header.
+ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL
+ Find(
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Property
+ );
+
+ //
+ // Add a control to the end of this header.
+ //
+ // Note: This function does not reallocate memory. Be careful to ensure
+ // there is space available.
+ //
+ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL
+ Add(
+ _In_ PKSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL pCtrl
+ );
+
+ void
+ Log();
+};
+
+// Note: No initializer classes are provided for the following DDI
+// structure definitions since there is no practical difference in their
+// definitions. However the CRoiIspControl::GetSize() method is aware
+// of them and will report the correct size of the structure if there were
+// any difference in size.
+//
+// - KSCAMERA_EXTENDEDPROP_ROI_WHITEBALANCE
+// - KSCAMERA_EXTENDEDPROP_ROI_EXPOSURE
+// - KSCAMERA_EXTENDEDPROP_ROI_FOCUS
+//
+class CRoiIspControl : public KSCAMERA_EXTENDEDPROP_ROI_ISPCONTROL
+{
+public:
+ BOOL
+ Init(
+ _In_ CRoiProperty *pRoiProperty,
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Property
+ );
+
+ CRoiIspControl(
+ _In_ KSPROPERTY_CAMERACONTROL_EXTENDED_PROPERTY Property=
+ KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+ );
+
+ void
+ Log();
+
+ ULONG
+ GetSize();
+};
+
+// Simple classes used by the driver to hold the maximum allowed number of ROIs.
+class CWhiteBalanceRoiIspControl : public CRoiIspControl
+{
+private:
+ KSCAMERA_EXTENDEDPROP_ROI_WHITEBALANCE ROI[MAX_ROI];
+
+public:
+ CWhiteBalanceRoiIspControl(
+ _In_ CRoiProperty *pRoiProperty
+ )
+ {
+ Init( pRoiProperty, KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE );
+ }
+
+ CWhiteBalanceRoiIspControl()
+ : CRoiIspControl( KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE )
+ {}
+
+ ULONGLONG
+ GetFlags()
+ {
+ return ( ROICount>0 ) ? ROI[0].ROIInfo.Flags : 0;
+ }
+};
+
+class CExposureRoiIspControl : public CRoiIspControl
+{
+private:
+ KSCAMERA_EXTENDEDPROP_ROI_EXPOSURE ROI[MAX_ROI];
+
+public:
+ CExposureRoiIspControl(
+ _In_ CRoiProperty *pRoiProperty
+ )
+ {
+ Init( pRoiProperty, KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE );
+ }
+
+ CExposureRoiIspControl()
+ : CRoiIspControl( KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE )
+ {}
+
+ ULONGLONG
+ GetFlags()
+ {
+ return ( ROICount>0 ) ? ROI[0].ROIInfo.Flags : 0;
+ }
+};
+
+class CFocusRoiIspControl : public CRoiIspControl
+{
+private:
+ KSCAMERA_EXTENDEDPROP_ROI_FOCUS ROI[MAX_ROI];
+
+public:
+ CFocusRoiIspControl(
+ _In_ CRoiProperty *pRoiProperty
+ )
+ {
+ Init( pRoiProperty, KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE );
+ }
+
+ CFocusRoiIspControl()
+ : CRoiIspControl( KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE )
+ {}
+
+ ULONGLONG
+ GetFlags()
+ {
+ return ( ROICount>0 ) ? ROI[0].ROIInfo.Flags : 0;
+ }
+};
+
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;
+}
diff --git a/AVStream/avscamera/sys/Sensor.h b/AVStream/avscamera/sys/Sensor.h
new file mode 100644
index 00000000..061e6ed5
--- /dev/null
+++ b/AVStream/avscamera/sys/Sensor.h
@@ -0,0 +1,605 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ Sensor.h
+
+ Abstract:
+
+ Base Sensor class. Derive from this class to implement an interface
+ to your hardware sensor object.
+
+ This class provides a set of "knobs" to control a model camera.
+
+ 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. Other
+ than that, it's just an interface class.
+
+ History:
+
+ created 5/5/2014
+
+**************************************************************************/
+
+#pragma once
+
+//
+// The following DECLARE_PROPERTY_XXX() macros are used to create consistent
+// function names for each control.
+//
+#define DECLARE_PROPERTY_GET( type, name ) \
+ virtual \
+ NTSTATUS \
+ Get##name( \
+ _Inout_ type *pProperty \
+ ); \
+
+#define DECLARE_PROPERTY_SIZEOF( name ) \
+ virtual \
+ ULONG \
+ SizeOf##name();
+
+#define DECLARE_PROPERTY_SET( type, name ) \
+ virtual \
+ NTSTATUS \
+ Set##name( \
+ _In_ type *pProperty \
+ );
+
+#define DECLARE_PROPERTY_SET_ASYNC( type, name ) \
+ virtual \
+ NTSTATUS \
+ Set##name##Async( \
+ _In_ type *pProperty, \
+ _In_ CNotifier *Notifier \
+ );
+
+#define DECLARE_PROPERTY_CANCEL( type, name ) \
+ virtual \
+ NTSTATUS \
+ Cancel##name();
+
+#define DECLARE_PROPERTY( type, name ) \
+ DECLARE_PROPERTY_GET( type, name ) \
+ DECLARE_PROPERTY_SET( type, name )
+
+#define DECLARE_PROPERTY_ASYNC_NOCANCEL( type, name ) \
+ DECLARE_PROPERTY_GET( type, name ) \
+ DECLARE_PROPERTY_SET_ASYNC( type, name )
+
+#define DECLARE_PROPERTY_ASYNC( type, name ) \
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( type, name ) \
+ DECLARE_PROPERTY_CANCEL( type, name )
+
+#define DECLARE_PROPERTY_VARSIZE_ASYNC( type, name ) \
+ DECLARE_PROPERTY_ASYNC( type, name ) \
+ DECLARE_PROPERTY_SIZEOF( name )
+
+#define DECLARE_PROPERTY_VARSIZE_ASYNC_NOCANCEL( type, name ) \
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( type, name ) \
+ DECLARE_PROPERTY_SIZEOF( name )
+
+
+//
+// CNotifer
+//
+// A CNotiver is just a wrapper on a KS event. It holds the parameters
+// needed to invoke the KS event successfully and it is referenced counted
+// to make sure the filter does not go away before your sensor is done with
+// the notifier.
+//
+// These objects should be instantiated in the filter and a reference
+// held in your sensor object.
+//
+class CNotifier : public CRef
+{
+private:
+ PVOID m_Object;
+ GUID m_EventSet;
+ ULONG m_EventId;
+ ULONG m_DataSize;
+ PVOID m_Data;
+ PFNKSGENERATEEVENTCALLBACK m_Callback;
+ PVOID m_CallbackContext;
+
+public:
+ CNotifier(
+ _In_ PKSFILTER Filter,
+ _In_ const GUID *EventSet,
+ _In_ ULONG EventId,
+ _In_ ULONG DataSize=0,
+ _In_opt_ PVOID Data=nullptr,
+ _In_opt_ PFNKSGENERATEEVENTCALLBACK Callback=nullptr,
+ _In_opt_ PVOID CallbackContext=nullptr
+ )
+ : m_Object(Filter)
+ , m_EventSet(*EventSet)
+ , m_EventId(EventId)
+ , m_DataSize(DataSize)
+ , m_Data(Data)
+ , m_Callback(Callback)
+ , m_CallbackContext(CallbackContext)
+ {}
+
+ CNotifier(
+ _In_ PKSPIN Pin,
+ _In_ const GUID *EventSet,
+ _In_ ULONG EventId,
+ _In_ ULONG DataSize=0,
+ _In_opt_ PVOID Data=nullptr,
+ _In_opt_ PFNKSGENERATEEVENTCALLBACK Callback=nullptr,
+ _In_opt_ PVOID CallbackContext=nullptr
+ )
+ : m_Object(Pin)
+ , m_EventSet(*EventSet)
+ , m_EventId(EventId)
+ , m_DataSize(DataSize)
+ , m_Data(Data)
+ , m_Callback(Callback)
+ , m_CallbackContext(CallbackContext)
+ {}
+
+ void
+ Set()
+ {
+ KsGenerateEvents(m_Object, &m_EventSet, m_EventId, m_DataSize, m_Data, m_Callback, m_CallbackContext);
+ }
+};
+
+class CSensor
+{
+protected:
+
+ CCaptureDevice *m_Device;
+
+ ULONG m_PinCount;
+ LONG m_FilterInstanceCount;
+
+ //
+ // The AVStream filter object associated with this CCaptureFilter.
+ //
+ CHardwareSimulation **m_HardwareSimulation;
+ CSynthesizer **m_Synthesizer;
+ ICapturePin **m_CapturePin;
+
+ PKS_VIDEOINFOHEADER *m_VideoInfoHeader;
+
+ //
+ // The number of ISR's that have occurred since capture started.
+ //
+ ULONG *m_InterruptTime;
+
+ //
+ // The last reading of mappings completed.
+ //
+ ULONG *m_LastMappingsCompleted;
+
+ static const ULONG INVALID_PIN_INDEX = 0xFFFFFFFF;
+ static const ULONG INVALID_PIN_MASK = 0;
+
+ ULONG m_PreviewMask;
+ ULONG m_StillMask;
+ ULONG m_VideoMask;
+
+ // Access control mutex.
+ KMutex m_SensorMutex;
+
+ ULONG m_PfsLoopLimit;
+ ULONG m_PfsFrameLimit;
+ ISP_FRAME_SETTINGS *m_pIspSettings;
+
+ ISP_FRAME_SETTINGS m_GlobalIspSettings;
+
+ AcpiPldRotation m_MountingOrientation;
+
+public:
+
+ CSensor(
+ _In_ CCaptureDevice *Device,
+ _In_ ULONG PinCount
+ );
+
+ //
+ // ~CSensor():
+ //
+ // The h/w Sensor destructor.
+ //
+ virtual
+ ~CSensor( );
+
+ virtual
+ NTSTATUS
+ Initialize();
+
+ virtual
+ NTSTATUS
+ ProgramDefaults();
+
+ virtual
+ void
+ Interrupt(
+ _In_ LONG PinIndex
+ );
+
+ virtual
+ PDEVICE_OBJECT
+ GetDeviceObject()
+ {
+ return m_Device->GetDeviceObject();
+ }
+
+ virtual
+ NTSTATUS
+ CreateSynthesizer(
+ _In_ PKSPIN Pin,
+ _In_ PKS_VIDEOINFOHEADER VideoInfoHeader
+ );
+
+ //
+ // AcquireHardwareResources():
+ //
+ // Called to acquire hardware resources for the device based on a given
+ // video info header. This will fail if another object has already
+ // acquired hardware resources since we emulate a single capture
+ // device.
+ //
+ virtual
+ NTSTATUS
+ AcquireHardwareResources(
+ _In_ PKSPIN Pin,
+ _In_ ICapturePin *CaptureSink,
+ _In_ PKS_VIDEOINFOHEADER VideoInfoHeader,
+ _Out_ CHardwareSimulation **pSim
+ );
+
+ //
+ // ReleaseHardwareResources():
+ //
+ // Called to release hardware resources for the device.
+ //
+ virtual
+ void
+ ReleaseHardwareResources(
+ _In_ PKSPIN Pin
+ //_In_ CHardwareSimulation *pSim
+ );
+
+ //
+ // Start():
+ //
+ // Called to start the hardware simulation. This causes us to simulate
+ // interrupts, simulate filling buffers with synthesized data, etc...
+ //
+ NTSTATUS
+ Start (
+ _In_ PKSPIN Pin
+ );
+
+ //
+ // Pause():
+ //
+ // Called to pause or unpause the hardware simulation. This will be
+ // indentical to a start or stop but it will not reset formats and
+ // counters.
+ //
+ NTSTATUS
+ Pause(
+ _In_ PKSPIN Pin,
+ _In_ BOOLEAN Pausing
+ );
+
+ NTSTATUS
+ Trigger(
+ _In_ ULONG PinId,
+ _In_ LONG mode
+ );
+
+ NTSTATUS
+ SetQPC(
+ _In_ ULONG StillIndex,
+ _In_ ULONGLONG QPC
+ );
+
+ NTSTATUS
+ GetQPC(
+ _In_ ULONG StillIndex,
+ _Out_ PULONGLONG QPC
+ );
+
+ NTSTATUS
+ SetPinMode(
+ _In_ ULONG StillIndex,
+ _In_ ULONGLONG Flags,
+ _In_ ULONG PastBuffers
+ );
+
+ NTSTATUS
+ SetPhotoFrameRate(
+ _In_ ULONG StillIndex,
+ _In_ ULONGLONG TimePerFrame
+ );
+
+ ULONGLONG
+ GetPhotoFrameRate(
+ _In_ ULONG StillIndex
+ );
+
+ NTSTATUS
+ SetFlashStatus(
+ _In_ ULONGLONG ulFlashStatus
+ );
+
+ bool
+ IsPreviewIndex(
+ _In_ ULONG Index
+ )
+ {
+ return !!(m_PreviewMask & (1<<Index)) ;
+ }
+
+ bool
+ IsStillIndex(
+ _In_ ULONG Index
+ )
+ {
+ return !!(m_StillMask & (1<<Index)) ;
+ }
+
+ bool
+ IsVideoIndex(
+ _In_ ULONG Index
+ )
+ {
+ return !!(m_VideoMask & (1<<Index)) ;
+ }
+
+ bool
+ IsValidIndex(
+ _In_ ULONG Index
+ )
+ {
+ return Index < GetPinCount() ;
+ }
+
+ inline ULONG GetNextPreviewIndex(ULONG Index=INVALID_PIN_INDEX)
+ {
+ while( IsValidIndex(++Index) )
+ {
+ if( IsPreviewIndex(Index) )
+ {
+ return Index;
+ }
+ }
+ return INVALID_PIN_INDEX;
+ }
+
+ inline ULONG GetNextStillIndex(ULONG Index=INVALID_PIN_INDEX)
+ {
+ while( IsValidIndex(++Index) )
+ {
+ if( IsStillIndex(Index) )
+ {
+ return Index;
+ }
+ }
+ return INVALID_PIN_INDEX;
+ }
+
+ inline ULONG GetNextVideoIndex(ULONG Index=INVALID_PIN_INDEX)
+ {
+ while( IsValidIndex(++Index) )
+ {
+ if( IsVideoIndex(Index) )
+ {
+ return Index;
+ }
+ }
+ return INVALID_PIN_INDEX;
+ }
+
+ LONG
+ GetTriggerMode(
+ _In_ ULONG PinId
+ );
+
+ //Not thread safe, for User mode notification only.
+ LONG
+ GetFilterCount()
+ {
+ return m_FilterInstanceCount;
+ }
+
+ NTSTATUS
+ AddFilter(PKSFILTER pFilter);
+
+ NTSTATUS
+ RemoveFilter(PKSFILTER pFilter);
+
+ ULONG
+ GetPinCount()
+ {
+ return m_PinCount;
+ }
+
+ //
+ // GetFourCC
+ //
+ // Return the FourCC code for the current pin.
+ //
+ ULONG
+ GetFourCC(
+ _In_ ULONG Index
+ )
+ {
+ return Index<m_PinCount ? m_VideoInfoHeader[Index]->bmiHeader.biCompression : 0;
+ }
+
+ //
+ // Stop():
+ //
+ // Called to stop the hardware simulation. This causes interrupts to
+ // stop issuing. When this call returns, the "fake" hardware has
+ // stopped accessing all s/g buffers, etc...
+ //
+ NTSTATUS
+ Stop (
+ _In_ PKSPIN
+ );
+
+ NTSTATUS
+ Reset(
+ _In_ PKSPIN
+ );
+
+ NTSTATUS
+ Reset(
+ );
+
+
+ //
+ // ProgramScatterGatherMappings():
+ //
+ // Called to program the hardware simulation's scatter / gather table.
+ // This synchronizes with the "fake" ISR and hardware simulation via
+ // a spinlock.
+ //
+ ULONG
+ ProgramScatterGatherMappings (
+ _In_ PKSPIN Pin,
+ _In_ PKSSTREAM_POINTER *Clone,
+ _In_ PUCHAR *Buffer,
+ _In_ PKSMAPPING Mappings,
+ _In_ ULONG MappingsCount
+ );
+
+ // Lets you know if Variable Photo Sequence is active.
+ // Note: This doesn't tell you if the pin is running.
+ virtual
+ BOOLEAN
+ IsVPSActive()
+ {
+ // VPS isn't supported by default.
+ return FALSE;
+ }
+
+ // Fetch a pointer to the global ISP_FRAME_SETTINGS
+ virtual
+ ISP_FRAME_SETTINGS *
+ GetGlobalIspSettings();
+
+ // 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.
+ virtual
+ NTSTATUS
+ SetPFS(
+ _In_ ISP_FRAME_SETTINGS *pIspSettings,
+ _In_ ULONG FrameLimit,
+ _In_ ULONG LoopLimit
+ );
+
+ virtual
+ void
+ UpdateZoom(void);
+
+ void
+ SetMountingOrientation(
+ _In_ AcpiPldRotation Orientation
+ )
+ {
+ m_MountingOrientation = Orientation;
+ }
+
+protected:
+ LONG
+ IncrementFilterCount()
+ {
+ return InterlockedIncrement(&m_FilterInstanceCount);
+ }
+
+ LONG
+ DecrementFilterCount()
+ {
+ return InterlockedDecrement(&m_FilterInstanceCount);
+ }
+
+public:
+
+ DECLARE_PROPERTY( KSPROPERTY_VIDEOCONTROL_MODE_S, VideoControlMode );
+ DECLARE_PROPERTY_GET( KSPROPERTY_VIDEOCONTROL_CAPS_S, VideoControlCaps );
+
+ DECLARE_PROPERTY_GET( KSCAMERA_EXTENDEDPROP_FOCUSSTATE, FocusState );
+ DECLARE_PROPERTY_ASYNC( KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S, FocusRect );
+ DECLARE_PROPERTY( KSPROPERTY_CAMERACONTROL_FLASH_S, Flash );
+ DECLARE_PROPERTY_GET( KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S, PinDependence );
+
+ DECLARE_PROPERTY_ASYNC( CExtendedPhotoMode, PhotoMode );
+ DECLARE_PROPERTY_GET( CExtendedProperty, PhotoFrameRate );
+ DECLARE_PROPERTY_ASYNC( CExtendedProperty, PhotoMaxFrameRate );
+ DECLARE_PROPERTY_ASYNC( CExtendedProperty, WarmStart );
+ DECLARE_PROPERTY( CExtendedMaxVideoFpsForPhotoRes, MaxVideoFpsForPhotoRes );
+ DECLARE_PROPERTY_GET( CExtendedFieldOfView, FieldOfView );
+ DECLARE_PROPERTY_GET( CExtendedCameraAngleOffset, CameraAngleOffset );
+ DECLARE_PROPERTY( CExtendedProperty, ExtendedFlash );
+
+ DECLARE_PROPERTY( CExtendedProperty, TriggerTime );
+ DECLARE_PROPERTY( CExtendedProperty, TorchMode );
+
+ DECLARE_PROPERTY_ASYNC( CExtendedVidProcSetting, Focus );
+ DECLARE_PROPERTY_ASYNC( CExtendedProperty, Iso );
+ DECLARE_PROPERTY_ASYNC( CExtendedVidProcSetting, IsoAdvanced );
+ DECLARE_PROPERTY_ASYNC( CExtendedEvCompensation, EvCompensation );
+ DECLARE_PROPERTY_ASYNC( CExtendedVidProcSetting, WhiteBalance );
+ DECLARE_PROPERTY_ASYNC( CExtendedVidProcSetting, Exposure );
+ DECLARE_PROPERTY( CExtendedProperty, PhotoConfirmation );
+ DECLARE_PROPERTY_ASYNC( CExtendedProperty, SceneMode );
+ DECLARE_PROPERTY( CExtendedProperty, FocusPriority );
+ DECLARE_PROPERTY_ASYNC( CExtendedProperty, Thumbnail );
+ DECLARE_PROPERTY( CExtendedProperty, VideoHDR );
+ DECLARE_PROPERTY( CExtendedProperty, VFR );
+ DECLARE_PROPERTY( CExtendedVidProcSetting, Zoom );
+ DECLARE_PROPERTY( CExtendedProperty, VideoStabilization );
+ DECLARE_PROPERTY( CExtendedProperty, Histogram );
+ DECLARE_PROPERTY( CExtendedMetadata, Metadata );
+ DECLARE_PROPERTY( CExtendedProperty, OpticalImageStabilization );
+ DECLARE_PROPERTY( CExtendedProperty, OptimizationHint );
+ DECLARE_PROPERTY( CExtendedProperty, AdvancedPhoto );
+ DECLARE_PROPERTY( CExtendedVidProcSetting, FaceDetection );
+
+ DECLARE_PROPERTY_VARSIZE_ASYNC( CRoiProperty, Roi );
+
+ DECLARE_PROPERTY( KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S, VideoStabMode );
+
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Exposure);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Focus);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Zoom);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, ZoomRelative);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Pan);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Roll);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Tilt);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S, FocalLength);
+
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, BacklightCompensation);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, Brightness);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, Contrast);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, Hue);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, WhiteBalance);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, PowerlineFreq);
+
+ DECLARE_PROPERTY_GET( CRoiConfig, RoiConfigCaps );
+
+ _Success_(return == 0)
+ virtual
+ NTSTATUS
+ GetPfsCaps(
+ _Inout_opt_ KSCAMERA_PERFRAMESETTING_CAP_HEADER *Caps,
+ _Inout_ ULONG *Size
+ );
+};
+
diff --git a/AVStream/avscamera/sys/SensorSimulation.cpp b/AVStream/avscamera/sys/SensorSimulation.cpp
new file mode 100644
index 00000000..3ebeb56b
--- /dev/null
+++ b/AVStream/avscamera/sys/SensorSimulation.cpp
@@ -0,0 +1,3537 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ SensorSimulation.cpp
+
+ Abstract:
+
+ Simulation class implementation. Derived from the base CSensor object.
+
+ This class simulates a theoretical model camera. The camera supports
+ every modern camera control available and produces a simulation of its
+ behavior. In most cases this simulation is very very basic because we
+ have no actual hardware to work with and there producing a visible
+ effect in the simulation would be difficult or expensive to do.
+
+ History:
+
+ created 5/8/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+//
+// The following macro is used to define a legacy control's range and
+// default value. We use the macro simply to minimize the verbosity of
+// our declarations.
+//
+#define DEFINE_LEGACY_CTRL_CAPS( Control, Minimum, Maximum, SteppingDelta, DefValue ) \
+/*-------------------------------------------------------------- \
+ This structure defines what the control is capable of. \
+--------------------------------------------------------------*/ \
+KSPROPERTY_STEPPING_LONG Control##RangeAndStep[] = \
+{ \
+ { \
+ SteppingDelta, /* SteppingDelta */ \
+ 0, /* Reserved */ \
+ Minimum, /* Minimum */ \
+ Maximum /* Maximum */ \
+ } \
+}; \
+ \
+/* This is the default control value. */ \
+const LONG Control##Default = DefValue; \
+ \
+KSPROPERTY_MEMBERSLIST Control##MembersList[] = \
+{ \
+ { \
+ { \
+ KSPROPERTY_MEMBER_STEPPEDRANGES, \
+ sizeof (Control##RangeAndStep), \
+ SIZEOF_ARRAY(Control##RangeAndStep), \
+ 0 \
+ }, \
+ (PVOID)Control##RangeAndStep, \
+ }, \
+ { \
+ { \
+ KSPROPERTY_MEMBER_VALUES, \
+ sizeof (Control##Default), \
+ 1, \
+ KSPROPERTY_MEMBER_FLAG_DEFAULT \
+ }, \
+ (PVOID)&Control##Default \
+ } \
+}; \
+ \
+KSPROPERTY_VALUES Control##Values = \
+{ \
+ { \
+ STATICGUIDOF(KSPROPTYPESETID_General), \
+ VT_I4, \
+ 0 \
+ }, \
+ SIZEOF_ARRAY(Control##MembersList), \
+ Control##MembersList \
+};
+
+DEFINE_LEGACY_CTRL_CAPS( ZoomRelative, -2, +2, 1, 0 )
+DEFINE_LEGACY_CTRL_CAPS( Zoom, FOCALLENGTH_OPTICAL_MIN, FOCALLENGTH_OPTICAL_MAX, 1, FOCALLENGTH_OCULAR )
+DEFINE_LEGACY_CTRL_CAPS( Pan, -180, 180, 1, 0 )
+DEFINE_LEGACY_CTRL_CAPS( Roll, -180, 180, 1, 0 )
+DEFINE_LEGACY_CTRL_CAPS( Tilt, -180, 180, 1, 0 )
+DEFINE_LEGACY_CTRL_CAPS( BacklightCompensation, 0, 1, 1, 0 )
+DEFINE_LEGACY_CTRL_CAPS( Brightness, -10000, 10000, 1, 750 )
+DEFINE_LEGACY_CTRL_CAPS( Contrast, -10000, 10000, 1, 100 )
+DEFINE_LEGACY_CTRL_CAPS( Hue, -18000, 18000, 1, 0 )
+DEFINE_LEGACY_CTRL_CAPS( PLF, POWERLINEFREQ_DISABLED, POWERLINEFREQ_AUTO, 1, POWERLINEFREQ_DEFAULT )
+DEFINE_LEGACY_CTRL_CAPS( WhiteBalance, WHITEBALANCE_MIN, WHITEBALANCE_MAX, WHITEBALANCE_STEP, WHITEBALANCE_DEF )
+DEFINE_LEGACY_CTRL_CAPS( Exposure, EXPOSURE_BILOG_MIN, EXPOSURE_BILOG_MAX, EXPOSURE_BILOG_STEP, EXPOSURE_BILOG_DEF)
+DEFINE_LEGACY_CTRL_CAPS( Focus, 1, 1200, 1, 100 );
+
+void
+CSensorSimulation::
+FocusConvergence(
+ _In_opt_ PVOID Context
+)
+/*++
+
+Routine Description:
+
+ A timer callback that simulates focus convergence.
+
+ Update the focus state to focused.
+
+ Update the position to a random location that is in bounds if we are in
+ an auto or continuous auto mode. The new location is probably not
+ realistic; but it is important to simulate the change in location for
+ testing.
+
+ Notice that we do no kick off the timer again on continuous auto focus.
+ A camera that is performing continuous auto focus in software would
+ probably do something there.
+
+Arguments:
+
+ Context -
+ In our case, this is a pointer to our simulation object.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ if( Context )
+ {
+ CSensorSimulation *Sensor = (CSensorSimulation *) Context;
+ KScopedMutex lock( Sensor->m_SensorMutex );
+
+ if( Sensor->m_FocusNotifier )
+ {
+ Sensor->m_FocusNotifier->Set();
+ Sensor->m_FocusNotifier = nullptr;
+ }
+
+ // Let's just fake a focus change if we get here from somewhere else.
+ // This only applies to auto focus modes and only if we're not focused.
+ if( (Sensor->m_GlobalIspSettings.FocusMode &
+ (KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO | KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS)) &&
+ Sensor->m_FocusState != KSCAMERA_EXTENDEDPROP_FOCUSSTATE_FOCUSED )
+ {
+ Sensor->m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul =
+ GetRandom( Sensor->m_GlobalIspSettings.FocusSetting.Min,
+ Sensor->m_GlobalIspSettings.FocusSetting.Max );
+ }
+ else if( Sensor->m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ switch( Sensor->m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_MASK )
+ {
+ case KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_INFINITY:
+ Sensor->m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul =
+ Sensor->m_GlobalIspSettings.FocusSetting.Max;
+ break;
+
+ case KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_HYPERFOCAL:
+ Sensor->m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul =
+ Sensor->m_GlobalIspSettings.FocusSetting.Max - Sensor->m_GlobalIspSettings.FocusSetting.Step;
+ break;
+
+ case KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_NEAREST:
+ Sensor->m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul =
+ Sensor->m_GlobalIspSettings.FocusSetting.Min;
+ break;
+
+ }
+ }
+
+ // TODO:
+ // If we're continuous focus, we should probably kick off another focus change here...
+ // ... but that tends to mess with testing.
+
+ // We always want to transition to here.
+ Sensor->m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_FOCUSED;
+ }
+}
+
+void
+CSensorSimulation::
+FocusRectConvergence(
+ _In_opt_ PVOID Context
+)
+/*++
+
+Routine Description:
+
+ A timer callback that simulates FocusRect convergence.
+
+Arguments:
+
+ Context -
+ In our case, this is a pointer to our simulation object.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ if( Context )
+ {
+ CSensorSimulation *Sensor = (CSensorSimulation *) Context;
+ KScopedMutex lock( Sensor->m_SensorMutex );
+
+ if( Sensor->m_FocusRectNotifier )
+ {
+ Sensor->m_FocusRectNotifier->Set();
+ Sensor->m_FocusRectNotifier = nullptr;
+ }
+
+ // Not much else to do here.
+ }
+}
+
+CSensorSimulation::CSensorSimulation(
+ _In_ CCaptureDevice *Device,
+ _In_ const KSFILTER_DESCRIPTOR *Descriptors
+)
+ : CSensor( Device, Descriptors->PinDescriptorsCount )
+ , m_Descriptors( Descriptors )
+ , m_MetadataInfo( nullptr )
+ , m_FocusTimer( nullptr )
+ , m_FocusRectTimer( nullptr )
+
+{
+ PAGED_CODE();
+
+ KeQuerySystemTime (&m_StartTime);
+}
+
+
+CSensorSimulation::~CSensorSimulation()
+{
+ PAGED_CODE();
+
+ delete m_FocusTimer;
+ delete m_FocusRectTimer;
+ delete [] m_MetadataInfo;
+ delete [] (PBYTE) m_pPerFrameSettings;
+ delete [] m_WarmStartEnabled;
+}
+
+NTSTATUS
+CSensorSimulation::
+ProgramDefaults()
+/*++
+
+Routine Description:
+
+ Reset our simulation back to the DDI-specified defaults.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+
+ m_FocusNotifier = nullptr;
+ m_pPerFrameSettings = nullptr;
+
+
+ m_FaceDetectionMax = MAX_FACES;
+ m_FaceDetectionFlags = KSCAMERA_EXTENDEDPROP_FACEDETECTION_OFF;
+ m_FaceDetectionCurrentMax = 0;
+ m_AutoFocusLock = false;
+ m_AutoExposureLock = false;
+ m_AutoWhitebalanceLock = false;
+ m_Flash = 0;
+ m_VideoStabMode = 0;
+ m_VFR = KSCAMERA_EXTENDEDPROP_VFR_ON;
+ m_VideoHDR = KSCAMERA_EXTENDEDPROP_VIDEOHDR_OFF;
+ m_VideoStabilization = KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_OFF;
+ m_Histogram = KSCAMERA_EXTENDEDPROP_HISTOGRAM_OFF;
+ m_OpticalImageStabilization = KSCAMERA_EXTENDEDPROP_OIS_AUTO;
+
+ m_AdvancedPhoto.PinId = GetNextStillIndex();
+ m_AdvancedPhoto.Flags = KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_OFF;
+ m_AdvancedPhoto.Capability = KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_OFF |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_HDR |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_FNF |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_ULTRALOWLIGHT;
+
+ m_FocusRect.left = 0;
+ m_FocusRect.top = 0;
+ m_FocusRect.right = 0;
+ m_FocusRect.bottom = 0;
+
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_UNINITIALIZED;
+
+ m_PhotoMode = CExtendedPhotoMode();
+ m_PhotoMode.Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE;
+ m_PhotoMode.PinId = GetNextStillIndex();
+ m_PhotoMode.MaxHistoryFrames() = IMAGE_CAPTURE_PIN_MAXIMUM_HISTORY_FRAMES;
+ m_PhotoMode.RequestedHistoryFrames() = 0;
+ m_PhotoMode.SubMode() = KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE_SUB_NONE;
+
+ m_MaxFrameRate = CExtendedProperty(); // assume nothing.
+
+ for( ULONG Index = GetNextStillIndex(); IsValidIndex( Index ); Index = GetNextStillIndex( Index ) )
+ {
+ SetQPC( Index, 0 );
+ }
+ m_TorchMode.Flags = KSCAMERA_EXTENDEDPROP_VIDEOTORCH_OFF;
+ m_TorchMode = 50UL;
+
+ m_OptimizationHint.Flags = KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO;
+
+ m_SceneMode = KSCAMERA_EXTENDEDPROP_SCENEMODE_AUTO;
+
+ // Wipe the global settings to zeros for now.
+ RtlFillBytes(&m_GlobalIspSettings, sizeof(m_GlobalIspSettings), 0);
+
+ m_GlobalIspSettings.FlashMode = KSCAMERA_EXTENDEDPROP_FLASH_OFF;
+ m_GlobalIspSettings.FlashValue = 50;
+
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.ISOValue = 200;
+
+ m_GlobalIspSettings.EVCompensation.Mode = 0;
+ m_GlobalIspSettings.EVCompensation.Min = -2;
+ m_GlobalIspSettings.EVCompensation.Max = 2;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.WhiteBalanceSetting.Max = WHITEBALANCE_MAX;
+ m_GlobalIspSettings.WhiteBalanceSetting.Min = WHITEBALANCE_MIN;
+ m_GlobalIspSettings.WhiteBalanceSetting.Step = WHITEBALANCE_STEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.Reserved = 0;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.Max = (MAX_EXPOSURE_TIME>LONG_MAX) ? LONG_MAX : (LONG)(LONG_MAX & MAX_EXPOSURE_TIME);
+ m_GlobalIspSettings.ExposureSetting.Min = (LONG)MIN_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Step = 1;
+ m_GlobalIspSettings.ExposureSetting.Reserved = 0;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.Max = 1200;
+ m_GlobalIspSettings.FocusSetting.Min = 1;
+ m_GlobalIspSettings.FocusSetting.Step = 1;
+ m_GlobalIspSettings.FocusSetting.Reserved = 0;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ m_GlobalIspSettings.FocusSetting.Mode = 0;
+ m_GlobalIspSettings.FocusPriority = KSCAMERA_EXTENDEDPROP_FOCUSPRIORITY_ON;
+
+ m_GlobalIspSettings.bPhotoConfirmation = TRUE;
+
+ // Defaults to fall back to if we get a cancel.
+ m_LastFocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_LastFocusSetting = 100;
+
+
+ // Specifies the dynamic range of our fictious camera's lens system
+ // Note: Magnification = Lobjective / Locular
+
+ // The following values set only the minimum and maximum for the rational number expressing the zoom.
+
+ // This specifies the denominator of the rational value used to specify magnification.
+ m_FocalLength.lOcularFocalLength = FOCALLENGTH_OCULAR;
+ // If lObjectiveFocalLengthMin < lOcularFocalLength, then camera allows Zoom out: aka, wide-field view.
+ m_FocalLength.lObjectiveFocalLengthMin = FOCALLENGTH_OPTICAL_MIN;
+ // If lObjectiveFocalLengthMax > lOcularFocalLength, then camera allows Zoom in: aka, Magnified, narrow-field view.
+ m_FocalLength.lObjectiveFocalLengthMax = FOCALLENGTH_OPTICAL_MAX;
+
+ // Cache values for the new extended zoom property.
+ m_ExtendedZoom.Flags = KSCAMERA_EXTENDEDPROP_ZOOM_DIRECT;
+ m_ExtendedZoom.Min() = (LONG)(TO_Q16(FOCALLENGTH_OPTICAL_MIN) / FOCALLENGTH_OCULAR);
+ m_ExtendedZoom.Max() = (LONG)(TO_Q16(FOCALLENGTH_OPTICAL_MAX) / FOCALLENGTH_OCULAR);
+ m_ExtendedZoom.Step() = 1; // This avoids the rounding issue.
+ m_ExtendedZoom = ZoomDefault;
+ //TO_Q16(ZoomRangeAndStep[0].SteppingDelta) / FOCALLENGTH_OCULAR;
+
+ // Set up our current zoom.
+ m_Zoom.Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE |
+ KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE;
+ m_Zoom.Value = ZoomDefault;
+ m_Zoom.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL | KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+
+ // Set up our relative zoom.
+ m_ZoomRelative.Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ m_ZoomRelative.Value = ZoomRelativeDefault;
+ m_ZoomRelative.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL | KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+
+ m_Pan.Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ m_Pan.Value = PanDefault;
+ m_Pan.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+
+ m_Roll.Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ m_Roll.Value = RollDefault;
+ m_Roll.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+
+ m_Tilt.Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ m_Tilt.Value = TiltDefault;
+ m_Tilt.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+
+ m_BacklightCompensation.Capabilities =
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL |
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO;
+ m_BacklightCompensation.Value = BacklightCompensationDefault;
+ m_BacklightCompensation.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+
+ m_Brightness.Capabilities =
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL |
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO;
+ m_Brightness.Value = BrightnessDefault;
+ m_Brightness.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+
+ m_Contrast.Capabilities =
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL |
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO;
+ m_Contrast.Value = ContrastDefault;
+ m_Contrast.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+
+ m_Hue.Capabilities =
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL |
+ KSPROPERTY_VIDEOPROCAMP_FLAGS_AUTO;
+ m_Hue.Value = HueDefault;
+ m_Hue.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+
+ // Set up our Power Line Frequency defaults.
+ m_PowerLineFreq.Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL | KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ m_PowerLineFreq.Value = POWERLINEFREQ_DEFAULT;
+ m_PowerLineFreq.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+
+ m_IsoResult = STATUS_SUCCESS;
+ m_EvCompResult = STATUS_SUCCESS;
+ m_WhiteBalanceResult= STATUS_SUCCESS;
+ m_ExposureResult = STATUS_SUCCESS;
+ m_SceneModeResult = STATUS_SUCCESS;
+ m_FaceDetectionResult = STATUS_SUCCESS;
+ m_FocusResult = STATUS_SUCCESS;
+
+ for( ULONG PinIndex=0; PinIndex<GetPinCount(); PinIndex++ )
+ {
+ // Reset the metadata control.
+ m_MetadataInfo[PinIndex] = CExtendedMetadata(PinIndex);
+
+ // Reset the warmstart control.
+ m_WarmStartEnabled[PinIndex] = CExtendedProperty(KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_DISABLED);
+ m_WarmStartEnabled[PinIndex].PinId = PinIndex;
+ }
+
+ DBG_LEAVE("()");
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CSensorSimulation::
+Initialize()
+/*++
+
+Routine Description:
+
+ Perform memory allocations for the simulation. Inspect the descriptors
+ for pins and allocate appropriate simulation objects based on the pin's
+ type.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE();
+
+ DBG_ENTER("()");
+ NTSTATUS Status = STATUS_SUCCESS;
+ IFFAILED_EXIT( Status = CSensor::Initialize() );
+
+ IFNULL_EXIT( m_FocusTimer = new (NonPagedPoolNx, 'emiT') KPassiveTimer( m_Device->GetDeviceObject() ) );
+ IFNULL_EXIT( m_FocusRectTimer = new (NonPagedPoolNx, 'emiT') KPassiveTimer( m_Device->GetDeviceObject() ) );
+ IFNULL_EXIT( m_MetadataInfo = new (PagedPool, 'ateM') CExtendedMetadata[GetPinCount()] );
+ IFNULL_EXIT( m_WarmStartEnabled = new (PagedPool, 'mraW' ) CExtendedProperty[GetPinCount()] );
+
+ for( ULONG PinIndex=0;
+ NT_SUCCESS(Status) && PinIndex<m_Descriptors->PinDescriptorsCount;
+ PinIndex++ )
+ {
+ const KSPIN_DESCRIPTOR_EX *PinDescriptors = m_Descriptors->PinDescriptors;
+ CHardwareSimulation *pSim=nullptr;
+
+ NT_ASSERT( m_Descriptors->PinDescriptorSize == sizeof( *PinDescriptors ) );
+
+ // Video pin type
+ if( IsEqualGUID( *PinDescriptors[PinIndex].PinDescriptor.Category, PIN_CATEGORY_CAPTURE ) )
+ {
+ pSim = new (NonPagedPoolNx, 'ediV') CVideoHardwareSimulation( this, PinIndex );
+ m_VideoMask |= 1<<PinIndex;
+ }
+ else if( IsEqualGUID( *PinDescriptors[PinIndex].PinDescriptor.Category, PIN_CATEGORY_PREVIEW ) )
+ {
+ pSim = new (NonPagedPoolNx, 'verP') CPreviewHardwareSimulation( this, PinIndex );
+ m_PreviewMask |= 1<<PinIndex; // must set to enable photo confirmation...
+ }
+ else if( IsEqualGUID( *PinDescriptors[PinIndex].PinDescriptor.Category, PINNAME_IMAGE ) )
+ {
+ pSim = new (NonPagedPoolNx, 'litS') CImageHardwareSimulation( this, PinIndex );
+ m_StillMask |= 1<<PinIndex;
+ }
+ else
+ {
+ // We don't know this pin type, so skip it.
+ m_HardwareSimulation[PinIndex] = nullptr;
+ continue;
+ }
+
+ if( pSim )
+ {
+ if( pSim->Initialize() )
+ {
+ m_HardwareSimulation[PinIndex] = pSim;
+ }
+ else
+ {
+ //
+ // If we couldn't create the hardware simulation, fail.
+ //
+ delete pSim;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+done:
+ DBG_ENTER("()=0x%08X", Status);
+ return Status;
+}
+
+/**************************************************************************
+
+ Sensor-level control simulations
+
+ 1. Query capabilities and state of the device.
+ 2. Issue a command or set state on the device.
+
+**************************************************************************/
+
+// Get for KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID
+NTSTATUS
+CSensorSimulation::
+GetFocusRect(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S pRoi
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pRoi->FocusRect = m_FocusRect;
+ pRoi->AutoFocusLock = m_AutoFocusLock;
+ pRoi->AutoExposureLock = m_AutoExposureLock;
+ pRoi->AutoWhitebalanceLock = m_AutoWhitebalanceLock;
+ pRoi->Capabilities = KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_FLAGS_AUTO | KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_FLAGS_ASYNC | KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_CONFIG_FOCUS |
+ KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_CONFIG_EXPOSURE;
+ return STATUS_SUCCESS;
+}
+
+// Set for KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID
+NTSTATUS
+CSensorSimulation::
+SetFocusRectAsync(
+ _In_ PKSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S pRoi,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ if( m_FocusRectNotifier )
+ {
+ // The last operation is still pending.
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ m_FocusRectNotifier = Notifier;
+
+ m_FocusRect = pRoi->FocusRect;
+ m_AutoFocusLock = pRoi->AutoFocusLock;
+ m_AutoExposureLock = pRoi->AutoExposureLock;
+ m_AutoWhitebalanceLock = pRoi->AutoWhitebalanceLock;
+
+ if(m_AutoFocusLock)
+ {
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ }
+ if(m_AutoExposureLock)
+ {
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll = DEF_EXPOSURE_TIME;
+ DBG_TRACE("ExposureMode=KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO, ExposureTime=%lld00ns",
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll);
+ }
+ if(m_AutoWhitebalanceLock)
+ {
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ }
+
+ // Fire a one-shot timer to transition the focus state.
+ m_FocusTimer->Set(
+ -2500000LL, // 250ms
+ FocusRectConvergence,
+ this );
+
+ return STATUS_SUCCESS;
+}
+
+// Cancel an outstanding KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID Set
+NTSTATUS
+CSensorSimulation::
+CancelFocusRect()
+{
+ PAGED_CODE();
+
+ // Per spec, this control cannot be cancelled. So we block until complete.
+ // Even if we didn't block here, the CNotifier object is reference counted,
+ // so the CCaptureFilter would block until the operation completes.
+ if( m_FocusRectNotifier )
+ {
+ m_FocusRectTimer->Wait();
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FACEDETECTION.
+NTSTATUS
+CSensorSimulation::
+GetFaceDetection(
+ _Inout_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedVidProcSetting( m_FaceDetectionFlags );
+
+ pProperty->Capability =
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_OFF |
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_PREVIEW |
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_VIDEO |
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_PHOTO |
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_BLINK |
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_SMILE ;
+
+ pProperty->Max() = m_FaceDetectionMax;
+ pProperty->Min() = 1;
+ pProperty->Step() = 1;
+ *pProperty = m_FaceDetectionCurrentMax;
+ pProperty->Result = m_FaceDetectionResult;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FACEDETECTION.
+NTSTATUS
+CSensorSimulation::
+SetFaceDetection(
+ _In_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_FaceDetectionCurrentMax =
+ ( KSCAMERA_EXTENDEDPROP_FACEDETECTION_MASK & pProperty->Flags ) ?
+ pProperty->GetULONG() : 0;
+ m_FaceDetectionFlags = pProperty->Flags;
+ m_FaceDetectionResult = STATUS_SUCCESS;
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSSTATE
+NTSTATUS
+CSensorSimulation::
+GetFocusState(
+ _Out_ KSCAMERA_EXTENDEDPROP_FOCUSSTATE *FocusState
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *FocusState = m_FocusState;
+
+ DBG_LEAVE("(%s)", FocusStateDbgTxt(m_FocusState));
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+NTSTATUS
+CSensorSimulation::
+GetFocus(
+ _Inout_ CExtendedVidProcSetting *pSetting
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // Mode
+ pSetting->Flags = m_GlobalIspSettings.FocusMode;
+
+ // capabilities.
+ pSetting->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_UNLOCK |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_CAPS_CANCELLABLE |
+ KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MACRO |
+ KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_NORMAL |
+ KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_INFINITY |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_HYPERFOCAL |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_NEAREST
+ ;
+
+ pSetting->Result = m_FocusResult;
+
+ // min/max/step/etc.
+ pSetting->m_Setting = m_GlobalIspSettings.FocusSetting;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+NTSTATUS
+CSensorSimulation::
+SetFocusAsync(
+ _In_ CExtendedVidProcSetting *pSetting,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // Signal immediately if the we are continuous focus.
+ bool bSignalImmediately = false;
+ ULONGLONG Flags = pSetting->Flags;
+
+ // Cache our current focus settings in case we get a cancel request.
+ m_LastFocusMode = m_GlobalIspSettings.FocusMode;
+ m_LastFocusSetting = m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul;
+
+ // If we've been asked to unlock, remove any lock flags.
+ if( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_UNLOCK )
+ {
+ // Mark us as signalling immediately if Focus was not locked.
+ bSignalImmediately =
+ ( m_GlobalIspSettings.FocusMode &
+ ( KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK ) ) == 0;
+
+ // Change our operation so we go back to the previous state.
+ Flags = m_GlobalIspSettings.FocusMode &
+ ~( KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK );
+ }
+
+ // Handle the stand-alone lock case by setting the appropriate flags.
+ if( ( Flags &
+ (KSCAMERA_EXTENDEDPROP_FOCUS_MODE_MASK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_MODE_ADVANCED_MASK) ) ==
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK )
+ {
+ if( m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO )
+ {
+ Flags =
+ m_GlobalIspSettings.FocusMode | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+ }
+ if( m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS )
+ {
+ Flags =
+ m_GlobalIspSettings.FocusMode |= KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK;
+ }
+ }
+
+ // Record the Focus mode.
+ DBG_TRACE("Recording FocusMode = 0x%016llX", Flags);
+ m_GlobalIspSettings.FocusMode = Flags;
+
+ if(m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL)
+ {
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.l = pSetting->GetLONG();
+ }
+
+ if( bSignalImmediately )
+ // Unlock, but nothing really to do.
+ {
+ Notifier->Set();
+ m_FocusNotifier = nullptr;
+ }
+ else if( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS )
+ // Continuous case: Signal immediately.
+ // Then prime the timer to switch the state to focused.
+ {
+ m_FocusNotifier = nullptr;
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_SEARCHING;
+ Notifier->Set();
+
+ // Fire a one-shot timer to transition the focus state.
+ m_FocusTimer->Set(
+ -4000000LL, // 400ms
+ FocusConvergence,
+ this );
+ }
+ else if( Flags & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO )
+ // Normal [auto?] focus operation.
+ // Autofocus should be SLOW.
+ {
+ m_FocusNotifier = Notifier;
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_SEARCHING;
+
+ // Fire a one-shot timer to transition the focus state.
+ m_FocusTimer->Set(
+ -4000000LL, // 400ms
+ FocusConvergence,
+ this );
+ }
+ else
+ // Handle Manual, lock & unlock cases FAST ~1 frame time.
+ {
+ m_FocusNotifier = Notifier;
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_SEARCHING;
+
+ // Fire a one-shot timer to transition the focus state.
+ m_FocusTimer->Set(
+ -330000LL, // 33ms
+ FocusConvergence,
+ this );
+ }
+
+ m_FocusResult = STATUS_SUCCESS;
+ return STATUS_SUCCESS;
+}
+
+// Cancel oustanding set KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+NTSTATUS
+CSensorSimulation::
+CancelFocus()
+{
+ PAGED_CODE();
+
+ // Cancel our timer to prevent a race.
+ m_FocusTimer->Cancel();
+
+ // Acquire the lock after the cancel to avoid a potential deadlock.
+ KScopedMutex lock( m_SensorMutex );
+
+ // Now check to see if an operation was still outstanding.
+ // We could just check the status from the timer's Cancel(), but I
+ // prefer checking to see if the handler cleared the notifier instead.
+ if( m_FocusNotifier )
+ {
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_LOST;
+
+ // Cancel behavior isn't well-defined in the spec. Do something reasonable.
+ // In our case, we'll put the focus mode and value back to the last setting.
+ m_GlobalIspSettings.FocusMode = m_LastFocusMode;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = m_LastFocusSetting;
+
+ m_FocusNotifier->Set();
+ m_FocusNotifier = nullptr;
+ m_FocusResult = (ULONG) STATUS_CANCELLED;
+ return STATUS_SUCCESS;
+ }
+ return STATUS_UNSUCCESSFUL;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FLASHMODE
+NTSTATUS
+CSensorSimulation::
+GetExtendedFlash(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedProperty( m_GlobalIspSettings.FlashMode );
+ *pProperty = m_GlobalIspSettings.FlashValue;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_FLASH_ON | KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER |
+ KSCAMERA_EXTENDEDPROP_FLASH_AUTO | KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER |
+ KSCAMERA_EXTENDEDPROP_FLASH_REDEYEREDUCTION | KSCAMERA_EXTENDEDPROP_FLASH_SINGLEFLASH |
+ KSCAMERA_EXTENDEDPROP_FLASH_MULTIFLASHSUPPORTED |
+ KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_ON | KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_OFF |
+ KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_AUTO
+ ;
+
+ DBG_TRACE("FlashMode=0x%016llX, FlashValue=%d",
+ m_GlobalIspSettings.FlashMode,
+ m_GlobalIspSettings.FlashValue );
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FLASHMODE
+NTSTATUS
+CSensorSimulation::
+SetExtendedFlash(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ if(pProperty->Flags & (KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER |
+ KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER) )
+ {
+ m_GlobalIspSettings.FlashValue = pProperty->m_Value.Value.ul;
+ }
+ else
+ {
+ m_GlobalIspSettings.FlashValue = 50;
+ }
+
+ m_GlobalIspSettings.FlashMode = pProperty->Flags;
+ NTSTATUS Status = SetFlashStatus(pProperty->Flags);
+
+ DBG_TRACE("FlashMode=0x%016llX, FlashValue=%d, Status=0x%08X",
+ m_GlobalIspSettings.FlashMode,
+ m_GlobalIspSettings.FlashValue,
+ Status );
+
+ pProperty->Result = (ULONG) Status;
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_ISO
+NTSTATUS
+CSensorSimulation::
+GetIso(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pProperty->Flags = IsoModeValue2Preset(
+ m_GlobalIspSettings.ISOMode,
+ m_GlobalIspSettings.ISOValue );
+ pProperty->Result = STATUS_SUCCESS;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_ISO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ISO_50 | KSCAMERA_EXTENDEDPROP_ISO_80 |
+ KSCAMERA_EXTENDEDPROP_ISO_100 | KSCAMERA_EXTENDEDPROP_ISO_200 |
+ KSCAMERA_EXTENDEDPROP_ISO_400 | KSCAMERA_EXTENDEDPROP_ISO_800 |
+ KSCAMERA_EXTENDEDPROP_ISO_1600 | KSCAMERA_EXTENDEDPROP_ISO_3200 |
+ KSCAMERA_EXTENDEDPROP_ISO_6400 | KSCAMERA_EXTENDEDPROP_ISO_12800 |
+ KSCAMERA_EXTENDEDPROP_ISO_25600 |
+ KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ pProperty->Result = m_IsoResult;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_ISO
+NTSTATUS
+CSensorSimulation::
+SetIsoAsync(
+ _In_ CExtendedProperty *pProperty,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_GlobalIspSettings.ISOMode = (ULONG)pProperty->Flags;
+ m_GlobalIspSettings.ISOValue = 0;
+
+ // This could be done in a separate work item after the scene mode has been programmed...
+ m_IsoResult = STATUS_SUCCESS;
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+#define KSCAMERA_EXTENDEDPROP_ISO_ADVANCED_MASK (KSCAMERA_EXTENDEDPROP_ISO_AUTO | KSCAMERA_EXTENDEDPROP_ISO_MANUAL)
+
+// Create a set of default settings...
+static
+const
+KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING g_IsoAdvancedSettings =
+{
+ 0, // Mode - Unused
+ 50, // Min
+ 25600, // Max
+ 1 // Step (advertised doesn't have to be actual)
+};
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED.
+NTSTATUS
+CSensorSimulation::
+GetIsoAdvanced(
+ _Inout_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // Initialize the property with defaults + (AUTO | MANUAL)
+ pProperty->Flags =
+ m_GlobalIspSettings.ISOMode &
+ KSCAMERA_EXTENDEDPROP_ISO_ADVANCED_MASK;
+ pProperty->Result = STATUS_SUCCESS;
+
+ // Advertise basic caps...
+ pProperty->Capability =
+ KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL |
+ KSCAMERA_EXTENDEDPROP_ISO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ISO_MANUAL ;
+
+ // Advertise the manual caps...
+ *pProperty = g_IsoAdvancedSettings;
+
+ // If ISO is MANUAL, set the value.
+ if( m_GlobalIspSettings.ISOMode == KSCAMERA_EXTENDEDPROP_ISO_MANUAL )
+ {
+ *pProperty = m_GlobalIspSettings.ISOValue;
+ }
+ else if( !(m_GlobalIspSettings.ISOMode == KSCAMERA_EXTENDEDPROP_ISO_AUTO) )
+ {
+ // Try converting any legacy presets to a manual value.
+ pProperty->Flags = KSCAMERA_EXTENDEDPROP_ISO_MANUAL;
+ // Convert the ISO setting
+ *pProperty = IsoPreset2Value( m_GlobalIspSettings.ISOMode );
+ // If we weren't able to report a valid number, just report something reasonable...
+ if( pProperty->GetLONG() > pProperty->Max() )
+ {
+ *pProperty = pProperty->Min();
+ }
+ }
+ pProperty->Result = m_IsoResult;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED.
+NTSTATUS
+CSensorSimulation::
+SetIsoAdvancedAsync(
+ _In_ CExtendedVidProcSetting *pProperty,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+
+ KScopedMutex lock( m_SensorMutex );
+
+ // Just save the parameters
+ if( pProperty->Flags & KSCAMERA_EXTENDEDPROP_ISO_MANUAL )
+ {
+ m_GlobalIspSettings.ISOMode = pProperty->Flags;
+ m_GlobalIspSettings.ISOValue= pProperty->GetULONG();
+ }
+ else if( pProperty->Flags & KSCAMERA_EXTENDEDPROP_ISO_AUTO )
+ {
+ m_GlobalIspSettings.ISOMode = pProperty->Flags;
+ }
+
+ // Set regardless - it takes effect immediately for us.
+ m_IsoResult = STATUS_SUCCESS;
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION
+NTSTATUS
+CSensorSimulation::
+GetEvCompensation(
+ _Inout_ CExtendedEvCompensation *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedEvCompensation( m_GlobalIspSettings.EVCompensation.Mode );
+
+ // Return our cached copy; but update the value from the global setting.
+ *pProperty = m_GlobalIspSettings.EVCompensation;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_EVCOMP_SIXTHSTEP | KSCAMERA_EXTENDEDPROP_EVCOMP_QUARTERSTEP |
+ KSCAMERA_EXTENDEDPROP_EVCOMP_THIRDSTEP | KSCAMERA_EXTENDEDPROP_EVCOMP_HALFSTEP |
+ KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP | KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ pProperty->Result = m_EvCompResult;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION
+NTSTATUS
+CSensorSimulation::
+SetEvCompensationAsync(
+ _In_ CExtendedEvCompensation *pProperty,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // Update the Globals
+ m_GlobalIspSettings.EVCompensation.Mode = (ULONG) pProperty->Flags;
+ m_GlobalIspSettings.EVCompensation.Value = pProperty->Value();
+
+ // Update the current setting in case we're queried for it later.
+ m_GlobalIspSettings.EVCompensation.Value = pProperty->Value();
+
+ // This could be done in a separate work item after the device has been programmed...
+ m_EvCompResult = STATUS_SUCCESS;
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+NTSTATUS
+CSensorSimulation::
+GetWhiteBalance(
+ _Inout_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedVidProcSetting( m_GlobalIspSettings.WhiteBalanceMode );
+
+ // Return our cached copy; but update the value from the global setting.
+ *pProperty = m_GlobalIspSettings.WhiteBalanceSetting;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ pProperty->Result = m_WhiteBalanceResult;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+NTSTATUS
+CSensorSimulation::
+SetWhiteBalanceAsync(
+ _In_ CExtendedVidProcSetting *pProperty,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_GlobalIspSettings.WhiteBalanceMode = pProperty->Flags;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = pProperty->Mode();
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = pProperty->GetULONG();
+
+ // This could be done in a separate work item after the device has been programmed...
+ m_WhiteBalanceResult = STATUS_SUCCESS;
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSURE
+NTSTATUS
+CSensorSimulation::
+GetExposure(
+ _Inout_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedVidProcSetting( m_GlobalIspSettings.ExposureMode );
+
+ // Return our cached copy; but update the value from the global setting.
+ *pProperty = m_GlobalIspSettings.ExposureSetting;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ pProperty->Result = m_ExposureResult;
+ DBG_TRACE("ExposureMode=0x%016llX, ExposureTime=%lld00ns",
+ pProperty->Flags, pProperty->GetLONGLONG());
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSURE
+NTSTATUS
+CSensorSimulation::
+SetExposureAsync(
+ _In_ CExtendedVidProcSetting *pProperty,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ DBG_TRACE("ExposureMode=0x%016llX, ExposureTime=%lld00ns",
+ pProperty->Flags, pProperty->GetLONGLONG());
+ if( pProperty->Flags & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ull = pProperty->GetULONGLONG();
+ }
+ m_GlobalIspSettings.ExposureMode = pProperty->Flags;
+
+ // This could be done in a separate work item after the device has been programmed...
+ m_ExposureResult = STATUS_SUCCESS;
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOCONFIRMATION
+NTSTATUS
+CSensorSimulation::
+GetPhotoConfirmation(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedProperty( m_GlobalIspSettings.bPhotoConfirmation );
+ DBG_TRACE( "Is %s", m_GlobalIspSettings.bPhotoConfirmation ? "On" : "Off" );
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOCONFIRMATION
+NTSTATUS
+CSensorSimulation::
+SetPhotoConfirmation(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // Return our cached copy; but update the value from the global setting.
+ m_GlobalIspSettings.bPhotoConfirmation =
+ BOOLEAN( (pProperty->Flags & KSCAMERA_EXTENDEDPROP_PHOTOCONFIRMATION_ON)
+ == KSCAMERA_EXTENDEDPROP_PHOTOCONFIRMATION_ON);
+ DBG_TRACE( "Is %s", m_GlobalIspSettings.bPhotoConfirmation ? "On" : "Off" );
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE
+NTSTATUS
+CSensorSimulation::
+GetSceneMode(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedProperty( m_SceneMode );
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_SCENEMODE_MACRO |
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_PORTRAIT | KSCAMERA_EXTENDEDPROP_SCENEMODE_SPORT |
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_SNOW | KSCAMERA_EXTENDEDPROP_SCENEMODE_NIGHT |
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_BEACH | KSCAMERA_EXTENDEDPROP_SCENEMODE_SUNSET |
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_CANDLELIGHT | KSCAMERA_EXTENDEDPROP_SCENEMODE_LANDSCAPE |
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_NIGHTPORTRAIT | KSCAMERA_EXTENDEDPROP_SCENEMODE_BACKLIT;
+ pProperty->Result = m_SceneModeResult;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE
+NTSTATUS
+CSensorSimulation::
+SetSceneModeAsync(
+ _In_ CExtendedProperty *pProperty,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_SceneMode = (ULONG)pProperty->Flags;
+
+ UpdateSettings( m_SceneMode );
+
+ // This could be done in a separate work item after the scene mode has been programmed...
+ m_SceneModeResult = STATUS_SUCCESS;
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+// Apply scene mode changes.
+NTSTATUS
+CSensorSimulation::
+UpdateSettings(
+ _In_ ULONGLONG ullSceneMode
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+ KScopedMutex lock( m_SensorMutex );
+
+ if( KSCAMERA_EXTENDEDPROP_SCENEMODE_AUTO==ullSceneMode )
+ {
+ //
+ // If the mode was auto, let's randomly replace it with another valid value.
+ //
+ static
+ ULONGLONG ValidModes[] =
+ {
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_MACRO,
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_PORTRAIT, KSCAMERA_EXTENDEDPROP_SCENEMODE_SPORT,
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_SNOW, KSCAMERA_EXTENDEDPROP_SCENEMODE_NIGHT,
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_BEACH, KSCAMERA_EXTENDEDPROP_SCENEMODE_SUNSET,
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_CANDLELIGHT, KSCAMERA_EXTENDEDPROP_SCENEMODE_LANDSCAPE,
+ KSCAMERA_EXTENDEDPROP_SCENEMODE_NIGHTPORTRAIT, KSCAMERA_EXTENDEDPROP_SCENEMODE_BACKLIT
+ };
+
+ ullSceneMode =
+ ValidModes[ (ULONG) (1 << GetRandom( (ULONG)0, SIZEOF_ARRAY(ValidModes)-1 )) ];
+ }
+
+ switch(ullSceneMode)
+ {
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_MACRO:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_PORTRAIT:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_SPORT:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_SNOW:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_NIGHT:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_BEACH:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_SUNSET:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_CANDLELIGHT:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_LANDSCAPE:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_NIGHTPORTRAIT:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ case KSCAMERA_EXTENDEDPROP_SCENEMODE_BACKLIT:
+ m_GlobalIspSettings.ISOMode = KSCAMERA_EXTENDEDPROP_ISO_AUTO;
+ m_GlobalIspSettings.EVCompensation.Value = 0;
+ m_GlobalIspSettings.EVCompensation.Mode = KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP;
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = WhiteBalanceDefault;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ m_GlobalIspSettings.WhiteBalanceMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureMode = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ul = DEF_EXPOSURE_TIME;
+ m_GlobalIspSettings.ExposureSetting.Mode = 0;
+ m_GlobalIspSettings.FocusMode = KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS | KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE;
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = 100;
+ break;
+ default:
+ break;
+ }
+ DBG_TRACE("ExposureMode=0x%016llX, ExposureTime=%lld00ns",
+ m_GlobalIspSettings.ExposureMode, m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll);
+ return status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSPRIORITY
+NTSTATUS
+CSensorSimulation::
+GetFocusPriority(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = CExtendedProperty(m_GlobalIspSettings.FocusPriority);
+ DBG_TRACE("Is %s", m_GlobalIspSettings.FocusPriority ? "On" : "Off");
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSPRIORITY
+NTSTATUS
+CSensorSimulation::
+SetFocusPriority(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_GlobalIspSettings.FocusPriority = pProperty->Flags;
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOHDR.
+NTSTATUS
+CSensorSimulation::
+GetVideoHDR(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pProperty->Flags = m_VideoHDR;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_VIDEOHDR_OFF |
+ KSCAMERA_EXTENDEDPROP_VIDEOHDR_ON |
+ KSCAMERA_EXTENDEDPROP_VIDEOHDR_AUTO;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOHDR.
+NTSTATUS
+CSensorSimulation::
+SetVideoHDR(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_VideoHDR = pProperty->Flags;
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_VFR.
+NTSTATUS
+CSensorSimulation::
+GetVFR(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pProperty->Flags = m_VFR;
+ pProperty->Capability = 0;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_VFR.
+NTSTATUS
+CSensorSimulation::
+SetVFR(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_VFR = pProperty->Flags;
+ return STATUS_SUCCESS;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ZOOM Get handler
+NTSTATUS
+CSensorSimulation::
+GetZoom(
+ _Inout_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ *pProperty = CExtendedVidProcSetting(m_ExtendedZoom);
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_ZOOM_DEFAULT |
+ KSCAMERA_EXTENDEDPROP_ZOOM_DIRECT |
+ KSCAMERA_EXTENDEDPROP_ZOOM_SMOOTH ;
+
+ // Update the zoom factor.
+ //
+ // I am using the same pFilter->m_Zoom value here just to keep the extended and legacy
+ // controls tied together. It is not necessary to implement both in a real driver.
+ // However the legacy control was implemented first in this simulation and leaving both
+ // in place might have some value. But supporting both adds the question of whether they
+ // should both present a consistent view of zoom or if they should just save and report
+ // the values set for their own respective properties.
+ //
+ // I have chosen to support a consistent view of the zoom factor between the extended and
+ // legacy controls. Given that the legacy control was implemented first, I have chosen
+ // to keep that storage and rescale the value set by the extended zoom to match the
+ // legacy settings.
+ //
+ // But to make the two controls more consistent, I have changed the reported Ocular Focal
+ // Length to 2^16, which matches the implied denominator in Q16 format - the format used
+ // by this extended property. So as long as lOcularFocalLength is 0x10000, the following
+ // function should not change the reported value at all. This should simplify any
+ // debugging or tracing.
+ //
+ DBG_TRACE("Legacy Zoom Value = %d", m_Zoom.Value);
+
+ // To ensure we clear out the high order value in the VideoProc
+ // union, we'll assign the LONG to LONGLONG field.
+ pProperty->m_Setting.VideoProc.Value.ll = (LONG) (TO_Q16(m_Zoom.Value) / m_FocalLength.lOcularFocalLength);
+
+ DBG_TRACE("Extended Zoom Value = %d", pProperty->GetLONG());
+
+ return STATUS_SUCCESS;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ZOOM Set handler
+NTSTATUS
+CSensorSimulation::
+SetZoom(
+ _In_ CExtendedVidProcSetting *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ LONG Zoom = pProperty->GetLONG();
+ DBG_TRACE("Extended Zoom Value = %d", Zoom);
+
+ m_ExtendedZoom = *pProperty;
+ DBG_TRACE("Zoom Flags = 0x%016llX", m_ExtendedZoom.Flags);
+
+ // Take us directly to the position if we're doing a direct zoom.
+ // Depends on IHVs, KSCAMERA_EXTENDEDPROP_ZOOM_DEFAULT may be either direct zoom or
+ // smooth zoom. Here direct zoom will be performed when DEFAULT is specified.
+ if( pProperty->Flags != KSCAMERA_EXTENDEDPROP_ZOOM_SMOOTH )
+ {
+ // Convert back to legacy notation...
+ //
+ // I am using the same pFilter->m_Zoom value here just to keep the extended and legacy
+ // controls tied together. It is not necessary to implement both in a real driver.
+ // However the legacy control was implemented first in this simulation and leaving both
+ // in place might have some value. But supporting both adds the question of whether they
+ // should both present a consistent view of zoom or if they should just save and report
+ // the values set for their own respective properties.
+ //
+ // I have chosen to support a consistent view of the zoom factor between the extended and
+ // legacy controls. Given that the legacy control was implemented first, I have chosen
+ // to keep that storage and rescale the value set by the extended zoom to match the
+ // legacy settings.
+ //
+ // But to make the two controls more consistent, I have changed the reported Ocular Focal
+ // Length to 2^16, which matches the implied denominator in Q16 format - the format used
+ // by this extended property. So as long as lOcularFocalLength is 0x10000, the following
+ // function should not change the reported value at all. This should simplify any
+ // debugging or tracing.
+ //
+ m_Zoom.Value = FROM_Q16(Zoom, m_FocalLength.lOcularFocalLength);
+ DBG_TRACE("Legacy Zoom Value = %d", m_Zoom.Value);
+ }
+
+ // It's always success; this is a sync control, so this isn't really used.
+ m_ExtendedZoom.Result = ntStatus;
+
+ DBG_LEAVE("()=0x%08X", ntStatus);
+ return ntStatus;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOSTABILIZATION.
+NTSTATUS
+CSensorSimulation::
+GetVideoStabilization(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pProperty->Flags = m_VideoStabilization;
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_OFF |
+ KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_ON |
+ KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_AUTO;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOSTABILIZATION.
+NTSTATUS
+CSensorSimulation::
+SetVideoStabilization(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ m_VideoStabilization = pProperty->Flags;
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_OIS.
+NTSTATUS
+CSensorSimulation::
+GetOpticalImageStabilization(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ *pProperty = CExtendedProperty(m_OpticalImageStabilization);
+ pProperty->Capability = KSCAMERA_EXTENDEDPROP_OIS_OFF |
+ KSCAMERA_EXTENDEDPROP_OIS_ON |
+ KSCAMERA_EXTENDEDPROP_OIS_AUTO;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_OIS.
+NTSTATUS
+CSensorSimulation::
+SetOpticalImageStabilization(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ m_OpticalImageStabilization = pProperty->Flags;
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_ADVANCEDPHOTO.
+NTSTATUS
+CSensorSimulation::
+GetAdvancedPhoto(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pProperty->Flags = m_AdvancedPhoto.Flags;
+ pProperty->Capability = m_AdvancedPhoto.Capability;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_ADVANCEDPHOTO.
+NTSTATUS
+CSensorSimulation::
+SetAdvancedPhoto(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ m_AdvancedPhoto = *pProperty;
+ return STATUS_SUCCESS;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_FOCUS
+NTSTATUS
+CSensorSimulation::
+GetFocus(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ pKsCameraControl->Flags = KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ // If we're currently set to AUTO or CONTINUOUS, report AUTO.
+ if (m_GlobalIspSettings.FocusMode &
+ ( KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO | KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS ))
+ {
+ pKsCameraControl->Flags |= KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else if (m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL)
+ {
+ pKsCameraControl->Flags |= KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ }
+ pKsCameraControl->Value = m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul;
+
+ return STATUS_SUCCESS;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_FOCUS
+NTSTATUS
+CSensorSimulation::
+SetFocus(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_GlobalIspSettings.FocusSetting.VideoProc.Value.ul = pKsCameraControl->Value;
+ m_GlobalIspSettings.FocusMode =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+
+ m_FocusNotifier = nullptr;
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_SEARCHING;
+
+ // Fire a one-shot timer to transition the focus state.
+ m_FocusTimer->Set(
+ -330000LL, // 33ms
+ FocusConvergence,
+ this);
+ }
+
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_GlobalIspSettings.FocusMode = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+
+ m_FocusNotifier = nullptr;
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_SEARCHING;
+
+ // Fire a one-shot timer to transition the focus state.
+ m_FocusTimer->Set(
+ -4000000LL, // 400ms
+ FocusConvergence,
+ this );
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_EXPOSURE
+NTSTATUS
+CSensorSimulation::
+GetExposure(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ pKsCameraControl->Flags = KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ if (m_GlobalIspSettings.ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO)
+ {
+ pKsCameraControl->Flags |= KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else if (m_GlobalIspSettings.ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL)
+ {
+ pKsCameraControl->Flags |= KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ }
+
+ pKsCameraControl->Value = Exposure100nsToBinaryLog(m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll);
+
+ DBG_TRACE("ExposureValue=%d, ExposureMode=0x%016llX, ExposureTime=%lld00ns",
+ pKsCameraControl->Value, m_GlobalIspSettings.ExposureMode, m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll);
+
+ return STATUS_SUCCESS;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_EXPOSURE
+NTSTATUS
+CSensorSimulation::
+SetExposure(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = BoundsCheckSigned( pKsCameraControl->Value, ExposureRangeAndStep[0] );
+
+ if( NT_SUCCESS(ntStatus) )
+ {
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE || !ExposureBinaryLogIsValid(pKsCameraControl->Value))
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload
+ m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll = ExposureBinaryLogTo100ns(pKsCameraControl->Value);
+ m_GlobalIspSettings.ExposureMode =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_GlobalIspSettings.ExposureMode = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ DBG_TRACE("ExposureValue=%d, ExposureMode=0x%016llX, ExposureTime=%lld00ns",
+ pKsCameraControl->Value, m_GlobalIspSettings.ExposureMode, m_GlobalIspSettings.ExposureSetting.VideoProc.Value.ll);
+
+ return ntStatus;
+}
+
+// Update the zoom factor over time.
+void
+CSensorSimulation::
+SmoothZoom()
+{
+ PAGED_CODE();
+
+#define ZOOM_SPEED (LONG) (TO_Q16(1) * 0.07f)
+#define ZOOM_SPEED_VIDEO_RECORDING (LONG) (TO_Q16(1) * 0.02f)
+#define ZOOM_EPSILON (LONG)(TO_Q16(1) * 0.005f)
+
+ LONG currentZoom = (LONG)
+ (TO_Q16(m_Zoom.Value) /
+ m_FocalLength.lOcularFocalLength);
+ LONG targetZoom = m_ExtendedZoom.GetLONG();
+
+ LONG ZoomDelta = abs(currentZoom - targetZoom);
+
+ // Jump to target if we are very close
+ if( ZoomDelta <= ZOOM_EPSILON )
+ {
+ currentZoom = targetZoom;
+ }
+ else
+ {
+ // Zoom direction
+ bool bZoomIn = (targetZoom > currentZoom);
+ LONG OpModeZoomSpeed = ZOOM_SPEED;
+
+ // Use lower zoom speed for video, if any record pin is running.
+ for( ULONG VideoIndex=GetNextVideoIndex(); IsValidIndex(VideoIndex); VideoIndex=GetNextVideoIndex(VideoIndex) )
+ {
+ if( PinRunning == m_HardwareSimulation[VideoIndex]->GetState() )
+ {
+ OpModeZoomSpeed = ZOOM_SPEED_VIDEO_RECORDING;
+ }
+ }
+
+ // Calculate zoom step that is relative to current zoom factor.
+ // the bigger the current zoom factor the bigger the step.
+ LONG ZoomStep;
+ if( bZoomIn )
+ {
+ ZoomStep = MULT_Q16(OpModeZoomSpeed, currentZoom);
+ }
+ else
+ {
+ ZoomStep = currentZoom - DIV_Q16(currentZoom, (TO_Q16(1) + OpModeZoomSpeed));
+ }
+
+ if( ZoomDelta < 2 * ZoomStep)
+ {
+ // decrease step when close to target
+ ZoomStep = MULT_Q16(ZoomDelta, ((LONG)(TO_Q16(1) * 0.4f)));
+ }
+
+ if (bZoomIn)
+ {
+ currentZoom += ZoomStep;
+ }
+ else
+ {
+ currentZoom -= ZoomStep;
+ }
+ }
+
+ // Convert back to the zoom factor.
+ m_Zoom.Value = FROM_Q16(currentZoom, m_FocalLength.lOcularFocalLength);
+
+ if (!NT_SUCCESS(BoundsCheckSigned(m_Zoom.Value, ZoomRangeAndStep[0])))
+ {
+ m_Zoom.Value = FROM_Q16(targetZoom, m_FocalLength.lOcularFocalLength);
+ }
+
+ DBG_LEAVE(" m_Zoom.Value=%d, FocusMode=0x%016llX", m_Zoom.Value, m_GlobalIspSettings.FocusMode);
+}
+
+
+// Adjust the zoom for each preview frame if the zoom is in motion.
+// This function is used by both the legacy relative zoom control
+// and the extended property smooth zoom control.
+void
+CSensorSimulation::
+UpdateZoom(void)
+{
+ PAGED_CODE();
+
+ // Legacy zoom relative adjustment.
+ LONG Value = m_Zoom.Value + m_ZoomRelative.Value;
+
+ if (NT_SUCCESS(BoundsCheckSigned(Value, ZoomRangeAndStep[0])))
+ {
+ m_Zoom.Value = Value;
+ }
+ else
+ {
+ m_ZoomRelative.Value = 0;
+ }
+
+ // Extended property zoom / smooth zoom adjustment.
+ SmoothZoom();
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_ZOOM
+NTSTATUS
+CSensorSimulation::
+GetZoom(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Zoom.Capabilities;
+ pKsCameraControl->Flags = m_Zoom.Flags;
+ pKsCameraControl->Value = m_Zoom.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_ZOOM
+NTSTATUS
+CSensorSimulation::
+SetZoom(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
+ {
+ pKsCameraControl->Value += m_Zoom.Value;
+ }
+
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, ZoomRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Zoom.Value = pKsCameraControl->Value;
+ m_Zoom.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Zoom.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_ZOOM_RELATIVE
+NTSTATUS
+CSensorSimulation::
+GetZoomRelative(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_ZoomRelative.Capabilities;
+ pKsCameraControl->Flags = m_ZoomRelative.Flags;
+ pKsCameraControl->Value = m_ZoomRelative.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_ZOOM_RELATIVE
+NTSTATUS
+CSensorSimulation::
+SetZoomRelative(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, ZoomRelativeRangeAndStep[0]);
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_ZoomRelative.Value = pKsCameraControl->Value;
+ m_ZoomRelative.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_PAN
+NTSTATUS
+CSensorSimulation::
+GetPan(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Pan.Capabilities;
+ pKsCameraControl->Flags = m_Pan.Flags;
+ pKsCameraControl->Value = m_Pan.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_PAN
+NTSTATUS
+CSensorSimulation::
+SetPan(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, PanRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Pan.Value = pKsCameraControl->Value;
+ m_Pan.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ }
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Pan.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_ROLL
+NTSTATUS
+CSensorSimulation::
+GetRoll(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Roll.Capabilities;
+ pKsCameraControl->Flags = m_Roll.Flags;
+ pKsCameraControl->Value = m_Roll.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_ROLL
+NTSTATUS
+CSensorSimulation::
+SetRoll(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, RollRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Roll.Value = pKsCameraControl->Value;
+ m_Roll.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ }
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Roll.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_TILT
+NTSTATUS
+CSensorSimulation::
+GetTilt(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Tilt.Capabilities;
+ pKsCameraControl->Flags = m_Tilt.Flags;
+ pKsCameraControl->Value = m_Tilt.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_TILT
+NTSTATUS
+CSensorSimulation::
+SetTilt(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Convert relative values to absolute.
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_RELATIVE)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ if (NT_SUCCESS(ntStatus))
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, TiltRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Tilt.Value = pKsCameraControl->Value;
+ m_Tilt.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL |
+ KSPROPERTY_CAMERACONTROL_FLAGS_ABSOLUTE;
+ }
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Tilt.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH
+NTSTATUS
+CSensorSimulation::
+GetFocalLength(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->lOcularFocalLength = m_FocalLength.lOcularFocalLength;
+ pKsCameraControl->lObjectiveFocalLengthMax = m_FocalLength.lObjectiveFocalLengthMax;
+ pKsCameraControl->lObjectiveFocalLengthMin = m_FocalLength.lObjectiveFocalLengthMin;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH
+NTSTATUS
+CSensorSimulation::
+SetFocalLength(
+ _In_ PKSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ return STATUS_NOT_FOUND;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION
+NTSTATUS
+CSensorSimulation::
+GetBacklightCompensation(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_BacklightCompensation.Capabilities;
+ pKsCameraControl->Flags = m_BacklightCompensation.Flags;
+ pKsCameraControl->Value = m_BacklightCompensation.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION
+NTSTATUS
+CSensorSimulation::
+SetBacklightCompensation(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, BacklightCompensationRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_BacklightCompensation.Value = pKsCameraControl->Value;
+ m_BacklightCompensation.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_BacklightCompensation.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
+NTSTATUS
+CSensorSimulation::
+GetBrightness(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Brightness.Capabilities;
+ pKsCameraControl->Flags = m_Brightness.Flags;
+ pKsCameraControl->Value = m_Brightness.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
+NTSTATUS
+CSensorSimulation::
+SetBrightness(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, BrightnessRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Brightness.Value = pKsCameraControl->Value;
+ m_Brightness.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Brightness.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_CONTRAST
+NTSTATUS
+CSensorSimulation::
+GetContrast(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Contrast.Capabilities;
+ pKsCameraControl->Flags = m_Contrast.Flags;
+ pKsCameraControl->Value = m_Contrast.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_CONTRAST
+NTSTATUS
+CSensorSimulation::
+SetContrast(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, ContrastRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Contrast.Value = pKsCameraControl->Value;
+ m_Contrast.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Contrast.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_HUE
+NTSTATUS
+CSensorSimulation::
+GetHue(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_Hue.Capabilities;
+ pKsCameraControl->Flags = m_Hue.Flags;
+ pKsCameraControl->Value = m_Hue.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_HUE
+NTSTATUS
+CSensorSimulation::
+SetHue(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, HueRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_Hue.Value = pKsCameraControl->Value;
+ m_Hue.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_Hue.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY
+NTSTATUS
+CSensorSimulation::
+GetPowerlineFreq(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = m_PowerLineFreq.Capabilities;
+ pKsCameraControl->Flags = m_PowerLineFreq.Flags;
+ pKsCameraControl->Value = m_PowerLineFreq.Value;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY
+NTSTATUS
+CSensorSimulation::
+SetPowerlineFreq(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // Bounds check
+ ntStatus = BoundsCheckSigned(pKsCameraControl->Value, PLFRangeAndStep[0]);
+ if (NT_SUCCESS(ntStatus))
+ {
+ // We report these changes in the next metadata payload.
+ m_PowerLineFreq.Value = pKsCameraControl->Value;
+ m_PowerLineFreq.Flags =
+ KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ }
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_PowerLineFreq.Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ m_PowerLineFreq.Value = POWERLINEFREQ_AUTO; // Auto is auto.
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get [legacy] KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE
+NTSTATUS
+CSensorSimulation::
+GetWhiteBalance(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+
+ pKsCameraControl->Capabilities = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO | KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ if (m_GlobalIspSettings.WhiteBalanceMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO)
+ {
+ pKsCameraControl->Flags = KSPROPERTY_CAMERACONTROL_FLAGS_AUTO;
+ }
+ else
+ {
+ pKsCameraControl->Flags = KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL;
+ }
+
+ ULONG temperature = m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul;
+ if (m_GlobalIspSettings.WhiteBalanceSetting.Mode != KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE)
+ {
+ temperature = WhiteBalancePreset2Temperature(m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul);
+ }
+ pKsCameraControl->Value = (LONG)temperature;
+
+ return STATUS_SUCCESS;
+}
+
+// Set [legacy] KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE
+NTSTATUS
+CSensorSimulation::
+SetWhiteBalance(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pKsCameraControl
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock(m_SensorMutex);
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_MANUAL)
+ {
+ // We report these changes in the next metadata payload.
+ m_GlobalIspSettings.WhiteBalanceSetting.VideoProc.Value.ul = pKsCameraControl->Value;
+ m_GlobalIspSettings.WhiteBalanceMode =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ m_GlobalIspSettings.WhiteBalanceSetting.Mode = KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE;
+ }
+ else if (pKsCameraControl->Flags & KSPROPERTY_CAMERACONTROL_FLAGS_AUTO)
+ {
+ m_GlobalIspSettings.WhiteBalanceMode =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_HISTOGRAM.
+NTSTATUS
+CSensorSimulation::
+GetHistogram(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pProperty->Flags = m_Histogram;
+ pProperty->m_Value.Value.ull = 0;
+ pProperty->Capability = 0;
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_HISTOGRAM.
+NTSTATUS
+CSensorSimulation::
+SetHistogram(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_Histogram = pProperty->Flags;
+
+ // Adjust the reported metadata buffer size for preview.
+ m_MetadataInfo[pProperty->PinId] =
+ CExtendedMetadata::METADATA_MAX +
+ (( m_Histogram == KSCAMERA_EXTENDEDPROP_HISTOGRAM_ON ) ? sizeof(CAMERA_METADATA_HISTOGRAM) : 0 ) ;
+
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_METADATA
+NTSTATUS
+CSensorSimulation::
+GetMetadata(
+ _Inout_ CExtendedMetadata *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = m_MetadataInfo[pProperty->PinId];
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_METADATA
+NTSTATUS
+CSensorSimulation::
+SetMetadata(
+ _In_ CExtendedMetadata *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = m_MetadataInfo[pProperty->PinId];
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_OPTIMIZATIONHINT
+NTSTATUS
+CSensorSimulation::
+GetOptimizationHint(
+ _Inout_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pProperty = m_OptimizationHint;
+ pProperty->Capability =
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_DEFAULT;
+
+ DBG_TRACE( "Hint = 0x%016llX", m_OptimizationHint.Flags );
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_OPTIMIZATIONHINT
+NTSTATUS
+CSensorSimulation::
+SetOptimizationHint(
+ _In_ CExtendedProperty *pProperty
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_OptimizationHint = *pProperty;
+
+ DBG_TRACE( "Hint = 0x%016llX", m_OptimizationHint.Flags );
+
+ return STATUS_SUCCESS;
+}
+
+// Get for PROPSETID_VIDCAP_CAMERACONTROL_VIDEO_STABILIZATION:0
+NTSTATUS
+CSensorSimulation::
+GetVideoStabMode(
+ _Inout_ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S *pMode
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pMode->Capabilities =
+ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_FLAGS_MANUAL ;
+ pMode->VideoStabilizationMode = m_VideoStabMode;
+ return STATUS_SUCCESS;
+}
+
+// Set for PROPSETID_VIDCAP_CAMERACONTROL_VIDEO_STABILIZATION:0
+NTSTATUS
+CSensorSimulation::
+SetVideoStabMode(
+ _In_ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S *pMode
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_VideoStabMode = pMode->VideoStabilizationMode;
+ return STATUS_SUCCESS;
+}
+
+// Get for KSPROPERTY_CAMERACONTROL_FLASH_PROPERTY_ID
+NTSTATUS
+CSensorSimulation::
+GetFlash(
+ _Inout_ KSPROPERTY_CAMERACONTROL_FLASH_S *pFlash
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pFlash->Capabilities =
+ KSPROPERTY_CAMERACONTROL_FLASH_FLAGS_AUTO |
+ KSPROPERTY_CAMERACONTROL_FLASH_FLAGS_MANUAL ;
+ pFlash->Flash = m_Flash;
+ return STATUS_SUCCESS;
+}
+
+// Set for KSPROPERTY_CAMERACONTROL_FLASH_PROPERTY_ID
+NTSTATUS
+CSensorSimulation::
+SetFlash(
+ _In_ KSPROPERTY_CAMERACONTROL_FLASH_S *pFlash
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_Flash = pFlash->Flash;
+ return STATUS_SUCCESS;
+}
+
+// Get for KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_PROPERTY_ID
+NTSTATUS
+CSensorSimulation::
+GetPinDependence(
+ _Inout_ KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S *pCaps
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // Limit capabilities to the valid set.
+ pCaps->Capabilities &=
+ ( KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_EXCLUSIVE_WITH_RECORD |
+ KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_SEQUENCE_EXCLUSIVE_WITH_RECORD );
+
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME
+NTSTATUS
+CSensorSimulation::
+GetTriggerTime(
+ _Inout_ CExtendedProperty *pQPC
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pQPC->Flags = 0;
+ NTSTATUS Status = GetQPC( pQPC->PinId, &pQPC->m_Value.Value.ull );
+
+ if( NT_SUCCESS(Status) )
+ {
+ pQPC->Flags = ( pQPC->m_Value.Value.ull != 0 ) ?
+ KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_SET :
+ KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_CLEAR;
+ }
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME
+NTSTATUS
+CSensorSimulation::
+SetTriggerTime(
+ _In_ CExtendedProperty *pQPC
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ ULONGLONG Time = ( pQPC->Flags & KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_SET ) ? *pQPC : 0;
+ return SetQPC( pQPC->PinId, Time );
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_TORCHMODE
+NTSTATUS
+CSensorSimulation::
+GetTorchMode(
+ _Inout_ CExtendedProperty *pTorchMode
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pTorchMode = m_TorchMode;
+ pTorchMode->Capability =
+ KSCAMERA_EXTENDEDPROP_VIDEOTORCH_OFF |
+ KSCAMERA_EXTENDEDPROP_VIDEOTORCH_ON |
+ KSCAMERA_EXTENDEDPROP_VIDEOTORCH_ON_ADJUSTABLEPOWER;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_TORCHMODE
+NTSTATUS
+CSensorSimulation::
+SetTorchMode(
+ _In_ CExtendedProperty *pTorchMode
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_TorchMode = *pTorchMode;
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE
+NTSTATUS
+CSensorSimulation::
+GetPhotoMode(
+ _Inout_ CExtendedPhotoMode *pPhotoMode
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pPhotoMode->Flags = m_PhotoMode.Flags;
+ pPhotoMode->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE;
+ pPhotoMode->MaxHistoryFrames() = IMAGE_CAPTURE_PIN_MAXIMUM_HISTORY_FRAMES;
+ pPhotoMode->RequestedHistoryFrames() = m_PhotoMode.RequestedHistoryFrames();
+ pPhotoMode->SubMode() = m_PhotoMode.SubMode();
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE
+NTSTATUS
+CSensorSimulation::
+SetPhotoModeAsync(
+ _In_ CExtendedPhotoMode *pPhotoMode,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ DBG_ENTER("()");
+
+ m_PhotoMode = *pPhotoMode;
+
+ NTSTATUS Status =
+ SetPinMode( pPhotoMode->PinId, pPhotoMode->Flags, pPhotoMode->RequestedHistoryFrames() );
+
+ // Tell the caller that we're done.
+ Notifier->Set();
+
+ DBG_LEAVE("()=0x%08X",Status);
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE Get Handler
+ */
+NTSTATUS
+CSensorSimulation::
+GetPhotoMaxFrameRate(
+ _Inout_ CExtendedProperty *pPhotoMaxFrameRate
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pPhotoMaxFrameRate->Flags = m_MaxFrameRate.Flags;
+ pPhotoMaxFrameRate->m_Value = m_MaxFrameRate.m_Value;
+ // If max frame rate is 0,0, we want to indicate 30fps to the caller.
+ if ((*pPhotoMaxFrameRate).m_Value.Value.ull == 0)
+ {
+ (*pPhotoMaxFrameRate).m_Value.Value.ratio.HighPart = 30000;
+ (*pPhotoMaxFrameRate).m_Value.Value.ratio.LowPart = 1000;
+ }
+ pPhotoMaxFrameRate->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ return STATUS_SUCCESS;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE Set Handler
+ */
+NTSTATUS
+CSensorSimulation::
+SetPhotoMaxFrameRateAsync(
+ _In_ CExtendedProperty *pPhotoMaxFrameRate,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+
+ ULONGLONG TimePerFrame = 0;
+ {
+ // Note: Don't lock around SetPhotoFrameRate() to avoid a priority inversion.
+ KScopedMutex lock( m_SensorMutex );
+
+ m_MaxFrameRate = *pPhotoMaxFrameRate;
+
+ // Try to apply the setting immediately.
+ LARGE_INTEGER PerformanceTime = { m_MaxFrameRate.m_Value.Value.ratio.LowPart };
+ LONGLONG Frequency = m_MaxFrameRate.m_Value.Value.ratio.HighPart;
+
+ if( Frequency != 0 )
+ {
+ TimePerFrame = KSCONVERT_PERFORMANCE_TIME( Frequency, PerformanceTime );
+ }
+ }
+
+ DBG_TRACE( "SetPhotoFrameRate(%lld)", TimePerFrame );
+
+ // Consume any error; we'll set the rate again when the pin starts.
+ SetPhotoFrameRate( pPhotoMaxFrameRate->PinId, TimePerFrame );
+
+ // Tell the caller that we're done.
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART
+ */
+NTSTATUS
+CSensorSimulation::
+GetWarmStart(
+ _Inout_ CExtendedProperty *pWarmStart
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ *pWarmStart = m_WarmStartEnabled[pWarmStart->PinId];
+ pWarmStart->Capability =
+ KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL |
+ KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_DISABLED |
+ KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED ;
+ return STATUS_SUCCESS;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART
+ */
+NTSTATUS
+CSensorSimulation::
+SetWarmStartAsync(
+ _In_ CExtendedProperty *pWarmStart,
+ _In_ CNotifier *Notifier // Use to notify the framework that the control is done.
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ m_WarmStartEnabled[pWarmStart->PinId] = *pWarmStart;
+
+ // Tell the caller that we're done.
+ Notifier->Set();
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES Get Handler
+ */
+NTSTATUS
+CSensorSimulation::
+GetMaxVideoFpsForPhotoRes(
+ _Inout_ CExtendedMaxVideoFpsForPhotoRes *pPhotoRes
+)
+{
+ PAGED_CODE();
+
+ // We're just a simulation and have no constraints - set 30FPS.
+ pPhotoRes->PreviewFPSNum() =30;
+ pPhotoRes->PreviewFPSDenom() = 1;
+ pPhotoRes->CaptureFPSNum() = 30;
+ pPhotoRes->CaptureFPSDenom() = 1;
+
+ return STATUS_SUCCESS;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES Set Handler
+ */
+NTSTATUS
+CSensorSimulation::
+SetMaxVideoFpsForPhotoRes(
+ _In_ CExtendedMaxVideoFpsForPhotoRes *pPhotoRes
+)
+{
+ PAGED_CODE();
+
+ // We don't really use this call.
+ return STATUS_SUCCESS;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FIELDOFVIEW
+NTSTATUS
+CSensorSimulation::
+GetFieldOfView(
+ _Inout_ CExtendedFieldOfView *pFieldOfView
+)
+{
+ PAGED_CODE();
+
+ // Report dummy values.
+ *pFieldOfView = CExtendedFieldOfView();
+ pFieldOfView->NormalizedFocalLengthX() = 35;
+ pFieldOfView->NormalizedFocalLengthY() = 35;
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FIELDOFVIEW
+NTSTATUS
+CSensorSimulation::
+GetCameraAngleOffset(
+ _Inout_ CExtendedCameraAngleOffset *pAngle
+)
+{
+ PAGED_CODE();
+
+ // Just return zeros. We're dead-on, no tilt.
+ *pAngle = CExtendedCameraAngleOffset();
+
+ return STATUS_SUCCESS;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_CONFIGCAPS Get handler
+NTSTATUS
+CSensorSimulation::
+GetRoiConfigCaps(
+ _Inout_ CRoiConfig *pCaps
+)
+{
+ PAGED_CODE();
+ // No state accessed...
+ //KScopedMutex lock( m_SensorMutex );
+
+ // Our CRoiConfig ctor defines our capabilities.
+ *pCaps = CRoiConfig();
+
+ return STATUS_SUCCESS;
+}
+
+// Per Frame Settings Caps
+struct SOC_PFS_CAPS
+{
+ KSCAMERA_PERFRAMESETTING_CAP_HEADER Hdr;
+ SOC_CAP_WITH_STEPPING_LONGLONG ExposureTime;
+ KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER Flash;
+ SOC_CAP_WITH_STEPPING EVCompensation;
+ SOC_CAP_WITH_STEPPING Iso;
+ SOC_CAP_WITH_STEPPING Focus;
+ KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER StillConfirmation;
+} ;
+
+const ULONG SOC_PFS_NUMCAPS = 6;
+
+// Our predefined Variable Photo Sequence capabilities.
+SOC_PFS_CAPS g_PFSCaps =
+{
+ // KSCAMERA_PERFRAMESETTING_CAP_HEADER
+ { sizeof(SOC_PFS_CAPS), SOC_PFS_NUMCAPS, 0 }, //Hdr
+ // ExposureTime
+ {
+ // SOC_CAP_WITH_STEPPING_LONGLONG
+ {
+ // KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+ sizeof(g_PFSCaps.ExposureTime), //Size
+ KSCAMERA_PERFRAMESETTING_ITEM_EXPOSURE_TIME, //Type
+ KSCAMERA_PERFRAMESETTING_AUTO //Flags
+ | KSCAMERA_PERFRAMESETTING_MANUAL
+ },
+ {
+ // KSPROPERTY_STEPPING_LONGLONG
+ 1000, //SteppingDelta (in us)
+ {
+ // KSPROPERTY_BOUNDS_LONGLONG
+ MIN_EXPOSURE_TIME, //SignedMinimum
+ MAX_EXPOSURE_TIME //SignedMaximum (arbitrary - 1 hour)
+ }
+ }
+ },
+ // Flash
+ {
+ // KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+ sizeof(g_PFSCaps.Flash),
+ KSCAMERA_PERFRAMESETTING_ITEM_FLASH,
+ KSCAMERA_EXTENDEDPROP_FLASH_OFF
+ | KSCAMERA_EXTENDEDPROP_FLASH_ON
+ | KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER
+ | KSCAMERA_EXTENDEDPROP_FLASH_AUTO
+ | KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER
+ | KSCAMERA_EXTENDEDPROP_FLASH_REDEYEREDUCTION
+ },
+ // ExposureCompensation
+ {
+ // SOC_CAP_WITH_STEPPING
+ {
+ // KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+ sizeof(g_PFSCaps.EVCompensation), //Size
+ KSCAMERA_PERFRAMESETTING_ITEM_EXPOSURE_COMPENSATION, //Type
+ KSCAMERA_PERFRAMESETTING_AUTO //Flags
+ | KSCAMERA_EXTENDEDPROP_EVCOMP_SIXTHSTEP
+ | KSCAMERA_EXTENDEDPROP_EVCOMP_QUARTERSTEP
+ | KSCAMERA_EXTENDEDPROP_EVCOMP_THIRDSTEP
+ | KSCAMERA_EXTENDEDPROP_EVCOMP_HALFSTEP
+ | KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP
+ },
+ {
+ // KSPROPERTY_STEPPING_LONG
+ 1, //SteppingDelta
+ 0, //Reserved
+ {
+ // KSPROPERTY_BOUNDS_LONG
+ -2, //SignedMinimum
+ 2 //SignedMaximum
+ }
+ }
+ },
+ // Iso
+ {
+ // SOC_CAP_WITH_STEPPING
+ {
+ // KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+ sizeof(g_PFSCaps.Iso),
+ KSCAMERA_PERFRAMESETTING_ITEM_ISO,
+ KSCAMERA_EXTENDEDPROP_ISO_AUTO
+ | KSCAMERA_EXTENDEDPROP_ISO_MANUAL
+ },
+ {
+ // KSPROPERTY_STEPPING_LONG
+ 50, //SteppingDelta
+ 0, //Reserved
+ {
+ // KSPROPERTY_BOUNDS_LONG
+ 50, //SignedMinimum
+ 256000 //SignedMaximum
+ }
+ }
+ },
+ // Focus
+ {
+ // SOC_CAP_WITH_STEPPING
+ {
+ // KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+ sizeof(g_PFSCaps.Focus), //Size
+ KSCAMERA_PERFRAMESETTING_ITEM_FOCUS, //Type
+ KSCAMERA_PERFRAMESETTING_AUTO //Flags
+ | KSCAMERA_PERFRAMESETTING_MANUAL
+ },
+ {
+ // KSPROPERTY_STEPPING_LONG
+ 10, //SteppingDelta (We'll use centimeters for kicks)
+ 0, //Reserved
+ {
+ // KSPROPERTY_BOUNDS_LONG
+ 0, //SignedMinimum
+ 10000 //SignedMaximum (100 meters max)
+ }
+ }
+ },
+ // StillConfirmation
+ {
+ // KSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+ sizeof(g_PFSCaps.StillConfirmation),
+ KSCAMERA_PERFRAMESETTING_ITEM_PHOTOCONFIRMATION,
+ 0
+ },
+};
+
+// Get KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_CAPABILITY
+_Success_(return == 0)
+NTSTATUS
+CSensorSimulation::
+GetPfsCaps(
+ _Inout_opt_ KSCAMERA_PERFRAMESETTING_CAP_HEADER *Caps,
+ _Inout_ ULONG *Size
+)
+{
+ PAGED_CODE();
+
+ if( Caps )
+ {
+ size_t Length = sizeof(g_PFSCaps);
+ if( Size && *Size < Length )
+ {
+ Length = *Size;
+ }
+ RtlCopyMemory( Caps, &g_PFSCaps, Length );
+ }
+
+ *Size = sizeof(g_PFSCaps);
+
+ return STATUS_SUCCESS;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL Get handler
+NTSTATUS
+CSensorSimulation::
+GetRoi(
+ _Inout_ CRoiProperty *pRoi
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ // *pRoiProperty = ...
+ *pRoi = CRoiProperty(); // initialize it.
+
+ // Add control properties to it.
+ pRoi->Add( &m_RoiWhiteBalance ) ;
+ pRoi->Add( &m_RoiExposureMode ) ;
+ pRoi->Add( &m_RoiFocusMode ) ;
+
+ // Log what we created.
+ pRoi->Log();
+
+ return STATUS_SUCCESS;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL Set handler
+NTSTATUS
+CSensorSimulation::
+SetRoiAsync(
+ _In_ CRoiProperty *pRoi,
+ _In_ CNotifier *Notifier
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ if( pRoi->GetControlCount() == 0 )
+ {
+ // Clear all settings.
+ DBG_TRACE("Clearing all settings...");
+ m_RoiWhiteBalance = CWhiteBalanceRoiIspControl();
+ m_RoiExposureMode = CExposureRoiIspControl();
+ m_RoiFocusMode = CFocusRoiIspControl();
+ }
+ else
+ {
+ // Parse our settings.
+ DBG_TRACE("Parsing new settings...");
+ if( m_RoiWhiteBalance.
+ Init( pRoi, KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE ) )
+ {
+ m_GlobalIspSettings.WhiteBalanceMode = m_RoiWhiteBalance.GetFlags();
+ m_RoiWhiteBalance.Log();
+ }
+ if( m_RoiExposureMode.
+ Init( pRoi, KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE ) )
+ {
+ m_GlobalIspSettings.ExposureMode = m_RoiExposureMode.GetFlags();
+ m_RoiExposureMode.Log();
+ }
+ if( m_RoiFocusMode.
+ Init( pRoi, KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE ) )
+ {
+ ULONGLONG Flags = m_RoiFocusMode.GetFlags();
+ DBG_TRACE("Requesting FocusMode = 0x%016llX", Flags);
+
+ if( Flags )
+ {
+ // If we've been asked to unlock, remove any lock flags.
+ if( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_UNLOCK )
+ {
+ // Change our operation so we go back to the previous state.
+ Flags = m_GlobalIspSettings.FocusMode &
+ ~( KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK );
+ }
+
+ // Handle the stand-alone lock case by setting the appropriate flags.
+ if( ( Flags &
+ (KSCAMERA_EXTENDEDPROP_FOCUS_MODE_MASK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_MODE_ADVANCED_MASK) ) ==
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK )
+ {
+ if( m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO )
+ {
+ Flags =
+ m_GlobalIspSettings.FocusMode | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+ }
+ if( m_GlobalIspSettings.FocusMode & KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS )
+ {
+ Flags =
+ m_GlobalIspSettings.FocusMode |= KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK;
+ }
+ }
+ // Note: We do not simulate deferred completion.
+ m_FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_FOCUSED;
+
+ // Record the Focus mode.
+ DBG_TRACE("Recording FocusMode = 0x%016llX", Flags);
+ m_GlobalIspSettings.FocusMode = Flags;
+ }
+
+ m_RoiFocusMode.Log();
+ }
+ }
+
+ Notifier->Set();
+ return STATUS_SUCCESS;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL size handler
+ULONG
+CSensorSimulation::
+SizeOfRoi()
+{
+ PAGED_CODE();
+
+ return
+ sizeof( CRoiProperty ) +
+ m_RoiWhiteBalance.GetSize() +
+ m_RoiExposureMode.GetSize() +
+ m_RoiFocusMode.GetSize() ;
+}
+
+
+// Get KSPROPERTY_VIDEOCONTROL_MODE.
+NTSTATUS
+CSensorSimulation::
+GetVideoControlMode(
+ _Inout_ KSPROPERTY_VIDEOCONTROL_MODE_S *pMode
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pMode->Mode = GetTriggerMode(pMode->StreamIndex);
+
+ return STATUS_SUCCESS;
+}
+
+// Set KSPROPERTY_VIDEOCONTROL_MODE.
+NTSTATUS
+CSensorSimulation::
+SetVideoControlMode(
+ _In_ KSPROPERTY_VIDEOCONTROL_MODE_S *pMode
+)
+{
+ PAGED_CODE();
+
+ // Note: Trigger will acquire a lock on the hwsim.
+ return Trigger( pMode->StreamIndex, pMode->Mode );
+}
+
+// Get KSPROPERTY_VIDEOCONTROL_CAPS.
+NTSTATUS
+CSensorSimulation::
+GetVideoControlCaps(
+ _Inout_ KSPROPERTY_VIDEOCONTROL_CAPS_S *pCaps
+)
+{
+ PAGED_CODE();
+ KScopedMutex lock( m_SensorMutex );
+
+ pCaps->VideoControlCaps = 0;
+ if( IsStillIndex( pCaps->StreamIndex ) )
+ {
+ pCaps->VideoControlCaps =
+ KS_VideoControlFlag_IndependentImagePin |
+ KS_VideoControlFlag_Trigger |
+ KS_VideoControlFlag_StartPhotoSequenceCapture |
+ KS_VideoControlFlag_StopPhotoSequenceCapture;
+ }
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/AVStream/avscamera/sys/SensorSimulation.h b/AVStream/avscamera/sys/SensorSimulation.h
new file mode 100644
index 00000000..4b07f84e
--- /dev/null
+++ b/AVStream/avscamera/sys/SensorSimulation.h
@@ -0,0 +1,281 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ SensorSimulation.h
+
+ Abstract:
+
+ Simulation class declaration. Derived from the base CSensor object.
+
+ This class simulates a theoretical model camera. The camera supports
+ every modern camera control available and produces a simulation of its
+ behavior. In most cases this simulation is very very basic because we
+ have no actual hardware to work with and there producing a visible
+ effect in the simulation would be difficult or expensive to do.
+
+ History:
+
+ created 5/8/2014
+
+**************************************************************************/
+
+#pragma once
+class CSensorSimulation :
+ public CSensor
+{
+protected:
+ const
+ KSFILTER_DESCRIPTOR *m_Descriptors;
+
+ LARGE_INTEGER m_StartTime;
+
+ // State for the various controls.
+ RECT m_FocusRect;
+ BOOL m_AutoFocusLock;
+ BOOL m_AutoExposureLock;
+ BOOL m_AutoWhitebalanceLock;
+ ULONG m_Flash;
+ ULONG m_VideoStabMode;
+ CExtendedProperty *m_WarmStartEnabled;
+ CExtendedPhotoMode m_PhotoMode;
+ ULONG m_RequestedHistoryFrames;
+ CExtendedProperty m_MaxFrameRate;
+ ULONGLONG m_FaceDetectionFlags;
+ ULONG m_FaceDetectionMax;
+ ULONG m_FaceDetectionCurrentMax;
+ ULONGLONG m_SceneMode;
+ CExtendedProperty m_TorchMode;
+ CExtendedProperty m_OptimizationHint;
+ CExtendedMetadata *m_MetadataInfo;
+ PKSCAMERA_PERFRAMESETTING_HEADER m_pPerFrameSettings;
+ ULONG m_PFSSize;
+ KSCAMERA_EXTENDEDPROP_FOCUSSTATE m_FocusState;
+ ULONGLONG m_VFR;
+ ULONGLONG m_VideoHDR;
+ ULONGLONG m_VideoStabilization;
+ ULONGLONG m_Histogram;
+ ULONGLONG m_OpticalImageStabilization;
+ CExtendedProperty m_AdvancedPhoto;
+
+ CWhiteBalanceRoiIspControl m_RoiWhiteBalance;
+ CExposureRoiIspControl m_RoiExposureMode;
+ CFocusRoiIspControl m_RoiFocusMode;
+
+ VIDCAP_PROPERTY m_Pan;
+ VIDCAP_PROPERTY m_Roll;
+ VIDCAP_PROPERTY m_Tilt;
+
+ // Zoom parameters
+ FOCAL_LENGTH_PROPERTY m_FocalLength; // A description of the zoom limits.
+ VIDCAP_PROPERTY m_Zoom; // Absolute zoom position / mode.
+ VIDCAP_PROPERTY m_ZoomRelative; // Relative zoom position / mode.
+
+ // Cached Q16-adjusted bounds. I do not use the zoom value stored below.
+ //
+ // I am using the same m_Zoom value here to keep both the extended and legacy
+ // controls tied together. It is not necessary to implement both in a real driver.
+ // However the legacy control was implemented first in this simulation and leaving both
+ // in place might have some value. But supporting both adds the question of whether they
+ // should both present a consistent view of zoom or if they should just save and report
+ // the values set for their own respective properties.
+ //
+ // I have chosen to support a consistent view of the zoom factor between the extended and
+ // legacy controls. Given that the legacy control was implemented first, I have chosen
+ // to keep that storage and rescale the value set by the extended zoom to match the
+ // legacy settings.
+ //
+ // But to make the two controls more consistent, I have changed the reported Ocular Focal
+ // Length to 2^16, which matches the implied denominator in Q16 format - the format used
+ // by this extended property. So as long as lOcularFocalLength is 0x10000, the following
+ // function should not change the reported value at all. This should simplify any
+ // debugging or tracing.
+
+ CExtendedVidProcSetting m_ExtendedZoom; // Must update zoom value on the fly.
+
+ VIDCAP_PROPERTY m_PowerLineFreq; // Power Line Frequency setting.
+ VIDCAP_PROPERTY m_BacklightCompensation;
+ VIDCAP_PROPERTY m_Brightness;
+ VIDCAP_PROPERTY m_Contrast;
+ VIDCAP_PROPERTY m_Hue;
+
+ ULONG m_IsoResult;
+ ULONG m_EvCompResult;
+ ULONG m_WhiteBalanceResult;
+ ULONG m_ExposureResult;
+ ULONG m_SceneModeResult;
+ ULONG m_FaceDetectionResult;
+ ULONG m_FocusResult;
+
+ ULONGLONG m_LastFocusMode;
+ ULONG m_LastFocusSetting;
+
+ CRefPtr<CNotifier> m_FocusNotifier; // A reference to the CNotifier for any Focus in flight.
+ KPassiveTimer *m_FocusTimer; // A timer object used to simulate a focus event.
+ CRefPtr<CNotifier> m_FocusRectNotifier;
+ KPassiveTimer *m_FocusRectTimer;
+
+ static const ULONG METADATA_MAX=4096;
+
+protected:
+ //
+ // Deal with scene mode changes.
+ //
+ NTSTATUS
+ UpdateSettings(
+ _In_ ULONGLONG ullSceneMode
+ );
+
+ //
+ // Put us back to the defaults specified in the DDI.
+ //
+ virtual
+ NTSTATUS
+ ProgramDefaults();
+
+public:
+ //
+ // This simulation is based solely on the Descriptors. Yours might
+ // need additional information.
+ //
+ CSensorSimulation(
+ _In_ CCaptureDevice *Device,
+ _In_ const KSFILTER_DESCRIPTOR *Descriptors
+ );
+
+ virtual ~CSensorSimulation();
+
+ //
+ // Parse descriptors to determine what pin simulations are required.
+ // Do memory allocations, etc.
+ //
+ virtual
+ NTSTATUS
+ Initialize();
+
+ virtual
+ NTSTATUS
+ GetFocusState(
+ _Out_ KSCAMERA_EXTENDEDPROP_FOCUSSTATE *FocusState
+ );
+
+ // Lets you know if Variable Photo Sequence is active.
+ // Note: This doesn't tell you if the pin is running.
+ virtual
+ BOOLEAN
+ IsVPSActive()
+ {
+ return
+ KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE_SUB_VARIABLE==m_PhotoMode.SubMode() &&
+ m_pIspSettings ;
+ }
+
+ // Callback to handle focus convergence.
+ static
+ void
+ FocusConvergence(
+ _In_opt_ PVOID Context
+ );
+
+ // Callback to handle focus convergence.
+ static
+ void
+ FocusRectConvergence(
+ _In_opt_ PVOID Context
+ );
+
+ // Declare the property controls handled by this sensor.
+ DECLARE_PROPERTY( KSPROPERTY_VIDEOCONTROL_MODE_S, VideoControlMode );
+ DECLARE_PROPERTY_GET( KSPROPERTY_VIDEOCONTROL_CAPS_S, VideoControlCaps );
+
+ DECLARE_PROPERTY_ASYNC( KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S, FocusRect );
+
+ DECLARE_PROPERTY( KSPROPERTY_CAMERACONTROL_FLASH_S, Flash );
+ DECLARE_PROPERTY_GET( KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S, PinDependence );
+ DECLARE_PROPERTY( CExtendedProperty, TriggerTime );
+ DECLARE_PROPERTY( CExtendedProperty, TorchMode );
+
+ DECLARE_PROPERTY( CExtendedProperty, ExtendedFlash );
+
+ DECLARE_PROPERTY_ASYNC( CExtendedVidProcSetting, Focus );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedProperty, Iso );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedVidProcSetting, IsoAdvanced );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedEvCompensation, EvCompensation );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedVidProcSetting, WhiteBalance );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedVidProcSetting, Exposure );
+ DECLARE_PROPERTY( CExtendedProperty, PhotoConfirmation );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedProperty, SceneMode );
+ DECLARE_PROPERTY( CExtendedProperty, FocusPriority );
+ DECLARE_PROPERTY( CExtendedProperty, VideoHDR );
+ DECLARE_PROPERTY( CExtendedProperty, VFR );
+ DECLARE_PROPERTY( CExtendedVidProcSetting, Zoom );
+ DECLARE_PROPERTY( CExtendedProperty, VideoStabilization );
+ DECLARE_PROPERTY( CExtendedProperty, Histogram );
+ DECLARE_PROPERTY( CExtendedMetadata, Metadata );
+ DECLARE_PROPERTY( CExtendedProperty, OpticalImageStabilization );
+ DECLARE_PROPERTY( CExtendedProperty, OptimizationHint );
+ DECLARE_PROPERTY( CExtendedProperty, AdvancedPhoto );
+ DECLARE_PROPERTY( CExtendedVidProcSetting, FaceDetection );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedPhotoMode, PhotoMode );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedProperty, PhotoMaxFrameRate );
+ DECLARE_PROPERTY_ASYNC_NOCANCEL( CExtendedProperty, WarmStart );
+ DECLARE_PROPERTY( CExtendedMaxVideoFpsForPhotoRes, MaxVideoFpsForPhotoRes );
+ DECLARE_PROPERTY_GET( CExtendedFieldOfView, FieldOfView );
+ DECLARE_PROPERTY_GET( CExtendedCameraAngleOffset, CameraAngleOffset );
+
+ DECLARE_PROPERTY_VARSIZE_ASYNC_NOCANCEL( CRoiProperty, Roi );
+
+ DECLARE_PROPERTY( KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S, VideoStabMode );
+
+ // Update the zoom factor over time.
+ void
+ SmoothZoom();
+
+ // Apply a zoom factor.
+ virtual
+ void
+ UpdateZoom(void);
+
+ // Declare legacy controls that are needed.
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Exposure);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Focus);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Zoom);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, ZoomRelative);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Pan);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Roll);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_S, Tilt);
+ DECLARE_PROPERTY(KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S, FocalLength);
+
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, BacklightCompensation);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, Brightness);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, Contrast);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, Hue);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, WhiteBalance);
+ DECLARE_PROPERTY(KSPROPERTY_VIDEOPROCAMP_S, PowerlineFreq);
+
+ DECLARE_PROPERTY_GET( CRoiConfig, RoiConfigCaps );
+
+ // Special-case Per-Frame settings since it requires a variable length structure.
+ _Success_(return == 0)
+ virtual
+ NTSTATUS
+ GetPfsCaps(
+ _Inout_opt_ KSCAMERA_PERFRAMESETTING_CAP_HEADER *Caps,
+ _Inout_ ULONG *Size
+ );
+};
+
+// Constants...
+const LONG WHITEBALANCE_MIN = 0;
+const LONG WHITEBALANCE_MAX = 15000;
+const LONG WHITEBALANCE_STEP= 1;
+const LONG WHITEBALANCE_DEF = 5000;
+
+const LONG EXPOSURE_BILOG_MIN = -10;
+const LONG EXPOSURE_BILOG_MAX = 9;
+const LONG EXPOSURE_BILOG_STEP = 1;
+const LONG EXPOSURE_BILOG_DEF = -5; \ No newline at end of file
diff --git a/AVStream/avscamera/sys/Sources.dep b/AVStream/avscamera/sys/Sources.dep
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/AVStream/avscamera/sys/Sources.dep
@@ -0,0 +1 @@
+
diff --git a/AVStream/avscamera/sys/Synthesizer.cpp b/AVStream/avscamera/sys/Synthesizer.cpp
new file mode 100644
index 00000000..4f591424
--- /dev/null
+++ b/AVStream/avscamera/sys/Synthesizer.cpp
@@ -0,0 +1,1558 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ Synthesizer.cpp
+
+ Abstract:
+
+ This file contains the implementation of CSynthesizer.
+
+ The base image synthesis and overlay class. These classes provide
+ image synthesis (pixel, color-bar, etc...) onto buffers of various
+ formats.
+
+ Internally, all CSynthesizer objects represent a pixel as a 32 bit
+ quantity with 8 bits per sample. The base CSynthesizer implements
+ all rendering functionality with this assumption in mind. It
+ simplifies rendering substantially and means we do not need to re-
+ implement rendering functions for each format.
+
+ Most end formats can be synthesized from this uncompressed format
+ with overhead that is slightly worse than a copy. Color spaces are
+ handled by using a rendering palette that is unique for each.
+
+ History:
+
+ created 04/14/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+/**************************************************************************
+
+ Constants
+
+**************************************************************************/
+
+//
+// Standard definition of EIA-189-A color bars. The actual color definitions
+// are either in CRGB24Synthesizer or CYUVSynthesizer.
+//
+
+const COLOR CSynthesizer::m_ColorBars[8] =
+{MAGENTA, BLUE, GREEN, BLACK, WHITE, YELLOW, RED, CYAN };
+
+
+//
+// Corner registration block colors.
+//
+const COLOR g_TopLeft = GREY;
+const COLOR g_TopRight = BLUE;
+const COLOR g_BotLeft = RED;
+const COLOR g_BotRight = GREEN;
+
+//
+// Persistent stats.
+//
+LONGLONG CSynthesizer::m_RelPts=0;
+LONGLONG CSynthesizer::m_QpcTime=0;
+ULONG CSynthesizer::m_Frame=0;
+
+//
+// The following is an 8x8 bitmapped font for use in the text overlay
+// code.
+//
+const UCHAR
+CSynthesizer::
+m_FontData [2][256][8] =
+{
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e},
+ {0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e},
+ {0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00},
+ {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00},
+ {0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c},
+ {0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c},
+ {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00},
+ {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff},
+ {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00},
+ {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff},
+ {0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78},
+ {0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18},
+ {0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0},
+ {0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0},
+ {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99},
+ {0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00},
+ {0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00},
+ {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18},
+ {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00},
+ {0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00},
+ {0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78},
+ {0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00},
+ {0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff},
+ {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00},
+ {0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00},
+ {0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00},
+ {0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00},
+ {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00},
+ {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00},
+ {0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00},
+ {0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00},
+ {0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00},
+ {0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00},
+ {0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00},
+ {0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00},
+ {0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00},
+ {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00},
+ {0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00},
+ {0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60},
+ {0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00},
+ {0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00},
+ {0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00},
+ {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00},
+ {0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00},
+ {0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00},
+ {0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00},
+ {0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00},
+ {0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00},
+ {0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00},
+ {0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00},
+ {0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00},
+ {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00},
+ {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60},
+ {0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00},
+ {0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00},
+ {0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00},
+ {0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00},
+ {0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00},
+ {0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00},
+ {0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00},
+ {0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00},
+ {0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00},
+ {0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00},
+ {0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00},
+ {0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00},
+ {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00},
+ {0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00},
+ {0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00},
+ {0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00},
+ {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00},
+ {0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00},
+ {0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00},
+ {0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00},
+ {0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00},
+ {0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00},
+ {0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},
+ {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00},
+ {0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00},
+ {0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00},
+ {0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00},
+ {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00},
+ {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00},
+ {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00},
+ {0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
+ {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00},
+ {0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00},
+ {0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00},
+ {0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00},
+ {0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
+ {0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00},
+ {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
+ {0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00},
+ {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78},
+ {0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00},
+ {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00},
+ {0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},
+ {0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00},
+ {0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0},
+ {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e},
+ {0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00},
+ {0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00},
+ {0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00},
+ {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00},
+ {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},
+ {0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00},
+ {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00},
+ {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
+ {0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00},
+ {0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00},
+ {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},
+ {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00},
+ {0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00},
+ {0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78},
+ {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
+ {0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
+ {0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00},
+ {0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
+ {0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
+ {0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
+ {0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38},
+ {0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00},
+ {0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
+ {0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
+ {0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00},
+ {0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00},
+ {0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00},
+ {0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},
+ {0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00},
+ {0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00},
+ {0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
+ {0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
+ {0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
+ {0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
+ {0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
+ {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
+ {0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00},
+ {0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00},
+ {0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18},
+ {0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00},
+ {0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30},
+ {0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7},
+ {0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70},
+ {0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
+ {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
+ {0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
+ {0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
+ {0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00},
+ {0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00},
+ {0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00},
+ {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00},
+ {0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00},
+ {0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00},
+ {0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f},
+ {0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03},
+ {0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00},
+ {0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00},
+ {0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00},
+ {0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88},
+ {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa},
+ {0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee},
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18},
+ {0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36},
+ {0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36},
+ {0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18},
+ {0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36},
+ {0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00},
+ {0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00},
+ {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00},
+ {0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18},
+ {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00},
+ {0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18},
+ {0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36},
+ {0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00},
+ {0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36},
+ {0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00},
+ {0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18},
+ {0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00},
+ {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18},
+ {0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36},
+ {0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36},
+ {0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
+ {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0},
+ {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f},
+ {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00},
+ {0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0},
+ {0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00},
+ {0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00},
+ {0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00},
+ {0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00},
+ {0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0},
+ {0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00},
+ {0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc},
+ {0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00},
+ {0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00},
+ {0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00},
+ {0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00},
+ {0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0},
+ {0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00},
+ {0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},
+ {0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00},
+ {0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00},
+ {0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00},
+ {0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00},
+ {0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18},
+ {0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70},
+ {0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00},
+ {0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00},
+ {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00},
+ {0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c},
+ {0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00},
+ {0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ },
+ {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x7e, 0x81, 0xa9, 0x8d, 0x8d, 0xa9, 0x81, 0x7e},
+ {0x7e, 0xff, 0xd7, 0xf3, 0xf3, 0xd7, 0xff, 0x7e},
+ {0x00, 0x70, 0xf8, 0xfc, 0x7e, 0xfc, 0xf8, 0x70},
+ {0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10},
+ {0x00, 0x18, 0x5d, 0xff, 0xff, 0xff, 0x5d, 0x18},
+ {0x00, 0x08, 0x1d, 0x3f, 0xff, 0x3f, 0x1d, 0x08},
+ {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00},
+ {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff},
+ {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00},
+ {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff},
+ {0xf0, 0xe0, 0xfe, 0xbf, 0x11, 0x11, 0x1f, 0x0e},
+ {0x00, 0x72, 0xfa, 0x8f, 0x8f, 0xfa, 0x72, 0x00},
+ {0xe0, 0xe0, 0xa0, 0xa0, 0xfe, 0xff, 0x07, 0x03},
+ {0xfc, 0xfe, 0xa6, 0xa0, 0xa0, 0xfe, 0xff, 0x03},
+ {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99},
+ {0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe},
+ {0x00, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10},
+ {0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00},
+ {0x00, 0xfa, 0xfa, 0x00, 0x00, 0xfa, 0xfa, 0x00},
+ {0xfe, 0xfe, 0x80, 0xfe, 0xfe, 0x90, 0xf0, 0x60},
+ {0x40, 0xc0, 0x9a, 0xbf, 0xa5, 0xfd, 0x5b, 0x02},
+ {0x00, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x00},
+ {0x01, 0x29, 0x6d, 0xff, 0xff, 0x6d, 0x29, 0x01},
+ {0x00, 0x20, 0x60, 0xfe, 0xfe, 0x60, 0x20, 0x00},
+ {0x00, 0x08, 0x0c, 0xfe, 0xfe, 0x0c, 0x08, 0x00},
+ {0x00, 0x10, 0x38, 0x7c, 0x54, 0x10, 0x10, 0x10},
+ {0x00, 0x10, 0x10, 0x10, 0x54, 0x7c, 0x38, 0x10},
+ {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x3c},
+ {0x10, 0x38, 0x7c, 0x10, 0x10, 0x7c, 0x38, 0x10},
+ {0x0c, 0x1c, 0x3c, 0x7c, 0x7c, 0x3c, 0x1c, 0x0c},
+ {0x60, 0x70, 0x78, 0x7c, 0x7c, 0x78, 0x70, 0x60},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x60, 0xfa, 0xfa, 0x60, 0x00},
+ {0x00, 0x00, 0xe0, 0xe0, 0x00, 0xe0, 0xe0, 0x00},
+ {0x00, 0x28, 0xfe, 0xfe, 0x28, 0xfe, 0xfe, 0x28},
+ {0x00, 0x00, 0x48, 0x5c, 0xd6, 0xd6, 0x74, 0x24},
+ {0x00, 0x46, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x62},
+ {0x00, 0x12, 0x5e, 0xec, 0xba, 0xf2, 0x5e, 0x0c},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0x20},
+ {0x00, 0x00, 0x00, 0x82, 0xc6, 0x7c, 0x38, 0x00},
+ {0x00, 0x00, 0x00, 0x38, 0x7c, 0xc6, 0x82, 0x00},
+ {0x10, 0x54, 0x7c, 0x38, 0x38, 0x7c, 0x54, 0x10},
+ {0x00, 0x00, 0x10, 0x10, 0x7c, 0x7c, 0x10, 0x10},
+ {0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x01, 0x00},
+ {0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
+ {0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00},
+ {0x00, 0x80, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},
+ {0x00, 0x7c, 0xfe, 0xb2, 0x9a, 0x8e, 0xfe, 0x7c},
+ {0x00, 0x00, 0x02, 0x02, 0xfe, 0xfe, 0x42, 0x02},
+ {0x00, 0x00, 0x66, 0xf6, 0x92, 0x9a, 0xce, 0x46},
+ {0x00, 0x00, 0x6c, 0xfe, 0x92, 0x92, 0xc6, 0x44},
+ {0x00, 0x0a, 0xfe, 0xfe, 0xca, 0x68, 0x38, 0x18},
+ {0x00, 0x00, 0x9c, 0xbe, 0xa2, 0xa2, 0xe6, 0xe4},
+ {0x00, 0x00, 0x0c, 0x9e, 0x92, 0xd2, 0x7e, 0x3c},
+ {0x00, 0x00, 0xe0, 0xf0, 0x9e, 0x8e, 0xc0, 0xc0},
+ {0x00, 0x00, 0x6c, 0xfe, 0x92, 0x92, 0xfe, 0x6c},
+ {0x00, 0x00, 0x78, 0xfc, 0x96, 0x92, 0xf2, 0x60},
+ {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x66, 0x67, 0x01, 0x00},
+ {0x00, 0x00, 0x00, 0x82, 0xc6, 0x6c, 0x38, 0x10},
+ {0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24},
+ {0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x82, 0x00},
+ {0x00, 0x00, 0x60, 0xf0, 0x9a, 0x8a, 0xc0, 0x40},
+ {0x00, 0x78, 0xf8, 0xba, 0xba, 0x82, 0xfe, 0x7c},
+ {0x00, 0x00, 0x3e, 0x7e, 0xc8, 0xc8, 0x7e, 0x3e},
+ {0x00, 0x6c, 0xfe, 0x92, 0x92, 0xfe, 0xfe, 0x82},
+ {0x00, 0x44, 0xc6, 0x82, 0x82, 0xc6, 0x7c, 0x38},
+ {0x00, 0x38, 0x7c, 0xc6, 0x82, 0xfe, 0xfe, 0x82},
+ {0x00, 0xc6, 0x82, 0xba, 0x92, 0xfe, 0xfe, 0x82},
+ {0x00, 0xc0, 0x80, 0xb8, 0x92, 0xfe, 0xfe, 0x82},
+ {0x00, 0x4e, 0xce, 0x8a, 0x82, 0xc6, 0x7c, 0x38},
+ {0x00, 0x00, 0xfe, 0xfe, 0x10, 0x10, 0xfe, 0xfe},
+ {0x00, 0x00, 0x00, 0x82, 0xfe, 0xfe, 0x82, 0x00},
+ {0x00, 0x80, 0xfc, 0xfe, 0x82, 0x02, 0x0e, 0x0c},
+ {0x00, 0xc6, 0xee, 0x38, 0x10, 0xfe, 0xfe, 0x82},
+ {0x00, 0x0e, 0x06, 0x02, 0x82, 0xfe, 0xfe, 0x82},
+ {0x00, 0xfe, 0xfe, 0x70, 0x38, 0x70, 0xfe, 0xfe},
+ {0x00, 0xfe, 0xfe, 0x18, 0x30, 0x60, 0xfe, 0xfe},
+ {0x00, 0x38, 0x7c, 0xc6, 0x82, 0xc6, 0x7c, 0x38},
+ {0x00, 0x60, 0xf0, 0x90, 0x92, 0xfe, 0xfe, 0x82},
+ {0x00, 0x00, 0x7a, 0xfe, 0x8e, 0x84, 0xfc, 0x78},
+ {0x00, 0x66, 0xfe, 0x98, 0x90, 0xfe, 0xfe, 0x82},
+ {0x00, 0x00, 0x4c, 0xce, 0x9a, 0xb2, 0xf6, 0x64},
+ {0x00, 0x00, 0xc0, 0x82, 0xfe, 0xfe, 0x82, 0xc0},
+ {0x00, 0x00, 0xfe, 0xfe, 0x02, 0x02, 0xfe, 0xfe},
+ {0x00, 0x00, 0xf8, 0xfc, 0x06, 0x06, 0xfc, 0xf8},
+ {0x00, 0xfe, 0xfe, 0x0c, 0x18, 0x0c, 0xfe, 0xfe},
+ {0x00, 0xc2, 0xe6, 0x3c, 0x18, 0x3c, 0xe6, 0xc2},
+ {0x00, 0x00, 0xe0, 0xf2, 0x1e, 0x1e, 0xf2, 0xe0},
+ {0x00, 0xce, 0xe6, 0xb2, 0x9a, 0x8e, 0xc6, 0xe2},
+ {0x00, 0x00, 0x00, 0x82, 0x82, 0xfe, 0xfe, 0x00},
+ {0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80},
+ {0x00, 0x00, 0x00, 0xfe, 0xfe, 0x82, 0x82, 0x00},
+ {0x00, 0x10, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x10},
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ {0x00, 0x00, 0x00, 0x20, 0xe0, 0xc0, 0x00, 0x00},
+ {0x00, 0x02, 0x1e, 0x3c, 0x2a, 0x2a, 0x2e, 0x04},
+ {0x00, 0x0c, 0x1e, 0x12, 0x12, 0xfc, 0xfe, 0x82},
+ {0x00, 0x00, 0x14, 0x36, 0x22, 0x22, 0x3e, 0x1c},
+ {0x00, 0x02, 0xfe, 0xfc, 0x92, 0x12, 0x1e, 0x0c},
+ {0x00, 0x00, 0x18, 0x3a, 0x2a, 0x2a, 0x3e, 0x1c},
+ {0x00, 0x00, 0x40, 0xc0, 0x92, 0xfe, 0x7e, 0x12},
+ {0x00, 0x20, 0x3e, 0x1f, 0x25, 0x25, 0x3d, 0x19},
+ {0x00, 0x1e, 0x3e, 0x20, 0x10, 0xfe, 0xfe, 0x82},
+ {0x00, 0x00, 0x00, 0x02, 0xbe, 0xbe, 0x22, 0x00},
+ {0x00, 0x00, 0xbe, 0xbf, 0x01, 0x01, 0x07, 0x06},
+ {0x00, 0x22, 0x36, 0x1c, 0x08, 0xfe, 0xfe, 0x82},
+ {0x00, 0x00, 0x00, 0x02, 0xfe, 0xfe, 0x82, 0x00},
+ {0x00, 0x1e, 0x3e, 0x38, 0x1c, 0x18, 0x3e, 0x3e},
+ {0x00, 0x00, 0x1e, 0x3e, 0x20, 0x20, 0x3e, 0x3e},
+ {0x00, 0x00, 0x1c, 0x3e, 0x22, 0x22, 0x3e, 0x1c},
+ {0x00, 0x18, 0x3c, 0x24, 0x25, 0x1f, 0x3f, 0x21},
+ {0x00, 0x21, 0x3f, 0x1f, 0x25, 0x24, 0x3c, 0x18},
+ {0x00, 0x18, 0x38, 0x20, 0x32, 0x1e, 0x3e, 0x22},
+ {0x00, 0x00, 0x24, 0x2e, 0x2a, 0x2a, 0x3a, 0x12},
+ {0x00, 0x00, 0x24, 0x22, 0xfe, 0x7c, 0x20, 0x00},
+ {0x00, 0x02, 0x3e, 0x3c, 0x02, 0x02, 0x3e, 0x3c},
+ {0x00, 0x00, 0x38, 0x3c, 0x06, 0x06, 0x3c, 0x38},
+ {0x00, 0x3c, 0x3e, 0x0e, 0x1c, 0x0e, 0x3e, 0x3c},
+ {0x00, 0x22, 0x36, 0x1c, 0x08, 0x1c, 0x36, 0x22},
+ {0x00, 0x00, 0x3e, 0x3f, 0x05, 0x05, 0x3d, 0x39},
+ {0x00, 0x00, 0x26, 0x32, 0x3a, 0x2e, 0x26, 0x32},
+ {0x00, 0x00, 0x82, 0x82, 0xee, 0x7c, 0x10, 0x10},
+ {0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x10, 0x10, 0x7c, 0xee, 0x82, 0x82},
+ {0x00, 0x80, 0xc0, 0x40, 0xc0, 0x80, 0xc0, 0x40},
+ {0x00, 0x0e, 0x1e, 0x32, 0x62, 0x32, 0x1e, 0x0e},
+ {0x00, 0x00, 0x52, 0xdf, 0x8d, 0x89, 0xf9, 0x70},
+ {0x00, 0x02, 0x5e, 0x5e, 0x02, 0x02, 0x5e, 0x5c},
+ {0x00, 0x00, 0x98, 0xba, 0xaa, 0x2a, 0x3e, 0x1c},
+ {0x42, 0xde, 0xbe, 0xaa, 0xaa, 0xae, 0xc4, 0x40},
+ {0x00, 0x02, 0x9e, 0xbe, 0x2a, 0x2a, 0xae, 0x84},
+ {0x00, 0x02, 0x1e, 0x3e, 0x2a, 0xaa, 0xae, 0x84},
+ {0x00, 0x02, 0x1e, 0x3e, 0xea, 0xea, 0x2e, 0x04},
+ {0x00, 0x00, 0x02, 0x27, 0x25, 0x25, 0x3c, 0x18},
+ {0x40, 0xd8, 0xba, 0xaa, 0xaa, 0xbe, 0xdc, 0x40},
+ {0x00, 0x00, 0x98, 0xba, 0x2a, 0x2a, 0xbe, 0x9c},
+ {0x00, 0x00, 0x18, 0x3a, 0x2a, 0xaa, 0xbe, 0x9c},
+ {0x00, 0x00, 0x80, 0x82, 0x3e, 0x3e, 0xa2, 0x80},
+ {0x00, 0x40, 0xc2, 0xbe, 0xbe, 0xa2, 0xc0, 0x40},
+ {0x00, 0x00, 0x00, 0x02, 0x3e, 0xbe, 0xa2, 0x80},
+ {0x00, 0x9e, 0xbe, 0x68, 0x48, 0x68, 0xbe, 0x9e},
+ {0x00, 0x00, 0x0e, 0x1e, 0xd4, 0xd4, 0x1e, 0x0e},
+ {0x00, 0x00, 0xa2, 0xaa, 0xaa, 0x3e, 0x3e, 0x22},
+ {0x2a, 0x2a, 0x3e, 0x3e, 0x2a, 0x2a, 0x2e, 0x04},
+ {0x00, 0x92, 0xfe, 0xfe, 0x90, 0xd0, 0x7e, 0x3e},
+ {0x00, 0x00, 0x4c, 0xde, 0x92, 0x92, 0xde, 0x4c},
+ {0x00, 0x00, 0x4c, 0x5e, 0x12, 0x12, 0x5e, 0x4c},
+ {0x00, 0x00, 0x0c, 0x1e, 0x12, 0x52, 0x5e, 0x4c},
+ {0x00, 0x02, 0x5e, 0xde, 0x82, 0x82, 0xde, 0x5c},
+ {0x00, 0x02, 0x1e, 0x1e, 0x02, 0x42, 0x5e, 0x5c},
+ {0x00, 0x00, 0x5e, 0x5f, 0x05, 0x05, 0x5d, 0x59},
+ {0x80, 0x98, 0x3c, 0x66, 0x66, 0x3c, 0x98, 0x80},
+ {0x00, 0x00, 0xbc, 0xbe, 0x02, 0x02, 0xbe, 0xbc},
+ {0x00, 0x24, 0x24, 0xe7, 0xe7, 0x24, 0x3c, 0x18},
+ {0x00, 0x04, 0x66, 0xc2, 0x92, 0xfe, 0x7e, 0x16},
+ {0x00, 0x00, 0xd4, 0xf4, 0x3f, 0x3f, 0xf4, 0xd4},
+ {0x05, 0x1f, 0x6f, 0xf4, 0x90, 0x90, 0xff, 0xff},
+ {0x40, 0xc0, 0x90, 0xfe, 0x7f, 0x11, 0x03, 0x02},
+ {0x00, 0x02, 0x9e, 0xbe, 0xaa, 0x2a, 0x2e, 0x04},
+ {0x00, 0x00, 0x00, 0x82, 0xbe, 0xbe, 0x22, 0x00},
+ {0x00, 0x00, 0x4c, 0x5e, 0x52, 0x12, 0x1e, 0x0c},
+ {0x00, 0x02, 0x5e, 0x5e, 0x42, 0x02, 0x1e, 0x1c},
+ {0x00, 0x00, 0x0e, 0x5e, 0x50, 0x50, 0x5e, 0x5e},
+ {0x00, 0x00, 0xbe, 0xbe, 0x8c, 0x98, 0xbe, 0xbe},
+ {0x00, 0x14, 0xf4, 0xf4, 0x94, 0xf4, 0x64, 0x00},
+ {0x00, 0x00, 0x64, 0xf4, 0x94, 0xf4, 0x64, 0x00},
+ {0x00, 0x00, 0x04, 0x06, 0xa2, 0xb2, 0x1e, 0x0c},
+ {0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x1c},
+ {0x00, 0x00, 0x1c, 0x1c, 0x10, 0x10, 0x10, 0x10},
+ {0x89, 0xdd, 0x77, 0x33, 0x18, 0x0c, 0xf6, 0xf2},
+ {0x9f, 0xdf, 0x6e, 0x36, 0x18, 0x0c, 0xf6, 0xf2},
+ {0x00, 0x00, 0x00, 0xde, 0xde, 0x00, 0x00, 0x00},
+ {0x44, 0x6c, 0x38, 0x10, 0x44, 0x6c, 0x38, 0x10},
+ {0x10, 0x38, 0x6c, 0x44, 0x10, 0x38, 0x6c, 0x44},
+ {0x00, 0xaa, 0x00, 0x55, 0x00, 0xaa, 0x00, 0x55},
+ {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55},
+ {0xee, 0xff, 0x55, 0xbb, 0xee, 0x55, 0xff, 0xbb},
+ {0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08},
+ {0x00, 0x00, 0x00, 0xff, 0xff, 0x28, 0x28, 0x28},
+ {0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x08, 0x08},
+ {0x00, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x08},
+ {0x00, 0x00, 0x00, 0x3f, 0x3f, 0x28, 0x28, 0x28},
+ {0x00, 0xff, 0xff, 0x00, 0xef, 0xef, 0x28, 0x28},
+ {0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00},
+ {0x00, 0x3f, 0x3f, 0x20, 0x2f, 0x2f, 0x28, 0x28},
+ {0x00, 0xf8, 0xf8, 0x08, 0xe8, 0xe8, 0x28, 0x28},
+ {0x00, 0xf8, 0xf8, 0x08, 0xf8, 0xf8, 0x08, 0x08},
+ {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x28, 0x28, 0x28},
+ {0x00, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x08, 0x08},
+ {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00},
+ {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x08, 0x08, 0x08},
+ {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x08, 0x08},
+ {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00},
+ {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08},
+ {0x08, 0x08, 0x08, 0xff, 0xff, 0x08, 0x08, 0x08},
+ {0x28, 0x28, 0x28, 0xff, 0xff, 0x00, 0x00, 0x00},
+ {0x08, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00},
+ {0x28, 0xe8, 0xe8, 0x08, 0xf8, 0xf8, 0x00, 0x00},
+ {0x28, 0x2f, 0x2f, 0x20, 0x3f, 0x3f, 0x00, 0x00},
+ {0x28, 0xe8, 0xe8, 0x08, 0xe8, 0xe8, 0x28, 0x28},
+ {0x28, 0x2f, 0x2f, 0x20, 0x2f, 0x2f, 0x28, 0x28},
+ {0x28, 0xef, 0xef, 0x00, 0xff, 0xff, 0x00, 0x00},
+ {0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28},
+ {0x28, 0xef, 0xef, 0x00, 0xef, 0xef, 0x28, 0x28},
+ {0x28, 0x28, 0x28, 0xe8, 0xe8, 0x28, 0x28, 0x28},
+ {0x08, 0xf8, 0xf8, 0x08, 0xf8, 0xf8, 0x08, 0x08},
+ {0x28, 0x28, 0x28, 0x2f, 0x2f, 0x28, 0x28, 0x28},
+ {0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x08},
+ {0x08, 0xf8, 0xf8, 0x08, 0xf8, 0xf8, 0x00, 0x00},
+ {0x28, 0x28, 0x28, 0xf8, 0xf8, 0x00, 0x00, 0x00},
+ {0x28, 0x28, 0x28, 0x3f, 0x3f, 0x00, 0x00, 0x00},
+ {0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x00, 0x00},
+ {0x08, 0xff, 0xff, 0x08, 0xff, 0xff, 0x08, 0x08},
+ {0x28, 0x28, 0x28, 0xff, 0xff, 0x28, 0x28, 0x28},
+ {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x08, 0x08, 0x08},
+ {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00},
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f},
+ {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
+ {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
+ {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0},
+ {0x00, 0x22, 0x36, 0x1c, 0x36, 0x22, 0x3e, 0x1c},
+ {0x00, 0x00, 0x28, 0x7c, 0x54, 0x54, 0x7f, 0x3f},
+ {0x00, 0x00, 0x60, 0x60, 0x40, 0x40, 0x7e, 0x7e},
+ {0x00, 0x40, 0x7e, 0x7e, 0x40, 0x7e, 0x7e, 0x40},
+ {0x00, 0x00, 0xc6, 0xc6, 0x92, 0xba, 0xee, 0xc6},
+ {0x00, 0x20, 0x20, 0x3c, 0x3e, 0x22, 0x3e, 0x1c},
+ {0x00, 0x78, 0x7c, 0x04, 0x04, 0x7e, 0x7f, 0x01},
+ {0x00, 0x40, 0x60, 0x3e, 0x7e, 0x40, 0x60, 0x20},
+ {0x00, 0x00, 0x99, 0xbd, 0xe7, 0xe7, 0xbd, 0x99},
+ {0x00, 0x38, 0x7c, 0xd6, 0x92, 0xd6, 0x7c, 0x38},
+ {0x00, 0x32, 0x7e, 0xce, 0x80, 0xce, 0x7e, 0x32},
+ {0x00, 0x00, 0x9c, 0xbe, 0xf2, 0x52, 0x1e, 0x0c},
+ {0x18, 0x3c, 0x24, 0x3c, 0x3c, 0x24, 0x3c, 0x18},
+ {0x18, 0xbc, 0xe4, 0x7c, 0x3c, 0x26, 0x3f, 0x19},
+ {0x00, 0x00, 0x00, 0x92, 0x92, 0xd6, 0x7c, 0x38},
+ {0x00, 0x00, 0x7e, 0xfe, 0x80, 0x80, 0xfe, 0x7e},
+ {0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54},
+ {0x00, 0x00, 0x22, 0x22, 0xfa, 0xfa, 0x22, 0x22},
+ {0x00, 0x00, 0x02, 0x22, 0x72, 0xda, 0x8a, 0x02},
+ {0x00, 0x00, 0x02, 0x8a, 0xda, 0x72, 0x22, 0x02},
+ {0x60, 0xe0, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x07, 0x06},
+ {0x00, 0x00, 0x10, 0x10, 0xd6, 0xd6, 0x10, 0x10},
+ {0x00, 0x48, 0x6c, 0x24, 0x6c, 0x48, 0x6c, 0x24},
+ {0x00, 0x00, 0x60, 0xf0, 0x90, 0xf0, 0x60, 0x00},
+ {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00},
+ {0x80, 0x80, 0xff, 0xff, 0x03, 0x0e, 0x0c, 0x08},
+ {0x00, 0x00, 0x78, 0xf8, 0x80, 0xf8, 0xf8, 0x00},
+ {0x00, 0x00, 0x00, 0x48, 0xe8, 0xb8, 0x98, 0x00},
+ {0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+ }
+};
+
+BOOLEAN
+CSynthesizer::
+Initialize()
+/*++
+
+Routine Description:
+
+ Class initialization.
+
+ Set the buffer the synthesizer generates images to.
+ Override to do any additional processing you think is needed.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE - success.
+
+--*/
+{
+ PAGED_CODE();
+
+ // Capture the working palette.
+ // Recast it to a point to an array of primaries.
+ if( !(m_Colors = GetPalette()) )
+ {
+ return FALSE;
+ }
+
+ // Clear the globals. This occurs redundantly, but hey ...
+ // ... test output doesn't make sense if we don't do this.
+ m_RelPts=0;
+ m_QpcTime=0;
+ m_Frame=0;
+
+ //
+ // Allocate a scratch buffer for the synthesizer.
+ //
+ NT_ASSERT(m_Length);
+ if( !m_Length )
+ {
+ return FALSE;
+ }
+
+ m_Buffer = new (PagedPool) UCHAR[m_Length];
+ NT_ASSERT(m_Buffer);
+ if( !m_Buffer )
+ {
+ return FALSE;
+ }
+
+ //
+ // Allocate a scratch buffer for the Gradient.
+ //
+ m_GradientBmp = new (PagedPool) CKsRgbQuad[m_Width * MAX_COLOR];
+ NT_ASSERT(m_GradientBmp);
+ if( !m_GradientBmp )
+ {
+ SAFE_DELETE_ARRAY( m_Buffer );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+LONGLONG
+ConvertPerfTime(
+ _In_ LONGLONG Freq,
+ _In_ LONGLONG Time
+)
+{
+ PAGED_CODE();
+
+ LARGE_INTEGER tL ;
+ tL.QuadPart = Time;
+ return KSCONVERT_PERFORMANCE_TIME( Freq, tL );
+}
+
+void
+CSynthesizer::
+Destroy()
+/*++
+
+Routine Description:
+
+ Clean up from initialize.
+
+ Note: A good place to generate synthesis stats.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ void.
+
+--*/
+{
+ PAGED_CODE();
+
+ SAFE_DELETE_ARRAY( m_Buffer );
+ SAFE_DELETE_ARRAY( m_GradientBmp );
+
+ // Report rendering times.
+ DBG_TRACE( "Synthesis Time - Total = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_SynthesisTime ) );
+ DBG_TRACE( " Count = %d", m_SynthesisCount );
+ DBG_TRACE( " Avg = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_SynthesisCount ? m_SynthesisTime / m_SynthesisCount : 0 ) );
+ DBG_TRACE( " Commit Time - Total = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_CommitTime ) );
+ DBG_TRACE( " Count = %d", m_CommitCount );
+ DBG_TRACE( " Avg = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_CommitCount ? m_CommitTime / m_CommitCount : 0 ) );
+}
+
+NTSTATUS
+CSynthesizer::
+SynthesizeBars()
+/*++
+
+Routine Description:
+
+ Synthesize EIA-189-A standard color bars onto the Image. The image
+ in question is the current synthesis buffer.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ success / failure
+
+--*/
+{
+ PAGED_CODE();
+
+ if( !m_Buffer )
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ const COLOR *CurColor = m_ColorBars;
+ ULONG ColorCount = SIZEOF_ARRAY (m_ColorBars);
+
+ //
+ // Set the default cursor...
+ //
+ GetImageLocation (0, 0);
+
+ //
+ // Synthesize a single line.
+ //
+ PUCHAR ImageStart = m_Cursor;
+ for (ULONG x = 0; x < m_Width; x++)
+ {
+ PutPixel (m_ColorBars [((x * ColorCount) / m_Width)]);
+ }
+
+ PUCHAR ImageEnd = m_Cursor;
+
+ //
+ // Copy the synthesized line to all subsequent lines.
+ //
+ for (ULONG line = 0; line < m_Height; line++)
+ {
+ GetImageLocation (0, line);
+
+ RtlCopyMemory (
+ m_Cursor,
+ ImageStart,
+ ImageEnd - ImageStart
+ );
+ }
+
+ // Paint the top left and top right registrations boxes.
+ GetImageLocation(0,0);
+
+ ImageStart = m_Cursor;
+ for(ULONG x =0; x < m_Width; x++)
+ {
+ if(x < (m_Height/16))
+ {
+ PutPixel(g_TopLeft);
+ }
+ else if(x > (m_Width - (m_Height / 16)))
+ {
+ PutPixel(g_TopRight);
+ }
+ else
+ {
+ PutPixel (m_ColorBars [((x * ColorCount) / m_Width)]);
+ }
+ }
+
+ ImageEnd = m_Cursor;
+
+ for (ULONG line = 0; line < m_Height/16; line++)
+ {
+ GetImageLocation (0, line);
+
+ RtlCopyMemory (
+ m_Cursor,
+ ImageStart,
+ ImageEnd - ImageStart
+ );
+ }
+
+ // Paint the bottom left and bottom right registrations boxes.
+ GetImageLocation(0, (15*m_Height) / 16);
+ ImageStart = m_Cursor;
+ for(ULONG x =0; x < m_Width; x++)
+ {
+ if(x < (m_Height/16))
+ {
+ PutPixel(g_BotLeft);
+ }
+ else if(x > (m_Width - (m_Height / 16)))
+ {
+ PutPixel(g_BotRight);
+ }
+ else
+ {
+ PutPixel (m_ColorBars [((x * ColorCount) / m_Width)]);
+ }
+ }
+
+ ImageEnd = m_Cursor;
+
+ for (ULONG line = 0; line < m_Height/16; line++)
+ {
+ GetImageLocation (0, line+(15*m_Height) / 16);
+
+ RtlCopyMemory (
+ m_Cursor,
+ ImageStart,
+ ImageEnd - ImageStart
+ );
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void
+CSynthesizer::
+EncodeNumber(
+ _In_ ULONG LocY,
+ _In_ UINT32 Number,
+ _In_ COLOR LowColor,
+ _In_ COLOR HighColor
+)
+/*
+Routine Description:
+
+ Overlays an encoded number over the synthesized image. The image buffer
+ used is the set synthesis buffer. The pattern is scaled to fit the image.
+
+Arguments:
+
+ LocY -
+ The row on the image to begin the overlay. This must
+ be inside the image.
+
+ Number -
+ The number to encode
+
+ LowColor -
+ The color to represent 0 (a clear bit)
+
+ HighColor -
+ The color to represent 1 (a set bit)
+
+Return Value:
+
+ void
+
+*/
+{
+ PAGED_CODE();
+
+ if( !m_Buffer )
+ {
+ return;
+ }
+
+ NT_ASSERT(LocY <= m_Height);
+
+ GetImageLocation(0, LocY);
+ UINT32 mask = 0x1;
+
+ PUCHAR ImageStart = m_Cursor;
+ for(ULONG i = 0; i < 32; i++)
+ {
+ for(ULONG j = 0; j < m_Width/32; j++)
+ {
+ if(Number & mask)
+ {
+ PutPixel(HighColor);
+ }
+ else
+ {
+ PutPixel(LowColor);
+ }
+ }
+ mask = mask << 1;
+ }
+ PUCHAR ImageEnd = m_Cursor;
+
+ //
+ // Copy the synthesized line to all subsequent lines.
+ //
+ for (ULONG line = 1; line < m_Height/16; line++)
+ {
+ RtlCopyMemory (
+ GetImageLocation (0, line + LocY),
+ ImageStart,
+ ImageEnd - ImageStart
+ );
+ }
+}
+
+void
+CSynthesizer::
+OverlayText (
+ _In_ ULONG LocX,
+ _In_ ULONG LocY,
+ _In_ ULONG Scaling,
+ _In_ LPSTR Text,
+ _In_ COLOR BgColor,
+ _In_ COLOR FgColor
+)
+/*++
+
+Routine Description:
+
+ Overlay text onto the synthesized image. Clip to fit the image
+ if the overlay does not fit. The image buffer used is the set
+ synthesis buffer.
+
+Arguments:
+
+ LocX -
+ The X location on the image to begin the overlay. This MUST
+ be inside the image or no text will be rendered.
+ POSITION_CENTER may be used to indicate horizontal centering.
+
+ LocY -
+ The Y location on the image to begin the overlay. This MUST
+ be inside the image or no text will be rendered.
+ POSITION_CENTER may be used to indicate vertical centering.
+
+ Scaling -
+ Normally, the overlay is done in an 8x8 font. A scaling of
+ 2 indicates 16x16, 3 indicates 24x24 and so forth.
+
+ Text -
+ A null terminated character string containing the information to
+ overlay
+
+ BgColor -
+ The background color of the overlay window. For transparency,
+ indicate TRANSPARENT here.
+
+ FgColor -
+ The foreground color for the text overlay.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ // Validate internal state.
+ if( !m_Buffer )
+ {
+ return;
+ }
+
+ NT_ASSERT( (LocX <= m_Width || LocX == POSITION_CENTER) &&
+ (LocY <= m_Height || LocY == POSITION_CENTER) &&
+ Text !=nullptr &&
+ (BgColor < MAX_COLOR || BgColor == TRANSPARENT) &&
+ (FgColor < MAX_COLOR || FgColor == TRANSPARENT)
+ );
+
+ // Validate parameters.
+ if( !( (LocX <= m_Width || LocX == POSITION_CENTER) &&
+ (LocY <= m_Height || LocY == POSITION_CENTER) &&
+ Text !=nullptr &&
+ (BgColor < MAX_COLOR || BgColor == TRANSPARENT) &&
+ (FgColor < MAX_COLOR || FgColor == TRANSPARENT) ) )
+ {
+ return;
+ }
+
+ size_t StrLen = 0;
+ PUCHAR CurChar;
+
+ //
+ // Determine the character length of the string.
+ //
+ if( !NT_SUCCESS( RtlStringCchLengthA( Text, m_Width, &StrLen ) ) )
+ {
+ // Invalid parameter.
+ return;
+ }
+
+ //
+ // Determine the physical size of the string plus border. There is
+ // a definable NO_CHARACTER_SEPARATION. If this is defined, there will
+ // be no added space between font characters. Otherwise, one empty pixel
+ // column is added between characters.
+ //
+#ifndef NO_CHARACTER_SEPARATION
+ ULONG LenX = (ULONG) ((StrLen * (((size_t)Scaling) << 3)) + 1 + StrLen);
+#else // NO_CHARACTER_SEPARATION
+ ULONG LenX = (ULONG) ((StrLen * (((size_t_)Scaling) << 3)) + 2);
+#endif // NO_CHARACTER_SEPARATION
+
+ ULONG LenY = 2 + (Scaling << 3);
+
+ //
+ // Adjust for center overlays.
+ //
+ // NOTE: If the overlay doesn't fit into the synthesis buffer, this
+ // merely left aligns the overlay and clips off the right side.
+ //
+ if (LocX == POSITION_CENTER)
+ {
+ //LocX = min( 0, ((LONG)m_Width - (LONG)LenX) >> 1);
+ if (LenX >= m_Width)
+ {
+ LocX = 0;
+ }
+ else
+ {
+ LocX = (m_Width - LenX) >> 1;
+ }
+ }
+
+ if (LocY == POSITION_CENTER)
+ {
+ //LocY = min( 0, ((LONG)m_Width - (LONG)LenY) >> 1);
+ if (LenY >= m_Height)
+ {
+ LocY = 0;
+ }
+ else
+ {
+ LocY = (m_Height - LenY) >> 1;
+ }
+ }
+
+ //
+ // Determine the amount of space available on the synthesis buffer.
+ // We will clip anything that finds itself outside the synthesis buffer.
+ //
+ ULONG SpaceX = m_Width - LocX;
+ ULONG SpaceY = m_Height - LocY;
+
+ //
+ // Set the default cursor position.
+ //
+ GetImageLocation (LocX, LocY);
+
+ //
+ // Overlay a background color row.
+ //
+ if( SpaceY )
+ {
+ if( BgColor != TRANSPARENT )
+ {
+ for (ULONG x = 0; x < LenX && x < SpaceX; x++)
+ {
+ PutPixel (BgColor);
+ }
+ }
+ SpaceY--;
+ }
+ LocY++;
+
+ //
+ // Loop across each row of the image.
+ //
+ for (ULONG row = 0; row < 8 && SpaceY; row++)
+ {
+ //
+ // Generate a line.
+ //
+ GetImageLocation (LocX, LocY++);
+
+ PUCHAR ImageStart = m_Cursor;
+
+ ULONG CurSpaceX = SpaceX;
+ if (CurSpaceX)
+ {
+ PutPixel (BgColor);
+ CurSpaceX--;
+ }
+
+ //
+ // Generate the row'th row of the overlay.
+ //
+ CurChar = (PUCHAR) Text;
+ while( *CurChar )
+ {
+ UCHAR CharBase = m_FontData [m_Rotation==AcpiPldRotation90][*CurChar++][row];
+ for (ULONG mask = 0x80; mask && CurSpaceX; mask >>= 1)
+ {
+ for (ULONG scale = 0; scale < Scaling && CurSpaceX; scale++)
+ {
+ if (CharBase & mask)
+ {
+ PutPixel (FgColor);
+ }
+ else
+ {
+ PutPixel (BgColor);
+ }
+ CurSpaceX--;
+ }
+ }
+
+ //
+ // Separate each character by one space. Account for the border
+ // space at the end by placing the separator after the last
+ // character also.
+ //
+#ifndef NO_CHARACTER_SEPARATION
+ if (CurSpaceX)
+ {
+ PutPixel (BgColor);
+ CurSpaceX--;
+ }
+#endif // NO_CHARACTER_SEPARATION
+ }
+
+ //
+ // If there is no separation character defined, account for the
+ // border.
+ //
+#ifdef NO_CHARACTER_SEPARATION
+ if (CurSpaceX)
+ {
+ PutPixel (BgColor);
+ CurSpaceX--;
+ }
+#endif // NO_CHARACTER_SEPARATION
+
+
+ PUCHAR ImageEnd = m_Cursor;
+ //
+ // Copy the line downward scale times.
+ //
+ for (ULONG scale = 1; scale < Scaling && SpaceY; scale++)
+ {
+ GetImageLocation (LocX, LocY++);
+ RtlCopyMemory (m_Cursor, ImageStart, ImageEnd - ImageStart);
+ SpaceY--;
+ }
+ }
+
+ //
+ // Add the bottom section of the overlay.
+ //
+ GetImageLocation (LocX, LocY);
+ if (BgColor != TRANSPARENT && SpaceY)
+ {
+ for (ULONG x = 0; x < LenX && x < SpaceX; x++)
+ {
+ PutPixel (BgColor);
+ }
+ }
+}
+
+void
+CSynthesizer::ApplyGradient(
+ _In_ ULONG LocY,
+ _In_ COLOR Gradient
+)
+/*++
+
+Routine Description:
+
+ Synthesize a horizontal gradient bar from a given color
+
+Arguments:
+
+ LocY -
+ row
+
+ Gradient -
+ A starting color
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ if( !m_Buffer )
+ {
+ return;
+ }
+
+ NT_ASSERT(LocY <= m_Height);
+
+ PUCHAR Image = GetImageLocation(0, LocY);
+ PUCHAR RowBmp = reinterpret_cast<PUCHAR>(&m_GradientBmp[Gradient*m_Width]);
+ ULONG Stride = m_Width * sizeof(CKsRgbQuad);
+
+ //
+ // Copy the synthesized line to all lines.
+ //
+ for (ULONG line = 0; line < m_Height/16; line++)
+ {
+ RtlCopyMemory (
+ Image,
+ RowBmp,
+ Stride
+ );
+ Image += Stride;
+ }
+}
+
+//
+// Synthesize
+//
+// Fill the image buffer with some base image. All h/w simulations will
+// call this function to generate a base image - even for jpeg.
+//
+NTSTATUS
+CSynthesizer::
+Synthesize()
+/*++
+
+Routine Description:
+
+ Fill the image buffer with some base image. All h/w simulations will
+ call this function to generate a base image.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+ PAGED_CODE();
+
+ if( !m_Buffer )
+ {
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ //
+ // Generate a "time stamp" just to overlay it onto the capture image.
+ // It makes it more exciting than bars that do nothing.
+ //
+ SynthesizeBars();
+
+ ApplyGradient( (m_Height)/16, RED);
+ ApplyGradient( (2*m_Height)/16, GREEN);
+ ApplyGradient( (3*m_Height)/16, BLUE);
+ ApplyGradient( (4*m_Height)/16, WHITE);
+
+ EncodeNumber((5*m_Height)/16, (UINT32)m_Frame, BLACK, WHITE);
+ EncodeNumber((6*m_Height)/16, (UINT32)(m_QpcTime), BLACK, WHITE);
+
+ CHAR Text [256];
+ RtlStringCbPrintfA(Text, sizeof(Text), "Frame: %ld", m_Frame);
+
+ //
+ // Overlay the frame # onto the scratch space image.
+ //
+ OverlayText (
+ POSITION_CENTER,
+ (m_Height - 28),
+ 1,
+ Text,
+ BLACK,
+ TEXT_COLOR
+ );
+
+ //
+ // Add a description of the frame type/width/height.
+ //
+ RtlStringCbPrintfA(Text, sizeof(Text), "%s (%dx%d)", m_FormatName, m_Width, m_Height);
+ OverlayText (
+ 0,
+ (m_Height - 28),
+ 1,
+ Text,
+ TRANSPARENT,
+ TEXT_COLOR
+ );
+
+ //
+ // Add a description of the mounting.
+ //
+ RtlStringCbPrintfA(Text, sizeof(Text), "%d\370 Mounting", DbgRotation2Degrees(m_Rotation));
+ size_t len = 0;
+ RtlStringCchLengthA(Text, sizeof(Text), &len);
+ OverlayText (
+ (m_Width - (((ULONG)len*8))), // right-adjust text.
+ (m_Height - 28),
+ 1,
+ Text,
+ TRANSPARENT,
+ TEXT_COLOR
+ );
+
+ return STATUS_SUCCESS;
+}
+
+void
+CSynthesizer::PutPixel (
+ COLOR Color
+)
+/*++
+
+Routine Description:
+
+ Place a pixel at the default cursor location. The cursor location
+ must be set via GetImageLocation(x, y).
+
+Arguments:
+
+ Color -
+ The pixel color to render
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ PKS_RGBQUAD &pPixel = (PKS_RGBQUAD &) m_Cursor;
+
+ if (Color != TRANSPARENT)
+ {
+ *pPixel = CKsRgbQuad( m_Colors[Color][2], m_Colors[Color][1], m_Colors[Color][0] );
+ }
+
+ // Next pixel
+ pPixel++;
+}
+
+//
+// PutPixel():
+//
+// Place a pixel at the default cursor location. The cursor location
+// must be set via GetImageLocation(x, y).
+//
+void
+CSynthesizer::PutPixel (
+ UCHAR colorR,
+ UCHAR colorB,
+ UCHAR colorG
+)
+/*++
+
+Routine Description:
+
+ Place a pixel at the default cursor location. The cursor location
+ must be set via GetImageLocation(x, y).
+
+ TODO: Remove. This function appears to be dead code.
+
+Arguments:
+
+ colorR -
+ The first color primary of the pixel.
+
+ colorB -
+ The third color primary of the pixel.
+
+ colorG -
+ The second color primary of the pixel.
+
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ PKS_RGBQUAD &pPixel = (PKS_RGBQUAD &) m_Cursor;
+
+ *pPixel++ = CKsRgbQuad( colorR, colorG, colorB );
+}
+
+
+//
+// Synthesize
+//
+// Fill the image buffer with some base image. All h/w simulations will
+// call this function to generate a base image - even for jpeg.
+//
+NTSTATUS
+CSynthesizer::
+DoSynthesize()
+{
+ PAGED_CODE();
+
+ LARGE_INTEGER StartTime = {0};
+ LARGE_INTEGER EndTime = {0};
+
+ StartTime = KeQueryPerformanceCounter(NULL);
+
+ NTSTATUS Status = Synthesize();
+
+ m_SynthesisTime += KeQueryPerformanceCounter(NULL).QuadPart - StartTime.QuadPart;
+ m_SynthesisCount++;
+
+ return Status;
+}
+
+//
+// Commit
+//
+// Copy (and reformat, if necessary) pixels from the internal scratch
+// buffer. If the output format decimates chrominance, do it here.
+//
+_Success_(return > 0)
+ULONG
+CSynthesizer::
+DoCommit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+)
+{
+ PAGED_CODE();
+
+ LARGE_INTEGER StartTime = KeQueryPerformanceCounter(NULL);
+
+ ULONG n = Commit( Buffer, Size, Stride );
+
+ m_CommitTime += KeQueryPerformanceCounter(NULL).QuadPart - StartTime.QuadPart;
+ m_CommitCount++;
+
+ return n;
+}
+
+//
+// DoCommit
+//
+// Note: The stride needs to be a function of the bits per pixel of the
+// OUTPUT format - not the format we store it in. The class ctor
+// must initialize m_OutputStride to a default stride value.
+//
+_Success_(return > 0)
+ULONG
+CSynthesizer::
+DoCommit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size
+)
+{
+ PAGED_CODE();
+
+ LARGE_INTEGER StartTime = KeQueryPerformanceCounter(NULL);
+
+ ULONG n = Commit( Buffer, Size );
+
+ m_CommitTime += KeQueryPerformanceCounter(NULL).QuadPart - StartTime.QuadPart;
+ m_CommitCount++;
+
+ return n;
+}
+
+#define CLEAR_HISTOGRAM( H ) \
+ if( H ) \
+ { \
+ RtlZeroMemory( H, 256*sizeof(*H) ); \
+ }
+
+#define BUMP_HISTOGRAM_PRIMARY( H, C ) \
+ if( H ) \
+ { \
+ H[C]++; \
+ }
+
+//
+// Histogram
+//
+// Fill an array with histogram data.
+//
+void
+CSynthesizer::
+Histogram(
+ _Out_writes_opt_(256)
+ PULONG HistogramP0, // rgbRed
+ _Out_writes_opt_(256)
+ PULONG HistogramP1, // rgbGreen
+ _Out_writes_opt_(256)
+ PULONG HistogramP2 // rgbBlue
+)
+/*++
+
+Routine Description:
+
+ Fill array(s) with histogram data.
+
+Arguments:
+
+ HistogramP0 -
+ Stats on the first primary.
+
+ HistogramP1 -
+ Stats on the second primary.
+
+ HistogramP2 -
+ Stats on the third primary.
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ CLEAR_HISTOGRAM( HistogramP0 );
+ CLEAR_HISTOGRAM( HistogramP1 );
+ CLEAR_HISTOGRAM( HistogramP2 );
+
+ ULONG row, col;
+
+ for( row=0; row<m_Height; row++ )
+ {
+ PKS_RGBQUAD pPixel = (PKS_RGBQUAD) GetImageLocation(0, row);
+
+ for( col=0; col<m_Width; col++ )
+ {
+ BUMP_HISTOGRAM_PRIMARY( HistogramP0, pPixel->rgbRed );
+ BUMP_HISTOGRAM_PRIMARY( HistogramP1, pPixel->rgbGreen );
+ BUMP_HISTOGRAM_PRIMARY( HistogramP2, pPixel->rgbBlue );
+ }
+ }
+}
diff --git a/AVStream/avscamera/sys/Synthesizer.h b/AVStream/avscamera/sys/Synthesizer.h
new file mode 100644
index 00000000..8bf730ac
--- /dev/null
+++ b/AVStream/avscamera/sys/Synthesizer.h
@@ -0,0 +1,521 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ Synthesizer.h
+
+ Abstract:
+
+ This file contains the definition of CSynthesizer.
+
+ The base image synthesis and overlay class. These classes provide
+ image synthesis (pixel, color-bar, etc...) onto buffers of various
+ formats.
+
+ Internally, all CSynthesizer objects represent a pixel as a 32 bit
+ quantity with 8 bits per sample. The base CSynthesizer implements
+ all rendering functionality with this assumption in mind. It
+ simplifies rendering substantially and means we do not need to re-
+ implement rendering functions for each format.
+
+ Most end formats can be synthesized from this uncompressed format
+ with overhead that is slightly worse than a copy. Color spaces are
+ handled by using a rendering palette that is unique for each.
+
+ History:
+
+ created 04/14/2014
+
+**************************************************************************/
+
+#pragma once
+
+//
+// COLOR:
+//
+// Pixel color for placement onto the synthesis buffer.
+//
+typedef enum
+{
+
+ BLACK = 0,
+ WHITE,
+ YELLOW,
+ CYAN,
+ GREEN,
+ MAGENTA,
+ RED,
+ BLUE,
+ GREY,
+
+ TEXT_COLOR, // Used to offset text
+
+ MAX_COLOR,
+ TRANSPARENT,
+
+} COLOR;
+
+#define CHANNEL_YCrCb ( MF_HISTOGRAM_CHANNEL_Y | MF_HISTOGRAM_CHANNEL_Cr | MF_HISTOGRAM_CHANNEL_Cb )
+#define CHANNEL_RGB ( MF_HISTOGRAM_CHANNEL_R | MF_HISTOGRAM_CHANNEL_G | MF_HISTOGRAM_CHANNEL_B )
+#define CHANNEL_NONE ( 0 )
+
+//
+// POSITION_CENTER:
+//
+// Only useful for text overlay. This can be substituted for LocX or LocY
+// in order to center the text screen on the synthesis buffer.
+//
+#define POSITION_CENTER ((ULONG)-1)
+
+//
+// Initializer class for a KS_RGBQUAD
+//
+class CKsRgbQuad : public KS_RGBQUAD
+{
+public:
+ // Initializer ctor
+ CKsRgbQuad(
+ BYTE r=0,
+ BYTE g=0,
+ BYTE b=0 )
+ {
+ rgbBlue = b;
+ rgbGreen = g;
+ rgbRed = r;
+ rgbReserved = 0;
+ }
+};
+
+/*************************************************
+
+ CSynthesizer
+
+ This class synthesizes images in various formats for output from the
+ capture filter. It is capable of performing various text overlays onto
+ the image surface.
+
+ The base synthesizer is essentially the XRGB Synthesizer. For YUV, we
+ repurpose the color primaries and provide a different definition for the
+ color pallette. A call to CSynthesizer::Commit(buffer) will reformat the
+ internal representation and down-sample the color primaries, as necessary
+ into the supplied buffer.
+
+*************************************************/
+
+typedef
+UCHAR UCHAR4[4];
+
+class CSynthesizer :
+ public CNonCopyable
+{
+protected:
+
+ static
+ const UCHAR m_FontData [2][256][8];
+ static
+ const COLOR m_ColorBars[8];
+
+ // These values are used by Synthesize() for display purposes. They are
+ // static so that setting the values on the preview pin affects all pins.
+ //
+ // TODO: Change to references to a shared object. Use of static values
+ // could cause confusion if two (or more) cameras are in use at
+ // the same time.
+ static
+ LONGLONG m_RelPts;
+ static
+ LONGLONG m_QpcTime;
+ static
+ ULONG m_Frame;
+
+ // This value is used to fudge a rotated image.
+ enum
+ AcpiPldRotation
+ m_Rotation;
+
+ //
+ // The width and height the synthesizer is set to.
+ //
+ ULONG m_Width;
+ ULONG m_Height;
+
+ //
+ // The synthesis buffer:
+ //
+ // This buffer points to an array of KS_RGBQUAD. Internally we synthesize
+ // images in an uncompressed format, because it is at least as fast to
+ // composite an image in such a format and convert to the target compressed
+ // format in a final pass over the image.
+ //
+ // An uncompressed format also has less loss of fidelity. For instance,
+ // NV12 only contains 1 chroma sample per macro-pixel (2x2). Once this
+ // macro pixel is rendered, compositing additional color information
+ // into it results in a loss of color precision / fidelity.
+ //
+ PUCHAR m_Buffer; // pointer to pixel data
+ ULONG m_Length; // size of the buffer in bytes
+ LONG m_SynthesisStride; // size of scan line in bytes
+
+ //
+ // The assumed stride of our output format. Currently used by YUY2 and
+ // all image captures, except NV12. This value should be initialized by
+ // the derived classes.
+ //
+ LONG m_OutputStride;
+
+ // Bitmap with a gradient applied for each color in the color pallet.
+ CKsRgbQuad *m_GradientBmp;
+
+ //
+ // The default cursor. This is a pointer into the synthesis buffer where
+ // a non specific PutPixel will be placed.
+ //
+ PUCHAR m_Cursor;
+
+ //
+ // A printable name identifying this format.
+ //
+ PCCHAR m_FormatName;
+
+ //
+ // A color palette for this colorspace.
+ //
+ // Specifying a unique color palette is a cheap method for switching
+ // between RGB and YUV color spaces. A derived class is free to assign
+ // this to any table it chooses. It can be used to either change the
+ // colors used for rendering, or it can be used to support a new (or
+ // slightly different) color space.
+ //
+ const UCHAR4 *m_Colors;
+
+ //
+ // A bitset specifying the color primaries used by this format.
+ // (Used by Histogram.)
+ //
+ ULONG m_ChannelMask;
+
+ //
+ // Debugging values
+ //
+ LARGE_INTEGER m_Frequency;
+ LONGLONG m_SynthesisTime;
+ ULONG m_SynthesisCount;
+ LONGLONG m_CommitTime;
+ ULONG m_CommitCount;
+
+public:
+
+ //
+ // DEFAULT CONSTRUCTOR
+ //
+ CSynthesizer(
+ PCCHAR Name="[Unknown]",
+ ULONG ChannelMask=0,
+ ULONG Width=0,
+ ULONG Height=0
+ )
+ : m_Width(Width)
+ , m_Height(Height)
+ , m_Buffer(nullptr)
+ , m_Cursor(nullptr)
+ , m_GradientBmp(nullptr)
+ , m_SynthesisStride(m_Width * sizeof(KS_RGBQUAD))
+ , m_OutputStride(0)
+ , m_FormatName(Name)
+ , m_ChannelMask(ChannelMask)
+ , m_SynthesisCount(0)
+ , m_SynthesisTime(0)
+ , m_CommitCount(0)
+ , m_CommitTime(0)
+ , m_Rotation(AcpiPldRotation0)
+ {
+ m_Length = Height * m_SynthesisStride;
+ KeQueryPerformanceCounter(&m_Frequency);
+ }
+
+ //
+ // DESTRUCTOR:
+ //
+ virtual
+ ~CSynthesizer()
+ {}
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at the default cursor location. The cursor location
+ // must be set via GetImageLocation(x, y).
+ //
+ virtual
+ void
+ PutPixel (
+ COLOR Color
+ );
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at the default cursor location. The cursor location
+ // must be set via GetImageLocation(x, y).
+ //
+ virtual
+ void
+ PutPixel (
+ UCHAR colorR,
+ UCHAR colorB,
+ UCHAR colorG
+ );
+
+ //
+ // Create a horizontal color bar that slowly fades from the specified
+ // color to black.
+ //
+ // Note: To generalize, this function could specify the height of the
+ // color bar instead of inferring it.
+ //
+ void
+ ApplyGradient(
+ _In_ ULONG LocY,
+ _In_ COLOR Gradient
+ );
+
+
+ //
+ // SetImageSize():
+ //
+ // Set the image size of the synthesis buffer.
+ //
+ void
+ SetImageSize (
+ _In_ ULONG Width,
+ _In_ ULONG Height
+ )
+ {
+ m_Width = Width;
+ m_Height = Height;
+ }
+
+ //
+ // Initialize()
+ //
+ // Set the buffer the synthesizer generates images to.
+ // Override to do any additional processing you think is needed.
+ //
+ virtual
+ BOOLEAN
+ Initialize();
+
+ //
+ // Destroy()
+ //
+ // Clean up from initialize.
+ //
+ virtual
+ void
+ Destroy();
+
+ //
+ // SynthesizeBars():
+ //
+ // Synthesize EIA-189-A standard color bars.
+ //
+ virtual
+ NTSTATUS
+ SynthesizeBars();
+
+ //
+ // Synthesize
+ //
+ // Fill the image buffer with some base image. All h/w simulations will
+ // call this function to generate a base image
+ //
+ virtual
+ NTSTATUS
+ Synthesize();
+
+ //
+ // Commit
+ //
+ // Copy (and reformat, if necessary) pixels from the internal scratch
+ // buffer. If the output format decimates chrominance, do it here.
+ //
+ virtual
+ _Success_(return > 0)
+ ULONG
+ Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+ )=0;
+
+ //
+ // Commit
+ //
+ // Note: The stride needs to be a function of the bits per pixel of the
+ // OUTPUT format - not the format we store it in. The class ctor
+ // must initialize m_OutputStride to a default stride value.
+ //
+ _Success_(return > 0)
+ ULONG
+ Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size
+ )
+ {
+ return Commit( Buffer, Size, m_OutputStride );
+ }
+
+ //
+ // Histogram
+ //
+ // Fill an array with histogram data. Each parameter is optional.
+ //
+ void
+ Histogram(
+ _Out_writes_opt_(256)
+ PULONG HistogramP0, // rgbRed
+ _Out_writes_opt_(256)
+ PULONG HistogramP1, // rgbGreen
+ _Out_writes_opt_(256)
+ PULONG HistogramP2 // rgbBlue
+ );
+
+ //
+ // Synthesize
+ //
+ // Fill the image buffer with some base image. All h/w simulations will
+ // call this function to generate a base image
+ //
+ NTSTATUS
+ DoSynthesize();
+
+ //
+ // Commit
+ //
+ // Copy (and reformat, if necessary) pixels from the internal scratch
+ // buffer. If the output format decimates chrominance, do it here.
+ //
+ _Success_(return > 0)
+ ULONG
+ DoCommit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+ );
+
+ //
+ // DoCommit
+ //
+ // Note: The stride needs to be a function of the bits per pixel of the
+ // OUTPUT format - not the format we store it in. The class ctor
+ // must initialize m_OutputStride to a default stride value.
+ //
+ _Success_(return > 0)
+ ULONG
+ DoCommit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size
+ );
+
+ //
+ // OverlayText():
+ //
+ // Overlay a text string onto the image.
+ //
+ void
+ OverlayText (
+ _In_ ULONG LocX,
+ _In_ ULONG LocY,
+ _In_ ULONG Scaling,
+ _In_ LPSTR Text,
+ _In_ COLOR BgColor,
+ _In_ COLOR FgColor
+ );
+
+ virtual
+ void
+ EncodeNumber(
+ _In_ ULONG LocY,
+ _In_ UINT32 Number,
+ _In_ COLOR LowColor,
+ _In_ COLOR HighColor
+ );
+
+ void
+ SetRelativePts( LONGLONG Pts )
+ {
+ m_RelPts = Pts;
+ }
+
+ void
+ SetQpcTime( LONGLONG Pts )
+ {
+ m_QpcTime = Pts;
+ }
+
+ void
+ SetFrameNumber( ULONG Frame )
+ {
+ m_Frame = Frame;
+ }
+
+ void
+ SetRotation( AcpiPldRotation Rotation )
+ {
+ m_Rotation = Rotation;
+ }
+
+ //
+ // GetChannelMask
+ //
+ // Get the color channel mask associated with this format.
+ //
+ ULONG
+ GetChannelMask()
+ {
+ return m_ChannelMask;
+ }
+
+protected:
+ //
+ // GetPalette
+ //
+ // Get a pointer to an array of palette colors. Used mostly to handle
+ // different color primaries. Location of the primary must agree with
+ // Commit().
+ //
+ virtual
+ const UCHAR4 *
+ GetPalette()
+ {
+ return nullptr;
+ }
+
+ //
+ // GetImageLocation
+ //
+ // Get the location into the image buffer for a specific X/Y location.
+ // This also sets the synthesizer's default cursor to the position
+ // LocX, LocY.
+ //
+ PUCHAR
+ GetImageLocation (
+ _In_ ULONG LocX,
+ _In_ ULONG LocY
+ )
+ {
+ return
+ m_Cursor =
+ (m_Buffer + (sizeof(CKsRgbQuad) * LocX) + (LocY * m_SynthesisStride));
+ }
+
+};
+
diff --git a/AVStream/avscamera/sys/Timer.cpp b/AVStream/avscamera/sys/Timer.cpp
new file mode 100644
index 00000000..5345a361
--- /dev/null
+++ b/AVStream/avscamera/sys/Timer.cpp
@@ -0,0 +1,172 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ timer.cpp
+
+ Abstract:
+
+ Contains the implementation of a KTimer and KPassiveTimer.
+
+ KTimer wraps a kernel timer object. KPassiveTimer uses a passive
+ callback through a KWorkItem.
+
+ History:
+
+ created 5/30/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+KTimer::
+KTimer( TIMER_TYPE type )
+ : m_Period(0)
+ , m_Context(NULL)
+ , m_Callback(NULL)
+{
+ KeInitializeTimerEx( &m_Timer,type ) ;
+ KeInitializeDpc( &m_Dpc, KTimer::DpcThunk, this ) ;
+}
+
+KTimer::
+~KTimer()
+{
+ Cancel();
+}
+
+//
+// Cancels the timer and ensures no DPC is executing.
+//
+BOOLEAN
+KTimer::
+Cancel()
+{
+ // Clear the timer and dequeue the DPC.
+ if( !Reset() )
+ {
+ // If the item wasn't found, flush all the DPC queues.
+ KeFlushQueuedDpcs() ;
+
+ // Return false because we lost the race.
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//
+// Support for waitable class
+//
+PVOID
+KTimer::
+GetDispatchObject()
+{
+ return &m_Timer;
+}
+
+//
+// Dpc Thunking function for KeSetTimerEx
+//
+_Function_class_(KDEFERRED_ROUTINE)
+VOID
+KTimer::
+DpcThunk(
+ _In_ PKDPC /*Dpc*/,
+ _Inout_opt_ PVOID DeferredContext,
+ _Inout_opt_ PVOID /*Arg1*/,
+ _Inout_opt_ PVOID /*Arg2*/
+)
+{
+ KTimer *pKTimer = (KTimer *) DeferredContext ;
+ pKTimer->Func() ;
+}
+
+//
+// Function invoked when a timer expires
+//
+// IRQL <= DISPATCH_LEVEL
+//
+void
+KTimer::
+Func()
+{
+ if( m_Callback )
+ {
+ m_Callback( m_Context ) ;
+ }
+}
+
+//
+// Dtor
+//
+// Calls Cancel() here to clean up.
+//
+// Note: KTimer will also call Cancel(), but it will invoke KTimer::Cancel().
+// Since KPassiveTimer::Cancel() first calls KTimer::Cancel() this second
+// call is redudant; but preventing it would probably require an explicit
+// call to Cancel() before destruction. This way you can just delete
+// timers when they are no longer needed, but it make take a bit longer.
+//
+KPassiveTimer::
+~KPassiveTimer()
+{
+ Cancel();
+}
+
+//
+// Function invoked when a timer expires
+//
+// IRQL == DISPATCH_LEVEL
+//
+void
+KPassiveTimer::
+Func()
+{
+ if( m_Callback )
+ {
+ // Start the work item. If it fails, there's not much we can do since
+ // it can only fail if the owner of this timer is trying to cancel it.
+ m_WorkItem.Start();
+ }
+}
+
+VOID
+KPassiveTimer::
+WorkThunk(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_opt_ PVOID Context
+)
+{
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if( Context )
+ {
+ ((KPassiveTimer *) Context)->KTimer::Func();
+ }
+}
+
+//
+// Cancels the timer
+//
+BOOLEAN
+KPassiveTimer::
+Cancel()
+{
+ // Kill the timer.
+ if( !KTimer::Cancel() )
+ {
+ // Wait until the work item is idle.
+ m_WorkItem.Wait();
+
+ // Reset the WorkItem so we can use it again.
+ m_WorkItem.Reset();
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
diff --git a/AVStream/avscamera/sys/Timer.h b/AVStream/avscamera/sys/Timer.h
new file mode 100644
index 00000000..d4e6322e
--- /dev/null
+++ b/AVStream/avscamera/sys/Timer.h
@@ -0,0 +1,199 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ timer.h
+
+ Abstract:
+
+ Contains the definition of a KTimer and KPassiveTimer.
+
+ KTimer wraps a kernel timer object. KPassiveTimer uses a passive
+ callback through a KWorkItem.
+
+ History:
+
+ created 5/30/2014
+
+**************************************************************************/
+
+#pragma once
+
+typedef void (*PKTimerCallback)( PVOID Context ) ;
+
+class KTimer : public KWaitable, public Cancelable
+{
+public:
+ KTimer( TIMER_TYPE type=NotificationTimer );
+
+ virtual
+ ~KTimer();
+
+public:
+ //
+ // Override function that is invoked when a timer expires
+ //
+ virtual
+ void
+ Func() ;
+
+ //
+ // Cancels the timer
+ //
+ virtual
+ BOOLEAN
+ Cancel();
+
+ //
+ // Returns TRUE is if the timer is signalled
+ //
+ BOOLEAN
+ State()
+ {
+ return KeReadStateTimer( &m_Timer ) ;
+ }
+
+ //
+ // Resets (Cancels) the timer and DPC.
+ //
+ // Reset() returns TRUE if the KTIMER or the KDPC are dequeued.
+ // If Reset() returns FALSE the DPC may still be executing on another
+ // processor.
+ //
+ BOOLEAN
+ Reset()
+ {
+ // Try cancelling the timer.
+ if( !KeCancelTimer( &m_Timer ) )
+ {
+ // If the timer couldn't be cancelled, try removing the DPC.
+ return KeRemoveQueueDpc( &m_Dpc ) ;
+ }
+ return TRUE;
+ }
+
+ //
+ // Sets the timer
+ //
+ BOOLEAN
+ Set(
+ _In_ LARGE_INTEGER DueTime,
+ _In_opt_ PKTimerCallback Callback=NULL,
+ _In_opt_ PVOID Context=NULL,
+ _In_ LONG Period=0
+ )
+ {
+ m_Callback = Callback ;
+ m_Context = Context ;
+ m_Period = Period ;
+ return KeSetTimerEx( &m_Timer, DueTime, Period, &m_Dpc ) ;
+ }
+
+ //
+ // Sets the timer
+ //
+ BOOLEAN
+ Set(
+ _In_ LONGLONG DueTime,
+ _In_opt_ PKTimerCallback Callback=NULL,
+ _In_opt_ PVOID Context=NULL,
+ _In_ LONG Period=0
+ )
+ {
+ m_Callback = Callback ;
+ m_Context = Context ;
+ m_Period = Period ;
+ LARGE_INTEGER Due;
+ Due.QuadPart = DueTime;
+ return KeSetTimerEx( &m_Timer, Due, Period, &m_Dpc ) ;
+ }
+
+ //
+ // Support for waitable class
+ //
+ virtual
+ PVOID
+ GetDispatchObject();
+
+private:
+ //
+ // Dpc Thunking function for KeSetTimerEx
+ //
+ _Function_class_(KDEFERRED_ROUTINE)
+ static
+ VOID
+ DpcThunk(
+ _In_ PKDPC Dpc,
+ _Inout_opt_ PVOID DeferredContext,
+ _Inout_opt_ PVOID Arg1,
+ _Inout_opt_ PVOID Arg2
+ ) ;
+
+ TIMER_TYPE GetType()
+ {
+ return m_type;
+ }
+
+private:
+ KTIMER m_Timer ;
+ TIMER_TYPE m_type;
+
+ KDPC m_Dpc ;
+ LONG m_Period ;
+
+protected:
+ PKTimerCallback m_Callback ;
+ PVOID m_Context ;
+};
+
+class KPassiveTimer : public KTimer
+{
+public:
+ KPassiveTimer(
+ _In_ PDEVICE_OBJECT DeviceObj,
+ _In_ TIMER_TYPE type=NotificationTimer
+ )
+ : KTimer( type )
+ , m_WorkItem( DeviceObj, WorkThunk, this )
+ {}
+
+ virtual
+ ~KPassiveTimer();
+
+ //
+ // Override function that is invoked when a timer expires
+ //
+ virtual
+ void
+ Func() ;
+
+ //
+ // Cancels the timer
+ //
+ virtual
+ BOOLEAN
+ Cancel();
+
+ //
+ // Make sure it's in a valid state.
+ //
+ virtual
+ BOOLEAN
+ IsValid()
+ {
+ return m_WorkItem.IsValid();
+ }
+private:
+ KWorkItem m_WorkItem;
+
+ //
+ // Dpc Thunking function for KeSetTimerEx
+ //
+ static
+ IO_WORKITEM_ROUTINE
+ WorkThunk;
+}; \ No newline at end of file
diff --git a/AVStream/avscamera/sys/Util.cpp b/AVStream/avscamera/sys/Util.cpp
new file mode 100644
index 00000000..7c788990
--- /dev/null
+++ b/AVStream/avscamera/sys/Util.cpp
@@ -0,0 +1,491 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ util.cpp
+
+ Abstract:
+
+ Contains miscellaneous helper functions such as random number
+ generation and bounds checking functions.
+
+ History:
+
+ created 7/12/2013
+
+**************************************************************************/
+
+#include "Common.h"
+#include <bcrypt.h>
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+//
+// Generate a random number using the standard Crypto library.
+// Fall back to the QPC, if crypto library reports an error.
+//
+ULONG
+GetRandom(
+ _In_ ULONG Minimum,
+ _In_ ULONG Maximum
+)
+{
+ ULONG Value=0;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ if( KeGetCurrentIrql()==PASSIVE_LEVEL )
+ {
+ Status=
+ BCryptGenRandom( NULL, (PUCHAR) &Value, sizeof(Value), BCRYPT_USE_SYSTEM_PREFERRED_RNG );
+ }
+
+ // Fallback to QPC if BCRYPT isn't available.
+ if( !NT_SUCCESS(Status) )
+ {
+ LARGE_INTEGER QPC = KeQueryPerformanceCounter(NULL);
+ Value = QPC.u.LowPart;
+ }
+
+ // Make sure we don't divide by 0.
+ if( Minimum < Maximum )
+ {
+ Value = ((Value - Minimum) % (Maximum - Minimum +1)) + Minimum;
+ }
+ else
+ {
+ Value = Minimum ;
+ }
+
+ return Value;
+}
+
+//
+// Generate a random number using the standard Crypto library.
+// Fall back to the QPC, if crypto library reports an error.
+//
+LONG
+GetRandom(
+ _In_ LONG Minimum,
+ _In_ LONG Maximum
+)
+{
+ ULONG Value=0;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ if( KeGetCurrentIrql()==PASSIVE_LEVEL )
+ {
+ Status=
+ BCryptGenRandom( NULL, (PUCHAR) &Value, sizeof(Value), BCRYPT_USE_SYSTEM_PREFERRED_RNG );
+ }
+
+ // Fallback to QPC if BCRYPT isn't available.
+ if( !NT_SUCCESS(Status) )
+ {
+ LARGE_INTEGER QPC = KeQueryPerformanceCounter(NULL);
+ Value = QPC.u.LowPart;
+ }
+
+ // Make sure we don't divide by 0.
+ if( Minimum < Maximum )
+ {
+ Value = ((Value - Minimum) % (Maximum - Minimum +1)) + Minimum;
+ }
+ else
+ {
+ Value = Minimum ;
+ }
+
+ return Value;
+}
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+//
+// Convert an EV Compensation flag into the denominator of a fraction.
+//
+LONG
+EVFlags2Denominator(
+ _In_ ULONGLONG Flags
+)
+{
+ PAGED_CODE( );
+
+ static
+ LONG val[] = {1,2,3,4,6};
+
+ switch( Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_EVCOMP_SIXTHSTEP:
+ return 6;
+ case KSCAMERA_EXTENDEDPROP_EVCOMP_QUARTERSTEP:
+ return 4;
+ case KSCAMERA_EXTENDEDPROP_EVCOMP_THIRDSTEP:
+ return 3;
+ case KSCAMERA_EXTENDEDPROP_EVCOMP_HALFSTEP:
+ return 2;
+ case KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP:
+ return 1;
+ case KSCAMERA_PERFRAMESETTING_AUTO:
+ return val[GetRandom( (ULONG) 0, (ULONG) SIZEOF_ARRAY(val)-1)];
+ }
+
+ return 0;
+}
+
+// Convert white balance presets to a temperature.
+ULONG
+WhiteBalancePreset2Temperature(
+ _In_ ULONG WBPreset
+)
+{
+ PAGED_CODE();
+
+ ULONG temp = 0;
+
+ switch (WBPreset)
+ {
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_CLOUDY:
+ temp = 6000;
+ break;
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_DAYLIGHT:
+ temp = 5200;
+ break;
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_FLASH:
+ temp = 6000;
+ break;
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_FLUORESCENT:
+ temp = 4000;
+ break;
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_TUNGSTEN:
+ temp = 3200;
+ break;
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_CANDLELIGHT:
+ temp = 1000;
+ break;
+ default:
+ temp = 5000;
+ break;
+ }
+
+ return temp;
+}
+
+typedef struct
+{
+ LONG exposureBinaryLog;
+ LONGLONG exposure100ns;
+} ExposurePresetStruct;
+
+const ExposurePresetStruct ExposurePresets[] =
+{
+ { -10, 10000 }, // 1/1024s -> 9765.625 (100 ns) (Min is 1 ms)
+ { -9, 19531 }, // 1/512s -> 19531.25 (100 ns)
+ { -8, 39063 }, // 1/256s -> 39062.5 (100 ns)
+ { -7, 78125 }, // 1/128s -> 78125 (100 ns)
+ { -6, 196250 }, // 1/64s -> 196250 (100 ns)
+ { -5, 312500 }, // 1/32s -> 312500 (100 ns)
+ { -4, 625000 }, // 1/16s -> 625000 (100 ns)
+ { -3, 1250000 }, // 1/8s -> 1250000 (100 ns)
+ { -2, 2500000 }, // 1/4s -> 2500000 (100 ns)
+ { -1, 5000000 }, // 1/2s -> 5000000 (100 ns)
+ { 0, 10000000 },// 1s -> 1 * 10000000 (100 ns)
+ { 1, 20000000 },// 2s -> 2 * 10000000 (100 ns)
+ { 2, 40000000 },// 4s -> 4 * 10000000 (100 ns)
+ { 3, 80000000 },// 8s -> 8 * 10000000 (100 ns)
+ { 4, 160000000 },// 16s -> 16 * 10000000 (100 ns)
+ { 5, 320000000 },// 32s -> 32 * 10000000 (100 ns)
+ { 6, 640000000 },// 64s -> 64 * 10000000 (100 ns)
+ { 7, 1280000000 },// 128s -> 128 * 10000000 (100 ns)
+ { 8, 2560000000 },// 256s -> 256 * 10000000 (100 ns)
+ { 9, 3600000000 } // 512s -> 512 * 10000000 (100 ns) (Max is 360 s)
+};
+
+const ExposurePresetStruct ExposureMidpoints[] =
+{
+ { -10, 13811 }, // 2^(-9.5) -> .001381067
+ { -9, 27621 }, // 2^(-8.5) -> .002762136
+ { -8, 55243 }, // 2^(-7.5) -> .005524271
+ { -7, 110485 }, // 2^(-6.5) -> .011048543
+ { -6, 220970 }, // 2^(-5.5) -> .022097086
+ { -5, 441941 }, // 2^(-4.5) -> .044194174
+ { -4, 883883 }, // 2^(-3.5) -> .0883883476
+ { -3, 1767767 }, // 2^(-2.5) -> .1767766953
+ { -2, 3535534 }, // 2^(-1.5) -> .3535533905
+ { -1, 7071067 }, // 2^(-0.5) -> .7071067811
+ { 0, 14142136 },// 2^(0.5) -> 1.414213562
+ { 1, 28284271 },// 2^(1.5) -> 2.828427125
+ { 2, 56568542 },// 2^(2.5) -> 5.656854250
+ { 3, 113137085 },// 2^(3.5) -> 11.31370850
+ { 4, 226274170 },// 2^(4.5) -> 22.62741700
+ { 5, 452548340 },// 2^(5.5) -> 45.25483400
+ { 6, 905096680 },// 2^(6.5) -> 90.50966799
+ { 7, 1810193360 },// 2^(7.5) -> 181.0193360
+ { 8, 3080000000 },// Halfway between 8 and Max: 30800
+ { 9, 3600000000 } // Above
+};
+
+BOOL
+ExposureBinaryLogIsValid(
+ _In_ LONG ExposureBL
+)
+{
+ PAGED_CODE();
+
+ return
+ ExposurePresets[0].exposureBinaryLog <= ExposureBL &&
+ ExposurePresets[_countof(ExposurePresets) - 1].exposureBinaryLog >= ExposureBL;
+}
+
+// Changes a Legacy Preset value into 100 ns units for Exposure. If the
+// preset is out of range of what we support, return 0 to indicate failure.
+LONGLONG
+ExposureBinaryLogTo100ns(
+ _In_ LONG ExposureBL
+)
+{
+ PAGED_CODE( );
+
+ for( LONG i = 0; i < _countof(ExposurePresets); i++ )
+ {
+ if (ExposureBL == ExposurePresets[i].exposureBinaryLog)
+ {
+ return ExposurePresets[i].exposure100ns;
+ }
+ }
+
+ return 0;
+}
+
+LONG
+Exposure100nsToBinaryLog(
+ _In_ LONGLONG Exposure100ns
+)
+{
+ PAGED_CODE( );
+
+ for( LONG i = 0; i < _countof(ExposureMidpoints) - 1; i++ )
+ {
+ if(Exposure100ns <= ExposureMidpoints[i].exposure100ns)
+ {
+ return ExposureMidpoints[i].exposureBinaryLog;
+ }
+ }
+
+ return ExposureMidpoints[_countof(ExposureMidpoints) - 1].exposureBinaryLog;
+}
+
+
+static
+ULONGLONG PotentialIsoSetting[] =
+{
+ KSCAMERA_EXTENDEDPROP_ISO_50
+ , KSCAMERA_EXTENDEDPROP_ISO_80
+ , KSCAMERA_EXTENDEDPROP_ISO_100
+ , KSCAMERA_EXTENDEDPROP_ISO_200
+ , KSCAMERA_EXTENDEDPROP_ISO_400
+ , KSCAMERA_EXTENDEDPROP_ISO_800
+ , KSCAMERA_EXTENDEDPROP_ISO_1600
+ , KSCAMERA_EXTENDEDPROP_ISO_3200
+ , KSCAMERA_EXTENDEDPROP_ISO_6400
+ , KSCAMERA_EXTENDEDPROP_ISO_12800
+ , KSCAMERA_EXTENDEDPROP_ISO_25600
+};
+
+//
+// Convert ISO preset flags to a preset number
+//
+ULONG
+IsoPreset2Value(
+ _In_ ULONGLONG Flags
+)
+{
+ PAGED_CODE( );
+
+ static
+ ULONG IsoValue[] =
+ {
+ 50
+ , 80
+ , 100
+ , 200
+ , 400
+ , 800
+ , 1600
+ , 3200
+ , 6400
+ , 12800
+ , 25600
+ };
+
+ // Simple scan for min
+ for( ULONG i=0; i<_countof(PotentialIsoSetting); i++ )
+ {
+ if( PotentialIsoSetting[i] & Flags )
+ {
+ return IsoValue[i];
+ }
+ }
+ return MAXULONG;
+}
+
+//
+// Convert ISO Mode & Value to legacy presets.
+//
+// Note: This function will simply pass legacy presets through.
+//
+ULONGLONG
+IsoModeValue2Preset(
+ _In_ ULONGLONG Mode,
+ _In_ ULONG Value
+)
+{
+ PAGED_CODE( );
+
+ // These values are staggerred midpoints along a logrithmic scale.
+ // Using these pre-calculated values simplifies our search to a
+ // simple set of comparisons.
+ static
+ ULONG IsoValue[] =
+ {
+ 64 //50 //KSCAMERA_EXTENDEDPROP_ISO_50
+ ,90 //, 80 //KSCAMERA_EXTENDEDPROP_ISO_80
+ , 142 //, 100 //KSCAMERA_EXTENDEDPROP_ISO_100
+ , 283 //, 200 //KSCAMERA_EXTENDEDPROP_ISO_200
+ , 566 //, 400 //KSCAMERA_EXTENDEDPROP_ISO_400
+ , 1132 //, 800 //KSCAMERA_EXTENDEDPROP_ISO_800
+ , 2263 //, 1600 //KSCAMERA_EXTENDEDPROP_ISO_1600
+ , 4526 //, 3200 //KSCAMERA_EXTENDEDPROP_ISO_3200
+ , 9051 //, 6400 //KSCAMERA_EXTENDEDPROP_ISO_6400
+ , 18102 //, 12800 //KSCAMERA_EXTENDEDPROP_ISO_12800
+ };
+
+ if( Mode & KSCAMERA_EXTENDEDPROP_ISO_MANUAL )
+ {
+ // Simple scan for min
+ for( ULONG i=0; i<_countof(PotentialIsoSetting)-1; i++ )
+ {
+ if( Value < IsoValue[i] )
+ {
+ return PotentialIsoSetting[i];
+ }
+ }
+ return KSCAMERA_EXTENDEDPROP_ISO_25600;
+ }
+ return Mode;
+}
+
+LPCSTR
+KSStateToStateName(
+ _In_ KSSTATE state
+)
+{
+ PAGED_CODE( );
+
+ static const CHAR *txt[] =
+ {
+ "STOP",
+ "ACQUIRE",
+ "PAUSE",
+ "RUN"
+ };
+
+ return ((KSSTATE_STOP <= state && KSSTATE_RUN >= state) ? txt[state] : "UNK");
+}
+
+// Debugging helper.
+PCSTR
+FocusStateDbgTxt(
+ _In_ KSCAMERA_EXTENDEDPROP_FOCUSSTATE State
+)
+{
+ PAGED_CODE();
+
+ switch( State )
+ {
+ case KSCAMERA_EXTENDEDPROP_FOCUSSTATE_UNINITIALIZED:
+ return "FOCUSSTATE_UNINITIALIZED";
+ case KSCAMERA_EXTENDEDPROP_FOCUSSTATE_LOST:
+ return "FOCUSSTATE_LOST";
+ case KSCAMERA_EXTENDEDPROP_FOCUSSTATE_SEARCHING:
+ return "FOCUSSTATE_SEARCHING";
+ case KSCAMERA_EXTENDEDPROP_FOCUSSTATE_FOCUSED:
+ return "FOCUSSTATE_FOCUSED";
+ case KSCAMERA_EXTENDEDPROP_FOCUSSTATE_FAILED:
+ return "FOCUSSTATE_FAILED";
+ default:
+ return "FOCUSSTATE_unknown";
+ }
+}
+
+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
+
+--*/
+
+{
+ PAGED_CODE();
+
+ *pab = a * b;
+ if ((a == 0) || (((*pab) / a) == b))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+DbgRotation2Degrees(
+ AcpiPldRotation r
+)
+{
+ switch( r )
+ {
+ case AcpiPldRotation0 : return 0;
+ case AcpiPldRotation45 : return 45;
+ case AcpiPldRotation90 : return 90;
+ case AcpiPldRotation135: return 135;
+ case AcpiPldRotation180: return 180;
+ case AcpiPldRotation225: return 225;
+ case AcpiPldRotation270: return 270;
+ case AcpiPldRotation315: return 315;
+ }
+ return -1;
+}
+
diff --git a/AVStream/avscamera/sys/Util.h b/AVStream/avscamera/sys/Util.h
new file mode 100644
index 00000000..f235a42d
--- /dev/null
+++ b/AVStream/avscamera/sys/Util.h
@@ -0,0 +1,298 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ util.h
+
+ Abstract:
+
+ Contains miscellaneous helper functions such as random number
+ generation and bounds checking functions.
+
+ History:
+
+ created 7/12/2013
+
+**************************************************************************/
+
+//
+// Generate a random number using the standard Crypto library.
+// Fall back to the QPC, if crypto library reports an error.
+//
+ULONG
+GetRandom(
+ _In_ ULONG Minimum,
+ _In_ ULONG Maximum
+);
+
+//
+// Generate a random number using the standard Crypto library.
+// Fall back to the QPC, if crypto library reports an error.
+//
+LONG
+GetRandom(
+ _In_ LONG Minimum,
+ _In_ LONG Maximum
+);
+
+//
+// Convert an EV Compensation flag into the denominator of a fraction.
+//
+LONG
+EVFlags2Denominator(
+ _In_ ULONGLONG Flags
+);
+
+//
+// Convert a WhiteBalance Extended Property Enum to temperature
+//
+ULONG
+WhiteBalancePreset2Temperature(
+ _In_ ULONG WBPreset
+);
+
+//
+// Checks if a legacy Exposure setting is in range
+//
+BOOL
+ExposureBinaryLogIsValid(
+ _In_ LONG ExposureBL
+);
+
+//
+// Converts a legacy Exposure setting into 100 ns
+//
+LONGLONG
+ExposureBinaryLogTo100ns(
+ _In_ LONG ExposureBL
+);
+
+//
+// Converts a Exposure setting into a Binary log preset
+//
+LONG
+Exposure100nsToBinaryLog(
+ _In_ LONGLONG Exposure100ns
+);
+
+//
+// Convert ISO preset flags to a preset number
+//
+ULONG
+IsoPreset2Value(
+ _In_ ULONGLONG Flags
+);
+
+//
+// Convert ISO Mode & Value to legacy presets.
+//
+// Note: This function will simply pass legacy presets through.
+//
+ULONGLONG
+IsoModeValue2Preset(
+ _In_ ULONGLONG Mode,
+ _In_ ULONG Value
+);
+
+LPCSTR
+KSStateToStateName(
+ _In_ KSSTATE state
+);
+
+BOOL
+MultiplyCheckOverflow (
+ ULONG a,
+ ULONG b,
+ ULONG *pab
+);
+
+// Note: I overload this function intentionally. Just use
+// the correct type as the first parameter and the
+// compiler figures out the function to use.
+template<class T>
+inline
+NTSTATUS
+BoundsCheck(
+ _In_ T Value,
+ _In_ const KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING &Bounds
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if( ((Value - T(Bounds.Min) ) % T(Bounds.Step)) != 0 ||
+ Value > T(Bounds.Max) ||
+ Value < T(Bounds.Min) )
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+inline
+NTSTATUS
+BoundsCheckSigned(
+ _In_ LONGLONG Value,
+ _In_ const KSCAMERA_EXTENDEDPROP_VIDEOPROCSETTING &Bounds
+)
+{
+ return BoundsCheck<LONGLONG>( Value, Bounds );
+}
+
+inline
+NTSTATUS
+BoundsCheckSigned(
+ _In_ LONG Value,
+ _In_ const KSPROPERTY_STEPPING_LONG &Bounds
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if( ((Value - Bounds.Bounds.SignedMinimum) % Bounds.SteppingDelta) != 0 ||
+ Value > Bounds.Bounds.SignedMaximum ||
+ Value < Bounds.Bounds.SignedMinimum )
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+inline
+NTSTATUS
+BoundsCheckSigned(
+ _In_ LONGLONG Value,
+ _In_ const KSPROPERTY_STEPPING_LONGLONG &Bounds
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if( ((Value - Bounds.Bounds.SignedMinimum) % Bounds.SteppingDelta) != 0 ||
+ Value > Bounds.Bounds.SignedMaximum ||
+ Value < Bounds.Bounds.SignedMinimum )
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Note: I overload this function intentionally. Just use
+// the correct type as the first parameter and the
+// compiler figures out the function to use.
+inline
+NTSTATUS
+BoundsCheckUnsigned(
+ _In_ ULONG Value,
+ _In_ const KSPROPERTY_STEPPING_LONG &Bounds
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if( ((Value - Bounds.Bounds.UnsignedMinimum) % Bounds.SteppingDelta) != 0 ||
+ Value > Bounds.Bounds.UnsignedMaximum ||
+ Value < Bounds.Bounds.UnsignedMinimum )
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+inline
+NTSTATUS
+BoundsCheckUnsigned(
+ _In_ ULONGLONG Value,
+ _In_ const KSPROPERTY_STEPPING_LONGLONG &Bounds
+)
+{
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ if( ((Value - Bounds.Bounds.UnsignedMinimum) % Bounds.SteppingDelta) != 0 ||
+ Value > Bounds.Bounds.UnsignedMaximum ||
+ Value < Bounds.Bounds.UnsignedMinimum )
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+//
+// This function is used internally to translate KSCAMERA_PERFRAMESETTING
+// AUTO & MANUAL flags to KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG AUTO & MANUAL
+// flags. There is no need to translate them back.
+//
+inline
+ULONGLONG
+TranslatePFS2VideoProcFlags(
+ ULONGLONG FromMode
+)
+{
+ // The PFS settings and VideoProc flags are mixed.
+ // To handle that, we'll first remove any PFS flags
+ // and hang onto the rest.
+ ULONGLONG ToMode=
+ FromMode & ~(KSCAMERA_PERFRAMESETTING_AUTO|KSCAMERA_PERFRAMESETTING_MANUAL);
+
+ if( FromMode & KSCAMERA_PERFRAMESETTING_AUTO )
+ {
+ ToMode |= KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO;
+ }
+ if( FromMode & KSCAMERA_PERFRAMESETTING_MANUAL )
+ {
+ ToMode |= KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ }
+
+ return ToMode;
+}
+
+//
+// Debugging Helper
+//
+PCSTR
+FocusStateDbgTxt(
+ _In_ KSCAMERA_EXTENDEDPROP_FOCUSSTATE State
+);
+
+//
+// Debugging Helper - translate ACPI rotation enum to degrees.
+//
+int
+DbgRotation2Degrees(
+ AcpiPldRotation r
+);
+
+
+#define SAFE_FREE(_x_) \
+ if( _x_ ) \
+ { \
+ ExFreePool( _x_ ); \
+ _x_ = nullptr; \
+ }
+
+#define SAFE_DELETE(_x_) \
+ if( _x_ ) \
+ { \
+ delete _x_; \
+ _x_ = nullptr; \
+ }
+
+#define SAFE_DELETE_ARRAY(_x_) \
+ if( _x_ ) \
+ { \
+ delete [] _x_; \
+ _x_ = nullptr; \
+ }
+
+#define SAFE_CLOSE_HANDLE(_x_) \
+ if( (_x_ != NULL) && (_x_ != INVALID_HANDLE_VALUE) ) \
+ { \
+ ZwClose( _x_ ); \
+ _x_ = INVALID_HANDLE_VALUE; \
+ }
+
diff --git a/AVStream/avscamera/sys/VideoCapture.cpp b/AVStream/avscamera/sys/VideoCapture.cpp
new file mode 100644
index 00000000..92bf4b51
--- /dev/null
+++ b/AVStream/avscamera/sys/VideoCapture.cpp
@@ -0,0 +1,130 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ videocapture.cpp
+
+ Abstract:
+
+ Video Capture Pin implementation.
+
+ Handles construction and defines pin data ranges.
+
+ History:
+
+ created 3/8/2001
+
+**************************************************************************/
+
+#include "Common.h"
+#include "ntintsafe.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+CVideoCapturePin::CVideoCapturePin(IN PKSPIN Pin) :
+ CCapturePin (Pin)
+{
+ PAGED_CODE();
+
+}
+
+
+/*************************************************
+
+Routine Description:
+
+ Create a new 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
+
+**************************************************/
+
+NTSTATUS
+CVideoCapturePin::
+DispatchCreate(
+ IN PKSPIN Pin,
+ IN PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(Pin=%d)", Pin->Id);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CCaptureFilter* pFilter = reinterpret_cast <CCaptureFilter*>(KsPinGetParentFilter(Pin)->Context);
+ CVideoCapturePin *CapPin = new (NonPagedPoolNx) CVideoCapturePin (Pin);
+
+ if( !CapPin )
+ {
+ // Fail if we couldn't create the pin.
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ Status =
+ CapPin->Initialize();
+ }
+
+ if( NT_SUCCESS (Status) )
+ {
+ //
+ // Adjust the stream header size. The video packets have extended
+ // header info (KS_FRAME_INFO).
+ //
+ pFilter->setPin(CapPin, Pin->Id);
+ }
+ else
+ {
+ // Clean up.
+ delete CapPin;
+ }
+
+ DBG_LEAVE("(Pin=%d)=0x%08X", Pin->Id, Status);
+ return Status;
+}
+
+//
+// CapturePinDispatch:
+//
+// This is the dispatch table for the capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc...
+//
+DEFINE_CAMERA_KSPIN_DISPATCH( VideoCapturePinDispatch, CVideoCapturePin );
+
+//
+// CapturePinAllocatorFraming:
+//
+// This is the simple framing structure for the capture pin. Note that this
+// will be modified via KsEdit when the actual capture format is determined.
+//
+DECLARE_SIMPLE_FRAMING_EX(
+ VideoCapturePinAllocatorFraming,
+ STATICGUIDOF( KSMEMORY_TYPE_KERNEL_NONPAGED ),
+ KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
+ KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY,
+ 2,
+ 0,
+ 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE
+);
+
+
diff --git a/AVStream/avscamera/sys/VideoCapture.h b/AVStream/avscamera/sys/VideoCapture.h
new file mode 100644
index 00000000..da08b0a8
--- /dev/null
+++ b/AVStream/avscamera/sys/VideoCapture.h
@@ -0,0 +1,34 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ videocapture.h
+
+ Abstract:
+
+ Video Capture Pin definition.
+
+ CVideoCapturePin derived from CCapturePin.
+
+ History:
+
+ created 3/8/2001
+
+**************************************************************************/
+
+#pragma once
+
+#include "capture.h"
+
+class CVideoCapturePin : public CCapturePin
+{
+public:
+ static NTSTATUS DispatchCreate (IN PKSPIN Pin, IN PIRP Irp);
+
+private:
+ CVideoCapturePin(IN PKSPIN Pin);
+};
diff --git a/AVStream/avscamera/sys/VideoHwSim.cpp b/AVStream/avscamera/sys/VideoHwSim.cpp
new file mode 100644
index 00000000..33b6de90
--- /dev/null
+++ b/AVStream/avscamera/sys/VideoHwSim.cpp
@@ -0,0 +1,66 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ VideoHwSim.cpp
+
+ Abstract:
+
+ A fake h/w simulation for the video pin. Provides Video pin specific
+ metadata.
+
+ History:
+
+ created 5/28/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+
+CVideoHardwareSimulation::CVideoHardwareSimulation(
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+)
+ : CHardwareSimulation( Sensor, PinID )
+{}
+
+
+CVideoHardwareSimulation::~CVideoHardwareSimulation()
+{}
+
+//
+// Emit metadata here for video pin.
+//
+void
+CVideoHardwareSimulation::
+EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+)
+{
+ NT_ASSERT(pStreamHeader);
+
+ // Add the normal frame info to the metadata
+ // Note: This call ensures the KSSTREAM_METADATA_INFO is properly initialized.
+ CHardwareSimulation::EmitMetadata( pStreamHeader );
+
+ if (0 != (pStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_METADATA))
+ {
+ CExtendedVidProcSetting FaceDetect;
+ m_Sensor->GetFaceDetection(&FaceDetect);
+
+ if( FaceDetect.Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_VIDEO )
+ {
+ DBG_TRACE("VIDEO");
+ EmitFaceMetadata(
+ pStreamHeader,
+ FaceDetect.GetULONG(),
+ FaceDetect.Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_ADVANCED_MASK);
+ }
+ }
+}
+
diff --git a/AVStream/avscamera/sys/VideoHwSim.h b/AVStream/avscamera/sys/VideoHwSim.h
new file mode 100644
index 00000000..40b0b24b
--- /dev/null
+++ b/AVStream/avscamera/sys/VideoHwSim.h
@@ -0,0 +1,42 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ VideoHwSim.h
+
+ Abstract:
+
+ A fake h/w simulation for the video pin. Provides Video pin specific
+ metadata.
+
+ History:
+
+ created 5/28/2014
+
+**************************************************************************/
+
+#pragma once
+class CVideoHardwareSimulation :
+ public CHardwareSimulation
+{
+public:
+ CVideoHardwareSimulation(
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+ );
+
+ virtual ~CVideoHardwareSimulation();
+
+ //
+ // Emit metadata here for video pin.
+ //
+ void
+ EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+ );
+};
+
diff --git a/AVStream/avscamera/sys/Waitable.cpp b/AVStream/avscamera/sys/Waitable.cpp
new file mode 100644
index 00000000..1de5827a
--- /dev/null
+++ b/AVStream/avscamera/sys/Waitable.cpp
@@ -0,0 +1,69 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ waitable.cpp
+
+ Abstract:
+
+ Base interface for any object that is waitable.
+ In otherwords, it contains a kernel dispatch object.
+
+ History:
+
+ created 5/30/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+KWaitable::
+KWaitable()
+{}
+
+
+KWaitable::
+~KWaitable()
+{}
+
+NTSTATUS
+KWaitable::
+Wait(
+ _In_opt_ PLARGE_INTEGER Timeout
+)
+/*++
+
+Routine Description:
+
+ Default Wait implementation.
+
+Arguments:
+
+ Timeout -
+ An optional timeout value in 100ns units. Negative is relative time.
+ If NULL, wait forever.
+
+Return Value:
+
+ Success / Failure.
+
+--*/
+{
+ PVOID pObj = GetDispatchObject() ;
+
+ if(pObj != NULL)
+ {
+ return
+ KeWaitForSingleObject(
+ pObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ Timeout);
+ }
+ return STATUS_SUCCESS;
+}
diff --git a/AVStream/avscamera/sys/Waitable.h b/AVStream/avscamera/sys/Waitable.h
new file mode 100644
index 00000000..1f092657
--- /dev/null
+++ b/AVStream/avscamera/sys/Waitable.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ waitable.h
+
+ Abstract:
+
+ Base interface for any object that is waitable.
+ In otherwords, it contains a kernel dispatch object.
+
+ Also implements a Cancelable interface class.
+
+ History:
+
+ created 5/30/2014
+
+**************************************************************************/
+
+#pragma once
+
+//
+// Interface definitions for KWaitable and Cancelable
+//
+class KWaitable :
+ public CNonCopyable
+{
+public:
+ KWaitable();
+
+ virtual
+ ~KWaitable();
+
+ virtual
+ NTSTATUS
+ Wait(
+ _In_opt_ PLARGE_INTEGER Timeout = NULL
+ );
+
+ // Must implement
+ virtual
+ PVOID
+ GetDispatchObject() = 0;
+};
+
+class Cancelable
+{
+public:
+ // Must implement
+ virtual
+ BOOLEAN
+ Cancel() = 0;
+};
+
diff --git a/AVStream/avscamera/sys/WorkItem.cpp b/AVStream/avscamera/sys/WorkItem.cpp
new file mode 100644
index 00000000..9bb0d795
--- /dev/null
+++ b/AVStream/avscamera/sys/WorkItem.cpp
@@ -0,0 +1,167 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ workitem.cpp
+
+ Abstract:
+
+ This module contains an implementation for KWorkItem.
+
+ A KWorkItem inherits from CRef and is reference counted. The object
+ cannot be destroyed until all references are released. This includes
+ the reference held when the workitem is in flight. This allows you
+ to store the workitem in an object that has a lifecycle shorter than
+ the parent device object.
+
+ History:
+
+ created 5/30/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+KWorkItem::
+KWorkItem(
+ _In_ PDEVICE_OBJECT DeviceObj,
+ _In_ PIO_WORKITEM_ROUTINE Callback,
+ _In_ PVOID Context,
+ _In_ WORK_QUEUE_TYPE QueueType
+)
+ : m_Callback( Callback )
+ , m_Context ( Context )
+ , m_QueueType( QueueType )
+/*++
+
+Routine Description:
+
+ Constructor.
+
+ Sets up callback handler for the workitem and performs initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ m_WorkItem = IoAllocateWorkItem( DeviceObj );
+}
+
+
+KWorkItem::
+~KWorkItem()
+/*++
+
+Routine Description:
+
+ Destructor.
+
+ Blocks until all references are released, then frees the workitem.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // Make sure the work item has been run down.
+ Wait();
+
+ // Now delete it.
+ if( m_WorkItem )
+ {
+ IoFreeWorkItem( m_WorkItem );
+ }
+}
+
+BOOLEAN
+KWorkItem::
+Start()
+/*++
+
+Routine Description:
+
+ Enqueue this workitem and acquires a reference on the object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - a workitem was scheduled.
+
+--*/
+{
+ // Make sure construction succeeded.
+ if( m_WorkItem )
+ {
+ // Make sure the work item isn't already in flight and acquire the lock.
+ // This is to make sure this KWorkItem doesn't get destroyed until
+ // the callback is complete.
+ if( Acquire() )
+ {
+ // Schedule the work item.
+ IoQueueWorkItem( m_WorkItem, &KWorkItem::Handler, m_QueueType, this );
+
+ // Note: Release() is called in Handler.
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+VOID
+KWorkItem::
+Handler(
+ _In_ PDEVICE_OBJECT IoObject,
+ _In_opt_ PVOID Context
+)
+/*++
+
+Routine Description:
+
+ Callback thunking function.
+
+ Calls the callback handler registered in the constructor, if one exists.
+ Releases the reference on this object.
+
+Arguments:
+
+ IoObject -
+ The parent device object.
+ Context -
+ An optional context object.
+
+Return Value:
+
+ void
+
+--*/
+{
+ // Get our "this" pointer (Me).
+ KWorkItem *Me = (KWorkItem *) Context;
+
+ // Invoke the callback if one exists.
+ if( Me->m_Callback )
+ {
+ Me->m_Callback( IoObject, Me->m_Context );
+ }
+
+ // Unlock the work item; allow for destruction or re-enqueing.
+ Me->Release();
+}
diff --git a/AVStream/avscamera/sys/WorkItem.h b/AVStream/avscamera/sys/WorkItem.h
new file mode 100644
index 00000000..dfce3b91
--- /dev/null
+++ b/AVStream/avscamera/sys/WorkItem.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ workitem.h
+
+ Abstract:
+
+ This module contains a class wrapper definition for an IO_WORKITEM.
+
+ A KWorkItem inherits from CRef and is reference counted. The object
+ cannot be destroyed until all references are released. This includes
+ the reference held when the workitem is in flight. This allows you
+ to store the workitem in an object that has a lifecycle shorter than
+ the parent device object.
+
+ History:
+
+ created 5/30/2014
+
+**************************************************************************/
+
+#pragma once
+class KWorkItem :
+ public CRef // Reference counted...
+{
+private:
+ PIO_WORKITEM m_WorkItem;
+ PIO_WORKITEM_ROUTINE m_Callback;
+ PVOID m_Context;
+ WORK_QUEUE_TYPE m_QueueType;
+
+public:
+ KWorkItem(
+ _In_ PDEVICE_OBJECT DeviceObj,
+ _In_ PIO_WORKITEM_ROUTINE Callback,
+ _In_ PVOID Context=nullptr,
+ _In_ WORK_QUEUE_TYPE QueueType=NormalWorkQueue
+ );
+
+ virtual
+ ~KWorkItem();
+
+ BOOLEAN
+ IsValid()
+ {
+ return m_WorkItem != nullptr;
+ }
+
+ // Returns FALSE if failed to start.
+ BOOLEAN
+ Start();
+
+private:
+ static
+ IO_WORKITEM_ROUTINE
+ Handler;
+};
+
diff --git a/AVStream/avscamera/sys/XRGBSynthesizer.cpp b/AVStream/avscamera/sys/XRGBSynthesizer.cpp
new file mode 100644
index 00000000..1aee170c
--- /dev/null
+++ b/AVStream/avscamera/sys/XRGBSynthesizer.cpp
@@ -0,0 +1,247 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ XRGBSynthesizer.cpp
+
+ Abstract:
+
+ This file contains the implementation of CXRGBSynthesizer.
+
+ CXRGBSynthesizer is derived from CSynthesizer. It uses the RGB
+ color space and defines a Commit() function. XRGB is known also
+ known as RGB32. It uses 8 bits per primary plus 8 bits of padding
+ for 4 bytes per pixel in a single plane.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+// suppressed due to Esp:773
+#pragma warning (push)
+#pragma warning( disable:26015 ) // Suppress OACR error. Seems nonsensical. TODO: Must revisit.
+#pragma warning( disable:6101 )
+_Success_(return > 0)
+ULONG
+CXRGBSynthesizer::
+Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+)
+/*++
+
+Routine Description:
+
+ Copy (and reformat, if necessary) pixels from the internal scratch
+ buffer. If the output format decimates chrominance, do it here.
+
+Arguments:
+
+ Buffer -
+ The output buffer to fill.
+
+ Size -
+ The size of the output buffer in bytes.
+
+ Stride -
+ The length of a row in bytes.
+
+Return Value:
+
+ Number of bytes copied into Buffer.
+
+--*/
+{
+ PAGED_CODE();
+
+ // In case stride isn't initialized.
+ if( Stride==0 )
+ {
+ Stride = m_OutputStride;
+ }
+
+ if( !( Buffer &&
+ m_Buffer &&
+ Size >= sizeof(KS_RGBQUAD) &&
+ m_Length >= sizeof(KS_RGBQUAD) &&
+ (Stride%4)==0 &&
+ (Size%4)==0
+ ) )
+ {
+ NT_ASSERT(FALSE);
+ return 0;
+ }
+
+ ULONG OutputStride = min( Stride, (ULONG) m_OutputStride );
+ ULONG OutputSize = min( Size, m_Length );
+ ULONG Limit = min( m_Height, OutputSize/Stride );
+
+ // Is the row order in the bitmap inverted?
+ if( m_FlipVertical )
+ {
+ PUCHAR Start = Buffer;
+ for( ULONG y=Limit; y; y-- )
+ {
+ // Inverted row copy, with possible stride, width or height difference.
+ RtlCopyMemory( Buffer, GetImageLocation( 0, y-1 ), OutputStride );
+ Buffer += Stride;
+ }
+ return (ULONG) (Buffer - Start);
+ }
+ else
+ {
+ PUCHAR Start = Buffer;
+
+ if( Limit * OutputStride == OutputSize )
+ {
+ // 1:1 copy case. (Path normally taken, so fastest.)
+ RtlCopyMemory( Buffer, m_Buffer, OutputSize );
+ return OutputSize;
+ }
+ else
+ {
+ for( ULONG y=0; y<Limit; y++ )
+ {
+ // Normal copy, with possible stride, width or height difference.
+ RtlCopyMemory( Buffer, GetImageLocation( 0, y ), OutputStride );
+ Buffer += Stride;
+ }
+ return (ULONG) (Buffer - Start);
+ }
+ }
+}
+// suppressed due to Esp:773
+#pragma warning (pop)
+
+const UCHAR4 *
+CXRGBSynthesizer::
+GetPalette()
+/*++
+
+Routine Description:
+
+ Get a pointer to an array of palette colors. Used mostly to handle
+ different color primaries. Location of the primary must agree with
+ Commit().
+
+Arguments:
+
+ none
+
+Return Value:
+
+ A pointer to an array of color primaries used for rendering.
+
+--*/
+{
+ PAGED_CODE();
+
+ static
+ UCHAR4 Colors [MAX_COLOR] =
+ {
+ {0, 0, 0}, // BLACK
+ {255, 255, 255}, // WHITE
+ {0, 255, 255}, // YELLOW
+ {255, 255, 0}, // CYAN
+ {0, 255, 0}, // GREEN
+ {255, 0, 255}, // MAGENTA
+ {0, 0, 255}, // RED
+ {255, 0, 0}, // BLUE
+ {128, 128, 128}, // GREY
+ {255, 255, 255}, // TEXT_COLOR
+ };
+
+ return Colors;
+}
+
+// Macros used to do fixed-point arithmetic in initialization.
+#define TO_Q24_8bit_to_32bit(_x_) ( ( (ULONG) (_x_) ) << 24 )
+#define FROM_Q24_32bit_to_8bit(_x_) ((UCHAR) (( (ULONG) (_x_) ) >> 24 ))
+
+BOOLEAN
+CXRGBSynthesizer::
+Initialize()
+/*++
+
+Routine Description:
+
+ Class initialization.
+
+ Used to pre-initialize a bitmap that contains a gradient bar that starts
+ with one of our rendering colors and fades to black. Each row will contain
+ the gradient for a single starting color. To paint a gradient bar, simply
+ replicate the row as many times as necessary.
+
+ This front-loads all gradient calculations to initialization and caches the
+ result, allowing us to render a gradient bar in the time it takes to copy
+ the pixels even on a relatively slow machine.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE - success.
+
+--*/
+{
+ PAGED_CODE();
+
+ // First, do the base class initialization.
+ BOOLEAN Status = CSynthesizer::Initialize();
+
+ if( Status )
+ {
+ // Now initialize the Gradient bmp...
+ CKsRgbQuad *Bmp = m_GradientBmp;
+
+ for( ULONG color=BLACK; color<MAX_COLOR; color++ )
+ {
+ ULONG HALF = TO_Q24_8bit_to_32bit(1)>>1; // round, don't truncate.
+ ULONG B = TO_Q24_8bit_to_32bit(m_Colors[color][0])+HALF;
+ ULONG G = TO_Q24_8bit_to_32bit(m_Colors[color][1])+HALF;
+ ULONG R = TO_Q24_8bit_to_32bit(m_Colors[color][2])+HALF;
+ ULONG BDelta = B-TO_Q24_8bit_to_32bit(m_Colors[BLACK][0]);
+ ULONG GDelta = G-TO_Q24_8bit_to_32bit(m_Colors[BLACK][1]);
+ ULONG RDelta = R-TO_Q24_8bit_to_32bit(m_Colors[BLACK][2]);
+
+ BDelta /= (ULONG) m_Width;
+ GDelta /= (ULONG) m_Width;
+ RDelta /= (ULONG) m_Width;
+
+ for(ULONG i = 0; i < m_Width; i++)
+ {
+ *Bmp++ = CKsRgbQuad(
+ FROM_Q24_32bit_to_8bit(R),
+ FROM_Q24_32bit_to_8bit(G),
+ FROM_Q24_32bit_to_8bit(B)
+ );
+ B -= BDelta;
+ G -= GDelta;
+ R -= RDelta;
+ }
+ }
+ }
+ return Status;
+}
diff --git a/AVStream/avscamera/sys/XRGBSynthesizer.h b/AVStream/avscamera/sys/XRGBSynthesizer.h
new file mode 100644
index 00000000..5e7ddd46
--- /dev/null
+++ b/AVStream/avscamera/sys/XRGBSynthesizer.h
@@ -0,0 +1,97 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ XRGBSynthesizer.h
+
+ Abstract:
+
+ This file contains the definition of CXRGBSynthesizer.
+
+ CXRGBSynthesizer is derived from CSynthesizer. It uses the RGB
+ color space and defines a Commit() function. XRGB is known also
+ known as RGB32. It uses 8 bits per primary plus 8 bits of padding
+ for 4 bytes per pixel in a single plane.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+/*************************************************
+
+ CXRGBSynthesizer
+
+ Image synthesizer for XRGB (aka RGB32) format.
+
+*************************************************/
+
+class CXRGBSynthesizer
+ : public CSynthesizer
+{
+protected:
+ BOOLEAN m_FlipVertical;
+
+public:
+ //
+ // DEFAULT CONSTRUCTOR:
+ //
+ CXRGBSynthesizer (
+ LONG Width=0,
+ LONG Height=0
+ ) :
+ CSynthesizer("RGB32", CHANNEL_RGB, Width, ABS(Height))
+ , m_FlipVertical(Height==ABS(Height))
+ {
+ m_OutputStride = Width * sizeof(KS_RGBQUAD);
+ }
+
+ //
+ // DESTRUCTOR:
+ //
+ virtual
+ ~CXRGBSynthesizer ()
+ {}
+
+ //
+ // Commit
+ //
+ // Copy (and reformat, if necessary) pixels from the internal scratch
+ // buffer. If the output format decimates chrominance, do it here.
+ //
+ virtual
+ _Success_(return > 0)
+ ULONG
+ Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+ );
+
+ //
+ // Initialize()
+ //
+ // Initialize the Gradient bmp for RGB color space.
+ //
+ virtual
+ BOOLEAN
+ Initialize();
+
+protected:
+ //
+ // GetPalette
+ //
+ // Get a pointer to an array of palette colors. Used mostly to handle
+ // different color primaries. Location of the primary must agree with
+ // Commit().
+ virtual
+ const UCHAR4 *
+ GetPalette();
+};
+
diff --git a/AVStream/avscamera/sys/YUVSynthesizer.cpp b/AVStream/avscamera/sys/YUVSynthesizer.cpp
new file mode 100644
index 00000000..27b4c7e9
--- /dev/null
+++ b/AVStream/avscamera/sys/YUVSynthesizer.cpp
@@ -0,0 +1,150 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ YUVSynthesizer.cpp
+
+ Abstract:
+
+ This file contains the implementation of CYUVSynthesizer.
+
+ A Base image synthesizer for all YUV formats. It provides a YUV color
+ palette and sets up cached gradient bars.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+const UCHAR4 *
+CYUVSynthesizer::
+GetPalette()
+/*++
+
+Routine Description:
+
+ Get a pointer to an array of palette colors. Used mostly to handle
+ different color primaries. Location of the primary must agree with
+ Commit().
+
+Arguments:
+
+ none
+
+Return Value:
+
+ A pointer to an array of color primaries used for rendering.
+
+--*/
+{
+ PAGED_CODE();
+
+ static
+ UCHAR4 Colors [MAX_COLOR] =
+ {
+ {128, 16, 128}, // BLACK
+ {128, 235, 128}, // WHITE
+ {16, 211, 146}, // YELLOW
+ {166, 170, 16}, // CYAN
+ {54, 145, 34}, // GREEN
+ {202, 106, 222}, // MAGENTA
+ {90, 81, 240}, // RED
+ {240, 41, 109}, // BLUE
+ {128, 125, 128}, // GREY
+ {128, 235, 128} // TEXT_COLOR
+ };
+
+ return Colors;
+};
+
+// Macros used to do fixed-point arithmetic in initialization.
+#define TO_Q24_8bit_to_32bit_signed(_x_) ( ( ( LONG) (_x_) ) << 24 )
+#define FROM_Q24_32bit_to_8bit_signed(_x_) (( CHAR) (( ( LONG) (_x_) ) >> 24 ))
+#define TO_Q24_8bit_to_32bit_unsigned(_x_) ( ( (ULONG) (_x_) ) << 24 )
+#define FROM_Q24_32bit_to_8bit_unsigned(_x_) ((UCHAR) (( (ULONG) (_x_) ) >> 24 ))
+
+BOOLEAN
+CYUVSynthesizer::
+Initialize()
+/*++
+
+Routine Description:
+
+ Class initialization.
+
+ Used to pre-initialize a bitmap that contains a gradient bar that starts
+ with one of our rendering colors and fades to black. Each row will contain
+ the gradient for a single starting color. To paint a gradient bar, simply
+ replicate the row as many times as necessary.
+
+ This front-loads all gradient calculations to initialization and caches the
+ result, allowing us to render a gradient bar in the time it takes to copy
+ the pixels even on a relatively slow machine.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE - success.
+
+--*/
+{
+ PAGED_CODE();
+
+ // First, do the base class initialization.
+ BOOLEAN Status = CSynthesizer::Initialize();
+
+ if( Status )
+ {
+ // Now initialize the Gradient bmp...
+ CKsRgbQuad *Bmp = m_GradientBmp;
+ // {54, 145, 34}, // GREEN to {128, 16, 128}, // BLACK
+ for( ULONG color=BLACK; color<MAX_COLOR; color++ )
+ {
+ // Must treat chroma as signed & luma as unsigned here.
+ ULONG HALF = TO_Q24_8bit_to_32bit_unsigned(1)>>1; // round, don't truncate.
+ LONG U = TO_Q24_8bit_to_32bit_signed (m_Colors[color][0])+HALF;
+ ULONG Y = TO_Q24_8bit_to_32bit_unsigned(m_Colors[color][1])+HALF;
+ LONG V = TO_Q24_8bit_to_32bit_signed (m_Colors[color][2])+HALF;
+ LONG UDelta = U-TO_Q24_8bit_to_32bit_signed (m_Colors[BLACK][0]);
+ ULONG YDelta = Y-TO_Q24_8bit_to_32bit_unsigned(m_Colors[BLACK][1]);
+ LONG VDelta = V-TO_Q24_8bit_to_32bit_signed (m_Colors[BLACK][2]);
+
+ UDelta /= (LONG) m_Width;
+ YDelta /= (LONG) m_Width;
+ VDelta /= (LONG) m_Width;
+
+ for(ULONG i = 0; i < m_Width; i++)
+ {
+ *Bmp++ = CKsRgbQuad(
+ FROM_Q24_32bit_to_8bit_signed (V),
+ FROM_Q24_32bit_to_8bit_unsigned(Y),
+ FROM_Q24_32bit_to_8bit_signed (U)
+ );
+ U -= UDelta;
+ Y -= YDelta;
+ V -= VDelta;
+ }
+ }
+ }
+ return Status;
+}
diff --git a/AVStream/avscamera/sys/YUVSynthesizer.h b/AVStream/avscamera/sys/YUVSynthesizer.h
new file mode 100644
index 00000000..819139e4
--- /dev/null
+++ b/AVStream/avscamera/sys/YUVSynthesizer.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ YUVSynthesizer.h
+
+ Abstract:
+
+ This file contains the definition of CYUVSynthesizer.
+
+ A Base image synthesizer for all YUV formats. It provides a YUV color
+ palette and sets up cached gradient bars.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+#pragma once
+
+/*************************************************
+
+ CYUVSynthesizer
+
+ Image synthesizer for YUV format.
+
+*************************************************/
+
+
+class CYUVSynthesizer :
+ public CSynthesizer
+{
+protected:
+ //
+ // GetPalette
+ //
+ // Get a pointer to an array of palette colors. Used mostly to handle
+ // different color primaries. Location of the primary must agree with
+ // Commit().
+ virtual
+ const UCHAR4 *
+ GetPalette();
+
+ //
+ // Initialize()
+ //
+ // Initialize the Gradient bmp for YUV color space.
+ //
+ virtual
+ BOOLEAN
+ Initialize();
+
+public:
+
+ //Default constructor
+ CYUVSynthesizer (
+ PCCHAR Name="[Something YUV]",
+ ULONG Width=0,
+ ULONG Height=0
+ )
+ : CSynthesizer(Name, CHANNEL_YCrCb, Width, Height)
+ {}
+};
+
diff --git a/AVStream/avscamera/sys/YUY2Synthesizer.cpp b/AVStream/avscamera/sys/YUY2Synthesizer.cpp
new file mode 100644
index 00000000..14a76262
--- /dev/null
+++ b/AVStream/avscamera/sys/YUY2Synthesizer.cpp
@@ -0,0 +1,137 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ YUVSynthesizer.cpp
+
+ Abstract:
+
+ This file contains the implementation of CYUY2Synthesizer.
+
+ CYUY2Synthesizer is derived from CYUVSynthesizer. An image
+ synthesizer for YUY2 format. It uses the YUV color space and defines
+ a Commit() function.
+
+ YUY2 is a 4:2:2 format that uses a single plane that decimates chroma
+ samples on the x axis with an effective bit rate of 16 bits per pixel.
+ A plane is an array of rows. Rows consist of pairs of pixels in the
+ sequence: Y0|U|Y1|V.
+
+ The synthesizer stores the YUV information in 32 bit format internally
+ for speed and accuracy. The Commit function does the format conversion.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+// suppressed due to Esp:773
+#pragma warning (push)
+#pragma warning( disable:26015 ) // Suppress OACR error. Seems nonsensical. TODO: Must revisit.
+#pragma warning( disable:26019 )
+_Success_(return > 0)
+ULONG
+CYUY2Synthesizer::
+Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+)
+/*++
+
+Routine Description:
+
+ Copy (and reformat, if necessary) pixels from the internal scratch
+ buffer. If the output format decimates chrominance, do it here.
+
+Arguments:
+
+ Buffer -
+ The output buffer to fill.
+
+ Size -
+ The size of the output buffer in bytes.
+
+ Stride -
+ The length of a row in bytes.
+
+Return Value:
+
+ Number of bytes copied into Buffer.
+
+--*/
+{
+ PAGED_CODE();
+
+ NT_ASSERT( Buffer );
+ NT_ASSERT( m_Buffer );
+ NT_ASSERT( Size >= Stride * m_Height );
+ NT_ASSERT( (Stride&3)==0 );
+ NT_ASSERT( (m_Width&1) == 0 );
+ NT_ASSERT( (m_Height&1) == 0 );
+ NT_ASSERT( m_Width>1 && m_Height>1 );
+ NT_ASSERT( (Size&1)==0 );
+
+ // In most cases, stride isn't initialized.
+ // If so, just assume its the Width.
+ if( Stride==0 )
+ {
+ Stride = m_OutputStride;
+ }
+
+ if( !( Buffer &&
+ m_Buffer &&
+ Size >= Stride * m_Height &&
+ (Stride&3)==0 &&
+ (m_Width&1) == 0 &&
+ (m_Height&1) == 0 &&
+ m_Width>1 && m_Height>1 &&
+ (Size&1)==0
+ ) )
+ {
+ // Wipe the destination before returning failure.
+ return 0;
+ }
+
+ PKS_RGBQUAD pSrc = (PKS_RGBQUAD) m_Buffer;
+ ULONG RowLimit = min( m_Height, Size / Stride );
+ ULONG ColLimit = min( m_Width, Stride/sizeof(WORD) ) & ~0x1;
+
+ for(ULONG row = 0; row < RowLimit; row++)
+ {
+ PDWORD pY = (PDWORD) &Buffer[ row * Stride ];
+
+ for(ULONG col = 0; col < ColLimit; col+=2)
+ {
+ KS_RGBQUAD L = pSrc[col+0];
+ KS_RGBQUAD R = pSrc[col+1];
+
+ *pY++ =
+ MAKELONG( MAKEWORD( L.rgbGreen, (ULONG(L.rgbBlue) + R.rgbBlue)/2),
+ MAKEWORD( R.rgbGreen, (ULONG(L.rgbRed ) + R.rgbRed )/2) );
+ }
+ pSrc = (PKS_RGBQUAD) (((PUCHAR) pSrc) + m_SynthesisStride);
+ }
+
+ return RowLimit * Stride;
+}
+// suppressed due to Esp:773
+#pragma warning (pop)
diff --git a/AVStream/avscamera/sys/YUY2Synthesizer.h b/AVStream/avscamera/sys/YUY2Synthesizer.h
new file mode 100644
index 00000000..a304fb43
--- /dev/null
+++ b/AVStream/avscamera/sys/YUY2Synthesizer.h
@@ -0,0 +1,68 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ YUY2Synthesizer.h
+
+ Abstract:
+
+ This file contains the definition of CYUY2Synthesizer.
+
+ CYUY2Synthesizer is derived from CYUVSynthesizer. An image
+ synthesizer for YUY2 format. It uses the YUV color space and defines
+ a Commit() function.
+
+ YUY2 is a 4:2:2 format that uses a single plane that decimates chroma
+ samples on the x axis with an effective bit rate of 16 bits per pixel.
+ A plane is an array of rows. Rows consist of pairs of pixels in the
+ sequence: Y0|U|Y1|V.
+
+ The synthesizer stores the YUV information in 32 bit format internally
+ for speed, accuracy and simplicity. The Commit function does the
+ format conversion.
+
+ History:
+
+ created 4/14/2014
+
+**************************************************************************/
+
+class CYUY2Synthesizer : public CYUVSynthesizer
+{
+public:
+ //
+ // DEFAULT CONSTRUCTOR
+ //
+ CYUY2Synthesizer (
+ ULONG Width=0,
+ ULONG Height=0
+ ) :
+ CYUVSynthesizer("YUY2", Width, Height)
+ {
+ NT_ASSERT( ( Width % 2 ) == 0 );
+ m_OutputStride = Width * sizeof(WORD);
+ }
+
+ //
+ // Commit
+ //
+ // Copy (and reformat, if necessary) pixels from the internal scratch
+ // buffer. If the output format decimates chrominance, do it here.
+ //
+ virtual
+ _Success_(return > 0)
+ ULONG
+ Commit(
+ _Out_writes_bytes_(Size)
+ PUCHAR Buffer,
+ _In_ ULONG Size,
+ _In_ ULONG Stride
+ );
+
+};
+
+
diff --git a/AVStream/avscamera/sys/avscamera.inf b/AVStream/avscamera/sys/avscamera.inf
new file mode 100644
index 00000000..d855cc6f
--- /dev/null
+++ b/AVStream/avscamera/sys/avscamera.inf
Binary files differ
diff --git a/AVStream/avscamera/sys/filter.cpp b/AVStream/avscamera/sys/filter.cpp
new file mode 100644
index 00000000..cb28775e
--- /dev/null
+++ b/AVStream/avscamera/sys/filter.cpp
@@ -0,0 +1,4080 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ filter.cpp
+
+ Abstract:
+
+ This file contains the filter level implementation for the base capture
+ filter class. It provides a wrapper on KSFILTER.
+
+ CCaptureFilter holds state information for the filter and contains
+ implementations for standard camera controls. These implementations
+ validate arguments and capabilities of the control according to DDI
+ definitions. Once validated, control is passes to a CSensor object
+ to manipulate the state of camera.
+
+ To add a new control, derive from CCaptureFilter and use one of the
+ DECLARE_PROPERTY_XXX() macros below to declare the property handlers.
+ You can also use the DEFINE_PROP_ITEM_XXX() and DEFINE_STD_EVENT_ITEM()
+ macros as aids in constructing a filter's automation table.
+
+ History:
+
+ created 3/12/2001
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+CCaptureFilter::CCaptureFilter (
+ _In_ PKSFILTER Filter
+):
+/*++
+
+Routine Description:
+
+ CCaptureFilter object construction.
+
+Arguments:
+
+ Filter -
+ The AVStream filter being wrapped.
+
+Return Value:
+
+ None
+
+--*/
+ m_pCaptureDevice(NULL),
+ m_pPerFrameSettings(nullptr),
+ m_pinArray(nullptr),
+ m_PhotoModeNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE ),
+ m_PhotoMaxFrameRateNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE) ,
+ m_FocusNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE ),
+ m_FocusRectNotifier( Filter, &EVENTSETID_VIDCAP_CAMERACONTROL_REGION_OF_INTEREST, KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID ),
+ m_IsoNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_ISO ),
+ m_IsoAdvancedNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED ),
+ m_EvCompensationNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION ),
+ m_WhiteBalanceNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE ),
+ m_ExposureNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE ),
+ m_SceneModeNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE ),
+ m_ThumbnailNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL ),
+ m_WarmStartNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART ),
+ m_RoiNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL ),
+ m_ProfileNotifier( Filter, &KSEVENTSETID_ExtendedCameraControl, KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE )
+{
+
+ PAGED_CODE();
+
+ DBG_ENTER("(Filter=%p)", Filter);
+
+ m_pKSFilter = Filter;
+
+ m_pCaptureDevice = CCaptureDevice::Recast(KsFilterGetDevice(Filter));
+
+ KeQuerySystemTime (&m_StartTime);
+
+ m_Profile.ProfileId = KSCAMERAPROFILE_Legacy;
+ m_Profile.Index = 0;
+ m_Profile.Reserved = 0;
+
+ DBG_ENTER("(Filter=%p)", Filter);
+}
+
+NTSTATUS
+CCaptureFilter::
+Initialize()
+/*++
+
+Routine Description:
+
+ Post construction initialization.
+
+Arguments:
+
+ [None]
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DBG_ENTER("(Filter=%S)", GetFilterName());
+
+ // Get Sensor object from our parent device object.
+
+ m_Sensor = m_pCaptureDevice->GetSensor(m_pKSFilter);
+ NT_ASSERT(m_Sensor);
+
+ // We get a nullptr back if the Filter doesn't match one of our's.
+ if( !m_Sensor )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ // In reality we're just adding a reference to the sensor for this filter.
+ // The sensor has no back pointer to the filter since more than one filter
+ // can be open at a time.
+ IFFAILED_EXIT( m_Sensor->AddFilter(m_pKSFilter) );
+
+ IFNULL_EXIT(m_pinArray = new (PagedPool, 'sniP') CCapturePin *[m_Sensor->GetPinCount()]);
+
+ for( ULONG i=0; i<m_Sensor->GetPinCount(); i++ )
+ {
+ m_pinArray[i] = nullptr;
+ }
+
+done:
+ DBG_LEAVE("(Filter=%S)=0x%08X", GetFilterName(), Status);
+ return Status;
+}
+
+void
+CCaptureFilter::Cleanup()
+/*++
+
+Routine Description:
+
+ Clean up. Cancels any outstanding operations on the sensor.
+
+Arguments:
+
+ [None]
+
+Return Value:
+
+ [None]
+
+--*/
+{
+ PAGED_CODE();
+
+ // Cancel all Async operations. Ignore any failures.
+ m_Sensor->CancelPhotoMode();
+ m_Sensor->CancelPhotoMaxFrameRate();
+ m_Sensor->CancelFocus();
+ m_Sensor->CancelFocusRect();
+ m_Sensor->CancelIso();
+ m_Sensor->CancelIsoAdvanced();
+ m_Sensor->CancelEvCompensation();
+ m_Sensor->CancelWhiteBalance();
+ m_Sensor->CancelExposure();
+ m_Sensor->CancelSceneMode();
+ m_Sensor->CancelThumbnail();
+ m_Sensor->CancelWarmStart();
+ m_Sensor->CancelRoi();
+}
+
+//
+// ~CCaptureFilter():
+//
+// The capture filter destructor.
+//
+CCaptureFilter::~CCaptureFilter()
+{
+ PAGED_CODE();
+
+ LPCWSTR Name = GetFilterName();
+ DBG_ENTER("(%S)", Name);
+
+ delete [] ((PBYTE) m_pPerFrameSettings);
+
+ // In reality we're just removing a reference to the sensor for this filter.
+ m_Sensor->RemoveFilter(m_pKSFilter);
+
+ // The sensor may need to do some cleanup. In particular, the image pin
+ // may need to have some things reset.
+ m_Sensor->Reset();
+
+ delete [] m_pinArray;
+
+ DBG_LEAVE("(%S)", Name);
+}
+
+
+NTSTATUS
+CCaptureFilter::
+DispatchCreate (
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp
+)
+/*++
+
+Routine Description:
+
+ Static function for creation dispatch for the capture filter. It creates
+ the CCaptureFilter object.
+
+Arguments:
+
+ Filter -
+ The AVStream filter being created
+
+ Irp -
+ The creation Irp
+
+Return Value:
+
+ Success / failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(Filter=0x%p)", Filter);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CCaptureFilter *CapFilter = new (NonPagedPoolNx, 'rtlf') CCaptureFilter (Filter);
+
+ if (!CapFilter)
+ {
+ //
+ // Return failure if we couldn't create the filter.
+ //
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+ else
+ {
+ // Allocate memory or whatever.
+ Status = CapFilter->Initialize();
+
+ if (!NT_SUCCESS (Status))
+ {
+ delete CapFilter;
+ }
+ else
+ {
+ Filter -> Context = reinterpret_cast <PVOID> (CapFilter);
+ }
+
+ }
+
+ DBG_LEAVE( "()=0x%08X", Status );
+ return Status;
+}
+
+NTSTATUS
+CCaptureFilter::DispatchClose(
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp
+)
+/*++
+
+Routine Description:
+
+ Static function for the close dispatch for the capture filter. It handles
+ filter cleanup.
+
+Arguments:
+
+ Filter -
+ The AVStream filter being closed
+
+ Irp -
+ The creation Irp
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+ PAGED_CODE();
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(Filter->Context);
+
+ if( pFilter )
+ {
+ pFilter->Cleanup();
+ delete pFilter;
+ }
+ return STATUS_SUCCESS;
+}
+
+void
+CCaptureFilter::
+setPin(
+ _In_ CCapturePin *pPin,
+ _In_ unsigned Id
+)
+/*++
+
+Routine Description:
+
+ Attach a CCapturePin to the filter.
+
+Arguments:
+
+ pPin -
+ The pin.
+ Id -
+ The pin index.
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ if( Id >= m_Sensor->GetPinCount() )
+ {
+ __debugbreak();
+ return;
+ }
+
+ // Take out a weak reference to the pin object.
+ m_pinArray[Id] = pPin;
+}
+
+CCapturePin *
+CCaptureFilter::
+getPin(
+ _In_ unsigned Id
+)
+/*++
+
+Routine Description:
+
+ Get a pointer to an attached CCapturePin.
+
+Arguments:
+
+ Id -
+ The pin index.
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+ PAGED_CODE( );
+
+ if( Id >= m_Sensor->GetPinCount() )
+ {
+ __debugbreak();
+ return nullptr;
+ }
+
+ // Convert back to a strong reference before returning.
+ return m_pinArray[Id] ;
+}
+
+NTSTATUS
+CCaptureFilter::
+UpdateAllocatorFraming(
+ _In_ ULONG PinId
+)
+/*++
+
+Routine Description:
+
+ Update the Pin's Allocator Framing.
+
+Arguments:
+
+ PinId -
+ A pin's index
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ // Acquire the lock and update the Pin's allocator framing.
+ LockFilter Lock(m_pKSFilter);
+
+ if( m_pinArray[PinId] )
+ {
+ Status = m_pinArray[PinId]->UpdateAllocatorFraming();
+ }
+
+ DBG_LEAVE("()=0x%08X",Status);
+ return Status;
+}
+
+/**************************************************************************
+
+ Control validation and forwarding.
+
+**************************************************************************/
+
+// Get for KSPROPERTY_CAMERACONTROL_FLASH_PROPERTY_ID
+NTSTATUS
+CCaptureFilter::
+GetFlash(
+ _Inout_ KSPROPERTY_CAMERACONTROL_FLASH_S *pFlash
+)
+{
+ PAGED_CODE();
+
+ return
+ m_Sensor->GetFlash( pFlash );
+}
+
+// Set for KSPROPERTY_CAMERACONTROL_FLASH_PROPERTY_ID
+NTSTATUS
+CCaptureFilter::
+SetFlash(
+ _In_ KSPROPERTY_CAMERACONTROL_FLASH_S *pFlash
+)
+{
+ PAGED_CODE();
+
+ KSPROPERTY_CAMERACONTROL_FLASH_S Caps;
+
+ RtlZeroMemory( &Caps, sizeof(Caps) );
+ NTSTATUS Status = m_Sensor->GetFlash(&Caps);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ // Validate the parameters against our caps.
+ switch( pFlash->Flash )
+ {
+ case KSPROPERTY_CAMERACONTROL_FLASH_OFF:
+ case KSPROPERTY_CAMERACONTROL_FLASH_ON:
+ if( Caps.Capabilities & KSPROPERTY_CAMERACONTROL_FLASH_FLAGS_MANUAL )
+ {
+ Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_FLASH_AUTO:
+ if( Caps.Capabilities & KSPROPERTY_CAMERACONTROL_FLASH_FLAGS_AUTO )
+ {
+ Status = STATUS_SUCCESS;
+ }
+ break;
+ }
+ }
+ if( NT_SUCCESS(Status) )
+ {
+ Status = m_Sensor->SetFlash( pFlash );
+ }
+
+ return Status;
+}
+
+// Get for PROPSETID_VIDCAP_CAMERACONTROL_VIDEO_STABILIZATION:0
+NTSTATUS
+CCaptureFilter::
+GetVideoStabMode(
+ _Inout_ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S *pVideoStab
+)
+{
+ PAGED_CODE();
+
+ return
+ m_Sensor->GetVideoStabMode( pVideoStab );
+}
+
+// Set for PROPSETID_VIDCAP_CAMERACONTROL_VIDEO_STABILIZATION:0
+NTSTATUS
+CCaptureFilter::
+SetVideoStabMode(
+ _In_ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S *pVideoStab
+)
+{
+ PAGED_CODE();
+
+ KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S Caps;
+
+ RtlZeroMemory( &Caps, sizeof(Caps) );
+ NTSTATUS Status = m_Sensor->GetVideoStabMode( &Caps );
+
+ DBG_ENTER("(Mode=0x%08X, Caps=0x%08X)", pVideoStab->VideoStabilizationMode, Caps.Capabilities );
+
+ if( NT_SUCCESS(Status) )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ switch( pVideoStab->VideoStabilizationMode )
+ {
+ case KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_OFF:
+ Status = STATUS_SUCCESS;
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_AUTO:
+ if( Caps.Capabilities & KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_FLAGS_AUTO )
+ {
+ Status = STATUS_SUCCESS;
+ }
+ break;
+
+ case KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_LOW:
+ case KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_MEDIUM:
+ case KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_HIGH:
+ if( Caps.Capabilities & KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_FLAGS_MANUAL )
+ {
+ Status = STATUS_SUCCESS;
+ }
+ break;
+ }
+ }
+ if( NT_SUCCESS(Status) )
+ {
+ Status = m_Sensor->SetVideoStabMode( pVideoStab );
+ }
+ DBG_LEAVE("(Mode=0x%08X, Caps=0x%08X)=0x%08X", pVideoStab->VideoStabilizationMode, Caps.Capabilities, Status );
+ return Status;
+}
+
+// Get for KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_PROPERTY_ID
+NTSTATUS
+CCaptureFilter::
+GetPinDependence(
+ _Inout_ KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S *pPinDependence
+)
+{
+ PAGED_CODE();
+
+ return
+ m_Sensor->GetPinDependence( pPinDependence );
+}
+
+//
+// A macro used for consistent asynchronous SET behavior.
+//
+#define INVOKE_SET_ASYNC( SENSOR, PROPERTY, OUTPUT, NOTIFIER ) \
+ ( OUTPUT->Flags & KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION ) ? SENSOR->Cancel ## PROPERTY () : \
+ SENSOR->Set ## PROPERTY ## Async( OUTPUT, &NOTIFIER );
+
+#define INVOKE_SET_ASYNC_NOT_CANCELLABLE( SENSOR, PROPERTY, OUTPUT, NOTIFIER ) \
+ ( OUTPUT->Flags & KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION ) ? STATUS_INVALID_PARAMETER : \
+ SENSOR->Set ## PROPERTY ## Async( OUTPUT, &NOTIFIER );
+
+// Get for KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID
+NTSTATUS
+CCaptureFilter::GetFocusRect(
+ _Inout_ KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S *pRoi
+)
+{
+ PAGED_CODE();
+ return m_Sensor->GetFocusRect( pRoi );
+}
+
+// Set for KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID
+NTSTATUS
+CCaptureFilter::
+SetFocusRect(
+ _In_ KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S *pRoi
+)
+{
+ PAGED_CODE();
+
+ return m_Sensor->SetFocusRectAsync( pRoi, &m_FocusRectNotifier );
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE
+NTSTATUS
+CCaptureFilter::GetPhotoMode(
+ _Inout_ CExtendedPhotoMode *pMode
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER( "()" );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pMode->isValid() &&
+ m_Sensor->IsStillIndex( pMode->PinId ) )
+ {
+ Status = m_Sensor->GetPhotoMode( pMode );
+ }
+
+ DBG_TRACE( "Capability=0x%016llX", pMode->Capability );
+ DBG_TRACE( "PinId=%d", pMode->PinId );
+ DBG_TRACE( "MaxHistoryFrames=%d", pMode->MaxHistoryFrames() );
+
+ DBG_LEAVE( "()=0x%08X", Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE
+NTSTATUS
+CCaptureFilter::
+SetPhotoMode(
+ _In_ CExtendedPhotoMode *pMode
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER( "()" );
+
+ if( pMode->isValid() &&
+ m_Sensor->IsStillIndex( pMode->PinId ) &&
+ (pMode->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) )
+ {
+ CExtendedPhotoMode Caps(*pMode);
+ Status = m_Sensor->GetPhotoMode( &Caps );
+ CCapturePin *pPin = getPin(pMode->PinId);
+
+ // Should always be valid.
+ NT_ASSERT(pPin);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter again.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( (pMode->Flags & Caps.Capability) == pMode->Flags )
+ {
+ // We don't support cancel here.
+ switch( pMode->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE:
+ {
+ // We cache the Per-Frame Settings in the filter as a simplification for the getter.
+ // But we can also use it here to tell us basic info about the current PFS.
+ PKSCAMERA_PERFRAMESETTING_HEADER pPFS = m_pPerFrameSettings;
+ if( pMode->SubMode() == KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE_SUB_VARIABLE &&
+ !pPFS )
+ {
+ DBG_TRACE( "VPS requested without Per Frame Settings." );
+ break;
+ }
+
+ // Reject any request for too many history frames.
+ if( pMode->RequestedHistoryFrames() > Caps.MaxHistoryFrames() )
+ {
+ DBG_TRACE( "Too many history frames requested." );
+ break;
+ }
+
+ DBG_TRACE( "Flags=0x%08X, RequestedHistoryFrames=%d, SubMode=0x%08X",
+ (ULONG) pMode->Flags,
+ pMode->RequestedHistoryFrames(),
+ pMode->SubMode() );
+
+ // Assume the normal photo sequence case.
+ // For normal photo sequence, we provide history frames +1 or at least a minimum of 3 frames.
+ ULONG TotalFrames = pMode->RequestedHistoryFrames() + 1;
+
+ // Modify TotalFrames for the VPS case.
+ // For VPS, we need LoopCount * FrameCount; but limit by the minimum(3) and maximum (20) frames.
+ if( KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE_SUB_VARIABLE==pMode->SubMode() )
+ {
+ // Assume at least one loop, if the loop is infinite.
+ ULONG LoopCount = max( pPFS->LoopCount, 1 );
+ ULONG FrameCount= pPFS->FrameCount;
+
+ // Add in the number of future frames expected.
+ TotalFrames+= (LoopCount * FrameCount) -1;
+
+ DBG_TRACE( "TotalFrames=%d, LoopCount=%d, FrameCount=%d", TotalFrames, LoopCount, FrameCount );
+ }
+
+ // Bound the frame count to minimum and maximums.
+ TotalFrames =
+ min( max( TotalFrames, IMAGE_CAPTURE_PIN_MINIMUM_FRAMES ), IMAGE_CAPTURE_PIN_MAXIMUM_FRAMES );
+ DBG_TRACE( "Advertising Framing requirement: %d", TotalFrames );
+
+
+ pPin->SetDesiredFrames(TotalFrames);
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ case KSCAMERA_EXTENDEDPROP_PHOTOMODE_NORMAL:
+ {
+ // Set it back to the minimum number of frames.
+ pPin->SetDesiredFrames(IMAGE_CAPTURE_PIN_MINIMUM_FRAMES);
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ // Update allocator framing.
+ if( NT_SUCCESS( Status ) )
+ {
+ Status = UpdateAllocatorFraming( pMode->PinId );
+ }
+
+ // Update the sensor object...
+ if( NT_SUCCESS(Status) )
+ {
+ Status = m_Sensor->SetPhotoModeAsync( pMode, &m_PhotoModeNotifier );
+ }
+ }
+ }
+ }
+
+ DBG_TRACE( "Capability=0x%016llX", pMode->Capability );
+ DBG_TRACE( "Flags=0x%016llX", pMode->Flags );
+ DBG_TRACE( "PinId=%d", pMode->PinId );
+ DBG_TRACE( "MaxHistoryFrames=%d", pMode->MaxHistoryFrames() );
+ DBG_TRACE( "RequestedHistoryFrames=%d", pMode->RequestedHistoryFrames() );
+ DBG_TRACE( "SubMode=0x%08X", pMode->SubMode() );
+ DBG_LEAVE( "()=0x%08X", Status );
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE Get Handler
+ */
+NTSTATUS
+CCaptureFilter::GetPhotoFrameRate(
+ _Inout_ CExtendedProperty *pFrameRate
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFrameRate->isValid() &&
+ m_Sensor->IsStillIndex(pFrameRate->PinId) )
+ {
+ ULONGLONG TimePerFrame = m_Sensor->GetPhotoFrameRate(pFrameRate->PinId);
+ if( TimePerFrame > ULONG_MAX )
+ {
+ // Handle very large (slow) frame rates in seconds.
+ pFrameRate->m_Value.Value.ratio.HighPart = 1;
+ pFrameRate->m_Value.Value.ratio.LowPart = (ULONG) (TimePerFrame / ONESECOND);
+ }
+ else
+ {
+ // Handle smaller frame rates as 100ns units.
+ pFrameRate->m_Value.Value.ratio.HighPart = ONESECOND;
+ pFrameRate->m_Value.Value.ratio.LowPart = (ULONG) TimePerFrame;
+ }
+ Status = STATUS_SUCCESS;
+ }
+
+ DBG_LEAVE("(PinId=%d, estimated FrameRate=%d/%d)=0x%08X",
+ pFrameRate->PinId,
+ pFrameRate->m_Value.Value.ratio.HighPart,
+ pFrameRate->m_Value.Value.ratio.LowPart,
+ Status );
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES Get Handler
+ */
+NTSTATUS
+CCaptureFilter::
+GetMaxVideoFpsForPhotoRes(
+ _Inout_ CExtendedMaxVideoFpsForPhotoRes *pFps
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFps->isValid() &&
+ pFps->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pFps->Capability == 0 &&
+ pFps->Flags == 0 )
+ {
+ Status = m_Sensor->GetMaxVideoFpsForPhotoRes( pFps );
+ }
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES Set Handler
+ */
+NTSTATUS
+CCaptureFilter::SetMaxVideoFpsForPhotoRes(
+ _In_ CExtendedMaxVideoFpsForPhotoRes *pFps
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFps->isValid() &&
+ pFps->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pFps->Capability == 0 &&
+ pFps->Flags == 0 )
+ {
+ Status = m_Sensor->SetMaxVideoFpsForPhotoRes( pFps );
+ }
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE Get Handler
+ */
+NTSTATUS
+CCaptureFilter::GetPhotoMaxFrameRate(
+ _Inout_ CExtendedProperty *pFrameRate
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFrameRate->isValid() &&
+ m_Sensor->IsStillIndex(pFrameRate->PinId) )
+ {
+ Status = m_Sensor->GetPhotoMaxFrameRate( pFrameRate );
+ }
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE Set Handler
+ */
+NTSTATUS
+CCaptureFilter::
+SetPhotoMaxFrameRate(
+ _In_ CExtendedProperty *pFrameRate
+)
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(MaxFrameRate = %d/%d)",
+ pFrameRate->m_Value.Value.ratio.HighPart,
+ pFrameRate->m_Value.Value.ratio.LowPart );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFrameRate->isValid() &&
+ m_Sensor->IsStillIndex( pFrameRate->PinId ) &&
+ (pFrameRate->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) )
+ {
+ // Don't allow either the numerator or denominator alone to be 0.
+ // We don't want a rate of 0 fps or undefined.
+ if( pFrameRate->m_Value.Value.ll == 0 ||
+ ( pFrameRate->m_Value.Value.ratio.LowPart != 0 &&
+ pFrameRate->m_Value.Value.ratio.HighPart != 0 ) )
+ {
+ // Take what we're given here; SetPhotoFrameRate handles default setting.
+ DBG_TRACE("[Override] MaxFrameRate = %d/%d",
+ pFrameRate->m_Value.Value.ratio.HighPart,
+ pFrameRate->m_Value.Value.ratio.LowPart );
+
+ Status = m_Sensor->SetPhotoMaxFrameRateAsync( pFrameRate, &m_PhotoMaxFrameRateNotifier );
+ }
+ }
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME
+NTSTATUS
+CCaptureFilter::
+GetTriggerTime(
+ _Inout_ CExtendedProperty *pTriggerTime
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pTriggerTime->isValid() &&
+ m_Sensor->IsStillIndex(pTriggerTime->PinId) )
+ {
+ Status = m_Sensor->GetTriggerTime( pTriggerTime );
+ }
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME
+NTSTATUS
+CCaptureFilter::
+SetTriggerTime(
+ _In_ CExtendedProperty *pTriggerTime
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pTriggerTime->isValid() &&
+ pTriggerTime->Capability == 0 &&
+ m_Sensor->IsStillIndex(pTriggerTime->PinId) )
+ {
+ Status = m_Sensor->SetTriggerTime( pTriggerTime );
+ }
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART
+ */
+NTSTATUS
+CCaptureFilter::
+GetWarmStart(
+ _Inout_ CExtendedProperty *pWarmStart
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pWarmStart->isValid() &&
+ m_Sensor->IsValidIndex( pWarmStart->PinId ) )
+ {
+ Status = m_Sensor->GetWarmStart( pWarmStart );
+ }
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pWarmStart->PinId, pWarmStart->Flags, pWarmStart->Capability, Status );
+ return Status;
+}
+
+/*
+ * KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART Set Handler
+ */
+NTSTATUS
+CCaptureFilter::SetWarmStart(
+ _In_ CExtendedProperty *pWarmStart
+)
+{
+ PAGED_CODE();
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)",
+ pWarmStart->PinId, pWarmStart->Flags, pWarmStart->Capability );
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pWarmStart->isValid() &&
+ m_Sensor->IsValidIndex( pWarmStart->PinId ) &&
+ (pWarmStart->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) )
+ {
+ CExtendedProperty Caps(*pWarmStart);
+ Status = m_Sensor->GetWarmStart( &Caps );
+
+ if( NT_SUCCESS(Status ) )
+ {
+ if( pWarmStart->Flags == (pWarmStart->Flags & Caps.Capability) )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, WarmStart, pWarmStart, m_WarmStartNotifier );
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X", Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL
+NTSTATUS
+CCaptureFilter::
+SetThumbnail(
+ _In_ CExtendedProperty *pThumbnail
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ // Validate
+ if( (pThumbnail->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pThumbnail->isValid() &&
+ m_Sensor->IsStillIndex(pThumbnail->PinId) )
+ {
+ CExtendedProperty Caps;
+ Status = m_Sensor->GetThumbnail( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ if( pThumbnail->Flags == (Caps.Capability & pThumbnail->Flags) )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, Thumbnail, pThumbnail, m_ThumbnailNotifier );
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL
+NTSTATUS
+CCaptureFilter::
+GetThumbnail(
+ _Inout_ CExtendedProperty *pThumbnail
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ // Validate
+ if( pThumbnail->isValid() &&
+ m_Sensor->IsStillIndex(pThumbnail->PinId) )
+ {
+ Status = m_Sensor->GetThumbnail( pThumbnail );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE
+NTSTATUS
+CCaptureFilter::
+GetSceneMode(
+ _Inout_ CExtendedProperty *pSceneMode
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pSceneMode->isValid() &&
+ pSceneMode->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetSceneMode( pSceneMode );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE
+NTSTATUS
+CCaptureFilter::
+SetSceneMode(
+ _In_ CExtendedProperty *pSceneMode
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ if( (pSceneMode->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pSceneMode->isValid() &&
+ pSceneMode->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ CExtendedProperty Caps;
+ Status = m_Sensor->GetSceneMode( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ if( pSceneMode->Flags == (Caps.Capability & pSceneMode->Flags) )
+ {
+ Status = INVOKE_SET_ASYNC_NOT_CANCELLABLE( m_Sensor, SceneMode, pSceneMode, m_SceneModeNotifier );
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_TORCHMODE
+NTSTATUS
+CCaptureFilter::
+GetTorchMode(
+ _Inout_ CExtendedProperty *pTorchMode
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pTorchMode->isValid() &&
+ pTorchMode->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetTorchMode( pTorchMode );
+ }
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pTorchMode->PinId, pTorchMode->Flags, pTorchMode->Capability, Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_TORCHMODE
+NTSTATUS
+CCaptureFilter::
+SetTorchMode(
+ _In_ CExtendedProperty *pTorchMode
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( !(pTorchMode->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pTorchMode->isValid() &&
+ pTorchMode->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pTorchMode->m_Value.Value.ul <= 100 )
+ {
+ CExtendedProperty Caps(*pTorchMode);
+ Status = m_Sensor->GetTorchMode(&Caps);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pTorchMode->Flags == (pTorchMode->Flags & Caps.Capability) )
+ {
+ switch( pTorchMode->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_VIDEOTORCH_OFF:
+ case KSCAMERA_EXTENDEDPROP_VIDEOTORCH_ON:
+ case KSCAMERA_EXTENDEDPROP_VIDEOTORCH_ON_ADJUSTABLEPOWER:
+ Status = m_Sensor->SetTorchMode( pTorchMode );
+ break;
+ }
+ }
+ }
+ }
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pTorchMode->PinId, pTorchMode->Flags, pTorchMode->Capability, Status );
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FLASHMODE
+NTSTATUS
+CCaptureFilter::
+GetExtendedFlash(
+ _Inout_ CExtendedProperty *pFlash
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFlash->isValid() &&
+ pFlash->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE)
+ {
+ Status = m_Sensor->GetExtendedFlash( pFlash );
+ }
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pFlash->PinId, pFlash->Flags, pFlash->Capability, Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FLASHMODE
+NTSTATUS
+CCaptureFilter::
+SetExtendedFlash(
+ _In_ CExtendedProperty *pFlash
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( !(pFlash->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pFlash->isValid() &&
+ pFlash->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE)
+ {
+ CExtendedProperty Caps;
+ Status = m_Sensor->GetExtendedFlash( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pFlash->Flags == (pFlash->Flags & Caps.Capability) )
+ {
+ // Validate flash settings.
+ // First validate the basic flash controls
+ switch( pFlash->Flags & KSCAMERA_EXTENDEDPROP_FLASH_MODE_MASK )
+ {
+ // Valid combinations
+ case KSCAMERA_EXTENDEDPROP_FLASH_OFF:
+ case KSCAMERA_EXTENDEDPROP_FLASH_ON:
+ case KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER:
+ case KSCAMERA_EXTENDEDPROP_FLASH_AUTO:
+ case KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER:
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ // Validate red eye reduction, single flash & multiflash supported.
+ if( !(pFlash->Flags &
+ ( KSCAMERA_EXTENDEDPROP_FLASH_REDEYEREDUCTION |
+ KSCAMERA_EXTENDEDPROP_FLASH_SINGLEFLASH |
+ KSCAMERA_EXTENDEDPROP_FLASH_MULTIFLASHSUPPORTED )) ||
+ (pFlash->Flags & KSCAMERA_EXTENDEDPROP_FLASH_MODE_MASK) != KSCAMERA_EXTENDEDPROP_FLASH_OFF )
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ // Validate Flash Assistant parameters
+ switch( pFlash->Flags & KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_MASK )
+ {
+ // Valid combinations
+ case KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_OFF:
+ case KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_ON:
+ case KSCAMERA_EXTENDEDPROP_FLASH_ASSISTANT_AUTO:
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+ }
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ Status = m_Sensor->SetExtendedFlash( pFlash );
+ }
+
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pFlash->PinId, pFlash->Flags, pFlash->Capability, Status );
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_OPTIMIZATIONHINT
+NTSTATUS
+CCaptureFilter::
+GetOptimizationHint(
+ _Inout_ CExtendedProperty *pHint
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pHint->isValid() &&
+ !(pHint->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pHint->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetOptimizationHint(pHint);
+ }
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pHint->PinId, pHint->Flags, pHint->Capability, Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_OPTIMIZATIONHINT
+NTSTATUS
+CCaptureFilter::
+SetOptimizationHint(
+ _In_ CExtendedProperty *pHint
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pHint->isValid() &&
+ !(pHint->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pHint->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ CExtendedProperty Caps(*pHint);
+ Status = m_Sensor->GetOptimizationHint(&Caps);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pHint->Flags == (pHint->Flags & Caps.Capability) )
+ {
+ // Inherit the previous primary use flag settings, if they were not set here.
+ if( KSCAMERA_EXTENDEDPROP_OPTIMIZATION_DEFAULT == pHint->Flags ||
+ 0 == (pHint->Flags & KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PRIMARYUSE_MASK) )
+ {
+ pHint->Flags |= (Caps.Flags & KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PRIMARYUSE_MASK);
+ }
+ else
+ {
+ // Inherit the previous perf flag settings, if they were not set here and if DEFAULT is not set.
+ if( 0 == (pHint->Flags & KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PERF_MASK) )
+ {
+ pHint->Flags |= (Caps.Flags & KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PERF_MASK);
+ }
+ }
+
+ // Make sure the requested flags are a valid capability combination.
+ switch( pHint->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO:
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO | KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY:
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO | KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY:
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO | KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO:
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO | KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY:
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO | KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY:
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO | KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_PHOTO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_QUALITY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER :
+ case KSCAMERA_EXTENDEDPROP_OPTIMIZATION_VIDEO |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_LATENCY |
+ KSCAMERA_EXTENDEDPROP_OPTIMIZATION_POWER :
+ Status = m_Sensor->SetOptimizationHint(pHint);
+ break;
+ }
+ }
+ }
+ }
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pHint->PinId, pHint->Flags, pHint->Capability, Status );
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FIELDOFVIEW
+NTSTATUS
+CCaptureFilter::
+GetFieldOfView(
+ _Inout_ CExtendedFieldOfView *pFieldOfView
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFieldOfView->isValid() &&
+ pFieldOfView->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetFieldOfView(pFieldOfView);
+ }
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_CAMERAANGLEOFFSET
+NTSTATUS
+CCaptureFilter::
+GetCameraAngleOffset(
+ _Inout_ CExtendedCameraAngleOffset *pAngleOffset
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pAngleOffset->isValid() &&
+ pAngleOffset->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetCameraAngleOffset(pAngleOffset);
+ }
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_METADATA
+NTSTATUS
+CCaptureFilter::
+GetMetadata(
+ _Inout_ CExtendedMetadata *pMetadata
+)
+{
+ PAGED_CODE();
+
+ if( pMetadata->PinId >= m_Sensor->GetPinCount() )
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return m_Sensor->GetMetadata( pMetadata );
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_METADATA
+NTSTATUS
+CCaptureFilter::
+SetMetadata(
+ _In_ CExtendedMetadata *pMetadata
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( !(pMetadata->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pMetadata->isValid() &&
+ m_Sensor->IsValidIndex( pMetadata->PinId ) )
+ {
+ if( m_pinArray[pMetadata->PinId] &&
+ m_pinArray[pMetadata->PinId]->GetState() == PinRunning )
+ {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ else
+ {
+ Status = m_Sensor->SetMetadata( pMetadata );
+ }
+ }
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_ISO
+NTSTATUS
+CCaptureFilter::
+GetIso(
+ _Inout_ CExtendedProperty *pIso
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pIso->isValid() &&
+ m_Sensor->IsStillIndex( pIso->PinId ) )
+ {
+ Status = m_Sensor->GetIso(pIso);
+ }
+
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pIso->PinId, pIso->Flags, pIso->Capability, Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_ISO
+NTSTATUS
+CCaptureFilter::
+SetIso(
+ _In_ CExtendedProperty *pIso
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("(Flags=0x%016llX)", pIso->Flags);
+
+ if( (pIso->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pIso->isValid() &&
+ m_Sensor->IsStillIndex( pIso->PinId ) )
+ {
+ CExtendedProperty Caps;
+ Status = m_Sensor->GetIso( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pIso->Flags == (pIso->Flags & Caps.Capability) )
+ {
+ // Make sure only one preset was set.
+ ULONGLONG presets = pIso->Flags &
+ ( KSCAMERA_EXTENDEDPROP_ISO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ISO_50 | KSCAMERA_EXTENDEDPROP_ISO_80 |
+ KSCAMERA_EXTENDEDPROP_ISO_100 | KSCAMERA_EXTENDEDPROP_ISO_200 |
+ KSCAMERA_EXTENDEDPROP_ISO_400 | KSCAMERA_EXTENDEDPROP_ISO_800 |
+ KSCAMERA_EXTENDEDPROP_ISO_1600 | KSCAMERA_EXTENDEDPROP_ISO_3200 |
+ KSCAMERA_EXTENDEDPROP_ISO_6400 | KSCAMERA_EXTENDEDPROP_ISO_12800 |
+ KSCAMERA_EXTENDEDPROP_ISO_25600 ) ;
+
+ DBG_TRACE("presets=0x%016llX", presets);
+
+ // Check to see if there is exactly one set.
+ if( presets && ( (presets-1) & presets ) == 0 )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, Iso, pIso, m_IsoNotifier );
+ }
+ }
+ }
+ }
+
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pIso->PinId, pIso->Flags, pIso->Capability, Status );
+
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION
+NTSTATUS
+CCaptureFilter::
+GetEvCompensation(
+ _Inout_ CExtendedEvCompensation *pEvComp
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pEvComp->isValid() &&
+ pEvComp->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetEvCompensation( pEvComp );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION
+NTSTATUS
+CCaptureFilter::
+SetEvCompensation(
+ _In_ CExtendedEvCompensation *pEvComp
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+ if( (pEvComp->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pEvComp->isValid() &&
+ pEvComp->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ CExtendedEvCompensation Caps;
+ Status = m_Sensor->GetEvCompensation( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( (pEvComp->Flags & Caps.Capability ) == pEvComp->Flags )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, EvCompensation, pEvComp, m_EvCompensationNotifier );
+ }
+ }
+ }
+
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX)=0x%08X",
+ pEvComp->PinId, pEvComp->Flags, pEvComp->Capability, Status );
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+NTSTATUS
+CCaptureFilter::
+GetWhiteBalance(
+ _Inout_ CExtendedVidProcSetting *pWhiteBalance
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pWhiteBalance->isValid() &&
+ pWhiteBalance->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetWhiteBalance( pWhiteBalance );
+ }
+
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX, Mode=0x%08X, Val=0x%016llX)=0x%08X",
+ pWhiteBalance->PinId, pWhiteBalance->Flags, pWhiteBalance->Capability,
+ pWhiteBalance->Mode(), pWhiteBalance->GetLONGLONG(), Status );
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+NTSTATUS
+CCaptureFilter::
+SetWhiteBalance(
+ _In_ CExtendedVidProcSetting *pWhiteBalance
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+ if( (pWhiteBalance->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pWhiteBalance->isValid() &&
+ pWhiteBalance->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ CExtendedVidProcSetting Caps;
+ Status = m_Sensor->GetWhiteBalance( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ if( (pWhiteBalance->Flags & Caps.Capability ) == pWhiteBalance->Flags )
+ {
+ switch( pWhiteBalance->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO:
+ break;
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ pWhiteBalance->Flags = KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO | KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK;
+ break;
+
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL:
+ switch( pWhiteBalance->Mode() )
+ {
+ case KSCAMERA_EXTENDEDPROP_WHITEBALANCE_TEMPERATURE:
+ Status = Caps.BoundsCheck( pWhiteBalance->GetLONGLONG() );
+ break;
+
+ case KSCAMERA_EXTENDEDPROP_WHITEBALANCE_PRESET:
+ switch( pWhiteBalance->GetLONGLONG() )
+ {
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_CLOUDY:
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_DAYLIGHT:
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_FLASH:
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_FLUORESCENT:
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_TUNGSTEN:
+ case KSCAMERA_EXTENDEDPROP_WBPRESET_CANDLELIGHT:
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, WhiteBalance, pWhiteBalance, m_WhiteBalanceNotifier );
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ DBG_LEAVE("(PinId=%d, Flags=0x%016llX, Cap=0x%016llX, Mode=0x%08X, Val=0x%016llX)=0x%08X",
+ pWhiteBalance->PinId, pWhiteBalance->Flags, pWhiteBalance->Capability,
+ pWhiteBalance->Mode(), pWhiteBalance->GetLONGLONG(), Status );
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE
+NTSTATUS
+CCaptureFilter::
+GetExposure(
+ _Inout_ CExtendedVidProcSetting *pExposure
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pExposure->isValid() &&
+ pExposure->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetExposure( pExposure );
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE
+NTSTATUS
+CCaptureFilter::
+SetExposure(
+ _In_ CExtendedVidProcSetting *pExposure
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+ if( (pExposure->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pExposure->isValid() &&
+ pExposure->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ CExtendedVidProcSetting Caps;
+ Status = m_Sensor->GetExposure( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ if( (pExposure->Flags & Caps.Capability ) == pExposure->Flags )
+ {
+ if( pExposure->Flags == KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Status = Caps.BoundsCheck( pExposure->GetULONGLONG() );
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, Exposure, pExposure, m_ExposureNotifier );
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+NTSTATUS
+CCaptureFilter::
+GetFocus(
+ _Inout_ CExtendedVidProcSetting *pFocus
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pFocus->isValid() &&
+ pFocus->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetFocus( pFocus );
+ }
+
+ DBG_LEAVE("(FocusMode=0x%016llX)=0x%08X", pFocus->Flags, Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+NTSTATUS
+CCaptureFilter::
+SetFocus(
+ _In_ CExtendedVidProcSetting *pFocus
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+ ULONGLONG Flags = pFocus->Flags;
+
+ DBG_ENTER("(Preset Flags=0x%016llX)", Flags);
+
+ CExtendedVidProcSetting Caps(*pFocus);
+
+ // This part is just setting validation.
+ if( (pFocus->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pFocus->isValid() &&
+ pFocus->Mode() == 0 &&
+ pFocus->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetFocus( &Caps );
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Make sure we have a valid combinations of Flags
+ switch( Flags &
+ (KSCAMERA_EXTENDEDPROP_FOCUS_MODE_MASK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_MODE_ADVANCED_MASK) )
+ {
+ // Auto-focus combinations:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ break;
+
+ // Continuous-focus combinations:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUSLOCK |
+ KSCAMERA_EXTENDEDPROP_FOCUS_REGIONBASED |
+ KSCAMERA_EXTENDEDPROP_FOCUS_DRIVERFALLBACK_OFF:
+ break;
+
+ // Manual stands alone.
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL:
+ Status = BoundsCheckSigned(
+ pFocus->GetLONG(),
+ Caps.m_Setting );
+
+ if( !NT_SUCCESS(Status) )
+ {
+ DBG_TRACE( "ERROR: Focus request out of bounds. Value=%d", pFocus->GetLONG() );
+ }
+ break;
+
+ // Unlock must stand alone.
+ // Also note that by definition unlock is accepted regardless of our current state.
+ case KSCAMERA_EXTENDEDPROP_FOCUS_UNLOCK:
+ break;
+
+ // Lock can stand alone.
+ case KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK:
+ // Make sure we are actually being asked during an auto or continuous.
+ if( !(Caps.Flags &
+ (KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO | KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS)) )
+ {
+ // This is an ambiguous case under the WinBlue DDI. However,
+ // producing an error code here will cause a test failure.
+ // Instead we will silently consume the error and just skip this
+ // request.
+ //
+ // Actually the WinBlue WinRT layer interprets a "Manual Preset" as
+ // a LOCK-only request when there is no value involved. That is kind
+ // rediculous since the value is sent without considering the previous
+ // mode. Instead, it thinks that just setting a LOCK-only mode is
+ // synonymous with "Manual at the current position."
+ //
+ // Therefore, our interpretation will be, If we're in manual, we can
+ // just silently consume the entire request and do nothing.
+ if( Caps.Flags & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Status = STATUS_INVALID_LOCK_SEQUENCE;
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+
+ // Anything else is just wrong.
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ // Validate focus ranges.
+ if( NT_SUCCESS(Status) )
+ {
+ // If AUTO or CONTINUOUS is requested, we may support RANGE flags.
+ if( (Flags &
+ (KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO |
+ KSCAMERA_EXTENDEDPROP_FOCUS_CONTINUOUS)) )
+ {
+ switch( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MASK )
+ {
+ case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MACRO:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_NORMAL:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_FULLRANGE:
+ // Depreciated flags are not supported:
+ //case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_INFINITY:
+ //case KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_HYPERFOCAL:
+ case 0:
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ // Otherwise no RANGE flags are permitted.
+ else if( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_RANGE_MASK )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ // Validate focus distances.
+ if( NT_SUCCESS(Status) )
+ {
+ // If MANUAL is requested, we may support DISTANCE flags.
+ if( Flags & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ switch( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_MASK )
+ {
+ case KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_INFINITY:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_HYPERFOCAL:
+ case KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_NEAREST:
+ case 0:
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ // Otherwise no DISTANCE flags are permitted.
+ else if( Flags & KSCAMERA_EXTENDEDPROP_FOCUS_DISTANCE_MASK )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, Focus, pFocus, m_FocusNotifier );
+ }
+ // This is the failure case. In this case, we don't change state; but
+ // if we were ASYNC, we need to signal the client that we completed.
+ else
+ {
+ // Don't need to set the event if this was [erroneously] an sync request.
+ if( pFocus->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL )
+ {
+ m_FocusNotifier.Set();
+ }
+
+ // Silently consume Lock after Manual requests:
+ if( STATUS_INVALID_LOCK_SEQUENCE == Status )
+ {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ DBG_LEAVE("(Preset Flags=0x%016llX)=0x%08X", Flags, Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOCONFIRMATION
+NTSTATUS
+CCaptureFilter::
+GetPhotoConfirmation(
+ _Inout_ CExtendedProperty *pConfirmation
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pConfirmation->isValid() &&
+ pConfirmation->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetPhotoConfirmation( pConfirmation );
+ }
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOCONFIRMATION
+NTSTATUS
+CCaptureFilter::
+SetPhotoConfirmation(
+ _In_ CExtendedProperty *pConfirmation
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( !(pConfirmation->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ pConfirmation->isValid() &&
+ pConfirmation->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ switch( pConfirmation->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_PHOTOCONFIRMATION_ON:
+ case KSCAMERA_EXTENDEDPROP_PHOTOCONFIRMATION_OFF:
+ Status = m_Sensor->SetPhotoConfirmation( pConfirmation );
+ break;
+ }
+ }
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_CAPABILITY
+NTSTATUS
+CCaptureFilter::GetPFSCaps(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+)
+{
+ PAGED_CODE();
+
+ NT_ASSERT(pIrp);
+ NT_ASSERT(pProperty);
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(KsGetFilterFromIrp(pIrp)->Context);
+ PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+ ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ ULONG RequiredLength = 0;
+
+ NTSTATUS Status =
+ pFilter->m_Sensor->GetPfsCaps( nullptr, &RequiredLength );
+
+ // Note: We may want to determine capabilities at runtime in the future.
+
+ // We only handle GETs
+ if( NT_SUCCESS(Status) )
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ pIrp->IoStatus.Information = RequiredLength;
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (ulOutputBufferLength < RequiredLength)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else if (pData && ulOutputBufferLength >= RequiredLength)
+ {
+ Status =
+ pFilter->m_Sensor->GetPfsCaps(
+ (KSCAMERA_PERFRAMESETTING_CAP_HEADER *) pData,
+ &RequiredLength );
+ pIrp->IoStatus.Information = RequiredLength;
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_SET
+NTSTATUS
+CCaptureFilter::GetPerFrameSettings(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+)
+{
+ PAGED_CODE();
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ NT_ASSERT(pIrp);
+ NT_ASSERT(pProperty);
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(KsGetFilterFromIrp(pIrp)->Context);
+ PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+ ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ ULONG ulOutputSize =
+ pFilter->m_pPerFrameSettings ? pFilter->m_pPerFrameSettings->Size : 0;
+
+ // Only handle GETs
+ if (ulOutputBufferLength == 0)
+ {
+ pIrp->IoStatus.Information = ulOutputSize;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (ulOutputBufferLength < ulOutputSize)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else if (pData && ulOutputBufferLength >= ulOutputSize)
+ {
+ // Return the cached copy.
+ RtlCopyMemory( pData, pFilter->m_pPerFrameSettings, ulOutputSize );
+ pIrp->IoStatus.Information = ulOutputSize;
+ ntStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+
+ return ntStatus;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_SET
+NTSTATUS
+CCaptureFilter::
+SetPerFrameSettings(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ NT_ASSERT(pIrp);
+ NT_ASSERT(pProperty);
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(KsGetFilterFromIrp(pIrp)->Context);
+ PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+ ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ // Only handle SETs
+ if (ulOutputBufferLength == 0)
+ {
+ // This is pretty meaningless.
+ // We can't really tell the caller the size of this buffer.
+ pIrp->IoStatus.Information =
+ sizeof(KSCAMERA_PERFRAMESETTING_HEADER) +
+ sizeof(KSCAMERA_PERFRAMESETTING_FRAME_HEADER) +
+ sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) ;
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_PERFRAMESETTING_HEADER))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ PKSCAMERA_PERFRAMESETTING_HEADER pPFS =
+ (PKSCAMERA_PERFRAMESETTING_HEADER) pData ;
+ ISP_FRAME_SETTINGS *pSettings = nullptr;
+
+ // Parse, but don't save the PerFrameSettings
+ Status = pFilter->ParsePFSBuffer( pPFS, ulOutputBufferLength, &pSettings );
+
+ // Cache a copy of the unparsed PFS for the GET.
+ // Pass the parsed settings down to the sensor.
+ if( NT_SUCCESS(Status) )
+ {
+ delete [] ((PBYTE) pFilter->m_pPerFrameSettings);
+ pFilter->m_pPerFrameSettings = (PKSCAMERA_PERFRAMESETTING_HEADER)
+ new (PagedPool, '-SFP') BYTE [pPFS->Size];
+
+ if( pFilter->m_pPerFrameSettings )
+ {
+ // Cache a copy of the settings for the GET.
+ RtlCopyMemory( pFilter->m_pPerFrameSettings, pPFS, pPFS->Size );
+
+ // Program the sensor with a copy of the parsed settings.
+ // The sensor object should copy what it needs.
+ pFilter->m_Sensor->SetPFS( pSettings, pPFS->FrameCount, pPFS->LoopCount );
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ // Delete the settings buffer ParsePFSBuffer created.
+ delete [] pSettings;
+ }
+
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_PERFRAMESETTING_CLEAR
+NTSTATUS
+CCaptureFilter::ClearPerFrameSettings(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+)
+{
+ PAGED_CODE();
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ NT_ASSERT(pIrp);
+ NT_ASSERT(pProperty);
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(KsGetFilterFromIrp(pIrp)->Context);
+
+ // Only handle SETs
+ delete [] ((PBYTE) pFilter->m_pPerFrameSettings);
+ pFilter->m_pPerFrameSettings = nullptr;
+ pFilter->m_Sensor->SetPFS( nullptr, 0, 0 );
+
+ return ntStatus;
+}
+
+PKSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER
+Find(
+ _In_ PKSCAMERA_PERFRAMESETTING_CAP_HEADER Caps,
+ _In_ ULONG Type
+)
+/*++
+
+Routine Description:
+
+ Helper function that finds a specific PFS capability.
+
+Arguments:
+
+ Caps -
+ A list of PFS capabilities.
+ Type -
+ The capability type to search for.
+
+Return Value:
+
+ A pointer to the capability item header.
+
+--*/
+{
+ PAGED_CODE();
+
+ if( Caps )
+ {
+ PKSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER Item =
+ (PKSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER) (Caps+1);
+
+ for( ULONG i=0; i<Caps->ItemCount; i++ )
+ {
+ if( Item->Type == Type )
+ {
+ return Item;
+ }
+ Item = (PKSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER) (((PBYTE) Item) + Item->Size);
+ }
+ }
+ return nullptr;
+}
+
+// This function can be used to validate PerFrameSettings, or
+// it can be used to populate a buffer containing PFS settings.
+_Success_(return == 0)
+NTSTATUS
+CCaptureFilter::
+ParsePFSBuffer(
+ _In_reads_bytes_(BufferLimit)
+ PKSCAMERA_PERFRAMESETTING_HEADER pPFS,
+ _In_ ULONG BufferLimit,
+ _Outptr_opt_result_maybenull_
+ ISP_FRAME_SETTINGS **ppSettings
+)
+/*++
+
+Routine Description:
+
+ Helper function that parses Per-Frame Settings.
+
+ This function validates the API's PerFrameSettings list and optionally
+ returns an array of ISP_FRAME_SETTINGS for each frame.
+
+ Any returned array of ISP_FRAME_SETTINGS must be deleted by the caller.
+
+Arguments:
+
+ pPFS -
+ A variable length list of per frame settings.
+ BufferLimit -
+ The maximum amount of space, in bytes, used by the PFS list.
+ ppSettings -
+ An optional pointer to an array of frame settings to be populated.
+
+Return Value:
+
+ Success / failure
+
+--*/
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ DBG_ENTER("[%S]()", GetFilterName());
+
+ NT_ASSERT(pPFS);
+ NT_ASSERT(BufferLimit!=0);
+
+ if( !pPFS ||
+ BufferLimit == 0 ||
+ pPFS->Size > BufferLimit ||
+ pPFS->Size < sizeof(KSCAMERA_PERFRAMESETTING_HEADER) ||
+ pPFS->LoopCount!=1 || // Hard-coded to 1, per spec.
+ pPFS->FrameCount > MAX_FRAME_COUNT ||
+ pPFS->FrameCount == 0 )
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ ULONG i=0 ;
+ ISP_FRAME_SETTINGS *pSettings = nullptr;
+ LPVOID pEnd = ((LPBYTE) pPFS) + BufferLimit ;
+ PKSCAMERA_PERFRAMESETTING_FRAME_HEADER pFrame =
+ (PKSCAMERA_PERFRAMESETTING_FRAME_HEADER) &pPFS[1];
+
+ // Make sure we have at least one frame in the array.
+ ULONG FrameCount = pPFS->FrameCount ? pPFS->FrameCount : 1 ;
+
+ // Query the PFS Caps from the Sensor
+ PKSCAMERA_PERFRAMESETTING_CAP_HEADER Caps = nullptr;
+ ULONG RequiredSize = 0;
+ Status = m_Sensor->GetPfsCaps( nullptr, &RequiredSize );
+
+ if( NT_SUCCESS(Status) )
+ {
+ Caps = (PKSCAMERA_PERFRAMESETTING_CAP_HEADER) new (PagedPool, '-SFP') BYTE[RequiredSize];
+
+ if( Caps )
+ {
+ RtlZeroMemory( Caps, RequiredSize );
+ Status = m_Sensor->GetPfsCaps( Caps, &RequiredSize );
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Allocate an array
+ pSettings = new (NonPagedPoolNx, '-SFP') ISP_FRAME_SETTINGS[FrameCount];
+ if( !pSettings )
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ // Initialize the array to our globals
+ pSettings[0] = *m_Sensor->GetGlobalIspSettings();
+ for( i=1; i<FrameCount; i++ )
+ {
+ pSettings[i] = pSettings[0];
+ }
+
+ while( ((pFrame+1)<=pEnd) )
+ {
+ PKSCAMERA_PERFRAMESETTING_FRAME_HEADER pNextFrame =
+ (PKSCAMERA_PERFRAMESETTING_FRAME_HEADER)
+ (((LPBYTE)pFrame) + pFrame->Size);
+ PKSCAMERA_PERFRAMESETTING_ITEM_HEADER pItem =
+ (PKSCAMERA_PERFRAMESETTING_ITEM_HEADER) &pFrame[1];
+
+ // Verify that the frame is within the buffer.
+ if( pFrame->Id >= pPFS->FrameCount ||
+ pNextFrame > pEnd ||
+ pFrame->Size < sizeof(KSCAMERA_PERFRAMESETTING_FRAME_HEADER) )
+ {
+ DBG_TRACE( "Malformed PFS Buffer. pPFS=%p pFrame=%p",
+ pPFS, pFrame );
+
+ Status=STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ DBG_TRACE("Frame Id=%d",pFrame->Id);
+
+ ISP_FRAME_SETTINGS &FrameSetting = pSettings[pFrame->Id] ;
+
+ // Scan for at most n Items regardless.
+ for( i=0;
+ i < pFrame->ItemCount &&
+ (pItem+1) <= (PVOID)pNextFrame;
+ i++ )
+ {
+ PKSCAMERA_PERFRAMESETTING_ITEM_HEADER pNextItem =
+ (PKSCAMERA_PERFRAMESETTING_ITEM_HEADER)
+ (((LPBYTE)pItem) + pItem->Size);
+
+ PKSCAMERA_PERFRAMESETTING_CAP_ITEM_HEADER ItemCap =
+ Find( Caps, pItem->Type );
+
+ // Verify that the item is within the frame ...
+ // ... and a supported capability.
+ if( pNextItem>(LPVOID)pNextFrame ||
+ pItem->Size<sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) ||
+ !ItemCap )
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ switch( pItem->Type )
+ {
+ case KSCAMERA_PERFRAMESETTING_ITEM_EXPOSURE_TIME:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_EXPOSURE_TIME");
+
+ FrameSetting.ExposureMode =
+ TranslatePFS2VideoProcFlags( pItem->Flags );
+
+ if( pItem->Flags & KSCAMERA_PERFRAMESETTING_MANUAL )
+ {
+ if( pItem->Size==
+ sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER)+
+ sizeof(KSCAMERA_EXTENDEDPROP_VALUE) )
+ {
+ FrameSetting.ExposureSetting.VideoProc.Value =
+ ((PKSCAMERA_EXTENDEDPROP_VALUE) &(pItem[1]))->Value;
+ // Make sure the setting is in range.
+ Status =
+ BoundsCheckSigned(
+ FrameSetting.ExposureSetting.VideoProc.Value.ll,
+ ((SOC_CAP_WITH_STEPPING_LONGLONG *) ItemCap)->Stepping );
+ DBG_TRACE("Status=0x%08X, ExposureMode=KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL, ExposureTime=%lldns, element=%d",
+ Status, FrameSetting.ExposureSetting.VideoProc.Value.ll, i);
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ DBG_TRACE("Status=STATUS_INVALID_PARAMETER");
+ }
+ }
+ else if( pItem->Size!=sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) )
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ DBG_TRACE("Status=STATUS_INVALID_PARAMETER");
+ }
+ break;
+
+ case KSCAMERA_PERFRAMESETTING_ITEM_FLASH:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_FLASH");
+ FrameSetting.FlashMode = pItem->Flags;
+ if( pItem->Flags &
+ (KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER |
+ KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER) )
+ {
+ if( pItem->Size==
+ sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER)+
+ sizeof(KSCAMERA_EXTENDEDPROP_VALUE) )
+ {
+ FrameSetting.FlashValue =
+ ((PKSCAMERA_EXTENDEDPROP_VALUE) &(pItem[1]))->Value.ul;
+
+ // Make sure the setting is in range.
+ if( FrameSetting.FlashValue > 100 )
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ DBG_TRACE("FlashPower (%d%) accepted...", FrameSetting.FlashValue);
+ }
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ }
+ else if( pItem->Size!=sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) )
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+
+ if( NT_SUCCESS(Status) )
+ {
+ DBG_TRACE("FlashMode=0x%016llX, FlashPower=%d", FrameSetting.FlashMode, FrameSetting.FlashValue);
+ }
+ break;
+
+ case KSCAMERA_PERFRAMESETTING_ITEM_EXPOSURE_COMPENSATION:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_EXPOSURE_COMPENSATION");
+ {
+ LONG Denominator = EVFlags2Denominator( pItem->Flags );
+ KSPROPERTY_STEPPING_LONG
+ Bounds = ((SOC_CAP_WITH_STEPPING *) ItemCap)->Stepping;
+
+ // Adjust the bounds for the step size... (A quirk of EV)
+ Bounds.Bounds.SignedMinimum *= Denominator;
+ Bounds.Bounds.SignedMaximum *= Denominator;
+
+ FrameSetting.EVCompensation.Mode = (ULONG)
+ pItem->Flags & ~(KSCAMERA_PERFRAMESETTING_AUTO);
+
+ // Validate manual setting
+ if( (pItem->Flags != KSCAMERA_PERFRAMESETTING_AUTO) )
+ {
+ if( pItem->Size==
+ sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER)+
+ sizeof(KSCAMERA_EXTENDEDPROP_VALUE) &&
+ (Denominator != 0) )
+ {
+ FrameSetting.EVCompensation.Value =
+ ((PKSCAMERA_EXTENDEDPROP_VALUE) &(pItem[1]))->Value.l;
+
+ // Make sure the setting is in range.
+ Status =
+ BoundsCheckSigned(
+ FrameSetting.EVCompensation.Value,
+ Bounds );
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ }
+ // Auto can be the only flag, if auto is enabled.
+ else //if( pItem->Flags == KSCAMERA_PERFRAMESETTING_AUTO )
+ {
+ if( pItem->Size==sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) )
+ {
+ static
+ ULONG step[] =
+ {
+ 0,
+ KSCAMERA_EXTENDEDPROP_EVCOMP_FULLSTEP, //1
+ KSCAMERA_EXTENDEDPROP_EVCOMP_HALFSTEP, //2
+ KSCAMERA_EXTENDEDPROP_EVCOMP_THIRDSTEP, //3
+ KSCAMERA_EXTENDEDPROP_EVCOMP_QUARTERSTEP, //4
+ 0, //5
+ KSCAMERA_EXTENDEDPROP_EVCOMP_SIXTHSTEP //6
+ };
+
+ // Work back from the randomly selected denominator ...
+ /// ... to the step flag.
+ FrameSetting.EVCompensation.Mode = step[Denominator];
+
+ // Now pick a "random" numerator that is in range.
+ FrameSetting.EVCompensation.Value = (LONG)
+ GetRandom( Bounds.Bounds.SignedMinimum,
+ Bounds.Bounds.SignedMaximum );
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+ break;
+
+ case KSCAMERA_PERFRAMESETTING_ITEM_ISO:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_ISO: Flags=0x%016llX", pItem->Flags);
+
+ FrameSetting.ISOMode = pItem->Flags;
+ // Handle Auto.
+ if( pItem->Flags == KSCAMERA_EXTENDEDPROP_ISO_AUTO )
+ {
+ if( pItem->Size==sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) )
+ {
+ FrameSetting.ISOValue = 0;
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ }
+ // Handle manual settings.
+ else if( pItem->Flags == KSCAMERA_EXTENDEDPROP_ISO_MANUAL )
+ {
+ if( pItem->Size==
+ sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER)+
+ sizeof(KSCAMERA_EXTENDEDPROP_VALUE) )
+ {
+ FrameSetting.ISOValue =
+ ((PKSCAMERA_EXTENDEDPROP_VALUE) &(pItem[1]))->Value.ul;
+ // Make sure the setting is in range.
+ Status =
+ BoundsCheckUnsigned(
+ FrameSetting.ISOValue,
+ ((SOC_CAP_WITH_STEPPING *)ItemCap)->Stepping );
+
+ DBG_TRACE("ISOValue=%d", FrameSetting.ISOValue);
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ break;
+
+ case KSCAMERA_PERFRAMESETTING_ITEM_FOCUS:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_FOCUS");
+ if( pItem->Flags == KSCAMERA_PERFRAMESETTING_MANUAL )
+ {
+ if( pItem->Size==
+ sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER)+
+ sizeof(KSCAMERA_EXTENDEDPROP_VALUE) )
+ {
+ FrameSetting.FocusMode =
+ KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL;
+ FrameSetting.FocusSetting.VideoProc =
+ *((PKSCAMERA_EXTENDEDPROP_VALUE) &(pItem[1]));
+ // Make sure the setting is in range.
+ Status =
+ BoundsCheckUnsigned(
+ FrameSetting.FocusSetting.VideoProc.Value.ul,
+ ((SOC_CAP_WITH_STEPPING *)ItemCap)->Stepping );
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ break;
+
+ case KSCAMERA_PERFRAMESETTING_ITEM_PHOTOCONFIRMATION:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_PHOTOCONFIRMATION");
+
+ if( pItem->Size!=sizeof(KSCAMERA_PERFRAMESETTING_ITEM_HEADER) )
+ {
+ Status=STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ switch( pItem->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_PHOTOCONFIRMATION_ON:
+ FrameSetting.bPhotoConfirmation = TRUE;
+ DBG_TRACE("PFS Photo Confirmation ON for frame #%d", pFrame->Id);
+ break;
+
+ case KSCAMERA_EXTENDEDPROP_PHOTOCONFIRMATION_OFF:
+ FrameSetting.bPhotoConfirmation = FALSE;
+ DBG_TRACE("PFS Photo Confirmation OFF for frame #%d", pFrame->Id);
+ break;
+
+ default:
+ Status=STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ break;
+
+ case KSCAMERA_PERFRAMESETTING_ITEM_CUSTOM:
+ DBG_TRACE("KSCAMERA_PERFRAMESETTING_ITEM_CUSTOM");
+ break;
+
+ default:
+ // We don't understand this item. Do nothing.
+ NT_ASSERT(FALSE);
+ break;
+ }
+
+ // Bail here (a little early) if any of the parsing failed.
+ if( !NT_SUCCESS(Status) )
+ {
+ break;
+ }
+
+ // Move to the next Item
+ pItem = pNextItem;
+ }
+
+ // Bail here (a little early) if any of the parsing failed.
+ if( !NT_SUCCESS(Status) )
+ {
+ DBG_TRACE( "Malformed PFS Buffer. pPFS=%p pItem=%p",
+ pPFS, pItem );
+ break;
+ }
+
+ // Move to next Frame
+ pFrame = pNextFrame;
+ }
+
+ // We need to log where in the buffer we encountered an error.
+ // For now we just emit info to the debugger.
+ }
+
+ if( NT_SUCCESS(Status) && ppSettings )
+ {
+ *ppSettings = pSettings;
+ }
+ else
+ {
+ delete [] pSettings;
+ }
+ }
+
+ delete [] ((PBYTE) Caps);
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSSTATE
+NTSTATUS
+CCaptureFilter::GetFocusState(
+ _Inout_ CExtendedProperty *pState
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pState->isValid() &&
+ pState->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ KSCAMERA_EXTENDEDPROP_FOCUSSTATE FocusState = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_UNINITIALIZED;
+ Status = m_Sensor->GetFocusState( &FocusState );
+ if( NT_SUCCESS(Status) )
+ {
+ *pState = CExtendedProperty( (ULONGLONG) FocusState );
+ pState->Capability = 0;
+ }
+ }
+ DBG_LEAVE("(PinId=%u, Flags=0x%016llX, Version=%u)=0x%08X",
+ pState->PinId, pState->Flags, pState->Version, Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSPRIORITY
+NTSTATUS
+CCaptureFilter::
+GetFocusPriority(
+ _Inout_ CExtendedProperty *pPriority
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pPriority->isValid() &&
+ pPriority->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetFocusPriority( pPriority );
+ }
+ DBG_LEAVE("(PinId=%u, Flags=0x%016llX, Version=%u)=0x%08X",
+ pPriority->PinId, pPriority->Flags, pPriority->Version, Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSPRIORITY
+NTSTATUS
+CCaptureFilter::
+SetFocusPriority(
+ _In_ CExtendedProperty *pPriority
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pPriority->isValid() &&
+ pPriority->Capability == 0 &&
+ pPriority->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ (pPriority->Flags & ~KSCAMERA_EXTENDEDPROP_FOCUSPRIORITY_ON) == 0 )
+ {
+ Status = m_Sensor->SetFocusPriority( pPriority );
+ }
+ DBG_LEAVE("(PinId=%u, Flags=0x%016llX, Version=%u)=0x%08X",
+ pPriority->PinId, pPriority->Flags, pPriority->Version, Status);
+ return Status;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_CONFIGCAPS Get handler
+NTSTATUS
+CCaptureFilter::
+GetRoiConfigCaps(
+ _Inout_ CRoiConfig *pOutput
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pOutput->isValid() &&
+ pOutput->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetRoiConfigCaps( pOutput );
+ }
+ return Status;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL Get handler
+//
+// Note: ROI handlers are left as static member functions because
+// it wasn't worth the code needed to generalize handling of a
+// variable length parameter.
+NTSTATUS
+CCaptureFilter::
+GetRoiIspControl(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ NT_ASSERT(pIrp);
+ NT_ASSERT(pProperty);
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(KsGetFilterFromIrp(pIrp)->Context);
+ CSensor *pSensor = pFilter->m_Sensor;
+ PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+ ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ CRoiProperty *pRoi = (reinterpret_cast<CRoiProperty *>(pData));
+ ULONG RequiredSize = pSensor->SizeOfRoi();
+
+ // Only handle GETs
+ if( ulOutputBufferLength == 0 )
+ {
+ pIrp->IoStatus.Information = RequiredSize;;
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if( ulOutputBufferLength < RequiredSize )
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else if( pData )
+ {
+ Status = pSensor->GetRoi( pRoi );
+ if( NT_SUCCESS(Status) )
+ {
+ pIrp->IoStatus.Information = pRoi->GetSize();
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X",Status);
+ return Status;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL Set handler
+NTSTATUS
+CCaptureFilter::
+SetRoiIspControl(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+ NT_ASSERT(pIrp);
+ NT_ASSERT(pProperty);
+
+ CCaptureFilter *pFilter = reinterpret_cast <CCaptureFilter *>(KsGetFilterFromIrp(pIrp)->Context);
+ CSensor *pSensor = pFilter->m_Sensor;
+ PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+ ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ CRoiProperty *pRoi = (reinterpret_cast<CRoiProperty *>(pData));
+ ULONG RequiredSize = sizeof(*pRoi);
+
+ // Only handle SETs
+ if( ulOutputBufferLength == 0 )
+ {
+ // Minimum size for this control.
+ pIrp->IoStatus.Information = RequiredSize;
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if( ulOutputBufferLength < RequiredSize )
+ {
+ DBG_TRACE("***BUFFER TOO SMALL*** ulOutputBufferLength=%d, Size=%d",
+ ulOutputBufferLength, pRoi->Size );
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else if( pData && ulOutputBufferLength >= pRoi->Size )
+ {
+ // Validate the data blob.
+ if( pRoi->isValid() &&
+ pRoi->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pRoi->Flags == 0 )
+ {
+ Status = INVOKE_SET_ASYNC( pSensor, Roi, pRoi, pFilter->m_RoiNotifier );
+ }
+ }
+
+ DBG_LEAVE("()=0x%08X",Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED.
+NTSTATUS
+CCaptureFilter::
+GetIsoAdvanced(
+ _Inout_ CExtendedVidProcSetting *pIso
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pIso->isValid() &&
+ m_Sensor->IsStillIndex(pIso->PinId) )
+ {
+ Status = m_Sensor->GetIsoAdvanced( pIso );
+ }
+
+ // Report to the debug output...
+ DBG_TRACE(" Flags = 0x%016llX", pIso->Flags);
+ DBG_TRACE(" Min = %d", pIso->m_Setting.Min);
+ DBG_TRACE(" Max = %d", pIso->m_Setting.Max);
+ DBG_TRACE(" Step = %d", pIso->m_Setting.Step);
+ DBG_TRACE("VideoProc.Value = %lld", pIso->m_Setting.VideoProc.Value.ll);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED.
+NTSTATUS
+CCaptureFilter::
+SetIsoAdvanced(
+ _In_ CExtendedVidProcSetting *pIso
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ // Report to the debug output...
+ DBG_TRACE(" Flags = 0x%016llX", pIso->Flags);
+ DBG_TRACE(" Min = %d", pIso->m_Setting.Min);
+ DBG_TRACE(" Max = %d", pIso->m_Setting.Max);
+ DBG_TRACE(" Step = %d", pIso->m_Setting.Step);
+ DBG_TRACE("VideoProc.Value = %lld", pIso->m_Setting.VideoProc.Value.ll);
+
+ // Validate
+ switch( pIso->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_ISO_AUTO:
+ case KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION:
+ case KSCAMERA_EXTENDEDPROP_ISO_AUTO | KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION:
+ case KSCAMERA_EXTENDEDPROP_ISO_MANUAL:
+ case KSCAMERA_EXTENDEDPROP_ISO_MANUAL | KSCAMERA_EXTENDEDPROP_FLAG_CANCELOPERATION:
+ if( pIso->isValid() &&
+ (pIso->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ m_Sensor->IsStillIndex(pIso->PinId) )
+ {
+ CExtendedVidProcSetting Caps;
+ Status = m_Sensor->GetIsoAdvanced(&Caps);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Just save the parameters
+ if( pIso->Flags & KSCAMERA_EXTENDEDPROP_ISO_MANUAL )
+ {
+ Status = BoundsCheckSigned( pIso->GetLONGLONG(), Caps.m_Setting );
+ }
+ if( NT_SUCCESS(Status) )
+ {
+ Status = INVOKE_SET_ASYNC( m_Sensor, IsoAdvanced, pIso, m_IsoAdvancedNotifier )
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ break;
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_VFR.
+NTSTATUS
+CCaptureFilter::
+GetVFR(
+ _Inout_ CExtendedProperty *pVFR
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsVideoIndex(pVFR->PinId) &&
+ pVFR->isValid() )
+ {
+ //Get the current VFR state
+ Status = m_Sensor->GetVFR( pVFR );
+ }
+ DBG_LEAVE("PinId=%u, VideoIndex=%u, Flags=0x%016llX, Version=%u, Status=0x%08X",
+ pVFR->PinId, m_Sensor->GetNextVideoIndex(), pVFR->Flags, pVFR->Version, Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_VFR.
+NTSTATUS
+CCaptureFilter::
+SetVFR(
+ _In_ CExtendedProperty *pVFR
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsVideoIndex(pVFR->PinId) &&
+ pVFR->isValid() &&
+ pVFR->Capability == 0 &&
+ (KSCAMERA_EXTENDEDPROP_VFR_OFF == pVFR->Flags ||
+ KSCAMERA_EXTENDEDPROP_VFR_ON == pVFR->Flags ||
+ KSCAMERA_EXTENDEDPROP_VIDEOHDR_AUTO == pVFR->Flags ) )
+ {
+ //Set the current VFR state
+ Status = m_Sensor->SetVFR( pVFR );
+ }
+ DBG_LEAVE("PinId=%u, VideoIndex=%u, Flags=0x%016llX, Version=%u, Status=0x%08X",
+ pVFR->PinId, m_Sensor->GetNextVideoIndex(), pVFR->Flags, pVFR->Version, Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOHDR.
+NTSTATUS
+CCaptureFilter::
+GetVideoHDR(
+ _Inout_ CExtendedProperty *pVideoHDR
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsVideoIndex(pVideoHDR->PinId) &&
+ pVideoHDR->isValid() )
+ {
+ //Get the current Video HDR state
+ Status = m_Sensor->GetVideoHDR(pVideoHDR);
+ }
+ DBG_LEAVE("PinId=%u, VideoIndex=%u, Flags=0x%016llX, Version=%u, Status=0x%08X",
+ pVideoHDR->PinId, m_Sensor->GetNextVideoIndex(), pVideoHDR->Flags, pVideoHDR->Version, Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOHDR.
+NTSTATUS
+CCaptureFilter::
+SetVideoHDR(
+ _In_ CExtendedProperty *pVideoHDR
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ // Call must come for Video PIN only and flags must be supported and mutually exclusive and version must be 1
+ if( m_Sensor->IsVideoIndex(pVideoHDR->PinId) &&
+ pVideoHDR->isValid() &&
+ !(pVideoHDR->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ (KSCAMERA_EXTENDEDPROP_VIDEOHDR_OFF == pVideoHDR->Flags ||
+ KSCAMERA_EXTENDEDPROP_VIDEOHDR_ON == pVideoHDR->Flags ||
+ KSCAMERA_EXTENDEDPROP_VIDEOHDR_AUTO== pVideoHDR->Flags) )
+ {
+ if( !m_pinArray[pVideoHDR->PinId] ||
+ m_pinArray[pVideoHDR->PinId]->GetState() == PinStopped )
+ {
+ CExtendedProperty Caps(*pVideoHDR);
+ Status = m_Sensor->GetVideoHDR( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ // Call must come for Video PIN only and flags must be supported and mutually exclusive and version must be 1
+ if( pVideoHDR->Flags == (pVideoHDR->Flags & Caps.Capability) )
+ {
+ Status = m_Sensor->SetVideoHDR(pVideoHDR);
+ }
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ }
+
+ DBG_LEAVE("PinId=%u, VideoIndex=%u, Flags=0x%016llX, Version=%u, Status=0x%08X",
+ pVideoHDR->PinId, m_Sensor->GetNextVideoIndex(), pVideoHDR->Flags, pVideoHDR->Version, Status);
+ return Status;
+}
+
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_HISTOGRAM.
+NTSTATUS
+CCaptureFilter::
+GetHistogram(
+ _Inout_ CExtendedProperty *pHistogram
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsPreviewIndex(pHistogram->PinId) &&
+ pHistogram->isValid() &&
+ pHistogram->Capability == 0 )
+ {
+ //Get the histogram state
+ Status = m_Sensor->GetHistogram( pHistogram );
+ }
+ DBG_TRACE("pHistogram->PinId = %u, m_sensor->PreviewIndex = %u, pHistogram->Flags = %016llx, pHistogram->Version = %u",
+ pHistogram->PinId, m_Sensor->GetNextPreviewIndex(), pHistogram->Flags, pHistogram->Version);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_HISTOGRAM.
+NTSTATUS
+CCaptureFilter::
+SetHistogram(
+ _In_ CExtendedProperty *pHistogram
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsPreviewIndex(pHistogram->PinId) &&
+ pHistogram->isValid() &&
+ !(pHistogram->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ (KSCAMERA_EXTENDEDPROP_HISTOGRAM_OFF == pHistogram->Flags ||
+ KSCAMERA_EXTENDEDPROP_HISTOGRAM_ON == pHistogram->Flags ) )
+ {
+ if( m_pinArray[pHistogram->PinId] &&
+ m_pinArray[pHistogram->PinId]->GetState() != PinStopped )
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ else
+ {
+ //Set the histogram state.
+ Status = m_Sensor->SetHistogram( pHistogram );
+ }
+ }
+
+ DBG_TRACE("pHistogram->PinId = %u, m_sensor->PreviewIndex = %u, pHistogram->Flags = %016llx, pHistogram->Version = %u",
+ pHistogram->PinId, m_Sensor->GetNextPreviewIndex(), pHistogram->Flags, pHistogram->Version);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_FACEDETECTION.
+NTSTATUS
+CCaptureFilter::
+GetFaceDetection(
+ _Inout_ CExtendedVidProcSetting *pFaceDetect
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ if( pFaceDetect->PinId==KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pFaceDetect->isValid() )
+ {
+ //Get the FaceDetection state
+ Status = m_Sensor->GetFaceDetection( pFaceDetect );
+ }
+
+ DBG_LEAVE("(): PinId=0x%08X, Flags=0x%016llX, Version=%u, Value=%d, Status=0x%08X",
+ pFaceDetect->PinId, pFaceDetect->Flags, pFaceDetect->Version, pFaceDetect->GetULONG(), Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_FACEDETECTION.
+NTSTATUS
+CCaptureFilter::
+SetFaceDetection(
+ _In_ CExtendedVidProcSetting *pFaceDetect
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("(): PinId=0x%08X, Flags=0x%016llX, Version=%u, Value=%d",
+ pFaceDetect->PinId, pFaceDetect->Flags, pFaceDetect->Version, pFaceDetect->GetULONG());
+
+ if( pFaceDetect->PinId==KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pFaceDetect->isValid() &&
+ ( KSCAMERA_EXTENDEDPROP_FACEDETECTION_OFF == pFaceDetect->Flags ||
+ (KSCAMERA_EXTENDEDPROP_FACEDETECTION_MASK & pFaceDetect->Flags) !=0 ) )
+ {
+ CExtendedVidProcSetting Caps(*pFaceDetect);
+ Status = m_Sensor->GetFaceDetection( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pFaceDetect->Flags == (pFaceDetect->Flags & Caps.Capability) &&
+ ( KSCAMERA_EXTENDEDPROP_FACEDETECTION_OFF == pFaceDetect->Flags ||
+ NT_SUCCESS( Status = Caps.BoundsCheck( pFaceDetect->GetULONG() ) ) ) )
+ {
+ //Set the FaceDetection state.
+ Status = m_Sensor->SetFaceDetection( pFaceDetect );
+ }
+ }
+ }
+
+ DBG_LEAVE("(): Status=0x%08X", Status);
+ return Status;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ZOOM Get handler
+NTSTATUS
+CCaptureFilter::
+GetZoom(
+ _Inout_ CExtendedVidProcSetting *pZoom
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pZoom->isValid() &&
+ pZoom->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE )
+ {
+ Status = m_Sensor->GetZoom(pZoom);
+ }
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// KSPROPERTY_CAMERACONTROL_EXTENDED_ZOOM Set handler
+NTSTATUS
+CCaptureFilter::
+SetZoom(
+ _In_ CExtendedVidProcSetting *pZoom
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ DBG_ENTER("()");
+
+ // Validate
+ if( pZoom->isValid() &&
+ pZoom->PinId == KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ !(pZoom->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) )
+ {
+ CExtendedVidProcSetting Caps(*pZoom);
+ Status = m_Sensor->GetZoom( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Report to the debug output...
+ DBG_TRACE(" Flags = 0x%016llX", Caps.Flags);
+ DBG_TRACE(" Min = %d", Caps.Min());
+ DBG_TRACE(" Max = %d", Caps.Max());
+ DBG_TRACE(" Step = %d", Caps.Step());
+ DBG_TRACE("VideoProc.Value = %d", pZoom->GetLONG());
+
+ if( pZoom->Flags == (pZoom->Flags & Caps.Capability) )
+ {
+ Status = BoundsCheckSigned( pZoom->GetLONG(), Caps.m_Setting );
+
+ if (NT_SUCCESS(Status))
+ {
+ Status = m_Sensor->SetZoom(pZoom);
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ DBG_LEAVE("(PinId = %u, Flags = 0x%016llX, Caps = 0x%016llX)=0x%08X",
+ pZoom->PinId, pZoom->Flags, pZoom->Capability, Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOSTABILIZATION.
+NTSTATUS
+CCaptureFilter::
+GetVideoStabilization(
+ _Inout_ CExtendedProperty *pVideoStab
+)
+{
+ PAGED_CODE();
+
+ if (m_Sensor->IsVideoIndex(pVideoStab->PinId) &&
+ pVideoStab->isValid())
+ {
+ //Get the current state
+ return m_Sensor->GetVideoStabilization(pVideoStab);
+ }
+ return STATUS_INVALID_PARAMETER;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOSTABILIZATION.
+NTSTATUS
+CCaptureFilter::
+SetVideoStabilization(
+ _In_ CExtendedProperty *pVideoStab
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ // Call must come for Video PIN only and flags must be supported and mutually exclusive and version must be 1
+ if( m_Sensor->IsVideoIndex(pVideoStab->PinId) &&
+ pVideoStab->isValid() &&
+ !(pVideoStab->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ (KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_OFF == pVideoStab->Flags ||
+ KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_ON == pVideoStab->Flags ||
+ KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_AUTO == pVideoStab->Flags) )
+ {
+ CExtendedProperty Caps(*pVideoStab);
+ Status = m_Sensor->GetVideoStabilization( &Caps );
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ // Call must come for Video PIN only and flags must be supported and mutually exclusive and version must be 1
+ if( pVideoStab->Flags == (pVideoStab->Flags & Caps.Capability) )
+ {
+ LockFilter Lock(m_pKSFilter);
+
+ if( m_pinArray[pVideoStab->PinId] &&
+ m_pinArray[pVideoStab->PinId]->GetState() != PinStopped )
+ {
+ Status = STATUS_INVALID_DEVICE_STATE;
+ }
+ else
+ {
+ Status = m_Sensor->SetVideoStabilization(pVideoStab);
+ }
+ }
+ }
+ }
+ DBG_TRACE("pVideoStab = %p, PinId = %u, m_sensor->VideoIndex = %u, Flags = %llu, Version = %u",
+ pVideoStab, pVideoStab->PinId, m_Sensor->GetNextVideoIndex(), pVideoStab->Flags, pVideoStab->Version);
+
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_OIS.
+NTSTATUS
+CCaptureFilter::
+GetOpticalImageStabilization(
+ _Inout_ CExtendedProperty *pOIS
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( pOIS->PinId==KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pOIS->isValid() )
+ {
+ //Get the current state
+ Status = m_Sensor->GetOpticalImageStabilization(pOIS);
+ }
+
+ DBG_TRACE("pOIS = %p, PinId = %u, Flags = %llu, Version = %u",
+ pOIS, pOIS->PinId, pOIS->Flags, pOIS->Version);
+
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_OIS.
+NTSTATUS
+CCaptureFilter::
+SetOpticalImageStabilization(
+ _In_ CExtendedProperty *pOIS
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ // Call must come for Video PIN only and flags must be supported and mutually exclusive and version must be 1
+ if( pOIS->PinId==KSCAMERA_EXTENDEDPROP_FILTERSCOPE &&
+ pOIS->isValid() &&
+ !(pOIS->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) &&
+ (KSCAMERA_EXTENDEDPROP_OIS_OFF == pOIS->Flags ||
+ KSCAMERA_EXTENDEDPROP_OIS_ON == pOIS->Flags ||
+ KSCAMERA_EXTENDEDPROP_OIS_AUTO== pOIS->Flags))
+ {
+ CExtendedProperty Caps(*pOIS);
+ Status = m_Sensor->GetOpticalImageStabilization(&Caps);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pOIS->Flags == (pOIS->Flags & Caps.Capability) )
+ {
+ Status = m_Sensor->SetOpticalImageStabilization(pOIS);
+ }
+ }
+ }
+ DBG_TRACE("pOIS = %p, PinId = %u, Flags = %llu, Version = %u",
+ pOIS, pOIS->PinId, pOIS->Flags, pOIS->Version);
+
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_EXTENDED_ADVANCEDPHOTO.
+NTSTATUS
+CCaptureFilter::
+GetAdvancedPhoto(
+ _Inout_ CExtendedProperty *pAdvancedPhoto
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsStillIndex(pAdvancedPhoto->PinId) &&
+ pAdvancedPhoto->isValid() )
+ {
+ //Get the current state
+ Status = m_Sensor->GetAdvancedPhoto(pAdvancedPhoto);
+ }
+
+ DBG_LEAVE(" PinId=%u, Flags=0x%016llX, Version=%u, Status=0x%08X",
+ pAdvancedPhoto->PinId, pAdvancedPhoto->Flags, pAdvancedPhoto->Version, Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_ADVANCEDPHOTO.
+NTSTATUS
+CCaptureFilter::
+SetAdvancedPhoto(
+ _In_ CExtendedProperty *pAdvancedPhoto
+)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ // Valid request, still pin & no unsupported flags.
+ if( m_Sensor->IsStillIndex(pAdvancedPhoto->PinId) &&
+ pAdvancedPhoto->isValid() &&
+ !(pAdvancedPhoto->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) )
+ {
+ CExtendedProperty Caps(*pAdvancedPhoto);
+ Status = m_Sensor->GetAdvancedPhoto(&Caps);
+
+ if( NT_SUCCESS(Status) )
+ {
+ // Assume an invalid parameter.
+ Status = STATUS_INVALID_PARAMETER;
+
+ if( pAdvancedPhoto->Flags == (pAdvancedPhoto->Flags & Caps.Capability) )
+ {
+ // Make sure the requested flags are a valid capability combination.
+ switch( pAdvancedPhoto->Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_OFF :
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO :
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_HDR :
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_FNF :
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_ULTRALOWLIGHT:
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_HDR :
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_FNF :
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_ULTRALOWLIGHT:
+ Status = m_Sensor->SetAdvancedPhoto(pAdvancedPhoto);
+ }
+ }
+ }
+ }
+
+ DBG_LEAVE(" PinId=%u, Flags=0x%016llX, Version=%u, Status=0x%08X",
+ pAdvancedPhoto->PinId, pAdvancedPhoto->Flags, pAdvancedPhoto->Version, Status);
+ return Status;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_EXPOSURE
+NTSTATUS
+CCaptureFilter::
+GetCameraProfile(
+ _Inout_ CExtendedProfile *pProfile
+)
+{
+ PAGED_CODE();
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ pProfile->Version = KSCAMERA_EXTENDEDPROP_VERSION;
+ pProfile->PinId = KSCAMERA_EXTENDEDPROP_FILTERSCOPE;
+ pProfile->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof (KSCAMERA_EXTENDEDPROP_PROFILE);
+ pProfile->Result = 0;
+ pProfile->Flags = 0;
+ pProfile->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ pProfile->m_Profile = m_Profile;
+
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE.
+NTSTATUS
+CCaptureFilter::
+SetCameraProfile(
+ _In_ CExtendedProfile *pProfile
+)
+{
+ PAGED_CODE();
+
+ if (pProfile->PinId != KSCAMERA_EXTENDEDPROP_FILTERSCOPE ||
+ !pProfile->isValid() ||
+ 0 == (pProfile->Capability & KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL) ||
+ pProfile->Flags != 0)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+ m_Profile = pProfile->m_Profile;
+
+ m_ProfileNotifier.Set();
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+CCaptureFilter::
+GetExposure(
+ _Inout_ KSPROPERTY_CAMERACONTROL_S *pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetExposure(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_EXPOSURE
+NTSTATUS
+CCaptureFilter::
+SetExposure(
+ _In_ KSPROPERTY_CAMERACONTROL_S *pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("(Property->Value=%d)", pProperty->Value);
+
+ NTSTATUS Status = m_Sensor->SetExposure(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_FOCUS
+NTSTATUS
+CCaptureFilter::
+GetFocus(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetFocus(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_FOCUS
+NTSTATUS
+CCaptureFilter::
+SetFocus(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ m_Sensor->CancelFocus();
+
+ NTSTATUS Status = m_Sensor->SetFocus(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_ZOOM
+NTSTATUS
+CCaptureFilter::
+GetZoom(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetZoom(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_ZOOM
+NTSTATUS
+CCaptureFilter::
+SetZoom(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetZoom(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get [legacy] KSPROPERTY_CAMERACONTROL_ZOOM_RELATIVE
+NTSTATUS
+CCaptureFilter::
+GetZoomRelative(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetZoomRelative(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set [legacy] KSPROPERTY_CAMERACONTROL_ZOOM_RELATIVE
+NTSTATUS
+CCaptureFilter::
+SetZoomRelative(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetZoomRelative(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_PAN
+NTSTATUS
+CCaptureFilter::
+GetPan(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetPan(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_PAN
+NTSTATUS
+CCaptureFilter::
+SetPan(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetPan(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_ROLL
+NTSTATUS
+CCaptureFilter::
+GetRoll(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetRoll(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_ROLL
+NTSTATUS
+CCaptureFilter::
+SetRoll(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetRoll(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_TILT
+NTSTATUS
+CCaptureFilter::
+GetTilt(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetTilt(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_TILT
+NTSTATUS
+CCaptureFilter::
+SetTilt(
+ _In_ PKSPROPERTY_CAMERACONTROL_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetTilt(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH
+NTSTATUS
+CCaptureFilter::
+GetFocalLength(
+ _Inout_ PKSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetFocalLength(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH
+NTSTATUS
+CCaptureFilter::
+SetFocalLength(
+ _In_ PKSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetFocalLength(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION
+NTSTATUS
+CCaptureFilter::
+GetBacklightCompensation(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetBacklightCompensation(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_BACKLIGHT_COMPENSATION
+NTSTATUS
+CCaptureFilter::
+SetBacklightCompensation(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetBacklightCompensation(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
+NTSTATUS
+CCaptureFilter::
+GetBrightness(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetBrightness(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_BRIGHTNESS
+NTSTATUS
+CCaptureFilter::
+SetBrightness(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetBrightness(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_CONTRAST
+NTSTATUS
+CCaptureFilter::
+GetContrast(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetContrast(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_CONTRAST
+NTSTATUS
+CCaptureFilter::
+SetContrast(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetContrast(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_HUE
+NTSTATUS
+CCaptureFilter::
+GetHue(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetHue(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_HUE
+NTSTATUS
+CCaptureFilter::
+SetHue(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetHue(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get [legacy] KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE
+NTSTATUS
+CCaptureFilter::
+GetWhiteBalance(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetWhiteBalance(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set [legacy] KSPROPERTY_VIDEOPROCAMP_WHITEBALANCE
+NTSTATUS
+CCaptureFilter::
+SetWhiteBalance(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetWhiteBalance(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY
+NTSTATUS
+CCaptureFilter::
+GetPowerlineFreq(
+ _Inout_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->GetPowerlineFreq(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Set KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY
+NTSTATUS
+CCaptureFilter::
+SetPowerlineFreq(
+ _In_ PKSPROPERTY_VIDEOPROCAMP_S pProperty
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = m_Sensor->SetPowerlineFreq(pProperty);
+
+ DBG_LEAVE("()=0x%08X", Status);
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOCONTROL_MODE.
+NTSTATUS
+CCaptureFilter::
+GetVideoControlMode(
+ _Inout_ KSPROPERTY_VIDEOCONTROL_MODE_S *pMode
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsStillIndex(pMode->StreamIndex) )
+ {
+ Status = m_Sensor->GetVideoControlMode( pMode );
+ }
+
+ DBG_LEAVE("( Pin=%d, Mode=0x%08X )=0x%08X",
+ pMode->StreamIndex, pMode->Mode, Status );
+ return Status;
+}
+
+// Set KSPROPERTY_VIDEOCONTROL_MODE.
+NTSTATUS
+CCaptureFilter::
+SetVideoControlMode(
+ _In_ KSPROPERTY_VIDEOCONTROL_MODE_S *pMode
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsStillIndex(pMode->StreamIndex) )
+ {
+ KSPROPERTY_VIDEOCONTROL_CAPS_S Caps;
+ RtlZeroMemory( &Caps, sizeof(Caps) );
+ Caps.StreamIndex = pMode->StreamIndex;
+
+ Status = m_Sensor->GetVideoControlCaps( &Caps );
+ if( NT_SUCCESS(Status) &&
+ pMode->Mode == (pMode->Mode & (LONG)Caps.VideoControlCaps ) )
+ {
+ DBG_TRACE("Mode=0x%08X, Caps.Mode=0x%08X", pMode->Mode, Caps.VideoControlCaps);
+ Status = m_Sensor->SetVideoControlMode( pMode );
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ DBG_LEAVE("( Pin=%d, Mode=0x%08X )=0x%08X",
+ pMode->StreamIndex, pMode->Mode, Status );
+ return Status;
+}
+
+// Get KSPROPERTY_VIDEOCONTROL_CAPS.
+NTSTATUS
+CCaptureFilter::
+GetVideoControlCaps(
+ _Inout_ KSPROPERTY_VIDEOCONTROL_CAPS_S *pCaps
+)
+{
+ PAGED_CODE();
+ DBG_ENTER("()");
+
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if( m_Sensor->IsValidIndex(pCaps->StreamIndex) )
+ {
+ Status = m_Sensor->GetVideoControlCaps( pCaps );
+ }
+
+ DBG_LEAVE("( Pin=%d, Caps=0x%08X )=0x%08X",
+ pCaps->StreamIndex, pCaps->VideoControlCaps, Status );
+ return Status;
+}
+
diff --git a/AVStream/avscamera/sys/filter.h b/AVStream/avscamera/sys/filter.h
new file mode 100644
index 00000000..58a0e9e8
--- /dev/null
+++ b/AVStream/avscamera/sys/filter.h
@@ -0,0 +1,483 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ filter.h
+
+ Abstract:
+
+ This file contains the filter level header for the base capture filter
+ class. It provides a wrapper on KSFILTER.
+
+ CCaptureFilter holds state information for the filter and contains
+ implementations for standard camera controls. These implementations
+ validate arguments and capabilities of the control according to DDI
+ definitions. Once validated, control is passes to a CSensor object
+ to manipulate the state of camera.
+
+ CCaptureFilter holds a reference to any active CCapturePins that may
+ have been created on this filter. The reference is used to obtain
+ the state of the pin and potentially modify the pin's allocator
+ framing.
+
+ To add a new control, derive from CCaptureFilter and use one of the
+ DECLARE_PROPERTY_XXX() macros below to declare the property handlers.
+ You can also use the DEFINE_PROP_ITEM_XXX() and DEFINE_STD_EVENT_ITEM()
+ macros as aids in constructing a filter's automation table.
+
+ History:
+
+ created 3/12/2001
+
+**************************************************************************/
+
+extern KSPROPERTY_VALUES ZoomRelativeValues;
+extern KSPROPERTY_VALUES ZoomValues;
+extern KSPROPERTY_VALUES PanValues;
+extern KSPROPERTY_VALUES RollValues;
+extern KSPROPERTY_VALUES TiltValues;
+extern KSPROPERTY_VALUES BacklightCompensationValues;
+extern KSPROPERTY_VALUES BrightnessValues;
+extern KSPROPERTY_VALUES ContrastValues;
+extern KSPROPERTY_VALUES HueValues;
+extern KSPROPERTY_VALUES PLFValues;
+extern KSPROPERTY_VALUES WhiteBalanceValues;
+extern KSPROPERTY_VALUES ExposureValues;
+extern KSPROPERTY_VALUES FocusValues;
+
+class CCapturePin;
+class CCaptureFilter
+{
+private:
+
+ //
+ // The AVStream filter object associated with this CCaptureFilter.
+ //
+ CCapturePin **m_pinArray;
+
+protected:
+ //
+ // Setup, memory allocation, etc.
+ //
+ NTSTATUS
+ Initialize();
+
+ //
+ // Cleanup
+ //
+ void
+ Cleanup();
+
+public:
+
+ //
+ // setPin()
+ //
+ // Attach a CCapturePin.
+ //
+ void
+ setPin(
+ _In_ CCapturePin *pPin,
+ _In_ unsigned Id
+ ) ;
+
+ //
+ // getPin()
+ //
+ // Query an attached CCapturePin.
+ //
+ CCapturePin *
+ getPin(
+ _In_ unsigned Id
+ ) ;
+
+ //
+ // CCaptureFilter()
+ //
+ // Constructor.
+ //
+ CCaptureFilter (
+ _In_ PKSFILTER Filter
+ );
+
+ //
+ // ~CCaptureFilter():
+ //
+ // The capture filter destructor.
+ //
+ virtual
+ ~CCaptureFilter ();
+
+ //
+ // DispatchCreate():
+ //
+ // This is the filter creation dispatch for the capture filter. It
+ // creates the CCaptureFilter object, associates it with the AVStream
+ // object, and bags it for easy cleanup later.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp
+ );
+
+ //
+ // Close(): Called in response to IRP_MJ_CLOSE.
+ //
+ static
+ NTSTATUS
+ DispatchClose(
+ _In_ PKSFILTER Filter,
+ _In_ PIRP Irp
+ );
+
+ LARGE_INTEGER m_StartTime;
+ CCaptureDevice *m_pCaptureDevice;
+ CSensor *m_Sensor;
+ PKSFILTER m_pKSFilter;
+ PKSCAMERA_PERFRAMESETTING_HEADER m_pPerFrameSettings;
+ ULONG m_PFSSize;
+
+ CNotifier m_PhotoModeNotifier;
+ CNotifier m_PhotoMaxFrameRateNotifier;
+ CNotifier m_FocusNotifier;
+ CNotifier m_FocusRectNotifier;
+ CNotifier m_IsoNotifier;
+ CNotifier m_IsoAdvancedNotifier;
+ CNotifier m_EvCompensationNotifier;
+ CNotifier m_WhiteBalanceNotifier;
+ CNotifier m_ExposureNotifier;
+ CNotifier m_SceneModeNotifier;
+ CNotifier m_ThumbnailNotifier;
+ CNotifier m_WarmStartNotifier;
+ CNotifier m_RoiNotifier;
+ CNotifier m_ProfileNotifier;
+
+ //
+ // The following static member template function is used to validate
+ // most KSPROPERTYs and thunk that call down to a handler that is a non-
+ // static member of CCaptureFilter (or a derived class).
+ //
+ // Note: A separate instance of this thunking function is instantiated for
+ // each control, so code space is not conserved. However, performing
+ // this logic in only one place ensures consistant behavior across
+ // controls and reduces the chances for mistakes.
+ //
+ template
+ <typename OUTPUT, // type of data consumed by the handler.
+ typename FILTER,
+ NTSTATUS (FILTER::*pFun)( // The local handling function.
+ _Inout_ OUTPUT *pOutput )>
+ __declspec(code_seg("PAGE")) // Put this function into paged code.
+ static
+ NTSTATUS
+ Prop(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData)
+ {
+ PAGED_CODE();
+ UNREFERENCED_PARAMETER(pProperty);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ NT_ASSERT(pIrp);
+
+ FILTER *pFilter = reinterpret_cast <FILTER *>(KsGetFilterFromIrp(pIrp)->Context);
+ PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
+ ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+ OUTPUT *pOutput = reinterpret_cast<OUTPUT *>(pData);
+
+ if (ulOutputBufferLength == 0)
+ {
+ pIrp->IoStatus.Information = sizeof(OUTPUT);
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (ulOutputBufferLength < sizeof(OUTPUT))
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(OUTPUT))
+ {
+ Status = (pFilter->*pFun)( pOutput );
+ if( NT_SUCCESS(Status) )
+ {
+ pIrp->IoStatus.Information = sizeof(OUTPUT);
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ return Status;
+ }
+
+ // Get Per Frame Setting Caps
+ static
+ NTSTATUS
+ GetPFSCaps(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+ );
+
+ // Get current Per Frame Settings
+ static
+ NTSTATUS
+ GetPerFrameSettings(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+ );
+
+ // Set new Per Frame Settings
+ static
+ NTSTATUS
+ SetPerFrameSettings(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+ );
+
+ // Clear Per Frame Settings
+ static
+ NTSTATUS
+ ClearPerFrameSettings(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+ );
+
+//
+// DECLARE_PROPERTY_XXX() macros.
+//
+// The follow macros declare a property handler using a common naming
+// convention. This convention is unique to this sample code. The
+// convention is used again in the DEFINE_PROP_ITEM_XXX() macros during
+// construction of the automation tables.
+//
+// Note: These definitions are non-static members of the filter.
+//
+
+// Declare a property's GET handler.
+#define DECLARE_PROPERTY_GET_HANDLER( type, name ) \
+ NTSTATUS \
+ Get##name( \
+ _Inout_ type *pOutput \
+ );
+
+// Declare a property's SET handler.
+#define DECLARE_PROPERTY_SET_HANDLER( type, name ) \
+ NTSTATUS \
+ Set##name( \
+ _In_ type *pOutput \
+ );
+
+// Declare a property's GET and SET handlers.
+#define DECLARE_PROPERTY_HANDLERS( type, name ) \
+DECLARE_PROPERTY_GET_HANDLER( type, name ) \
+DECLARE_PROPERTY_SET_HANDLER( type, name )
+
+ //
+ // Declaration of all the standard control handlers that use fixed structures.
+ //
+ DECLARE_PROPERTY_HANDLERS( CExtendedPhotoMode, PhotoMode );
+ DECLARE_PROPERTY_GET_HANDLER( CExtendedProperty, PhotoFrameRate );
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, PhotoMaxFrameRate );
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, WarmStart );
+ DECLARE_PROPERTY_HANDLERS( CExtendedMaxVideoFpsForPhotoRes, MaxVideoFpsForPhotoRes );
+ DECLARE_PROPERTY_GET_HANDLER( CExtendedFieldOfView, FieldOfView );
+ DECLARE_PROPERTY_GET_HANDLER( CExtendedCameraAngleOffset, CameraAngleOffset );
+ DECLARE_PROPERTY_HANDLERS( KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_S, FocusRect );
+ DECLARE_PROPERTY_HANDLERS( CExtendedVidProcSetting, Focus );
+ DECLARE_PROPERTY_GET_HANDLER( CExtendedProperty, FocusState );
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, FocusPriority );
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, ExtendedFlash )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, Iso )
+ DECLARE_PROPERTY_HANDLERS( CExtendedVidProcSetting, IsoAdvanced )
+ DECLARE_PROPERTY_HANDLERS( CExtendedEvCompensation, EvCompensation )
+ DECLARE_PROPERTY_HANDLERS( CExtendedVidProcSetting, WhiteBalance )
+ DECLARE_PROPERTY_HANDLERS( CExtendedVidProcSetting, Exposure )
+ DECLARE_PROPERTY_HANDLERS( CExtendedVidProcSetting, FaceDetection )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, PhotoConfirmation )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, SceneMode )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, VFR )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, VideoHDR )
+ DECLARE_PROPERTY_HANDLERS( CExtendedVidProcSetting, Zoom )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, VideoStabilization)
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, Histogram )
+ DECLARE_PROPERTY_HANDLERS( CExtendedMetadata, Metadata )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, OpticalImageStabilization )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, OptimizationHint )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, AdvancedPhoto )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProfile, CameraProfile )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, Thumbnail )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, TriggerTime )
+ DECLARE_PROPERTY_HANDLERS( CExtendedProperty, TorchMode )
+
+ DECLARE_PROPERTY_HANDLERS( KSPROPERTY_CAMERACONTROL_VIDEOSTABILIZATION_MODE_S, VideoStabMode )
+ DECLARE_PROPERTY_HANDLERS( KSPROPERTY_CAMERACONTROL_FLASH_S, Flash )
+ DECLARE_PROPERTY_GET_HANDLER( KSPROPERTY_CAMERACONTROL_IMAGE_PIN_CAPABILITY_S, PinDependence )
+
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, Exposure);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, Focus);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, Zoom);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, ZoomRelative);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, Pan);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, Roll);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_S, Tilt);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_CAMERACONTROL_FOCAL_LENGTH_S, FocalLength);
+
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOPROCAMP_S, BacklightCompensation);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOPROCAMP_S, Brightness);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOPROCAMP_S, Contrast);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOPROCAMP_S, Hue);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOPROCAMP_S, WhiteBalance);
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOPROCAMP_S, PowerlineFreq);
+
+ DECLARE_PROPERTY_GET_HANDLER( CRoiConfig, RoiConfigCaps );
+
+ DECLARE_PROPERTY_HANDLERS(KSPROPERTY_VIDEOCONTROL_MODE_S, VideoControlMode);
+ DECLARE_PROPERTY_GET_HANDLER(KSPROPERTY_VIDEOCONTROL_CAPS_S, VideoControlCaps);
+
+ //
+ // The following are property handlers that use an atypical variable
+ // length (not known at compile-time) parameter list.
+ //
+ // Since we only have a few, declare them explicitly.
+ //
+
+ // KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL Get handler
+ static
+ NTSTATUS
+ GetRoiIspControl(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData
+ );
+
+ // KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL Set handler
+ static
+ NTSTATUS
+ SetRoiIspControl(
+ _In_ PIRP pIrp,
+ _In_ PKSPROPERTY pProperty,
+ _Inout_ PVOID pData);
+
+ // Make sure the PERFRAMESETTINGs passed to us are valid.
+ _Success_(return == 0)
+ NTSTATUS
+ CCaptureFilter::ParsePFSBuffer(
+ _In_reads_bytes_(BufferLimit)
+ PKSCAMERA_PERFRAMESETTING_HEADER pPFS,
+ _In_ ULONG BufferLimit,
+ _Outptr_opt_result_maybenull_
+ ISP_FRAME_SETTINGS **ppSettings );
+
+ // Helper function for finding our filter object.
+ static
+ CCaptureFilter *
+ GetFilter(
+ _In_ PKSPIN Pin
+ )
+ {
+ return reinterpret_cast <CCaptureFilter *>
+ (KsPinGetParentFilter(Pin)->Context);
+ }
+
+ // Accessor to convert a reference to a CCaptureFilter to a PKSFILTER.
+ operator PKSFILTER()
+ {
+ return m_pKSFilter;
+ }
+
+ // Get the name of the filter from the context structure passed in at initialization.
+ LPCWSTR GetFilterName()
+ {
+ return m_pCaptureDevice->GetFilterName(m_pCaptureDevice->GetFilterIndex(m_pKSFilter));
+ }
+
+ // Update the pin's allocator to a specific frame count.
+ NTSTATUS
+ UpdateAllocatorFraming(
+ _In_ ULONG PinId
+ );
+
+private:
+ // An arbitrary limit on Per-Frame settings.
+ static
+ const ULONG MAX_FRAME_COUNT=512;
+
+ // Filter level state information.
+ KSCAMERA_EXTENDEDPROP_PROFILE m_Profile;
+};
+
+//
+// Helper definitions for creating custom property sets
+//
+// Note: Property automation tables require a statically defined accessor
+// functions, however our properties functions are (mostly) implemented
+// as non-static member functions. The following macros provide a
+// static member thunking function by invoking a member template
+// function called Prop<>. The Prop<> performs limited validation on
+// the buffer, provides back the size if the buffer size was 0, picks
+// up a pointer to the filter through the IRP and calls the member
+// function that handles the property.
+//
+
+#define DEFINE_PROP_ITEM_NO_SET( T, ctrl, type, name ) \
+ DEFINE_KSPROPERTY_ITEM( \
+ ctrl, \
+ (&T::Prop<type, T, &T::Get##name>), \
+ sizeof(KSPROPERTY), \
+ 0, \
+ NULL, \
+ NULL, 0, NULL, NULL, 0 \
+ )
+
+#define DEFINE_PROP_ITEM_WITH_VALUES( T, ctrl, type, name, values ) \
+ DEFINE_KSPROPERTY_ITEM( \
+ ctrl, \
+ (&T::Prop<type, T, &T::Get##name>), \
+ sizeof(KSPROPERTY), \
+ 0, \
+ (&T::Prop<type, T, &T::Set##name>), \
+ values, 0, NULL, NULL, 0 \
+ )
+
+#define DEFINE_PROP_ITEM( T, ctrl, type, name ) \
+ DEFINE_PROP_ITEM_WITH_VALUES( T, ctrl, type, name, NULL )
+
+//
+// A simplification for defining a KSEVENT. We only need to specify one parameter.
+//
+#define DEFINE_STD_EVENT_ITEM(EVENTID) \
+ DEFINE_KSEVENT_ITEM \
+ ( \
+ EVENTID, \
+ sizeof(KSEVENTDATA), \
+ 0, \
+ NULL, \
+ NULL, \
+ NULL \
+ )
+
+//
+// A simplification for defining a KSPROPERTY_SET. We only need to specify two parameters.
+//
+#define DEFINE_STD_PROPERTY_SET(SET, PROPERTIES) \
+ DEFINE_KSPROPERTY_SET( \
+ &SET, \
+ SIZEOF_ARRAY(PROPERTIES), \
+ PROPERTIES, \
+ 0, \
+ NULL)
+
+const LONGLONG MAX_EXPOSURE_TIME = 10000000ULL * 60 * 60; // 1 min
+const LONG MIN_EXPOSURE_TIME=10000; // 1 ms
+const LONG DEF_EXPOSURE_TIME=10000 * 30; // 30 ms.
diff --git a/AVStream/avscamera/sys/formats.cpp b/AVStream/avscamera/sys/formats.cpp
new file mode 100644
index 00000000..0c03d4ab
--- /dev/null
+++ b/AVStream/avscamera/sys/formats.cpp
@@ -0,0 +1,390 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ Formats.cpp
+
+ Abstract:
+
+ A list of available Image and Video formats.
+
+ History:
+
+ created 2/12/2016
+
+**************************************************************************/
+
+#include "Common.h"
+#include "ntintsafe.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+/**************************************************************************
+
+ DISPATCH AND DESCRIPTOR LAYOUT
+
+**************************************************************************/
+
+DEFINE_DATARANGE_VIDEO(
+ FormatNV12_CaptureVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_NV12),
+ DMAX_X, DMAX_Y,
+ 30,
+ 1,
+ 12,
+ FOURCC_NV12)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureQVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ D_X, D_Y,
+ 30,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureQVGAOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ D_X_OS, D_Y_OS,
+ 30,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X, DMAX_Y,
+ 30,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGAOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X_OS, DMAX_Y_OS,
+ 30,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureQVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ D_X, D_Y,
+ 30,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureQVGAOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ D_X_OS, D_Y_OS,
+ 30,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X, DMAX_Y,
+ 30,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGAOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X_OS, DMAX_Y_OS,
+ 30,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA_60fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X, DMAX_Y,
+ 60,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA_60fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X_OS, DMAX_Y_OS,
+ 60,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA_60fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X, DMAX_Y,
+ 60,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA_60fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X_OS, DMAX_Y_OS,
+ 60,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA_90fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X, DMAX_Y,
+ 90,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA_90fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X_OS, DMAX_Y_OS,
+ 90,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA_90fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X, DMAX_Y,
+ 90,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA_90fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X_OS, DMAX_Y_OS,
+ 90,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA_120fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X, DMAX_Y,
+ 120,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatYUY2_CaptureVGA_120fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_YUY2),
+ DMAX_X_OS, DMAX_Y_OS,
+ 120,
+ 1,
+ 16,
+ FOURCC_YUY2)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA_120fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X, DMAX_Y,
+ 120,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB24Bpp_CaptureVGA_120fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB24),
+ DMAX_X_OS, DMAX_Y_OS,
+ 120,
+ 1,
+ 24,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X, DMAX_Y,
+ 30,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGAOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X_OS, DMAX_Y_OS,
+ 30,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA_60fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X, DMAX_Y,
+ 60,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA_60fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X_OS, DMAX_Y_OS,
+ 60,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA_90fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X, DMAX_Y,
+ 90,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA_90fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X_OS, DMAX_Y_OS,
+ 90,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA_120fps,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X, DMAX_Y,
+ 120,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureVGA_120fpsOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ DMAX_X_OS, DMAX_Y_OS,
+ 120,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureQVGA,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ D_X, D_Y,
+ 30,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+DEFINE_DATARANGE_VIDEO(
+ FormatRGB32Bpp_CaptureQVGAOverscan,
+ STATICGUIDOF(KSDATAFORMAT_SUBTYPE_RGB32),
+ D_X_OS, D_Y_OS,
+ 30,
+ 1,
+ 32,
+ KS_BI_RGB)
+
+
+//
+// CapturePinDataRanges:
+//
+// This is the list of data ranges supported on the capture pin. We support
+// two: one RGB24, and one YUY2.
+//
+const
+PKSDATARANGE
+ImageCapturePinDataRanges[ IMAGE_CAPTURE_PIN_DATA_RANGE_COUNT ] =
+{
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA,
+ (PKSDATARANGE) &FormatNV12_CaptureVGA
+};
+
+//
+// CapturePinDataRanges:
+//
+// This is the list of data ranges supported on the capture pin. We support
+// RGB24, YUY2, and RGB32
+//
+const
+PKSDATARANGE
+VideoCapturePinDataRanges [VIDEO_CAPTURE_PIN_DATA_RANGE_COUNT] =
+{
+ (PKSDATARANGE) &FormatYUY2_CaptureQVGA,
+ (PKSDATARANGE) &FormatYUY2_CaptureQVGAOverscan,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGAOverscan,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureQVGA,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureQVGAOverscan,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGAOverscan,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_60fps,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_60fpsOverscan,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_60fps,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_60fpsOverscan,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_90fps,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_90fpsOverscan,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_90fps,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_90fpsOverscan,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_120fps,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_120fpsOverscan,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_120fps,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_120fpsOverscan,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGAOverscan,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_60fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_60fpsOverscan,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_90fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_90fpsOverscan,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_120fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_120fpsOverscan,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureQVGA,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureQVGAOverscan,
+};
+
+const
+PKSDATARANGE
+VideoPreviewPinDataRanges[VIDEO_PREVIEW_PIN_DATA_RANGE_COUNT] =
+{
+ (PKSDATARANGE) &FormatYUY2_CaptureQVGA,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureQVGA,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_60fps,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_60fps,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_90fps,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_90fps,
+ (PKSDATARANGE) &FormatYUY2_CaptureVGA_120fps,
+ (PKSDATARANGE) &FormatRGB24Bpp_CaptureVGA_120fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_60fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_90fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureVGA_120fps,
+ (PKSDATARANGE) &FormatRGB32Bpp_CaptureQVGA,
+};
diff --git a/AVStream/avscamera/sys/formats.h b/AVStream/avscamera/sys/formats.h
new file mode 100644
index 00000000..e967e52b
--- /dev/null
+++ b/AVStream/avscamera/sys/formats.h
@@ -0,0 +1,137 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ Formats.h
+
+ Abstract:
+
+ A list of available Image and Video formats.
+
+ History:
+
+ created 2/12/2016
+
+**************************************************************************/
+
+#pragma once
+
+#include "capture.h"
+
+#define DEFINE_DATARANGE_VIDEO(_RANGE_NAME_, _Subtype_, _X_, _Y_, _Rate_, _Planes_, _BitCount_, _Compression_) \
+const \
+KS_DATARANGE_VIDEO \
+_RANGE_NAME_ = \
+{ \
+ \
+ /* \
+ // KSDATARANGE \
+ */ \
+ { \
+ sizeof( KS_DATARANGE_VIDEO ), /* FormatSize */ \
+ 0, /* Flags */ \
+ ULONG((ULONGLONG(_X_) *_Y_ * _BitCount_)/8),/* SampleSize */ \
+ 0, /* Reserved */ \
+ \
+ STATICGUIDOF( KSDATAFORMAT_TYPE_VIDEO ), /* aka. MEDIATYPE_Video */ \
+ _Subtype_, /* aka. MEDIASUBTYPE_RGB24, */ \
+ STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ) /* aka. FORMAT_VideoInfo */ \
+ }, \
+ \
+ TRUE, /* BOOL, bFixedSizeSamples (all samples same size?) */ \
+ FALSE, /* BOOL, bTemporalCompression (all I frames?) */ \
+ 0, /* Reserved (was StreamDescriptionFlags) */ \
+ 0, /* Reserved (was MemoryAllocationFlags */ \
+ /* (KS_VIDEO_ALLOC_*)) */ \
+ /* */ \
+ /* _KS_VIDEO_STREAM_CONFIG_CAPS */ \
+ /* */ \
+ { \
+ STATICGUIDOF( KSDATAFORMAT_SPECIFIER_VIDEOINFO ), /* GUID */ \
+ KS_AnalogVideo_None, /* AnalogVideoStandard */ \
+ _X_,_Y_, /* InputSize, (the inherent size of the incoming signal */ \
+ /* with every digitized pixel unique) */ \
+ _X_,_Y_, /* MinCroppingSize, smallest rcSrc cropping rect allowed */ \
+ _X_,_Y_, /* MaxCroppingSize, largest rcSrc cropping rect allowed */ \
+ 8, /* CropGranularityX, granularity of cropping size */ \
+ 1, /* CropGranularityY */ \
+ 8, /* CropAlignX, alignment of cropping rect */ \
+ 1, /* CropAlignY; */ \
+ _X_, _Y_, /* MinOutputSize, smallest bitmap stream can produce */ \
+ _X_, _Y_, /* MaxOutputSize, largest bitmap stream can produce */ \
+ 8, /* OutputGranularityX, granularity of output bitmap size */ \
+ 1, /* OutputGranularityY; */ \
+ 0, /* StretchTapsX (0 no stretch, 1 pix dup, 2 interp...) */ \
+ 0, /* StretchTapsY */ \
+ 0, /* ShrinkTapsX */ \
+ 0, /* ShrinkTapsY */ \
+ (ONESECOND / _Rate_), /* MinFrameInterval, 100 nS units */ \
+ 640000000, /* MaxFrameInterval, 100 nS units */ \
+ ULONG(min(ULONG_MAX,(ULONGLONG(_X_) *_Y_ * _BitCount_)*_Rate_)),/* MinBitsPerSecond;*/ \
+ ULONG(min(ULONG_MAX,(ULONGLONG(_X_) *_Y_ * _BitCount_)*_Rate_)) /* MaxBitsPerSecond;*/ \
+ }, \
+ \
+ /* \
+ // KS_VIDEOINFOHEADER (default format) \
+ */ \
+ { \
+ 0,0,0,0, /* RECT rcSource; */ \
+ 0,0,0,0, /* RECT rcTarget; */ \
+ ULONG(min(ULONG_MAX,(ULONGLONG(_X_) *_Y_ * _BitCount_)*_Rate_)),/* DWORD dwBitRate;*/ \
+ 0L, /* DWORD dwBitErrorRate; */ \
+ (ONESECOND / _Rate_), /* REFERENCE_TIME AvgTimePerFrame; */ \
+ sizeof( KS_BITMAPINFOHEADER ), /* DWORD biSize; */ \
+ _X_, /* LONG biWidth; */ \
+ _Y_, /* LONG biHeight; */ \
+ _Planes_, /* WORD biPlanes; */ \
+ _BitCount_, /* WORD biBitCount; */ \
+ _Compression_, /* DWORD biCompression; */ \
+ ULONG((ULONGLONG(_X_) *_Y_ * _BitCount_)/8),/* DWORD biSizeImage; */ \
+ 0, /* LONG biXPelsPerMeter; */ \
+ 0, /* LONG biYPelsPerMeter; */ \
+ 0, /* DWORD biClrUsed; */ \
+ 0 /* DWORD biClrImportant; */ \
+ } \
+}; \
+
+
+extern const KS_DATARANGE_VIDEO FormatYUY2Image_Capture;
+extern const KS_DATARANGE_VIDEO FormatNV12Image_Capture;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureQVGA;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureQVGAOverscan;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGAOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureQVGA;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureQVGAOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGAOverscan;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA_60fps;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA_60fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA_60fps;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA_60fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA_90fps;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA_90fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA_90fps;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA_90fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA_120fps;
+extern const KS_DATARANGE_VIDEO FormatYUY2_CaptureVGA_120fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA_120fps;
+extern const KS_DATARANGE_VIDEO FormatRGB24Bpp_CaptureVGA_120fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGAOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA_60fps;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA_60fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA_90fps;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA_90fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA_120fps;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureVGA_120fpsOverscan;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureQVGA;
+extern const KS_DATARANGE_VIDEO FormatRGB32Bpp_CaptureQVGAOverscan;
+
+extern const PKSDATARANGE VideoCapturePinDataRanges[VIDEO_CAPTURE_PIN_DATA_RANGE_COUNT];
+extern const PKSDATARANGE VideoPreviewPinDataRanges[VIDEO_PREVIEW_PIN_DATA_RANGE_COUNT];
+extern const PKSDATARANGE ImageCapturePinDataRanges[IMAGE_CAPTURE_PIN_DATA_RANGE_COUNT];
diff --git a/AVStream/avscamera/sys/hwsim.cpp b/AVStream/avscamera/sys/hwsim.cpp
new file mode 100644
index 00000000..f00a4684
--- /dev/null
+++ b/AVStream/avscamera/sys/hwsim.cpp
@@ -0,0 +1,1409 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ hwsim.cpp
+
+ Abstract:
+
+ This file contains the implementation of CHardwareSimulation used to
+ simulate a camera's capture stream.
+
+ Our simulation cannot mimic a real camera with any precision. A real
+ camera would likely have dedicated hardware to provide interrupts, do
+ DMA transfers of frames from an internal buffer as well as do scaling
+ and on-the-fly colorspace and planar format conversions so as to supply
+ frames for preview, video and photo in varying resolutions and
+ colorspaces.
+
+ This simulation does not have such hardware, so instead it synthesizes
+ a frame on the fly for each local pin as required. The frame is
+ synthesized from common state information, so the images produced
+ should be comparable from pin to pin. CHardwareSimulation is used as
+ a base class for each simulated pin / hardware.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+inline
+CHwSimTimer::
+CHwSimTimer(
+ _In_ CHardwareSimulation *Parent
+)
+ : KPassiveTimer( Parent->m_Sensor->GetDeviceObject() )
+ , m_Parent( Parent )
+/*++
+
+Routine Description:
+
+ CHwSimTimer object construction.
+
+Arguments:
+
+ Parent -
+ The parent CHardwareSimulation.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+}
+
+void
+CHwSimTimer::Handler(
+ _In_opt_ PVOID Context
+)
+/*++
+
+Routine Description:
+
+ Punts to the HardwareSim...
+
+Arguments:
+
+ Context -
+ Our parent CHardwareSimulation.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+ ((CHardwareSimulation *) Context)->FakeHardware();
+}
+
+/*************************************************/
+
+CHardwareSimulation::
+CHardwareSimulation (
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+)
+ : m_Sensor (Sensor)
+ , m_IsrTimer(this)
+ , m_ScatterGatherMappingsMax (SCATTER_GATHER_MAPPINGS_MAX)
+ , m_TimePerFrame(ONESECOND/30)
+ , m_PinID(PinID)
+ , m_Synthesizer(nullptr)
+ , m_Width(0)
+ , m_Height(0)
+ , m_ImageSize(0)
+ , m_PinState(PinStopped)
+ , m_NumMappingsCompleted(0)
+ , m_ScatterGatherMappingsQueued(0)
+ , m_ScatterGatherBytesQueued(0)
+ , m_NumFramesSkipped(0)
+ , m_InterruptTime(0)
+ , m_LastReportedExposureTime(DEF_EXPOSURE_TIME) // Assume the default exposure time for now.
+ , m_LastReportedWhiteBalance(0)
+ , m_FaceDetectionDelay(1) // Start out reporting immediately.
+
+/*++
+
+Routine Description:
+
+ CHardwareSimulation Construction.
+
+Arguments:
+
+ Sensor -
+ The parent CSensor object that contains state for the controls.
+ PinID -
+ The pin index.
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ PAGED_CODE();
+
+ //
+ // Initialize the timer's, and locks necessary to simulate this hardware.
+ //
+ InitializeListHead (&m_ScatterGatherMappings);
+
+ //
+ // Initialize the entry lookaside.
+ //
+ ExInitializeNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ NULL,
+ NULL,
+ POOL_NX_ALLOCATION,
+ sizeof (SCATTER_GATHER_ENTRY),
+ 'nEGS',
+ 0
+ );
+
+ m_StartTime.QuadPart = 0;
+}
+
+CHardwareSimulation::
+~CHardwareSimulation()
+{
+ PAGED_CODE();
+
+ // Cancel the timer, just in case its running.
+ m_IsrTimer.Cancel();
+
+ //
+ // Delete the scatter / gather lookaside list.
+ //
+ ExDeleteNPagedLookasideList (&m_ScatterGatherLookaside);
+}
+
+/*************************************************/
+
+BOOLEAN
+CHardwareSimulation::
+Initialize()
+
+/*++
+
+Routine Description:
+
+ Initialize the hardware simulation
+
+Arguments:
+
+ [none]
+
+Return Value:
+
+ TRUE - CHardwareSimulation is fully initialized.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ return m_IsrTimer.IsValid() ;
+}
+
+/*************************************************/
+
+NTSTATUS
+CHardwareSimulation::
+Start (
+ IN CSynthesizer *ImageSynth,
+ IN LONGLONG TimePerFrame,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG ImageSize
+)
+
+/*++
+
+Routine Description:
+
+ Start the hardware simulation. This will kick the interrupts on,
+ begin issuing DPC's, filling in capture information, etc...
+ We keep track of starvation starting at this point.
+
+Arguments:
+
+ ImageSynth -
+ The image synthesizer to use to generate pictures to display
+ on the capture buffer.
+
+ TimePerFrame -
+ The time per frame... we issue interrupts this often.
+
+ Width -
+ The image width
+
+ Height -
+ The image height
+
+ ImageSize -
+ The size of the image. We allocate a temporary scratch buffer
+ based on this size to fake hardware.
+
+Return Value:
+
+ Success / Failure (typical failure will be out of memory on the
+ scratch buffer, etc...)
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ // Prevent state-changes during this call.
+ KScopedMutex Lock(m_ListLock);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ m_Synthesizer = ImageSynth;
+ m_TimePerFrame = TimePerFrame;
+ m_ImageSize = ImageSize;
+ m_Height = Height;
+ m_Width = Width;
+
+ m_NumMappingsCompleted = 0;
+ m_ScatterGatherMappingsQueued = 0;
+ m_NumFramesSkipped = 0;
+ m_InterruptTime = 0;
+
+ KeQuerySystemTime (&m_StartTime);
+
+ if( !m_Synthesizer->Initialize() )
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // If everything is ok, start issuing interrupts.
+ //
+ if (NT_SUCCESS (Status))
+ {
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart + m_TimePerFrame;
+
+ m_PinState = PinRunning;
+ m_IsrTimer.Set( NextTime );
+ }
+
+ return Status;
+}
+
+/*************************************************/
+
+NTSTATUS
+CHardwareSimulation::
+Pause (
+ BOOLEAN Pausing
+)
+
+/*++
+
+Routine Description:
+
+ Pause the hardware simulation... When the hardware simulation is told
+ to pause, it stops stops the timer, but it does not reset the counters.
+
+Arguments:
+
+ Pausing -
+ Indicates whether the hardware is pausing or not.
+
+ TRUE -
+ Pause the hardware
+
+ FALSE -
+ Unpause the hardware from a previous pause
+
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ {
+ // Prevent state-changes during this call.
+ KScopedMutex Lock(m_ListLock);
+
+ if (Pausing && m_PinState == PinRunning)
+ {
+ //
+ // If we were running, stop completing mappings, etc...
+ //
+ m_PinState = PinPaused;
+ }
+ else if (!Pausing && m_PinState == PinPaused)
+ {
+ //
+ // For unpausing the hardware, we need to compute the relative time
+ // and restart interrupts.
+ //
+ LARGE_INTEGER UnpauseTime;
+
+ KeQuerySystemTime (&UnpauseTime);
+ m_InterruptTime = (ULONG) (
+ (UnpauseTime.QuadPart - m_StartTime.QuadPart) /
+ m_TimePerFrame
+ );
+
+ UnpauseTime.QuadPart = m_StartTime.QuadPart +
+ (m_InterruptTime + 1) * m_TimePerFrame;
+
+ m_PinState = PinRunning;
+ m_IsrTimer.Set( UnpauseTime );
+ }
+ }
+
+ // If we are pausing, it's best to stop the timer and not wait for another frame.
+ if( Pausing )
+ {
+ m_IsrTimer.Cancel();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CHardwareSimulation::
+Stop()
+
+/*++
+
+Routine Description:
+
+ Stop the hardware simulation...
+
+ For us, stop the timer, free the synthesizer and flush the queue.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ //
+ // If the hardware is told to stop while it's running, we need to
+ // halt the interrupts first. If we're already paused, this has
+ // already been done.
+ //
+
+ DBG_ENTER("(): m_PinID=%d", m_PinID);
+
+ BOOLEAN bCancel = FALSE;
+
+ {
+ // Prevent state-changes during this call.
+ KScopedMutex Lock(m_ListLock);
+
+ bCancel = (m_PinState == PinRunning);
+ m_PinState = PinStopped;
+
+ // Free the synthesis buffer.
+ m_Synthesizer->Destroy();
+
+ //
+ // Free S/G buffer
+ //
+ FreeSGList( &m_ScatterGatherMappings, L"StreamPointer Stop SG List" );
+
+ m_ScatterGatherMappingsQueued=0;
+ m_NumMappingsCompleted = 0;
+ m_ScatterGatherBytesQueued = 0;
+ }
+
+ // If running, stop the timer to make sure we don't try to deliver one last frame.
+ if( bCancel )
+ {
+ m_IsrTimer.Cancel();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CHardwareSimulation::
+Reset()
+{
+ PAGED_CODE();
+
+ KScopedMutex Lock( m_ListLock );
+ DBG_ENTER("(): m_PinID=%d", m_PinID);
+
+ FreeSGList( &m_ScatterGatherMappings, L"StreamPointer Reset SG List" );
+
+ m_ScatterGatherMappingsQueued=0;
+ m_NumMappingsCompleted = 0;
+ m_ScatterGatherBytesQueued = 0;
+
+ DBG_LEAVE("(): m_PinID=%d", m_PinID);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CHardwareSimulation::
+Reset (IN PKSPIN Pin)
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+ if(Pin->ResetState == KSRESET_END)
+ {
+ KsPinAttemptProcessing(Pin, TRUE);
+ }
+ else
+ {
+ status = Reset();
+ }
+
+ return status;
+}
+
+ULONG
+CHardwareSimulation::
+ReadNumberOfMappingsCompleted()
+
+/*++
+
+Routine Description:
+
+ Read the number of scatter / gather mappings which have been
+ completed since the last reset of the simulated hardware
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Total number of completed mappings.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ return m_NumMappingsCompleted;
+}
+
+/*************************************************/
+
+
+ULONG
+CHardwareSimulation::
+ProgramScatterGatherMappings (
+ IN PKSSTREAM_POINTER *Clone,
+ IN PUCHAR *Buffer,
+ IN PKSMAPPING Mappings,
+ IN ULONG MappingsCount,
+ IN ULONG MappingStride
+)
+
+/*++
+
+Routine Description:
+
+ Add a single entry to our queue. In practice our simulation can only
+ accept one frame at a time, but we still base this code off of the
+ avshws sample.
+
+Arguments:
+
+ Buffer -
+ The virtual address of the buffer mapped by the mapping list
+
+ ClonePointer
+ The KSStreamClone Pointer to be associated with the entry item
+
+ Mappings -
+ The KSMAPPINGS array corresponding to the buffer
+
+ MappingsCount -
+ The number of mappings in the mappings array
+
+ MappingStride -
+ The mapping stride used in initialization of AVStream DMA
+
+Return Value:
+
+ Number of mappings actually inserted.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ ULONG MappingsInserted = 0;
+
+ DBG_ENTER("(Clone=%p, Buffer=%p, MappingsCount=%d)",
+ Clone, Buffer, MappingsCount);
+
+ //
+ // Protect our S/G list with a spinlock.
+ //
+ KScopedMutex Lock( m_ListLock );
+
+ //
+ // Loop through the scatter / gather list and break the buffer up into
+ // chunks equal to the scatter / gather mappings. Stuff the virtual
+ // addresses of these chunks on a list somewhere. We update the buffer
+ // pointer the caller passes as a more convenient way of doing this.
+ //
+ // If I could just remap physical in the list to virtual easily here,
+ // I wouldn't need to do it.
+ //
+ do
+ {
+ PSCATTER_GATHER_ENTRY Entry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ ExAllocateFromNPagedLookasideList (
+ &m_ScatterGatherLookaside
+ )
+ );
+
+ if (!Entry)
+ {
+ break;
+ }
+
+ Entry ->CloneEntry = nullptr;
+ Entry -> Virtual = nullptr;
+ Entry -> ByteCount = 0;
+
+
+ Entry ->CloneEntry = *Clone;
+ Entry -> CloneEntry -> StreamHeader -> PresentationTime.Time = 0;
+ Entry -> CloneEntry -> StreamHeader -> OptionsFlags &= ~KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
+
+ Entry -> Virtual = *Buffer;
+ Entry -> ByteCount = MappingsCount;
+ Entry->PhotoConfirmationInfo = PHOTOCONFIRMATION_INFO();
+
+ //
+ // Move forward a specific number of bytes in chunking this into
+ // mapping sized va buffers.
+ //
+ *Buffer += MappingsCount;
+ Mappings = reinterpret_cast <PKSMAPPING> (
+ (reinterpret_cast <PUCHAR> (Mappings) + MappingStride)
+ );
+
+ InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry));
+ m_ScatterGatherMappingsQueued++;
+ MappingsInserted = MappingsCount;
+ DBG_TRACE("m_ScatterGatherMappingsQueued=%d", m_ScatterGatherMappingsQueued);
+ m_ScatterGatherBytesQueued += MappingsCount;
+
+ }
+ while(FALSE);
+
+ DBG_LEAVE(" MappingsInserted=%d", MappingsInserted );
+
+ return MappingsInserted;
+
+}
+
+/**************************************************************************
+
+ The following are helper functions used in the production of metadata.
+ Since this is just a simulation, most "auto" modes get converted into
+ a random value that is in range.
+
+ While simple, this still requires writing a helper function for each
+ piece of data.
+
+**************************************************************************/
+
+//
+// Translate Exposure settings into a "current value".
+//
+LONGLONG
+CHardwareSimulation::
+GetCurrentExposureTime()
+{
+ PAGED_CODE();
+
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+ LONGLONG Value = 0;
+ LPCSTR Mode = "[UNKNOWN]";
+
+ if( pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO )
+ {
+ // Get random value in global setting's bound (LONG)
+ // I'm abandoning the reported min/max and using something more reasonable.
+ Value = GetRandom( MIN_EXPOSURE_TIME*5, DEF_EXPOSURE_TIME*5 );
+ Mode = "KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO";
+ }
+
+ if( pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Value = pSettings->ExposureSetting.VideoProc.Value.ll;
+ Mode = "KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL";
+ }
+
+ // Locked just reports the last value set...
+ if( pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK )
+ {
+ Value = m_LastReportedExposureTime;
+ Mode = "KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK";
+ }
+
+ DBG_TRACE("ExposureMode=0x%016llX (%s), Time=%llu00ns, LastReported=%llu00ns",
+ pSettings->ExposureMode, Mode, Value, m_LastReportedExposureTime );
+
+ m_LastReportedExposureTime = Value;
+ return Value;
+}
+
+//
+// Translate White Balance into a "current value".
+//
+ULONG
+CHardwareSimulation::
+GetCurrentWhiteBalance()
+{
+ PAGED_CODE();
+
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+ ULONG Value = 0;
+
+ if( pSettings->WhiteBalanceMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO )
+ {
+ Value = (ULONG) GetRandom( pSettings->WhiteBalanceSetting.Min, pSettings->WhiteBalanceSetting.Max );
+ }
+
+ if( pSettings->WhiteBalanceMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Value = pSettings->WhiteBalanceSetting.VideoProc.Value.ul;
+ }
+
+ // Locked just reports the last value set...
+ if( pSettings->WhiteBalanceMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK )
+ {
+ Value = m_LastReportedWhiteBalance;
+ }
+
+ m_LastReportedWhiteBalance= Value;
+ return Value;
+}
+
+//
+// Translate ISO settings into a "current value".
+//
+ULONG
+CHardwareSimulation::
+GetCurrentISOSpeed()
+{
+ PAGED_CODE();
+
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+ ULONG Value = 0;
+
+ if( pSettings->ISOMode & KSCAMERA_EXTENDEDPROP_ISO_AUTO )
+ {
+ Value = GetRandom( (ULONG) 50, (ULONG) 3200 );
+ }
+ else if( pSettings->ISOMode & KSCAMERA_EXTENDEDPROP_ISO_MANUAL )
+ {
+ Value = pSettings->ISOValue;
+ }
+ else
+ {
+ Value = // Try converting any legacy presets to a manual value.
+ IsoPreset2Value( pSettings->ISOMode );
+ }
+ return Value;
+}
+
+//
+// Translate Exposure Mode to an Exif Exposure Program value
+//
+USHORT
+CHardwareSimulation::
+GetExposureProgram()
+{
+ PAGED_CODE();
+
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+ USHORT Value = 0; // Undefined.
+
+ if( pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Value = 1; // Manual
+ }
+ if( pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_AUTO )
+ {
+ Value = 2; // Normal
+ }
+
+ // TODO: Extend SceneMode to ISP settings so I can use it here to capture Portrait mode, etc.
+ return Value;
+}
+
+/*************************************************/
+
+//
+// Emit metadata here that is common to all pins.
+//
+// All derived classes' EmitMetadata() function must
+// call this function first.
+//
+void
+CHardwareSimulation::
+EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+)
+{
+ PAGED_CODE();
+
+ NT_ASSERT(pStreamHeader);
+
+ if (0 != (pStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_METADATA))
+ {
+ PKS_FRAME_INFO pFrameInfo = (PKS_FRAME_INFO)(pStreamHeader + 1);
+ PKSSTREAM_METADATA_INFO pMetadata = (PKSSTREAM_METADATA_INFO) (pFrameInfo + 1);
+ //PBYTE pData = (PBYTE) pMetadata->SystemVa;
+ //ULONG BytesLeft = pMetadata->BufferSize;
+
+ // A real driver might write focus state or other info here. We've got nothing.
+ pMetadata->UsedSize = 0;
+ }
+ else
+ {
+ DBG_TRACE("Metadata not present...");
+ }
+}
+
+void
+CHardwareSimulation::
+EmitFaceMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader,
+ _In_ ULONG Count,
+ _In_ ULONGLONG Flags,
+ _In_ ULONG DelayLimit
+)
+/*++
+
+Routine Description:
+
+ Helper function that emits FaceDetection metadata.
+
+ Note: This function assumes a metadata buffer is present.
+
+Arguments:
+
+ pStreamHeader -
+ The frame's stream header.
+
+ Count -
+ The maximum number of faces to detect.
+
+ Flags -
+ A combination of the KSCAMERA_EXTENDEDPROP_FACEDETECTION_BLINK and
+ KSCAMERA_EXTENDEDPROP_FACEDETECTION_BLINK flags passed to the face
+ detection control. Used to decide what characterization data to
+ present in the metadata.
+
+ DelayLimit -
+ The maximum number of frames to delay before generating the next
+ face detection.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PAGED_CODE();
+
+ NT_ASSERT(pStreamHeader);
+ NT_ASSERT(Count <= SIZEOF_ARRAY(m_LastFaceDetect.Data));
+
+ // Do nothing if we're turned on, but they want no faces.
+ if( Count==0 )
+ {
+ return;
+ }
+
+ if( --m_FaceDetectionDelay != 0 || // Count down our random delay for new face data.
+ Count > m_LastFaceDetect.Count ) // Make sure we never emit more faces than requested.
+ {
+ ULONG CountReported = GetRandom( 0, Count );
+
+ DBG_TRACE("Generating new faces (Count=%d, Flags=0x%016llX, Delay=%d)...",
+ Count, Flags, DelayLimit);
+
+ // Synthesize a new set of "detected" faces...
+ m_LastFaceDetect.Header.MetadataId = (ULONG) MetadataId_Custom_FaceDetection;
+ m_LastFaceDetect.Header.Size =
+ sizeof(CAMERA_METADATA_FACEHEADER) + (sizeof(METADATA_FACEDATA) * CountReported);
+
+ m_LastFaceDetect.Count = CountReported;
+ m_LastFaceDetect.Flags = Flags;
+ m_LastFaceDetect.Timestamp = pStreamHeader->PresentationTime.Time ;
+
+ DBG_TRACE("Count=%d, Flags=0x%016llX, Time=0x%016llX",
+ m_LastFaceDetect.Count,
+ m_LastFaceDetect.Flags,
+ m_LastFaceDetect.Timestamp );
+
+ // Report face data...
+ for( ULONG i=0; i<CountReported; i++ )
+ {
+ RtlZeroMemory( &m_LastFaceDetect.Data[i], sizeof(m_LastFaceDetect.Data[i]) );
+
+ RECT &rect = m_LastFaceDetect.Data[i].Region;
+ rect.top = GetRandom((LONG)0, TO_Q31(1)-2);
+ rect.left = GetRandom((LONG)0, TO_Q31(1)-2);
+ rect.bottom = GetRandom(rect.top+1, TO_Q31(1)-1);
+ rect.right = GetRandom(rect.left+1, TO_Q31(1)-1);
+
+ m_LastFaceDetect.Data[i].confidenceLevel = GetRandom((ULONG)25, 100); // Don't bother reporting really low confidence faces.
+
+ DBG_TRACE(" #%d: [(0x%08X,0x%08X), (0x%08X,0x%08X)](Conf=%d%%)",
+ i,
+ rect.top, rect.left, rect.bottom, rect.right,
+ m_LastFaceDetect.Data[i].confidenceLevel);
+
+ if( Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_BLINK )
+ {
+ m_LastFaceDetect.Data[i].BlinkScoreLeft = GetRandom((ULONG)0, 100); // Should really skew these numbers more in favor of no blink.
+ m_LastFaceDetect.Data[i].BlinkScoreRight = GetRandom((ULONG)0, 100);
+
+ DBG_TRACE(" --- Blink(left=%d%%, right=%d%%)",
+ m_LastFaceDetect.Data[i].BlinkScoreLeft,
+ m_LastFaceDetect.Data[i].BlinkScoreRight);
+ }
+
+ if( Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_SMILE )
+ {
+ m_LastFaceDetect.Data[i].FacialExpression = GetRandom((ULONG)0, 1) ? EXPRESSION_SMILE : 0;
+ m_LastFaceDetect.Data[i].FacialExpressionScore = GetRandom((ULONG)0, 100);
+
+ DBG_TRACE(" --- Smile(exp=%s, score=%d%%)",
+ (m_LastFaceDetect.Data[i].FacialExpression==EXPRESSION_SMILE ? "Smile":"[unknown]"),
+ m_LastFaceDetect.Data[i].FacialExpressionScore);
+ }
+ }
+
+ // Randomly choose when to generate new facedetection data.
+ m_FaceDetectionDelay = GetRandom( 1, DelayLimit );
+ DBG_TRACE("Delay to next is %d", m_FaceDetectionDelay);
+ }
+
+ // The flags can change between face detection updates.
+ // Drop the additional characterization data immediately, if requested.
+ // We can hardly add it that fast since it might not be generated straight away.
+ ULONGLONG LostFlags = m_LastFaceDetect.Flags & ~Flags;
+ for( ULONG i=0; i<m_LastFaceDetect.Count; i++ )
+ {
+ if( LostFlags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_BLINK )
+ {
+ m_LastFaceDetect.Data[i].BlinkScoreLeft = 0;
+ m_LastFaceDetect.Data[i].BlinkScoreRight = 0;
+ }
+ if( LostFlags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_SMILE )
+ {
+ m_LastFaceDetect.Data[i].FacialExpression = 0;
+ m_LastFaceDetect.Data[i].FacialExpressionScore = 0;
+ }
+ }
+ m_LastFaceDetect.Flags &= Flags;
+
+ PKS_FRAME_INFO pFrameInfo = (PKS_FRAME_INFO)(pStreamHeader + 1);
+ PKSSTREAM_METADATA_INFO pMetadata = (PKSSTREAM_METADATA_INFO) (pFrameInfo + 1);
+ ULONG BytesLeft = pMetadata->BufferSize - pMetadata->UsedSize;
+
+ // Write Face Detection Info here
+ // Note: If we derived Video and Preview from a common base class, we
+ // might use that to emit this information for both types.
+ if( BytesLeft >= m_LastFaceDetect.Header.Size )
+ {
+ // Always write the most recently generated face detection info.
+ RtlCopyMemory(
+ ((PBYTE)pMetadata->SystemVa) + pMetadata->UsedSize,
+ &m_LastFaceDetect,
+ m_LastFaceDetect.Header.Size );
+
+ DBG_TRACE("Emitting Face metadata...");
+
+ BytesLeft -= m_LastFaceDetect.Header.Size;
+ pMetadata->UsedSize += m_LastFaceDetect.Header.Size;
+ }
+ else
+ {
+ DBG_TRACE("WARNING: Out of metadata buffer...");
+ }
+}
+
+//
+// PIN_STATE text for debug output.
+//
+static
+const char *
+GetPinStateTxt( PIN_STATE state )
+{
+ PAGED_CODE();
+
+ switch( state )
+ {
+ case PinStopped:
+ return "STOPPED";
+ case PinPaused:
+ return "PAUSED";
+ case PinRunning:
+ return "RUNNING";
+ }
+ return "[UNKNOWN]";
+}
+
+NTSTATUS
+CHardwareSimulation::
+FillScatterGatherBuffers()
+
+/*++
+
+Routine Description:
+
+ The hardware has synthesized a buffer and we're to fill a frame buffer.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER("() m_PinState=%s, m_PinID=0x%08X, m_ImageSize=0x%08X, m_ScatterGatherMappingsQueued=%u, "
+ "m_ScatterGatherBytesQueue=0x%08X",
+ GetPinStateTxt(m_PinState),
+ m_PinID, m_ImageSize, m_ScatterGatherMappingsQueued, m_ScatterGatherBytesQueued);
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+
+ ULONG BufferRemaining = m_ImageSize;
+
+ //
+ // If there isn't a frame buffer queued, we justskip the frame and consider
+ // it starvation.
+ //
+ while (BufferRemaining &&
+ !IsListEmpty(&m_ScatterGatherMappings) &&
+ m_ScatterGatherBytesQueued >= BufferRemaining)
+ {
+ LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings);
+ m_ScatterGatherMappingsQueued--;
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+
+ // Deal with cancellation.
+ PIRP pIrp = KsStreamPointerGetIrp(SGEntry->CloneEntry, FALSE, FALSE);
+ if (pIrp)
+ {
+ if (pIrp->Cancel)
+ {
+ DBG_TRACE( "Cancelling..." );
+ FreeSGEntry( listEntry, L"StreamPointer Cancel SG List" );
+ continue;
+ }
+ }
+
+ //
+ // Since we're software, we'll be accessing this by virtual address...
+ //
+ ULONG Stride = 0;
+ if ( SGEntry->CloneEntry -> StreamHeader -> Size >= sizeof (KSSTREAM_HEADER) +
+ sizeof (KS_FRAME_INFO))
+ {
+ PKS_FRAME_INFO FrameInfo = reinterpret_cast <PKS_FRAME_INFO> (SGEntry->CloneEntry->StreamHeader+1);
+ Stride = (ULONG) ABS(FrameInfo->lSurfacePitch);
+ }
+
+ // Have the synthesizer output a frame to the buffer.
+ ULONG BytesCopied = m_Synthesizer->DoCommit( SGEntry->Virtual, SGEntry->ByteCount, Stride );
+ NT_ASSERT( BytesCopied );
+ DBG_TRACE( "BytesCopied = %d", BytesCopied );
+
+ //Adding time stamp
+ if(m_PhotoConfirmationEntry.isRequired())
+ {
+ SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Time =
+ m_PhotoConfirmationEntry.getTime();
+ DBG_TRACE("Using Photo Confirmation time = 0x%016llX", m_PhotoConfirmationEntry.getTime());
+ }
+ else
+ {
+ SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Time = ConvertQPCtoTimeStamp(NULL);
+ DBG_TRACE("PresentationTime = 0x%016llX", SGEntry->CloneEntry->StreamHeader->PresentationTime.Time );
+ }
+
+ SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Numerator =
+ SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Denominator = 1;
+
+ SGEntry -> CloneEntry -> StreamHeader -> OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID ;
+
+ // Add metadata to the sample.
+ EmitMetadata( SGEntry -> CloneEntry -> StreamHeader );
+
+ BufferRemaining = 0; //-= BytesCopied;
+ m_NumMappingsCompleted++;
+ m_ScatterGatherBytesQueued -= SGEntry -> ByteCount;
+
+ //
+ // Release the scatter / gather entry back to our lookaside.
+ //
+ ExFreeToNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ reinterpret_cast <PVOID> (SGEntry)
+ );
+
+ }
+
+ // Report an error if we used the last buffer.
+ if (BufferRemaining)
+ {
+ //DBG_TRACE("BufferRemaining=%u", BufferRemaining);
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ DBG_LEAVE("() = 0x%08X", ntStatus);
+ return ntStatus;
+}
+
+/**************************************************************************
+
+ Debug helpers
+
+**************************************************************************/
+
+PCCHAR
+DVS_Text( ULONGLONG Flags )
+{
+ PAGED_CODE();
+
+ switch( Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_OFF: return "Off";
+ case KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_ON: return "On";
+ case KSCAMERA_EXTENDEDPROP_VIDEOSTABILIZATION_AUTO: return "Auto";
+ default:
+ {
+ static
+ CHAR buffer[32];
+
+ RtlStringCbPrintfA(buffer, sizeof(buffer), "Unknown [0x%016llX]", Flags);
+ return (PCCHAR) buffer;
+ }
+ }
+}
+
+PCCHAR
+OIS_Text( ULONGLONG Flags )
+{
+ PAGED_CODE();
+
+ switch( Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_OIS_OFF: return "Off";
+ case KSCAMERA_EXTENDEDPROP_OIS_ON: return "On";
+ case KSCAMERA_EXTENDEDPROP_OIS_AUTO: return "Auto";
+ default:
+ {
+ static
+ CHAR buffer[32];
+
+ RtlStringCbPrintfA(buffer, sizeof(buffer), "Unknown [0x%016llX]", Flags);
+ return (PCCHAR) buffer;
+ }
+ }
+}
+
+/**************************************************************************/
+
+void
+CHardwareSimulation::
+FakeHardware (
+)
+
+/*++
+
+Routine Description:
+
+ Simulate an interrupt and what the hardware would have done in the
+ time since the previous interrupt.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ KScopedMutex Lock( m_ListLock );
+
+ m_InterruptTime++;
+
+ //
+ // The hardware can be in a pause state in which case, it issues interrupts
+ // but does not complete mappings. In this case, don't bother synthesizing
+ // a frame and doing the work of looking through the mappings table.
+ //
+ if (m_PinState == PinRunning)
+ {
+ //
+ // Generate a "time stamp" just to overlay it onto the capture image.
+ // It makes it more exciting than bars that do nothing.
+ //
+ ULONGLONG time = ConvertQPCtoTimeStamp(NULL);
+ DBG_TRACE("QPC=0x%016llX", time);
+
+ m_Synthesizer->SetFrameNumber( m_InterruptTime );
+ m_Synthesizer->SetRelativePts( (m_InterruptTime + 1) * m_TimePerFrame );
+ m_Synthesizer->SetQpcTime( time );
+
+ m_Synthesizer->DoSynthesize();
+
+ CHAR Text[64];
+
+ CExtendedProperty Control;
+ m_Sensor->GetVideoStabilization( &Control );
+ RtlStringCbPrintfA(Text, sizeof(Text), "DVS: %s", DVS_Text(Control.Flags));
+ m_Synthesizer->OverlayText( 0, m_Height-38, 1, Text, TRANSPARENT, TEXT_COLOR );
+
+ m_Sensor->GetOpticalImageStabilization( &Control );
+ RtlStringCbPrintfA(Text, sizeof(Text), "OIS: %s", OIS_Text(Control.Flags));
+ m_Synthesizer->OverlayText( 0, m_Height-48, 1, Text, TRANSPARENT, TEXT_COLOR );
+
+ //
+ // Fill scatter gather buffers
+ //
+ if (!NT_SUCCESS (FillScatterGatherBuffers ()))
+ {
+ InterlockedIncrement (PLONG (&m_NumFramesSkipped));
+ }
+
+ }
+
+ //
+ // Issue an interrupt to our hardware sink. This is a "fake" interrupt.
+ // It will occur at DISPATCH_LEVEL.
+ //
+ m_Sensor -> Interrupt (m_PinID);
+
+ //
+ // Schedule the timer for the next interrupt time, if the pin is still running.
+ //
+ if( m_PinState == PinRunning )
+ {
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart +
+ (m_TimePerFrame * (m_InterruptTime + 1));
+
+#ifdef ENABLE_TRACING // To keep us from a tight spin when trying to debug this code...
+ LARGE_INTEGER Now;
+ KeQuerySystemTime(&Now);
+
+ if( Now.QuadPart >= NextTime.QuadPart )
+ {
+ NextTime.QuadPart = 0LL - m_TimePerFrame ;
+ }
+
+#endif
+ m_IsrTimer.Set( NextTime );
+ }
+}
+
+ULONGLONG
+CHardwareSimulation::
+ConvertQPCtoTimeStamp(
+ _In_opt_ PLARGE_INTEGER pQpcTime
+)
+/*++
+
+Routine Description:
+
+ Get the QPC measured in 100ns units.
+
+Arguments:
+
+ pQpcTime -
+ An optional time value to convert. If NULL, use the current QPC.
+
+Return Value:
+
+ ULONLONG -
+ The time in 100ns increments.
+
+--*/
+{
+ PAGED_CODE();
+
+ LARGE_INTEGER qpcTime = {0};
+ LARGE_INTEGER qpcFrequency;
+
+ qpcTime = KeQueryPerformanceCounter(&qpcFrequency);
+
+ if( pQpcTime )
+ {
+ qpcTime = *pQpcTime;
+ }
+
+ return KSCONVERT_PERFORMANCE_TIME( qpcFrequency.QuadPart, qpcTime );
+}
+
+NTSTATUS
+CHardwareSimulation::
+GeneratePhotoConfirmation(
+ _In_ ULONG PfsFrameNumber,
+ _In_ LONGLONG time
+)
+/*++
+
+Routine Description:
+
+ So a photo sim can ask a preview sim for a confirmation frame.
+
+Arguments:
+
+ PfsFrameNumber -
+ The VPS shot number.
+ time -
+ The precise time of the associated photo.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ KScopedMutex Lock( m_ListLock );
+
+ if( PinRunning != m_PinState )
+ {
+ return STATUS_DEVICE_NOT_READY;
+ }
+
+ DBG_ENTER("( Index=%d, Time=0x%016llX )", PfsFrameNumber, time );
+
+ m_PhotoConfirmationEntry = PHOTOCONFIRMATION_INFO( PfsFrameNumber, time );
+
+ // We basically used the previously synthesized preview image
+ NTSTATUS status = FillScatterGatherBuffers();
+
+ //Clean up the photo confiramtion flag
+ m_PhotoConfirmationEntry = PHOTOCONFIRMATION_INFO();
+
+ if(NT_SUCCESS(status))
+ {
+ m_Sensor->Interrupt (m_PinID);
+ }
+
+ DBG_LEAVE("() = 0x%08X", status);
+
+ return status;
+}
+
+void
+CHardwareSimulation::
+FreeSGEntry(
+ _In_ PLIST_ENTRY Entry,
+ _In_ PCWSTR EventName,
+ _In_opt_ LPCGUID Activity,
+ _In_ ULONG DataUsed
+)
+{
+ PAGED_CODE();
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ Entry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+
+ NT_ASSERT(SGEntry->CloneEntry);
+ NT_ASSERT(SGEntry->CloneEntry->StreamHeader);
+
+ SGEntry->CloneEntry->StreamHeader->DataUsed = DataUsed;
+
+ KsStreamPointerDelete(SGEntry->CloneEntry);
+
+ //
+ // Release the scatter / gather entry back to our lookaside.
+ //
+ ExFreeToNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ SGEntry
+ );
+}
+
+void
+CHardwareSimulation::
+FreeSGList(
+ _In_ PLIST_ENTRY List,
+ _In_ PCWSTR EventName,
+ _In_opt_ LPCGUID Activity
+)
+{
+ PAGED_CODE();
+
+ while(!IsListEmpty(List))
+ {
+ PLIST_ENTRY head = RemoveHeadList(List);
+ m_ScatterGatherMappingsQueued--;
+ FreeSGEntry( head, EventName, Activity );
+ }
+}
+
+//
+// Get the current frame settings.
+//
+ISP_FRAME_SETTINGS *
+CHardwareSimulation::
+GetIspSettings(void)
+{
+ PAGED_CODE();
+
+ return m_Sensor->GetGlobalIspSettings();
+}
diff --git a/AVStream/avscamera/sys/hwsim.h b/AVStream/avscamera/sys/hwsim.h
new file mode 100644
index 00000000..247de1f0
--- /dev/null
+++ b/AVStream/avscamera/sys/hwsim.h
@@ -0,0 +1,316 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ hwsim.h
+
+ Abstract:
+
+ This file contains the definition of the base class, CHardwareSimulation,
+ used to simulate a camera's capture stream.
+
+ Our simulation cannot mimic a real camera with any precision. A real
+ camera would likely have dedicated hardware to provide interrupts, do
+ DMA transfers of frames from an internal buffer as well as do scaling
+ and on-the-fly colorspace and planar format conversions so as to supply
+ frames for preview, video and photo in varying resolutions and
+ colorspaces.
+
+ This simulation does not have such hardware, so instead it synthesizes
+ a frame on the fly for each local pin as required. The frame is
+ synthesized from common state information, so the images produced
+ should be comparable from pin to pin. CHardwareSimulation is used as
+ a base class for each simulated pin / hardware.
+
+ A CHardwareSimulation contains state, a list of frame bufferss and a
+ timer that is used in place of a hardware interrupt. The timer
+ schedules a workitem that is used to synthesize an image, select a
+ buffer and copy that image into the buffer.
+
+ Specializations of CHardwareSimulation provide differing metadata and
+ implement specialized functionality for photo sequence and variable
+ photo sequence.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+#define SCATTER_GATHER_MAPPINGS_MAX 128
+
+// forward class references
+class CSensor;
+class CHardwareSimulation;
+class CHwSimTimer;
+
+// internal structure definitions
+
+// Face metadata structure. Face metadata can be synthesized on any pin.
+class CAMERA_METADATA_FACE_DETECTION
+ : public CAMERA_METADATA_FACEHEADER
+{
+public:
+ METADATA_FACEDATA Data[MAX_FACES];
+};
+
+// Information about each frame buffer in the queue.
+typedef struct _SCATTER_GATHER_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ PKSSTREAM_POINTER CloneEntry;
+ PUCHAR Virtual;
+ ULONG ByteCount;
+ PHOTOCONFIRMATION_INFO PhotoConfirmationInfo;
+} SCATTER_GATHER_ENTRY, *PSCATTER_GATHER_ENTRY;
+
+//
+// A specialization of a KPassiveTimer that holds a back pointer to the
+// CHardwareSimulation that owns it.
+//
+class CHwSimTimer
+ : public KPassiveTimer
+{
+ CHardwareSimulation *m_Parent;
+
+public:
+ CHwSimTimer(
+ _In_ CHardwareSimulation *Parent
+ );
+
+ //
+ // Sets the timer
+ //
+ BOOLEAN
+ Set(
+ _In_ LARGE_INTEGER DueTime
+ );
+
+private:
+ static
+ void
+ Handler(
+ _In_opt_ PVOID Context
+ );
+};
+
+class CHardwareSimulation
+{
+protected:
+ CSynthesizer *m_Synthesizer; // Synthesizer for various formats.
+ LONGLONG m_TimePerFrame;
+ ULONG m_Width;
+ ULONG m_Height;
+ ULONG m_ImageSize;
+ LONG m_PinID;
+ KMutex m_ListLock;
+ LIST_ENTRY m_ScatterGatherMappings;
+
+ NPAGED_LOOKASIDE_LIST m_ScatterGatherLookaside;
+ PIN_STATE m_PinState;
+ ULONG m_ScatterGatherMappingsMax;
+ ULONG m_NumMappingsCompleted;
+ ULONG m_ScatterGatherMappingsQueued;
+ ULONG m_ScatterGatherBytesQueued;
+ ULONG m_NumFramesSkipped;
+ ULONG m_InterruptTime;
+ LARGE_INTEGER m_StartTime;
+
+ CSensor *m_Sensor;
+ CHwSimTimer m_IsrTimer;
+
+ PHOTOCONFIRMATION_INFO m_PhotoConfirmationEntry;
+
+ // Cached values used for Locking simulated state.
+ LONGLONG m_LastReportedExposureTime;
+ ULONG m_LastReportedWhiteBalance;
+
+ // Used to simulate the skipping of frames when reporting face detection data.
+ ULONG m_FaceDetectionDelay;
+ CAMERA_METADATA_FACE_DETECTION m_LastFaceDetect;
+
+ // Copy a synthesized framebuffer.
+ virtual
+ NTSTATUS
+ FillScatterGatherBuffers();
+
+ // Overloadable function for attaching metadata to a frame.
+ virtual
+ void
+ EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+ );
+
+ // Helper function to generate random face metadata.
+ void
+ EmitFaceMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader,
+ _In_ ULONG Count,
+ _In_ ULONGLONG Flags,
+ _In_ ULONG DelayLimit=30
+ );
+
+ // Release an entry from our queue.
+ void
+ FreeSGEntry(
+ _In_ PLIST_ENTRY Entry,
+ _In_ PCWSTR EventName=L"StreamPointer freed",
+ _In_opt_ LPCGUID Activity=NULL,
+ _In_ ULONG DataUsed=0
+ );
+
+ // Release our entire queue.
+ void
+ FreeSGList(
+ _In_ PLIST_ENTRY List,
+ _In_ PCWSTR EventName=L"StreamPointer freed",
+ _In_opt_ LPCGUID Activity=NULL
+ );
+
+public:
+
+ // Debug helper
+ LONG GetSkippedFrameCount()
+ {
+ return m_NumFramesSkipped;
+ }
+
+ // Constructor
+ CHardwareSimulation (
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+ );
+
+ // Destructor
+ virtual
+ ~CHardwareSimulation ();
+
+ // Periodic interrupt handling
+ virtual
+ void
+ FakeHardware (
+ );
+
+ // Start streaming.
+ virtual
+ NTSTATUS
+ Start (
+ CSynthesizer *ImageSynth,
+ IN LONGLONG TimePerFrame,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG ImageSize
+ );
+
+ // Pause streaming
+ virtual
+ NTSTATUS
+ Pause (
+ IN BOOLEAN Pausing
+ );
+
+ // Stop streaming.
+ virtual
+ NTSTATUS
+ Stop();
+
+ // Reset streaming.
+ virtual
+ NTSTATUS
+ Reset(
+ IN PKSPIN Pin
+ );
+
+ // Reset streaming.
+ virtual
+ NTSTATUS
+ Reset();
+
+ // Add a frame buffer to our queue.
+ virtual
+ ULONG
+ ProgramScatterGatherMappings (
+ IN PKSSTREAM_POINTER *Clone,
+ IN PUCHAR *Buffer,
+ IN PKSMAPPING Mappings,
+ IN ULONG MappingsCount,
+ IN ULONG MappingStride
+ );
+
+ // Initialization.
+ virtual
+ BOOLEAN
+ Initialize();
+
+ // Number of frames completed during this run.
+ ULONG
+ ReadNumberOfMappingsCompleted();
+
+ // Get the QPC measured in 100ns units.
+ ULONGLONG
+ ConvertQPCtoTimeStamp(
+ _In_opt_ PLARGE_INTEGER pQpcTime
+ );
+
+ // Get the current frame settings.
+ virtual
+ ISP_FRAME_SETTINGS *
+ GetIspSettings(void);
+
+ // So a photo sim can ask a preview sim for a confirmation frame.
+ NTSTATUS
+ GeneratePhotoConfirmation(
+ _In_ ULONG PfsFrameNumber,
+ _In_ LONGLONG time
+ );
+
+ // Get the exposure value for the current frame.
+ LONGLONG
+ GetCurrentExposureTime();
+
+ // Get the White balance for the current frame.
+ ULONG
+ GetCurrentWhiteBalance();
+
+ // Get the ISO Speed value for the current frame.
+ ULONG
+ GetCurrentISOSpeed();
+
+ // Get the Lens position for the current frame.
+ ULONG
+ GetCurrentLensPosition();
+
+ // Get the Scene Mode for the current frame.
+ ULONG
+ GetCurrentSceneMode();
+
+ // Translate Exposure Mode to an Exif Exposure Program value
+ USHORT
+ GetExposureProgram();
+
+ // Pin state accessor...
+ PIN_STATE
+ GetState()
+ {
+ return m_PinState;
+ }
+
+ friend class CHwSimTimer;
+};
+
+//
+// Sets the timer using our callback and our parent CHardwareSimulation.
+//
+inline
+BOOLEAN
+CHwSimTimer::
+Set(
+ _In_ LARGE_INTEGER DueTime
+)
+{
+ return KPassiveTimer::Set( DueTime, Handler, m_Parent );
+}
diff --git a/AVStream/avscamera/sys/imagecapture.cpp b/AVStream/avscamera/sys/imagecapture.cpp
new file mode 100644
index 00000000..06d334d3
--- /dev/null
+++ b/AVStream/avscamera/sys/imagecapture.cpp
@@ -0,0 +1,155 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ imagecapture.cpp
+
+ Abstract:
+
+ An implementation of CImageCapturePin
+
+ History:
+
+ created 3/8/2001
+
+**************************************************************************/
+
+#include "Common.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+CImageCapturePin::
+CImageCapturePin(
+ _In_ PKSPIN Pin
+) : CCapturePin (Pin)
+{
+ PAGED_CODE();
+}
+
+NTSTATUS
+CImageCapturePin::
+DispatchCreate(
+ _In_ PKSPIN Pin,
+ _In_ PIRP Irp
+)
+/*++
+
+Routine Description:
+
+ Static member function called when a pin is created. Instantiate a
+ CImageCapturePin and attach it to our filter object.
+
+Arguments:
+
+ Pin -
+ The KSPIN to wrap.
+
+ Irp -
+ The IRP assocated with this request.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE();
+
+ DBG_ENTER("(Pin=%d)", Pin->Id);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CCaptureFilter* pFilter = reinterpret_cast <CCaptureFilter*>(KsPinGetParentFilter(Pin)->Context);
+ CImageCapturePin *CapPin = new (NonPagedPoolNx) CImageCapturePin (Pin);
+
+ if( !CapPin )
+ {
+ // Fail if we couldn't create the pin.
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ // Query the filter for the PhotoMode so we can figure out how many frames should be allocated.
+ CExtendedPhotoMode Mode;
+ Mode.PinId = Pin->Id; // Use Pin ID from KS.
+ Status = pFilter->GetPhotoMode( &Mode );
+
+ // CSensor::GetPhotoMode could fail if the framework gives us a Pin ID that doesn't match our descriptors...
+ if( NT_SUCCESS(Status) )
+ {
+ // Override the number of frames.
+ CapPin->SetDesiredFrames(
+ ( (Mode.Flags & KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE) ?
+ Mode.RequestedHistoryFrames() : 1)
+ + IMAGE_CAPTURE_PIN_MINIMUM_FRAMES );
+
+ Status =
+ CapPin->Initialize();
+ }
+ }
+
+ if (NT_SUCCESS (Status))
+ {
+ //
+ // Adjust the stream header size. The video packets have extended
+ // header info (KS_FRAME_INFO).
+ //
+ pFilter->setPin(CapPin, Pin->Id);
+ }
+ else
+ {
+ // Clean up.
+ delete CapPin;
+ }
+
+ DBG_LEAVE("(Pin=%d)=0x%08X", Pin->Id, Status);
+ return Status;
+}
+
+
+NTSTATUS
+CImageCapturePin::
+Close(
+ _In_ PIRP Irp
+)
+{
+ PAGED_CODE();
+
+ Reset();
+
+ return STATUS_SUCCESS;
+}
+
+// ImageCapturePinDispatch:
+//
+// This is the dispatch table for the capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc...
+// just a copy of CapturePinDispatch for now.
+//
+DEFINE_CAMERA_KSPIN_DISPATCH( ImageCapturePinDispatch, CImageCapturePin );
+
+
+//
+// ImagePinAllocatorFraming:
+//
+// This is the simple framing structure for the capture pin. Note that this
+// will be modified via KsEdit when the actual capture format is determined.
+// just a copy of CapturePinAllocatorFraming for now.
+//
+DECLARE_SIMPLE_FRAMING_EX (
+ ImageCapturePinAllocatorFraming,
+ STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED),
+ KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
+ KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY,
+ 4,
+ 0,
+ 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE
+);
+
diff --git a/AVStream/avscamera/sys/imagecapture.h b/AVStream/avscamera/sys/imagecapture.h
new file mode 100644
index 00000000..1e11c31a
--- /dev/null
+++ b/AVStream/avscamera/sys/imagecapture.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ imagecapture.h
+
+ Abstract:
+
+ Image Capture Pin - A specialization of a capture pin.
+
+ CImageCapturePin defines a unique list of data ranges for the image
+ pin.
+
+ History:
+
+ created 3/8/2001
+
+**************************************************************************/
+#pragma once
+
+#include "capture.h"
+
+class CImageCapturePin : public CCapturePin
+{
+public:
+ static NTSTATUS DispatchCreate(
+ _In_ PKSPIN Pin,
+ _In_ PIRP Irp
+ );
+
+private:
+ virtual
+ NTSTATUS Close(
+ _In_ PIRP Irp
+ );
+
+ CImageCapturePin(
+ _In_ PKSPIN Pin
+ );
+};
diff --git a/AVStream/avscamera/sys/imagehwsim.cpp b/AVStream/avscamera/sys/imagehwsim.cpp
new file mode 100644
index 00000000..e6256d45
--- /dev/null
+++ b/AVStream/avscamera/sys/imagehwsim.cpp
@@ -0,0 +1,1509 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ ImageHwSim.cpp
+
+ Abstract:
+
+ This file contains the implementation of the CImageHardwareSimulation
+ class.
+
+ This is a specialization of CHardwareSimulation that provides photo-
+ specific metadata and implements specialized functionality for photo,
+ photo sequence and variable photo sequence.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+#include "Common.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+CImageHardwareSimulation::
+CImageHardwareSimulation (
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+)
+ : CHardwareSimulation( Sensor, PinID )
+ , m_Clock(NULL)
+ , m_PfsLoopLimit(0)
+ , m_PfsFrameLimit(0)
+ , m_pIspSettings(nullptr)
+ , m_PfsLoopNumber(0)
+ , m_PfsFrameNumber(0)
+ , m_GlobalFrameNumber(0)
+ , m_bEndOfSequence(FALSE)
+ , m_PastBufferCount(0) // Zero only when the simulation inits.
+
+/*++
+
+Routine Description:
+
+ Construct a hardware simulation
+
+Arguments:
+
+ Sensor -
+ The hardware sink interface. This is used to trigger
+ fake interrupt service routines from.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ InitializeListHead (&m_BurstList);
+}
+
+CImageHardwareSimulation::
+~CImageHardwareSimulation()
+{
+
+ PAGED_CODE();
+
+ SAFE_DELETE( m_pIspSettings );
+
+ if (m_Clock)
+ {
+ m_Clock -> Release ();
+ m_Clock = NULL;
+ }
+}
+
+/*************************************************/
+
+NTSTATUS
+CImageHardwareSimulation::
+Start (
+ _In_ CSynthesizer *ImageSynth,
+ _In_ ULONG Width,
+ _In_ ULONG Height,
+ _In_ ULONG ImageSize,
+ _In_ PIN_MODE pinMode
+)
+
+/*++
+
+Routine Description:
+
+ Start capturing frames. This turns on the timer and begins frame capture,
+ but it we do not deliver frames until we receive a Trigger. We keep track
+ of starvation starting at this point.
+
+Arguments:
+
+ ImageSynth -
+ The image synthesizer to use to generate pictures to display
+ on the capture buffer.
+
+ Width -
+ The image width
+
+ Height -
+ The image height
+
+ ImageSize -
+ The size of the image. We allocate a temporary scratch buffer
+ based on this size to fake hardware.
+
+ PinMode -
+ Normal or photosequence.
+
+
+Return Value:
+
+ Success / Failure (typical failure will be out of memory on the
+ scratch buffer, etc...)
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ DBG_ENTER("(Width=%d, Height=%d, ImageSize=%d, pinMode=%s): m_PinID=%d",
+ Width, Height, ImageSize, pinMode?"PinBurstMode":"PinNormalMode", m_PinID );
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ // Prevent state-changes during this call.
+ KScopedMutex Lock(m_ListLock);
+
+ m_Synthesizer = ImageSynth;
+
+ NT_ASSERT(ImageSize);
+ m_ImageSize = ImageSize;
+ m_Height = Height;
+ m_Width = Width;
+
+ m_NumMappingsCompleted = 0;
+ m_ScatterGatherMappingsQueued = 0;
+ m_NumFramesSkipped = 0;
+ m_InterruptTime = 0;
+ m_bTriggered = FALSE;
+ m_bEndOfSequence = FALSE;
+ m_pClone = NULL;
+ m_bPastBufferTrigger = FALSE;
+ m_PinMode = pinMode;
+ m_TriggerTime = 0;
+ m_bFlashed = FALSE;
+
+ DBG_TRACE("m_bTriggered=FALSE, m_bPastBufferTrigger=FALSE");
+
+ m_FlashStatus = 0;
+
+ // Initialize VPS counters.
+ m_PfsLoopNumber = 0 ;
+ m_PfsFrameNumber= 0 ;
+ m_GlobalFrameNumber = 0;
+
+ KeQuerySystemTime (&m_StartTime);
+
+ if( !m_Synthesizer->Initialize() )
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // If everything is ok, start issuing interrupts.
+ //
+ if (NT_SUCCESS (Status))
+ {
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart + m_TimePerFrame;
+
+ m_PinState = PinRunning;
+ m_IsrTimer.Set( NextTime );
+
+ }
+
+ DBG_LEAVE("(Width=%d, Height=%d, ImageSize=%d, pinMode=%s): m_PinID=%d, Status=0x%08X",
+ Width, Height, ImageSize, pinMode?"PinBurstMode":"PinNormalMode", m_PinID, Status );
+
+ return Status;
+
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+Trigger(
+ _In_ LONG mode
+)
+/*++
+
+Routine Description:
+
+ Take a picture / Begin delivering frames.
+
+Arguments:
+
+ mode -
+ Normal trigger, start or stop photo sequence.
+
+
+Return Value:
+
+ Success / Failure (typical failure will be out of memory on the
+ scratch buffer, etc...)
+
+--*/
+
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+
+ DBG_ENTER( "(mode=0x%08X), m_PinMode=%d", mode, m_PinMode );
+
+ KScopedMutex Lock( m_ListLock );
+
+ //Start Trigger for Burst Mode
+ if(mode & KS_VideoControlFlag_StartPhotoSequenceCapture)
+ {
+ if(m_bTriggered == FALSE && m_PinMode == PinBurstMode)
+ {
+ m_bPastBufferTrigger = TRUE;
+ m_bTriggered = TRUE;
+ DBG_TRACE("m_bTriggered=TRUE, m_bPastBufferTrigger=TRUE");
+
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ //Stop Trigger for Burst Mode
+ else if(mode & KS_VideoControlFlag_StopPhotoSequenceCapture)
+ {
+ if(m_bTriggered == TRUE && m_PinMode == PinBurstMode)
+ {
+ m_bTriggered = FALSE;
+ DBG_TRACE("m_bTriggered=FALSE");
+
+ // reset the PFS EOS, frame number and loop count.
+ m_bEndOfSequence = FALSE;
+ m_PfsFrameNumber = 0;
+ m_PfsLoopNumber = 0;
+
+ m_bFlashed = FALSE;
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ //Normal Trigger
+ else if(mode & KS_VideoControlFlag_Trigger )
+ {
+ if(m_PinMode == PinBurstMode)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ m_bTriggered = TRUE;
+ m_bEndOfSequence = FALSE;
+ DBG_TRACE("m_bTriggered=TRUE");
+ }
+ }
+
+ DBG_LEAVE("()");
+
+ return STATUS_SUCCESS;
+}
+
+
+LONG
+CImageHardwareSimulation::
+GetTriggerMode()
+/*++
+
+Returns the pin's current trigger mode and state:
+
+ Return Value:
+
+ mode -
+ Normal trigger, start or stop photo sequence.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ NTSTATUS status = STATUS_SUCCESS;
+ LONG mode = 0;
+
+ DBG_ENTER( "(), m_PinMode=%d", m_PinMode );
+
+ KScopedMutex Lock( m_ListLock );
+
+ if( m_bTriggered )
+ {
+ mode = (m_PinMode == PinBurstMode) ?
+ KS_VideoControlFlag_StartPhotoSequenceCapture :
+ KS_VideoControlFlag_Trigger;
+ }
+
+ DBG_LEAVE("()=0x%08X", mode);
+
+ return mode;
+}
+
+
+NTSTATUS
+CImageHardwareSimulation::
+SetMode(
+ _In_ ULONGLONG Flags,
+ _In_ ULONG PastBuffers
+)
+/*++
+
+Routine Description:
+
+ Set the photo sequence mode.
+
+Arguments:
+
+ Flags -
+ Normal or photo sequence.
+
+ PastBuffers -
+ Number of history frames to gather.
+
+
+Return Value:
+
+ Success / Failure (typical failure will be out of memory on the
+ scratch buffer, etc...)
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER( "(Flags=0x%016llX, PastBuffers=%d)", Flags, PastBuffers );
+
+ if(m_bTriggered == TRUE)
+ {
+ return STATUS_INVALID_TRANSACTION;
+ }
+
+ m_PastBufferCount = PastBuffers;
+
+ if(Flags & KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE)
+ {
+ m_PinMode = PinBurstMode;
+ }
+ else
+ {
+ m_PinMode = PinNormalMode;
+ }
+
+ DBG_LEAVE("()");
+
+ return STATUS_SUCCESS;
+}
+
+//
+// Set the interval between frames here.
+//
+NTSTATUS
+CImageHardwareSimulation::
+SetPhotoFrameRate(
+ _In_ ULONGLONG TimePerFrame
+)
+{
+ PAGED_CODE();
+
+ // Prevent state-changes during this call.
+ KScopedMutex Lock(m_ListLock);
+
+ m_TimePerFrame = TimePerFrame;
+
+ //
+ // Reschedule the timer if the hardware isn't being stopped.
+ //
+ if( m_PinState == PinRunning ) // && !m_StopHardware )
+ {
+ // First restart our start time. We can't use the old time.
+ KeQuerySystemTime( &m_StartTime );
+
+ //
+ // Reschedule the timer for the next interrupt time.
+ //
+ m_StartTime.QuadPart += m_TimePerFrame;
+ m_InterruptTime = 0;
+
+ m_IsrTimer.Set( m_StartTime );
+ }
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+Stop()
+
+/*++
+
+Routine Description:
+
+ Stop the hardware simulation...
+
+ Wait until the timer has stopped, flush the queue, dereference the clock
+ and reset our state before returning.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ // If the hardware is told to stop while it's running, we need to
+ // halt the interrupts first. If we're already paused, this has
+ // already been done.
+ //
+
+ DBG_ENTER("(): m_PinID=%d", m_PinID);
+
+ //
+ // Protect the S/G list
+ //
+ KScopedMutex Lock( m_ListLock );
+
+ CHardwareSimulation::Stop();
+
+ //
+ // Free S/G buffer
+ //
+ FreeSGList( &m_ScatterGatherMappings, L"StreamPointer Stop Burst List" );
+
+ if (m_Clock)
+ {
+ m_Clock -> Release ();
+ m_Clock = NULL;
+ }
+
+ m_bTriggered = FALSE;
+ m_bEndOfSequence = FALSE;
+ m_pClone = NULL;
+ m_bPastBufferTrigger = FALSE;
+ m_PinMode = PinNormalMode;
+ m_TriggerTime = 0;
+
+ DBG_TRACE("m_bTriggered=FALSE, m_bPastBufferTrigger=FALSE");
+
+ DBG_LEAVE("(): m_PinID=%d", m_PinID);
+
+ return STATUS_SUCCESS;
+}
+
+
+/*************************************************/
+
+
+//
+// Helper function that collects current settings into our metadata structure.
+//
+METADATA_IMAGEAGGREGATION
+CImageHardwareSimulation::
+GetMetadata()
+{
+ PAGED_CODE();
+
+ METADATA_IMAGEAGGREGATION Metadata;
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+
+ // Wipe the metadata so all settings will default to "Not Set".
+ RtlZeroMemory( &Metadata, sizeof(Metadata) );
+
+ // Identify the current PFS frame number.
+ // If PFS not active, then this item is not present.
+ Metadata.FrameId.Set = IsPfsActive();
+ Metadata.FrameId.Value = (ULONG) m_PfsFrameNumber;
+ DBG_TRACE("Metadata.FrameId.Set=%s, Metadata.FrameId.Value=%d",
+ (Metadata.FrameId.Set?"Yes":"No"), Metadata.FrameId.Value);
+
+ // Just reflect the exposure time from the setting.
+ //Metadata.ExposureTime.Set = TRUE;
+ //Metadata.ExposureTime.Value = GetCurrentExposureTime();
+
+ // Just reflect the ISO Speed from the setting.
+ Metadata.ISOSpeed = CMetadataLong(GetCurrentISOSpeed());
+ DBG_TRACE("ISO=%d, ISO Flags=0x%016llX", Metadata.ISOSpeed.Value, pSettings->ISOMode);
+
+ // TODO: Do we need to bracket this by whether or not a flash has been taken?
+ // Report the current flash mode.
+ Metadata.FlashOn = CMetadataLong((ULONG) pSettings->FlashMode);
+
+ // Report the current flash power.
+ Metadata.FlashPower = CMetadataLong(pSettings->FlashValue);
+
+ // Set the White Balance lock state.
+ Metadata.WhiteBalanceLocked = CMetadataLong(
+ ( (pSettings->WhiteBalanceMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK)
+ == KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK) );
+
+ // Set the Exposure lock state.
+ Metadata.ExposureLocked = CMetadataLong(
+ ( (pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK)
+ == KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_LOCK) );
+
+ Metadata.ExposureTime =
+ //CMetadataRational(GetCurrentExposureTime(), 10000000);
+ CMetadataLongLong( GetCurrentExposureTime() );
+
+ Metadata.LensPosition = CMetadataLong( pSettings->FocusSetting.VideoProc.Value.ul );
+
+ Metadata.SceneMode = CMetadataULongLong(KSCAMERA_EXTENDEDPROP_SCENEMODE_AUTO); //TODO: Need to fill in real value from CCaptureFilter::m_SceneMode
+
+ Metadata.WhiteBalanceMode = CMetadataLong((ULONG) pSettings->WhiteBalanceMode);
+
+ CExtendedVidProcSetting Zoom;
+ m_Sensor->GetZoom( &Zoom );
+ Metadata.ZoomFactor = CMetadataLong(Zoom.GetLONG()); //TODO: Fill in a real value from zoom simulation.
+
+ Metadata.FocusLocked = CMetadataLong(FALSE); //TODO: Fill in a real value when we complete the focus changes.
+
+ // Add EVCompensation metadata...
+ Metadata.EVCompensation = CMetadataEVCompensation(pSettings->EVCompensation.Mode, pSettings->EVCompensation.Value);
+
+ Metadata.Orientation = CMetadataShort(Metadata_Orientation_TopBottomLeftRight); //TODO: Randomize?
+
+ {
+ LARGE_INTEGER SystemTime;
+ LARGE_INTEGER LocalTime;
+
+ KeQuerySystemTimePrecise( &SystemTime );
+ ExSystemTimeToLocalTime( &SystemTime, &LocalTime );
+ RtlTimeToTimeFields( &LocalTime, &Metadata.LocalTime.Time );
+ Metadata.LocalTime.Set = TRUE;
+ }
+
+ Metadata.Make = CMetadataShortString("Make: Microsoft SOC Camera");
+ Metadata.Model = CMetadataShortString( "Model: AvsCam" );
+ Metadata.Software = CMetadataShortString( "Software: Microsoft Camera Sim" );
+
+ Metadata.ColorSpace.Set = TRUE;
+ Metadata.ColorSpace.Value = 0xFFFF; // 0xFFFF Means "uncalibrated". Use this value for all non-RGB formats.
+
+ Metadata.Gamma = CMetadataRational();
+
+ Metadata.MakerNote = CMetadataShortString( "Maker's Note..." );
+
+ // Just reflect the exposure time from the setting.
+ //Metadata.ExposureTime =
+ // CMetadataRational( GetCurrentExposureTime(), 1000 ); // report exposure time as milliseconds.
+
+ Metadata.FNumber = CMetadataRational(4); // Fake an FNumber of 4. // TODO: It looks like we might be able to calculate this.
+
+ Metadata.ExposureProgram.Set = TRUE;
+ Metadata.ExposureProgram.Value = GetExposureProgram();
+
+ Metadata.ShutterSpeedValue = CMetadataSRational(); // TODO: Calculate this from the ExposureTime. ***
+ Metadata.Aperture = CMetadataRational(4); // TODO: Calculate this from the F-Number. (We're currently faking the FNumber.)
+ Metadata.Brightness = CMetadataSRational(0); // TODO: Find a more reasonable brightness value.
+ Metadata.ExposureBias = CMetadataSRational(0); // TODO: More reasonable?
+ Metadata.SubjectDistance = CMetadataRational(0xFFFFFFFF); // Distance in meters. Infinity. (Anything better?)
+
+ Metadata.MeteringMode.Set = TRUE;
+ Metadata.MeteringMode.Value = (USHORT) GetRandom( (ULONG) 1, (ULONG) 6); // Pick a number ... any number.
+
+ Metadata.LightSource.Set = TRUE;
+ Metadata.LightSource.Value = 1; // TODO: Pick a random value; but override when a flash occurs.
+
+ Metadata.Flash.Set = TRUE;
+ Metadata.Flash.Value = (UINT16) pSettings->FlashMode; // We assume that the flash fires when requested!
+ DBG_TRACE("FlashMode=0x%016llX, FlashPower=%d", pSettings->FlashMode, pSettings->FlashValue);
+
+ Metadata.FocalLength = CMetadataRational(); // TODO: Calculate?
+ Metadata.FocalPlaneXResolution = CMetadataRational(); // TODO: Calculate?
+ Metadata.FocalPlaneYResolution = CMetadataRational(); // TODO: Calculate?
+ Metadata.ExposureIndex = CMetadataRational(); // TODO: Calculate?
+
+ Metadata.ExposureMode.Set = TRUE;
+ Metadata.ExposureMode.Value = 0 ; // Assume Auto exposure.
+ if( pSettings->ExposureMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Metadata.ExposureMode.Value = 0 ; // Manual exposure.
+ }
+
+ Metadata.WhiteBalance.Set = TRUE;
+ Metadata.WhiteBalance.Value = 0 ; // Assume Auto white balance.
+ if( pSettings->WhiteBalanceMode & KSCAMERA_EXTENDEDPROP_VIDEOPROCFLAG_MANUAL )
+ {
+ Metadata.WhiteBalance.Value = 0 ; // Manual while balance.
+ }
+
+ Metadata.DigitalZoomRatio = CMetadataRational(1);
+
+ Metadata.FocalLengthIn35mmFilm = CMetadataShort(0);
+ Metadata.SceneCaptureType = CMetadataShort(0);
+ Metadata.GainControl = CMetadataRational();
+ Metadata.Contrast = CMetadataShort(0);
+ Metadata.Saturation = CMetadataShort(0);
+ Metadata.Sharpness = CMetadataShort(0);
+ Metadata.SubjectDistanceRange = CMetadataShort(0);
+
+ // Report (optional) focus state.
+ KSCAMERA_EXTENDEDPROP_FOCUSSTATE State = KSCAMERA_EXTENDEDPROP_FOCUSSTATE_UNINITIALIZED;
+ if( NT_SUCCESS(m_Sensor->GetFocusState( &State )) )
+ {
+ Metadata.FocusState = CMetadataLong((UINT32)State);
+ }
+
+ return Metadata;
+}
+
+//
+// Emit metadata here for still pin.
+//
+void
+CImageHardwareSimulation::
+EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+)
+/*++
+
+Routine Description:
+
+ Emit metadata for a photo.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+{
+ PAGED_CODE();
+
+ NT_ASSERT(pStreamHeader);
+
+ // Add the normal frame info to the metadata
+ CHardwareSimulation::EmitMetadata( pStreamHeader );
+
+ if (0 != (pStreamHeader->OptionsFlags & KSSTREAM_HEADER_OPTIONSF_METADATA))
+ {
+ PKS_FRAME_INFO pFrameInfo = (PKS_FRAME_INFO)(pStreamHeader + 1);
+ PKSSTREAM_METADATA_INFO pMetadata = (PKSSTREAM_METADATA_INFO) (pFrameInfo + 1);
+ PCAMERA_METADATA_IMAGEAGGREGATION pAggregation =
+ (PCAMERA_METADATA_IMAGEAGGREGATION) (((PBYTE) pMetadata->SystemVa) + pMetadata->UsedSize);
+ ULONG BytesLeft = pMetadata->BufferSize - pMetadata->UsedSize;
+
+ if( BytesLeft >= sizeof(*pAggregation) )
+ {
+ pAggregation->Header.MetadataId = (ULONG) MetadataId_Custom_ImageAggregation;
+ pAggregation->Header.Size = sizeof(*pAggregation);
+
+ // Just copy over the current frame's ISP settings for now.
+ // We still need to develop a contract between the driver and the MFT0 for these settings.
+ pAggregation->Data = GetMetadata();
+
+ pMetadata->UsedSize += sizeof(*pAggregation);
+ BytesLeft -= sizeof(*pAggregation);
+ }
+
+ CExtendedVidProcSetting FaceDetect;
+ m_Sensor->GetFaceDetection(&FaceDetect);
+
+ if( FaceDetect.Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_PHOTO )
+ {
+ DBG_TRACE("IMAGE");
+ EmitFaceMetadata(
+ pStreamHeader,
+ FaceDetect.GetULONG(),
+ FaceDetect.Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_ADVANCED_MASK,
+ 1);
+ }
+ }
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+FillScatterGatherBuffers()
+
+/*++
+
+Routine Description:
+
+ The hardware has synthesized a buffer in scratch space and we're to
+ fill scatter / gather buffers.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ DBG_ENTER("() m_PinID=0x%08X, m_ImageSize=0x%08X, m_ScatterGatherMappingsQueued=%d, "
+ "m_ScatterGatherBytesQueue=0x%08X",
+ m_PinID, m_ImageSize, m_ScatterGatherMappingsQueued, m_ScatterGatherBytesQueued);
+
+ //
+ // We're using this list lock to protect our scatter / gather lists instead
+ // of some hardware mechanism / KeSynchronizeExecution / whatever.
+ //
+ //KeAcquireSpinLockAtDpcLevel (&m_ListLock);
+
+ ULONG BufferRemaining = m_ImageSize;
+
+ //
+ // If there aren't enough scatter / gather buffers queued, consider it starvation.
+ //
+ while( BufferRemaining &&
+ !IsListEmpty(&m_ScatterGatherMappings) &&
+ m_ScatterGatherBytesQueued >= BufferRemaining)
+ {
+ DBG_TRACE( "BufferRemaining=0x%08X, m_ScatterGatherBytesQueued=0x%08X, m_ScatterGatherMappingsQueued=%d",
+ BufferRemaining, m_ScatterGatherBytesQueued, m_ScatterGatherMappingsQueued );
+
+ LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings);
+ m_ScatterGatherMappingsQueued--;
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+
+ // Deal with cancellation.
+ PIRP pIrp = KsStreamPointerGetIrp(SGEntry->CloneEntry, FALSE, FALSE);
+ if (pIrp)
+ {
+ if (pIrp->Cancel)
+ {
+ DBG_TRACE( "Cancelling..." );
+ FreeSGEntry( listEntry, L"StreamPointer Cancel SG List" );
+ continue;
+ }
+ }
+
+ //
+ // Since we're software, we'll be accessing this by virtual address...
+ //
+ ULONG BytesToCopy = min( BufferRemaining, SGEntry->ByteCount );
+
+ // Have the synthesizer output a frame to the buffer.
+ DBG_TRACE( "DataUsed before Commit() = %d", SGEntry->CloneEntry->StreamHeader->DataUsed );
+ ULONG BytesCopied =
+ m_Synthesizer->DoCommit( SGEntry->Virtual, BytesToCopy );
+ NT_ASSERT(BytesCopied);
+ DBG_TRACE( "BytesCopied = %d", BytesCopied );
+
+ BufferRemaining = 0; //-= BytesCopied;
+
+ // Add metadata to the sample.
+ EmitMetadata( SGEntry -> CloneEntry -> StreamHeader );
+
+ ULONGLONG time = ConvertQPCtoTimeStamp(NULL);
+
+ if (IsPhotoConfirmationNeeded())
+ {
+ DBG_TRACE( "PhotoConfirmation is needed. Frame=%d, Time=0x%016llX", m_PfsFrameNumber, (LONGLONG) time );
+ SGEntry->PhotoConfirmationInfo = PHOTOCONFIRMATION_INFO( m_PfsFrameNumber, (LONGLONG) time );
+ }
+
+ SGEntry -> CloneEntry -> StreamHeader -> PresentationTime.Time = time;
+ DBG_TRACE("PresentationTime = 0x%016llX", SGEntry->CloneEntry->StreamHeader->PresentationTime.Time );
+
+ SGEntry -> CloneEntry -> StreamHeader -> OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
+
+ DBG_TRACE("m_FlashStatus=0x%016llX", m_FlashStatus);
+
+ if(m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_ON || m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_ON_ADJUSTABLEPOWER ||
+ m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_AUTO || m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_AUTO_ADJUSTABLEPOWER)
+ {
+ if(m_FlashStatus & KSCAMERA_EXTENDEDPROP_FLASH_SINGLEFLASH && time >= m_TriggerTime && m_TriggerTime != 0 && !m_bFlashed)
+ {
+ m_bFlashed = TRUE;
+ DBG_TRACE("(Single) FLASHED!!!");
+ }
+ }
+
+ //
+ // Release the scatter / gather entry back to our lookaside.
+ //
+ if( m_bTriggered && !IsPfsEOS() )
+ {
+ DBG_TRACE("m_PinMode=%d", m_PinMode);
+ m_pClone = SGEntry->CloneEntry;
+ m_PhotoConfirmationInfo = SGEntry->PhotoConfirmationInfo;
+ m_NumMappingsCompleted++;
+ m_ScatterGatherBytesQueued -= SGEntry -> ByteCount;
+
+ DBG_TRACE( "m_NumMappingsCompleted=%d, m_PhotoConfirmationInfo.isRequired()=%s", m_NumMappingsCompleted, m_PhotoConfirmationInfo.isRequired()?"TRUE":"FALSE" );
+
+ if(m_PinMode != PinBurstMode)
+ {
+ m_bTriggered = FALSE;
+ DBG_TRACE("m_bTriggered=FALSE");
+ }
+
+ // Update the VPS frame and loop numbers here. Mark the frame as the EOS
+ // if we've completed the sequence.
+ //
+ // Note: It's actually up to DevProxy to stop feeding us frames!
+ if( AdvanceFrameCounter() )
+ {
+ // We've reached the end of a VPS sequence! Mark the frame as EOS.
+ SGEntry->CloneEntry->StreamHeader->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_ENDOFPHOTOSEQUENCE;
+ m_bEndOfSequence = TRUE;
+ }
+
+ ExFreeToNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ reinterpret_cast <PVOID> (SGEntry)
+ );
+ }
+ else
+ {
+ InsertTailList( &m_ScatterGatherMappings, listEntry );
+ m_ScatterGatherMappingsQueued++;
+ m_pClone = NULL;
+ }
+ }
+
+ DBG_LEAVE("()");
+
+ if (BufferRemaining)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ return STATUS_SUCCESS;
+ }
+}
+
+/**************************************************************************
+
+ Debug helpers
+
+**************************************************************************/
+
+PCCHAR
+AdvancedPhoto_Text( ULONGLONG Flags )
+{
+ PAGED_CODE();
+
+ switch( Flags )
+ {
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_OFF: return "Off";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO: return "Auto";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_HDR: return "HDR";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_FNF: return "FNF";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_ULTRALOWLIGHT: return "UltraLL";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_HDR: return "Auto|HDR";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_FNF: return "Auto|FNF";
+ case KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_AUTO |
+ KSCAMERA_EXTENDEDPROP_ADVANCEDPHOTO_ULTRALOWLIGHT: return "Auto|UltraLL";
+ default:
+ {
+ static
+ CHAR buffer[32];
+
+ RtlStringCbPrintfA(buffer, sizeof(buffer), "Unknown [0x%016llX]", Flags);
+ return (PCCHAR) buffer;
+ }
+ }
+}
+
+/*************************************************/
+
+void
+CImageHardwareSimulation::
+FakeHardware()
+
+/*++
+
+Routine Description:
+
+ Simulate an interrupt and what the hardware would have done in the
+ time since the previous interrupt.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ // Prevent state-changes during this call.
+ KScopedMutex Lock(m_ListLock);
+
+ m_InterruptTime++;
+
+ //
+ // The hardware can be in a pause state in which case, it issues interrupts
+ // but does not complete mappings. In this case, don't bother synthesizing
+ // a frame and doing the work of looking through the mappings table.
+ //
+ if( m_PinState == PinRunning )
+ {
+ if(m_PinMode == PinBurstMode && m_bTriggered && m_bPastBufferTrigger)
+ {
+ CompletePastBuffers();
+ }
+
+ m_Synthesizer->DoSynthesize();
+
+ CHAR Text[64];
+
+ CExtendedProperty Control;
+ m_Sensor->GetAdvancedPhoto(&Control);
+ RtlStringCbPrintfA(Text, sizeof(Text), "Adv: %s", AdvancedPhoto_Text(Control.Flags));
+ m_Synthesizer->OverlayText( 0, m_Height-38, 1, Text, TRANSPARENT, WHITE );
+
+ //
+ // Fill scatter gather buffers
+ //
+ if (!NT_SUCCESS (FillScatterGatherBuffers ()))
+ {
+ InterlockedIncrement (PLONG (&m_NumFramesSkipped));
+ }
+ }
+
+ //
+ // Issue an interrupt to our hardware sink. This is a "fake" interrupt.
+ // It will occur at DISPATCH_LEVEL.
+ //
+ m_Sensor -> Interrupt (m_PinID);
+
+ //
+ // Schedule the timer for the next interrupt time, if the pin is still running.
+ //
+ if( m_PinState == PinRunning )
+ {
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart +
+ (m_TimePerFrame * (m_InterruptTime + 1));
+
+#ifdef ENABLE_TRACING // To keep us from a tight spin when trying to debug this code...
+ LARGE_INTEGER Now;
+ KeQuerySystemTime(&Now);
+
+ if( Now.QuadPart >= NextTime.QuadPart )
+ {
+ NextTime.QuadPart = 0LL - m_TimePerFrame ;
+ }
+
+#endif
+ m_IsrTimer.Set( NextTime );
+ }
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+CompletePastBuffers()
+
+/*++
+
+Routine Description:
+
+ Find and complete any history frames.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ PAGED_CODE();
+
+ ULONG ulNumBuffers = m_PastBufferCount;
+ BOOLEAN bContinue = TRUE;
+ LIST_ENTRY *listEntry = NULL;
+
+ DBG_ENTER("()");
+ DBG_TRACE("m_PastBufferCount=%d, m_TriggerTime=0x%016llX", m_PastBufferCount, m_TriggerTime );
+
+ // If we're in burst mode and have ISP settings, we can't
+ // really support changing the ISP settings in the past...
+ // ... so we'll just treat them all past frames.
+ // Note: The upper layer will determine past frames from the
+ // metadata FrameId.
+ if( m_PinMode == PinBurstMode &&
+ !m_pIspSettings )
+ {
+ // Walk through the entire list of buffers, find the most
+ // recent frame presentation time and put all past buffers
+ // into another list.
+ while( !IsListEmpty(&m_ScatterGatherMappings) )
+ {
+ listEntry = RemoveTailList(&m_ScatterGatherMappings);
+ m_ScatterGatherMappingsQueued--;
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+
+ NT_ASSERT(SGEntry);
+ NT_ASSERT(SGEntry->CloneEntry);
+ NT_ASSERT(SGEntry->CloneEntry->StreamHeader);
+
+ // We've found one that's not stamped. We must be at the end.
+ // Push it back and exit the loop.
+ if(SGEntry->CloneEntry->StreamHeader->PresentationTime.Time == 0)
+ {
+ InsertTailList(&m_ScatterGatherMappings, listEntry);
+ m_ScatterGatherMappingsQueued++;
+ DBG_TRACE( "No past frames found." );
+ bContinue = FALSE;
+ break;
+ }
+
+ // Since we're walking from the most recent to least recent frame,
+ // This one is a valid "future" frame.
+ DBG_TRACE( "Adding 'future frame' to the list" );
+ PushCloneList(SGEntry);
+
+ // If the presentation time is less than the trigger time, stop here
+ // and use this as the first triggered frame.
+ if((ULONGLONG)(SGEntry->CloneEntry->StreamHeader->PresentationTime.Time) < m_TriggerTime)
+ {
+ DBG_TRACE( "First matching frame time=0x%016llX", SGEntry->CloneEntry->StreamHeader->PresentationTime.Time );
+ break;
+ }
+
+ // Watch out! We might actually need to pick up multiple frames since
+ // in theory we could have generated several since the trigger time.
+ }
+ }
+
+ // Grab N past frames from the queue, if we have them.
+ while( bContinue &&
+ !IsListEmpty(&m_ScatterGatherMappings) &&
+ ulNumBuffers)
+ {
+ listEntry = RemoveTailList(&m_ScatterGatherMappings);
+ m_ScatterGatherMappingsQueued--;
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+
+ if(!(SGEntry -> CloneEntry -> StreamHeader -> OptionsFlags & KSSTREAM_HEADER_OPTIONSF_TIMEVALID) )
+ {
+ InsertTailList(&m_ScatterGatherMappings, listEntry);
+ m_ScatterGatherMappingsQueued++;
+ DBG_TRACE( "No more past frames found." );
+ bContinue = FALSE;
+ }
+ else
+ {
+ PushCloneList(SGEntry);
+ ulNumBuffers--;
+ DBG_TRACE( "Past frame #%d found (%p)", ulNumBuffers, SGEntry->CloneEntry->StreamHeader );
+ }
+ }
+
+ // If we got all of the past frames we needed and didn't consume the entire queue...
+ if(bContinue && (m_ScatterGatherMappingsQueued > 0))
+ {
+ //Mark the next tail as Time = 0 so that we don't output any super old frames.
+ listEntry = RemoveTailList(&m_ScatterGatherMappings);
+ m_ScatterGatherMappingsQueued--;
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+ // Mark the PTS as invalid.
+ SGEntry->CloneEntry->StreamHeader->PresentationTime.Time = 0;
+ SGEntry->CloneEntry->StreamHeader->OptionsFlags &= ~KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
+
+ InsertTailList(&m_ScatterGatherMappings, listEntry);
+ m_ScatterGatherMappingsQueued++;
+ }
+
+ CompleteCloneList();
+
+ m_bPastBufferTrigger = FALSE;
+
+ DBG_LEAVE("()");
+
+ return STATUS_SUCCESS;
+
+}
+
+//
+// Put an item onto the history list.
+//
+void
+CImageHardwareSimulation::
+PushCloneList(
+ _Inout_ PSCATTER_GATHER_ENTRY SGEntry
+)
+{
+ PAGED_CODE();
+
+ DBG_TRACE( "Frame %p, PresentationTime=0x%016llX",
+ SGEntry->CloneEntry->StreamHeader,
+ SGEntry->CloneEntry->StreamHeader->PresentationTime.Time );
+
+ InsertHeadList( &m_BurstList, &SGEntry->ListEntry );
+}
+
+//
+// Complete the history list.
+//
+NTSTATUS
+CImageHardwareSimulation::
+CompleteCloneList()
+{
+ PAGED_CODE();
+
+ int i = 0;
+ while(!IsListEmpty(&m_BurstList))
+ {
+ LIST_ENTRY *listEntry = RemoveHeadList(&m_BurstList);
+
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+
+ m_pClone = SGEntry->CloneEntry;
+ m_PhotoConfirmationInfo = SGEntry->PhotoConfirmationInfo;
+
+ m_NumMappingsCompleted++;
+ m_ScatterGatherBytesQueued -= SGEntry -> ByteCount;
+
+ DBG_TRACE( "m_NumMappingsCompleted=%d, m_PhotoConfirmationInfo.isRequired()=%s", m_NumMappingsCompleted, m_PhotoConfirmationInfo.isRequired( )?"TRUE":"FALSE" );
+ DBG_TRACE( "Frame %p, PresentationTime=0x%016llX",
+ SGEntry->CloneEntry->StreamHeader,
+ SGEntry->CloneEntry->StreamHeader->PresentationTime.Time );
+
+ m_Sensor -> Interrupt (m_PinID);
+
+ ExFreeToNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ reinterpret_cast <PVOID> (SGEntry)
+ );
+ i++;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+SetClock(PKSPIN pin)
+{
+ PAGED_CODE();
+
+ if(!NT_SUCCESS(KsPinGetReferenceClockInterface(pin, &m_Clock)))
+ {
+ m_Clock = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void
+CImageHardwareSimulation::
+SetTriggerTime(
+ _In_ ULONGLONG TriggerTime
+)
+/*++
+
+Routine Description:
+
+ Identify exactly when the user pressed that button.
+
+Arguments:
+
+ TriggerTime -
+ The QPC time in 100ns when the user asked for the photo.
+
+Return Value:
+
+ void
+
+--*/
+{
+ PAGED_CODE();
+
+ m_TriggerTime = TriggerTime;
+ DBG_TRACE( "Setting Trigger Time = 0x%016llX", TriggerTime );
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+Reset()
+{
+ PAGED_CODE();
+
+ KScopedMutex Lock( m_ListLock );
+ DBG_ENTER("(): m_PinID=%d", m_PinID);
+
+ // Parent class reset first...
+ CHardwareSimulation::Reset();
+
+ FreeSGList( &m_ScatterGatherMappings, L"StreamPointer Reset Burst List" );
+
+ m_bTriggered = FALSE;
+ m_bEndOfSequence = FALSE;
+ m_pClone = NULL;
+ m_bPastBufferTrigger = FALSE;
+ m_TriggerTime = 0;
+
+ DBG_LEAVE("(): m_PinID=%d", m_PinID);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CImageHardwareSimulation::
+SetFlashStatus(
+ _In_ ULONGLONG ullFlashStatus
+)
+{
+ PAGED_CODE();
+
+ m_FlashStatus = ullFlashStatus;
+
+ DBG_TRACE("FlashStatus=0x%016llX", ullFlashStatus);
+
+ 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
+CImageHardwareSimulation::
+SetPFS(
+ _In_ ISP_FRAME_SETTINGS *pIspSettings,
+ _In_ ULONG FrameLimit,
+ _In_ ULONG LoopLimit
+)
+{
+ PAGED_CODE();
+
+ // 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;
+}
+
+// Function:
+// bool CImageHardwareSimulation::AdvanceFrameCounter(void)
+//
+// Description:
+// Advance our frame and loop pointers to the next PFS settings.
+//
+// Parameters:
+// [None]
+//
+// Returns:
+// bool - true if we've reached the end of our Per Frame Settings.
+//
+bool
+CImageHardwareSimulation::
+AdvanceFrameCounter(void)
+{
+ PAGED_CODE();
+
+ bool bEOS = false;
+
+ DBG_ENTER( "()" );
+
+ m_GlobalFrameNumber ++;
+ DBG_TRACE( "m_GlobalFrameNumber=%lld", m_GlobalFrameNumber );
+
+ //
+ // Calculate the PFS frame & loop numbers, but only if we've
+ // gotten ISP settings.
+ //
+ if( m_bTriggered &&
+ m_PinMode == PinBurstMode &&
+ m_pIspSettings )
+ {
+ m_PfsFrameNumber ++;
+
+ if( m_PfsFrameNumber >= m_PfsFrameLimit )
+ {
+ m_PfsFrameNumber = 0;
+ m_PfsLoopNumber ++;
+ }
+
+ // Only mark EOS if we're not in an infinite loop.
+ if( m_PfsLoopLimit != 0 )
+ {
+ NT_ASSERT( !(m_PfsLoopNumber > m_PfsLoopLimit) );
+ // Check to see if we've hit our limit.
+ if( m_PfsLoopNumber >= m_PfsLoopLimit )
+ {
+ DBG_TRACE( "Marking EOS" );
+ bEOS = true;
+ }
+ }
+ }
+
+ DBG_TRACE( "m_PfsFrameNumber=%d, m_PfsLoopNumber=%d", m_PfsFrameNumber, m_PfsLoopNumber );
+ DBG_TRACE( "m_PfsFrameLimit=%d, m_PfsLoopLimit=%d", m_PfsFrameLimit, m_PfsLoopLimit );
+ DBG_LEAVE( "() = %s", bEOS ? "true" : "false" );
+ return bEOS;
+}
+
+
+// Function:
+// bool CImageHardwareSimulation::IsPfsEOS(void)
+//
+// Description:
+// Determine if we're at the EOS.
+//
+// Parameters:
+// [None]
+//
+// Returns:
+// bool - true if we've reached the end of our Per Frame Settings.
+//
+bool
+CImageHardwareSimulation::
+IsPfsEOS(void)
+{
+ PAGED_CODE();
+
+ DBG_ENTER( "()" );
+ DBG_TRACE( "m_bTriggered=%s, m_bEndOfSequence=%s, m_PinMode=%d, m_pIspSetting=0x%p",
+ ( m_bTriggered ? "true" : "false" ),
+ ( m_bEndOfSequence ? "true" : "false" ),
+ m_PinMode,
+ m_pIspSettings );
+
+ //
+ // Make sure we're in a Variable Photo Sequence.
+ //
+ bool result =
+ bool( m_bTriggered == TRUE &&
+ m_bEndOfSequence &&
+ m_PinMode == PinBurstMode &&
+ m_pIspSettings ); // Must have ISP settings set to be PFS EOS.
+
+ DBG_LEAVE( "() = %s", (result ? "true" : "false") );
+ return result;
+}
+
+// Function:
+// BOOL CImageHardwareSimulation::IsPfsActive(void)
+//
+// Description:
+// Determine if we're in a Variable Photo Sequence.
+//
+// Parameters:
+// [None]
+//
+// Returns:
+// BOOL - TRUE if we are actively processing Per Frame Settings.
+//
+BOOL
+CImageHardwareSimulation::
+IsPfsActive(void)
+{
+ PAGED_CODE();
+
+ return
+ BOOL( m_bTriggered && !m_bEndOfSequence &&
+ m_PinMode == PinBurstMode &&
+ m_pIspSettings ) ;
+}
+
+// Get the current frame settings.
+//
+// Note:
+// Call this function to acquire ISP settings for the current frame's
+// simulation. Initially we'll just use it to report back the ISP
+// settings originally requested in the PFS by the user.
+//
+ISP_FRAME_SETTINGS *
+CImageHardwareSimulation::
+GetIspSettings(void)
+{
+ PAGED_CODE();
+
+ return
+ IsPfsActive()
+ ? &m_pIspSettings[m_PfsFrameNumber]
+ : CHardwareSimulation::GetIspSettings() ;
+}
+
+BOOLEAN
+CImageHardwareSimulation::
+IsPhotoConfirmationNeeded()
+/*++
+
+Routine Description:
+
+ Check flags for photo confirmation and return
+ whether driver should issue confirmation.
+
+--*/
+{
+ PAGED_CODE();
+
+ ISP_FRAME_SETTINGS *pSettings = GetIspSettings();
+
+ return pSettings ? pSettings->bPhotoConfirmation : FALSE;
+}
diff --git a/AVStream/avscamera/sys/imagehwsim.h b/AVStream/avscamera/sys/imagehwsim.h
new file mode 100644
index 00000000..1355a527
--- /dev/null
+++ b/AVStream/avscamera/sys/imagehwsim.h
@@ -0,0 +1,205 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ ImageHwSim.h
+
+ Abstract:
+
+ This file contains the definition of the CImageHardwareSimulation class.
+
+ This is a specialization of CHardwareSimulation that provides photo-
+ specific metadata and implements specialized functionality for photo,
+ photo sequence and variable photo sequence.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+// forward references
+struct ISP_FRAME_SETTINGS;
+
+class CImageHardwareSimulation
+ : public CHardwareSimulation
+{
+private:
+ LIST_ENTRY m_BurstList;
+ PWSTR m_szwFramePath;
+ BOOLEAN m_bTriggered;
+ BOOLEAN m_bEndOfSequence;
+ BOOLEAN m_bFlashed;
+ BOOLEAN m_bPastBufferTrigger;
+ PIN_MODE m_PinMode;
+ ULONG m_PastBufferCount;
+ ULONGLONG m_TriggerTime;
+ PIKSREFERENCECLOCK m_Clock;
+ ULONGLONG m_FlashStatus;
+
+ // Settings for VPS simulation.
+ ULONG m_PfsLoopLimit;
+ ULONG m_PfsFrameLimit;
+ ISP_FRAME_SETTINGS *m_pIspSettings; //
+ ULONG m_PfsLoopNumber; // Number of loops we've done.
+ ULONG m_PfsFrameNumber;
+ ULONGLONG m_GlobalFrameNumber; // Informational only.
+
+ // Copy a synthesized framebuffer.
+ virtual
+ NTSTATUS
+ FillScatterGatherBuffers();
+
+ // Find and complete any history frames.
+ NTSTATUS
+ CompletePastBuffers();
+
+ // Put an item onto the history list.
+ void
+ PushCloneList(_Inout_ PSCATTER_GATHER_ENTRY SGEntry);
+
+ // Complete the history list.
+ NTSTATUS
+ CompleteCloneList();
+
+ // Add Photo-specific metadata.
+ void
+ EmitMetadata(
+ _Inout_ PKSSTREAM_HEADER pStreamHeader
+ );
+
+ // Does the current frame need a photo confirmation?
+ BOOLEAN
+ IsPhotoConfirmationNeeded();
+
+ // Helper function that gets a buffer full of image metadata.
+ METADATA_IMAGEAGGREGATION
+ GetMetadata();
+
+public:
+ PKSSTREAM_POINTER m_pClone;
+ PHOTOCONFIRMATION_INFO m_PhotoConfirmationInfo;
+
+ // Constructor
+ CImageHardwareSimulation (
+ _Inout_ CSensor *Sensor,
+ _In_ LONG PinID
+ );
+
+ // Destructor
+ virtual
+ ~CImageHardwareSimulation();
+
+ // Periodic interrupt handling
+ virtual
+ void
+ FakeHardware();
+
+ // Start streaming.
+ virtual
+ NTSTATUS
+ Start(
+ _In_ CSynthesizer *ImageSynth,
+ _In_ ULONG Width,
+ _In_ ULONG Height,
+ _In_ ULONG ImageSize,
+ _In_ PIN_MODE pinMode
+ );
+
+ // Stop streaming.
+ virtual
+ NTSTATUS
+ Stop();
+
+ virtual
+ NTSTATUS
+ Reset();
+
+ // Take a picture or start a photo sequence.
+ virtual
+ NTSTATUS
+ Trigger(
+ _In_ LONG mode
+ );
+
+ LONG
+ GetTriggerMode();
+
+ // Limit the rate of frames produced.
+ virtual
+ NTSTATUS
+ SetPhotoFrameRate (
+ _In_ ULONGLONG TimePerFrame
+ );
+
+ // Get the rate of frames produced.
+ virtual
+ ULONGLONG
+ GetPhotoFrameRate()
+ {
+ return m_TimePerFrame;
+ }
+
+ // Set the master clock.
+ NTSTATUS
+ SetClock(
+ _In_ PKSPIN pin
+ );
+
+ // Identify exactly when the user pressed that button.
+ void
+ SetTriggerTime(
+ _In_ ULONGLONG TriggerTime
+ );
+
+ // Report the current trigger time.
+ ULONGLONG
+ GetTriggerTime()
+ {
+ return m_TriggerTime;
+ }
+
+ // Normal vs. Photo sequence + number of history frames.
+ NTSTATUS
+ SetMode(
+ _In_ ULONGLONG Flags,
+ _In_ ULONG PastBuffers
+ );
+
+ NTSTATUS
+ SetFlashStatus(
+ _In_ ULONGLONG ulFlashStatus
+ );
+
+ // 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
+ SetPFS(
+ _In_ ISP_FRAME_SETTINGS *pIspSettings,
+ _In_ ULONG FrameLimit,
+ _In_ ULONG LoopLimit
+ );
+
+ // Advance our frame and loop pointers to the next PFS settings.
+ bool
+ AdvanceFrameCounter(void);
+
+ // Determine if we're at the EOS.
+ bool
+ IsPfsEOS(void);
+
+ // Determine if we're in a Variable Photo Sequence.
+ BOOL
+ IsPfsActive(void);
+
+ // Get the current frame settings.
+ virtual
+ ISP_FRAME_SETTINGS *
+ GetIspSettings(void);
+};