summaryrefslogtreecommitdiff
path: root/AVStream
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
parent687b274aa38fd05c8c26e3068932121876d7f745 (diff)
Updated for "Windows 10 Anniversary Update" (Version 1607)
Diffstat (limited to 'AVStream')
-rw-r--r--AVStream/avscamera/Package/package.VcxProj87
-rw-r--r--AVStream/avscamera/Package/package.VcxProj.Filters21
-rw-r--r--AVStream/avscamera/README.md13
-rw-r--r--AVStream/avscamera/avscamera.sln59
-rw-r--r--AVStream/avscamera/common/CustomProperties.h59
-rw-r--r--AVStream/avscamera/common/Macros.h48
-rw-r--r--AVStream/avscamera/common/MetadataInternal.h267
-rw-r--r--AVStream/avscamera/mft0/AvsCameraMFT0.rc13
-rw-r--r--AVStream/avscamera/mft0/AvsCameraMft0.vcxproj216
-rw-r--r--AVStream/avscamera/mft0/AvsCameraMft0.vcxproj.Filters42
-rw-r--r--AVStream/avscamera/mft0/MFT0.def13
-rw-r--r--AVStream/avscamera/mft0/MFT0.idl46
-rw-r--r--AVStream/avscamera/mft0/MFT0Impl.cpp2106
-rw-r--r--AVStream/avscamera/mft0/MFT0Impl.h328
-rw-r--r--AVStream/avscamera/mft0/MFT0clsid.h26
-rw-r--r--AVStream/avscamera/mft0/SampleHelpers.h106
-rw-r--r--AVStream/avscamera/mft0/dllmain.cpp191
-rw-r--r--AVStream/avscamera/mft0/sources.dep21
-rw-r--r--AVStream/avscamera/mft0/stdafx.h32
-rw-r--r--AVStream/avscamera/mft0/stdafxsrc.cpp1
-rw-r--r--AVStream/avscamera/mft0/targetver.h15
-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
-rw-r--r--AVStream/samplemft0/Package/package.vcxproj91
-rw-r--r--AVStream/samplemft0/Package/package.vcxproj.Filters21
94 files changed, 31766 insertions, 0 deletions
diff --git a/AVStream/avscamera/Package/package.VcxProj b/AVStream/avscamera/Package/package.VcxProj
new file mode 100644
index 00000000..92690b1a
--- /dev/null
+++ b/AVStream/avscamera/Package/package.VcxProj
@@ -0,0 +1,87 @@
+<?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>
+ <ItemGroup>
+ <ProjectReference Include="..\mft0\AvsCameraMft0.vcxproj">
+ <Project>{2C0B129E-88F3-479A-AE5D-65609A88BE66}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\sys\AvsCamera.vcxproj">
+ <Project>{24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="PropertySheets">
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Utility</ConfigurationType>
+ <DriverType>Package</DriverType>
+ <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+ <Configuration>Debug</Configuration>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{9397D285-8C29-4661-A741-F6703E2F5FD6}</ProjectGuid>
+ <SampleGuid>{B28A4CED-96FB-4426-8E77-15A9C0BCFDD5}</SampleGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <ImportToStore>False</ImportToStore>
+ <InstallMode>None</InstallMode>
+ <HardwareIdString />
+ <CommandLine />
+ <ScriptPath />
+ <DeployFiles />
+ <ScriptName />
+ <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery>
+ <EnableVerifier>False</EnableVerifier>
+ <AllDrivers>False</AllDrivers>
+ <VerifyProjectOutput>True</VerifyProjectOutput>
+ <VerifyDrivers />
+ <VerifyFlags>133563</VerifyFlags>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/avscamera/Package/package.VcxProj.Filters b/AVStream/avscamera/Package/package.VcxProj.Filters
new file mode 100644
index 00000000..55d9d3d7
--- /dev/null
+++ b/AVStream/avscamera/Package/package.VcxProj.Filters
@@ -0,0 +1,21 @@
+<?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>{F1A06F53-B8EA-4605-9176-11EC0176E816}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{F24A15E4-0A77-4A7C-9140-398C8C947588}</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>{2C36364F-95CF-43D3-AE5B-AFEEE8D123EF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{C72B8B2A-0C65-4C86-A70C-475757BF3912}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/avscamera/README.md b/AVStream/avscamera/README.md
new file mode 100644
index 00000000..e6f79be6
--- /dev/null
+++ b/AVStream/avscamera/README.md
@@ -0,0 +1,13 @@
+AvsCamera: AVStream Camera Sample Driver
+========================================
+The AvsCamera sample provides a pin-centric AVStream capture driver for a simulated front and back camera. The driver performs simulated captures at 320x240 or 640x480 in RGB24, RGB32, YUY2 and NV12 formats at various frame rates. The purpose of the sample is to demonstrate how to write a fully functional AVStream camera driver.
+
+This sample features strong parameter validation and overflow detection. It provides validation and simulation logic for all advanced camera controls in the CCaptureFilter class. A real camera driver would replace the filter automation table and CSensor and CSynthesizer class hierarchies to produce a new camera driver.
+
+The sample comes with its own MFT0 called AvsCameraMft0.dll. This MFT0 is used to parse metadata supplied in the AvsCamera driver samples. The metadata communications from the driver is primarily a private channel to its MFT0. The MFT0 is responsible for reformatting that information for the capture pipeline.
+
+## Universal Windows Driver Compliant
+This sample builds a Universal Windows Driver. It uses only APIs and DDIs that are included in OneCoreUAP. The sample works on 32-bit and 64-bit x86, amd64 and arm platforms. Once installed, the simulated camera should show in the Windows Inbox camera app.
+
+## Building the sample
+The AvsCamera sample can be built by opening the AvsCamera.sln solution file. A successful build produces AvsCamera.sys, AvsCameraMft0.dll, AvsCamera.inf and AvsCamera.cat.
diff --git a/AVStream/avscamera/avscamera.sln b/AVStream/avscamera/avscamera.sln
new file mode 100644
index 00000000..faa04506
--- /dev/null
+++ b/AVStream/avscamera/avscamera.sln
@@ -0,0 +1,59 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{174AB66C-6250-4DDB-88C5-856B9D499DB7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mft0", "Mft0", "{8031E506-AE20-4995-9F28-2D177A1FB319}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{72571B45-7827-4380-8821-38A33FBFF4E2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{9397D285-8C29-4661-A741-F6703E2F5FD6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvsCameraMft0", "mft0\AvsCameraMft0.vcxproj", "{2C0B129E-88F3-479A-AE5D-65609A88BE66}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AvsCamera", "sys\AvsCamera.vcxproj", "{24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|Win32.Build.0 = Debug|Win32
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|Win32.ActiveCfg = Release|Win32
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|Win32.Build.0 = Release|Win32
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|x64.ActiveCfg = Debug|x64
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Debug|x64.Build.0 = Debug|x64
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|x64.ActiveCfg = Release|x64
+ {9397D285-8C29-4661-A741-F6703E2F5FD6}.Release|x64.Build.0 = Release|x64
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|Win32.Build.0 = Debug|Win32
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|Win32.ActiveCfg = Release|Win32
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|Win32.Build.0 = Release|Win32
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|x64.ActiveCfg = Debug|x64
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Debug|x64.Build.0 = Debug|x64
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|x64.ActiveCfg = Release|x64
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66}.Release|x64.Build.0 = Release|x64
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|Win32.ActiveCfg = Debug|Win32
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|Win32.Build.0 = Debug|Win32
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|Win32.ActiveCfg = Release|Win32
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|Win32.Build.0 = Release|Win32
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|x64.ActiveCfg = Debug|x64
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Debug|x64.Build.0 = Debug|x64
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|x64.ActiveCfg = Release|x64
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9397D285-8C29-4661-A741-F6703E2F5FD6} = {174AB66C-6250-4DDB-88C5-856B9D499DB7}
+ {2C0B129E-88F3-479A-AE5D-65609A88BE66} = {8031E506-AE20-4995-9F28-2D177A1FB319}
+ {24D35D6E-BDB0-4949-8A34-7DD25F0E8F68} = {72571B45-7827-4380-8821-38A33FBFF4E2}
+ EndGlobalSection
+EndGlobal
diff --git a/AVStream/avscamera/common/CustomProperties.h b/AVStream/avscamera/common/CustomProperties.h
new file mode 100644
index 00000000..f9a9db09
--- /dev/null
+++ b/AVStream/avscamera/common/CustomProperties.h
@@ -0,0 +1,59 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ CustomProperties.h
+
+ Abstract:
+
+ This file contains a definition used to demonstrate a custom property.
+
+ History:
+
+ created 10/10/2014
+
+**************************************************************************/
+#pragma once
+
+
+#define STATIC_PROPSETID_VIDCAP_CUSTOM_CAMERACONTROL_MFT0 \
+ 0x452da6d7, 0xa42b, 0x4906, 0xa6, 0xc3, 0x81, 0x62, 0xe7, 0x2d, 0x38, 0x3d
+DEFINE_GUIDSTRUCT("452da6d7-a42b-4906-a6c3-8162e72d383d", PROPSETID_VIDCAP_CUSTOM_CAMERACONTROL_MFT0);
+#define PROPSETID_VIDCAP_CUSTOM_CAMERACONTROL_MFT0 DEFINE_GUIDNAMED(PROPSETID_VIDCAP_CUSTOM_CAMERACONTROL_MFT0)
+
+typedef enum
+{
+ KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION
+} KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0;
+
+typedef struct
+{
+ BOOL VideoStabilizationEnabled;
+} KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION_S, *PKSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION_S;
+
+// {05DC8943-B9FB-4201-808F-6E91451C4760}
+#define STATIC_PROPSETID_VIDCAP_CUSTOMCONTROL \
+ 0x5dc8943, 0xb9fb, 0x4201, 0x80, 0x8f, 0x6e, 0x91, 0x45, 0x1c, 0x47, 0x60
+DEFINE_GUIDSTRUCT("05DC8943-B9FB-4201-808F-6E91451C4760", PROPSETID_VIDCAP_CUSTOMCONTROL );
+#define PROPSETID_VIDCAP_CUSTOMCONTROL DEFINE_GUIDNAMED(PROPSETID_VIDCAP_CUSTOMCONTROL )
+
+enum
+{
+ KSPROPERTY_CUSTOMCONTROL_DUMMY
+};
+
+// {570615F9-D924-42AC-B967-BE7B0E489965}
+#define STATIC_PROPSETID_SENSOR_CUSTOMCONTROL \
+ 0x570615f9, 0xd924, 0x42ac, 0xb9, 0x67, 0xbe, 0x7b, 0xe, 0x48, 0x99, 0x65
+DEFINE_GUIDSTRUCT("570615F9-D924-42AC-B967-BE7B0E489965", PROPSETID_SENSOR_CUSTOMCONTROL);
+#define PROPSETID_SENSOR_CUSTOMCONTROL DEFINE_GUIDNAMED(PROPSETID_SENSOR_CUSTOMCONTROL )
+
+enum
+{
+ KSPROPERTY_SENSOR_PIN_CUSTOM_CONTROL_ULONG=0
+};
+
diff --git a/AVStream/avscamera/common/Macros.h b/AVStream/avscamera/common/Macros.h
new file mode 100644
index 00000000..b87aa436
--- /dev/null
+++ b/AVStream/avscamera/common/Macros.h
@@ -0,0 +1,48 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ macros.h
+
+ Abstract:
+
+ This file contains common error checking macros for the MFT0
+
+ History:
+
+ created 10/10/2014
+
+**************************************************************************/
+
+#pragma once
+
+#define IFFAILED_BREAK(exp) \
+{ \
+ if ( FAILED(hr= (exp)) ) \
+ { \
+ break; \
+ } \
+}
+
+#define IFFALSE_BREAK_HR(exp, retval) \
+{ \
+ if ( !(exp)) \
+ { \
+ hr = retval; \
+ break; \
+ } \
+}
+
+
+#define IFNULL_BREAK_HR(exp, retval) \
+{ \
+ if ( (exp) == NULL ) \
+ { \
+ hr = retval; \
+ break; \
+ } \
+} \ No newline at end of file
diff --git a/AVStream/avscamera/common/MetadataInternal.h b/AVStream/avscamera/common/MetadataInternal.h
new file mode 100644
index 00000000..41f49469
--- /dev/null
+++ b/AVStream/avscamera/common/MetadataInternal.h
@@ -0,0 +1,267 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ MetadataInternal.h
+
+ Abstract:
+
+ Internal structures for private metadata communication between the
+ driver and its MFT0.
+
+ History:
+
+ created 4/29/2013
+
+**************************************************************************/
+
+
+
+enum MetadataId_Custom
+{
+ MetadataId_Custom_ImageAggregation = MetadataId_Custom_Start,
+ MetadataId_Custom_FaceDetection,
+ MetadataId_Custom_PreviewAggregation,
+ MetadataId_Custom_Histogram
+};
+
+typedef struct
+{
+ UINT32 Set;
+ UINT32 Value;
+} METADATA_UINT32, METADATA_LONG;
+
+typedef struct
+{
+ UINT32 Set;
+ UINT16 Value;
+ UINT16 Reserved;
+} METADATA_UINT16, METADATA_SHORT;
+
+typedef struct
+{
+ UINT32 Length; // Use a length of 0 for not Set
+ CHAR String[32];
+} METADATA_SHORTSTRING;
+
+typedef struct
+{
+ UINT32 Set;
+ UINT32 Reserved;
+ UINT32 Numerator;
+ UINT32 Denominator;
+} METADATA_RATIONAL;
+
+typedef struct
+{
+ UINT32 Set;
+ UINT32 Reserved;
+ INT64 Value;
+} METADATA_INT64;
+
+typedef struct
+{
+ UINT32 Set;
+ UINT32 Reserved;
+ UINT64 Value;
+} METADATA_UINT64;
+
+typedef struct
+{
+ UINT32 Set;
+ UINT32 Reserved;
+ INT32 Numerator;
+ INT32 Denominator;
+} METADATA_SRATIONAL;
+
+typedef struct
+{
+ UINT32 Set;
+ INT32 Value;
+ UINT64 Flags;
+} METADATA_EVCOMP;
+
+#ifndef _WDM_INCLUDED_
+//
+// Time conversion routines
+//
+typedef short CSHORT;
+
+typedef struct _TIME_FIELDS
+{
+ CSHORT Year; // range [1601...]
+ CSHORT Month; // range [1..12]
+ CSHORT Day; // range [1..31]
+ CSHORT Hour; // range [0..23]
+ CSHORT Minute; // range [0..59]
+ CSHORT Second; // range [0..59]
+ CSHORT Milliseconds;// range [0..999]
+ CSHORT Weekday; // range [0..6] == [Sunday..Saturday]
+} TIME_FIELDS;
+typedef TIME_FIELDS *PTIME_FIELDS;
+
+#endif //TIME_FIELDS
+
+typedef struct
+{
+ UINT32 Set;
+ UINT32 Reserved;
+ TIME_FIELDS Time;
+} METADATA_TIMEFIELDS;
+
+typedef struct _METADATA_PREVIEWAGGREGATION
+{
+ // Mandatory fields
+ UINT32 FocusState;
+ UINT32 Reserved;
+ METADATA_INT64 ExposureTime;
+ METADATA_EVCOMP EVCompensation;
+ METADATA_UINT32 ISOSpeed;
+ METADATA_UINT32 LensPosition;
+ METADATA_UINT32 FlashOn;
+ METADATA_UINT32 WhiteBalanceMode;
+ METADATA_SRATIONAL IsoAnalogGain; // MF_CAPTURE_METADATA_ISO_GAINS
+ METADATA_SRATIONAL IsoDigitalGain; // MF_CAPTURE_METADATA_ISO_GAINS
+ METADATA_UINT64 SensorFrameRate; // MF_CAPTURE_METADATA_SENSORFRAMERATE
+ METADATA_SRATIONAL WhiteBalanceGain_R; // MF_CAPTURE_METADATA_WHITEBALANCE_GAINS
+ METADATA_SRATIONAL WhiteBalanceGain_G; // MF_CAPTURE_METADATA_WHITEBALANCE_GAINS
+ METADATA_SRATIONAL WhiteBalanceGain_B; // MF_CAPTURE_METADATA_WHITEBALANCE_GAINS
+
+} METADATA_PREVIEWAGGREGATION, *PMETADATA_PREVIEWAGGREGATION;
+
+typedef struct _METADATA_IMAGEAGGREGATION
+{
+ // Mandatory fields
+ METADATA_UINT32 FrameId;
+ METADATA_INT64 ExposureTime;
+ METADATA_UINT32 ISOSpeed;
+ METADATA_UINT32 LensPosition;
+ METADATA_UINT64 SceneMode;
+ METADATA_UINT32 FlashOn;
+ METADATA_UINT32 FlashPower;
+ METADATA_UINT32 WhiteBalanceMode;
+ METADATA_UINT32 ZoomFactor;
+ METADATA_UINT32 FocusLocked;
+ METADATA_UINT32 WhiteBalanceLocked;
+ METADATA_UINT32 ExposureLocked;
+
+ // Required Exif data
+ METADATA_SHORT Orientation;
+ METADATA_TIMEFIELDS LocalTime;
+ METADATA_SHORTSTRING Make;
+ METADATA_SHORTSTRING Model;
+ METADATA_SHORTSTRING Software;
+ METADATA_SHORT ColorSpace;
+ METADATA_RATIONAL Gamma;
+ METADATA_SHORTSTRING MakerNote;
+ METADATA_RATIONAL FNumber;
+ METADATA_SHORT ExposureProgram;
+ METADATA_SRATIONAL ShutterSpeedValue;
+ METADATA_RATIONAL Aperture;
+ METADATA_SRATIONAL Brightness;
+ METADATA_SRATIONAL ExposureBias;
+ METADATA_RATIONAL SubjectDistance;
+ METADATA_SHORT MeteringMode;
+ METADATA_SHORT LightSource;
+ METADATA_SHORT Flash;
+ METADATA_RATIONAL FocalLength;
+ METADATA_RATIONAL FocalPlaneXResolution;
+ METADATA_RATIONAL FocalPlaneYResolution;
+ METADATA_RATIONAL ExposureIndex;
+ METADATA_SHORT ExposureMode;
+ METADATA_SHORT WhiteBalance;
+ METADATA_RATIONAL DigitalZoomRatio;
+ METADATA_SHORT FocalLengthIn35mmFilm;
+ METADATA_SHORT SceneCaptureType;
+ METADATA_RATIONAL GainControl;
+ METADATA_SHORT Contrast;
+ METADATA_SHORT Saturation;
+ METADATA_SHORT Sharpness;
+ METADATA_SHORT SubjectDistanceRange;
+
+ // Additional required metadata
+ METADATA_EVCOMP EVCompensation;
+
+ // Optional
+ METADATA_LONG FocusState;
+
+} METADATA_IMAGEAGGREGATION, *PMETADATA_IMAGEAGGREGATION;
+
+typedef enum
+{
+ Metadata_Orientation_TopBottomLeftRight = 1,
+ Metadata_Orientation_TopBottomRightLeft = 2,
+ Metadata_Orientation_BottomTopLeftRight = 3,
+ Metadata_Orientation_BottomTopRightLeft = 4,
+ Metadata_Orientation_LeftRightTopBottom = 5, // 90 degree rotation
+ Metadata_Orientation_RightLeftTopBottom = 6,
+ Metadata_Orientation_LeftRightBottomTop = 7,
+ Metadata_Orientation_RightLeftBottomTop = 8
+
+} METADATA_ORIENTATION_ENUM;
+
+typedef struct
+{
+ KSCAMERA_METADATA_ITEMHEADER Header;
+ METADATA_PREVIEWAGGREGATION Data;
+} CAMERA_METADATA_PREVIEWAGGREGATION, *PCAMERA_METADATA_PREVIEWAGGREGATION;
+
+typedef struct
+{
+ KSCAMERA_METADATA_ITEMHEADER Header;
+ METADATA_IMAGEAGGREGATION Data;
+} CAMERA_METADATA_IMAGEAGGREGATION, *PCAMERA_METADATA_IMAGEAGGREGATION;
+
+typedef struct
+{
+ KSCAMERA_METADATA_ITEMHEADER Header;
+ UINT32 eFocusState;
+ UINT32 Reserved;
+} CAMERA_METADATA_FOCUS_STATE, *PCAMERA_METADATA_FOCUS_STATE;
+
+typedef enum _METADATA_EXPRESSION
+{
+ EXPRESSION_NONE=0,
+ EXPRESSION_SMILE=1
+} METADATA_EXPRESSION;
+
+typedef struct _METADATA_FACEDATA
+{
+ RECT Region; // A rectangle describing the face.
+ ULONG confidenceLevel; // [0, 100].
+ ULONG BlinkScoreLeft; // [0, 100]. 0 indicates no blink for the left eye. 100 indicates definite blink for the left eye
+ ULONG BlinkScoreRight; // [0, 100]. 0 indicates no blink for the right eye. 100 indicates definite blink for the right eye
+ ULONG Reserved; // Pad for 64-bit alignment.
+ BOOL FacialExpression; // Is the face smiling?
+ ULONG FacialExpressionScore; // [0, 100]. 0 indicates no such facial expression as identified. 100 indicates definite such facial expression as defined
+} METADATA_FACEDATA, *PMETADATA_FACEDATA;
+
+typedef struct _CAMERA_METADATA_FACEHEADER
+{
+ KSCAMERA_METADATA_ITEMHEADER Header;
+ UINT32 Count; // Number of detected faces.
+ UINT64 Flags; // If KSCAMERA_EXTENDEDPROP_FACEDETECTION_BLINK or _SMILE bitflags are set, characterization metadata is valid.
+ UINT64 Timestamp; // Time in 100ns of actual face detection.
+} CAMERA_METADATA_FACEHEADER, *PCAMERA_METADATA_FACEHEADER;
+
+typedef struct _METADATA_HISTOGRAM
+{
+ ULONG Width;
+ ULONG Height;
+ ULONG ChannelMask;
+ ULONG FourCC;
+ ULONG P0Data[256]; // first primary (R / Y )
+ ULONG P1Data[256]; // second (G / Cr)
+ ULONG P2Data[256]; // third (B / Cb)
+} METADATA_HISTOGRAM, *PMETADATA_HISTOGRAM;
+
+typedef struct _CAMERA_METADATA_HISTOGRAM
+{
+ KSCAMERA_METADATA_ITEMHEADER Header;
+ METADATA_HISTOGRAM Data;
+} CAMERA_METADATA_HISTOGRAM, *PCAMERA_METADATA_HISTOGRAM;
+
diff --git a/AVStream/avscamera/mft0/AvsCameraMFT0.rc b/AVStream/avscamera/mft0/AvsCameraMFT0.rc
new file mode 100644
index 00000000..86c06ba2
--- /dev/null
+++ b/AVStream/avscamera/mft0/AvsCameraMFT0.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+#include <ntverp.h>
+
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "A/V Stream Camera MFT0"
+#define VER_INTERNALNAME_STR "AvsCameraMft0.dll"
+#define VER_ORIGINALFILENAME_STR "AvsCameraMft0.dll"
+#define VER_LANGNEUTRAL
+
+#include "common.ver"
+
diff --git a/AVStream/avscamera/mft0/AvsCameraMft0.vcxproj b/AVStream/avscamera/mft0/AvsCameraMft0.vcxproj
new file mode 100644
index 00000000..3e071c71
--- /dev/null
+++ b/AVStream/avscamera/mft0/AvsCameraMft0.vcxproj
@@ -0,0 +1,216 @@
+<?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>{2C0B129E-88F3-479A-AE5D-65609A88BE66}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <SupportsPackaging>false</SupportsPackaging>
+ <RequiresPackageProject>true</RequiresPackageProject>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{1921F93C-296D-4875-BD67-D087F1DBF95B}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</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>AvsCameraMft0</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>AvsCameraMft0</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>AvsCameraMft0</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>AvsCameraMft0</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)\ks;..\common</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Mft0.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Mft0.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Mft0.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);mfplat.lib;uuid.lib;mfuuid.lib;OneCoreUAP.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Mft0.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="$(IntDir)\Mft0_i.c" />
+ <ClCompile Include="dllmain.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="Mft0Impl.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="stdafxsrc.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <Midl Include="Mft0.idl" />
+ <ResourceCompile Include="AvsCameraMft0.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/mft0/AvsCameraMft0.vcxproj.Filters b/AVStream/avscamera/mft0/AvsCameraMft0.vcxproj.Filters
new file mode 100644
index 00000000..ec3124e3
--- /dev/null
+++ b/AVStream/avscamera/mft0/AvsCameraMft0.vcxproj.Filters
@@ -0,0 +1,42 @@
+<?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>{5293FBF9-AB37-479B-86A2-4DE6B858B90A}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{BB11CFC9-BD19-4353-9E5F-42D5BA1A0CB3}</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>{49D3ED6A-39BD-49AC-96B4-4C1645E71934}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="Debug\\Mft0_i.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Mft0Impl.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdafxsrc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <Midl Include="Mft0.idl">
+ <Filter>Source Files</Filter>
+ </Midl>
+ <None Include="MFT0.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="AvsCameraMft0.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/avscamera/mft0/MFT0.def b/AVStream/avscamera/mft0/MFT0.def
new file mode 100644
index 00000000..b4430ceb
--- /dev/null
+++ b/AVStream/avscamera/mft0/MFT0.def
@@ -0,0 +1,13 @@
+; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+; PARTICULAR PURPOSE.
+; Copyright (c) Microsoft Corporation. All rights reserved
+
+; SampleMft0.def : Declares the module parameters.
+
+LIBRARY
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE \ No newline at end of file
diff --git a/AVStream/avscamera/mft0/MFT0.idl b/AVStream/avscamera/mft0/MFT0.idl
new file mode 100644
index 00000000..40098f71
--- /dev/null
+++ b/AVStream/avscamera/mft0/MFT0.idl
@@ -0,0 +1,46 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+// SampleMft0.idl : IDL source for SampleMft0
+//
+
+// This file will be processed by the MIDL tool to
+// produce the type library (SampleMft0.tlb) and marshalling code.
+
+import "oaidl.idl";
+import "ocidl.idl";
+import "Inspectable.idl";
+import "mftransform.idl";
+[
+ object,
+ uuid(7B917902-D657-4437-9F93-93B94482F286),
+ oleautomation,
+ nonextensible,
+ pointer_default(unique)
+]
+interface ISocMft0 : IUnknown{
+ [id(1)] HRESULT SetState([in] UINT32 state);
+ [id(2)] HRESULT GetState([out] UINT* pState);
+};
+[
+ uuid(8F14E328-2084-442E-A4D9-A80AA30ECBA8),
+ version(1.0),
+]
+library SampleSocMft0Lib
+{
+ importlib("stdole2.tlb");
+ [
+ uuid(424BF154-D92A-42EB-B041-1395F9E5B4A2)
+ ]
+ coclass Mft0
+ {
+ [default] interface ISocMft0;
+ interface IInspectable;
+ interface IMFTransform;
+ };
+};
+
diff --git a/AVStream/avscamera/mft0/MFT0Impl.cpp b/AVStream/avscamera/mft0/MFT0Impl.cpp
new file mode 100644
index 00000000..90caedd6
--- /dev/null
+++ b/AVStream/avscamera/mft0/MFT0Impl.cpp
@@ -0,0 +1,2106 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ Mft0Impl.cpp
+
+ Abstract:
+
+ This is the implementation of CSocMft0.
+
+ CSocMft0 is the MFT0 for the AvsCamera sample driver. This MFT0
+ performs the following key tasks:
+ 1. Filters overscan media types supplied by the driver, and
+ 2. Parses private metadata and attaches an IMFAttribute to the sample.
+
+ History:
+
+ created 5/15/2014
+
+**************************************************************************/
+
+
+#include "stdafx.h"
+#include "Mft0Impl.h"
+#include "SampleHelpers.h"
+#include "metadataInternal.h"
+#include <WinString.h>
+#include <ks.h>
+#include <ksproxy.h>
+#include <initguid.h>
+
+#include "CustomProperties.h"
+#include "macros.h"
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// These two functions demostrate that OEM application can communicate with MFT0
+//
+STDMETHODIMP CSocMft0::SetState(UINT32 state)
+{
+ // OEM can use similar function to update the status of MFT
+ // From their own application
+ m_uiInternalState = state;
+ return S_OK;
+}
+
+STDMETHODIMP CSocMft0::GetState(UINT32 *pState)
+{
+ HRESULT hr = S_OK;
+
+ // OEM can use similar function to get the status of MFT
+ // From their own application
+ if(!pState)
+ {
+ return E_POINTER;
+ }
+ *pState = m_uiInternalState;
+
+ return hr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+//
+// This initializes the CSocMFT0 for Com
+//
+//
+HRESULT CSocMft0::CreateInstance(
+ REFIID iid,
+ void **ppMFT
+)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFTransform> spMFT;
+ UNREFERENCED_PARAMETER(iid);
+
+ auto sObject = Microsoft::WRL::Make<CSocMft0>();
+
+ if(!sObject)
+ {
+ return E_OUTOFMEMORY;
+ }
+ hr = sObject->FinalConstruct();
+
+ if(SUCCEEDED(hr))
+ {
+ hr = sObject.As(&spMFT);
+ *ppMFT = spMFT.Detach();
+ }
+
+ return hr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// IInspectable interface enable COM interface to talk with other programming environments
+//
+// Gets the interfaces that are implemented by the current Windows Runtime class.
+//
+STDMETHODIMP CSocMft0::GetIids(
+ _Out_ ULONG *iidCount,
+ _Outptr_result_buffer_maybenull_(*iidCount) IID **iids
+)
+{
+ HRESULT hr = S_OK;
+
+ if(!iidCount)
+ {
+ return E_POINTER;
+ }
+
+ if(!iids)
+ {
+ return E_POINTER;
+ }
+
+ *iids = NULL;
+ *iidCount = 0;
+
+ return hr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Gets the fully qualified name of the current Windows Runtime object.
+//
+STDMETHODIMP CSocMft0::GetRuntimeClassName(
+ _Outptr_result_maybenull_ HSTRING *pClassName
+)
+{
+
+ if(!pClassName)
+ {
+ return E_POINTER;
+ }
+ return WindowsCreateString(NULL, 0, pClassName);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Gets the trust level of the current Windows Runtime object.
+//
+STDMETHODIMP CSocMft0::GetTrustLevel(
+ _Out_ TrustLevel *trustLevel
+)
+{
+ HRESULT hr = S_OK;
+
+ if(trustLevel)
+ {
+ return E_POINTER;
+ }
+ *trustLevel = TrustLevel::BaseTrust;
+
+ return hr;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// Final Construct
+//
+HRESULT CSocMft0::FinalConstruct()
+{
+ HRESULT hr = S_OK;
+ hr = MFCreateAttributes(&m_spGlobalAttributes, 3);
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+
+ hr = m_spGlobalAttributes->SetUINT32(MF_TRANSFORM_ASYNC, FALSE);
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+
+ hr = m_spGlobalAttributes->SetString(
+ MFT_ENUM_HARDWARE_URL_Attribute,
+ L"Sample_CameraExtensionMft");
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+
+ hr = m_spGlobalAttributes->SetUINT32(
+ MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE,
+ TRUE);
+
+done:
+ if(FAILED(hr))
+ {
+ m_spGlobalAttributes.Reset();
+ }
+ return hr;
+}
+
+// IMFTransform methods. Refer to the Media Foundation SDK documentation for details.
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetStreamLimits
+// Returns the minimum and maximum number of streams.
+//
+STDMETHODIMP CSocMft0::GetStreamLimits(
+ _Out_ DWORD *pdwInputMinimum,
+ _Out_ DWORD *pdwInputMaximum,
+ _Out_ DWORD *pdwOutputMinimum,
+ _Out_ DWORD *pdwOutputMaximum
+)
+{
+ if( (!pdwInputMinimum) ||
+ (!pdwInputMaximum) ||
+ (!pdwOutputMinimum) ||
+ (!pdwOutputMaximum))
+ {
+ return E_POINTER;
+ }
+
+ // This MFT has a fixed number of streams.
+ *pdwInputMinimum = 1;
+ *pdwInputMaximum = 1;
+ *pdwOutputMinimum = 1;
+ *pdwOutputMaximum = 1;
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetStreamCount
+// Returns the actual number of streams.
+//
+STDMETHODIMP CSocMft0::GetStreamCount(
+ _Out_ DWORD *pcInputStreams,
+ _Out_ DWORD *pcOutputStreams
+)
+{
+ if(!pcInputStreams || !pcOutputStreams)
+ {
+ return E_POINTER;
+ }
+
+ // This MFT has a fixed number of streams.
+ *pcInputStreams = 1;
+ *pcOutputStreams = 1;
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetStreamIDs
+// Returns stream IDs for the input and output streams.
+//
+STDMETHODIMP CSocMft0::GetStreamIDs(
+ DWORD dwInputIDArraySize,
+ _Out_writes_(dwInputIDArraySize) DWORD *pdwInputIDs,
+ DWORD dwOutputIDArraySize,
+ _Out_writes_(dwOutputIDArraySize) DWORD *pdwOutputIDs
+)
+{
+ UNREFERENCED_PARAMETER(dwInputIDArraySize);
+ UNREFERENCED_PARAMETER(dwOutputIDArraySize);
+ UNREFERENCED_PARAMETER(pdwInputIDs);
+ UNREFERENCED_PARAMETER(pdwOutputIDs);
+
+ // It is not required to implement this method if the MFT has a fixed number of
+ // streams AND the stream IDs are numbered sequentially from zero (that is, the
+ // stream IDs match the stream indexes).
+
+ // In that case, it is OK to return E_NOTIMPL.
+ return (E_NOTIMPL);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetInputStreamInfo
+// Returns information about an input stream.
+//
+STDMETHODIMP CSocMft0::GetInputStreamInfo(
+ DWORD dwInputStreamID,
+ _Out_ MFT_INPUT_STREAM_INFO *pStreamInfo
+)
+{
+ CAutoLock lock(&m_critSec);
+
+ if(!pStreamInfo)
+ {
+ return E_POINTER;
+ }
+
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if(!m_spInputType)
+ {
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ pStreamInfo->hnsMaxLatency = 0;
+ pStreamInfo->cbAlignment = 0;
+ pStreamInfo->cbSize = 0;
+ pStreamInfo->dwFlags =
+ MFT_INPUT_STREAM_WHOLE_SAMPLES |
+ MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
+ MFT_INPUT_STREAM_PROCESSES_IN_PLACE ;
+ pStreamInfo->hnsMaxLatency = 0;
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetOutputStreamInfo
+// Returns information about an output stream.
+//
+STDMETHODIMP CSocMft0::GetOutputStreamInfo(
+ DWORD dwOutputStreamID,
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+)
+{
+ CAutoLock lock(&m_critSec);
+
+ if(!pStreamInfo)
+ {
+ return E_POINTER;
+ }
+
+ if (!IsValidInputStream(dwOutputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if(!m_spOutputType)
+ {
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ pStreamInfo->cbAlignment = 0;
+ pStreamInfo->cbSize = 0;
+ pStreamInfo->dwFlags =
+ MFT_OUTPUT_STREAM_WHOLE_SAMPLES |
+ MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER |
+ MFT_OUTPUT_STREAM_PROVIDES_SAMPLES |
+ MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
+
+ return S_OK;
+}
+
+/////////////////////////////////////////////////////////////////////////
+//
+// GetAttributes
+// Returns the global attributes for the MFT.
+//
+STDMETHODIMP CSocMft0::GetAttributes(
+ _Outptr_result_maybenull_ IMFAttributes **ppAttributes
+)
+{
+ if(!ppAttributes)
+ {
+ return E_POINTER;
+ }
+
+ return m_spGlobalAttributes.CopyTo(ppAttributes);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetInputStreamAttributes
+// Returns stream-level attributes for an input stream.
+//
+STDMETHODIMP CSocMft0::GetInputStreamAttributes(
+ DWORD dwInputStreamID,
+ _Outptr_result_maybenull_ IMFAttributes **ppAttributes
+)
+{
+ HRESULT hr = S_OK;
+
+ if(dwInputStreamID > 0)
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+ if(!ppAttributes)
+ {
+ return E_POINTER;
+ }
+
+ if(!m_spInputAttributes)
+ {
+ hr = MFCreateAttributes(&m_spInputAttributes, 2);
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+ hr = m_spInputAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE);
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+ hr = m_spInputAttributes->SetString(MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft");
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+ }
+ hr = m_spInputAttributes.CopyTo(ppAttributes);
+
+done:
+ if(FAILED(hr))
+ {
+ m_spInputAttributes.Reset();
+ }
+ return hr;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetOutputStreamAttributes
+// Returns stream-level attributes for an output stream.
+//
+STDMETHODIMP CSocMft0::GetOutputStreamAttributes(
+ DWORD dwOutputStreamID,
+ _Outptr_result_maybenull_ IMFAttributes **ppAttributes
+)
+{
+ if(dwOutputStreamID > 0)
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if(!ppAttributes)
+ {
+ return E_POINTER;
+ }
+
+ if(!m_spInputAttributes)
+ {
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ return m_spInputAttributes.CopyTo(ppAttributes);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// DeleteInputStream
+//
+STDMETHODIMP CSocMft0::DeleteInputStream(
+ DWORD dwStreamID
+)
+{
+ UNREFERENCED_PARAMETER(dwStreamID);
+
+ // This MFT has a fixed number of input streams, so the method is not supported.
+ return (E_NOTIMPL);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// AddInputStreams
+//
+STDMETHODIMP CSocMft0::AddInputStreams(
+ DWORD cStreams,
+ _In_ DWORD *adwStreamIDs
+)
+{
+ UNREFERENCED_PARAMETER(cStreams);
+ UNREFERENCED_PARAMETER(adwStreamIDs);
+
+ // This MFT has a fixed number of output streams, so the method is not supported.
+ return (E_NOTIMPL);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetInputAvailableType
+// Returns a preferred input type.
+//
+STDMETHODIMP CSocMft0::GetInputAvailableType(
+ DWORD dwInputStreamID,
+ DWORD dwTypeIndex,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IUnknown> spUnknown;
+ ComPtr<IMFAttributes> spSourceAttributes;
+
+ CAutoLock lock(&m_critSec);
+ if(!IsValidInputStream(dwInputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if(!m_spSourceTransform && m_spInputAttributes)
+ {
+ hr = m_spInputAttributes->GetUnknown(MFT_CONNECTED_STREAM_ATTRIBUTE, IID_PPV_ARGS(spSourceAttributes.ReleaseAndGetAddressOf()));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spSourceAttributes->GetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, IID_PPV_ARGS(spUnknown.ReleaseAndGetAddressOf()));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spUnknown.As(&m_spSourceTransform);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spSourceAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spSourceAttributes->GetUINT32(MF_DEVICESTREAM_STREAM_ID, &m_uiSourceStreamId);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = GenerateMFMediaTypeListFromDevice();
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ hr = GetMediaType(dwInputStreamID, dwTypeIndex, ppType);
+
+ return hr;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetOutputAvailableType
+// Returns a preferred output type.
+//
+STDMETHODIMP CSocMft0::GetOutputAvailableType(
+ DWORD dwOutputStreamID,
+ DWORD dwTypeIndex,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IUnknown> spUnknown;
+ ComPtr<IMFAttributes> spSourceAttributes;
+
+ CAutoLock lock(&m_critSec);
+
+ if (!IsValidInputStream(dwOutputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if (!m_spSourceTransform && m_spInputAttributes)
+ {
+ hr = m_spInputAttributes->GetUnknown(MFT_CONNECTED_STREAM_ATTRIBUTE, IID_PPV_ARGS(spSourceAttributes.ReleaseAndGetAddressOf()));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spSourceAttributes->GetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, IID_PPV_ARGS(spUnknown.ReleaseAndGetAddressOf()));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spUnknown.As(&m_spSourceTransform);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spSourceAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = spSourceAttributes->GetUINT32(MF_DEVICESTREAM_STREAM_ID, &m_uiSourceStreamId);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ //
+ // This is the first function get called after the MFT0 object get instantiated,
+ // Here we can generate the supported media type from the connected input pin,
+ // Also, we can selectively plug in MFT0 only on pins requires processing
+ // by returning error on the unwanted pin types. Example below if we did not
+ // want MFT0 for Record
+
+ //if(m_stStreamType != PINNAME_IMAGE && m_stStreamType != PINNAME_VIDEO_PREVIEW)
+ //{
+ // return E_UNEXPECTED;
+ //}
+
+ hr = GenerateMFMediaTypeListFromDevice();
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ return GetMediaType(dwOutputStreamID, dwTypeIndex, ppType);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// SetInputType
+//
+STDMETHODIMP CSocMft0::SetInputType(
+ DWORD dwInputStreamID,
+ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags
+)
+{
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+
+ BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
+
+ // Validate flags.
+ // Only MFT_SET_TYPE_TEST_ONLY is supported, if any other bit flags
+ // get set, it should return error.
+ if(dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
+ {
+ return E_INVALIDARG;
+ }
+
+ if(!bReallySet)
+ {
+ return IsMediaTypeSupported(dwInputStreamID, pType);
+ }
+
+ ComPtr<IMFMediaType> spFullType;
+ hr = IsMediaTypeSupported(dwInputStreamID, pType, spFullType.ReleaseAndGetAddressOf());
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ m_spInputType = spFullType;
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// SetOutputType
+// This function set the output media type and at the same time, it should
+// also choose a compatible input type
+//
+STDMETHODIMP CSocMft0::SetOutputType(
+ DWORD dwOutputStreamID,
+ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags
+)
+{
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+ BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
+ BOOL bUseModifiedInputType = FALSE;
+
+ // Validate flags.
+ if(dwFlags & ~MFT_SET_TYPE_TEST_ONLY)
+ {
+ return E_INVALIDARG;
+ }
+
+ if(!bReallySet)
+ {
+ return IsMediaTypeSupported(dwOutputStreamID, pType);
+ }
+
+ ComPtr<IMFMediaType> spFullType;
+ ComPtr<IMFMediaType> spFullInputType;
+ hr = IsMediaTypeSupported(dwOutputStreamID, pType, spFullType.ReleaseAndGetAddressOf());
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ if (m_stStreamType == PINNAME_CAPTURE)
+ {
+ hr = GetVideoStabilizationEnabled();
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ // Hardware Video Stabilization is enabled
+ if (m_bEnableVideoStabilization)
+ {
+ UINT32 uiIndex = 0;
+ //This shouldn't fail, since it is derived from IsMediaTypeSupported
+ // and that just passed.
+ hr = FindMediaIndex(dwOutputStreamID, pType, &uiIndex);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ //Device Driver contains a static list of mediatypes on the pin
+ // We have ordered them in such a way so that all odd mediatypes are the
+ // overscan media of the even mediatype immediatley proceeding it, ie.
+ // -normalVGA
+ // -overscanVGA
+ // -normalQVGA
+ // -overscanQVGA
+ // etc
+ // The following command determines if we are dealing with an overscan or normal mediatype
+ // if it is overscan, we fail (cannot overscan an overscan mediatype)
+ // otherwise, we set our input mediatype to the overscan type associated with it.
+ if (uiIndex % 2 != 0) //odd means overscan
+ {
+ return MF_E_INVALIDMEDIATYPE;
+ }
+ else //even
+ {
+ hr = GetMediaType(dwOutputStreamID, uiIndex + 1, spFullInputType.ReleaseAndGetAddressOf());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ bUseModifiedInputType = TRUE;
+ }
+ }
+ }
+ m_spOutputType = spFullType;
+
+ // Here, we choose a compatible input type which is the same type
+ // as output. If OEM choose to encode sample here, it should choose
+ // an input which is supported by encoder.
+ if (bUseModifiedInputType)
+ {
+ m_spInputType = spFullInputType;
+ }
+ else
+ {
+ m_spInputType = spFullType;
+ }
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetInputCurrentType
+// Returns the current input type.
+//
+STDMETHODIMP CSocMft0::GetInputCurrentType(
+ DWORD dwInputStreamID,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+)
+{
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+
+ if(!ppType)
+ {
+ return E_POINTER;
+ }
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if(!m_spInputType)
+ {
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ ComPtr<IMFMediaType> spMediaType;
+ hr = MFCreateMediaType(spMediaType.ReleaseAndGetAddressOf());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = m_spInputType->CopyAllItems(spMediaType.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ return spMediaType.CopyTo(ppType);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetOutputCurrentType
+// Returns the current output type.
+//
+STDMETHODIMP CSocMft0::GetOutputCurrentType(
+ DWORD dwOutputStreamID,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+)
+{
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+
+ if(!ppType)
+ {
+ return E_POINTER;
+ }
+
+ if (!IsValidOutputStream(dwOutputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+ if(!m_spOutputType)
+ {
+ return MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ ComPtr<IMFMediaType> spMediaType;
+ hr = MFCreateMediaType(spMediaType.ReleaseAndGetAddressOf());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = m_spOutputType->CopyAllItems(spMediaType.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ return spMediaType.CopyTo(ppType);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetInputStatus
+// Query if the MFT is accepting more input.
+//
+STDMETHODIMP CSocMft0::GetInputStatus(
+ DWORD dwInputStreamID,
+ _Out_ DWORD *pdwFlags
+)
+{
+ CAutoLock lock(&m_critSec);
+
+ if(!pdwFlags)
+ {
+ return E_POINTER;
+ }
+
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ // If we already have an input sample, we don't accept
+ // another one until the client calls ProcessOutput or Flush.
+ if (m_spSample == NULL)
+ {
+ *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
+ }
+ else
+ {
+ *pdwFlags = 0;
+ }
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// GetOutputStatus
+// Query if the MFT can produce output.
+//
+STDMETHODIMP CSocMft0::GetOutputStatus(
+ _Out_ DWORD *pdwFlags
+)
+{
+ if(!pdwFlags)
+ {
+ return E_POINTER;
+ }
+
+ CAutoLock lock(&m_critSec);
+
+ // We can produce an output sample if (and only if)
+ // we have an input sample.
+ if (m_spSample != NULL)
+ {
+ *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
+ }
+ else
+ {
+ *pdwFlags = 0;
+ }
+
+ return S_OK;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// SetOutputBounds
+// Sets the range of time stamps that the MFT will output.
+//
+STDMETHODIMP CSocMft0::SetOutputBounds(
+ LONGLONG hnsLowerBound,
+ LONGLONG hnsUpperBound
+)
+{
+ UNREFERENCED_PARAMETER(hnsLowerBound);
+ UNREFERENCED_PARAMETER(hnsUpperBound);
+
+ // Implementation of this method is optional.
+ return (E_NOTIMPL);
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ProcessEvent
+// Sends an event to an input stream.
+//
+STDMETHODIMP CSocMft0::ProcessEvent(
+ DWORD dwInputStreamID,
+ _In_opt_ IMFMediaEvent *pEvent
+)
+{
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(pEvent);
+ return E_NOTIMPL;
+}
+
+////////////////////////////////////////////////////////////////////////
+//
+// ProcessMessage
+//
+STDMETHODIMP CSocMft0::ProcessMessage(
+ MFT_MESSAGE_TYPE eMessage,
+ ULONG_PTR ulParam
+)
+{
+ UNREFERENCED_PARAMETER(ulParam);
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+
+ switch (eMessage)
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ // Flush the MFT.
+ hr = OnFlush();
+ break;
+ }
+
+ return hr;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// ProcessInput
+// Process an input sample. The sample is cached and real work is done
+// in ProcessOutput
+//
+STDMETHODIMP CSocMft0::ProcessInput(
+ DWORD dwInputStreamID,
+ IMFSample *pSample,
+ DWORD dwFlags
+)
+{
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+
+ if(!pSample)
+ {
+ return E_POINTER;
+ }
+ if(dwFlags != 0)
+ {
+ return E_INVALIDARG;
+ }
+
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if (!m_spInputType || !m_spOutputType)
+ {
+ return MF_E_NOTACCEPTING; // Client must set input and output types.
+ }
+
+ if (m_spSample != NULL)
+ {
+ return MF_E_NOTACCEPTING; // We already have an input sample.
+ }
+
+ // Validate the number of buffers. There should only be a single buffer to hold the video frame.
+ DWORD dwBufferCount = 0;
+ hr = pSample->GetBufferCount(&dwBufferCount);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ if (dwBufferCount == 0)
+ {
+ return E_FAIL;
+ }
+
+ if (dwBufferCount > 1)
+ {
+ return MF_E_SAMPLE_HAS_TOO_MANY_BUFFERS;
+ }
+
+ // Cache the sample. We do the actual work in ProcessOutput.
+ m_spSample = pSample;
+
+ return S_OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// ProcessOutput
+// Process an output sample.
+//
+STDMETHODIMP CSocMft0::ProcessOutput(
+ DWORD dwFlags,
+ DWORD cOutputBufferCount,
+ MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ DWORD *pdwStatus
+)
+{
+ HRESULT hr = S_OK;
+
+ CAutoLock lock(&m_critSec);
+
+ if(dwFlags != 0)
+ {
+ return E_INVALIDARG;
+ }
+
+ if(!pOutputSamples || !pdwStatus)
+ {
+ return E_POINTER;
+ }
+
+ if( pOutputSamples[0].pSample)
+ {
+ pOutputSamples[0].pSample->Release();
+ pOutputSamples[0].pSample = nullptr;
+ }
+
+ // Must be exactly one output buffer.
+ if(cOutputBufferCount != 1)
+ {
+ return E_INVALIDARG;
+ }
+
+ // If we don't have an input sample, we need some input before
+ // we can generate any output.
+ if(m_spSample == nullptr)
+ {
+ return MF_E_TRANSFORM_NEED_MORE_INPUT;
+ }
+
+ hr = ProcessMetadata();
+ if(FAILED(hr))
+ {
+ //Log the failure
+ hr = S_OK;
+ }
+ hr = CreateOutputSample(&pOutputSamples[0].pSample);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ pOutputSamples[0].dwStatus = 0;
+ *pdwStatus = 0;
+
+ // if createOutputSample actually make a copy of the sample,
+ // (for example, JPEG encoding case), we need to copy the
+ // attribute from m_spSample to spOutputIMFSample
+ m_spSample.Reset();
+ return hr;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// The actual processing is here, required operation is demux
+// Other operation is optional
+//
+HRESULT
+CSocMft0::
+CreateOutputSample(
+ _Outptr_result_maybenull_
+ IMFSample **ppSample
+)
+{
+ HRESULT hr = S_OK;
+
+ //Do nothing for now
+ if(!ppSample)
+ {
+ return E_POINTER;
+ }
+
+ m_spSample.CopyTo(ppSample);
+
+ return hr;
+}
+/////////////////////////////////////////////////////////////////////
+//
+// Flush the MFT.
+//
+STDMETHODIMP CSocMft0::OnFlush()
+{
+ // For this MFT, flushing just means releasing the input sample.
+ CAutoLock lock(&m_critSec);
+ m_spSample.Reset();
+ return S_OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// Get the mediaType of selected stream.
+//
+STDMETHODIMP CSocMft0::GetMediaType(
+ _In_ DWORD dwStreamId,
+ _In_ DWORD dwTypeIndex,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaType> spMediaType;
+
+ if(!ppType)
+ {
+ return E_POINTER;
+ }
+
+ if(dwStreamId != 0)
+ {
+ return MF_E_INVALIDSTREAMNUMBER;
+ }
+
+ if(dwTypeIndex >= m_listOfMediaTypes.size())
+ {
+ return MF_E_NO_MORE_TYPES;
+ }
+
+ hr = MFCreateMediaType(spMediaType.ReleaseAndGetAddressOf());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = m_listOfMediaTypes[dwTypeIndex]->CopyAllItems(spMediaType.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ return spMediaType.CopyTo(ppType);
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// Check if the media type is supported by MFT0.
+//
+STDMETHODIMP CSocMft0::IsMediaTypeSupported(
+ _In_ UINT uiStreamId,
+ _In_ IMFMediaType *pIMFMediaType,
+ _Outptr_result_maybenull_ IMFMediaType **ppIMFMediaTypeFull
+)
+{
+ HRESULT hr = S_OK;
+
+ if(!pIMFMediaType)
+ {
+ return E_POINTER;
+ }
+
+ if(uiStreamId != 0)
+ {
+ return MF_E_INVALIDINDEX;
+ }
+
+ BOOL bFound =FALSE;
+
+
+ for(UINT i = 0; i< m_listOfMediaTypes.size(); i++)
+ {
+ DWORD dwResult = 0;
+ hr = m_listOfMediaTypes[i]->IsEqual(pIMFMediaType, &dwResult);
+ if(hr == S_FALSE)
+ {
+ if((dwResult & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_DATA))
+ {
+ hr = S_OK;
+ }
+ }
+ if(hr == S_OK)
+ {
+ bFound = TRUE;
+ if(ppIMFMediaTypeFull)
+ {
+ m_listOfMediaTypes[i].CopyTo(ppIMFMediaTypeFull);
+ }
+ break;
+ }
+ else if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(bFound == FALSE)
+ {
+ return MF_E_INVALIDMEDIATYPE;
+ }
+
+ return S_OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// Check if the media type is supported by MFT0.
+//
+_Success_(return == 0)
+STDMETHODIMP CSocMft0::FindMediaIndex(
+ _In_ UINT uiStreamId,
+ _In_ IMFMediaType *pIMFMediaType,
+ _Out_ UINT *puiMediaIndex
+)
+{
+ HRESULT hr = S_OK;
+
+ if(!pIMFMediaType || !puiMediaIndex)
+ {
+ return E_INVALIDARG;
+ }
+
+ if(uiStreamId != 0)
+ {
+ return MF_E_INVALIDINDEX;
+ }
+
+ BOOL bFound = FALSE;
+
+ for(UINT i = 0; i< m_listOfMediaTypes.size(); i++)
+ {
+ DWORD dwResult = 0;
+ hr = m_listOfMediaTypes[i]->IsEqual(pIMFMediaType, &dwResult);
+ if(hr == S_FALSE)
+ {
+ if((dwResult & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) &&
+ (dwResult & MF_MEDIATYPE_EQUAL_FORMAT_TYPES) &&
+ (dwResult & MF_MEDIATYPE_EQUAL_FORMAT_DATA))
+ {
+ hr = S_OK;
+ }
+ }
+ if(hr == S_OK)
+ {
+ bFound = TRUE;
+ *puiMediaIndex = i;
+ break;
+ }
+ else if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(bFound == FALSE)
+ {
+ return MF_E_INVALIDMEDIATYPE;
+ }
+
+ return S_OK;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// Generate the supported input media type from device source media type
+//
+STDMETHODIMP CSocMft0::GenerateMFMediaTypeListFromDevice()
+{
+ HRESULT hr = S_OK;
+
+ if(!m_spSourceTransform)
+ {
+ return MF_E_NOT_FOUND;
+ }
+
+ m_listOfMediaTypes.clear();
+ UINT iMediaType = 0;
+ while(SUCCEEDED(hr))
+ {
+ ComPtr<IMFMediaType> spMediaType;
+ hr = m_spSourceTransform->GetOutputAvailableType(m_uiSourceStreamId, iMediaType, spMediaType.ReleaseAndGetAddressOf());
+ if(FAILED(hr))
+ {
+ if(hr == MF_E_NO_MORE_TYPES)
+ {
+ hr = S_OK;
+ }
+ break;
+ }
+
+ if(m_stStreamType == PINNAME_IMAGE || m_stStreamType == PINNAME_VIDEO_STILL)
+ {
+ GUID guidPhotoSubType = {};
+ spMediaType->GetGUID(MF_MT_SUBTYPE, &guidPhotoSubType);
+ if (IsEqualGUID(guidPhotoSubType, MFVideoFormat_NV12))
+ {
+ // Need to set MF_MT_VIDEO_NOMINAL_RANGE on NV12 or the pipeline ends up with a copy due to mismatched nominal range
+ hr = spMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+
+ m_listOfMediaTypes.push_back(spMediaType);
+ }
+
+ else if (m_stStreamType == PINNAME_CAPTURE)
+ {
+ UINT32 width = 0;
+ UINT32 height = 0;
+ hr = MFGetAttributeSize(spMediaType.Get(), MF_MT_FRAME_SIZE, &width, &height);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ MFVideoArea validVideo;
+ validVideo.OffsetX.value = 0;
+ validVideo.OffsetX.fract = 0;
+ validVideo.OffsetY.value = 0;
+ validVideo.OffsetY.fract = 0;
+ validVideo.Area.cx = width;
+ validVideo.Area.cy = height;
+ hr = spMediaType->SetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (BYTE *)&validVideo, sizeof(validVideo));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ m_listOfMediaTypes.push_back(spMediaType);
+ }
+
+ else
+ {
+ m_listOfMediaTypes.push_back(spMediaType);
+ }
+
+ iMediaType++;
+ }
+
+ return hr;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// Get the current media type in order to generate photo confirmation
+//
+HRESULT CSocMft0::GetPreviewMediaType(
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+)
+{
+ CAutoLock lock(&m_critSec);
+ if(!m_spSourceTransform)
+ {
+ return MF_E_NOT_FOUND;
+ }
+
+ DWORD dwInStreamCount = 0, dwOutStreamCount = 0;
+ HRESULT hr = m_spSourceTransform->GetStreamCount(
+ &dwInStreamCount,
+ &dwOutStreamCount);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ for(UINT32 i = 0 ; i < dwOutStreamCount; i++)
+ {
+ ComPtr<IMFAttributes> spAttributes;
+ hr = m_spSourceTransform->GetOutputStreamAttributes(i, spAttributes.ReleaseAndGetAddressOf());
+ if(FAILED(hr))
+ {
+ continue;
+ }
+
+ GUID guidPinCategory = GUID_NULL;
+ hr = spAttributes->GetGUID(
+ MF_DEVICESTREAM_STREAM_CATEGORY,
+ &guidPinCategory);
+ if(FAILED(hr))
+ {
+ continue;
+ }
+ if (IsEqualGUID(guidPinCategory, PINNAME_VIDEO_PREVIEW))
+ {
+ ComPtr<IMFMediaType> spMediaType;
+ hr = m_spSourceTransform->GetOutputCurrentType(i, spMediaType.ReleaseAndGetAddressOf());
+ if(FAILED(hr))
+ {
+ return MF_E_NOT_FOUND;
+ }
+ return spMediaType.CopyTo(ppType);
+ }
+ }
+
+ return MF_E_NOT_FOUND;
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// Handle the Metadata with the buffer
+//
+HRESULT CSocMft0::ProcessMetadata()
+{
+ ComPtr<IMFAttributes> spMetadata;
+ HRESULT hr = m_spSample->GetUnknown(MFSampleExtension_CaptureMetadata, IID_PPV_ARGS(spMetadata.ReleaseAndGetAddressOf()));
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ ComPtr<IMFMediaBuffer> spBuffer;
+ hr = spMetadata->GetUnknown(MF_CAPTURE_METADATA_FRAME_RAWSTREAM, IID_PPV_ARGS(spBuffer.ReleaseAndGetAddressOf()));
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ MediaBufferLock bufferLock(spBuffer.Get());
+ BYTE *pData = NULL;
+ DWORD dwLength = 0;
+ hr = bufferLock.LockBuffer(&pData, NULL, &dwLength);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ // OEM put meta data passing logic here,
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ LONG lBufferLeft = static_cast<LONG>(dwLength);
+ if(lBufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PKSCAMERA_METADATA_ITEMHEADER pItem = (PKSCAMERA_METADATA_ITEMHEADER) pData;
+
+ while(lBufferLeft > 0)
+ {
+ switch (pItem->MetadataId)
+ {
+ case MetadataId_Custom_PreviewAggregation:
+ hr = ParseMetadata_PreviewAggregation(pItem, spMetadata.Get());
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ break;
+ case MetadataId_Custom_ImageAggregation:
+ hr = ParseMetadata_ImageAggregation(pItem, spMetadata.Get());
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ break;
+ case MetadataId_Custom_Histogram:
+ hr = ParseMetadata_Histogram(pItem, spMetadata.Get());
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ break;
+ case MetadataId_Custom_FaceDetection:
+ hr = ParseMetadata_FaceDetection(pItem, spMetadata.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(!pItem->Size)
+ {
+ // 0 size item will cause the loop to break and
+ // we will report buffer malformated
+ break;
+ }
+ lBufferLeft -= (LONG)pItem->Size;
+ if(lBufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER))
+ {
+ break;
+ }
+ pItem = reinterpret_cast<PKSCAMERA_METADATA_ITEMHEADER>
+ (reinterpret_cast<PBYTE>(pItem) + pItem->Size);
+ }
+
+ if(lBufferLeft != 0)
+ {
+ //Check and log for malformated data
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
+
+HRESULT CSocMft0::ParseMetadata_PreviewAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+)
+{
+ HRESULT hr = S_OK;
+ if(pItem->Size < sizeof(CAMERA_METADATA_PREVIEWAGGREGATION))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_PREVIEWAGGREGATION pFixedStruct =
+ (PCAMERA_METADATA_PREVIEWAGGREGATION)pItem;
+
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FOCUSSTATE,
+ pFixedStruct->Data.FocusState);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+
+ if(pFixedStruct->Data.ExposureTime.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_EXPOSURE_TIME,
+ pFixedStruct->Data.ExposureTime.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.ISOSpeed.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_ISO_SPEED,
+ pFixedStruct->Data.ISOSpeed.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.LensPosition.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_LENS_POSITION,
+ pFixedStruct->Data.LensPosition.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.FlashOn.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FLASH,
+ pFixedStruct->Data.FlashOn.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.WhiteBalanceMode.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_WHITEBALANCE,
+ pFixedStruct->Data.WhiteBalanceMode.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.EVCompensation.Set)
+ {
+ CapturedMetadataExposureCompensation EVCompensation;
+
+ EVCompensation.Flags = pFixedStruct->Data.EVCompensation.Flags;
+ EVCompensation.Value = pFixedStruct->Data.EVCompensation.Value;
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_EXPOSURE_COMPENSATION,
+ (const UINT8 *)&EVCompensation,
+ sizeof(EVCompensation));
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.SensorFrameRate.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_SENSORFRAMERATE,
+ pFixedStruct->Data.SensorFrameRate.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if( pFixedStruct->Data.IsoAnalogGain.Set ||
+ pFixedStruct->Data.IsoDigitalGain.Set )
+ {
+ CapturedMetadataISOGains IsoGains;
+
+ if( pFixedStruct->Data.IsoAnalogGain.Set )
+ {
+ IsoGains.AnalogGain =
+ FLOAT( pFixedStruct->Data.IsoAnalogGain.Numerator ) /
+ FLOAT( pFixedStruct->Data.IsoAnalogGain.Denominator );
+ }
+ if( pFixedStruct->Data.IsoDigitalGain.Set )
+ {
+ IsoGains.DigitalGain =
+ FLOAT( pFixedStruct->Data.IsoDigitalGain.Numerator ) /
+ FLOAT( pFixedStruct->Data.IsoDigitalGain.Denominator );
+ }
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_ISO_GAINS,
+ (const UINT8 *)&IsoGains,
+ sizeof(IsoGains));
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if( pFixedStruct->Data.WhiteBalanceGain_R.Set ||
+ pFixedStruct->Data.WhiteBalanceGain_G.Set ||
+ pFixedStruct->Data.WhiteBalanceGain_B.Set )
+ {
+ CapturedMetadataWhiteBalanceGains WhiteBalanceGains;
+
+ if( pFixedStruct->Data.WhiteBalanceGain_R.Set )
+ {
+ WhiteBalanceGains.R =
+ FLOAT( pFixedStruct->Data.WhiteBalanceGain_R.Numerator ) /
+ FLOAT( pFixedStruct->Data.WhiteBalanceGain_R.Denominator );
+ }
+ if( pFixedStruct->Data.WhiteBalanceGain_G.Set )
+ {
+ WhiteBalanceGains.G =
+ FLOAT( pFixedStruct->Data.WhiteBalanceGain_G.Numerator ) /
+ FLOAT( pFixedStruct->Data.WhiteBalanceGain_G.Denominator );
+ }
+ if( pFixedStruct->Data.WhiteBalanceGain_B.Set )
+ {
+ WhiteBalanceGains.B =
+ FLOAT( pFixedStruct->Data.WhiteBalanceGain_B.Numerator ) /
+ FLOAT( pFixedStruct->Data.WhiteBalanceGain_B.Denominator );
+ }
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_WHITEBALANCE_GAINS,
+ (const UINT8 *)&WhiteBalanceGains,
+ sizeof(WhiteBalanceGains));
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CSocMft0::ParseMetadata_ImageAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+)
+{
+ HRESULT hr = S_OK;
+ if(pItem->Size < sizeof(CAMERA_METADATA_IMAGEAGGREGATION))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_IMAGEAGGREGATION pFixedStruct =
+ (PCAMERA_METADATA_IMAGEAGGREGATION)pItem;
+
+ if(pFixedStruct->Data.FrameId.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_REQUESTED_FRAME_SETTING_ID,
+ pFixedStruct->Data.FrameId.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.ExposureTime.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_EXPOSURE_TIME,
+ pFixedStruct->Data.ExposureTime.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.ISOSpeed.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_ISO_SPEED,
+ pFixedStruct->Data.ISOSpeed.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.LensPosition.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_LENS_POSITION,
+ pFixedStruct->Data.LensPosition.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.SceneMode.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_SCENE_MODE,
+ pFixedStruct->Data.SceneMode.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.FlashOn.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FLASH,
+ pFixedStruct->Data.FlashOn.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.FlashPower.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FLASH_POWER,
+ pFixedStruct->Data.FlashPower.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.WhiteBalanceMode.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_WHITEBALANCE,
+ pFixedStruct->Data.WhiteBalanceMode.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.ZoomFactor.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_ZOOMFACTOR,
+ pFixedStruct->Data.ZoomFactor.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if(pFixedStruct->Data.EVCompensation.Set)
+ {
+ CapturedMetadataExposureCompensation EVCompensation;
+
+ EVCompensation.Flags = pFixedStruct->Data.EVCompensation.Flags;
+ EVCompensation.Value = pFixedStruct->Data.EVCompensation.Value;
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_EXPOSURE_COMPENSATION,
+ (const UINT8 *)&EVCompensation,
+ sizeof(EVCompensation));
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if( pFixedStruct->Data.FocusState.Set )
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FOCUSSTATE,
+ pFixedStruct->Data.FocusState.Value);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ }
+ return S_OK;
+}
+
+struct HistogramData
+{
+ HistogramDataHeader Header;
+ ULONG Color[256];
+
+ HistogramData()
+ {
+ Header.Size = sizeof(*this);
+ Header.ChannelMask = 0;
+ Header.Linear = 1;
+ RtlZeroMemory( Color, sizeof(Color) );
+ }
+};
+
+// This is the blob we pass back every time.
+template <ULONG I>
+struct Histogram
+{
+ HistogramBlobHeader Blob;
+ // RGB or YUV Histograms.
+ HistogramHeader Header;
+ HistogramData Data[I];
+
+ Histogram(
+ _In_ ULONG Width=0,
+ _In_ ULONG Height=0
+ )
+ {
+ Blob.Histograms = 1;
+ Blob.Size = sizeof(*this);
+
+ Header.Size = sizeof(Header) + sizeof(Data);
+ Header.Bins = 256;
+ Header.Grid.Height = Height;
+ Header.Grid.Width = Width;
+ Header.Grid.Region.top = 0;
+ Header.Grid.Region.left = 0;
+ Header.Grid.Region.bottom = Height-1;
+ Header.Grid.Region.right = Width-1;
+ }
+};
+
+#define MF_HISTOGRAM_RGB (MF_HISTOGRAM_CHANNEL_R | MF_HISTOGRAM_CHANNEL_G | MF_HISTOGRAM_CHANNEL_B )
+#define MF_HISTOGRAM_YCrCb (MF_HISTOGRAM_CHANNEL_Y | MF_HISTOGRAM_CHANNEL_Cr | MF_HISTOGRAM_CHANNEL_Cb)
+
+HRESULT CSocMft0::ParseMetadata_Histogram(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+)
+{
+ if(pItem->Size < sizeof(CAMERA_METADATA_HISTOGRAM))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_HISTOGRAM pHistogram = (PCAMERA_METADATA_HISTOGRAM) pItem;
+
+ if( (pHistogram->Data.ChannelMask & MF_HISTOGRAM_RGB) == MF_HISTOGRAM_RGB )
+ {
+ Histogram<4> Blob( pHistogram->Data.Width, pHistogram->Data.Height );
+
+ Blob.Header.FourCC = pHistogram->Data.FourCC;
+ Blob.Header.ChannelMasks = pHistogram->Data.ChannelMask;
+
+ // For a RGB Histogram, we fake the Y channel by copying the G channel.
+ Blob.Data[0].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Y;
+ RtlCopyMemory( Blob.Data[0].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[0].Color) );
+
+ // Now just copy the RGB channels normally.
+ Blob.Data[1].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_R;
+ RtlCopyMemory( Blob.Data[1].Color, pHistogram->Data.P0Data, sizeof(Blob.Data[1].Color) );
+ Blob.Data[2].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_G;
+ RtlCopyMemory( Blob.Data[2].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[2].Color) );
+ Blob.Data[3].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_B;
+ RtlCopyMemory( Blob.Data[3].Color, pHistogram->Data.P2Data, sizeof(Blob.Data[3].Color) );
+
+ return pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_HISTOGRAM,
+ (PBYTE) &Blob,
+ sizeof(Blob)
+ );
+ }
+ else if( (pHistogram->Data.ChannelMask & MF_HISTOGRAM_YCrCb) == MF_HISTOGRAM_YCrCb )
+ {
+ Histogram<3> Blob( pHistogram->Data.Width, pHistogram->Data.Height );
+
+ Blob.Header.FourCC = pHistogram->Data.FourCC;
+ Blob.Header.ChannelMasks = pHistogram->Data.ChannelMask;
+
+ Blob.Data[0].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Y;
+ RtlCopyMemory( Blob.Data[0].Color, pHistogram->Data.P0Data, sizeof(Blob.Data[0].Color) );
+ Blob.Data[1].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Cr;
+ RtlCopyMemory( Blob.Data[1].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[1].Color) );
+ Blob.Data[2].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Cb;
+ RtlCopyMemory( Blob.Data[2].Color, pHistogram->Data.P2Data, sizeof(Blob.Data[2].Color) );
+
+ //TODO:
+ return pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_HISTOGRAM,
+ (PBYTE) &Blob,
+ sizeof(Blob)
+ );
+ }
+ return E_UNEXPECTED;
+}
+
+HRESULT CSocMft0::ParseMetadata_FaceDetection(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+)
+{
+ HRESULT hr = S_OK;
+
+ if (pItem->Size < sizeof(CAMERA_METADATA_FACEHEADER))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_FACEHEADER pFaceHeader = (PCAMERA_METADATA_FACEHEADER)pItem;
+
+ if( pItem->Size < (sizeof(CAMERA_METADATA_FACEHEADER) + (sizeof(METADATA_FACEDATA) * pFaceHeader->Count)) )
+ {
+ return E_UNEXPECTED;
+ }
+ PMETADATA_FACEDATA pFaceData = (PMETADATA_FACEDATA) (pFaceHeader+1);
+ UINT32 cbRectSize = sizeof(FaceRectInfoBlobHeader) + (sizeof(FaceRectInfo) * (pFaceHeader->Count));
+ BYTE *pRectBuf = new BYTE [cbRectSize];
+ if (pRectBuf == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ UINT32 cbCharSize = sizeof(FaceCharacterizationBlobHeader) + (sizeof(FaceCharacterization) * (pFaceHeader->Count));
+ BYTE *pCharBuf = new BYTE[cbCharSize];
+ if (pCharBuf == NULL)
+ {
+ delete [] pRectBuf;
+ return E_OUTOFMEMORY;
+ }
+
+ FaceRectInfoBlobHeader *pFaceRectHeader = (FaceRectInfoBlobHeader *)pRectBuf;
+ pFaceRectHeader->Size = cbRectSize;
+ pFaceRectHeader->Count = pFaceHeader->Count;
+
+ FaceCharacterizationBlobHeader *pFaceCharHeader = (FaceCharacterizationBlobHeader *)pCharBuf;
+ pFaceCharHeader->Size = cbCharSize;
+ pFaceCharHeader->Count = pFaceHeader->Count;
+
+ FaceRectInfo *FaceRegions = (FaceRectInfo *)(pFaceRectHeader + 1);
+ FaceCharacterization *FaceChars = (FaceCharacterization *) (pFaceCharHeader + 1);
+
+ for (UINT i = 0; i < pFaceHeader->Count; i++)
+ {
+ FaceRegions[i].Region = pFaceData[i].Region;
+ FaceRegions[i].confidenceLevel = pFaceData[i].confidenceLevel;
+
+ FaceChars[i].BlinkScoreLeft = pFaceData[i].BlinkScoreLeft;
+ FaceChars[i].BlinkScoreRight = pFaceData[i].BlinkScoreRight;
+ FaceChars[i].FacialExpression = (pFaceData[i].FacialExpression==EXPRESSION_SMILE)?MF_METADATAFACIALEXPRESSION_SMILE:0;
+ FaceChars[i].FacialExpressionScore = pFaceData[i].FacialExpressionScore;
+ }
+
+ hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROIS, pRectBuf, cbRectSize);
+ if( FAILED(hr) )
+ {
+ goto done;
+ }
+
+ MetadataTimeStamps timestamp;
+ timestamp.Flags = MF_METADATATIMESTAMPS_DEVICE;
+ timestamp.Device = pFaceHeader->Timestamp;
+
+ hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROITIMESTAMPS, (const UINT8 *)&timestamp, sizeof(MetadataTimeStamps));
+ if( FAILED(hr) )
+ {
+ goto done;
+ }
+
+ // Include characterization data if any of the associated bits were set.
+ if( pFaceHeader->Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_ADVANCED_MASK )
+ {
+ hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROICHARACTERIZATIONS , pCharBuf, cbCharSize);
+ }
+
+done:
+ delete [] pRectBuf;
+ delete [] pCharBuf;
+
+ return hr;
+}
+
+HRESULT CSocMft0::FillBufferLengthFromMediaType(
+ _In_ IMFMediaType *pPreviewType,
+ _Inout_ IMFMediaBuffer *pBuffer
+)
+{
+ if(!pPreviewType || !pBuffer)
+ {
+ return E_INVALIDARG;
+ }
+
+ UINT32 uiWidth = 0, uiHeight = 0, uiImageSize = 0;
+ GUID guidSubType= {};
+
+ HRESULT hr = MFGetAttributeSize(pPreviewType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = pPreviewType->GetGUID(MF_MT_SUBTYPE, &guidSubType);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = MFCalculateImageSize(guidSubType, uiWidth, uiHeight, &uiImageSize);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ return pBuffer->SetCurrentLength(uiImageSize);
+}
+
+HRESULT CSocMft0::GetVideoStabilizationEnabled()
+{
+ HRESULT hr = S_OK;
+ ComPtr<IKsControl> spKsControl;
+ KSPROPERTY ksProperty = { 0 };
+ KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION_S ksData = { 0 };
+ ULONG bytesReturned = 0;
+
+ if (m_spSourceTransform != NULL)
+ {
+ hr = m_spSourceTransform.As(&spKsControl);
+ if (SUCCEEDED(hr))
+ {
+ ksProperty.Set = PROPSETID_VIDCAP_CUSTOM_CAMERACONTROL_MFT0;
+ ksProperty.Id = KSPROPERTY_CUSTOM_CAMERACONTROL_MFT0_VIDEOSTABILIZATION;
+ ksProperty.Flags = KSPROPERTY_TYPE_GET;
+
+ hr = spKsControl->KsProperty(&ksProperty, sizeof(ksProperty), &ksData, sizeof(ksData), &bytesReturned);
+ if (SUCCEEDED(hr))
+ {
+ m_bEnableVideoStabilization = ksData.VideoStabilizationEnabled;
+ }
+ }
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ return hr;
+}
diff --git a/AVStream/avscamera/mft0/MFT0Impl.h b/AVStream/avscamera/mft0/MFT0Impl.h
new file mode 100644
index 00000000..8644cf84
--- /dev/null
+++ b/AVStream/avscamera/mft0/MFT0Impl.h
@@ -0,0 +1,328 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ Mft0Impl.h
+
+ Abstract:
+
+ The CSocMft0 class definition - an implementation of the iSocMft0
+ interface found in Mft0.idl.
+
+ History:
+
+ created 4/26/2013
+
+**************************************************************************/
+
+
+#pragma once
+#include "Mft0.h"
+#include "SampleHelpers.h"
+#include "Mft0clsid.h"
+
+#include <wrl.h>
+
+// CSocMft0
+#define FaceDetectionDelayMax 2 //frames between emitting facedetection data
+
+ULONG DllAddRef();
+ULONG DllRelease();
+
+using namespace Microsoft::WRL;
+
+class CSocMft0:
+ public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>,
+ ISocMft0,
+ IMFTransform,
+ IInspectable>
+{
+
+public:
+
+ static HRESULT CreateInstance(REFIID iid, void **ppMFT);
+
+ CSocMft0():
+ m_bEnableEffects(TRUE),
+ m_bEnableVideoStabilization(FALSE),
+ m_uiSourceStreamId(0),
+ m_uiInternalState(0),
+ m_uThumbnailScaleFactor(4)
+ {
+ InitializeCriticalSection(&m_critSec);
+ m_stThumbnailFormat = MFVideoFormat_ARGB32;
+ DllAddRef();
+
+ }
+
+ HRESULT FinalConstruct();
+
+public:
+
+ /*ISocMft0*/
+ STDMETHOD(SetState)(UINT32 state);
+ STDMETHOD(GetState)(UINT32 *pState);
+
+ /*IInspectable*/
+ STDMETHOD(GetIids)(
+ _Out_ ULONG *iidCount,
+ _Outptr_result_buffer_maybenull_(*iidCount)
+ IID **iids
+ );
+
+ STDMETHOD(GetRuntimeClassName)(
+ _Outptr_result_maybenull_ HSTRING *pClassName
+ );
+
+ STDMETHOD(GetTrustLevel)(
+ _Out_ TrustLevel *trustLevel
+ );
+
+ /*IMFTransform*/
+ STDMETHOD(GetStreamLimits)(
+ _Out_ DWORD *pdwInputMinimum,
+ _Out_ DWORD *pdwInputMaximum,
+ _Out_ DWORD *pdwOutputMinimum,
+ _Out_ DWORD *pdwOutputMaximum
+ );
+
+ STDMETHOD(GetStreamCount)(
+ _Out_ DWORD *pcInputStreams,
+ _Out_ DWORD *pcOutputStreams
+ );
+
+ STDMETHOD(GetStreamIDs)(
+ DWORD dwInputIDArraySize,
+ _Out_writes_(dwInputIDArraySize) DWORD *pdwInputIDs,
+ DWORD dwOutputIDArraySize,
+ _Out_writes_(dwOutputIDArraySize) DWORD *pdwOutputIDs
+ );
+
+ STDMETHOD(GetInputStreamInfo)(
+ DWORD dwInputStreamID,
+ _Out_ MFT_INPUT_STREAM_INFO *pStreamInfo
+ );
+
+ STDMETHOD(GetOutputStreamInfo)(
+ DWORD dwOutputStreamID,
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+ );
+
+ STDMETHOD(GetAttributes)(
+ _Outptr_result_maybenull_ IMFAttributes **pAttributes
+ );
+
+ STDMETHOD(GetInputStreamAttributes)(
+ DWORD dwInputStreamID,
+ _Outptr_result_maybenull_ IMFAttributes **pAttributes
+ );
+
+ STDMETHOD(GetOutputStreamAttributes)(
+ DWORD dwOutputStreamID,
+ _Outptr_result_maybenull_
+ IMFAttributes **pAttributes
+ );
+
+ STDMETHOD(DeleteInputStream)(
+ DWORD dwStreamID
+ );
+
+ STDMETHOD(AddInputStreams)(
+ DWORD cStreams,
+ _In_ DWORD *adwStreamIDs
+ );
+
+ STDMETHOD(GetInputAvailableType)(
+ DWORD dwInputStreamID,
+ DWORD dwTypeIndex,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+ );
+
+ STDMETHOD(GetOutputAvailableType)(
+ DWORD dwOutputStreamID,
+ DWORD dwTypeIndex,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+ );
+
+ STDMETHOD(SetInputType)(
+ DWORD dwInputStreamID,
+ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags);
+
+ STDMETHOD(SetOutputType)(
+ DWORD dwOutputStreamID,
+ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags);
+
+ STDMETHOD(GetInputCurrentType)(
+ DWORD dwInputStreamID,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+ );
+
+ STDMETHOD(GetOutputCurrentType)(
+ DWORD dwOutputStreamID,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+ );
+
+ STDMETHOD(GetInputStatus)(
+ DWORD dwInputStreamID,
+ _Out_ DWORD *pdwFlags
+ );
+
+ STDMETHOD(GetOutputStatus)(
+ _Out_ DWORD *pdwFlags
+ );
+
+ STDMETHOD(SetOutputBounds)(
+ LONGLONG hnsLowerBound,
+ LONGLONG hnsUpperBound
+ );
+
+ STDMETHOD(ProcessEvent)(
+ DWORD dwInputStreamID,
+ _In_opt_ IMFMediaEvent *pEvent
+ );
+
+ STDMETHOD(ProcessMessage)(
+ MFT_MESSAGE_TYPE eMessage,
+ ULONG_PTR ulParam
+ );
+
+ STDMETHOD(ProcessInput)(
+ DWORD dwInputStreamID,
+ IMFSample *pSample,
+ DWORD dwFlags
+ );
+
+ STDMETHOD(ProcessOutput)(
+ DWORD dwFlags,
+ DWORD cOutputBufferCount,
+ MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ DWORD *pdwStatus
+ );
+
+protected:
+ virtual ~CSocMft0()
+ {
+ DeleteCriticalSection(&m_critSec);
+ DllRelease();
+ }
+
+ STDMETHOD(GetMediaType)(
+ _In_ DWORD dwStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+ );
+
+ STDMETHOD(IsMediaTypeSupported)(
+ _In_ UINT uiStreamId,
+ _In_ IMFMediaType *pIMFMediaType,
+ _Outptr_result_maybenull_ IMFMediaType **ppIMFMediaTypeFull = NULL
+ );
+
+ STDMETHOD(GenerateMFMediaTypeListFromDevice)();
+
+ _Success_(return == 0)
+ STDMETHOD(FindMediaIndex)(
+ _In_ UINT uiStreamId,
+ _In_ IMFMediaType *pIMFMediaType,
+ _Out_ UINT *puiMediaIndex
+ );
+
+ // HasPendingOutput: Returns TRUE if the MFT is holding an input sample.
+ BOOL HasPendingOutput() const
+ {
+ return m_spSample != NULL;
+ }
+
+ // IsValidInputStream: Returns TRUE if dwInputStreamID is a valid input stream identifier.
+ BOOL IsValidInputStream(DWORD dwInputStreamID) const
+ {
+ return dwInputStreamID == 0;
+ }
+
+ // IsValidOutputStream: Returns TRUE if dwOutputStreamID is a valid output stream identifier.
+ BOOL IsValidOutputStream(DWORD dwOutputStreamID) const
+ {
+ return dwOutputStreamID == 0;
+ }
+
+ HRESULT CreateOutputSample(
+ _Outptr_result_maybenull_ IMFSample **ppSample
+ );
+
+ HRESULT GetPreviewMediaType(
+ _Outptr_result_maybenull_ IMFMediaType **ppType
+ );
+
+ HRESULT ProcessMetadata();
+
+ HRESULT ParseMetadata_PreviewAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+ );
+
+ HRESULT ParseMetadata_ImageAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+ );
+
+ HRESULT ParseMetadata_Histogram(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+ );
+
+ HRESULT ParseMetadata_FaceDetection(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes *pMetaDataAttributes
+ );
+
+ HRESULT FillBufferLengthFromMediaType(
+ _In_ IMFMediaType *pPreviewType,
+ _Inout_ IMFMediaBuffer *pBuffer
+ );
+
+ STDMETHOD(OnFlush)();
+
+ HRESULT GetVideoStabilizationEnabled();
+
+ HRESULT GetThumbnailResolution();
+
+ HRESULT OnProcessImage(
+ _Outptr_result_maybenull_
+ IMFSample **ppIMFOutputSample
+ );
+
+ CRITICAL_SECTION m_critSec;
+
+ ComPtr<IMFSample> m_spSample; // Input sample.
+ ComPtr<IMFMediaType> m_spInputType; // Input media type.
+ ComPtr<IMFMediaType> m_spOutputType; // Output media type.
+
+ // Image transform function. (Changes based on the media type.)
+ ComPtr<IMFAttributes> m_spInputAttributes;
+ ComPtr<IMFAttributes> m_spGlobalAttributes;
+ GUID m_stStreamType;
+ ComPtr<IMFTransform> m_spSourceTransform;
+ volatile BOOL m_bEnableEffects;
+ BOOL m_bEnableVideoStabilization;
+ UINT m_uiSourceStreamId;
+ UINT m_uiInternalState;
+ BYTE m_uThumbnailScaleFactor;
+ GUID m_stThumbnailFormat;
+
+ std::vector<ComPtr<IMFMediaType>>
+ m_listOfMediaTypes;
+
+};
+
+inline HRESULT MFT0CreateInstance(REFIID riid, void **ppv)
+{
+ return CSocMft0::CreateInstance(riid, ppv);
+}
+
+//CoCreateableClass(CSocMft0); \ No newline at end of file
diff --git a/AVStream/avscamera/mft0/MFT0clsid.h b/AVStream/avscamera/mft0/MFT0clsid.h
new file mode 100644
index 00000000..d8aad5f5
--- /dev/null
+++ b/AVStream/avscamera/mft0/MFT0clsid.h
@@ -0,0 +1,26 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2015, Microsoft Corporation.
+
+ File:
+
+ Mft0clsid.h
+
+ Abstract:
+
+ Define the Class GUID of the MFT.
+
+ History:
+
+ created 2/19/2015
+
+**************************************************************************/
+
+#pragma once
+
+// CLSID of the MFT.
+// {1C2CE17A-FAAD-4E73-85E7-167068093F25}
+DEFINE_GUID(CLSID_AvsCamMft0,
+ 0x1c2ce17a, 0xfaad, 0x4e73, 0x85, 0xe7, 0x16, 0x70, 0x68, 0x9, 0x3f, 0x25);
diff --git a/AVStream/avscamera/mft0/SampleHelpers.h b/AVStream/avscamera/mft0/SampleHelpers.h
new file mode 100644
index 00000000..11908f82
--- /dev/null
+++ b/AVStream/avscamera/mft0/SampleHelpers.h
@@ -0,0 +1,106 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2013, Microsoft Corporation.
+
+ File:
+
+ SampleHelpers.h
+
+ Abstract:
+
+ Helper classes for the MFT0.
+
+ History:
+
+ created 4/26/2013
+
+**************************************************************************/
+
+#pragma once
+
+/***************************************************************************\
+*****************************************************************************
+*
+* class CAutoLock
+*
+* Locks a critical section at construction time and unlocks it automatically
+* when the object goes out of scope
+*
+*****************************************************************************
+\***************************************************************************/
+
+class CAutoLock
+{
+private:
+ // Make copy constructor and assignment operator inaccessible
+ CAutoLock(const CAutoLock &refAutoLock);
+ CAutoLock &operator=(const CAutoLock &refAutoLock);
+
+ // CAutoLock should not be created on the heap, so declare
+ // (but do not implement) private operator new/delete.
+ static void *operator new(size_t);
+ static void operator delete(void *);
+ static void *operator new[](size_t);
+ static void operator delete[](void *);
+
+protected:
+ CRITICAL_SECTION *m_pLock;
+
+public:
+ _Acquires_lock_(m_pLock)
+ explicit CAutoLock(CRITICAL_SECTION *pLock):
+ m_pLock(pLock)
+ {
+ EnterCriticalSection(m_pLock);
+ }
+
+ _Releases_lock_(m_pLock)
+ ~CAutoLock()
+ {
+ LeaveCriticalSection(m_pLock);
+ }
+};
+
+class MediaBufferLock
+{
+public:
+ MediaBufferLock(_In_ IMFMediaBuffer *pBuffer):
+ m_bLocked(false)
+ {
+ m_spBuffer = pBuffer;
+ }
+
+ HRESULT LockBuffer(
+ _Outptr_result_bytebuffer_to_(*pcbMaxLength, *pcbCurrentLength) BYTE **ppbBuffer,
+ _Out_opt_ DWORD *pcbMaxLength,
+ _Out_opt_ DWORD *pcbCurrentLength)
+ {
+ if(!m_spBuffer)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr = m_spBuffer->Lock(ppbBuffer, pcbMaxLength, pcbCurrentLength);
+ if(FAILED(hr))
+ {
+ return hr;
+ }
+ m_bLocked = true;
+ return S_OK;
+ }
+
+ ~MediaBufferLock()
+ {
+ if(m_spBuffer && m_bLocked)
+ {
+ //Unlock fails only if we did not lock it first
+ (void) m_spBuffer->Unlock();
+ }
+ }
+
+private:
+ ComPtr<IMFMediaBuffer> m_spBuffer;
+ bool m_bLocked;
+};
diff --git a/AVStream/avscamera/mft0/dllmain.cpp b/AVStream/avscamera/mft0/dllmain.cpp
new file mode 100644
index 00000000..5eda92dc
--- /dev/null
+++ b/AVStream/avscamera/mft0/dllmain.cpp
@@ -0,0 +1,191 @@
+/**************************************************************************
+
+ A/V Stream Camera Sample
+
+ Copyright (c) 2014, Microsoft Corporation.
+
+ File:
+
+ dllmain.cpp
+
+ Abstract:
+
+ DLL and COM initialization.
+
+ History:
+
+ created 5/15/2014
+
+**************************************************************************/
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+
+#include "stdafx.h"
+#include "Mft0.h"
+#include "Mft0clsid.h"
+#include "Mft0Impl.h"
+#include <wrl\module.h>
+
+using namespace Microsoft::WRL;
+
+// Module Ref count
+volatile ULONG g_cRefModule = 0;
+
+// Handle to the DLL's module
+HMODULE g_hModule = NULL;
+
+ULONG DllAddRef()
+{
+ return InterlockedIncrement(&g_cRefModule);
+}
+
+ULONG DllRelease()
+{
+ return InterlockedDecrement(&g_cRefModule);
+}
+
+class CClassFactory : public IClassFactory
+{
+public:
+ static HRESULT CreateInstance(
+ REFCLSID clsid,
+ REFIID riid,
+ _COM_Outptr_ void **ppv
+ )
+ {
+ *ppv = NULL;
+
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ if(IsEqualGUID(clsid, CLSID_AvsCamMft0))
+ {
+ IClassFactory *pClassFactory = new (std::nothrow) CClassFactory();
+ if(!pClassFactory)
+ {
+ return E_OUTOFMEMORY;
+ }
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ return hr;
+ }
+
+ //IUnknown methods
+ IFACEMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
+ {
+ HRESULT hr = S_OK;
+
+ if(ppvObject == NULL)
+ {
+ return E_POINTER;
+ }
+
+ if(riid == IID_IUnknown)
+ {
+ *ppvObject = (IUnknown*)this;
+ }
+ else if(riid == IID_IClassFactory)
+ {
+ *ppvObject = (IClassFactory*)this;
+ }
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return hr;
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&m_cRef);
+ if(cRef == 0)
+ {
+ delete this;
+ }
+ return cRef;
+ }
+
+ //IClassFactory Methods
+ IFACEMETHODIMP CreateInstance(_In_ IUnknown *punkOuter, _In_ REFIID riid, _Outptr_ void **ppv)
+ {
+ return punkOuter ? CLASS_E_NOAGGREGATION : MFT0CreateInstance(riid, ppv);
+ }
+
+ IFACEMETHODIMP LockServer(BOOL fLock)
+ {
+ if(fLock)
+ {
+ DllAddRef();
+ }
+ else
+ {
+ DllRelease();
+ }
+ return S_OK;
+ }
+
+private:
+ CClassFactory() :
+ m_cRef(1)
+ {
+ DllAddRef();
+ }
+
+ ~CClassFactory()
+ {
+ DllRelease();
+ }
+
+ long m_cRef;
+};
+
+
+
+
+STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void *)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ g_hModule = (HMODULE)hinst;
+ DisableThreadLibraryCalls(hinst);
+ }
+ return TRUE;
+}
+
+//
+// DllCanUnloadNow
+//
+/////////////////////////////////////////////////////////////////////////
+STDAPI DllCanUnloadNow()
+{
+ return (g_cRefModule == 0) ? S_OK : S_FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////
+//
+// DllGetClassObject
+//
+/////////////////////////////////////////////////////////////////////////
+_Check_return_
+STDAPI DllGetClassObject(
+ _In_ REFCLSID rclsid,
+ _In_ REFIID riid,
+ _Outptr_ LPVOID FAR *ppv
+)
+{
+ return CClassFactory::CreateInstance(rclsid, riid, ppv);
+}
diff --git a/AVStream/avscamera/mft0/sources.dep b/AVStream/avscamera/mft0/sources.dep
new file mode 100644
index 00000000..ad8b9029
--- /dev/null
+++ b/AVStream/avscamera/mft0/sources.dep
@@ -0,0 +1,21 @@
+PUBLIC_PASS0_CONSUMES= \
+ avcore\published\idl|PASS0 \
+ avcore\published\media|PASS0 \
+ avcore\published\mf\publish|PASS0 \
+ base\appmodel\search\search\search\structuredquery\interfaces\publish|PASS0 \
+ base\published2|PASS0 \
+ com\published\idlole\publish|PASS0 \
+ enduser\sql\xml\msxml3\publish|PASS0 \
+ inetcore\published\sdk\inc|PASS0 \
+ minkernel\published\base|PASS0 \
+ onecore\avcore\published\media|PASS0 \
+ onecore\base\published2|PASS0 \
+ onecore\com\published\idlole\publish|PASS0 \
+ onecore\enduser\sql\xml\msxml3\publish|PASS0 \
+ onecore\inetcore\published\sdk\inc|PASS0 \
+ onecore\shell\propsys\inc0|PASS0 \
+ onecore\shell\published\inc\inc0|PASS0 \
+ onecoreuap\base\appmodel\search\search\search\structuredquery\interfaces\publish|PASS0 \
+ shell\propsys\inc0|PASS0 \
+ shell\published\inc\inc0|PASS0 \
+
diff --git a/AVStream/avscamera/mft0/stdafx.h b/AVStream/avscamera/mft0/stdafx.h
new file mode 100644
index 00000000..ef768c0b
--- /dev/null
+++ b/AVStream/avscamera/mft0/stdafx.h
@@ -0,0 +1,32 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#ifndef STRICT
+#define STRICT
+#endif
+
+#include "targetver.h"
+
+#include <wrl.h>
+
+#include <initguid.h>
+#include <mfapi.h>
+#include <mfidl.h>
+#include <mferror.h>
+#include <ks.h>
+#include <ksmedia.h>
+#include <inspectable.h>
+#include <vector>
+
+
+using namespace Microsoft::WRL; \ No newline at end of file
diff --git a/AVStream/avscamera/mft0/stdafxsrc.cpp b/AVStream/avscamera/mft0/stdafxsrc.cpp
new file mode 100644
index 00000000..1577c4e3
--- /dev/null
+++ b/AVStream/avscamera/mft0/stdafxsrc.cpp
@@ -0,0 +1 @@
+#include "stdafx.h" \ No newline at end of file
diff --git a/AVStream/avscamera/mft0/targetver.h b/AVStream/avscamera/mft0/targetver.h
new file mode 100644
index 00000000..fc349fa5
--- /dev/null
+++ b/AVStream/avscamera/mft0/targetver.h
@@ -0,0 +1,15 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>
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);
+};
diff --git a/AVStream/samplemft0/Package/package.vcxproj b/AVStream/samplemft0/Package/package.vcxproj
new file mode 100644
index 00000000..b1b4d0a1
--- /dev/null
+++ b/AVStream/samplemft0/Package/package.vcxproj
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.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="PropertySheets">
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Utility</ConfigurationType>
+ <DriverType>Package</DriverType>
+ <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+ <Configuration>Debug</Configuration>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{07664D04-E5E5-4249-8382-4D97E3E5557D}</ProjectGuid>
+ <SampleGuid>{A92ABE31-4404-4415-B763-7186FA03850E}</SampleGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ <EnableDeployment>False</EnableDeployment>
+ <ImportToStore>False</ImportToStore>
+ <InstallMode>None</InstallMode>
+ <HardwareIdString />
+ <CommandLine />
+ <ScriptPath />
+ <DeployFiles />
+ <ScriptName />
+ <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery>
+ <EnableVerifier>False</EnableVerifier>
+ <AllDrivers>False</AllDrivers>
+ <VerifyProjectOutput>True</VerifyProjectOutput>
+ <VerifyDrivers />
+ <VerifyFlags>133563</VerifyFlags>
+ <PackageDir>$(OutDir)Package</PackageDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <!--Inf Include="DriverInf.inv" /-->
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\SampleMft0.vcxproj">
+ <Project>{DCF923F6-7164-4A0E-9486-B8A140234CCA}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/samplemft0/Package/package.vcxproj.Filters b/AVStream/samplemft0/Package/package.vcxproj.Filters
new file mode 100644
index 00000000..8850da4d
--- /dev/null
+++ b/AVStream/samplemft0/Package/package.vcxproj.Filters
@@ -0,0 +1,21 @@
+<?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>{D7556E25-EFF2-4B16-A8D7-3E0BEEEC9FEB}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{C45D5482-9F0A-49E8-9BB8-05C43E65E305}</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</Extensions>
+ <UniqueIdentifier>{D323AE8C-19AA-4F7B-8142-0599701C44A8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{83B1A36B-57FD-4945-A280-98586DD2E63A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+</Project> \ No newline at end of file