summaryrefslogtreecommitdiff
path: root/AVStream/avshws
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 19:47:04 -0700
committerWei Mao <[email protected]>2017-03-17 19:47:04 -0700
commit1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch)
treebf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream/avshws
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'AVStream/avshws')
-rw-r--r--AVStream/avshws/README.md76
-rw-r--r--AVStream/avshws/avshws.h323
-rw-r--r--AVStream/avshws/avshws.inf173
-rw-r--r--AVStream/avshws/avshws.rc22
-rw-r--r--AVStream/avshws/avshws.sln28
-rw-r--r--AVStream/avshws/avshws.vcxproj200
-rw-r--r--AVStream/avshws/avshws.vcxproj.Filters46
-rw-r--r--AVStream/avshws/capture.cpp1704
-rw-r--r--AVStream/avshws/capture.h313
-rw-r--r--AVStream/avshws/device.cpp875
-rw-r--r--AVStream/avshws/device.h294
-rw-r--r--AVStream/avshws/filter.cpp203
-rw-r--r--AVStream/avshws/filter.h88
-rw-r--r--AVStream/avshws/hwsim.cpp868
-rw-r--r--AVStream/avshws/hwsim.h290
-rw-r--r--AVStream/avshws/image.cpp605
-rw-r--r--AVStream/avshws/image.h478
-rw-r--r--AVStream/avshws/purecall.c50
18 files changed, 6636 insertions, 0 deletions
diff --git a/AVStream/avshws/README.md b/AVStream/avshws/README.md
new file mode 100644
index 00000000..73d4a389
--- /dev/null
+++ b/AVStream/avshws/README.md
@@ -0,0 +1,76 @@
+AVStream simulated hardware sample driver (Avshws)
+==================================================
+
+The AVStream simulated hardware sample driver (Avshws) provides a pin-centric [AVStream](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554240) capture driver for a simulated piece of hardware. This streaming media driver performs video captures at 320 x 240 pixels in either RGB24 or YUV422 format using direct memory access (DMA) into capture buffers. The purpose of the sample is to demonstrate how to write a pin-centric AVStream minidriver. The sample also shows how to implement DMA by using the related functionality provided by the AVStream class driver.
+
+This sample features enhanced parameter validation and overflow detection.
+
+Provision a target computer
+---------------------------
+
+After you've installed the sample on your host computer, run Visual Studio, and from the **File** menu, select **Open**, then **Project/Solution...**, navigate to the directory where you've copied the Avshws sample, then to the C++ folder, and select **avshws.vcxproj** (the VC++ Project).
+
+In the **Solution Explorer** pane in Visual Studio, at the top is **Solution 'avshws'**. Right-click this and select **Configuration Manager**. Follow the instructions in [Building a Driver with the WDK](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644) to set the platform, operating system, and debug configuration you want to use, and to build the sample. This sample project will automatically sign the driver package.
+
+Provision your target computer using instructions in, for example, [Preparing a Computer for Provisioning](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265573). Ensure that in the **Network and Sharing Center** control panel your target computer has **Network Discovery** and **File and Printer Sharing** enabled.
+
+Deploy the driver to the target computer
+----------------------------------------
+
+Now you can deploy the Avshws driver that you've just built to the target computer, using guidance in [Deploying a Driver to a Test Computer](http://msdn.microsoft.com/en-us/library/windows/hardware/hh454834). Specifically, find the package file under the **Package** folder in the Avshws solution. Right-click **package** and select **Properties**. Under Configuration Properties, click **Driver install** and then **Deployment**. Here you must click the check box for **Enable deployment**, and then click the button to the right of **\<Configure Computer...\>**. In the next dialog you enter the **Target Computer Name** and can let the host computer automatically provision the target computer and set up debugger options.
+
+Finally, in Visual Studio, from the **Build** menu select **Deploy Solution** to deploy the sample to the target computer. On the target computer, you can see the deployed package in the **%Systemdrive%\\drivertest\\drivers** folder.
+
+Install the driver
+------------------
+
+On the target computer, open Device Manager, and follow these steps:
+
+1. In the **Action** menu, click **Add Legacy Hardware**, and the **Add Hardware Wizard** appears. Click **Next** and then **Next** again.
+2. In the **Add Hardware** window, select **Show All Devices**.
+3. In the **Manufacturer** list in the left pane, click **Microsoft**.
+4. You should see the **AVStream Simulated Hardware Sample** in the **Model** pane on the right. Click this and then click **Next**.
+5. Click **Next** again to install the driver, and then click **Finish** to exit the wizard.
+
+The sample driver now appears in the Device Manager console tree under **Sound, video and game controllers**. The Avshws INF file will be on the system drive at, for example, **...windows\\System32\\DriverStore\\FileRepository\\**.
+
+Sample code hierarchy
+---------------------
+
+[**DriverEntry**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff558717) in Device.cpp is the initial point of entry into the driver. This routine passes control to AVStream by calling the [**KsInitializeDriver**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff562683) function. In this call, the minidriver passes the device descriptor, an AVStream structure that recursively defines the AVStream object hierarchy for a driver. This is common behavior for an AVStream minidriver.
+
+At device start time, a simulated piece of capture hardware is created (the **CHardwareSimulation** class), and a DMA adapter is acquired from the operating system and is registered with AVStream by calling the [**KsDeviceRegisterAdapterObject**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff561687) function. This call is required for a sample that performs DMA access directly into the capture buffers, instead of using DMA access to write to a common buffer. The driver creates the [KS Filter](http://msdn.microsoft.com/en-us/library/windows/hardware/ff567644) for this device dynamically by calling the [**KsCreateFilterFactory**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff561650) function.
+
+Filter.cpp is where the sample lays out the [**KSPIN\_DESCRIPTOR\_EX**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff563534) structure for the single video pin. In addition, a [**KSFILTER\_DISPATCH**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff562554) structure and a [**KSFILTER\_DESCRIPTOR**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff562553) structure are provided in this source file. The filter dispatch provides only a create dispatch, a routine that is included in Filter.cpp. The process dispatch is provided on the pin because this is a pin-centric sample.
+
+Capture.cpp contains source for the video capture pin on the capture filter. This is where the [**KSPIN\_DISPATCH**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff563535) structure for the unique pin is provided. This dispatch structure specifies a *Process* callback routine, also defined in this source file. This routine is where stream pointer manipulation and cloning occurs.
+
+The process callback is one of two routines of interest in Capture.cpp that demonstrate how to perform DMA transfers with AVStream functionality. The other is the **CCapturePin::CompleteMappings** method. These two methods show how to use the queue, obtain clone pointers, use scatter/gather lists, and perform other DMA-related tasks.
+
+For more information, see the comments in all .cpp files.
+
+Run the sample
+--------------
+
+Follow these steps to see how the sample driver functions:
+
+1. After installation has completed, access the driver through the Graphedt tool. Graphedt.exe is available in the *tools* directory of the WDK.
+2. Before running GraphEdit, use the regsvr32 utility to register the proppage.dll DLL and to enable GraphEdit to display property pages for some of the built-in Microsoft DirectShow filters. Open an elevated command window with Administrator privileges, and navigate to the WDK or SDK *tools* directory that contains proppage.dll.
+3. On the command line, type regsvr32 proppage.dll. If the registration succeeds, you'll get a message, "DllRegisterServer in proppage.dll succeeded." Click OK.
+4. In the Graphedt tool, click the **Graph** menu and click **Insert Filters**. The sample appears under "WDM Streaming Capture Devices" as "avshws Source."
+5. Click **Insert Filter**. The sample appears in the graph as a single filter labeled, "avshws Source." There is one output pin, which is the video capture pin. This pin emits video in YUY2 format.
+6. Attach this filter to either a DirectShow Video Renderer or to the VMR default video renderer. Then click **Play**.
+
+The output that is produced by the sample is a 320 x 240 pixel image of standard EIA-189-A color bars. In the middle of the image near the bottom, a clock appears over the image. This clock displays the elapsed time since the graph was introduced into the run state following the last stop. The clock display format is MINUTES:SECONDS.HUNDREDTHS.
+
+In the upper-left corner of the image, a counter counts the number of frames that have been dropped since the graph was introduced into the run state after the last stop.
+
+Code tour
+---------
+
+### File Manifest
+
+File | Description
+-----|------------
+Avshws.h | Main header file for the sample
+Avshws.inf | Sample installation file
diff --git a/AVStream/avshws/avshws.h b/AVStream/avshws/avshws.h
new file mode 100644
index 00000000..70f220f3
--- /dev/null
+++ b/AVStream/avshws/avshws.h
@@ -0,0 +1,323 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ avshws.h
+
+ Abstract:
+
+ AVStream Simulated Hardware Sample header file. This is the
+ main header.
+
+ History:
+
+ created 3/12/2001
+
+**************************************************************************/
+
+/*************************************************
+
+ Standard Includes
+
+*************************************************/
+
+#ifndef _avshws_h_
+#define _avshws_h_
+
+extern "C" {
+#include <wdm.h>
+}
+
+#include <windef.h>
+#include <stdio.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <windef.h>
+#define NOBITMAP
+#include <mmreg.h>
+#undef NOBITMAP
+#include <unknown.h>
+#include <ks.h>
+#include <ksmedia.h>
+#include <kcom.h>
+
+/*************************************************
+
+ Misc Definitions
+
+*************************************************/
+#pragma warning (disable : 4100 4127 4131 4189 4701 4706)
+#define STR_MODULENAME "avshws: "
+#define DEBUGLVL_VERBOSE 2
+#define DEBUGLVL_TERSE 1
+#define DEBUGLVL_ERROR 0
+
+const 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
+
+#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')
+//
+// CAPTURE_PIN_DATA_RANGE_COUNT:
+//
+// The number of ranges supported on the capture pin.
+//
+#define CAPTURE_PIN_DATA_RANGE_COUNT 2
+
+//
+// CAPTURE_FILTER_PIN_COUNT:
+//
+// The number of pins on the capture filter.
+//
+#define CAPTURE_FILTER_PIN_COUNT 1
+
+//
+// CAPTURE_FILTER_CATEGORIES_COUNT:
+//
+// The number of categories for the capture filter.
+//
+#define CAPTURE_FILTER_CATEGORIES_COUNT 3
+
+#define AVSHWS_POOLTAG 'hSVA'
+
+/*************************************************
+
+ Externed information
+
+*************************************************/
+//
+// filter.cpp externs:
+//
+extern
+const
+KSFILTER_DISPATCH
+CaptureFilterDispatch;
+
+extern
+const
+KSFILTER_DESCRIPTOR
+CaptureFilterDescriptor;
+
+extern
+const
+KSPIN_DESCRIPTOR_EX
+CaptureFilterPinDescriptors [CAPTURE_FILTER_PIN_COUNT];
+
+extern
+const
+GUID
+CaptureFilterCategories [CAPTURE_FILTER_CATEGORIES_COUNT];
+
+//
+// capture.cpp externs:
+//
+extern
+const
+KSALLOCATOR_FRAMING_EX
+CapturePinAllocatorFraming;
+
+extern
+const
+KSPIN_DISPATCH
+CapturePinDispatch;
+
+extern
+const
+PKSDATARANGE
+CapturePinDataRanges [CAPTURE_PIN_DATA_RANGE_COUNT];
+
+/*************************************************
+
+ Enums / Typedefs
+
+*************************************************/
+
+typedef enum _HARDWARE_STATE {
+
+ HardwareStopped = 0,
+ HardwarePaused,
+ HardwareRunning
+
+} HARDWARE_STATE, *PHARDWARE_STATE;
+
+/*************************************************
+
+ Class Definitions
+
+*************************************************/
+
+//
+// IHardwareSink:
+//
+// This interface is used by the hardware simulation to fake interrupt
+// service routines. The Interrupt method is called at DPC as a fake
+// interrupt.
+//
+class IHardwareSink {
+
+public:
+
+ virtual
+ void
+ Interrupt (
+ ) = 0;
+
+};
+
+//
+// ICaptureSink:
+//
+// This is a capture sink interface. The device level calls back the
+// CompleteMappings method passing the number of completed mappings for
+// the capture pin. This method is called during the device DPC.
+//
+class ICaptureSink {
+
+public:
+
+ virtual
+ void
+ CompleteMappings (
+ IN ULONG NumMappings
+ ) = 0;
+
+};
+
+
+
+/*************************************************
+
+ Global Functions
+
+*************************************************/
+
+/*++
+
+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);
+ }
+}
+
+/*************************************************
+
+ Internal Includes
+
+*************************************************/
+
+#include "image.h"
+#include "hwsim.h"
+#include "device.h"
+#include "filter.h"
+#include "capture.h"
+#include <uuids.h>
+#endif //_avshws_h_ \ No newline at end of file
diff --git a/AVStream/avshws/avshws.inf b/AVStream/avshws/avshws.inf
new file mode 100644
index 00000000..8360d50f
--- /dev/null
+++ b/AVStream/avshws/avshws.inf
@@ -0,0 +1,173 @@
+;/*++
+;
+;Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; 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.
+;
+;Module Name:
+;
+; AVSHWS.INF
+;
+;Abstract:
+;
+;
+;AVStream pin centric sample mini driver (AVSHWS.sys) installation file.
+;Supports x86, amd64, arm and arm64 platforms
+;
+;--*/
+
+[Version]
+signature="$WINDOWS NT$"
+Class=Media
+ClassGUID={4d36e96c-e325-11ce-bfc1-08002be10318}
+Provider=%ProviderName%
+Catalogfile=avshws.cat
+DriverVer=08/31/2006,6.0.5600.0
+
+[SourceDisksNames]
+1000=%cdname%,,,
+
+[SourceDisksFiles]
+avshws.sys=1000
+
+[DestinationDirs]
+DefaultDestDir=12
+avshws.CopyFiles=12
+
+[avshws.CopyFiles]
+avshws.sys
+
+[Manufacturer]
+%ManufacturerName%=Standard,NTx86,NTamd64,ntarm,ntarm64
+
+[Standard.NTx86]
+%avshws.DeviceDesc%=avshws.NTx86,AVSHWS
+
+[Standard.NTamd64]
+%avshws.DeviceDesc%=avshws.NTamd64,AVSHWS
+
+[Standard.NTarm]
+%avshws.DeviceDesc%=avshws.NTarm,AVSHWS
+
+[Standard.NTarm64]
+%avshws.DeviceDesc%=avshws.NTarm64,AVSHWS
+
+;---------------------------------------------------------------
+; x 86 D D I n s t a l l
+;---------------------------------------------------------------
+
+[avshws.NTx86]
+Include=ks.inf, KSCAPTUR.inf
+Needs=KS.Registration,KSCAPTUR.Registration.NT
+CopyFiles=avshws.CopyFiles
+
+;---------------------------------------------------------------
+; A M D 64 D D I n s t a l l
+;---------------------------------------------------------------
+
+[avshws.NTamd64]
+Include=ks.inf,KSCAPTUR.inf
+Needs=KS.Registration,KSCAPTUR.Registration.NT
+CopyFiles=avshws.CopyFiles
+
+;---------------------------------------------------------------
+; A R M D D I n s t a l l
+;---------------------------------------------------------------
+
+[avshws.NTarm]
+Include=ks.inf,KSCAPTUR.inf
+Needs=KS.Registration,KSCAPTUR.Registration.NT
+CopyFiles=avshws.CopyFiles
+
+;---------------------------------------------------------------
+; A R M 64 D D I n s t a l l
+;---------------------------------------------------------------
+
+[avshws.NTarm64]
+Include=ks.inf,KSCAPTUR.inf
+Needs=KS.Registration,KSCAPTUR.Registration.NT
+CopyFiles=avshws.CopyFiles
+
+;---------------------------------------------------------------
+; I n t e r f a c e s
+;---------------------------------------------------------------
+
+[avshws.NTx86.Interfaces]
+AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0
+
+[avshws.NTamd64.Interfaces]
+AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0
+
+[avshws.NTarm.Interfaces]
+AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0
+
+[avshws.NTarm64.Interfaces]
+AddInterface=%KSCATEGORY_CAPTURE%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO%,"GLOBAL",CaptureInterface.NT,0
+AddInterface=%KSCATEGORY_VIDEO_CAMERA%,"GLOBAL",CaptureInterface.NT,0
+
+[CaptureInterface.NT]
+AddReg=avshws.Reader.AddReg
+
+;---------------------------------------------------------------
+; A d d R e g
+;---------------------------------------------------------------
+
+[avshws.Reader.AddReg]
+HKR,,CLSID,,%Proxy.CLSID%
+HKR,,FriendlyName,,%avshws.Reader.FriendlyName%
+
+;---------------------------------------------------------------
+; S e r v i c e s
+;---------------------------------------------------------------
+
+[avshws.NTx86.Services]
+AddService=avshws, 0x00000002, avshws.ServiceInstall
+
+[avshws.NTamd64.Services]
+AddService=avshws, 0x00000002, avshws.ServiceInstall
+
+[avshws.NTarm.Services]
+AddService=avshws, 0x00000002, avshws.ServiceInstall
+
+[avshws.NTarm64.Services]
+AddService=avshws, 0x00000002, avshws.ServiceInstall
+
+[avshws.ServiceInstall]
+DisplayName=%avshws.DeviceDesc%
+ServiceType=%SERVICE_KERNEL_DRIVER%
+StartType=%SERVICE_DEMAND_START%
+ErrorControl=%SERVICE_ERROR_NORMAL%
+ServiceBinary=%12%\avshws.sys
+
+;---------------------------------------------------------------
+; S t r i n g s
+;---------------------------------------------------------------
+
+[Strings]
+; non-localizable
+Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}"
+KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
+KSCATEGORY_VIDEO="{6994AD05-93EF-11D0-A3CC-00A0C9223196}"
+KSCATEGORY_VIDEO_CAMERA="{E5323777-F976-4f5b-9B55-B94699C46E44}"
+
+SERVICE_KERNEL_DRIVER=1
+SERVICE_DEMAND_START=3
+SERVICE_ERROR_NORMAL=1
+REG_DWORD=0x00010001
+
+;localizable
+ProviderName="TODO-Set-Provider"
+ManufacturerName="TODO-Set-Manufacturer"
+avshws.DeviceDesc="AVStream Simulated Hardware Sample"
+avshws.Reader.FriendlyName="avshws Source"
+cdname="AVSHWS Installation Disk" \ No newline at end of file
diff --git a/AVStream/avshws/avshws.rc b/AVStream/avshws/avshws.rc
new file mode 100644
index 00000000..3e8a3e6a
--- /dev/null
+++ b/AVStream/avshws/avshws.rc
@@ -0,0 +1,22 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+//
+// Copyright (C) Microsoft Corporation, 1999 - 1999
+//
+// File: captst.rc
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "AVStream Simulated Hardware Sample"
+#define VER_INTERNALNAME_STR "avshws.sys"
+#define VER_ORIGINALFILENAME_STR "avshws.sys"
+
+#include "common.ver"
+
diff --git a/AVStream/avshws/avshws.sln b/AVStream/avshws/avshws.sln
new file mode 100644
index 00000000..b8aebb75
--- /dev/null
+++ b/AVStream/avshws/avshws.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avshws", "avshws.vcxproj", "{77FA53EC-3637-411C-B708-C8EED64543A4}"
+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
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Debug|Win32.ActiveCfg = Debug|Win32
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Debug|Win32.Build.0 = Debug|Win32
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Release|Win32.ActiveCfg = Release|Win32
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Release|Win32.Build.0 = Release|Win32
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Debug|x64.ActiveCfg = Debug|x64
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Debug|x64.Build.0 = Debug|x64
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Release|x64.ActiveCfg = Release|x64
+ {77FA53EC-3637-411C-B708-C8EED64543A4}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/AVStream/avshws/avshws.vcxproj b/AVStream/avshws/avshws.vcxproj
new file mode 100644
index 00000000..b3909878
--- /dev/null
+++ b/AVStream/avshws/avshws.vcxproj
@@ -0,0 +1,200 @@
+<?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>{77FA53EC-3637-411C-B708-C8EED64543A4}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{555099C6-5354-4C50-A241-A09CDD72299D}</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>avshws</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>avshws</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>avshws</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>avshws</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib</AdditionalDependencies>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib</AdditionalDependencies>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib</AdditionalDependencies>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ks.lib</AdditionalDependencies>
+ <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE</AdditionalOptions>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE;DEBUG_LEVEL=DEBUGLVL_BLAB;_WIN2K_COMPAT_SLIST_USAGE;_NO_SYS_GUID_OPERATOR_EQ_</PreprocessorDefinitions>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="capture.cpp" />
+ <ClCompile Include="device.cpp" />
+ <ClCompile Include="filter.cpp" />
+ <ClCompile Include="hwsim.cpp" />
+ <ClCompile Include="image.cpp" />
+ <ClCompile Include="purecall.c" />
+ <ResourceCompile Include="avshws.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/avshws/avshws.vcxproj.Filters b/AVStream/avshws/avshws.vcxproj.Filters
new file mode 100644
index 00000000..4e32a73f
--- /dev/null
+++ b/AVStream/avshws/avshws.vcxproj.Filters
@@ -0,0 +1,46 @@
+<?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>{124F9628-D980-4A5F-BCB3-C73BBF85F98E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{53840AE7-57A9-46F8-8D16-B52859B4C272}</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>{1156F063-8F29-4654-8347-0519BE2E0418}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{77087805-4D7E-4591-B71F-4ABA9576DD2A}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <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="image.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="purecall.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="avshws.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/avshws/capture.cpp b/AVStream/avshws/capture.cpp
new file mode 100644
index 00000000..f23ec0e7
--- /dev/null
+++ b/AVStream/avshws/capture.cpp
@@ -0,0 +1,1704 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ capture.cpp
+
+ Abstract:
+
+ This file contains source for the video capture pin on the capture
+ filter. The capture 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
+
+**************************************************************************/
+
+#include "avshws.h"
+#include <ksmedia.h>
+#include "ntintsafe.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+#define DMAX_X 320
+#define DMAX_Y 240
+#define D_X 320
+#define D_Y 240
+
+CCapturePin::
+CCapturePin (
+ IN PKSPIN Pin
+ ) :
+ m_Pin (Pin)
+ ,m_PresentationTime (0)
+
+/*++
+
+Routine Description:
+
+ Construct a new capture pin.
+
+Arguments:
+
+ Pin -
+ The AVStream pin object corresponding to the capture pin
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ PKSDEVICE Device = KsPinGetDevice (Pin);
+
+ //
+ // Set up our device pointer. This gives us access to "hardware I/O"
+ // during the capture routines.
+ //
+ m_Device = reinterpret_cast <CCaptureDevice *> (Device -> Context);
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCapturePin::
+DispatchCreate (
+ IN PKSPIN Pin,
+ IN PIRP Irp
+ )
+
+/*++
+
+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
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CCapturePin *CapPin = new (NonPagedPoolNx, 'niPC') CCapturePin (Pin);
+
+ if (!CapPin) {
+ //
+ // Return failure if we couldn't create the pin.
+ //
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } 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 (
+ Pin -> Bag,
+ reinterpret_cast <PVOID> (CapPin),
+ reinterpret_cast <PFNKSFREE> (CCapturePin::Cleanup)
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ delete CapPin;
+ } else {
+ Pin -> Context = reinterpret_cast <PVOID> (CapPin);
+ }
+
+ }
+
+ //
+ // 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.
+ //
+ PKS_VIDEOINFOHEADER VideoInfoHeader = NULL;
+
+ if (NT_SUCCESS (Status)) {
+
+ VideoInfoHeader = CapPin -> CaptureVideoInfoHeader ();
+ if (!VideoInfoHeader) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (NT_SUCCESS(Status)) {
+ //
+ // We need to edit the descriptor to ensure we don't mess up any other
+ // pins using the descriptor or touch read-only memory.
+ //
+ Status = KsEdit (
+ Pin,
+ &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 (
+ Pin,
+ &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> (
+ Pin -> Descriptor -> AllocatorFraming
+ );
+
+ Framing -> FramingItem [0].Frames = 2;
+
+ //
+ // The physical and optimal ranges must be biSizeImage. We only
+ // support one frame size, precisely the size of each capture
+ // image.
+ //
+ Framing -> FramingItem [0].PhysicalRange.MinFrameSize =
+ Framing -> FramingItem [0].PhysicalRange.MaxFrameSize =
+ Framing -> FramingItem [0].FramingRange.Range.MinFrameSize =
+ Framing -> FramingItem [0].FramingRange.Range.MaxFrameSize =
+ VideoInfoHeader -> bmiHeader.biSizeImage;
+
+ Framing -> FramingItem [0].PhysicalRange.Stepping =
+ Framing -> FramingItem [0].FramingRange.Range.Stepping =
+ 0;
+
+ }
+
+ }
+ }
+
+ if (NT_SUCCESS (Status)) {
+ //
+ // Adjust the stream header size. The video packets have extended
+ // header info (KS_FRAME_INFO).
+ //
+ Pin -> StreamHeaderSize = sizeof (KSSTREAM_HEADER) +
+ sizeof (KS_FRAME_INFO);
+
+ }
+ return Status;
+}
+
+/*************************************************/
+
+
+PKS_VIDEOINFOHEADER
+CCapturePin::
+CaptureVideoInfoHeader (
+ )
+
+/*++
+
+Routine Description:
+
+ Capture the video info header out of the connection format. This
+ is what we use to base synthesized images off.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ The captured video info header or NULL if there is insufficient
+ memory.
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ 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)
+ return NULL;
+
+ //
+ // Bag the newly allocated header space. This will get cleaned up
+ // automatically when the pin closes.
+ //
+ NTSTATUS Status =
+ KsAddItemToObjectBag (
+ m_Pin -> Bag,
+ reinterpret_cast <PVOID> (m_VideoInfoHeader),
+ NULL
+ );
+
+ if (!NT_SUCCESS (Status)) {
+
+ ExFreePool (m_VideoInfoHeader);
+ return NULL;
+
+ } else {
+
+ //
+ // Copy the connection format video info header into the newly
+ // allocated "captured" video info header.
+ //
+ RtlCopyMemory (
+ m_VideoInfoHeader,
+ ConnectionHeader,
+ KS_SIZE_VIDEOHEADER (ConnectionHeader)
+ );
+
+ }
+
+ return m_VideoInfoHeader;
+
+}
+
+
+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();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PKSSTREAM_POINTER Leading;
+
+ _DbgPrintF(DEBUGLVL_VERBOSE, ("Process"));
+
+ 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);
+ Status = STATUS_SUCCESS;
+ }
+
+ //
+ // 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_Device -> ProgramScatterGatherMappings (
+ 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 in a completion DPC.
+ //
+ if (!NT_SUCCESS (Status) || Status == STATUS_PENDING) {
+ m_PendIo = TRUE;
+ }
+
+ _DbgPrintF(DEBUGLVL_VERBOSE, ("Leaving Process..."));
+ return Status;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCapturePin::
+CleanupReferences (
+ )
+
+/*++
+
+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::
+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;
+
+ switch (ToState) {
+
+ case KSSTATE_STOP:
+
+ //
+ // First, stop the hardware if we actually did anything to it.
+ //
+ if (m_HardwareState != HardwareStopped) {
+ Status = m_Device -> Stop ();
+ NT_ASSERT (NT_SUCCESS (Status));
+
+ m_HardwareState = HardwareStopped;
+ }
+
+ //
+ // 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 = CleanupReferences ();
+
+ //
+ // 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_Device -> ReleaseHardwareResources (
+ );
+
+ 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.
+ //
+ if (FromState == KSSTATE_STOP) {
+ Status = m_Device -> AcquireHardwareResources (
+ this,
+ m_VideoInfoHeader
+ );
+
+ 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;
+ }
+
+ } else {
+ //
+ // Standard transport pins will always receive transitions in
+ // +/- 1 manner. This means we'll always see a PAUSE->ACQUIRE
+ // transition before stopping the pin.
+ //
+ // The below is done because on DirectX 8.0, when the pin gets
+ // a message to stop, the queue is inaccessible. The reset
+ // which comes on every stop happens after this (at which time
+ // the queue is inaccessible also). So, for compatibility with
+ // DirectX 8.0, I am stopping the "fake" hardware at this
+ // point and cleaning up all references we have on frames. See
+ // the comments above regarding the CleanupReferences call.
+ //
+ // If this sample were targeting XP only, the below code would
+ // not be here. Again, I only do this so the sample does not
+ // hang when it is stopped running on a configuration such as
+ // Win2K + DX8.
+ //
+ if (m_HardwareState != HardwareStopped) {
+ Status = m_Device -> Stop ();
+ NT_ASSERT (NT_SUCCESS (Status));
+
+ m_HardwareState = HardwareStopped;
+ }
+
+ Status = CleanupReferences ();
+ }
+
+ 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_Device -> Pause (TRUE);
+
+ if (NT_SUCCESS (Status)) {
+ m_HardwareState = HardwarePaused;
+ }
+
+ }
+ 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 (m_HardwareState == HardwarePaused) {
+ Status = m_Device -> Pause (FALSE);
+ } else {
+ Status = m_Device -> Start ();
+ }
+
+ if (NT_SUCCESS (Status)) {
+ m_HardwareState = HardwareRunning;
+ }
+
+ break;
+
+ }
+
+ 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 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 VideoInfoSpecifier =
+ {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_VIDEOINFO)};
+
+ NT_ASSERT(Filter);
+ NT_ASSERT(Irp);
+ NT_ASSERT(PinInstance);
+ NT_ASSERT(CallerDataRange);
+ NT_ASSERT(DescriptorDataRange);
+ NT_ASSERT(DataSize);
+
+ ULONG DataFormatSize;
+
+ //
+ // Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
+ //
+ if (IsEqualGUID(CallerDataRange->Specifier, VideoInfoSpecifier) &&
+ CallerDataRange -> FormatSize >= sizeof (KS_DATARANGE_VIDEO)) {
+
+ PKS_DATARANGE_VIDEO callerDataRange =
+ reinterpret_cast <PKS_DATARANGE_VIDEO> (CallerDataRange);
+
+ PKS_DATARANGE_VIDEO descriptorDataRange =
+ reinterpret_cast <PKS_DATARANGE_VIDEO> (DescriptorDataRange);
+
+ PKS_DATAFORMAT_VIDEOINFOHEADER FormatVideoInfoHeader;
+
+ //
+ // Check that the other fields match
+ //
+ if ((callerDataRange->bFixedSizeSamples !=
+ descriptorDataRange->bFixedSizeSamples) ||
+ (callerDataRange->bTemporalCompression !=
+ descriptorDataRange->bTemporalCompression) ||
+ (callerDataRange->StreamDescriptionFlags !=
+ descriptorDataRange->StreamDescriptionFlags) ||
+ (callerDataRange->MemoryAllocationFlags !=
+ descriptorDataRange->MemoryAllocationFlags) ||
+ (RtlCompareMemory (&callerDataRange->ConfigCaps,
+ &descriptorDataRange->ConfigCaps,
+ sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) !=
+ sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)))
+ {
+ return STATUS_NO_MATCH;
+ }
+
+ //
+ // KS_SIZE_VIDEOHEADER() below is relying on bmiHeader.biSize from
+ // the caller's data range. This **MUST** be validated; the
+ // extended bmiHeader size (biSize) must not extend past the end
+ // of the range buffer. Possible arithmetic overflow is also
+ // checked for.
+ //
+ {
+ ULONG VideoHeaderSize = KS_SIZE_VIDEOHEADER (
+ &callerDataRange->VideoInfoHeader
+ );
+
+ ULONG DataRangeSize =
+ FIELD_OFFSET (KS_DATARANGE_VIDEO, VideoInfoHeader) +
+ VideoHeaderSize;
+
+ //
+ // Check that biSize does not extend past the buffer. The
+ // first two checks are for arithmetic overflow on the
+ // operations to compute the alleged size. (On unsigned
+ // math, a+b < a iff an arithmetic overflow occurred).
+ //
+ if (
+ VideoHeaderSize < callerDataRange->
+ VideoInfoHeader.bmiHeader.biSize ||
+ DataRangeSize < VideoHeaderSize ||
+ DataRangeSize > callerDataRange -> DataRange.FormatSize
+ ) {
+
+ return STATUS_INVALID_PARAMETER;
+
+ }
+
+ }
+
+ DataFormatSize =
+ sizeof (KSDATAFORMAT) +
+ KS_SIZE_VIDEOHEADER (&callerDataRange->VideoInfoHeader);
+
+
+ //
+ // If the passed buffer size is 0, it indicates that this is a size
+ // only query. Return the size of the intersecting data format and
+ // pass back STATUS_BUFFER_OVERFLOW.
+ //
+ if (BufferSize == 0) {
+
+ *DataSize = DataFormatSize;
+ return STATUS_BUFFER_OVERFLOW;
+
+ }
+
+ //
+ // Verify that the provided structure is large enough to
+ // accept the result.
+ //
+ if (BufferSize < DataFormatSize)
+ {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Copy over the KSDATAFORMAT, followed by the actual VideoInfoHeader
+ //
+ *DataSize = DataFormatSize;
+
+ FormatVideoInfoHeader = PKS_DATAFORMAT_VIDEOINFOHEADER( Data );
+
+ //
+ // Copy over the KSDATAFORMAT. This is precisely the same as the
+ // KSDATARANGE (it's just the GUIDs, etc... not the format information
+ // following any data format.
+ //
+ RtlCopyMemory (
+ &FormatVideoInfoHeader->DataFormat,
+ DescriptorDataRange,
+ sizeof (KSDATAFORMAT));
+
+ FormatVideoInfoHeader->DataFormat.FormatSize = DataFormatSize;
+
+ //
+ // Copy over the callers requested VIDEOINFOHEADER
+ //
+
+ RtlCopyMemory (
+ &FormatVideoInfoHeader->VideoInfoHeader,
+ &callerDataRange->VideoInfoHeader,
+ KS_SIZE_VIDEOHEADER (&callerDataRange->VideoInfoHeader)
+ );
+
+ //
+ // Calculate biSizeImage for this request, and put the result in both
+ // the biSizeImage field of the bmiHeader AND in the SampleSize field
+ // of the DataFormat.
+ //
+ // Note that for compressed sizes, this calculation will probably not
+ // be just width * height * bitdepth
+ //
+ FormatVideoInfoHeader->VideoInfoHeader.bmiHeader.biSizeImage =
+ FormatVideoInfoHeader->DataFormat.SampleSize =
+ KS_DIBSIZE (FormatVideoInfoHeader->VideoInfoHeader.bmiHeader);
+
+ //
+ // REVIEW - Perform other validation such as cropping and scaling checks
+ //
+
+ return STATUS_SUCCESS;
+
+ } // End of VIDEOINFOHEADER specifier
+
+ return STATUS_NO_MATCH;
+}
+
+/*************************************************/
+
+BOOL
+MultiplyCheckOverflow (
+ ULONG a,
+ ULONG b,
+ ULONG *pab
+ )
+
+/*++
+
+Routine Description:
+
+ Perform a 32 bit unsigned multiplication and check for arithmetic overflow.
+
+Arguments:
+
+ a -
+ First operand
+
+ b -
+ Second operand
+
+ pab -
+ Result
+
+Return Value:
+
+ TRUE -
+ no overflow
+
+ FALSE -
+ overflow occurred
+
+--*/
+
+{
+ PAGED_CODE();
+
+ *pab = a * b;
+ if ((a == 0) || (((*pab) / a) == b)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCapturePin::
+DispatchSetFormat (
+ IN PKSPIN Pin,
+ IN PKSDATAFORMAT OldFormat OPTIONAL,
+ IN PKSMULTIPLE_ITEM OldAttributeList OPTIONAL,
+ IN const KSDATARANGE *DataRange,
+ IN const KSATTRIBUTE_LIST *AttributeRange OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This is the set data format dispatch for the capture pin. It is called
+ in two circumstances.
+
+ 1: before Pin's creation dispatch has been made to verify that
+ Pin -> ConnectionFormat is an acceptable format for the range
+ DataRange. In this case OldFormat is NULL.
+
+ 2: after Pin's creation dispatch has been made and an initial format
+ selected in order to change the format for the pin. In this case,
+ OldFormat will not be NULL.
+
+ Validate that the format is acceptible and perform the actions necessary
+ to change format if appropriate.
+
+Arguments:
+
+ Pin -
+ The pin this format is being set on. The format itself will be in
+ Pin -> ConnectionFormat.
+
+ OldFormat -
+ The previous format used on this pin. If this is NULL, it is an
+ indication that Pin's creation dispatch has not yet been made and
+ that this is a request to validate the initial format and not to
+ change formats.
+
+ OldAttributeList -
+ The old attribute list for the prior format
+
+ DataRange -
+ A range out of our list of data ranges which was determined to be
+ at least a partial match for Pin -> ConnectionFormat. If the format
+ there is unacceptable for the range, STATUS_NO_MATCH should be
+ returned.
+
+ AttributeRange -
+ The attribute range
+
+Return Value:
+
+ Success / Failure
+
+ STATUS_SUCCESS -
+ The format is acceptable / the format has been changed
+
+ STATUS_NO_MATCH -
+ The format is not-acceptable / the format has not been changed
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_NO_MATCH;
+
+ const GUID VideoInfoSpecifier =
+ {STATICGUIDOF(KSDATAFORMAT_SPECIFIER_VIDEOINFO)};
+
+ CCapturePin *CapPin = NULL;
+
+ //
+ // Find the pin, if it exists yet. OldFormat will be an indication of
+ // this. If we're changing formats, OldFormat will be non-NULL.
+ //
+ // You cannot use Pin -> Context to make the determination. AVStream
+ // preinitializes this to the filter's context.
+ //
+ if (OldFormat) {
+ CapPin = reinterpret_cast <CCapturePin *> (Pin -> Context);
+ }
+
+ if (IsEqualGUID (Pin -> ConnectionFormat -> Specifier,
+ VideoInfoSpecifier) &&
+ Pin -> ConnectionFormat -> FormatSize >=
+ sizeof (KS_DATAFORMAT_VIDEOINFOHEADER)) {
+
+ PKS_DATAFORMAT_VIDEOINFOHEADER ConnectionFormat =
+ reinterpret_cast <PKS_DATAFORMAT_VIDEOINFOHEADER>
+ (Pin -> ConnectionFormat);
+
+ //
+ // DataRange comes out of OUR data range list. I know the range
+ // is valid as such.
+ //
+ const KS_DATARANGE_VIDEO *VIRange =
+ reinterpret_cast <const KS_DATARANGE_VIDEO *>
+ (DataRange);
+
+ //
+ // Check that bmiHeader.biSize is valid since we use it later.
+ //
+ ULONG VideoHeaderSize = KS_SIZE_VIDEOHEADER (
+ &ConnectionFormat -> VideoInfoHeader
+ );
+
+ ULONG DataFormatSize = FIELD_OFFSET (
+ KS_DATAFORMAT_VIDEOINFOHEADER, VideoInfoHeader
+ ) + VideoHeaderSize;
+
+ if (
+ VideoHeaderSize < ConnectionFormat->
+ VideoInfoHeader.bmiHeader.biSize ||
+ DataFormatSize < VideoHeaderSize ||
+ DataFormatSize > ConnectionFormat -> DataFormat.FormatSize
+ ) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // Check that the format is a match for the selected range.
+ //
+ else if (
+ (ConnectionFormat -> VideoInfoHeader.bmiHeader.biWidth !=
+ VIRange -> VideoInfoHeader.bmiHeader.biWidth) ||
+
+ (ConnectionFormat -> VideoInfoHeader.bmiHeader.biHeight !=
+ VIRange -> VideoInfoHeader.bmiHeader.biHeight) ||
+
+ (ConnectionFormat -> VideoInfoHeader.bmiHeader.biCompression !=
+ VIRange -> VideoInfoHeader.bmiHeader.biCompression)
+
+ ) {
+
+ Status = STATUS_NO_MATCH;
+
+ } else {
+
+ //
+ // Compute the minimum size of our buffers to validate against.
+ // The image synthesis routines synthesize |biHeight| rows of
+ // biWidth pixels in either RGB24 or UYVY. In order to ensure
+ // safe synthesis into the buffer, we need to know how large an
+ // image this will produce.
+ //
+ // I do this explicitly because of the method that the data is
+ // synthesized. A variation of this may or may not be necessary
+ // depending on the mechanism the driver in question fills the
+ // capture buffers. The important thing is to ensure that they
+ // aren't overrun during capture.
+ //
+ ULONG ImageSize;
+
+ if (!MultiplyCheckOverflow (
+ (ULONG)ConnectionFormat->VideoInfoHeader.bmiHeader.biWidth,
+ (ULONG)abs (ConnectionFormat->
+ VideoInfoHeader.bmiHeader.biHeight),
+ &ImageSize
+ )) {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // We only support KS_BI_RGB (24) and KS_BI_YUV422 (16), so
+ // this is valid for those formats.
+ //
+ else if (!MultiplyCheckOverflow (
+ ImageSize,
+ (ULONG)(ConnectionFormat->
+ VideoInfoHeader.bmiHeader.biBitCount / 8),
+ &ImageSize
+ )) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ }
+
+ //
+ // Valid for the formats we use. Otherwise, this would be
+ // checked later.
+ //
+ else if (ConnectionFormat->VideoInfoHeader.bmiHeader.biSizeImage <
+ ImageSize) {
+
+ Status = STATUS_INVALID_PARAMETER;
+
+ } else {
+
+ //
+ // We can accept the format.
+ //
+ Status = STATUS_SUCCESS;
+
+ //
+ // OldFormat is an indication that this is a format change.
+ // Since I do not implement the
+ // KSPROPERTY_CONNECTION_PROPOSEDATAFORMAT, by default, I do
+ // not handle dynamic format changes.
+ //
+ // If something changes while we're in the stop state, we're
+ // fine to handle it since we haven't "configured the hardware"
+ // yet.
+ //
+ if (OldFormat) {
+ //
+ // 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 -> CaptureVideoInfoHeader ()) {
+ 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;
+ }
+ }
+
+ }
+
+ }
+
+ }
+ return Status;
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+void
+CCapturePin::
+CompleteMappings (
+ IN ULONG NumMappings
+ )
+
+/*++
+
+Routine Description:
+
+ Called to notify the pin that a given number of scatter / gather
+ mappings have completed. Let the buffers go if possible.
+ We're called at DPC.
+
+Arguments:
+
+ NumMappings -
+ The number of mappings that have completed.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ ULONG MappingsRemaining = NumMappings;
+
+ //
+ // Walk through the clones list and delete clones whose time has come.
+ // The list is guaranteed to be kept in the order they were cloned.
+ //
+ PKSSTREAM_POINTER Clone = KsPinGetFirstCloneStreamPointer (m_Pin);
+
+ while (MappingsRemaining && Clone) {
+
+ PKSSTREAM_POINTER NextClone = KsStreamPointerGetNextClone (Clone);
+
+#if defined(_X86_)
+ //
+ // Count up the number of bytes we've completed and mark this
+ // in the Stream Header. In mapped queues
+ // (KSPIN_FLAG_GENERATE_MAPPINGS), this is the responsibility of
+ // the minidriver. In non-mapped queues, AVStream performs this.
+ //
+ ULONG MappingsToCount =
+ (MappingsRemaining > Clone -> OffsetOut.Remaining) ?
+ Clone -> OffsetOut.Remaining :
+ MappingsRemaining;
+
+ //
+ // Update DataUsed according to the mappings.
+ //
+ for (ULONG CurMapping = 0; CurMapping < MappingsToCount; CurMapping++) {
+ Clone -> StreamHeader -> DataUsed +=
+ Clone -> OffsetOut.Mappings [CurMapping].ByteCount;
+ }
+#endif
+
+ //
+ // 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 !defined(_X86_)
+ if (Clone -> StreamHeader -> DataUsed >= Clone -> OffsetOut.Remaining) {
+#else
+ if (MappingsRemaining >= Clone -> OffsetOut.Remaining) {
+#endif
+ Clone -> StreamHeader -> Duration =
+ m_VideoInfoHeader -> AvgTimePerFrame;
+
+ Clone -> StreamHeader -> PresentationTime.Numerator =
+ Clone -> StreamHeader -> PresentationTime.Denominator = 1;
+
+ //
+ // If a clock has been assigned, timestamp the packets with the
+ // time shown on the clock.
+ //
+ if (m_Clock) {
+
+ LONGLONG ClockTime = m_Clock -> GetTime ();
+
+ Clone -> StreamHeader -> PresentationTime.Time = ClockTime;
+
+ Clone -> StreamHeader -> OptionsFlags =
+ KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
+ KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
+
+ } else {
+ //
+ // If there is no clock, don't time stamp the packets.
+ //
+ Clone -> StreamHeader -> PresentationTime.Time = 0;
+
+ }
+
+ //
+ // Increment the frame number. This is the total count of frames which
+ // have attempted capture.
+ //
+ 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;
+ }
+
+
+ //
+ // If all of the mappings in this clone have been completed,
+ // delete the clone. We've already updated DataUsed above.
+ //
+
+#if !defined(_X86_)
+ MappingsRemaining--;
+#else
+ MappingsRemaining -= Clone -> OffsetOut.Remaining;
+#endif
+ 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.
+ //
+#if !defined(_X86_)
+ (void)KsStreamPointerAdvanceOffsets (
+ Clone,
+ 0,
+ Clone -> StreamHeader -> DataUsed,
+ FALSE
+ );
+
+#else
+ (void)KsStreamPointerAdvanceOffsets (
+ Clone,
+ 0,
+ MappingsRemaining,
+ FALSE
+ );
+
+#endif
+ MappingsRemaining = 0;
+
+ }
+
+ //
+ // Go to the next clone.
+ //
+ Clone = NextClone;
+
+ }
+
+ //
+ // 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) {
+ m_PendIo = TRUE;
+ KsPinAttemptProcessing (m_Pin, TRUE);
+ }
+
+}
+
+/**************************************************************************
+
+ DISPATCH AND DESCRIPTOR LAYOUT
+
+**************************************************************************/
+
+//
+// FormatRGB24Bpp_Capture:
+//
+// This is the data range description of the RGB24 capture format we support.
+//
+const
+KS_DATARANGE_VIDEO
+FormatRGB24Bpp_Capture = {
+
+ //
+ // KSDATARANGE
+ //
+ {
+ sizeof (KS_DATARANGE_VIDEO), // FormatSize
+ 0, // Flags
+ D_X * D_Y * 3, // SampleSize
+ 0, // Reserved
+
+ STATICGUIDOF (KSDATAFORMAT_TYPE_VIDEO), // aka. MEDIATYPE_Video
+ 0xe436eb7d, 0x524f, 0x11ce, 0x9f, 0x53, 0x00, 0x20,
+ 0xaf, 0x0b, 0xa7, 0x70, // 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
+ D_X,D_Y, // InputSize, (the inherent size of the incoming signal
+ // with every digitized pixel unique)
+ D_X,D_Y, // MinCroppingSize, smallest rcSrc cropping rect allowed
+ D_X,D_Y, // MaxCroppingSize, largest rcSrc cropping rect allowed
+ 8, // CropGranularityX, granularity of cropping size
+ 1, // CropGranularityY
+ 8, // CropAlignX, alignment of cropping rect
+ 1, // CropAlignY;
+ D_X, D_Y, // MinOutputSize, smallest bitmap stream can produce
+ D_X, D_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
+ 333667, // MinFrameInterval, 100 nS units
+ 640000000, // MaxFrameInterval, 100 nS units
+ 8 * 3 * 30 * D_X * D_Y, // MinBitsPerSecond;
+ 8 * 3 * 30 * D_X * D_Y // MaxBitsPerSecond;
+ },
+
+ //
+ // KS_VIDEOINFOHEADER (default format)
+ //
+ {
+ 0,0,0,0, // RECT rcSource;
+ 0,0,0,0, // RECT rcTarget;
+ D_X * D_Y * 3 * 8 * 30, // DWORD dwBitRate;
+ 0L, // DWORD dwBitErrorRate;
+ 333667, // REFERENCE_TIME AvgTimePerFrame;
+ sizeof (KS_BITMAPINFOHEADER), // DWORD biSize;
+ D_X, // LONG biWidth;
+ D_Y, // LONG biHeight;
+ 1, // WORD biPlanes;
+ 24, // WORD biBitCount;
+ KS_BI_RGB, // DWORD biCompression;
+ D_X * D_Y * 3, // DWORD biSizeImage;
+ 0, // LONG biXPelsPerMeter;
+ 0, // LONG biYPelsPerMeter;
+ 0, // DWORD biClrUsed;
+ 0 // DWORD biClrImportant;
+ }
+};
+
+//
+// FormatYUY2_Capture:
+//
+// This is the data range description of the YUY2 format we support.
+//
+const
+KS_DATARANGE_VIDEO
+FormatYUY2_Capture = {
+
+ //
+ // KSDATARANGE
+ //
+ {
+ sizeof (KS_DATARANGE_VIDEO), // FormatSize
+ 0, // Flags
+ DMAX_X * DMAX_Y * 2, // SampleSize
+ 0, // Reserved
+ STATICGUIDOF (KSDATAFORMAT_TYPE_VIDEO), // aka. MEDIATYPE_Video
+ 0x32595559, 0x0000, 0x0010, 0x80, 0x00,
+ 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71, //aka. MEDIASUBTYPE_YUY2,
+ 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
+ DMAX_X, DMAX_Y, // InputSize, (the inherent size of the incoming signal
+ // with every digitized pixel unique)
+ D_X,D_Y, // MinCroppingSize, smallest rcSrc cropping rect allowed
+ DMAX_X, DMAX_Y, // MaxCroppingSize, largest rcSrc cropping rect allowed
+ 8, // CropGranularityX, granularity of cropping size
+ 1, // CropGranularityY
+ 8, // CropAlignX, alignment of cropping rect
+ 1, // CropAlignY;
+ D_X, D_Y, // MinOutputSize, smallest bitmap stream can produce
+ DMAX_X, DMAX_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
+ 333667, // MinFrameInterval, 100 nS units
+ 640000000, // MaxFrameInterval, 100 nS units
+ 8 * 2 * 30 * D_X * D_Y, // MinBitsPerSecond;
+ 8 * 2 * 30 * DMAX_X * DMAX_Y, // MaxBitsPerSecond;
+ },
+
+ //
+ // KS_VIDEOINFOHEADER (default format)
+ //
+ {
+ 0, 0, 0, 0, // RECT rcSource;
+ 0, 0, 0, 0, // RECT rcTarget;
+ DMAX_X * DMAX_Y * 2 * 8 * 30, // DWORD dwBitRate;
+ 0L, // DWORD dwBitErrorRate;
+ 333667, // REFERENCE_TIME AvgTimePerFrame;
+ sizeof (KS_BITMAPINFOHEADER), // DWORD biSize;
+ DMAX_X, // LONG biWidth;
+ DMAX_Y, // LONG biHeight;
+ 1, // WORD biPlanes;
+ 16, // WORD biBitCount;
+ FOURCC_YUY2, // DWORD biCompression;
+ DMAX_X * DMAX_Y * 2, // DWORD biSizeImage;
+ 0, // LONG biXPelsPerMeter;
+ 0, // LONG biYPelsPerMeter;
+ 0, // DWORD biClrUsed;
+ 0 // DWORD biClrImportant;
+ }
+};
+
+//
+// CapturePinDispatch:
+//
+// This is the dispatch table for the capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc...
+//
+const
+KSPIN_DISPATCH
+CapturePinDispatch = {
+ CCapturePin::DispatchCreate, // Pin Create
+ NULL, // Pin Close
+ CCapturePin::DispatchProcess, // Pin Process
+ NULL, // Pin Reset
+ CCapturePin::DispatchSetFormat, // Pin Set Data Format
+ CCapturePin::DispatchSetState, // Pin Set Device State
+ NULL, // Pin Connect
+ NULL, // Pin Disconnect
+ NULL, // Clock Dispatch
+ NULL // Allocator Dispatch
+};
+
+//
+// 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 (
+ CapturePinAllocatorFraming,
+ STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED),
+ KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
+ KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY,
+ 2,
+ 0,
+ 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE
+ );
+
+//
+// CapturePinDataRanges:
+//
+// This is the list of data ranges supported on the capture pin. We support
+// two: one RGB24, and one YUY2.
+//
+const
+PKSDATARANGE
+CapturePinDataRanges [CAPTURE_PIN_DATA_RANGE_COUNT] = {
+ (PKSDATARANGE) &FormatYUY2_Capture,
+ (PKSDATARANGE) &FormatRGB24Bpp_Capture
+ };
diff --git a/AVStream/avshws/capture.h b/AVStream/avshws/capture.h
new file mode 100644
index 00000000..502e01e3
--- /dev/null
+++ b/AVStream/avshws/capture.h
@@ -0,0 +1,313 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ capture.h
+
+ Abstract:
+
+ This file contains header for the video capture pin on the capture
+ filter. The capture 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
+
+**************************************************************************/
+#include <initguid.h>
+//
+// 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 ICaptureSink {
+
+private:
+
+ //
+ // The AVStream pin we're associated with.
+ //
+ PKSPIN m_Pin;
+
+ //
+ // Pointer to the internal device object for our capture device.
+ // We access the "fake" hardware through this object.
+ //
+ CCaptureDevice *m_Device;
+
+ //
+ // The state we've put the hardware into. This allows us to keep track
+ // of whether to do things like unpausing or restarting.
+ //
+ HARDWARE_STATE m_HardwareState;
+
+ //
+ // The clock we've been assigned. As with other capture filters, we do
+ // not expose a clock. If one has been assigned, we will use it to
+ // time stamp packets (plus a reasonable delta to work the capture stream
+ // in a preview graph).
+ //
+ PIKSREFERENCECLOCK m_Clock;
+
+ //
+ // The captured video info header. The settings for "fake" hardware will be
+ // programmed via this video info header.
+ //
+ PKS_VIDEOINFOHEADER m_VideoInfoHeader;
+
+ //
+ // 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;
+
+ //
+ // An indication of whether or not we pended I/O for some reason. If this
+ // is set, the DPC will resume I/O when any mappings are completed.
+ //
+ BOOLEAN m_PendIo;
+
+ //
+ // An indication of whether or not this pin has acquired the necessary
+ // hardware resources to operate. When the pin reaches KSSTATE_ACQUIRE,
+ // we attempt to acquire the hardware. This flag will be set based on
+ // our success / failure.
+ //
+ BOOLEAN m_AcquiredResources;
+
+ //
+ // Presentation time for the sample
+ //
+ LONGLONG m_PresentationTime;
+
+ LONGLONG m_FrameNumber;
+ LONGLONG m_DroppedFrames;
+
+ //
+ // CleanupReferences():
+ //
+ // Clean up any references we hold on frames in the queue. This is called
+ // when we abruptly stop the fake hardware.
+ //
+ NTSTATUS
+ CleanupReferences (
+ );
+
+ //
+ // SetState():
+ //
+ // This is the state transition handler for the capture pin. It attempts
+ // to acquire resources for the capture pin (or releasing them if
+ // necessary) and starts and stops the hardware as required.
+ //
+ NTSTATUS
+ SetState (
+ IN KSSTATE ToState,
+ IN KSSTATE FromState
+ );
+
+ //
+ // Process():
+ //
+ // This is the processing dispatch for the capture pin. It handles
+ // programming the scatter / gather tables for the hardware as buffers
+ // become available. This processing routine is designed for a direct
+ // into the capture buffers kind of DMA as opposed to common-buffer
+ // and copy strategies.
+ //
+ NTSTATUS
+ Process (
+ );
+ //
+ // CaptureVideoInfoHeader():
+ //
+ // This routine stashes the video info header set on the pin connection
+ // in the CCapturePin object. This is used to base hardware settings.
+ //
+ PKS_VIDEOINFOHEADER
+ CaptureVideoInfoHeader (
+ );
+
+ //
+ // Cleanup():
+ //
+ // This is the free callback from the bagged item (CCapturePin). If we
+ // do not provide a callback when we bag the CCapturePin, ExFreePool
+ // would be called. This is not desirable for C++ constructed objects.
+ // We merely delete the object here.
+ //
+ static
+ void
+ Cleanup (
+ IN CCapturePin *Pin
+ )
+ {
+ delete Pin;
+ }
+
+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.
+ //
+ ~CCapturePin (
+ )
+ {
+ }
+
+ //
+ // ICaptureSink::CompleteMappings()
+ //
+ // This is the capture sink notification mechanism for mapping completion.
+ // When the device DPC detects that a given number of mappings have been
+ // completed by the fake hardware, it signals the capture sink of this
+ // through this method.
+ //
+ virtual
+ void
+ CompleteMappings (
+ IN ULONG NumMappings
+ );
+
+ /*************************************************
+
+ Dispatch Routines
+
+ *************************************************/
+
+ //
+ // DispatchCreate():
+ //
+ // This is the creation dispatch for the capture pin. It creates
+ // the CCapturePin object and associates it with the AVStream object
+ // bagging it in the process.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ IN PKSPIN Pin,
+ IN PIRP Irp
+ );
+
+ //
+ // DispatchSetState():
+ //
+ // This is the set device state dispatch for the pin. The routine bridges
+ // to SetState() in the context of the CCapturePin.
+ //
+ static
+ NTSTATUS
+ DispatchSetState (
+ IN PKSPIN Pin,
+ IN KSSTATE ToState,
+ IN KSSTATE FromState
+ )
+ {
+ return
+ (reinterpret_cast <CCapturePin *> (Pin -> Context)) ->
+ SetState (ToState, FromState);
+ }
+
+ //
+ // DispatchSetFormat():
+ //
+ // This is the set data format dispatch for the pin. This will be called
+ // BEFORE pin creation to validate that a data format selected is a match
+ // for the range pulled out of our range list. It will also be called
+ // for format changes.
+ //
+ // If OldFormat is NULL, this is an indication that it's the initial
+ // call and not a format change. Even fixed format pins get this call
+ // once.
+ //
+ static
+ NTSTATUS
+ DispatchSetFormat (
+ IN PKSPIN Pin,
+ IN PKSDATAFORMAT OldFormat OPTIONAL,
+ IN PKSMULTIPLE_ITEM OldAttributeList OPTIONAL,
+ IN const KSDATARANGE *DataRange,
+ IN const KSATTRIBUTE_LIST *AttributeRange OPTIONAL
+ );
+
+ //
+ // DispatchProcess():
+ //
+ // This is the processing dispatch for the capture pin. The routine
+ // bridges to Process() in the context of the CCapturePin.
+ //
+ static
+ NTSTATUS
+ DispatchProcess (
+ IN PKSPIN Pin
+ )
+ {
+ return
+ (reinterpret_cast <CCapturePin *> (Pin -> Context)) ->
+ Process ();
+
+ }
+
+ //
+ // IntersectHandler():
+ //
+ // This is the data intersection handler for the capture pin. This
+ // determines an optimal format in the intersection of two ranges,
+ // one local and one possibly foreign. If there is no compatible format,
+ // STATUS_NO_MATCH is returned.
+ //
+ static
+ NTSTATUS
+ IntersectHandler (
+ IN PKSFILTER Filter,
+ IN PIRP Irp,
+ IN PKSP_PIN PinInstance,
+ IN PKSDATARANGE CallerDataRange,
+ IN PKSDATARANGE DescriptorDataRange,
+ IN ULONG BufferSize,
+ OUT PVOID Data OPTIONAL,
+ OUT PULONG DataSize
+ );
+
+}; \ No newline at end of file
diff --git a/AVStream/avshws/device.cpp b/AVStream/avshws/device.cpp
new file mode 100644
index 00000000..75b06cd5
--- /dev/null
+++ b/AVStream/avshws/device.cpp
@@ -0,0 +1,875 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ device.cpp
+
+ Abstract:
+
+ This file contains the device level implementation of the AVStream
+ hardware sample. Note that this is not the "fake" hardware. The
+ "fake" hardware is in hwsim.cpp.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+#include "avshws.h"
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+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();
+
+ NTSTATUS Status;
+
+ CCaptureDevice *CapDevice = new (NonPagedPoolNx, 'veDC') CCaptureDevice (Device);
+
+ if (!CapDevice) {
+ //
+ // Return failure if we couldn't create the pin.
+ //
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ //
+ // 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.
+ //
+ KsAcquireDevice (Device);
+ Status = KsAddItemToObjectBag (
+ Device -> Bag,
+ reinterpret_cast <PVOID> (CapDevice),
+ reinterpret_cast <PFNKSFREE> (CCaptureDevice::Cleanup)
+ );
+ KsReleaseDevice (Device);
+
+ if (!NT_SUCCESS (Status)) {
+ delete CapDevice;
+ } else {
+ Device -> Context = reinterpret_cast <PVOID> (CapDevice);
+ }
+
+ }
+
+ 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 virtual 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;
+
+ if (!m_Device -> Started) {
+ // Create the Filter for the device
+ KsAcquireDevice(m_Device);
+ Status = KsCreateFilterFactory( m_Device->FunctionalDeviceObject,
+ &CaptureFilterDescriptor,
+ L"GLOBAL",
+ NULL,
+ KSCREATE_ITEM_FREEONSTOP,
+ NULL,
+ NULL,
+ NULL );
+ KsReleaseDevice(m_Device);
+
+ }
+ //
+ // 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.
+ //
+ if (NT_SUCCESS(Status) && (!m_Device -> Started)) {
+
+ m_HardwareSimulation = new (NonPagedPoolNx, 'miSH') CHardwareSimulation (this);
+ if (!m_HardwareSimulation) {
+ //
+ // If we couldn't create the hardware simulation, fail.
+ //
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+ Status = KsAddItemToObjectBag (
+ m_Device -> Bag,
+ reinterpret_cast <PVOID> (m_HardwareSimulation),
+ reinterpret_cast <PFNKSFREE> (CHardwareSimulation::Cleanup)
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ delete m_HardwareSimulation;
+ }
+ }
+#if defined(_X86_)
+ //
+ // DMA operations illustrated in this sample are applicable only for 32bit platform.
+ //
+ INTERFACE_TYPE InterfaceBuffer;
+ ULONG InterfaceLength;
+ DEVICE_DESCRIPTION DeviceDescription;
+
+ if (NT_SUCCESS (Status)) {
+ //
+ // Set up DMA...
+ //
+ // Ordinarilly, we'd be using InterfaceBuffer or
+ // InterfaceTypeUndefined if !NT_SUCCESS (IfStatus) as the
+ // InterfaceType below; however, for the purposes of this sample,
+ // we lie and say we're on the PCI Bus. Otherwise, we're using map
+ // registers on x86 32 bit physical to 32 bit logical and this isn't
+ // what I want to show in this sample.
+ //
+ //
+ // NTSTATUS IfStatus =
+
+ IoGetDeviceProperty (
+ m_Device -> PhysicalDeviceObject,
+ DevicePropertyLegacyBusType,
+ sizeof (INTERFACE_TYPE),
+ &InterfaceBuffer,
+ &InterfaceLength
+ );
+
+ //
+ // Initialize our fake device description. We claim to be a
+ // bus-mastering 32-bit scatter/gather capable piece of hardware.
+ //
+ DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ DeviceDescription.DmaChannel = ((ULONG) ~0);
+ DeviceDescription.InterfaceType = PCIBus;
+ DeviceDescription.DmaWidth = Width32Bits;
+ DeviceDescription.DmaSpeed = Compatible;
+ DeviceDescription.ScatterGather = TRUE;
+ DeviceDescription.Master = TRUE;
+ DeviceDescription.Dma32BitAddresses = TRUE;
+ DeviceDescription.AutoInitialize = FALSE;
+ DeviceDescription.MaximumLength = (ULONG) -1;
+
+ //
+ // Get a DMA adapter object from the system.
+ //
+ m_DmaAdapterObject = IoGetDmaAdapter (
+ m_Device -> PhysicalDeviceObject,
+ &DeviceDescription,
+ &m_NumberOfMapRegisters
+ );
+
+ if (!m_DmaAdapterObject) {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+ //
+ // Initialize our DMA adapter object with AVStream. This is
+ // **ONLY** necessary **IF** you are doing DMA directly into
+ // capture buffers as this sample does. For this,
+ // KSPIN_FLAG_GENERATE_MAPPINGS must be specified on a queue.
+ //
+
+ //
+ // The (1 << 20) below is the maximum size of a single s/g mapping
+ // that this hardware can handle. Note that I have pulled this
+ // number out of thin air for the "fake" hardware.
+ //
+ KsDeviceRegisterAdapterObject (
+ m_Device,
+ m_DmaAdapterObject,
+ (1 << 20),
+ sizeof (KSMAPPING)
+ );
+
+ }
+#endif
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+void
+CCaptureDevice::
+PnpStop (
+ )
+
+/*++
+
+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
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ if (m_DmaAdapterObject) {
+ //
+ // Return the DMA adapter back to the system.
+ //
+ m_DmaAdapterObject -> DmaOperations ->
+ PutDmaAdapter (m_DmaAdapterObject);
+
+ m_DmaAdapterObject = NULL;
+ }
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCaptureDevice::
+AcquireHardwareResources (
+ IN ICaptureSink *CaptureSink,
+ IN PKS_VIDEOINFOHEADER VideoInfoHeader
+ )
+
+/*++
+
+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:
+
+ CaptureSink -
+ The capture sink attempting to acquire resources. When scatter /
+ gather mappings are completed, the capture sink 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.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ //
+ // If we're the first pin to go into acquire (remember we can have
+ // a filter in another graph going simultaneously), grab the resources.
+ //
+ if (InterlockedCompareExchange (
+ &m_PinsWithResources,
+ 1,
+ 0) == 0) {
+
+ m_VideoInfoHeader = VideoInfoHeader;
+
+ //
+ // If there's an old hardware simulation sitting around for some
+ // reason, blow it away.
+ //
+ if (m_ImageSynth) {
+ delete m_ImageSynth;
+ m_ImageSynth = NULL;
+ }
+
+ //
+ // Create the necessary type of image synthesizer.
+ //
+ if (m_VideoInfoHeader -> bmiHeader.biBitCount == 24 &&
+ m_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_ImageSynth = new (NonPagedPoolNx, 'RysI')
+ CRGB24Synthesizer (
+ m_VideoInfoHeader -> bmiHeader.biHeight >= 0
+ );
+
+ } else
+ if (m_VideoInfoHeader -> bmiHeader.biBitCount == 16 &&
+ (m_VideoInfoHeader -> bmiHeader.biCompression == FOURCC_YUY2)) {
+
+ //
+ // If we're UYVY, create the YUV synth.
+ //
+ m_ImageSynth = new(NonPagedPoolNx, 'YysI') CYUVSynthesizer;
+
+ }
+ else
+ //
+ // We don't synthesize anything but RGB 24 and UYVY.
+ //
+ Status = STATUS_INVALID_PARAMETER;
+
+ if (NT_SUCCESS (Status) && !m_ImageSynth) {
+
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+ //
+ // If everything has succeeded thus far, set the capture sink.
+ //
+ m_CaptureSink = CaptureSink;
+
+ } else {
+ //
+ // If anything failed in here, we release the resources we've
+ // acquired.
+ //
+ ReleaseHardwareResources ();
+ }
+
+ } else {
+
+ //
+ // TODO: Better status code?
+ //
+ Status = STATUS_SHARING_VIOLATION;
+
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+void
+CCaptureDevice::
+ReleaseHardwareResources (
+ )
+
+/*++
+
+Routine Description:
+
+ Release hardware resources. This should only be called by
+ an object which has acquired them.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ //
+ // Blow away the image synth.
+ //
+ if (m_ImageSynth) {
+ delete m_ImageSynth;
+ m_ImageSynth = NULL;
+
+ }
+
+ m_VideoInfoHeader = NULL;
+ m_CaptureSink = NULL;
+
+ //
+ // Release our "lock" on hardware resources. This will allow another
+ // pin (perhaps in another graph) to acquire them.
+ //
+ InterlockedExchange (
+ &m_PinsWithResources,
+ 0
+ );
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCaptureDevice::
+Start (
+ )
+
+/*++
+
+Routine Description:
+
+ Start the capture device based on the video info header we were told
+ about when resources were acquired.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ m_LastMappingsCompleted = 0;
+ m_InterruptTime = 0;
+
+ return
+ m_HardwareSimulation -> Start (
+ m_ImageSynth,
+ m_VideoInfoHeader -> AvgTimePerFrame,
+ m_VideoInfoHeader -> bmiHeader.biWidth,
+ ABS (m_VideoInfoHeader -> bmiHeader.biHeight),
+ m_VideoInfoHeader -> bmiHeader.biSizeImage
+ );
+
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCaptureDevice::
+Pause (
+ 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:
+
+ 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 -> Pause (
+ Pausing
+ );
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCaptureDevice::
+Stop (
+ )
+
+/*++
+
+Routine Description:
+
+ Stop the capture device.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ return
+ m_HardwareSimulation -> Stop ();
+
+}
+
+/*************************************************/
+
+
+ULONG
+CCaptureDevice::
+ProgramScatterGatherMappings (
+ IN PKSSTREAM_POINTER Clone,
+ IN PUCHAR *Buffer,
+ IN PKSMAPPING Mappings,
+ IN ULONG MappingsCount
+ )
+
+/*++
+
+Routine Description:
+
+ Program the scatter / gather mappings for the "fake" hardware.
+
+Arguments:
+
+ 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 -> ProgramScatterGatherMappings (
+ Clone,
+ Buffer,
+ Mappings,
+ MappingsCount,
+ sizeof (KSMAPPING)
+ );
+
+}
+
+/*************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+ULONG
+CCaptureDevice::
+QueryInterruptTime (
+ )
+
+/*++
+
+Routine Description:
+
+ Return the number of frame intervals that have elapsed since the
+ start of the device. This will be the frame number.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ The interrupt time of the device (the number of frame intervals that
+ have elapsed since the start of the device).
+
+--*/
+
+{
+
+ return m_InterruptTime;
+
+}
+
+/*************************************************/
+
+
+void
+CCaptureDevice::
+Interrupt (
+ )
+
+/*++
+
+Routine Description:
+
+ This is the "faked" interrupt service routine for this device. It
+ is called at dispatch level by the hardware simulation.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ m_InterruptTime++;
+
+ //
+ // 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 NumMappingsCompleted =
+ m_HardwareSimulation -> ReadNumberOfMappingsCompleted ();
+
+ //
+ // Inform the capture sink that a given number of scatter / gather
+ // mappings have completed.
+ //
+ m_CaptureSink -> CompleteMappings (
+ NumMappingsCompleted - m_LastMappingsCompleted
+ );
+
+ m_LastMappingsCompleted = NumMappingsCompleted;
+
+}
+
+/**************************************************************************
+
+ DESCRIPTOR AND DISPATCH LAYOUT
+
+**************************************************************************/
+
+//
+// CaptureFilterDescriptor:
+//
+// The filter descriptor for the capture device.
+DEFINE_KSFILTER_DESCRIPTOR_TABLE (FilterDescriptors) {
+ &CaptureFilterDescriptor
+};
+
+//
+// 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.
+//
+const
+KSDEVICE_DISPATCH
+CaptureDeviceDispatch = {
+ CCaptureDevice::DispatchCreate, // Pnp Add Device
+ CCaptureDevice::DispatchPnpStart, // Pnp Start
+ NULL, // Post-Start
+ NULL, // Pnp Query Stop
+ NULL, // Pnp Cancel Stop
+ CCaptureDevice::DispatchPnpStop, // Pnp Stop
+ NULL, // Pnp Query Remove
+ NULL, // Pnp Cancel Remove
+ NULL, // Pnp Remove
+ NULL, // Pnp Query Capabilities
+ NULL, // Pnp Surprise Removal
+ NULL, // Power Query Power
+ NULL, // Power Set Power
+ NULL // Pnp Query Interface
+};
+
+//
+// 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
+CaptureDeviceDescriptor = {
+ &CaptureDeviceDispatch,
+ 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,
+ &CaptureDeviceDescriptor
+ );
+
+}
diff --git a/AVStream/avshws/device.h b/AVStream/avshws/device.h
new file mode 100644
index 00000000..2bd9899d
--- /dev/null
+++ b/AVStream/avshws/device.h
@@ -0,0 +1,294 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ device.h
+
+ Abstract:
+
+ The header for the device level of the simulated hardware. This is
+ not actually the hardware simulation itself. The hardware simulation
+ is contained in hwsim.*, image.*.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+class CCaptureDevice :
+ public IHardwareSink {
+
+private:
+
+ //
+ // The AVStream device we're associated with.
+ //
+ PKSDEVICE m_Device;
+
+ //
+ // Number of pins with resources acquired. This is used as a locking
+ // mechanism for resource acquisition on the device.
+ //
+ LONG m_PinsWithResources;
+
+ //
+ // Since we don't have physical hardware, this provides the hardware
+ // simulation. m_HardwareSimulation provides the fake ISR, fake DPC,
+ // etc... m_ImageSynth provides RGB24 and UYVY image synthesis and
+ // overlay in software.
+ //
+ CHardwareSimulation *m_HardwareSimulation;
+ CImageSynthesizer *m_ImageSynth;
+
+ //
+ // The number of ISR's that have occurred since capture started.
+ //
+ ULONG m_InterruptTime;
+
+ //
+ // The last reading of mappings completed.
+ //
+ ULONG m_LastMappingsCompleted;
+
+ //
+ // 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;
+
+ //
+ // The capture sink. When we complete scatter / gather mappings, we
+ // notify the capture sink.
+ //
+ ICaptureSink *m_CaptureSink;
+
+ //
+ // The video info header we're basing hardware settings on. The pin
+ // provides this to us when acquiring resources and must guarantee its
+ // stability until resources are released.
+ //
+ PKS_VIDEOINFOHEADER m_VideoInfoHeader;
+
+ //
+ // 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;
+ }
+
+ //
+ // PnpStart():
+ //
+ // This is the Pnp start routine for our simulated hardware. Note that
+ // DispatchStart bridges to here in the context of the CCaptureDevice.
+ //
+ 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.
+ //
+ void
+ PnpStop (
+ );
+
+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
+ ) :
+ m_Device (Device)
+ {
+ }
+
+ //
+ // ~CCaptureDevice():
+ //
+ // The capture device destructor.
+ //
+ ~CCaptureDevice (
+ )
+ {
+ }
+
+ //
+ // 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
+ );
+ //
+ // DispatchPnpStart():
+ //
+ // This is the Pnp Start dispatch for the capture device. It simply
+ // bridges to PnpStart() in the context of the CCaptureDevice.
+ //
+ static
+ NTSTATUS
+ DispatchPnpStart (
+ IN PKSDEVICE Device,
+ IN PIRP Irp,
+ IN PCM_RESOURCE_LIST TranslatedResourceList,
+ IN PCM_RESOURCE_LIST UntranslatedResourceList
+ )
+ {
+ return
+ (reinterpret_cast <CCaptureDevice *> (Device -> Context)) ->
+ PnpStart (
+ TranslatedResourceList,
+ UntranslatedResourceList
+ );
+ }
+
+ //
+ // DispatchPnpStop():
+ //
+ // This is the Pnp stop dispatch for the capture device. It simply
+ // bridges to PnpStop() in the context of the CCaptureDevice.
+ //
+ static
+ void
+ DispatchPnpStop (
+ IN PKSDEVICE Device,
+ IN PIRP Irp
+ )
+ {
+ return
+ (reinterpret_cast <CCaptureDevice *> (Device -> Context)) ->
+ PnpStop (
+ );
+ }
+
+ //
+ // 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.
+ //
+ NTSTATUS
+ AcquireHardwareResources (
+ IN ICaptureSink *CaptureSink,
+ IN PKS_VIDEOINFOHEADER VideoInfoHeader
+ );
+
+ //
+ // ReleaseHardwareResources():
+ //
+ // Called to release hardware resources for the device.
+ //
+ void
+ ReleaseHardwareResources (
+ );
+
+ //
+ // Start():
+ //
+ // Called to start the hardware simulation. This causes us to simulate
+ // interrupts, simulate filling buffers with synthesized data, etc...
+ //
+ NTSTATUS
+ Start (
+ );
+
+ //
+ // 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 BOOLEAN Pausing
+ );
+
+ //
+ // 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 (
+ );
+
+ //
+ // 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 PKSSTREAM_POINTER Clone,
+ IN PUCHAR *Buffer,
+ IN PKSMAPPING Mappings,
+ IN ULONG MappingsCount
+ );
+
+ //
+ // QueryInterruptTime():
+ //
+ // Determine the frame number that this frame corresponds to.
+ //
+ ULONG
+ QueryInterruptTime (
+ );
+
+ //
+ // IHardwareSink::Interrupt():
+ //
+ // The interrupt service routine as called through the hardware sink
+ // interface. The "fake" hardware uses this method to inform the device
+ // of a "fake" ISR. The routine is called at dispatch level and must
+ // be in locked code.
+ //
+ virtual
+ void
+ Interrupt (
+ );
+
+ LONG GetDroppedFrameCount(){return m_HardwareSimulation->GetSkippedFrameCount();};
+};
diff --git a/AVStream/avshws/filter.cpp b/AVStream/avshws/filter.cpp
new file mode 100644
index 00000000..aea3acf7
--- /dev/null
+++ b/AVStream/avshws/filter.cpp
@@ -0,0 +1,203 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ filter.cpp
+
+ Abstract:
+
+ This file contains the filter level implementation for the
+ capture filter.
+
+ History:
+
+ created 3/12/2001
+
+**************************************************************************/
+
+#include "avshws.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+NTSTATUS
+CCaptureFilter::
+DispatchCreate (
+ IN PKSFILTER Filter,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This is the creation dispatch for the capture filter. It creates
+ the CCaptureFilter object, associates it with the AVStream filter
+ object, and bag the CCaptureFilter for later cleanup.
+
+Arguments:
+
+ Filter -
+ The AVStream filter being created
+
+ Irp -
+ The creation Irp
+
+Return Value:
+
+ Success / failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CCaptureFilter *CapFilter = new (NonPagedPoolNx, 'liFC') CCaptureFilter (Filter);
+
+ if (!CapFilter) {
+ //
+ // Return failure if we couldn't create the filter.
+ //
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ } else {
+ //
+ // Add the item to the object bag if we we were successful.
+ // Whenever the filter closes, the bag is cleaned up and we will be
+ // freed.
+ //
+ Status = KsAddItemToObjectBag (
+ Filter -> Bag,
+ reinterpret_cast <PVOID> (CapFilter),
+ reinterpret_cast <PFNKSFREE> (CCaptureFilter::Cleanup)
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ delete CapFilter;
+ } else {
+ Filter -> Context = reinterpret_cast <PVOID> (CapFilter);
+ }
+
+ }
+
+ return Status;
+
+}
+
+/**************************************************************************
+
+ DESCRIPTOR AND DISPATCH LAYOUT
+
+**************************************************************************/
+
+GUID g_PINNAME_VIDEO_CAPTURE = {STATIC_PINNAME_VIDEO_CAPTURE};
+
+//
+// CaptureFilterCategories:
+//
+// The list of category GUIDs for the capture filter.
+//
+const
+GUID
+CaptureFilterCategories [CAPTURE_FILTER_CATEGORIES_COUNT] = {
+ STATICGUIDOF (KSCATEGORY_VIDEO),
+ STATICGUIDOF (KSCATEGORY_CAPTURE),
+ STATICGUIDOF (KSCATEGORY_VIDEO_CAMERA)
+};
+
+//
+// CaptureFilterPinDescriptors:
+//
+// The list of pin descriptors on the capture filter.
+//
+const
+KSPIN_DESCRIPTOR_EX
+CaptureFilterPinDescriptors [CAPTURE_FILTER_PIN_COUNT] = {
+ //
+ // Video Capture Pin
+ //
+ {
+ &CapturePinDispatch,
+ NULL,
+ {
+ 0, // Interfaces (NULL, 0 == default)
+ NULL,
+ 0, // Mediums (NULL, 0 == default)
+ NULL,
+ SIZEOF_ARRAY(CapturePinDataRanges),// Range Count
+ CapturePinDataRanges, // Ranges
+ KSPIN_DATAFLOW_OUT, // Dataflow
+ KSPIN_COMMUNICATION_BOTH, // Communication
+ &PIN_CATEGORY_CAPTURE, // Category
+ &g_PINNAME_VIDEO_CAPTURE, // Name
+ 0 // Reserved
+ },
+#ifdef _X86_
+ KSPIN_FLAG_GENERATE_MAPPINGS | // Pin Flags
+#endif
+ KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY,
+ 1, // Instances Possible
+ 1, // Instances Necessary
+ &CapturePinAllocatorFraming, // Allocator Framing
+ reinterpret_cast <PFNKSINTERSECTHANDLEREX>
+ (CCapturePin::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
+CaptureFilterDispatch = {
+ CCaptureFilter::DispatchCreate, // Filter Create
+ NULL, // Filter Close
+ NULL, // Filter Process
+ NULL // Filter Reset
+};
+
+
+//
+// CaptureFilterDescription:
+//
+// 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
+CaptureFilterDescriptor = {
+ &CaptureFilterDispatch, // Dispatch Table
+ NULL, // Automation Table
+ KSFILTER_DESCRIPTOR_VERSION, // Version
+ 0, // Flags
+ &KSNAME_Filter, // Reference GUID
+ DEFINE_KSFILTER_PIN_DESCRIPTORS (CaptureFilterPinDescriptors),
+ DEFINE_KSFILTER_CATEGORIES (CaptureFilterCategories),
+ 0,
+ sizeof (KSNODE_DESCRIPTOR),
+ NULL,
+ 0,
+ NULL,
+ NULL // Component ID
+}; \ No newline at end of file
diff --git a/AVStream/avshws/filter.h b/AVStream/avshws/filter.h
new file mode 100644
index 00000000..e5cb9895
--- /dev/null
+++ b/AVStream/avshws/filter.h
@@ -0,0 +1,88 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ filter.h
+
+ Abstract:
+
+ This file contains the filter level header for the capture filter.
+
+ History:
+
+ created 3/12/2001
+
+**************************************************************************/
+
+class CCaptureFilter {
+
+private:
+
+ //
+ // The AVStream filter object associated with this CCaptureFilter.
+ //
+ PKSFILTER m_Filter;
+
+ //
+ // Cleanup():
+ //
+ // This is the bag cleanup callback for the CCaptureFilter. Not providing
+ // one would cause ExFreePool to be used. This is not good for C++
+ // constructed objects. We simply delete the object here.
+ //
+ static
+ void
+ Cleanup (
+ IN CCaptureFilter *CapFilter
+ )
+ {
+ delete CapFilter;
+ }
+
+public:
+
+ //
+ // CCaptureFilter():
+ //
+ // The capture filter object constructor. Since the new operator will
+ // have zeroed the memory, do not bother initializing any NULL or 0
+ // fields. Only initialize non-NULL, non-0 fields.
+ //
+ CCaptureFilter (
+ IN PKSFILTER Filter
+ ) :
+ m_Filter (Filter)
+ {
+ }
+
+ //
+ // ~CCaptureFilter():
+ //
+ // The capture filter destructor.
+ //
+ ~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
+ );
+
+};
+
+
diff --git a/AVStream/avshws/hwsim.cpp b/AVStream/avshws/hwsim.cpp
new file mode 100644
index 00000000..9a6d5f86
--- /dev/null
+++ b/AVStream/avshws/hwsim.cpp
@@ -0,0 +1,868 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ hwsim.cpp
+
+ Abstract:
+
+ This file contains the hardware simulation. It fakes "DMA" transfers,
+ scatter gather mapping handling, ISR's, etc... The ISR routine in
+ here will be called when an ISR would be generated by the fake hardware
+ and it will directly call into the device level ISR for more accurate
+ simulation.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+#include "avshws.h"
+
+
+/*************************************************/
+KDEFERRED_ROUTINE SimulatedInterrupt;
+
+void
+SimulatedInterrupt (
+ IN PKDPC Dpc,
+ IN PVOID DeferredContext,
+ IN PVOID SystemArg1,
+ IN PVOID SystemArg2
+ )
+{
+ CHardwareSimulation* HardwareSim = (CHardwareSimulation*)DeferredContext;
+
+ if (HardwareSim)
+ {
+ HardwareSim -> FakeHardware ();
+ }
+}
+
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+
+CHardwareSimulation::
+CHardwareSimulation (
+ IN IHardwareSink *HardwareSink
+ ) :
+ m_HardwareSink (HardwareSink),
+ m_ScatterGatherMappingsMax (SCATTER_GATHER_MAPPINGS_MAX)
+
+/*++
+
+Routine Description:
+
+ Construct a hardware simulation
+
+Arguments:
+
+ HardwareSink -
+ The hardware sink interface. This is used to trigger
+ fake interrupt service routines from.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ //
+ // Initialize the DPC's, timer's, and locks necessary to simulate
+ // this capture hardware.
+ //
+ KeInitializeDpc (
+ &m_IsrFakeDpc,
+ SimulatedInterrupt,
+ this
+ );
+
+ KeInitializeEvent (
+ &m_HardwareEvent,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ KeInitializeTimer (&m_IsrTimer);
+
+ KeInitializeSpinLock (&m_ListLock);
+
+}
+
+/*************************************************/
+
+
+CHardwareSimulation *
+CHardwareSimulation::
+Initialize (
+ IN KSOBJECT_BAG Bag,
+ IN IHardwareSink *HardwareSink
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the hardware simulation
+
+Arguments:
+
+ HardwareSink -
+ The hardware sink interface. This is what ISR's will be
+ triggered through.
+
+Return Value:
+
+ A fully initialized hardware simulation or NULL if the simulation
+ could not be initialized.
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ CHardwareSimulation *HwSim =
+ new (NonPagedPoolNx, 'miSH') CHardwareSimulation (HardwareSink);
+
+ return HwSim;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CHardwareSimulation::
+Start (
+ IN CImageSynthesizer *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();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ m_ImageSynth = ImageSynth;
+ m_TimePerFrame = TimePerFrame;
+ m_ImageSize = ImageSize;
+ m_Height = Height;
+ m_Width = Width;
+
+ InitializeListHead (&m_ScatterGatherMappings);
+ m_NumMappingsCompleted = 0;
+ m_ScatterGatherMappingsQueued = 0;
+ m_NumFramesSkipped = 0;
+ m_InterruptTime = 0;
+
+ KeQuerySystemTime (&m_StartTime);
+
+ //
+ // Allocate a scratch buffer for the synthesizer.
+ //
+ m_SynthesisBuffer = reinterpret_cast <PUCHAR> (
+ ExAllocatePoolWithTag (
+ NonPagedPoolNx,
+ m_ImageSize,
+ AVSHWS_POOLTAG
+ )
+ );
+
+ if (!m_SynthesisBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // If everything is ok, start issuing interrupts.
+ //
+ if (NT_SUCCESS (Status)) {
+
+ //
+ // Initialize the entry lookaside.
+ //
+ ExInitializeNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ NULL,
+ NULL,
+ POOL_NX_ALLOCATION,
+ sizeof (SCATTER_GATHER_ENTRY),
+ 'nEGS',
+ 0
+ );
+
+ //
+ // Set up the synthesizer with the width, height, and scratch buffer.
+ //
+ m_ImageSynth -> SetImageSize (m_Width, m_Height);
+ m_ImageSynth -> SetBuffer (m_SynthesisBuffer);
+
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart + m_TimePerFrame;
+
+ m_HardwareState = HardwareRunning;
+ KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc);
+
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CHardwareSimulation::
+Pause (
+ BOOLEAN Pausing
+ )
+
+/*++
+
+Routine Description:
+
+ Pause the hardware simulation... When the hardware simulation is told
+ to pause, it stops issuing interrupts, etc... 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();
+
+ if (Pausing && m_HardwareState == HardwareRunning) {
+ //
+ // If we were running, stop completing mappings, etc...
+ //
+ m_StopHardware = TRUE;
+
+ KeWaitForSingleObject (
+ &m_HardwareEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ NT_ASSERT (m_StopHardware == FALSE);
+
+ m_HardwareState = HardwarePaused;
+
+ } else if (!Pausing && m_HardwareState == HardwarePaused) {
+
+ //
+ // 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_HardwareState = HardwareRunning;
+ KeSetTimer (&m_IsrTimer, UnpauseTime, &m_IsrFakeDpc);
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+CHardwareSimulation::
+Stop (
+ )
+
+/*++
+
+Routine Description:
+
+ Stop the hardware simulation.... Wait until the hardware simulation
+ has successfully stopped and then return.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+ KIRQL Irql;
+ //
+ // 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.
+ //
+ if (m_HardwareState == HardwareRunning) {
+
+ m_StopHardware = TRUE;
+
+ KeWaitForSingleObject (
+ &m_HardwareEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ NT_ASSERT (m_StopHardware == FALSE);
+
+ }
+
+ m_HardwareState = HardwareStopped;
+
+ //
+ // The image synthesizer may still be around. Just for safety's
+ // sake, NULL out the image synthesis buffer and toast it.
+ //
+ m_ImageSynth -> SetBuffer (NULL);
+
+ if (m_SynthesisBuffer) {
+ ExFreePool (m_SynthesisBuffer);
+ m_SynthesisBuffer = NULL;
+ }
+
+ //
+ // Protect the S/G list
+ //
+ KeAcquireSpinLock (&m_ListLock, &Irql);
+ //
+ // Free S/G buffer
+ //
+ //
+ while (m_ScatterGatherMappingsQueued > 0) {
+ LIST_ENTRY *listEntry = RemoveHeadList (&m_ScatterGatherMappings);
+ m_ScatterGatherMappingsQueued--;
+ PSCATTER_GATHER_ENTRY SGEntry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ CONTAINING_RECORD (
+ listEntry,
+ SCATTER_GATHER_ENTRY,
+ ListEntry
+ )
+ );
+ //
+ // Release the scatter / gather entry back to our lookaside.
+ //
+ ExFreeToNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ reinterpret_cast <PVOID> (SGEntry)
+ );
+ }
+
+ m_NumMappingsCompleted = 0;
+ m_ScatterGatherBytesQueued = 0;
+ //
+ // Delete the scatter / gather lookaside for this run.
+ //
+ ExDeleteNPagedLookasideList (&m_ScatterGatherLookaside);
+
+ KeReleaseSpinLock (&m_ListLock, Irql);
+
+ return STATUS_SUCCESS;
+
+}
+
+
+ULONG
+CHardwareSimulation::
+ReadNumberOfMappingsCompleted (
+ )
+
+/*++
+
+Routine Description:
+
+ Read the number of scatter / gather mappings which have been
+ completed (TOTAL NUMBER) since the last reset of the simulated
+ hardware
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Total number of completed mappings.
+
+--*/
+
+{
+
+ //
+ // Don't care if this is being updated this moment in the DPC... I only
+ // need a number to return which isn't too great (too small is ok).
+ // In real hardware, this wouldn't be done this way anyway.
+ //
+ return m_NumMappingsCompleted;
+
+}
+
+/*************************************************/
+
+
+ULONG
+CHardwareSimulation::
+ProgramScatterGatherMappings (
+ IN PKSSTREAM_POINTER Clone,
+ IN PUCHAR *Buffer,
+ IN PKSMAPPING Mappings,
+ IN ULONG MappingsCount,
+ IN ULONG MappingStride
+ )
+
+/*++
+
+Routine Description:
+
+ Program the scatter gather mapping list. This shoves a bunch of
+ entries on a list for access during the fake interrupt. Note that
+ we have physical addresses here only for simulation. We really
+ access via the virtual address.... although we chunk it into multiple
+ buffers to more realistically simulate S/G
+
+Arguments:
+
+ Buffer -
+ The virtual address of the buffer mapped by the mapping list
+
+ 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.
+
+--*/
+
+{
+
+ KIRQL Irql;
+
+ ULONG MappingsInserted = 0;
+
+ //
+ // Protect our S/G list with a spinlock.
+ //
+ KeAcquireSpinLock (&m_ListLock, &Irql);
+
+ //
+ // 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.
+ //
+#if !defined(_X86_)
+ do
+ {
+ PSCATTER_GATHER_ENTRY Entry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ ExAllocateFromNPagedLookasideList (
+ &m_ScatterGatherLookaside
+ )
+ );
+
+ if (!Entry) {
+ break;
+ }
+ Entry -> Virtual = *Buffer;
+ Entry -> ByteCount = MappingsCount;
+ Entry -> CloneEntry = Clone;
+
+ //
+ // 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));
+ MappingsInserted = MappingsCount;
+ m_ScatterGatherMappingsQueued++;
+ m_ScatterGatherBytesQueued += MappingsCount;
+
+ }
+ while(FALSE);
+
+#else
+ for (ULONG MappingNum = 0;
+ MappingNum < MappingsCount &&
+ m_ScatterGatherMappingsQueued < m_ScatterGatherMappingsMax;
+ MappingNum++) {
+
+ PSCATTER_GATHER_ENTRY Entry =
+ reinterpret_cast <PSCATTER_GATHER_ENTRY> (
+ ExAllocateFromNPagedLookasideList (
+ &m_ScatterGatherLookaside
+ )
+ );
+
+ if (!Entry) {
+ break;
+ }
+
+ Entry -> Virtual = *Buffer;
+ Entry -> ByteCount = Mappings -> ByteCount;
+
+ //
+ // Move forward a specific number of bytes in chunking this into
+ // mapping sized va buffers.
+ //
+ *Buffer += Entry -> ByteCount;
+ Mappings = reinterpret_cast <PKSMAPPING> (
+ (reinterpret_cast <PUCHAR> (Mappings) + MappingStride)
+ );
+
+ InsertTailList (&m_ScatterGatherMappings, &(Entry -> ListEntry));
+ MappingsInserted++;
+ m_ScatterGatherMappingsQueued++;
+ m_ScatterGatherBytesQueued += Entry -> ByteCount;
+
+ }
+#endif
+
+ KeReleaseSpinLock (&m_ListLock, Irql);
+
+ return MappingsInserted;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CHardwareSimulation::
+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
+
+--*/
+
+{
+
+ //
+ // We're using this list lock to protect our scatter / gather lists instead
+ // of some hardware mechanism / KeSynchronizeExecution / whatever.
+ //
+ KeAcquireSpinLockAtDpcLevel (&m_ListLock);
+
+ PUCHAR Buffer = reinterpret_cast <PUCHAR> (m_SynthesisBuffer);
+ ULONG BufferRemaining = m_ImageSize;
+
+ //
+ // For simplification, if there aren't enough scatter / gather buffers
+ // queued, we don't partially fill the ones that are available. We just
+ // skip the frame and consider it starvation.
+ //
+ // This could be enforced by only programming scatter / gather mappings
+ // for a buffer if all of them fit in the table also...
+ //
+ while (BufferRemaining &&
+ m_ScatterGatherMappingsQueued > 0 &&
+ 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
+ )
+ );
+
+ //
+ // Since we're software, we'll be accessing this by virtual address...
+ //
+ ULONG BytesToCopy =
+ (BufferRemaining < SGEntry -> ByteCount) ?
+ BufferRemaining :
+ SGEntry -> ByteCount;
+
+ LONG Width = m_Width*(m_ImageSynth->GetBytesPerPixel());
+
+ LONG Stride = Width;
+ 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);
+ if(FrameInfo->lSurfacePitch != 0)
+ {
+ Stride = FrameInfo->lSurfacePitch;
+ if(FrameInfo->lSurfacePitch < 0)
+ {
+ Stride = -Stride;
+ }
+ }
+ }
+
+ for(ULONG y = 0; y < m_Height; y++)
+ {
+ RtlCopyMemory((SGEntry->Virtual+(ULONG)Stride*y), Buffer, Width);
+ Buffer += Width;
+ BytesToCopy -= Width;
+ BufferRemaining -= Width;
+ }
+
+ m_NumMappingsCompleted++;
+ m_ScatterGatherBytesQueued -= SGEntry -> ByteCount;
+
+ //
+ // Release the scatter / gather entry back to our lookaside.
+ //
+ ExFreeToNPagedLookasideList (
+ &m_ScatterGatherLookaside,
+ reinterpret_cast <PVOID> (SGEntry)
+ );
+
+ }
+
+ KeReleaseSpinLockFromDpcLevel (&m_ListLock);
+
+ if (BufferRemaining) return STATUS_INSUFFICIENT_RESOURCES;
+ else return STATUS_SUCCESS;
+
+}
+
+/*************************************************/
+
+
+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
+
+--*/
+
+{
+
+ 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_HardwareState == HardwareRunning) {
+
+ //
+ // Generate a "time stamp" just to overlay it onto the capture image.
+ // It makes it more exciting than bars that do nothing.
+ //
+ LONGLONG PtsRel = ((m_InterruptTime + 1) * m_TimePerFrame);
+
+ ULONG Min = (ULONG)(PtsRel / 600000000);
+ ULONG RemMin = (ULONG)(PtsRel % 600000000);
+ ULONG Sec = (ULONG)(RemMin / 10000000);
+ ULONG RemSec = (ULONG)(RemMin % 10000000);
+ ULONG Hund = (ULONG)(RemSec / 100000);
+
+ //
+ // Synthesize a buffer in scratch space.
+ //
+ m_ImageSynth -> SynthesizeBars ();
+
+ CHAR Text [256];
+ Text[0] = '\0';
+ (void) RtlStringCbPrintfA(Text, sizeof(Text), "%ld:%02ld.%02ld", Min, Sec, Hund);
+
+ //
+ // Overlay a clock onto the scratch space image.
+ //
+ m_ImageSynth -> OverlayText (
+ POSITION_CENTER,
+ (m_Height - 28),
+ 1,
+ Text,
+ BLACK,
+ WHITE
+ );
+
+ //
+ // Overlay a counter of skipped frames onto the scratch image.
+ //
+ (void) RtlStringCbPrintfA(Text, sizeof(Text), "Skipped: %ld", m_NumFramesSkipped);
+ m_ImageSynth -> OverlayText (
+ 10,
+ 10,
+ 1,
+ Text,
+ TRANSPARENT,
+ BLUE
+ );
+
+ //
+ // 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_HardwareSink -> Interrupt ();
+
+ //
+ // Reschedule the timer if the hardware isn't being stopped.
+ //
+ if (!m_StopHardware) {
+
+ //
+ // Reschedule the timer for the next interrupt time.
+ //
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart +
+ (m_TimePerFrame * (m_InterruptTime + 1));
+
+ KeSetTimer (&m_IsrTimer, NextTime, &m_IsrFakeDpc);
+
+ } else {
+ //
+ // If someone is waiting on the hardware to stop, raise the stop
+ // event and clear the flag.
+ //
+ m_StopHardware = FALSE;
+ KeSetEvent (&m_HardwareEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+}
diff --git a/AVStream/avshws/hwsim.h b/AVStream/avshws/hwsim.h
new file mode 100644
index 00000000..21ddcb41
--- /dev/null
+++ b/AVStream/avshws/hwsim.h
@@ -0,0 +1,290 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ hwsim.cpp
+
+ Abstract:
+
+ This file is the hardware simulation header.
+
+ The simulation fakes "DMA" transfers, scatter gather mapping handling,
+ ISR's, etc... The ISR routine in here will be called when an ISR
+ would be generated by the fake hardware and it will directly call into
+ the device level ISR for more accurate simulation.
+
+ History:
+
+ created 3/9/2001
+
+**************************************************************************/
+
+//
+// SCATTER_GATHER_MAPPINGS_MAX:
+//
+// The maximum number of entries in the hardware's scatter/gather list. I
+// am making this so large for a few reasons:
+//
+// 1) we're faking this with uncompressed surfaces --
+// these are large buffers which will map to a lot of s/g entries
+// 2) the fake hardware implementation requires at least one frame's
+// worth of s/g entries to generate a frame
+//
+#define SCATTER_GATHER_MAPPINGS_MAX 128
+
+//
+// SCATTER_GATHER_ENTRY:
+//
+// This structure is used to keep the scatter gather table for the fake
+// hardware as a doubly linked list.
+//
+typedef struct _SCATTER_GATHER_ENTRY {
+
+ LIST_ENTRY ListEntry;
+ PKSSTREAM_POINTER CloneEntry;
+ PUCHAR Virtual;
+ ULONG ByteCount;
+
+} SCATTER_GATHER_ENTRY, *PSCATTER_GATHER_ENTRY;
+
+//
+// CHardwareSimulation:
+//
+// The hardware simulation class.
+//
+class CHardwareSimulation {
+
+private:
+
+ //
+ // The image synthesizer. This is a piece of code which actually draws
+ // the requested images.
+ //
+ CImageSynthesizer *m_ImageSynth;
+
+ //
+ // The synthesis buffer. This is a private buffer we use to generate the
+ // capture image in. The fake "scatter / gather" mappings are filled
+ // in from this buffer during each interrupt.
+ //
+ PUCHAR m_SynthesisBuffer;
+
+ //
+ // Key information regarding the frames we generate.
+ //
+ LONGLONG m_TimePerFrame;
+ ULONG m_Width;
+ ULONG m_Height;
+ ULONG m_ImageSize;
+
+ //
+ // Scatter gather mappings for the simulated hardware.
+ //
+ KSPIN_LOCK m_ListLock;
+ LIST_ENTRY m_ScatterGatherMappings;
+
+ //
+ // Lookaside for memory for the scatter / gather entries on the scatter /
+ // gather list.
+ //
+ NPAGED_LOOKASIDE_LIST m_ScatterGatherLookaside;
+
+ //
+ // The current state of the fake hardware.
+ //
+ HARDWARE_STATE m_HardwareState;
+
+ //
+ // The pause / stop hardware flag and event.
+ //
+ BOOLEAN m_StopHardware;
+ KEVENT m_HardwareEvent;
+
+ //
+ // Maximum number of scatter / gather mappins in the s/g table of the
+ // fake hardware.
+ //
+ ULONG m_ScatterGatherMappingsMax;
+
+ //
+ // Number of scatter / gather mappings that have been completed (total)
+ // since the start of the hardware or any reset.
+ //
+ ULONG m_NumMappingsCompleted;
+
+ //
+ // Number of scatter / gather mappings that are queued for this hardware.
+ //
+ ULONG m_ScatterGatherMappingsQueued;
+ ULONG m_ScatterGatherBytesQueued;
+
+ //
+ // Number of frames skipped due to lack of scatter / gather mappings.
+ //
+ ULONG m_NumFramesSkipped;
+
+ //
+ // The "Interrupt Time". Number of "fake" interrupts that have occurred
+ // since the hardware was started.
+ //
+ ULONG m_InterruptTime;
+
+ //
+ // The system time at start.
+ //
+ LARGE_INTEGER m_StartTime;
+
+ //
+ // The DPC used to "fake" ISR
+ //
+ KDPC m_IsrFakeDpc;
+ KTIMER m_IsrTimer;
+
+ //
+ // The hardware sink that will be used for interrupt notifications.
+ //
+ IHardwareSink *m_HardwareSink;
+
+ //
+ // FillScatterGatherBuffers():
+ //
+ // This is called by the hardware simulation to fill a series of scatter /
+ // gather buffers with synthesized data.
+ //
+ NTSTATUS
+ FillScatterGatherBuffers (
+ );
+
+public:
+
+ LONG GetSkippedFrameCount()
+ {
+ return InterlockedExchange((LONG*)&this->m_NumFramesSkipped, this->m_NumFramesSkipped);
+ }
+ //
+ // CHardwareSimulation():
+ //
+ // The hardware simulation constructor. Since the new operator will
+ // have zeroed the memory, only initialize non-NULL, non-0 fields.
+ //
+ CHardwareSimulation (
+ IN IHardwareSink *HardwareSink
+ );
+
+ //
+ // ~CHardwareSimulation():
+ //
+ // The hardware simulation destructor.
+ //
+ ~CHardwareSimulation (
+ )
+ {
+ }
+
+ //
+ // Cleanup():
+ //
+ // This is the free callback for the bagged hardware sim. Not providing
+ // one will call ExFreePool, which is not what we want for a constructed
+ // C++ object. This simply deletes the simulation.
+ //
+ static
+ void
+ Cleanup (
+ IN CHardwareSimulation *HwSim
+ )
+ {
+ delete HwSim;
+ }
+
+ //
+ // FakeHardware():
+ //
+ // Called from the simulated interrupt. First we fake the hardware's
+ // actions (at DPC) then we call the "Interrupt service routine" on
+ // the hardware sink.
+ //
+ void
+ FakeHardware (
+ );
+
+ //
+ // Start():
+ //
+ // "Start" the fake hardware. This will start issuing interrupts and
+ // DPC's.
+ //
+ // The frame rate, image size, and a synthesizer must be provided.
+ //
+ NTSTATUS
+ Start (
+ CImageSynthesizer *ImageSynth,
+ IN LONGLONG TimePerFrame,
+ IN ULONG Width,
+ IN ULONG Height,
+ IN ULONG ImageSize
+ );
+
+ //
+ // Pause():
+ //
+ // "Pause" or "unpause" the fake hardware. This will stop issuing
+ // interrupts or DPC's on a pause and restart them on an unpause. Note
+ // that this will not reset counters as a Stop() would.
+ //
+ NTSTATUS
+ Pause (
+ IN BOOLEAN Pausing
+ );
+
+ //
+ // Stop():
+ //
+ // "Stop" the fake hardware. This will stop issuing interrupts and
+ // DPC's.
+ //
+ NTSTATUS
+ Stop (
+ );
+
+ //
+ // ProgramScatterGatherMappings():
+ //
+ // Program a series of scatter gather mappings into the fake hardware.
+ //
+ ULONG
+ ProgramScatterGatherMappings (
+ IN PKSSTREAM_POINTER Clone,
+ IN PUCHAR *Buffer,
+ IN PKSMAPPING Mappings,
+ IN ULONG MappingsCount,
+ IN ULONG MappingStride
+ );
+
+ //
+ // Initialize():
+ //
+ // Initialize a piece of simulated hardware.
+ //
+ static
+ CHardwareSimulation *
+ Initialize (
+ IN KSOBJECT_BAG Bag,
+ IN IHardwareSink *HardwareSink
+ );
+
+ //
+ // ReadNumberOfMappingsCompleted():
+ //
+ // Read the number of mappings completed since the last hardware reset.
+ //
+ ULONG
+ ReadNumberOfMappingsCompleted (
+ );
+
+};
+
diff --git a/AVStream/avshws/image.cpp b/AVStream/avshws/image.cpp
new file mode 100644
index 00000000..8ab35624
--- /dev/null
+++ b/AVStream/avshws/image.cpp
@@ -0,0 +1,605 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ image.cpp
+
+ Abstract:
+
+ The image synthesis and overlay code. These objects provide image
+ synthesis (pixel, color-bar, etc...) onto RGB24 and UYVY buffers as
+ well as software string overlay into these buffers.
+
+ This entire file, data and all, must be in locked segments.
+
+ History:
+
+ created 1/16/2001
+
+**************************************************************************/
+
+#include "avshws.h"
+
+/**************************************************************************
+
+ Constants
+
+**************************************************************************/
+
+//
+// g_FontData:
+//
+// The following is an 8x8 bitmapped font for use in the text overlay
+// code.
+//
+UCHAR g_FontData [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}
+};
+
+//
+// Standard definition of EIA-189-A color bars. The actual color definitions
+// are either in CRGB24Synthesizer or CYUVSynthesizer.
+//
+const COLOR g_ColorBars[] =
+ {WHITE, YELLOW, CYAN, GREEN, MAGENTA, RED, BLUE, BLACK};
+
+const UCHAR CRGB24Synthesizer::Colors [MAX_COLOR][3] = {
+ {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
+};
+
+const UCHAR CYUVSynthesizer::Colors [MAX_COLOR][3] = {
+ {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
+};
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+void
+CImageSynthesizer::
+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:
+
+ None
+
+--*/
+
+{
+ const COLOR *CurColor = g_ColorBars;
+ ULONG ColorCount = SIZEOF_ARRAY (g_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 (g_ColorBars [((x * ColorCount) / m_Width)]);
+
+ PUCHAR ImageEnd = m_Cursor;
+
+ //
+ // Copy the synthesized line to all subsequent lines.
+ //
+ for (ULONG line = 1; line < m_Height; line++) {
+
+ GetImageLocation (0, line);
+
+ RtlCopyMemory (
+ m_Cursor,
+ ImageStart,
+ ImageEnd - ImageStart
+ );
+ }
+}
+
+/*************************************************/
+
+
+void
+CImageSynthesizer::
+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. 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. POSITION_CENTER may be used to indicate
+ vertical centering.
+
+ Scaling -
+ Normally, the overlay is done in 8x8 font. A scaling of
+ 2 indicates 16x16, 3 indicates 24x24 and so forth.
+
+ Text -
+ A 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
+
+--*/
+
+{
+
+ NT_ASSERT ((LocX <= m_Width || LocX == POSITION_CENTER) &&
+ (LocY <= m_Height || LocY == POSITION_CENTER));
+
+ ULONG StrLen = 0;
+ CHAR* CurChar;
+
+ //
+ // Determine the character length of the string.
+ //
+ for (CurChar = Text; CurChar && *CurChar; CurChar++)
+ StrLen++;
+
+ //
+ // 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 = (StrLen * (Scaling << 3)) + 1 + StrLen;
+ #else // NO_CHARACTER_SEPARATION
+ ULONG LenX = (StrLen * (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) {
+ if (LenX >= m_Width) {
+ LocX = 0;
+ } else {
+ LocX = (m_Width >> 1) - (LenX >> 1);
+ }
+ }
+
+ if (LocY == POSITION_CENTER) {
+ if (LenY >= m_Height) {
+ LocY = 0;
+ } else {
+ LocY = (m_Height >> 1) - (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 (BgColor != TRANSPARENT && SpaceY) {
+ for (ULONG x = 0; x < LenX && x < SpaceX; x++) {
+ PutPixel (BgColor);
+ }
+ }
+ LocY++;
+ if (SpaceY) SpaceY--;
+
+ //
+ // 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 = Text;
+ while (CurChar && *CurChar) {
+
+ UCHAR CharBase = g_FontData [*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);
+ }
+ }
+
+}
diff --git a/AVStream/avshws/image.h b/AVStream/avshws/image.h
new file mode 100644
index 00000000..95574479
--- /dev/null
+++ b/AVStream/avshws/image.h
@@ -0,0 +1,478 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ image.h
+
+ Abstract:
+
+ The image synthesis and overlay header. These objects provide image
+ synthesis (pixel, color-bar, etc...) onto RGB24 and UYVY buffers as
+ well as software string overlay into these buffers.
+
+ History:
+
+ created 1/16/2001
+
+**************************************************************************/
+
+/**************************************************************************
+
+ Constants
+
+**************************************************************************/
+
+//
+// COLOR:
+//
+// Pixel color for placement onto the synthesis buffer.
+//
+typedef enum {
+
+ BLACK = 0,
+ WHITE,
+ YELLOW,
+ CYAN,
+ GREEN,
+ MAGENTA,
+ RED,
+ BLUE,
+ GREY,
+
+ MAX_COLOR,
+ TRANSPARENT,
+
+} COLOR;
+
+//
+// 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)
+
+/*************************************************
+
+ CImageSynthesizer
+
+ 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.
+
+*************************************************/
+
+class CImageSynthesizer {
+
+protected:
+
+ //
+ // The width and height the synthesizer is set to.
+ //
+ ULONG m_Width;
+ ULONG m_Height;
+
+ //
+ // The synthesis buffer. All scan conversion happens in the synthesis
+ // buffer. This must be set with SetBuffer() before any scan conversion
+ // routines are called.
+ //
+ PUCHAR m_SynthesisBuffer;
+
+ //
+ // The default cursor. This is a pointer into the synthesis buffer where
+ // a non specific PutPixel will be placed.
+ //
+ PUCHAR m_Cursor;
+
+public:
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at the specified image cursor and move right
+ // by one pixel. No bounds checking... wrap around occurs.
+ //
+ virtual void
+ PutPixel (
+ PUCHAR *ImageLocation,
+ COLOR Color
+ ) = 0;
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at the default image cursor and move right
+ // by one pixel. No bounds checking... wrap around occurs.
+ //
+ // If the derived class doesn't provide an implementation, provide
+ // one.
+ //
+ virtual void
+ PutPixel (
+ COLOR Color
+ )
+ {
+ PutPixel (&m_Cursor, Color);
+ }
+
+ virtual long
+ GetBytesPerPixel() = 0;
+
+
+ //
+ // 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.
+ //
+ virtual PUCHAR
+ GetImageLocation (
+ ULONG LocX,
+ ULONG LocY
+ ) = 0;
+
+ //
+ // SetImageSize():
+ //
+ // Set the image size of the synthesis buffer.
+ //
+ void
+ SetImageSize (
+ ULONG Width,
+ ULONG Height
+ )
+ {
+ m_Width = Width;
+ m_Height = Height;
+ }
+
+ //
+ // SetBuffer():
+ //
+ // Set the buffer the synthesizer generates images to.
+ //
+ void
+ SetBuffer (
+ PUCHAR SynthesisBuffer
+ )
+ {
+ m_SynthesisBuffer = SynthesisBuffer;
+ }
+
+ //
+ // SynthesizeBars():
+ //
+ // Synthesize EIA-189-A standard color bars.
+ //
+ void
+ SynthesizeBars (
+ );
+
+ //
+ // 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
+ );
+
+ //
+ // DEFAULT CONSTRUCTOR
+ //
+ CImageSynthesizer (
+ ) :
+ m_Width (0),
+ m_Height (0),
+ m_SynthesisBuffer (NULL)
+ {
+ }
+
+ //
+ // CONSTRUCTOR:
+ //
+ CImageSynthesizer (
+ ULONG Width,
+ ULONG Height
+ ) :
+ m_Width (Width),
+ m_Height (Height),
+ m_SynthesisBuffer (NULL)
+ {
+ }
+
+ //
+ // DESTRUCTOR:
+ //
+ virtual
+ ~CImageSynthesizer (
+ )
+ {
+ }
+
+};
+
+/*************************************************
+
+ CRGB24Synthesizer
+
+ Image synthesizer for RGB24 format.
+
+*************************************************/
+
+class CRGB24Synthesizer : public CImageSynthesizer {
+
+private:
+
+ const static UCHAR Colors [MAX_COLOR][3];
+
+ BOOLEAN m_FlipVertical;
+
+public:
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at a specific cursor location. *ImageLocation must
+ // reside within the synthesis buffer.
+ //
+ virtual void
+ PutPixel (
+ PUCHAR *ImageLocation,
+ COLOR Color
+ )
+ {
+ if (Color != TRANSPARENT) {
+ *(*ImageLocation)++ = Colors [(ULONG)Color][0];
+ *(*ImageLocation)++ = Colors [(ULONG)Color][1];
+ *(*ImageLocation)++ = Colors [(ULONG)Color][2];
+ } else {
+ *ImageLocation += 3;
+ }
+ }
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at the default cursor location. The cursor location
+ // must be set via GetImageLocation(x, y).
+ //
+ virtual void
+ PutPixel (
+ COLOR Color
+ )
+ {
+ if (Color != TRANSPARENT) {
+ *m_Cursor++ = Colors [(ULONG)Color][0];
+ *m_Cursor++ = Colors [(ULONG)Color][1];
+ *m_Cursor++ = Colors [(ULONG)Color][2];
+ } else {
+ m_Cursor += 3;
+ }
+ }
+
+ virtual long
+ GetBytesPerPixel ()
+ {
+ return 3;
+ }
+
+ virtual PUCHAR
+ GetImageLocation (
+ ULONG LocX,
+ ULONG LocY
+ )
+ {
+ if (m_FlipVertical) {
+ return (m_Cursor =
+ (m_SynthesisBuffer + 3 *
+ (LocX + (m_Height - 1 - LocY) * m_Width))
+ );
+ } else {
+ return (m_Cursor =
+ (m_SynthesisBuffer + 3 * (LocX + LocY * m_Width))
+ );
+ }
+ }
+
+ //
+ // DEFAULT CONSTRUCTOR:
+ //
+ CRGB24Synthesizer (
+ BOOLEAN FlipVertical
+ ) :
+ m_FlipVertical (FlipVertical)
+ {
+ }
+
+ //
+ // CONSTRUCTOR:
+ //
+ CRGB24Synthesizer (
+ BOOLEAN FlipVertical,
+ ULONG Width,
+ ULONG Height
+ ) :
+ CImageSynthesizer (Width, Height),
+ m_FlipVertical (FlipVertical)
+ {
+ }
+
+ //
+ // DESTRUCTOR:
+ //
+ virtual
+ ~CRGB24Synthesizer (
+ )
+ {
+ }
+
+};
+
+/*************************************************
+
+ CYUVSynthesizer
+
+ Image synthesizer for YUV format.
+
+*************************************************/
+
+class CYUVSynthesizer : public CImageSynthesizer {
+
+private:
+
+ const static UCHAR Colors [MAX_COLOR][3];
+
+ BOOLEAN m_Parity;
+
+public:
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at a specific cursor location. *ImageLocation must
+ // reside within the synthesis buffer.
+ //
+ virtual void
+ PutPixel (
+ PUCHAR *ImageLocation,
+ COLOR Color
+ )
+ {
+
+ BOOLEAN Parity = (((*ImageLocation - m_SynthesisBuffer) & 0x2) != 0);
+
+#if DBG
+ //
+ // Check that the current pixel points to a valid start pixel
+ // in the UYVY buffer.
+ //
+ BOOLEAN Odd = (((*ImageLocation - m_SynthesisBuffer) & 0x1) != 0);
+ NT_ASSERT ((m_Parity && Odd) || (!m_Parity && !Odd));
+#endif // DBG
+
+ if (Color != TRANSPARENT) {
+ if (Parity) {
+ *(*ImageLocation)++ = Colors [(ULONG)Color][2];
+ } else {
+ *(*ImageLocation)++ = Colors [(ULONG)Color][1];
+ *(*ImageLocation)++ = Colors [(ULONG)Color][0];
+ *(*ImageLocation)++ = Colors [(ULONG)Color][1];
+ }
+ } else {
+ *ImageLocation += (Parity ? 1 : 3);
+ }
+
+ }
+
+ //
+ // PutPixel():
+ //
+ // Place a pixel at the default cursor location. The cursor location
+ // must be set via GetImageLocation(x, y).
+ //
+ virtual void
+ PutPixel (
+ COLOR Color
+ )
+
+ {
+
+ if (Color != TRANSPARENT) {
+ if (m_Parity) {
+ *m_Cursor++ = Colors [(ULONG)Color][2];
+ } else {
+ *m_Cursor++ = Colors [(ULONG)Color][1];
+ *m_Cursor++ = Colors [(ULONG)Color][0];
+ *m_Cursor++ = Colors [(ULONG)Color][1];
+ }
+ } else {
+ m_Cursor += (m_Parity ? 1 : 3);
+ }
+
+ m_Parity = !m_Parity;
+
+ }
+
+ virtual long
+ GetBytesPerPixel ()
+ {
+ return 2;
+ }
+
+ virtual PUCHAR
+ GetImageLocation (
+ ULONG LocX,
+ ULONG LocY
+ )
+ {
+
+ m_Cursor = m_SynthesisBuffer + ((LocX + LocY * m_Width) << 1);
+ if (m_Parity = ((LocX & 1) != 0))
+ m_Cursor++;
+
+ return m_Cursor;
+ }
+
+ //
+ // DEFAULT CONSTRUCTOR:
+ //
+ CYUVSynthesizer (
+ )
+ {
+ }
+
+ //
+ // CONSTRUCTOR:
+ //
+ CYUVSynthesizer (
+ ULONG Width,
+ ULONG Height
+ ) :
+ CImageSynthesizer (Width, Height)
+ {
+ }
+
+ //
+ // DESTRUCTOR:
+ //
+ virtual
+ ~CYUVSynthesizer (
+ )
+ {
+ }
+
+};
+
diff --git a/AVStream/avshws/purecall.c b/AVStream/avshws/purecall.c
new file mode 100644
index 00000000..ea61fbff
--- /dev/null
+++ b/AVStream/avshws/purecall.c
@@ -0,0 +1,50 @@
+/**************************************************************************
+
+ AVStream Simulated Hardware Sample
+
+ Copyright (c) 2001, Microsoft Corporation.
+
+ File:
+
+ purecall.c
+
+ Abstract:
+
+ This file contains the _purecall stub necessary for virtual function
+ usage in drivers on 98 gold.
+
+ History:
+
+ created 9/16/02
+
+**************************************************************************/
+
+/*************************************************
+
+ Function:
+
+ _purecall
+
+ Description:
+
+ _purecall stub for virtual function usage
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ 0
+
+*************************************************/
+#pragma warning (disable : 4100 4131)
+int __cdecl
+_purecall (
+ VOID
+ )
+
+{
+ return 0;
+}
+