diff options
| author | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
|---|---|---|
| committer | Wei Mao <[email protected]> | 2017-03-17 19:47:04 -0700 |
| commit | 1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch) | |
| tree | bf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream/avshws | |
| parent | da21c8784c83c5fd614f3030323e229d6a5fb10e (diff) | |
Fix cases
Diffstat (limited to 'AVStream/avshws')
| -rw-r--r-- | AVStream/avshws/README.md | 76 | ||||
| -rw-r--r-- | AVStream/avshws/avshws.h | 323 | ||||
| -rw-r--r-- | AVStream/avshws/avshws.inf | 173 | ||||
| -rw-r--r-- | AVStream/avshws/avshws.rc | 22 | ||||
| -rw-r--r-- | AVStream/avshws/avshws.sln | 28 | ||||
| -rw-r--r-- | AVStream/avshws/avshws.vcxproj | 200 | ||||
| -rw-r--r-- | AVStream/avshws/avshws.vcxproj.Filters | 46 | ||||
| -rw-r--r-- | AVStream/avshws/capture.cpp | 1704 | ||||
| -rw-r--r-- | AVStream/avshws/capture.h | 313 | ||||
| -rw-r--r-- | AVStream/avshws/device.cpp | 875 | ||||
| -rw-r--r-- | AVStream/avshws/device.h | 294 | ||||
| -rw-r--r-- | AVStream/avshws/filter.cpp | 203 | ||||
| -rw-r--r-- | AVStream/avshws/filter.h | 88 | ||||
| -rw-r--r-- | AVStream/avshws/hwsim.cpp | 868 | ||||
| -rw-r--r-- | AVStream/avshws/hwsim.h | 290 | ||||
| -rw-r--r-- | AVStream/avshws/image.cpp | 605 | ||||
| -rw-r--r-- | AVStream/avshws/image.h | 478 | ||||
| -rw-r--r-- | AVStream/avshws/purecall.c | 50 |
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; +} + |
