summaryrefslogtreecommitdiff
path: root/AVStream
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 19:47:04 -0700
committerWei Mao <[email protected]>2017-03-17 19:47:04 -0700
commit1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch)
treebf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'AVStream')
-rw-r--r--AVStream/avshws/README.md76
-rw-r--r--AVStream/avshws/avshws.h323
-rw-r--r--AVStream/avshws/avshws.inf173
-rw-r--r--AVStream/avshws/avshws.rc22
-rw-r--r--AVStream/avshws/avshws.sln28
-rw-r--r--AVStream/avshws/avshws.vcxproj200
-rw-r--r--AVStream/avshws/avshws.vcxproj.Filters46
-rw-r--r--AVStream/avshws/capture.cpp1704
-rw-r--r--AVStream/avshws/capture.h313
-rw-r--r--AVStream/avshws/device.cpp875
-rw-r--r--AVStream/avshws/device.h294
-rw-r--r--AVStream/avshws/filter.cpp203
-rw-r--r--AVStream/avshws/filter.h88
-rw-r--r--AVStream/avshws/hwsim.cpp868
-rw-r--r--AVStream/avshws/hwsim.h290
-rw-r--r--AVStream/avshws/image.cpp605
-rw-r--r--AVStream/avshws/image.h478
-rw-r--r--AVStream/avshws/purecall.c50
-rw-r--r--AVStream/avssamp/Filter.cpp836
-rw-r--r--AVStream/avssamp/README.md51
-rw-r--r--AVStream/avssamp/audio.cpp655
-rw-r--r--AVStream/avssamp/audio.h150
-rw-r--r--AVStream/avssamp/avssamp.cpp243
-rw-r--r--AVStream/avssamp/avssamp.h252
-rw-r--r--AVStream/avssamp/avssamp.inf93
-rw-r--r--AVStream/avssamp/avssamp.rc22
-rw-r--r--AVStream/avssamp/avssamp.sln28
-rw-r--r--AVStream/avssamp/avssamp.vcxproj202
-rw-r--r--AVStream/avssamp/avssamp.vcxproj.Filters52
-rw-r--r--AVStream/avssamp/capture.cpp249
-rw-r--r--AVStream/avssamp/capture.h284
-rw-r--r--AVStream/avssamp/filter.h253
-rw-r--r--AVStream/avssamp/image.cpp647
-rw-r--r--AVStream/avssamp/image.h476
-rw-r--r--AVStream/avssamp/purecall.c50
-rw-r--r--AVStream/avssamp/video.cpp1433
-rw-r--r--AVStream/avssamp/video.h221
-rw-r--r--AVStream/avssamp/wave.cpp598
-rw-r--r--AVStream/avssamp/wave.h192
-rw-r--r--AVStream/sampledevicemft/SampleDeviceMft.sln28
-rw-r--r--AVStream/sampledevicemft/Source.def5
-rw-r--r--AVStream/sampledevicemft/basepin.cpp847
-rw-r--r--AVStream/sampledevicemft/basepin.h596
-rw-r--r--AVStream/sampledevicemft/common.h717
-rw-r--r--AVStream/sampledevicemft/custompin.cpp98
-rw-r--r--AVStream/sampledevicemft/custompin.h30
-rw-r--r--AVStream/sampledevicemft/dllmain.cpp354
-rw-r--r--AVStream/sampledevicemft/mftpeventgenerator.cpp250
-rw-r--r--AVStream/sampledevicemft/mftpeventgenerator.h94
-rw-r--r--AVStream/sampledevicemft/multipinmft.cpp2453
-rw-r--r--AVStream/sampledevicemft/multipinmft.h477
-rw-r--r--AVStream/sampledevicemft/multipinmft.vcxproj263
-rw-r--r--AVStream/sampledevicemft/multipinmft.vcxproj.Filters46
-rw-r--r--AVStream/sampledevicemft/multipinmfthelpers.cpp988
-rw-r--r--AVStream/sampledevicemft/multipinmfthelpers.h291
-rw-r--r--AVStream/sampledevicemft/multipinmftutils.cpp877
-rw-r--r--AVStream/sampledevicemft/stdafx.h39
-rw-r--r--AVStream/sampledevicemft/stdafxsrc.cpp1
-rw-r--r--AVStream/samplemft0/Mft0.cpp975
-rw-r--r--AVStream/samplemft0/Mft0.h224
-rw-r--r--AVStream/samplemft0/Mft0.rgs15
-rw-r--r--AVStream/samplemft0/README.md28
-rw-r--r--AVStream/samplemft0/SampleHelpers.h143
-rw-r--r--AVStream/samplemft0/SampleMft0.cpp83
-rw-r--r--AVStream/samplemft0/SampleMft0.def16
-rw-r--r--AVStream/samplemft0/SampleMft0.idl48
-rw-r--r--AVStream/samplemft0/SampleMft0.rcbin0 -> 6644 bytes
-rw-r--r--AVStream/samplemft0/SampleMft0.rgs3
-rw-r--r--AVStream/samplemft0/SampleMft0.sln41
-rw-r--r--AVStream/samplemft0/SampleMft0.vcxproj146
-rw-r--r--AVStream/samplemft0/SampleMft0.vcxproj.Filters99
-rw-r--r--AVStream/samplemft0/dllmain.cpp19
-rw-r--r--AVStream/samplemft0/dllmain.h10
-rw-r--r--AVStream/samplemft0/resource.hbin0 -> 1710 bytes
-rw-r--r--AVStream/samplemft0/stdafx.cpp13
-rw-r--r--AVStream/samplemft0/stdafx.h42
-rw-r--r--AVStream/samplemft0/stdafxsrc.cpp1
-rw-r--r--AVStream/samplemft0/targetver.h15
78 files changed, 23998 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;
+}
+
diff --git a/AVStream/avssamp/Filter.cpp b/AVStream/avssamp/Filter.cpp
new file mode 100644
index 00000000..524d6ad8
--- /dev/null
+++ b/AVStream/avssamp/Filter.cpp
@@ -0,0 +1,836 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ filter.cpp
+
+ Abstract:
+
+ This file contails the capture filter implementation (including
+ frame synthesis) for the fake capture filter.
+
+ History:
+
+ created 5/31/01
+
+**************************************************************************/
+
+#include "avssamp.h"
+
+//
+// TimerRoutine():
+//
+// This is the timer routine called every 1/Nth of a second to trigger
+// capture by the filter.
+//
+KDEFERRED_ROUTINE TimerRoutine;
+void
+TimerRoutine (
+ IN PKDPC Dpc,
+ IN PVOID This,
+ IN PVOID SystemArg1,
+ IN PVOID SystemArg2
+ )
+{
+ CCaptureFilter *pCCaptureFilter = (CCaptureFilter*)This;
+ if (pCCaptureFilter)
+ {
+ pCCaptureFilter -> TimerDpc ();
+ }
+}
+
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+CCaptureFilter::
+CCaptureFilter (
+ IN PKSFILTER Filter
+ ) :
+ m_Filter (Filter)
+
+/*++
+
+Routine Description:
+
+ This is the constructor for the capture filter. It initializes all the
+ structures necessary to kick off timer DPC's for capture.
+
+Arguments:
+
+ Filter -
+ The AVStream filter being created.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ //
+ // Initialize the DPC's, timers, and events necessary to cause a
+ // capture trigger to happen.
+ //
+ KeInitializeDpc (
+ &m_TimerDpc,
+ TimerRoutine,
+ this
+ );
+
+ KeInitializeEvent (
+ &m_StopDPCEvent,
+ SynchronizationEvent,
+ FALSE
+ );
+
+ KeInitializeTimer (&m_Timer);
+
+}
+
+/*************************************************/
+
+
+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 (NonPagedPool) 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);
+ }
+
+ }
+
+ //
+ // Create the wave reader. We need it at this point because the data
+ // ranges exposed on the audio pin need to change dynamically right
+ // now.
+ //
+ if (NT_SUCCESS (Status)) {
+
+ CapFilter -> m_WaveObject =
+ new (NonPagedPool, 'evaW') CWaveObject (
+ L"\\DosDevices\\c:\\avssamp.wav"
+ );
+
+ if (!CapFilter -> m_WaveObject) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ Status = CapFilter -> m_WaveObject -> ParseAndRead ();
+
+ //
+ // If the file cannot be found, don't fail to create the filter.
+ // This simply means that audio cannot be synthesized.
+ //
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
+ Status == STATUS_ACCESS_DENIED) {
+ delete CapFilter -> m_WaveObject;
+ CapFilter -> m_WaveObject = NULL;
+ Status = STATUS_SUCCESS;
+ }
+
+ }
+
+ }
+
+ if (NT_SUCCESS (Status) && CapFilter -> m_WaveObject) {
+ //
+ // Add the wave object to the filter's bag for auto-cleanup.
+ //
+ Status = KsAddItemToObjectBag (
+ Filter -> Bag,
+ reinterpret_cast <PVOID> (CapFilter -> m_WaveObject),
+ reinterpret_cast <PFNKSFREE> (CWaveObject::Cleanup)
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ delete CapFilter -> m_WaveObject;
+ CapFilter -> m_WaveObject = NULL;
+ } else {
+ Status = CapFilter -> BindAudioToWaveObject ();
+ }
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+NTSTATUS
+CCaptureFilter::
+BindAudioToWaveObject (
+ )
+
+/*++
+
+Routine Description:
+
+ Create an audio pin directly bound to m_WaveObject (aka: it only exposes
+ the format (channels, frequency, etc...) that m_WaveObject represents.
+ This will actually create a pin on the filter dynamically.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NT_ASSERT (m_WaveObject);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ //
+ // Build a pin descriptor from the template. This descriptor is
+ // temporary scratch space because the call to AVStream to create the
+ // pin will actually duplicate the descriptor.
+ //
+ KSPIN_DESCRIPTOR_EX PinDescriptor = AudioPinDescriptorTemplate;
+
+ //
+ // The data range must be dynamically created since we're basing it
+ // on dynamic reading of a wave file!
+ //
+ PKSDATARANGE_AUDIO DataRangeAudio =
+ reinterpret_cast <PKSDATARANGE_AUDIO> (
+ ExAllocatePoolWithTag (PagedPool, sizeof (KSDATARANGE_AUDIO), AVSSMP_POOLTAG)
+ );
+
+ PKSDATARANGE_AUDIO *DataRanges =
+ reinterpret_cast <PKSDATARANGE_AUDIO *> (
+ ExAllocatePoolWithTag (PagedPool, sizeof (PKSDATARANGE_AUDIO), AVSSMP_POOLTAG)
+ );
+
+ PKSALLOCATOR_FRAMING_EX Framing =
+ reinterpret_cast <PKSALLOCATOR_FRAMING_EX> (
+ ExAllocatePoolWithTag (PagedPool, sizeof (KSALLOCATOR_FRAMING_EX), AVSSMP_POOLTAG)
+ );
+
+ if (DataRangeAudio && DataRanges && Framing) {
+ DataRangeAudio -> DataRange.FormatSize = sizeof (KSDATARANGE_AUDIO);
+ DataRangeAudio -> DataRange.Flags = 0;
+ DataRangeAudio -> DataRange.SampleSize = 0;
+ DataRangeAudio -> DataRange.Reserved = 0;
+ DataRangeAudio -> DataRange.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
+ DataRangeAudio -> DataRange.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ DataRangeAudio -> DataRange.Specifier =
+ KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
+
+ m_WaveObject -> WriteRange (DataRangeAudio);
+
+ *DataRanges = DataRangeAudio;
+
+ } else {
+ if (DataRangeAudio) {
+ ExFreePool (DataRangeAudio);
+ DataRangeAudio = NULL;
+ }
+ if (DataRanges) {
+ ExFreePool (DataRanges);
+ DataRanges = NULL;
+ }
+ if (Framing) {
+ ExFreePool (Framing);
+ Framing = NULL;
+ }
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ if (NT_SUCCESS (Status)) {
+ //
+ // Bag the newly created range information in the filter's bag since
+ // this will be alive for the lifetime of the filter.
+ //
+ Status = KsAddItemToObjectBag (
+ m_Filter -> Bag,
+ DataRangeAudio,
+ NULL
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ ExFreePool (DataRangeAudio);
+ ExFreePool (DataRanges);
+ ExFreePool (Framing);
+ }
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+
+ Status = KsAddItemToObjectBag (
+ m_Filter -> Bag,
+ DataRanges,
+ NULL
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ ExFreePool (DataRanges);
+ ExFreePool (Framing);
+ }
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+
+ Status = KsAddItemToObjectBag (
+ m_Filter -> Bag,
+ Framing,
+ NULL
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ ExFreePool (Framing);
+ }
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+ //
+ // The physical and optimal ranges must block aligned and
+ // the size of 1/(fps) * bytes_per_sec in size. It's true
+ // that we don't know the frame rate at this point due
+ // to the fact that the video pin doesn't exist yet; however, that
+ // would also be true if this were edited at audio pin creation.
+ //
+ // Thus, we instead adjust the allocator for the minimum frame rate
+ // we support (which is 1/30 of a second).
+ //
+ *Framing = *PinDescriptor.AllocatorFraming;
+
+ Framing -> FramingItem [0].PhysicalRange.MinFrameSize =
+ Framing -> FramingItem [0].PhysicalRange.MaxFrameSize =
+ Framing -> FramingItem [0].FramingRange.Range.MinFrameSize =
+ Framing -> FramingItem [0].FramingRange.Range.MaxFrameSize =
+ ((DataRangeAudio -> MaximumSampleFrequency *
+ DataRangeAudio -> MaximumBitsPerSample *
+ DataRangeAudio -> MaximumChannels) + 29) / 30;
+
+ Framing -> FramingItem [0].PhysicalRange.Stepping =
+ Framing -> FramingItem [0].FramingRange.Range.Stepping =
+ 0;
+
+ PinDescriptor.AllocatorFraming = Framing;
+
+ PinDescriptor.PinDescriptor.DataRangesCount = 1;
+ PinDescriptor.PinDescriptor.DataRanges =
+ reinterpret_cast <const PKSDATARANGE *> (DataRanges);
+
+ //
+ // Create the actual pin. We need to save the pin id returned. It
+ // is how we refer to the audio pin in the future.
+ //
+ Status = KsFilterCreatePinFactory (
+ m_Filter,
+ &PinDescriptor,
+ &m_AudioPinId
+ );
+
+ }
+
+ return Status;
+
+}
+
+
+/*************************************************/
+
+
+void
+CCaptureFilter::
+StartDPC (
+ IN LONGLONG TimerInterval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the timer DPC running at a specified interval. The
+ specified interval is the amount of time between triggering frame captures.
+ Once this routine returns, the timer DPC should be running and attempting
+ to trigger processing on the capture filter as a whole.
+
+Arguments:
+
+ TimerInterval -
+ The amount of time between timer DPC's. This is the amount of delay
+ between one frame and the next. Since the DPC is driven off the
+ video capture pin, this should be an amount of time specified by
+ the video info header.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ //
+ // Initialize any variables used by the timer DPC.
+ //
+ m_Tick = 0;
+ m_TimerInterval = TimerInterval;
+ KeQuerySystemTime (&m_StartTime);
+
+ //
+ // Schedule the DPC to happen one frame time from now.
+ //
+ LARGE_INTEGER NextTime;
+ NextTime.QuadPart = m_StartTime.QuadPart + m_TimerInterval;
+
+ KeSetTimer (&m_Timer, NextTime, &m_TimerDpc);
+
+}
+
+/*************************************************/
+
+
+void
+CCaptureFilter::
+StopDPC (
+ )
+
+/*++
+
+Routine Description:
+
+ Stop the timer DPC from firing. After this routine returns, there is
+ a guarantee that no more timer DPC's will fire and no more processing
+ attempts will occur. Note that this routine does block.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ m_StoppingDPC = TRUE;
+
+ KeWaitForSingleObject (
+ &m_StopDPCEvent,
+ Suspended,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ NT_ASSERT (m_StoppingDPC == FALSE);
+
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+LONGLONG
+CCaptureFilter::
+GetTimerInterval (
+ )
+
+/*++
+
+Routine Description:
+
+ Return the timer interval being used to fire DPC's.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ The timer interval being used to fire DPC's.
+
+--*/
+
+{
+
+ return m_TimerInterval;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCaptureFilter::
+Process (
+ IN PKSPROCESSPIN_INDEXENTRY ProcessPinsIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This is the processing function for the capture filter. It is responsible
+ for copying synthesized image data into the image buffers. The timer DPC
+ will attempt to trigger processing (and hence indirectly call this routine)
+ to trigger a capture.
+
+Arguments:
+
+ ProcessPinsIndex -
+ Contains a pointer to an array of process pin index entries. This
+ array is indexed by pin ID. An index entry indicates the number
+ of pin instances for the corresponding filter type and points to the
+ first corresponding process pin structure in the ProcessPins array.
+ This allows the process pin structure to be quickly accessed by pin ID
+ when the number of instances per type is not known in advance.
+
+Return Value:
+
+ Indication of whether more processing should be done if frames are
+ available. A value of STATUS_PENDING indicates that processing should not
+ continue even if frames are available on all required queues.
+ STATUS_SUCCESS indicates processing should continue if frames are available
+ on all required queues.
+
+--*/
+
+{
+
+ //
+ // The audio and video pins do not necessarily need to exist (one could
+ // be capturing video w/o audio or vice-versa). Do not assume the
+ // existence by checking Index[ID].Pins[0]. Always check the Count
+ // field first.
+ //
+ PKSPROCESSPIN VideoPin = NULL;
+ CCapturePin *VidCapPin = NULL;
+ PKSPROCESSPIN AudioPin = NULL;
+ CCapturePin *AudCapPin = NULL;
+ ULONG VidCapDrop = 0;
+ ULONG AudCapDrop = (ULONG)-1;
+
+ if (ProcessPinsIndex [VIDEO_PIN_ID].Count != 0) {
+ //
+ // There can be at most one instance via the possible instances field,
+ // so the below is safe.
+ //
+ VideoPin = ProcessPinsIndex [VIDEO_PIN_ID].Pins [0];
+ VidCapPin =
+ reinterpret_cast <CCapturePin *> (VideoPin -> Pin -> Context);
+ }
+
+ //
+ // The audio pin only exists on the filter if the wave object does.
+ // They're tied together at filter create time.
+ //
+ if (m_WaveObject && ProcessPinsIndex [m_AudioPinId].Count != 0) {
+ //
+ // There can be at most one instance via the possible instances field,
+ // so the below is safe.
+ //
+ AudioPin = ProcessPinsIndex [m_AudioPinId].Pins [0];
+ AudCapPin =
+ reinterpret_cast <CCapturePin *> (AudioPin -> Pin -> Context);
+ }
+
+ if (VidCapPin) {
+ VidCapDrop = VidCapPin -> QueryFrameDrop ();
+ }
+
+ if (AudCapPin) {
+ AudCapDrop = AudCapPin -> QueryFrameDrop ();
+ }
+
+ //
+ // If there's a video pin around, trigger capture on it. We call the
+ // pin object to actually synthesize the frame; however, we could just
+ // as easily have done that here.
+ //
+ if (VidCapPin) {
+ //
+ // This is used to notify the pin how many frames have been dropped
+ // on each pin to allow that to be rendered.
+ //
+ VidCapPin -> NotifyDrops (VidCapDrop, AudCapDrop);
+ VidCapPin -> CaptureFrame (VideoPin, m_Tick);
+ }
+
+ //
+ // If there's an audio pin around, trigger capture on it. Since the
+ // audio capture pin isn't necessary for capture, there might be an
+ // instance which is connected and is in the stop state when we get
+ // called [there will never be one in acquire or pause since we specify
+ // KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY]. Don't bother triggering capture
+ // on the pin unless it's actually running.
+ //
+ // On DX8.x platforms, the Pin -> ClientState field does not exist.
+ // Hence, we check the state we maintain ourselves. DeviceState is not
+ // the right thing to check here.
+ //
+ if (AudCapPin && AudCapPin -> GetState () == KSSTATE_RUN) {
+ AudCapPin -> CaptureFrame (AudioPin, m_Tick);
+ }
+
+ //
+ // STATUS_PENDING indicates that we do not want to be called back if
+ // there is more data available. We only want to trigger processing
+ // (and hence capture) on the timer ticks.
+ //
+ return STATUS_PENDING;
+
+}
+
+/*************************************************/
+
+
+void
+CCaptureFilter::
+TimerDpc (
+ )
+
+/*++
+
+Routine Description:
+
+ This is the timer function for our timer (bridged to from TimerRoutine
+ in the context of the appropriate CCaptureFilter). It is called every
+ 1/Nth of a second as specified in StartDpc() to trigger capture of a video
+ frame.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ //
+ // Increment the tick counter. This keeps track of the number of ticks
+ // that have happened since the timer DPC started running. Note that the
+ // timer DPC starts running before the pins go into run state and this
+ // variable gets incremented from the original start point.
+ //
+ m_Tick++;
+
+ //
+ // Trigger processing on the filter. Since the filter is prepared to
+ // run at DPC, we do not request asynchronous processing. Thus, if
+ // possible, processing will occur in the context of this DPC.
+ //
+ KsFilterAttemptProcessing (m_Filter, FALSE);
+
+ //
+ // Reschedule the timer if the hardware isn't being stopped.
+ //
+ if (!m_StoppingDPC) {
+
+ LARGE_INTEGER NextTime;
+
+ NextTime.QuadPart = m_StartTime.QuadPart +
+ (m_TimerInterval * (m_Tick + 1));
+
+ KeSetTimer (&m_Timer, NextTime, &m_TimerDpc);
+
+ } else {
+
+ //
+ // If another thread is waiting on the DPC to stop running, raise
+ // the stop event and clear the flag.
+ //
+ m_StoppingDPC = FALSE;
+ KeSetEvent (&m_StopDPCEvent, IO_NO_INCREMENT, FALSE);
+
+ }
+
+}
+
+/**************************************************************************
+
+ 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)
+};
+
+//
+// CaptureFilterPinDescriptors:
+//
+// The list of pin descriptors on the capture filter.
+//
+const
+KSPIN_DESCRIPTOR_EX
+CaptureFilterPinDescriptors [CAPTURE_FILTER_PIN_COUNT] = {
+ //
+ // Video Capture Pin
+ //
+ {
+ &VideoCapturePinDispatch,
+ NULL,
+ {
+ NULL, // Interfaces (NULL, 0 == default)
+ 0,
+ NULL, // Mediums (NULL, 0 == default)
+ 0,
+ SIZEOF_ARRAY (VideoCapturePinDataRanges), // Range Count
+ VideoCapturePinDataRanges, // Ranges
+ KSPIN_DATAFLOW_OUT, // Dataflow
+ KSPIN_COMMUNICATION_BOTH, // Communication
+ &KSCATEGORY_VIDEO, // Category
+ &g_PINNAME_VIDEO_CAPTURE, // Name
+ 0 // Reserved
+ },
+ KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING | // Flags
+ KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING |
+ KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY,
+ 1, // Instances Possible
+ 1, // Instances Necessary
+ &VideoCapturePinAllocatorFraming, // Allocator Framing
+ reinterpret_cast <PFNKSINTERSECTHANDLEREX>
+ (CVideoCapturePin::IntersectHandler)
+ }
+};
+
+//
+// CaptureFilterDispatch:
+//
+// This is the dispatch table for the capture filter. It provides notification
+// of creation, closure, processing, and resets.
+//
+const
+KSFILTER_DISPATCH
+CaptureFilterDispatch = {
+ CCaptureFilter::DispatchCreate, // Filter Create
+ NULL, // Filter Close
+ CCaptureFilter::DispatchProcess, // 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
+ KSFILTER_FLAG_DISPATCH_LEVEL_PROCESSING,// Flags
+ &KSNAME_Filter, // Reference GUID
+ DEFINE_KSFILTER_PIN_DESCRIPTORS (CaptureFilterPinDescriptors),
+ DEFINE_KSFILTER_CATEGORIES (CaptureFilterCategories),
+
+ DEFINE_KSFILTER_NODE_DESCRIPTORS_NULL,
+ DEFINE_KSFILTER_DEFAULT_CONNECTIONS,
+
+ NULL // Component ID
+};
+
+
diff --git a/AVStream/avssamp/README.md b/AVStream/avssamp/README.md
new file mode 100644
index 00000000..6188c5b3
--- /dev/null
+++ b/AVStream/avssamp/README.md
@@ -0,0 +1,51 @@
+AVStream filter-centric simulated capture sample driver (Avssamp)
+=================================================================
+
+The AVStream filter-centric simulated capture sample driver (Avssamp) provides a filter-centric [AVStream](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554240) capture driver with functional audio. This streaming media driver performs video captures at 320 x 240 pixel resolution in RGB24 or YUV422 format while playing a user-provided Pulse Code Modulation (PCM) wave audio file in a loop. The sample demonstrates how to write a filter-centric AVStream minidriver.
+
+
+Installation instructions
+-------------------------
+
+1. Copy AVssamp.inf to a directory, for example, C:\\Avstream\\.
+2. In this directory, create a new subdirectory named objfre\_x86 if the target operating system is x86-based, or objfre\_amd64 for an x64-based target operating system, for example, C:\\AVstream\\objfre\_x86\\.
+3. Copy the processor-appropriate Avssamp.sys file to the objfre\_\* directory.
+4. Start a command prompt with administrator privilege and run the processor-specific WDK tool Devcon.exe to launch the installation. For example:
+
+ `C:\WinDDK\7600.16384.0\tools\devcon\i386\devcon.exe install C:\AVstream\avssamp.inf SW\{20698827-7099-4c4e-861A-4879D639A35F}`
+
+Programming Tour
+----------------
+
+[**DriverEntry**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff558717) in Avssamp.cpp is the initial point of entry into the driver. This routine passes control to AVStream by calling [**KsInitializeDriver**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff562683). 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.
+
+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 capture pin. Audio.cpp contains the **KSPIN\_DESCRIPTOR\_EX** structure for the audio capture pin. This pin is dynamically created only if C:\\avssamp.wav exists and is a valid and readable PCM format wave file.
+
+The filter dispatch structure [**KSFILTER\_DISPATCH**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff562554) in Filter.cpp provides dispatches to create and process data. The **DispatchProcess** method is defined inline in Filter.h. It calls the **Process** method in Filter.cpp in the context of the **CCaptureFilter** class. Be aware that the process dispatch is provided in **KSFILTER\_DISPATCH** because this sample is filter-centric.
+
+Audio.cpp lays out a [**KSPIN\_DISPATCH**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff563535) pin dispatch structure, which contains the dispatch table for the audio pin. Be aware that the **Process** member of this structure is **NULL** because the sample is filter-centric. Similarly, Video.cpp contains the **KSPIN\_DISPATCH** structure for the video capture pin, again with the **Process** member set to **NULL**.
+
+For more information, see the comments in all .cpp files.
+
+File Manifest
+-------------
+
+File | Description
+-----|----------
+Audio.cpp | Audio capture pin implementation.
+Audio.h | Header file for Audio.cpp.
+Avssamp.cpp | Main file for the AVStream filter-centric sample.
+Avssamp.h | Main header for the AVStream filter-centric sample.
+Avssamp.inf | Installation information for the AVStream sample driver (avssamp.sys).
+Capture.cpp | Capture pin implementation for all capture pins on the sample filter.
+Capture .h | Capture pin level header for all capture pins on the sample filter.
+Filter.cpp | Capture filter implementation (including frame synthesis) for the fake capture filter.
+Filter.h | Filter level header for the filter-centric capture filter.
+Image.cpp | 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.
+Image.h | Image synthesis and overlay header.
+Purecall.h | _purecall stub necessary for virtual function usage in drivers.
+Video.cpp | Video capture pin implementation.
+Video.h | Video capture pin header.
+Wave.cpp | Wave object implementation
+Wave.h | Wave object header
+
diff --git a/AVStream/avssamp/audio.cpp b/AVStream/avssamp/audio.cpp
new file mode 100644
index 00000000..cc35f869
--- /dev/null
+++ b/AVStream/avssamp/audio.cpp
@@ -0,0 +1,655 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ audio.cpp
+
+ Abstract:
+
+ This file contains the audio capture pin implementation.
+
+ History:
+
+ created 6/28/01
+
+**************************************************************************/
+
+#include "avssamp.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+NTSTATUS
+CAudioCapturePin::
+DispatchCreate (
+ IN PKSPIN Pin,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Create a new audio capture pin. This is the creation dispatch for
+ the audio capture pin.
+
+Arguments:
+
+ Pin -
+ The pin being created
+
+ Irp -
+ The creation Irp
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ CAudioCapturePin *CapPin = new (NonPagedPool) CAudioCapturePin (Pin);
+ CCapturePin *BasePin = static_cast <CCapturePin *> (CapPin);
+
+ 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> (BasePin),
+ reinterpret_cast <PFNKSFREE> (CCapturePin::BagCleanup)
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ delete CapPin;
+ } else {
+ Pin -> Context = reinterpret_cast <PVOID> (BasePin);
+ }
+
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CAudioCapturePin::
+Acquire (
+ IN KSSTATE FromState
+ )
+
+/*++
+
+Routine Description:
+
+ Called when the pin transitions into acquire, this gets and releases
+ our hold on the wave object we use to synthesize audio streams.
+
+Arguments:
+
+ FromState -
+ The state the pin is transitioning away from
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (FromState == KSSTATE_STOP) {
+ //
+ // On the transition into acquire from stop, get ahold of the
+ // wave object we're synthesizing from.
+ //
+ m_WaveObject = m_ParentFilter -> GetWaveObject ();
+ NT_ASSERT (m_WaveObject);
+
+ //
+ // There must be a wave object or something is really wrong.
+ //
+ if (!m_WaveObject) {
+ Status = STATUS_INTERNAL_ERROR;
+ } else {
+ m_WaveObject -> Reset ();
+ }
+
+ } else {
+ //
+ // Ensure we hold no reference on the wave object.
+ //
+ m_WaveObject = NULL;
+
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CAudioCapturePin::
+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:
+
+ The intersect handler for the audio capture pin. This is really quite
+ simple because the audio pin only exposes the number of channels,
+ sampling frequency, etc... that the wave file it is synthesizing from
+ contains.
+
+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();
+
+ //
+ // Verify that the inpassed range is valid size.
+ //
+ if (CallerDataRange -> FormatSize < sizeof (KSDATARANGE_AUDIO)) {
+ return STATUS_NO_MATCH;
+ }
+
+ //
+ // Because the only range we expose is such that it will match
+ // KSDATARANGE_AUDIO, it is safe to interpret the data structures as
+ // KSDATARANGE_AUDIO. This is due to the fact that AVStream will have
+ // prematched the GUIDs for us.
+ //
+ PKSDATARANGE_AUDIO CallerAudioRange =
+ reinterpret_cast <PKSDATARANGE_AUDIO> (CallerDataRange);
+
+ PKSDATARANGE_AUDIO DescriptorAudioRange =
+ reinterpret_cast <PKSDATARANGE_AUDIO> (DescriptorDataRange);
+
+ //
+ // We are returning a KSDATAFORMAT_WAVEFORMATEX. Specify such if a size
+ // query happens.
+ //
+ if (BufferSize == 0) {
+ *DataSize = sizeof (KSDATAFORMAT_WAVEFORMATEX);
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (BufferSize < sizeof (KSDATAFORMAT_WAVEFORMATEX)) {
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Match the blocks. We only support one format (not really a range), so
+ // this intersection aught to be really simple. It's more of a check
+ // if the format we are going to use intersects somewhere in
+ // CallerAudioRange.
+ //
+ if (DescriptorAudioRange -> MaximumChannels >
+ CallerAudioRange -> MaximumChannels ||
+ DescriptorAudioRange -> MinimumBitsPerSample <
+ CallerAudioRange -> MinimumBitsPerSample ||
+ DescriptorAudioRange -> MinimumBitsPerSample >
+ CallerAudioRange -> MaximumBitsPerSample ||
+ DescriptorAudioRange -> MinimumSampleFrequency <
+ CallerAudioRange -> MinimumSampleFrequency ||
+ DescriptorAudioRange -> MinimumSampleFrequency >
+ CallerAudioRange -> MaximumSampleFrequency) {
+
+ //
+ // If the descriptor's "range" (more of a single format specified
+ // in a range) doesn't intersect the caller's, no match the call.
+ //
+ *DataSize = sizeof (KSDATAFORMAT_WAVEFORMATEX);
+ return STATUS_NO_MATCH;
+
+ }
+
+ //
+ // Build the format.
+ //
+ PKSDATAFORMAT_WAVEFORMATEX WaveFormat =
+ reinterpret_cast <PKSDATAFORMAT_WAVEFORMATEX> (Data);
+
+ RtlCopyMemory (
+ &WaveFormat -> DataFormat,
+ &DescriptorAudioRange -> DataRange,
+ sizeof (KSDATAFORMAT)
+ );
+
+ WaveFormat -> WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
+ WaveFormat -> WaveFormatEx.nChannels =
+ (WORD)DescriptorAudioRange -> MaximumChannels;
+ WaveFormat -> WaveFormatEx.nSamplesPerSec =
+ DescriptorAudioRange -> MaximumSampleFrequency;
+ WaveFormat -> WaveFormatEx.wBitsPerSample =
+ (WORD)DescriptorAudioRange -> MaximumBitsPerSample;
+ WaveFormat -> WaveFormatEx.nBlockAlign =
+ (WaveFormat -> WaveFormatEx.wBitsPerSample / 8) *
+ WaveFormat -> WaveFormatEx.nChannels;
+ WaveFormat -> WaveFormatEx.nAvgBytesPerSec =
+ WaveFormat -> WaveFormatEx.nBlockAlign *
+ WaveFormat -> WaveFormatEx.nSamplesPerSec;
+ WaveFormat -> WaveFormatEx.cbSize = 0;
+ WaveFormat -> DataFormat.SampleSize =
+ WaveFormat -> WaveFormatEx.nBlockAlign;
+
+ WaveFormat -> DataFormat.FormatSize =
+ *DataSize = sizeof (KSDATAFORMAT_WAVEFORMATEX);
+
+ return STATUS_SUCCESS;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CAudioCapturePin::
+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();
+
+ //
+ // This pin does not accept any format changes. It is fixed format based
+ // on what the wave file we're synthesizing from is. Thus, we don't
+ // need to worry about this being called in any context except pin
+ // creation (KSPIN_FLAG_FIXED_FORMAT ensures this). Knowing that the
+ // format already is a GUID match for the range and we only have one
+ // range, the interpretation without any guid checks is safe.
+ //
+ NT_ASSERT (!OldFormat);
+
+ const KSDATARANGE_AUDIO *DataRangeAudio =
+ reinterpret_cast <const KSDATARANGE_AUDIO *> (DataRange);
+
+ //
+ // Verify the format is the right size.
+ //
+ if (Pin -> ConnectionFormat -> FormatSize <
+ sizeof (KSDATAFORMAT_WAVEFORMATEX)) {
+
+ return STATUS_NO_MATCH;
+ }
+
+ PKSDATAFORMAT_WAVEFORMATEX WaveFormat =
+ reinterpret_cast <PKSDATAFORMAT_WAVEFORMATEX> (
+ Pin -> ConnectionFormat
+ );
+
+ //
+ // This is not an intersection, but rather a direct comparison due to
+ // the fact that we're fixed to a single format and do not really have
+ // a range.
+ //
+ if (WaveFormat -> WaveFormatEx.wFormatTag != WAVE_FORMAT_PCM ||
+ WaveFormat -> WaveFormatEx.nChannels !=
+ DataRangeAudio -> MaximumChannels ||
+ WaveFormat -> WaveFormatEx.nSamplesPerSec !=
+ DataRangeAudio -> MaximumSampleFrequency ||
+ WaveFormat -> WaveFormatEx.wBitsPerSample !=
+ DataRangeAudio -> MaximumBitsPerSample) {
+
+ return STATUS_NO_MATCH;
+
+ }
+
+ //
+ // The format passes consideration. Allow the pin creation with this
+ // particular format.
+ //
+ return STATUS_SUCCESS;
+
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+NTSTATUS
+CAudioCapturePin::
+CaptureFrame (
+ IN PKSPROCESSPIN ProcessPin,
+ IN ULONG Tick
+ )
+
+/*++
+
+Routine Description:
+
+ Called to synthesize a frame of audio data from the wave object.
+
+Arguments:
+
+ ProcessPin -
+ The process pin from the filter's process pins index
+
+ Tick -
+ The tick counter from the filter (the number of DPC's that have
+ happened since the DPC timer started). Note that the DPC timer
+ starts at pause and capture starts at run.
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ NT_ASSERT (ProcessPin -> Pin == m_Pin);
+
+ //
+ // Increment the frame number. This is the total count of frames which
+ // have attempted capture.
+ //
+ m_FrameNumber++;
+
+ //
+ // Find out how much time worth of audio data to synthesize into
+ // the buffer a buffer (or how much time to skip if there are no available
+ // capture buffers).
+ //
+ LONGLONG TimerInterval = m_ParentFilter -> GetTimerInterval ();
+
+ //
+ // Since this pin is KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING, it
+ // means that we do not require frames available in order to process.
+ // This means that this routine can get called from our DPC with no
+ // buffers available to capture into. In this case, we increment our
+ // dropped frame counter and skip forward into the audio stream.
+ //
+ if (ProcessPin -> BytesAvailable) {
+ //
+ // Synthesize a fixed amount of audio data based on the timer interval.
+ //
+ ULONG BytesUsed = m_WaveObject -> SynthesizeFixed (
+ TimerInterval,
+ ProcessPin -> Data,
+ ProcessPin -> BytesAvailable
+ );
+
+ ProcessPin -> BytesUsed = BytesUsed;
+ ProcessPin -> Terminate = TRUE;
+
+ //
+ // Time stamp the packet if there is a clock assigned.
+ //
+ if (m_Clock) {
+ PKSSTREAM_HEADER StreamHeader =
+ ProcessPin -> StreamPointer -> StreamHeader;
+
+ StreamHeader -> PresentationTime.Time = m_Clock -> GetTime ();
+ StreamHeader -> PresentationTime.Numerator =
+ StreamHeader -> PresentationTime.Denominator = 1;
+ StreamHeader -> OptionsFlags |=
+ KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
+ }
+
+ } else {
+ m_DroppedFrames++;
+
+ //
+ // Since we've skipped an audio frame, inform the wave object to
+ // skip forward this much.
+ //
+ m_WaveObject -> SkipFixed (TimerInterval);
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+/**************************************************************************
+
+ DESCRIPTOR / DISPATCH LAYOUT
+
+**************************************************************************/
+
+//
+// AudioCapturePinDispatch:
+//
+// This is the dispatch table for the capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc...
+//
+const
+KSPIN_DISPATCH
+AudioCapturePinDispatch = {
+ CAudioCapturePin::DispatchCreate, // Pin Create
+ NULL, // Pin Close
+ NULL, // Pin Process
+ NULL, // Pin Reset
+ CAudioCapturePin::DispatchSetFormat, // Pin Set Data Format
+ CCapturePin::DispatchSetState, // Pin Set Device State
+ NULL, // Pin Connect
+ NULL, // Pin Disconnect
+ NULL, // Clock Dispatch
+ NULL // Allocator Dispatch
+};
+
+//
+// AudioDefaultAllocatorFraming:
+//
+// A default framing for the audio pin. In order for this to work properly,
+// the frame size must be at least 1/fps * bytes_per_sec large. Otherwise,
+// the audio stream will fall behind. This is dynamically adjusted when
+// the actual pin is created.
+//
+DECLARE_SIMPLE_FRAMING_EX (
+ AudioDefaultAllocatorFraming,
+ STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED),
+ KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
+ KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY,
+ 25,
+ 0,
+ 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE
+ );
+
+//
+// g_PINNAME_AUDIO_CAPTURE:
+//
+// A GUID identifying the name of the audio capture pin. I use the standard
+// STATIC_PINNAME_VIDEO_CAPTURE for the video capture pin, but a custom name
+// as defined in avssamp.inf for the audio capture pin.
+//
+GUID g_PINNAME_AUDIO_CAPTURE =
+ {0xba1184b9, 0x1fe6, 0x488a, 0xae, 0x78, 0x6e, 0x99, 0x7b, 0x2, 0xca, 0xea};
+
+//
+// AudioPinDescriptorTemplate:
+//
+// The template for the audio pin descriptor. The audio pin on this filter
+// is created dynamically -- if and only if c:\avssamp.wav exists and is
+// a valid and readable wave file.
+//
+const
+KSPIN_DESCRIPTOR_EX
+AudioPinDescriptorTemplate = {
+ //
+ // Audio Capture Pin
+ //
+ &AudioCapturePinDispatch,
+ NULL,
+ {
+ NULL, // Interfaces (NULL, 0 == default)
+ 0,
+ NULL, // Mediums (NULL, 0 == default)
+ 0,
+ 0, // Range count (filled in later)
+ NULL, // Ranges (filled in later)
+ KSPIN_DATAFLOW_OUT, // Dataflow
+ KSPIN_COMMUNICATION_BOTH, // Communication
+ &KSCATEGORY_AUDIO, // Category
+ &g_PINNAME_AUDIO_CAPTURE, // Name
+ 0 // Reserved
+ },
+ KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING | // Flags
+ KSPIN_FLAG_DO_NOT_INITIATE_PROCESSING |
+ KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY |
+ KSPIN_FLAG_FIXED_FORMAT,
+ 1, // Instances Possible
+ 0, // Instances Necessary
+ &AudioDefaultAllocatorFraming, // Allocator Framing (filled later)
+ reinterpret_cast <PFNKSINTERSECTHANDLEREX> // Intersect Handler
+ (CAudioCapturePin::IntersectHandler)
+};
+
diff --git a/AVStream/avssamp/audio.h b/AVStream/avssamp/audio.h
new file mode 100644
index 00000000..0240ddc8
--- /dev/null
+++ b/AVStream/avssamp/audio.h
@@ -0,0 +1,150 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ audio.h
+
+ Abstract:
+
+ This file contains the audio capture pin header.
+
+ History:
+
+ created 6/28/01
+
+**************************************************************************/
+
+class CAudioCapturePin :
+ public CCapturePin
+
+{
+
+private:
+
+ //
+ // The wave object used to synthesize audio data.
+ //
+ CWaveObject *m_WaveObject;
+
+public:
+
+ //
+ // CAudioCapturePin():
+ //
+ // Construct a new audio capture pin.
+ //
+ CAudioCapturePin (
+ IN PKSPIN Pin
+ ) : CCapturePin (Pin)
+ {
+ }
+
+ //
+ // ~CAudioCapturePin():
+ //
+ // Destruct an audio capture pin.
+ //
+ ~CAudioCapturePin (
+ )
+ {
+ }
+
+ //
+ // Acquire():
+ //
+ // Called when the audio capture pin is transitioning into the acquire
+ // state (from either stop or pause). This routine will get ahold of
+ // the wave object from the filter.
+ //
+ virtual
+ NTSTATUS
+ Acquire (
+ IN KSSTATE FromState
+ );
+
+ //
+ // CaptureFrame():
+ //
+ // This is called when the filter processes and wants to trigger processing
+ // of an audio frame. The routine will compute how far into the stream
+ // we've progressed and ask the filter's wave object to copy enough
+ // "synthesized" audio data from the wave object in order to reach
+ // the position.
+ //
+ virtual
+ NTSTATUS
+ CaptureFrame (
+ IN PKSPROCESSPIN ProcessPin,
+ IN ULONG Tick
+ );
+
+ /*************************************************
+
+ Dispatch Functions
+
+ *************************************************/
+
+ //
+ // DispatchCreate():
+ //
+ // This is the creation dispatch for the audio capture pin on the filter.
+ // It creates the CAudioCapturePin, associates it with the AVStream pin
+ // object and bags the class object for automatic cleanup when the
+ // pin is closed.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ IN PKSPIN Pin,
+ IN PIRP Irp
+ );
+
+ //
+ // 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
+ );
+
+ //
+ // 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
+ );
+
+
+};
diff --git a/AVStream/avssamp/avssamp.cpp b/AVStream/avssamp/avssamp.cpp
new file mode 100644
index 00000000..5a2c2b77
--- /dev/null
+++ b/AVStream/avssamp/avssamp.cpp
@@ -0,0 +1,243 @@
+/**************************************************************************
+
+AVStream Filter-Centric Sample
+
+Copyright (c) 1999 - 2001, Microsoft Corporation
+
+File:
+
+avssamp.cpp
+
+Abstract:
+
+This is the main file for the filter-centric sample.
+
+History:
+
+created 6/18/01
+
+**************************************************************************/
+
+#include "avssamp.h"
+
+/**************************************************************************
+
+INITIALIZATION CODE
+
+**************************************************************************/
+
+
+extern "C" DRIVER_INITIALIZE DriverEntry;
+
+PVOID operator new
+(
+ size_t iSize,
+ _When_((poolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+ POOL_TYPE poolType
+ )
+{
+ PVOID result = ExAllocatePoolWithTag(poolType, iSize, 'wNCK');
+
+ if (result) {
+ RtlZeroMemory(result, iSize);
+ }
+
+ return result;
+}
+
+PVOID operator new
+(
+ size_t iSize,
+ _When_((poolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+ POOL_TYPE poolType,
+ ULONG tag
+ )
+{
+ PVOID result = ExAllocatePoolWithTag(poolType, iSize, tag);
+
+ if (result) {
+ RtlZeroMemory(result, iSize);
+ }
+
+ return result;
+}
+
+/*++
+
+Routine Description:
+
+Array delete() operator.
+
+Arguments:
+
+pVoid -
+The memory to free.
+
+Return Value:
+
+None
+
+--*/
+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
+
+--*/
+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
+
+--*/
+void __cdecl operator delete[]
+(
+ void *pVoid,
+ size_t /*size*/
+ )
+{
+ if (pVoid)
+ {
+ ExFreePool(pVoid);
+ }
+}
+
+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
+ );
+
+}
+
+/**************************************************************************
+
+DESCRIPTOR AND DISPATCH LAYOUT
+
+**************************************************************************/
+
+//
+// FilterDescriptors:
+//
+// The table of filter descriptors that this device supports. Each one of
+// these will be used as a template to create a filter-factory on the device.
+//
+DEFINE_KSFILTER_DESCRIPTOR_TABLE(FilterDescriptors) {
+ &CaptureFilterDescriptor
+};
+
+//
+// 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 = {
+ //
+ // Since this is a software sample (filter-centric filters usually are
+ // software kinds of transforms), we really don't care about device level
+ // notifications and work. The default behavior done on behalf of us
+ // by AVStream will be quite sufficient.
+ //
+ NULL,
+ SIZEOF_ARRAY(FilterDescriptors),
+ FilterDescriptors,
+ KSDEVICE_DESCRIPTOR_VERSION
+};
+
diff --git a/AVStream/avssamp/avssamp.h b/AVStream/avssamp/avssamp.h
new file mode 100644
index 00000000..7d0bd7c3
--- /dev/null
+++ b/AVStream/avssamp/avssamp.h
@@ -0,0 +1,252 @@
+/**************************************************************************
+
+AVStream Filter-Centric Sample
+
+Copyright (c) 2001, Microsoft Corporation
+
+File:
+
+avssamp.h
+
+Abstract:
+
+AVStream Filter-Centric Sample header file. This is the main
+header.
+
+History:
+
+created 6/18/01
+
+**************************************************************************/
+
+/*************************************************
+
+Standard Includes
+
+*************************************************/
+
+extern "C" {
+#include <wdm.h>
+}
+
+#include <windef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ntstrsafe.h>
+#define NOBITMAP
+#include <mmreg.h>
+#undef NOBITMAP
+#include <unknown.h>
+#include <ks.h>
+#include <ksmedia.h>
+#pragma warning (disable : 4100 4101 4131 4127 4189 4701 4706)
+/*************************************************
+
+Misc Definitions
+
+*************************************************/
+
+#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_YUV422 mmioFOURCC('U', 'Y', 'V', 'Y')
+
+//
+// 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 2
+
+#define AVSSMP_POOLTAG 'sSVA'
+
+/*************************************************
+
+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];
+
+//
+// video.cpp externs:
+//
+extern
+const
+KSALLOCATOR_FRAMING_EX
+VideoCapturePinAllocatorFraming;
+
+extern
+const
+KSPIN_DISPATCH
+VideoCapturePinDispatch;
+
+extern
+const
+PKSDATARANGE
+VideoCapturePinDataRanges[CAPTURE_PIN_DATA_RANGE_COUNT];
+
+//
+// audio.cpp externs:
+//
+extern
+const
+KSPIN_DESCRIPTOR_EX
+AudioPinDescriptorTemplate;
+
+//
+// avssamp.cpp externs:
+//
+extern
+const
+KSDEVICE_DESCRIPTOR
+CaptureDeviceDescriptor;
+
+#ifndef _NEW_DELETE_OPERATORS_
+#define _NEW_DELETE_OPERATORS_
+
+PVOID operator new
+(
+ size_t iSize,
+ _When_((poolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+ POOL_TYPE poolType
+ );
+
+PVOID operator new
+(
+ size_t iSize,
+ _When_((poolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+ POOL_TYPE poolType,
+ ULONG tag
+ );
+
+/*++
+
+Routine Description:
+
+Array delete() operator.
+
+Arguments:
+
+pVoid -
+The memory to free.
+
+Return Value:
+
+None
+
+--*/
+void
+__cdecl
+operator delete[](
+ PVOID pVoid
+ );
+
+/*++
+
+Routine Description:
+
+Sized delete() operator.
+
+Arguments:
+
+pVoid -
+The memory to free.
+
+size -
+The size of the memory to free.
+
+Return Value:
+
+None
+
+--*/
+void __cdecl operator delete
+(
+ void *pVoid,
+ size_t /*size*/
+ );
+
+/*++
+
+Routine Description:
+
+Sized delete[]() operator.
+
+Arguments:
+
+pVoid -
+The memory to free.
+
+size -
+The size of the memory to free.
+
+Return Value:
+
+None
+
+--*/
+void __cdecl operator delete[]
+(
+ void *pVoid,
+ size_t /*size*/
+ );
+
+#endif // _NEW_DELETE_OPERATORS_
+
+/*************************************************
+
+Internal Includes
+
+*************************************************/
+
+#include "image.h"
+#include "wave.h"
+#include "filter.h"
+#include "capture.h"
+#include "video.h"
+#include "audio.h"
diff --git a/AVStream/avssamp/avssamp.inf b/AVStream/avssamp/avssamp.inf
new file mode 100644
index 00000000..62db5009
--- /dev/null
+++ b/AVStream/avssamp/avssamp.inf
@@ -0,0 +1,93 @@
+; Copyright (c) Microsoft Corporation. All rights reserved.
+;
+; avssamp.INF -- This file contains installation information for the filter-based
+; AVStream sample driver avssamp.sys
+;
+; Note:
+;
+; This INF expects the following hierarchy in the installation folder:
+;
+; \
+; avssamp.inf
+; avssamp.sys
+;
+
+[Version]
+Signature="$Windows NT$"
+Class=MEDIA
+ClassGUID={4d36e96c-e325-11ce-bfc1-08002be10318}
+Provider=%ProviderName%
+CatalogFile=avssamp.cat
+DriverVer=09/30/2004,1.0.0.0
+
+[SourceDisksNames]
+1000 = %cdname%,,,
+
+[SourceDisksFiles]
+avssamp.sys = 1000
+
+[ControlFlags]
+ExcludeFromSelect=*
+
+[DestinationDirs]
+avssamp.CopyFiles=12
+
+[Manufacturer]
+%ManufacturerName%=Standard,NTamd64,NTx86
+
+;---------------------------------------------------------------
+; The preferred method to install as a Root-enumerated device.
+; NOTE: DO NOT INCLUDE THIS FOR A HARDWARE DRIVER!
+;---------------------------------------------------------------
+
+[DeviceInstall32]
+AddDevice = ROOT\SW\{20698827-7099-4c4e-861A-4879D639A35F},,avssamp_RootEnumInstall
+
+[avssamp_RootEnumInstall]
+HardwareIds = SW\{20698827-7099-4c4e-861A-4879D639A35F}
+;---------------------------------------------------------------
+
+[Standard.NTx86]
+%avssamp.DeviceDesc%=avssamp,SW\{20698827-7099-4c4e-861A-4879D639A35F}
+
+[Standard.NTamd64]
+%avssamp.DeviceDesc%=avssamp,SW\{20698827-7099-4c4e-861A-4879D639A35F}
+
+[avssamp.NT]
+include=ks.inf,kscaptur.inf
+needs=KS.Registration,KSCAPTUR.Registration.NT
+CopyFiles=avssamp.CopyFiles
+
+[avssamp.CopyFiles]
+avssamp.sys
+
+[avssamp.NT.Services]
+AddService=avssamp, 0x00000002, avssamp.ServiceInstall
+
+[avssamp.ServiceInstall]
+DisplayName=%avssamp.DeviceDesc%
+ServiceType=%SERVICE_KERNEL_DRIVER%
+StartType=%SERVICE_DEMAND_START%
+ErrorControl=%SERVICE_ERROR_NORMAL%
+ServiceBinary=%12%\avssamp.sys
+
+[Strings]
+; non-localizable
+Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}"
+avssamp.DeviceId="{20698827-7099-4c4e-861A-4879D639A35F}"
+KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
+KSSTRING_Filter="{9B365890-165F-11D0-A195-0020AFD156E4}"
+
+SERVICE_KERNEL_DRIVER=1
+SERVICE_DEMAND_START=3
+SERVICE_ERROR_NORMAL=1
+REG_EXPAND_SZ=0x00020000
+REG_DWORD=0x00010001
+
+;localizable
+ProviderName="TODO-Set-Provider"
+ManufacturerName="TODO-Set-Manufacturer"
+avssamp.DeviceDesc="AVStream Filter-Centric Sample Driver"
+avssamp.Reader.FriendlyName="avssamp Source"
+
+cdname="Disk 1"
diff --git a/AVStream/avssamp/avssamp.rc b/AVStream/avssamp/avssamp.rc
new file mode 100644
index 00000000..b8c7f25b
--- /dev/null
+++ b/AVStream/avssamp/avssamp.rc
@@ -0,0 +1,22 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+//
+// Copyright (C) Microsoft Corporation, 1999 - 1999
+//
+// File: avssamp.rc
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "AVStream Filter-Centric Sample"
+#define VER_INTERNALNAME_STR "avssamp.sys"
+#define VER_ORIGINALFILENAME_STR "avssamp.sys"
+
+#include "common.ver"
+
diff --git a/AVStream/avssamp/avssamp.sln b/AVStream/avssamp/avssamp.sln
new file mode 100644
index 00000000..6b6d6b07
--- /dev/null
+++ b/AVStream/avssamp/avssamp.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}") = "avssamp", "avssamp.vcxproj", "{2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}"
+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
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Debug|Win32.ActiveCfg = Debug|Win32
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Debug|Win32.Build.0 = Debug|Win32
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Release|Win32.ActiveCfg = Release|Win32
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Release|Win32.Build.0 = Release|Win32
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Debug|x64.ActiveCfg = Debug|x64
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Debug|x64.Build.0 = Debug|x64
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Release|x64.ActiveCfg = Release|x64
+ {2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/AVStream/avssamp/avssamp.vcxproj b/AVStream/avssamp/avssamp.vcxproj
new file mode 100644
index 00000000..21c292d2
--- /dev/null
+++ b/AVStream/avssamp/avssamp.vcxproj
@@ -0,0 +1,202 @@
+<?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>{2CCFF21D-0B89-4F39-A4FC-2D0CCC25A071}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{B0781D0B-B397-4C3A-9D2D-6993E9C47C60}</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>avssamp</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>avssamp</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>avssamp</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>avssamp</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="audio.cpp" />
+ <ClCompile Include="avssamp.cpp" />
+ <ClCompile Include="capture.cpp" />
+ <ClCompile Include="filter.cpp" />
+ <ClCompile Include="image.cpp" />
+ <ClCompile Include="purecall.c" />
+ <ClCompile Include="video.cpp" />
+ <ClCompile Include="wave.cpp" />
+ <ResourceCompile Include="avssamp.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/avssamp/avssamp.vcxproj.Filters b/AVStream/avssamp/avssamp.vcxproj.Filters
new file mode 100644
index 00000000..9b056e4d
--- /dev/null
+++ b/AVStream/avssamp/avssamp.vcxproj.Filters
@@ -0,0 +1,52 @@
+<?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>{CA27E3B0-4B55-4FE3-9F26-29F35E3AF608}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{3F416EF8-A9B0-42DF-9371-BAA2CC072CD3}</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>{C2BB2712-8840-4220-B911-1CD96B679F83}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{F67003C9-C833-4C37-97BC-2593BB03BE03}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="audio.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="avssamp.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="capture.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="image.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="purecall.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="video.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wave.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="avssamp.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/avssamp/capture.cpp b/AVStream/avssamp/capture.cpp
new file mode 100644
index 00000000..019b5ad7
--- /dev/null
+++ b/AVStream/avssamp/capture.cpp
@@ -0,0 +1,249 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ capture.cpp
+
+ Abstract:
+
+ This file contains the capture pin implementation for all capture
+ pins on the sample filter.
+
+ History:
+
+ created 5/31/01
+
+**************************************************************************/
+
+#include "avssamp.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+CCapturePin::
+CCapturePin (
+ IN PKSPIN Pin
+ ) :
+ m_Pin (Pin),
+ m_State (KSSTATE_STOP)
+
+/*++
+
+Routine Description:
+
+ Construct a new capture pin. Find out the filter associated with this
+ pin and stash a pointer to our parent filter.
+
+Arguments:
+
+ Pin -
+ The AVStream pin object being created.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ PKSFILTER ParentFilter = KsPinGetParentFilter (Pin);
+
+ m_ParentFilter = reinterpret_cast <CCaptureFilter *> (
+ ParentFilter -> Context
+ );
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CCapturePin::
+SetState (
+ IN KSSTATE ToState,
+ IN KSSTATE FromState
+ )
+
+/*++
+
+Routine Description:
+
+ Called when the pin is transitioning state. This is a bridge from
+ DispatchSetState in the context of the capture pin. The function itself
+ performs basic clock handling (things that all the derived pins would use)
+ and then calls the appropriate method in the derived class.
+
+Arguments:
+
+ FromState -
+ The state the pin is transitioning away from
+
+ ToState -
+ The state the pin is transitioning towards
+
+Return Value:
+
+ Success / Failure of state transition.
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ switch (ToState) {
+
+ case KSSTATE_STOP:
+
+ //
+ // Reset the dropped frame counter.
+ //
+ m_DroppedFrames = 0;
+ m_FrameNumber = 0;
+
+ //
+ // On a transition to stop, the clock will be released.
+ //
+ if (m_Clock) {
+ m_Clock -> Release ();
+ m_Clock = NULL;
+ }
+
+ Status = Stop (FromState);
+ break;
+
+ case KSSTATE_ACQUIRE:
+
+ //
+ // On a transition to acqiure (from stop), the pin queries for
+ // its assigned clock. This can be done either here or at the
+ // transition to pause.
+ //
+ if (FromState == KSSTATE_STOP) {
+
+ Status = KsPinGetReferenceClockInterface (
+ m_Pin,
+ &m_Clock
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ m_Clock = NULL;
+ }
+
+ }
+
+ Status = Acquire (FromState);
+ break;
+
+ case KSSTATE_PAUSE:
+
+ Status = Pause (FromState);
+ break;
+
+ case KSSTATE_RUN:
+
+ Status = Run (FromState);
+ break;
+
+ }
+
+ if (NT_SUCCESS (Status)) {
+ m_State = ToState;
+ }
+
+ return Status;
+
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+ULONG
+CCapturePin::
+QueryFrameDrop (
+ )
+
+/*++
+
+Routine Description:
+
+ Return the number of frames which have been dropped on this pin.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ The number of frames which have been dropped on this pin.
+
+--*/
+
+{
+
+ return m_DroppedFrames;
+
+}
+
+/*************************************************/
+
+
+void
+CCapturePin::
+NotifyDrops (
+ IN ULONG VidDrop,
+ IN ULONG AudDrop
+ )
+
+/*++
+
+Routine Description:
+
+ Stash the number of dropped frames on each pin in this pin to allow
+ this data to be incorporated into any synthesis.
+
+Arguments:
+
+ VidDrop -
+ Number of video frames that have been dropped
+
+ AudDrop -
+ Number of audio frames that have been dropped
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ m_NotifyVidDrop = VidDrop;
+ m_NotifyAudDrop = AudDrop;
+
+}
diff --git a/AVStream/avssamp/capture.h b/AVStream/avssamp/capture.h
new file mode 100644
index 00000000..a761358f
--- /dev/null
+++ b/AVStream/avssamp/capture.h
@@ -0,0 +1,284 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ capture.h
+
+ Abstract:
+
+ This file contains the capture pin level header for all capture pins
+ on the sample filter.
+
+ History:
+
+ created 5/31/01
+
+**************************************************************************/
+
+class CCapturePin
+{
+
+protected:
+
+ //
+ // The clock object associated with this pin.
+ //
+ PIKSREFERENCECLOCK m_Clock;
+
+ //
+ // The AVStream pin object associated with this pin.
+ //
+ PKSPIN m_Pin;
+
+ //
+ // The CCaptureFilter owning this pin.
+ //
+ CCaptureFilter *m_ParentFilter;
+
+ //
+ // The count of dropped frames. The base class will reset this upon
+ // stopping the pin.
+ //
+ ULONG m_DroppedFrames;
+
+ //
+ // The frame number.
+ //
+ ULONGLONG m_FrameNumber;
+
+ //
+ // Notifications as to frame drop. This is used to incorporate frame
+ // drop data into the synthesis.
+ //
+ ULONG m_NotifyVidDrop;
+ ULONG m_NotifyAudDrop;
+
+ //
+ // Current state.
+ //
+ KSSTATE m_State;
+
+public:
+
+ //
+ // CCapturePin():
+ //
+ // Construct a new capture pin.
+ //
+ CCapturePin (
+ IN PKSPIN Pin
+ );
+
+ //
+ // ~CCapturePin():
+ //
+ // Destruct a capture pin. The destructor is virtual because the cleanup
+ // code will delete the derived class as a CCapturePin.
+ //
+ virtual
+ ~CCapturePin (
+ )
+ {
+ }
+
+ //
+ // ClockAssigned():
+ //
+ // Determine whether or not there is a clock assigned to the pin.
+ //
+ BOOLEAN
+ ClockAssigned (
+ )
+ {
+ return (m_Clock != NULL);
+ }
+
+ //
+ // GetTime():
+ //
+ // Get the time on the clock. There must be a clock assigned to the pin
+ // for this call to work. Verification should be made through
+ // the ClockAssigned() call.
+ //
+ LONGLONG
+ GetTime (
+ )
+ {
+ return m_Clock -> GetTime ();
+ }
+
+ //
+ // SetState():
+ //
+ // Called to set the state of the pin. The base class performs clock
+ // handling and calls the appropriate derived method (Run/Pause/Acquire/
+ // Stop).
+ //
+ NTSTATUS
+ SetState (
+ IN KSSTATE ToState,
+ IN KSSTATE FromState
+ );
+
+ //
+ // Run():
+ //
+ // Called when a pin transitions to KSSTATE_ACQUIRE by SetState().
+ // The derived class can override this to provide any implementation it
+ // needs.
+ //
+ virtual
+ NTSTATUS
+ Run (
+ IN KSSTATE FromState
+ )
+ {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Pause():
+ //
+ // Called when a pin transitions to KSSTATE_PAUSE by SetState().
+ // The derived class can override this to provide any implementation it
+ // needs.
+ //
+ virtual
+ NTSTATUS
+ Pause (
+ IN KSSTATE FromState
+ )
+ {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Acquire():
+ //
+ // Called when a pin transitions to KSSTATE_ACQUIRE by SetState().
+ // The derived class can override this to provide any implementation it
+ // needs.
+ //
+ virtual
+ NTSTATUS
+ Acquire (
+ IN KSSTATE FromState
+ )
+ {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Stop():
+ //
+ // Called when a pin transitions to KSSTATE_STOP by SetState().
+ // The derived class can override this to provide any implementation it
+ // needs.
+ //
+ virtual
+ NTSTATUS
+ Stop (
+ IN KSSTATE FromState
+ )
+ {
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // GetState():
+ //
+ // Return the current state of the pin.
+ //
+ KSSTATE
+ GetState (
+ )
+ {
+ return m_State;
+ }
+
+ //
+ // CaptureFrame():
+ //
+ // Called in order to trigger capture of a frame on the given pin. The
+ // filter's "tick" count is passed as a reference to synthesize an
+ // appropriate frame.
+ //
+ virtual
+ NTSTATUS
+ CaptureFrame (
+ IN PKSPROCESSPIN ProcessPin,
+ IN ULONG Tick
+ ) = 0;
+
+ //
+ // QueryFrameDrop():
+ //
+ // Query the number of dropped frames.
+ //
+ ULONG
+ QueryFrameDrop (
+ );
+
+ //
+ // NotifyDrops():
+ //
+ // Notify the pin how many frames have been dropped on all pins.
+ //
+ void
+ NotifyDrops (
+ IN ULONG VidDrop,
+ IN ULONG AudDrop
+ );
+
+ /*************************************************
+
+ Dispatch Functions
+
+ *************************************************/
+
+ //
+ // DispatchSetState():
+ //
+ // This is the set device state dispatch for the pin. It merely acts
+ // as a bridge to SetState() in the context of the CCapturePin associated
+ // with Pin.
+ //
+ static
+ NTSTATUS
+ DispatchSetState (
+ IN PKSPIN Pin,
+ IN KSSTATE ToState,
+ IN KSSTATE FromState
+ )
+ {
+ return
+ (reinterpret_cast <CCapturePin *> (Pin -> Context)) ->
+ SetState (ToState, FromState);
+ }
+
+ //
+ // BagCleanup():
+ //
+ // This is the free callback for the CCapturePin that we bag. Normally,
+ // ExFreePool would be used, but we must delete instead. This function
+ // will just delete the CCapturePin instead of freeing it. Because our
+ // destructor is virtual, the appropriate derived class destructor will
+ // get called.
+ //
+ static
+ void
+ BagCleanup (
+ IN CCapturePin *This
+ )
+
+ {
+
+ delete This;
+
+ }
+
+};
diff --git a/AVStream/avssamp/filter.h b/AVStream/avssamp/filter.h
new file mode 100644
index 00000000..b39255ea
--- /dev/null
+++ b/AVStream/avssamp/filter.h
@@ -0,0 +1,253 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ filter.h
+
+ Abstract:
+
+ This file contails the filter level header for the filter-centric
+ capture filter.
+
+ History:
+
+ created 5/31/01
+
+**************************************************************************/
+
+/**************************************************************************
+
+ DEFINES
+
+**************************************************************************/
+
+//
+// VIDEO_PIN_ID:
+//
+// The pin factory id of the video pin (the order in the descriptor table).
+//
+#define VIDEO_PIN_ID 0
+
+/**************************************************************************
+
+ CLASSES
+
+**************************************************************************/
+
+class CCaptureFilter {
+
+private:
+
+ //
+ // The AVStream filter object associated with this CCaptureFilter.
+ //
+ PKSFILTER m_Filter;
+
+ //
+ // The DPC used for the timer.
+ //
+ KDPC m_TimerDpc;
+
+ //
+ // The timer used for simulation of capture timings.
+ //
+ KTIMER m_Timer;
+
+ //
+ // Boolean used to detect whether the DPC routine is to shutdown or not
+ //
+ BOOLEAN m_StoppingDPC;
+
+ //
+ // The event used to signal successful shutdown of the timer DPC
+ //
+ KEVENT m_StopDPCEvent;
+
+ //
+ // The number of timer ticks that have occurred since the timer DPC
+ // started firing.
+ //
+ volatile ULONG m_Tick;
+
+ //
+ // The system time at the point that the timer DPC starts.
+ //
+ LARGE_INTEGER m_StartTime;
+
+ //
+ // The amount of time between timer DPC's (and hence frame capture
+ // triggers).
+ //
+ LONGLONG m_TimerInterval;
+
+ //
+ // The wave object. This is passed to the audio pin later, but it's
+ // used at filter create time to determine what ranges to expose on
+ // the audio pin.
+ //
+ CWaveObject *m_WaveObject;
+
+ //
+ // The audio pin factory id. This is dynamic since the pin is created
+ // dynamically at filter create time.
+ //
+ ULONG m_AudioPinId;
+
+ //
+ // Process():
+ //
+ // The process routine for the capture filter. This is responsible for
+ // copying synthesized data into image buffers. The DispatchProcess()
+ // function bridges to this routine in the context of the CCaptureFilter.
+ //
+ NTSTATUS
+ Process (
+ IN PKSPROCESSPIN_INDEXENTRY ProcessPinsIndex
+ );
+
+
+ //
+ // BindAudioToWaveObject():
+ //
+ // This function call binds the audio stream exposed by the filter to
+ // the wave object m_WaveObject.
+ //
+ NTSTATUS
+ BindAudioToWaveObject (
+ );
+
+ //
+ // 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
+ );
+
+ //
+ // ~CCaptureFilter():
+ //
+ // The capture filter destructor.
+ //
+ ~CCaptureFilter (
+ )
+ {
+ }
+
+ //
+ // StartDPC():
+ //
+ // This is called in order to start the timer DPC running.
+ //
+ void
+ StartDPC (
+ IN LONGLONG TimerInterval
+ );
+
+ //
+ // StopDPC():
+ //
+ // This is called in order to stop the timer DPC running. The function
+ // will not return until it guarantees that no more timer DPC's fire.
+ //
+ void
+ StopDPC (
+ );
+
+ //
+ // GetWaveObject():
+ //
+ // Returns the wave object that has been opened for the filter.
+ //
+ CWaveObject *
+ GetWaveObject (
+ )
+ {
+ return m_WaveObject;
+ }
+
+ //
+ // GetTimerInterval():
+ //
+ // Returns the timer interval we're using to generate DPC's.
+ //
+ LONGLONG
+ GetTimerInterval (
+ );
+
+ /*************************************************
+
+ Dispatch Routines
+
+ *************************************************/
+
+ //
+ // 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
+ );
+
+ //
+ // DispatchProcess():
+ //
+ // This is the filter process dispatch for the capture filter. It merely
+ // bridges to Process() in the context of the CCaptureFilter.
+ //
+ static
+ NTSTATUS
+ DispatchProcess (
+ IN PKSFILTER Filter,
+ IN PKSPROCESSPIN_INDEXENTRY ProcessPinsIndex
+ )
+ {
+ return
+ (reinterpret_cast <CCaptureFilter *> (Filter -> Context)) ->
+ Process (ProcessPinsIndex);
+ }
+
+
+ //
+ // TimerDpc():
+ //
+ // The timer dpc routine. This is bridged to from TimerRoutine in the
+ // context of the appropriate CCaptureFilter.
+ //
+ void
+ TimerDpc (
+ );
+
+};
+
diff --git a/AVStream/avssamp/image.cpp b/AVStream/avssamp/image.cpp
new file mode 100644
index 00000000..f4e70655
--- /dev/null
+++ b/AVStream/avssamp/image.cpp
@@ -0,0 +1,647 @@
+/**************************************************************************
+
+ 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 "avssamp.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
+
+--*/
+
+{
+ 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::
+Fill (
+ IN ULONG X_TopLeft,
+ IN ULONG Y_TopLeft,
+ IN ULONG X_BottomRight,
+ IN ULONG Y_BottomRight,
+ IN COLOR Color
+ )
+
+{
+
+ //
+ // Set the default cursor and capture the copy location. Draw a line
+ // of the specified color at the default location.
+ //
+ PUCHAR ImageStart = GetImageLocation (X_TopLeft, Y_TopLeft);
+ for (ULONG x = X_TopLeft; x <= X_BottomRight; x++)
+ PutPixel (Color);
+
+ PUCHAR ImageEnd = m_Cursor;
+
+ //
+ // Copy the fill line from the current location downward to the requested
+ // end location.
+ //
+ for (ULONG y = Y_TopLeft + 1; y <= Y_BottomRight; y++) {
+
+ GetImageLocation (X_TopLeft, y);
+
+ 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/avssamp/image.h b/AVStream/avssamp/image.h
new file mode 100644
index 00000000..6d9091e0
--- /dev/null
+++ b/AVStream/avssamp/image.h
@@ -0,0 +1,476 @@
+/**************************************************************************
+
+ 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);
+ }
+
+ //
+ // Fill():
+ //
+ // Fill an area of the image with a specific color.
+ //
+ virtual void
+ Fill (
+ IN ULONG X_TopLeft,
+ IN ULONG Y_TopLeft,
+ IN ULONG X_BottomRight,
+ IN ULONG Y_BottomRight,
+ IN COLOR Color
+ );
+
+ //
+ // 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 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][1];
+ } else {
+ *(*ImageLocation)++ = Colors [(ULONG)Color][0];
+ *(*ImageLocation)++ = Colors [(ULONG)Color][1];
+ *(*ImageLocation)++ = Colors [(ULONG)Color][2];
+ }
+ } 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][1];
+ } else {
+ *m_Cursor++ = Colors [(ULONG)Color][0];
+ *m_Cursor++ = Colors [(ULONG)Color][1];
+ *m_Cursor++ = Colors [(ULONG)Color][2];
+ }
+ } else {
+ m_Cursor += (m_Parity ? 1 : 3);
+ }
+
+ m_Parity = !m_Parity;
+
+ }
+
+ 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/avssamp/purecall.c b/AVStream/avssamp/purecall.c
new file mode 100644
index 00000000..efb3cb49
--- /dev/null
+++ b/AVStream/avssamp/purecall.c
@@ -0,0 +1,50 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 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;
+}
+
diff --git a/AVStream/avssamp/video.cpp b/AVStream/avssamp/video.cpp
new file mode 100644
index 00000000..d2291a24
--- /dev/null
+++ b/AVStream/avssamp/video.cpp
@@ -0,0 +1,1433 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ video.cpp
+
+ Abstract:
+
+ This file contains the video capture pin implementation.
+
+ History:
+
+ created 6/11/01
+
+**************************************************************************/
+
+#include "avssamp.h"
+
+/**************************************************************************
+
+ PAGEABLE CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+CVideoCapturePin::
+DispatchCreate (
+ IN PKSPIN Pin,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Create a new video 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;
+
+ CVideoCapturePin *CapPin = new (NonPagedPool) CVideoCapturePin (Pin);
+ CCapturePin *BasePin = static_cast <CCapturePin *> (CapPin);
+
+ 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> (BasePin),
+ reinterpret_cast <PFNKSFREE> (CCapturePin::BagCleanup)
+ );
+
+ if (!NT_SUCCESS (Status)) {
+ delete CapPin;
+ } else {
+ Pin -> Context = reinterpret_cast <PVOID> (BasePin);
+ }
+
+ }
+
+ //
+ // 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, 'aChS');
+
+ if (NT_SUCCESS (Status)) {
+ Status = KsEdit (
+ Pin,
+ &(Pin -> Descriptor -> AllocatorFraming),
+ 'aChS'
+ );
+ }
+
+ //
+ // If the edits proceeded without running out of memory, adjust
+ // the framing based on the video info header.
+ //
+ 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
+CVideoCapturePin::
+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 (
+ NonPagedPool,
+ KS_SIZE_VIDEOHEADER (ConnectionHeader),
+ AVSSMP_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
+CVideoCapturePin::
+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
+CVideoCapturePin::
+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;
+ CVideoCapturePin *VidCapPin = 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);
+
+ //
+ // We know this pin happens to be the video capture pin. Downcast it.
+ //
+ VidCapPin = static_cast <CVideoCapturePin *> (CapPin);
+ }
+
+ 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 (!VidCapPin -> 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;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CVideoCapturePin::
+Pause (
+ IN KSSTATE FromState
+ )
+
+/*++
+
+Routine Description:
+
+ Called when the pin transitions into the pause state. If we're in an
+ upward transition, start the capture DPC. Note that we do not actually
+ trigger capture in the pause state, but we start up our DPC.
+
+Arguments:
+
+ FromState -
+ The state that the pin is transitioning away from. This is either
+ KSSTATE_ACQUIRE, indicating an upward transition, or KSSTATE_RUN,
+ indicating a downward transition.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ //
+ // On the transition from acquire -> pause, start the timer DPC running.
+ //
+ if (FromState == KSSTATE_ACQUIRE) {
+ m_ParentFilter -> StartDPC (m_VideoInfoHeader -> AvgTimePerFrame);
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CVideoCapturePin::
+Acquire (
+ IN KSSTATE FromState
+ )
+
+/*++
+
+Routine Description:
+
+ This is called from the base class when the video capture pin transitions
+ into the acquire state (from either Stop or Pause). The state the pin
+ transitioned from is passed in.
+
+ During this phase, the video capture pin creates the image synthesizer
+ and initializes it.
+
+Arguments:
+
+ FromState -
+ The state transitioning from (KSSTATE_STOP or KSSTATE_PAUSE)
+
+Return Value:
+
+ Success / Failure
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NT_ASSERT (m_VideoInfoHeader);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (FromState == KSSTATE_STOP) {
+
+ m_SynthesisBuffer = reinterpret_cast <PUCHAR> (
+ ExAllocatePoolWithTag (
+ NonPagedPool,
+ m_VideoInfoHeader -> bmiHeader.biSizeImage,
+ AVSSMP_POOLTAG
+ )
+ );
+
+ if (!m_SynthesisBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ } else {
+ //
+ // Determine the necessary type of image synthesizer to create
+ // based on the format that has been set on this pin.
+ //
+ 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 (NonPagedPool, 'RysI')
+ CRGB24Synthesizer (
+ m_VideoInfoHeader -> bmiHeader.biHeight >= 0,
+ m_VideoInfoHeader -> bmiHeader.biWidth,
+ ABS (m_VideoInfoHeader -> bmiHeader.biHeight)
+ );
+
+ } else
+ if (m_VideoInfoHeader -> bmiHeader.biBitCount == 16 &&
+ m_VideoInfoHeader -> bmiHeader.biCompression == FOURCC_YUV422) {
+
+ //
+ // If we're UYVY, create the YUV synth.
+ //
+ m_ImageSynth = new (NonPagedPool, 'YysI') CYUVSynthesizer (
+ m_VideoInfoHeader -> bmiHeader.biWidth,
+ m_VideoInfoHeader -> bmiHeader.biHeight
+ );
+
+ } 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;
+ }
+
+ }
+
+ //
+ // Bag the image synthesizer.
+ //
+ if (NT_SUCCESS (Status)) {
+
+ Status = KsAddItemToObjectBag (
+ m_Pin -> Bag,
+ m_ImageSynth,
+ reinterpret_cast <PFNKSFREE> (CVideoCapturePin::CleanupSynth)
+ );
+
+ }
+
+ //
+ // If everything is okay at this point, inform the synthesizer of
+ // the scratch buffer.
+ //
+ if (NT_SUCCESS (Status)) {
+ m_ImageSynth -> SetBuffer (m_SynthesisBuffer);
+ }
+
+ } else {
+
+ //
+ // The only other state we can come from is pause. If we're in a
+ // downward state transition below pause, tell the filter to stop the
+ // capture DPC.
+ //
+ m_ParentFilter -> StopDPC ();
+
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CVideoCapturePin::
+Stop (
+ IN KSSTATE FromState
+ )
+
+/*++
+
+Routine Description:
+
+ Called when the video capture pin transitions from acquire to stop.
+ This function will clean up the image synth and any data structures
+ that we need to clean up on stop.
+
+Arguments:
+
+ FromState -
+ The state the pin is transitioning away from. This should
+ always be KSSTATE_ACQUIRE for this call.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PAGED_CODE();
+
+ NT_ASSERT (FromState == KSSTATE_ACQUIRE);
+
+ //
+ // Remove the image synthesizer from the object bag and free it.
+ //
+ KsRemoveItemFromObjectBag (
+ m_Pin -> Bag,
+ m_ImageSynth,
+ TRUE
+ );
+
+ m_ImageSynth = NULL;
+
+ if (m_SynthesisBuffer) {
+ ExFreePool (m_SynthesisBuffer);
+ m_SynthesisBuffer = NULL;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+NTSTATUS
+CVideoCapturePin::
+CaptureFrame (
+ IN PKSPROCESSPIN ProcessPin,
+ IN ULONG Tick
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called from the filter processing function to capture
+ a frame for the video capture pin. The process pin to capture to is
+ passed.
+
+Arguments:
+
+ ProcessPin -
+ The process pin associated with this pin.
+
+ Tick -
+ The tick count on the filter. This is the number of timer DPC's that
+ have fired since the timer DPC started.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+
+ NT_ASSERT (ProcessPin -> Pin == m_Pin);
+
+ //
+ // Increment the frame number. This is the total count of frames which
+ // have attempted capture.
+ //
+ m_FrameNumber++;
+
+ //
+ // Since this pin is KSPIN_FLAG_FRAMES_NOT_REQUIRED_FOR_PROCESSING, it
+ // means that we do not require frames available in order to process.
+ // This means that this routine can get called from our DPC with no
+ // buffers available to capture into. In this case, we increment our
+ // dropped frame counter and do nothing.
+ //
+ if (ProcessPin -> BytesAvailable) {
+
+ //
+ // Because we adjusted the allocator framing, each frame should be
+ // sufficient to trigger capture of the appropriate buffer size.
+ //
+ NT_ASSERT (ProcessPin -> BytesAvailable >=
+ m_VideoInfoHeader -> bmiHeader.biSizeImage);
+
+ //
+ // If we get an invalid buffer, kick it out.
+ //
+ if (ProcessPin -> BytesAvailable <
+ m_VideoInfoHeader -> bmiHeader.biSizeImage) {
+
+ ProcessPin -> BytesUsed = 0;
+ ProcessPin -> Terminate = TRUE;
+ m_DroppedFrames++;
+ return STATUS_SUCCESS;
+ }
+
+ //
+ // Generate a synthesized image.
+ //
+ m_ImageSynth -> SynthesizeBars ();
+
+ //
+ // Overlay some activity onto the bars.
+ //
+ ULONG DropLength = (Tick * 2) %
+ (ABS (m_VideoInfoHeader -> bmiHeader.biHeight));
+
+ //
+ // Create a drop flowing down DropLength lines from the top of the
+ // image.
+ //
+ m_ImageSynth -> Fill (
+ 0, 0,
+ m_VideoInfoHeader -> bmiHeader.biWidth - 1, DropLength,
+ GREEN
+ );
+
+ //
+ // Overlay the dropped frame count over the image.
+ //
+ char Text [256];
+ Text[0] = '\0';
+ RtlStringCbPrintfA(Text, sizeof(Text), "Video Skipped: %ld", m_DroppedFrames);
+
+ m_ImageSynth -> OverlayText (
+ 10,
+ 10,
+ 1,
+ Text,
+ TRANSPARENT,
+ BLUE
+ );
+
+ //
+ // This is used to indicate that there is no audio pin.
+ //
+ if (m_NotifyAudDrop != (ULONG)-1) {
+ RtlStringCbPrintfA(Text, sizeof(Text), "Audio Skipped: %ld", m_NotifyAudDrop);
+
+ m_ImageSynth -> OverlayText (
+ 10,
+ 20,
+ 1,
+ Text,
+ TRANSPARENT,
+ BLUE
+ );
+ }
+
+ //
+ // Copy the synthesized image into the buffer.
+ //
+ RtlCopyMemory (
+ ProcessPin -> Data,
+ m_SynthesisBuffer,
+ m_VideoInfoHeader -> bmiHeader.biSizeImage
+ );
+
+ ProcessPin -> BytesUsed = m_VideoInfoHeader -> bmiHeader.biSizeImage;
+ ProcessPin -> Terminate = TRUE;
+
+
+ PKSSTREAM_HEADER StreamHeader =
+ ProcessPin -> StreamPointer -> StreamHeader;
+
+ //
+ // If there is a clock assigned to the pin, time stamp the sample.
+ //
+ if (m_Clock) {
+
+ StreamHeader -> PresentationTime.Time = GetTime ();
+ StreamHeader -> Duration = m_VideoInfoHeader -> AvgTimePerFrame;
+
+ StreamHeader -> OptionsFlags =
+ KSSTREAM_HEADER_OPTIONSF_TIMEVALID |
+ KSSTREAM_HEADER_OPTIONSF_DURATIONVALID;
+
+ }
+
+ //
+ // Update the extended header info.
+ //
+ NT_ASSERT (StreamHeader -> Size >= sizeof (KSSTREAM_HEADER) +
+ sizeof (KS_FRAME_INFO));
+
+ //
+ // 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 (StreamHeader -> Size >= sizeof (KSSTREAM_HEADER) +
+ sizeof (KS_FRAME_INFO)) {
+
+ PKS_FRAME_INFO FrameInfo = reinterpret_cast <PKS_FRAME_INFO> (
+ StreamHeader + 1
+ );
+
+ FrameInfo -> ExtendedHeaderSize = sizeof (KS_FRAME_INFO);
+ FrameInfo -> PictureNumber = (LONGLONG)m_FrameNumber;
+ FrameInfo -> DropCount = (LONGLONG)m_DroppedFrames;
+
+ }
+
+ } else {
+ m_DroppedFrames++;
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+/**************************************************************************
+
+ DESCRIPTOR AND DISPATCH LAYOUT
+
+**************************************************************************/
+
+#define D_X 320
+#define D_Y 240
+
+//
+// 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?)
+ TRUE, // 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_NTSC_M |
+ KS_AnalogVideo_PAL_B, // AnalogVideoStandard
+ 720,480, // InputSize, (the inherent size of the incoming signal
+ // with every digitized pixel unique)
+ 160,120, // MinCroppingSize, smallest rcSrc cropping rect allowed
+ 720,480, // MaxCroppingSize, largest rcSrc cropping rect allowed
+ 8, // CropGranularityX, granularity of cropping size
+ 1, // CropGranularityY
+ 8, // CropAlignX, alignment of cropping rect
+ 1, // CropAlignY;
+ 160, 120, // MinOutputSize, smallest bitmap stream can produce
+ 720, 480, // 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 * 160 * 120, // MinBitsPerSecond;
+ 8 * 3 * 30 * 720 * 480 // MaxBitsPerSecond;
+ },
+
+ //
+ // KS_VIDEOINFOHEADER (default format)
+ //
+ {
+ 0,0,0,0, // RECT rcSource;
+ 0,0,0,0, // RECT rcTarget;
+ D_X * D_Y * 3 * 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;
+ }
+};
+
+#undef D_X
+#undef D_Y
+
+#define D_X 320
+#define D_Y 240
+
+//
+// FormatUYU2_Capture:
+//
+// This is the data range description of the UYVY format we support.
+//
+const
+KS_DATARANGE_VIDEO
+FormatUYU2_Capture = {
+
+ //
+ // KSDATARANGE
+ //
+ {
+ sizeof (KS_DATARANGE_VIDEO), // FormatSize
+ 0, // Flags
+ D_X * D_Y * 2, // SampleSize
+ 0, // Reserved
+ STATICGUIDOF (KSDATAFORMAT_TYPE_VIDEO), // aka. MEDIATYPE_Video
+ 0x59565955, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa,
+ 0x00, 0x38, 0x9b, 0x71, // aka. MEDIASUBTYPE_UYVY,
+ STATICGUIDOF (KSDATAFORMAT_SPECIFIER_VIDEOINFO) // aka. FORMAT_VideoInfo
+ },
+
+ TRUE, // BOOL, bFixedSizeSamples (all samples same size?)
+ TRUE, // 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_NTSC_M |
+ KS_AnalogVideo_PAL_B, // AnalogVideoStandard
+ 720,480, // InputSize, (the inherent size of the incoming signal
+ // with every digitized pixel unique)
+ 160,120, // MinCroppingSize, smallest rcSrc cropping rect allowed
+ 720,480, // MaxCroppingSize, largest rcSrc cropping rect allowed
+ 8, // CropGranularityX, granularity of cropping size
+ 1, // CropGranularityY
+ 8, // CropAlignX, alignment of cropping rect
+ 1, // CropAlignY;
+ 160, 120, // MinOutputSize, smallest bitmap stream can produce
+ 720, 480, // 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 * 160 * 120, // MinBitsPerSecond;
+ 8 * 2 * 30 * 720 * 480 // MaxBitsPerSecond;
+ },
+
+ //
+ // KS_VIDEOINFOHEADER (default format)
+ //
+ {
+ 0,0,0,0, // RECT rcSource;
+ 0,0,0,0, // RECT rcTarget;
+ D_X * D_Y * 2 * 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;
+ 16, // WORD biBitCount;
+ FOURCC_YUV422, // DWORD biCompression;
+ D_X * D_Y * 2, // DWORD biSizeImage;
+ 0, // LONG biXPelsPerMeter;
+ 0, // LONG biYPelsPerMeter;
+ 0, // DWORD biClrUsed;
+ 0 // DWORD biClrImportant;
+ }
+};
+
+//
+// VideoCapturePinDispatch:
+//
+// This is the dispatch table for the capture pin. It provides notifications
+// about creation, closure, processing, data formats, etc...
+//
+const
+KSPIN_DISPATCH
+VideoCapturePinDispatch = {
+ CVideoCapturePin::DispatchCreate, // Pin Create
+ NULL, // Pin Close
+ NULL, // Pin Process
+ NULL, // Pin Reset
+ CVideoCapturePin::DispatchSetFormat, // Pin Set Data Format
+ CCapturePin::DispatchSetState, // Pin Set Device State
+ NULL, // Pin Connect
+ NULL, // Pin Disconnect
+ NULL, // Clock Dispatch
+ NULL // Allocator Dispatch
+};
+
+//
+// VideoCapturePinAllocatorFraming:
+//
+// This is the simple framing structure for the capture pin. Note that this
+// will be modified via KsEdit when the actual capture format is determined.
+//
+DECLARE_SIMPLE_FRAMING_EX (
+ VideoCapturePinAllocatorFraming,
+ STATICGUIDOF (KSMEMORY_TYPE_KERNEL_NONPAGED),
+ KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
+ KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY,
+ 2,
+ 0,
+ 2 * PAGE_SIZE,
+ 2 * PAGE_SIZE
+ );
+
+//
+// VideoCapturePinDataRanges:
+//
+// This is the list of data ranges supported on the capture pin. We support
+// two: one RGB24, and one UYVY.
+//
+const
+PKSDATARANGE
+VideoCapturePinDataRanges [CAPTURE_PIN_DATA_RANGE_COUNT] = {
+ (PKSDATARANGE) &FormatRGB24Bpp_Capture,
+ (PKSDATARANGE) &FormatUYU2_Capture
+ };
+
diff --git a/AVStream/avssamp/video.h b/AVStream/avssamp/video.h
new file mode 100644
index 00000000..36b9dbe5
--- /dev/null
+++ b/AVStream/avssamp/video.h
@@ -0,0 +1,221 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ video.h
+
+ Abstract:
+
+ This file contains the video capture pin header.
+
+ History:
+
+ created 6/11/01
+
+**************************************************************************/
+
+class CVideoCapturePin :
+ public CCapturePin {
+
+private:
+
+ //
+ // A scratch buffer to write into. Due to the fact that we're likely
+ // sitting upstream of the VMR and getting video memory, I don't want the
+ // image synthesizer writing to video memory a single byte at a time.
+ // This will be the buffer that the image synth uses. After a synthesis,
+ // the buffer will get copied into the data buffers for capture.
+ //
+ PUCHAR m_SynthesisBuffer;
+
+ //
+ // The captured video info header. The settings for image synthesis will
+ // be based off this header.
+ //
+ PKS_VIDEOINFOHEADER m_VideoInfoHeader;
+
+ //
+ // The image synthesizer. This object is used to construct synthesized
+ // image data in the video format specified by the connection format.
+ //
+ CImageSynthesizer *m_ImageSynth;
+
+ //
+ // CaptureVideoInfoHeader():
+ //
+ // This routine stashes the video info header set on the pin connection
+ // in the CVideoCapturePin object. This is used to determine necessary
+ // variables for image synthesis, etc...
+ //
+ PKS_VIDEOINFOHEADER
+ CaptureVideoInfoHeader (
+ );
+
+protected:
+
+public:
+
+ //
+ // CVideoCapturePin():
+ //
+ // Construct a new video capture pin.
+ //
+ CVideoCapturePin (
+ IN PKSPIN Pin
+ ) :
+ CCapturePin (Pin)
+ {
+ }
+
+ //
+ // ~CVideoCapturePin():
+ //
+ // Destruct a video capture pin.
+ //
+ virtual
+ ~CVideoCapturePin (
+ )
+ {
+ }
+
+ //
+ // CaptureFrame():
+ //
+ // Called from the filter processing routine to indicate that the pin
+ // should attempt to trigger capture of a video frame. This routine
+ // will copy synthesized image data into the frame buffer and complete
+ // the frame buffer.
+ //
+ virtual
+ NTSTATUS
+ CaptureFrame (
+ IN PKSPROCESSPIN ProcessPin,
+ IN ULONG Tick
+ );
+
+ //
+ // Pause():
+ //
+ // Called when the video capture pin is transitioning into the pause
+ // state. This will instruct the capture filter to start the timer DPC's
+ // at the interval demanded by the video info header in the connection
+ // format.
+ //
+ virtual
+ NTSTATUS
+ Pause (
+ IN KSSTATE FromState
+ );
+
+ //
+ // Acquire():
+ //
+ // Called when the video capture pin is transitioning into the acquire
+ // state. This will create the necessary image synthesizer to begin
+ // synthesizing frame capture data when the pin transitions to the
+ // appropriate state.
+ //
+ virtual
+ NTSTATUS
+ Acquire (
+ IN KSSTATE FromState
+ );
+
+ //
+ // Stop():
+ //
+ // Called when the video capture pin is transitioning into a stop state.
+ // This simply destroys the image synthesizer in preparation for creating
+ // a new one next acquire.
+ //
+ virtual
+ NTSTATUS
+ Stop (
+ IN KSSTATE FromState
+ );
+
+ /*************************************************
+
+ Dispatch Functions
+
+ *************************************************/
+
+ //
+ // DispatchCreate():
+ //
+ // This is the creation dispatch for the video capture pin on the filter.
+ // It creates the CVideoCapturePin, associates it with the AVStream pin
+ // object and bags the class object for automatic cleanup when the
+ // pin is closed.
+ //
+ static
+ NTSTATUS
+ DispatchCreate (
+ IN PKSPIN Pin,
+ IN PIRP Irp
+ );
+
+ //
+ // 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
+ );
+
+ //
+ // 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
+ );
+
+ //
+ // CleanupSynth():
+ //
+ // Called when the Image Synthesizer is removed from the object bag
+ // to be cleaned up. We simply delete the image synth.
+ //
+ static
+ void
+ CleanupSynth (
+ IN CImageSynthesizer *ImageSynth
+ )
+ {
+ delete ImageSynth;
+ }
+
+};
+
diff --git a/AVStream/avssamp/wave.cpp b/AVStream/avssamp/wave.cpp
new file mode 100644
index 00000000..7af2f60a
--- /dev/null
+++ b/AVStream/avssamp/wave.cpp
@@ -0,0 +1,598 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ wave.cpp
+
+ Abstract:
+
+ Wave object implementation.
+
+ History:
+
+ Created 6/28/01
+
+**************************************************************************/
+
+#include "avssamp.h"
+
+/**************************************************************************
+
+ PAGED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg("PAGE")
+#endif // ALLOC_PRAGMA
+
+
+CWaveObject::
+~CWaveObject (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a wave object.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PAGED_CODE();
+
+ if (m_WaveData) {
+ ExFreePool (m_WaveData);
+ }
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CWaveObject::
+ParseForBlock (
+ IN HANDLE FileHandle,
+ IN ULONG BlockHeader,
+ IN OUT PLARGE_INTEGER BlockPosition,
+ OUT PULONG BlockSize
+ )
+
+/*++
+
+Routine Description:
+
+ Given that BlockPosition points to the offset of the start of a RIFF block,
+ continue parsing the specified file until a block with the header of
+ BlockHeader is found. Return the position of the block data and the size
+ of the block.
+
+Arguments:
+
+ FileHandle -
+ Handle to the file to parse
+
+ BlockHeader -
+ The block header to scan for
+
+ BlockPosition -
+ INPUT : Points to the block header to start at
+ OUTPUT: If successful, points to the block data for the sought block
+ If unsuccessful, unchanged
+
+ BlockSize -
+ On output, if successful -- the size of the sought block will be
+ placed here
+
+Return Value:
+
+ Success / Failure of the search
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status;
+ ULONG FmtBlockSize = 0;
+ LARGE_INTEGER ReadPos = *BlockPosition;
+ IO_STATUS_BLOCK iosb;
+
+ while (1) {
+ ULONG BlockHeaderData [2];
+
+ Status = ZwReadFile (
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ BlockHeaderData,
+ sizeof (BlockHeaderData),
+ &ReadPos,
+ NULL
+ );
+
+ if (NT_SUCCESS (Status)) {
+ if (BlockHeaderData [0] == BlockHeader) {
+ FmtBlockSize = BlockHeaderData [1];
+ ReadPos.QuadPart += 0x8;
+ break;
+ } else {
+ //
+ // This isn't a format block. Just ignore it. All we
+ // care about is the format block and the PCM data.
+ //
+ ReadPos.QuadPart += BlockHeaderData [1] + 0x8;
+ }
+ } else {
+ break;
+ }
+
+ }
+
+ if (FmtBlockSize == 0) {
+ Status = STATUS_NOT_FOUND;
+ } else {
+ *BlockPosition = ReadPos;
+ *BlockSize = FmtBlockSize;
+ }
+
+ return Status;
+
+}
+
+/*************************************************/
+
+
+NTSTATUS
+CWaveObject::
+ParseAndRead (
+ )
+
+/*++
+
+Routine Description:
+
+ Parse the wave file and read the data into an internally allocated
+ buffer. This prepares to synthesize audio data from the wave
+ object.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Success / Failure
+
+ If the wave is unrecognized, unparsable, or insufficient memory
+ exists to allocate the internal buffer, an error code will
+ be returned and the object will be incapable of synthesizing
+ audio data based on the wave.
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ IO_STATUS_BLOCK iosb;
+ UNICODE_STRING FileName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE FileHandle = NULL;
+ FILE_OBJECT *FileObj;
+
+ RtlInitUnicodeString (&FileName, m_FileName);
+
+ InitializeObjectAttributes (
+ &ObjectAttributes,
+ &FileName,
+ (OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE),
+ NULL,
+ NULL
+ );
+
+ Status = ZwCreateFile (
+ &FileHandle,
+ GENERIC_READ | SYNCHRONIZE,
+ &ObjectAttributes,
+ &iosb,
+ 0,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT,
+ NULL,
+ 0
+ );
+
+ if (NT_SUCCESS (Status)) {
+ ULONG RiffWaveHeader [3];
+
+ //
+ // Read the header: RIFF size WAVE
+ //
+ Status = ZwReadFile (
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ RiffWaveHeader,
+ sizeof (RiffWaveHeader),
+ NULL,
+ NULL
+ );
+
+ //
+ // Ensure that this is a RIFF file and it's a WAVE.
+ //
+ if (NT_SUCCESS (Status)) {
+
+ if (RiffWaveHeader [0] != 'FFIR' ||
+ RiffWaveHeader [2] != 'EVAW') {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ //
+ // Find the wave format block and ensure it's WAVEFORMATEX and PCM
+ // data. Otherwise, this can't parse the wave.
+ //
+ LARGE_INTEGER ReadPos;
+ ReadPos.QuadPart = 0xc;
+ ULONG FmtBlockSize = 0;
+
+ if (NT_SUCCESS (Status)) {
+ Status = ParseForBlock (FileHandle, ' tmf', &ReadPos, &FmtBlockSize);
+ }
+
+ //
+ // If the format block was not found, the file cannot be parsed. If the
+ // format block is unrecognized, the file cannot be parsed.
+ //
+ if (FmtBlockSize >= sizeof (m_WaveFormat)) {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ if (NT_SUCCESS (Status)) {
+ Status = ZwReadFile (
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &m_WaveFormat,
+ FmtBlockSize,
+ &ReadPos,
+ NULL
+ );
+ }
+
+ if (NT_SUCCESS (Status)) {
+ if (m_WaveFormat.wFormatTag != WAVE_FORMAT_PCM) {
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ ReadPos.QuadPart += FmtBlockSize;
+
+ //
+ // Find the data block and read it in.
+ //
+ ULONG DataBlockSize;
+ if (NT_SUCCESS (Status)) {
+ Status = ParseForBlock (FileHandle, 'atad', &ReadPos, &DataBlockSize);
+ }
+
+ //
+ // Perform a slight validation.
+ //
+ if (NT_SUCCESS (Status) &&
+ (DataBlockSize == 0 ||
+ (DataBlockSize & (m_WaveFormat.nBlockAlign - 1)))) {
+
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // If we're okay so far, allocate memory for the wave data.
+ //
+ if (NT_SUCCESS (Status)) {
+ m_WaveData = reinterpret_cast <PUCHAR> (
+ ExAllocatePoolWithTag (NonPagedPool, DataBlockSize, AVSSMP_POOLTAG)
+ );
+
+ if (!m_WaveData) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ //
+ // Read the wave data in.
+ //
+ if (NT_SUCCESS (Status)) {
+ Status = ZwReadFile (
+ FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ m_WaveData,
+ DataBlockSize,
+ &ReadPos,
+ NULL
+ );
+
+ m_WaveSize = DataBlockSize;
+ }
+
+ //
+ // If we failed, clean up.
+ //
+ if (!NT_SUCCESS (Status)) {
+ if (m_WaveData) {
+ ExFreePool (m_WaveData);
+ m_WaveData = NULL;
+ }
+ }
+
+ if (FileHandle) {
+ ZwClose (FileHandle);
+ }
+
+ return Status;
+}
+
+/*************************************************/
+
+
+void
+CWaveObject::
+WriteRange (
+ OUT PKSDATARANGE_AUDIO DataRange
+ )
+
+/*++
+
+Routine Description:
+
+ Fill out the extended portion of the audio data range at DataRange. This
+ includes the channel, bps, and frequency fields.
+
+Arguments:
+
+ DataRange -
+ The data range to fill out
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ DataRange -> MaximumChannels = m_WaveFormat.nChannels;
+ DataRange -> MinimumBitsPerSample =
+ DataRange -> MaximumBitsPerSample =
+ m_WaveFormat.wBitsPerSample;
+ DataRange -> MinimumSampleFrequency =
+ DataRange -> MaximumSampleFrequency =
+ m_WaveFormat.nSamplesPerSec;
+
+
+}
+
+/**************************************************************************
+
+ LOCKED CODE
+
+**************************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma code_seg()
+#endif // ALLOC_PRAGMA
+
+
+void
+CWaveObject::
+SkipFixed (
+ IN LONGLONG TimeDelta
+ )
+
+/*++
+
+Routine Description:
+
+ Skip ahead a specific time delta within the wave.
+
+Arguments:
+
+ TimeDelta -
+ The amount of time to skip ahead.
+
+--*/
+
+{
+ if (TimeDelta > 0) {
+
+ //
+ // Compute the number of bytes of audio data necessary to move the
+ // stream forward TimeDelta time. Remember that TimeDelta is in
+ // units of 100nS.
+ //
+ ULONG Samples = (ULONG)(
+ (m_WaveFormat.nSamplesPerSec * TimeDelta) / 10000000
+ );
+
+ ULONG Bytes = Samples * (m_WaveFormat.wBitsPerSample / 8) *
+ m_WaveFormat.nChannels;
+
+ m_WavePointer = (m_WavePointer + Bytes) % m_WaveSize;
+
+ m_SynthesisTime += TimeDelta;
+
+ }
+
+}
+
+
+ULONG
+CWaveObject::
+SynthesizeFixed (
+ IN LONGLONG TimeDelta,
+ IN PVOID Buffer,
+ IN ULONG BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ Copy wave data from our wave block in order to synthesize forward in time
+ TimeDelta (in 100nS units).
+
+Arguments:
+
+ TimeDelta -
+ The amount of time to move the stream (in 100nS increments)
+
+ Buffer -
+ The buffer to synthesize into
+
+ BufferSize -
+ The size of the buffer
+
+Return Value:
+
+ Number of bytes synthesized.
+
+--*/
+
+{
+
+ //
+ // If there is no time delta, return 0.
+ //
+ if (TimeDelta < 0)
+ return 0;
+
+ //
+ // Compute the number of bytes of audio data necessary to move the stream
+ // forward TimeDelta time. Remember that TimeDelta is in units of 100nS.
+ //
+ ULONG Samples = (ULONG)(
+ (m_WaveFormat.nSamplesPerSec * TimeDelta) / 10000000
+ );
+
+ ULONG Bytes = Samples * (m_WaveFormat.wBitsPerSample / 8) *
+ m_WaveFormat.nChannels;
+
+ //
+ // Now that we have a specified number of bytes, we determine how many
+ // to really copy based on the Size of the buffer.
+ //
+ if (Bytes > BufferSize) Bytes = BufferSize;
+
+ //
+ // Because the buffer is looping, this may multiple distinct copies. For
+ // large wave files, this may be two chunks. For small wave files, this
+ // may be MANY distinct chunks.
+ //
+ ULONG BytesRemaining = Bytes;
+ PUCHAR DataCopy = reinterpret_cast <PUCHAR> (Buffer);
+
+ while (BytesRemaining) {
+ ULONG ChunkCount = m_WaveSize - m_WavePointer;
+ if (ChunkCount > BytesRemaining) ChunkCount = BytesRemaining;
+
+ RtlCopyMemory (
+ DataCopy,
+ m_WaveData + m_WavePointer,
+ ChunkCount
+ );
+
+ m_WavePointer += ChunkCount;
+ if (m_WavePointer >= m_WaveSize) m_WavePointer -= m_WaveSize;
+
+ BytesRemaining -= ChunkCount;
+ DataCopy += ChunkCount;
+
+ }
+
+ //
+ // Consider that we have synthesized up to the specified time. If the
+ // buffer was not large enough to do this, we'll end up falling behind
+ // the synthesis time. This does not skip samples.
+ //
+ m_SynthesisTime += TimeDelta;
+
+ return Bytes;
+
+}
+
+
+ULONG
+CWaveObject::
+SynthesizeTo (
+ IN LONGLONG StreamTime,
+ IN PVOID Buffer,
+ IN ULONG BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ Copy wave data from our wave block in order to synthesize the stream
+ up to the specified stream time. If the buffers are not large enough,
+ this will fall behind on synthesis.
+
+Arguments:
+
+ StreamTime -
+ The time to synthesize up to
+
+ Buffer -
+ The buffer to copy synthesized wave data into
+
+ BufferSize -
+ The size of the buffer
+
+Return Value:
+
+ The number of bytes used.
+
+--*/
+
+{
+
+ LONGLONG TimeDelta = StreamTime - m_SynthesisTime;
+
+ return SynthesizeFixed (TimeDelta, Buffer, BufferSize);
+
+
+}
+
diff --git a/AVStream/avssamp/wave.h b/AVStream/avssamp/wave.h
new file mode 100644
index 00000000..d8546e3e
--- /dev/null
+++ b/AVStream/avssamp/wave.h
@@ -0,0 +1,192 @@
+/**************************************************************************
+
+ AVStream Filter-Centric Sample
+
+ Copyright (c) 1999 - 2001, Microsoft Corporation
+
+ File:
+
+ wave.h
+
+ Abstract:
+
+ Wave object header.
+
+ History:
+
+ Created 6/28/01
+
+**************************************************************************/
+
+//
+// The CWaveObject is a class which will parse PCM wave files, read the
+// data, and expose the data in a loop. This allows the sample to "synthesize"
+// audio data by using any PCM wave file the user wishes.
+//
+class CWaveObject {
+
+private:
+
+ //
+ // The wave format.
+ //
+ WAVEFORMATEX m_WaveFormat;
+
+ //
+ // The wave data.
+ //
+ PUCHAR m_WaveData;
+
+ //
+ // The size of the wave data.
+ //
+ ULONG m_WaveSize;
+
+ //
+ // The filename for the wave file. This string must be constant and
+ // static over the lifetime of the wave object.
+ //
+ PWCHAR m_FileName;
+
+ //
+ // The time we have synthesized to.
+ //
+ LONGLONG m_SynthesisTime;
+
+ //
+ // The pointer into the wave data that we have synthesized to.
+ //
+ ULONG m_WavePointer;
+
+ //
+ // ParseBlock():
+ //
+ // Parse the wave file, starting at the specified location, until the
+ // specified block has been found. The pointer will be updated to
+ // point to the block data and the amount of data in the block will
+ // be returned in a variable.
+ //
+ NTSTATUS
+ ParseForBlock (
+ IN HANDLE FileHandle,
+ IN ULONG BlockHeader,
+ IN OUT PLARGE_INTEGER BlockPointer,
+ OUT PULONG BlockSize
+ );
+
+public:
+
+ //
+ // CWaveObject():
+ //
+ // Construct a new wave object using the specified file name.
+ //
+ CWaveObject (
+ _In_ LPWSTR FileName
+ ) :
+ m_FileName (FileName)
+ {
+ m_WaveData = NULL;
+ }
+
+ //
+ // ~CWaveObject():
+ //
+ // Destroy a wave object.
+ //
+ ~CWaveObject (
+ );
+
+ //
+ // ParseAndRead():
+ //
+ // Parse the wave file and read it into an internally allocated buffer
+ // inside the wave object. This is preparation to synthesize looped
+ // audio based on the wave.
+ //
+ NTSTATUS
+ ParseAndRead (
+ );
+
+ //
+ // WriteRange():
+ //
+ // Given the address of a KSDATARANGE_AUDIO, write out a range which
+ // matches exactly the specifications of the wave we're using to
+ // synthesize audio data.
+ //
+ // The GUIDs must be filled out already. This only fills out the
+ // channel, bps, and freq fields.
+ //
+ void
+ WriteRange (
+ PKSDATARANGE_AUDIO AudioRange
+ );
+
+ //
+ // SynthesizeTo():
+ //
+ // Given a specific stream time, synthesize from the current stream time
+ // (assume 0) to the supplied stream time.
+ //
+ ULONG
+ SynthesizeTo (
+ IN LONGLONG StreamTime,
+ IN PVOID Data,
+ IN ULONG BufferSize
+ );
+
+ //
+ // SynthesizeFixed():
+ //
+ // Given a specific amount of time, synthesize forward in time that
+ // particular amount. Units expressed in 100nS increments.
+ //
+ ULONG
+ SynthesizeFixed (
+ IN LONGLONG TimeDelta,
+ IN PVOID Data,
+ IN ULONG BufferSize
+ );
+
+ //
+ // SkipFixed():
+ //
+ // Given a specific amount of time, skip forward in time that
+ // particular amount. Units expressed in 100nS increments.
+ //
+ void
+ SkipFixed (
+ IN LONGLONG TimeDelta
+ );
+
+ //
+ // Reset():
+ //
+ // Reset the synthesis time and block pointers. This will cause the
+ // clock with respect to this wave object to go to zero.
+ //
+ void
+ Reset (
+ )
+ {
+ m_WavePointer = 0;
+ m_SynthesisTime = 0;
+ }
+
+ //
+ // Cleanup():
+ //
+ // This is a bag cleanup callback. It merely deletes the wave object
+ // instead of letting the default of ExFreePool free it.
+ //
+ static
+ void
+ Cleanup (
+ IN CWaveObject *This
+ )
+ {
+ delete This;
+ }
+
+};
diff --git a/AVStream/sampledevicemft/SampleDeviceMft.sln b/AVStream/sampledevicemft/SampleDeviceMft.sln
new file mode 100644
index 00000000..a6a00c4d
--- /dev/null
+++ b/AVStream/sampledevicemft/SampleDeviceMft.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}") = "multipinmft", "multipinmft.vcxproj", "{E77657CD-A270-49E1-823A-8A14FF8596C8}"
+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
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.Build.0 = Debug|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.ActiveCfg = Release|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.Build.0 = Release|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.ActiveCfg = Debug|x64
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.Build.0 = Debug|x64
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.ActiveCfg = Release|x64
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/AVStream/sampledevicemft/Source.def b/AVStream/sampledevicemft/Source.def
new file mode 100644
index 00000000..752ef2ea
--- /dev/null
+++ b/AVStream/sampledevicemft/Source.def
@@ -0,0 +1,5 @@
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DllGetClassObject PRIVATE
diff --git a/AVStream/sampledevicemft/basepin.cpp b/AVStream/sampledevicemft/basepin.cpp
new file mode 100644
index 00000000..a1f71860
--- /dev/null
+++ b/AVStream/sampledevicemft/basepin.cpp
@@ -0,0 +1,847 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmft.h"
+#include "multipinmfthelpers.h"
+#include "basepin.h"
+
+#ifdef MF_WPP
+#include "basepin.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+/* -------> New STATE
+ |
+ |old State
+DeviceStreamState_Stop DeviceStreamState_Pause DeviceStreamState_Run DeviceStreamState_Disabled
+DeviceStreamState_Pause
+DeviceStreamState_Run
+DeviceStreamState_Disabled
+*/
+
+DeviceStreamState pinStateTransition[4][4] = {
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled }
+};
+
+CBasePin::CBasePin( _In_ ULONG id, _In_ CMultipinMft *parent) :
+ m_StreamId(id)
+ , m_Parent(parent)
+ , m_setMediaType(nullptr)
+{
+
+}
+
+CBasePin::~CBasePin()
+{
+ IMFMediaType *pMediaType = nullptr;
+ for ( ULONG ulIndex = 0, ulSize = (ULONG)m_listOfMediaTypes.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ pMediaType = m_listOfMediaTypes[ulIndex];
+ SAFE_RELEASE(pMediaType);
+ }
+ m_listOfMediaTypes.clear();
+ m_spAttributes = nullptr;
+}
+
+HRESULT CBasePin::AddMediaType( _Inout_ DWORD *pos, _In_ IMFMediaType *pMediaType)
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+ DMFTCHECKNULL_GOTO(pMediaType, done, E_INVALIDARG);
+
+ hr = ExceptionBoundary([&]()
+ {
+ m_listOfMediaTypes.push_back(pMediaType);
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+ pMediaType->AddRef();
+
+ if (pos)
+ {
+ *pos = (DWORD)(m_listOfMediaTypes.size() - 1);
+ }
+
+done:
+ return hr;
+}
+
+HRESULT CBasePin::GetMediaTypeAt( _In_ DWORD pos, _Outptr_result_maybenull_ IMFMediaType **ppMediaType )
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+ DMFTCHECKNULL_GOTO(ppMediaType,done,E_INVALIDARG);
+
+ if (pos >= m_listOfMediaTypes.size())
+ {
+ DMFTCHECKHR_GOTO(MF_E_NO_MORE_TYPES,done);
+ }
+ *ppMediaType = m_listOfMediaTypes[pos];
+ if (*ppMediaType)
+ {
+ (*ppMediaType)->AddRef();
+ }
+done:
+ return hr;
+}
+
+STDMETHODIMP_(BOOL) CBasePin::IsMediaTypeSupported
+(
+ _In_ IMFMediaType *pMediaType,
+ _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
+ IMFMediaType **ppIMFMediaTypeFull
+)
+{
+ HRESULT hr = S_OK;
+ BOOL bFound = FALSE;
+ CAutoLock Lock(lock());
+ DMFTCHECKNULL_GOTO(pMediaType,done,E_INVALIDARG);
+ if (ppIMFMediaTypeFull)
+ {
+ *ppIMFMediaTypeFull = nullptr;
+ }
+
+ for (UINT uIIndex = 0, uISize = (UINT)m_listOfMediaTypes.size(); uIIndex < uISize ; uIIndex++ )
+ {
+ DWORD dwResult = 0;
+ hr = m_listOfMediaTypes[ uIIndex ]->IsEqual( pMediaType, &dwResult );
+ if (hr == S_FALSE)
+ {
+
+ if ((dwResult & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_DATA))
+ {
+ hr = S_OK;
+ }
+ }
+ if (hr == S_OK)
+ {
+ bFound = TRUE;
+ if (ppIMFMediaTypeFull) {
+ *ppIMFMediaTypeFull = m_listOfMediaTypes[uIIndex];
+ (*ppIMFMediaTypeFull)->AddRef();
+ }
+ break;
+ }
+ else if (FAILED(hr))
+ {
+ DMFTCHECKHR_GOTO(hr,done);
+ }
+ }
+done:
+ return SUCCEEDED(hr) ? TRUE : FALSE;
+}
+
+
+STDMETHODIMP CBasePin::GetOutputAvailableType(_In_ DWORD dwTypeIndex, _Out_opt_ IMFMediaType** ppType)
+{
+ return GetMediaTypeAt( dwTypeIndex, ppType );
+}
+
+
+HRESULT CBasePin::QueryInterface(
+ _In_ REFIID iid,
+ _Outptr_result_maybenull_ void** ppv
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(ppv, out, E_POINTER);
+
+ *ppv = nullptr;
+
+ if ( iid == __uuidof( IUnknown ) )
+ {
+ *ppv = static_cast<VOID*>(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFAttributes ) )
+ {
+ *ppv = static_cast< IMFAttributes* >( this );
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ AddRef();
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+out:
+ return hr;
+}
+
+
+
+
+//
+//Input Pin implementation
+//
+CInPin::CInPin(
+ _In_opt_ IMFAttributes *pAttributes,
+ _In_ ULONG ulPinId,
+ _In_ CMultipinMft *pParent)
+ :
+ CBasePin(ulPinId, pParent),
+ m_stStreamType(GUID_NULL),
+ m_activeStreamCount(0),
+ m_state(DeviceStreamState_Stop),
+ m_prefferedMediaType(nullptr),
+ m_waitInputMediaTypeWaiter(NULL),
+ m_preferredStreamState(DeviceStreamState_Stop)
+{
+ setAttributes(pAttributes);
+}
+
+
+
+CInPin::~CInPin()
+{
+ setAttributes( nullptr );
+ m_spSourceTransform = nullptr;
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_outpins.size();
+ ulIndex < ulSize;
+ ulIndex++)
+ {
+ CBasePin *pPin = m_outpins[ulIndex];
+ SAFERELEASE(pPin);
+ }
+ if (m_waitInputMediaTypeWaiter)
+ {
+ CloseHandle(m_waitInputMediaTypeWaiter);
+ }
+
+}
+
+
+
+STDMETHODIMP CInPin::Init(
+ _In_ IMFTransform* pTransform
+ )
+{
+
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO( pTransform, done, E_INVALIDARG );
+
+ m_spSourceTransform = pTransform;
+
+ DMFTCHECKHR_GOTO( GetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType ), done );
+
+ //
+ //Get the DevProxy IKSControl.. used to send the KSControls or the device control IOCTLS over to devproxy and finally on to the driver!!!!
+ //
+ DMFTCHECKHR_GOTO( m_spAttributes.As( &m_spIkscontrol ), done );
+
+ m_waitInputMediaTypeWaiter = CreateEvent( NULL,
+ FALSE,
+ FALSE,
+ TEXT("MediaTypeWaiter")
+ );
+ DMFTCHECKNULL_GOTO( m_waitInputMediaTypeWaiter, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( GenerateMFMediaTypeListFromDevice(streamId()),done );
+
+done:
+ if ( FAILED(hr) )
+ {
+ m_spSourceTransform = nullptr;
+
+ if ( m_waitInputMediaTypeWaiter )
+ {
+ CloseHandle( m_waitInputMediaTypeWaiter );
+ m_waitInputMediaTypeWaiter = NULL;
+ }
+
+ m_stStreamType = GUID_NULL;
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP CInPin::GenerateMFMediaTypeListFromDevice(
+ _In_ UINT uiStreamId
+ )
+{
+ HRESULT hr = S_OK;
+ GUID stSubType = { 0 };
+ //This is only called in the begining when the input pin is constructed
+ DMFTCHECKNULL_GOTO( m_spSourceTransform, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+ for (UINT iMediaType = 0; SUCCEEDED(hr) ; iMediaType++)
+ {
+ ComPtr<IMFMediaType> spMediaType;
+ DWORD pos = 0;
+
+ hr = m_spSourceTransform->MFTGetOutputAvailableType(uiStreamId, iMediaType, spMediaType.GetAddressOf());
+ if (hr != S_OK)
+ break;
+
+ DMFTCHECKHR_GOTO(AddMediaType(&pos, spMediaType.Get()), done);
+ }
+done:
+ if (hr == MF_E_NO_MORE_TYPES) {
+ hr = S_OK;
+ }
+ return hr;
+}
+
+STDMETHODIMP CInPin::SendSample(
+ _In_ IMFSample *pSample
+ )
+{
+ HRESULT hr = S_OK;
+ BOOL sentOne = TRUE;
+ DMFTCHECKNULL_GOTO(pSample, done, S_OK);
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG) m_outpins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ COutPin *poPin = (COutPin *)m_outpins[ ulIndex ];
+
+ pSample->AddRef();
+
+ if (FAILED(hr = poPin->AddSample(pSample, this)))
+ {
+ pSample->Release();
+ }
+ sentOne = (sentOne || SUCCEEDED(hr));
+ }
+done:
+ return sentOne ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP_(VOID) CInPin::ConnectPin( _In_ CBasePin * poPin )
+{
+ CAutoLock Lock(lock());
+ if (poPin!=nullptr)
+ {
+ m_outpins.push_back(poPin);
+ poPin->AddRef();
+ }
+}
+
+STDMETHODIMP_(DeviceStreamState) CInPin::GetState()
+{
+ return m_state;
+}
+
+STDMETHODIMP_(DeviceStreamState) CInPin::SetState( _In_ DeviceStreamState state )
+{
+ return (DeviceStreamState)InterlockedExchange((LONG*)&m_state, state );
+}
+
+STDMETHODIMP CInPin::WaitForSetInputPinMediaChange()
+{
+ DWORD dwWait = 0;
+ HRESULT hr = S_OK;
+
+ dwWait = WaitForSingleObject( m_waitInputMediaTypeWaiter, INFINITE );
+
+ if ( dwWait != WAIT_OBJECT_0 )
+ {
+ hr = E_FAIL;
+ goto done;
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CInPin::GetInputStreamPreferredState(
+ _Inout_ DeviceStreamState* value,
+ _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType
+ )
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+
+ if (value!=nullptr)
+ {
+ *value = m_preferredStreamState;
+ }
+
+ if (ppMediaType )
+ {
+ *ppMediaType = nullptr;
+ if ( m_prefferedMediaType != nullptr )
+ {
+ m_prefferedMediaType.CopyTo(ppMediaType);
+ }
+ }
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+HRESULT CInPin::SetInputStreamState(
+ _In_ IMFMediaType* pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+
+ CAutoLock Lock(lock());
+ //
+ //Set the media type
+ //
+
+ setMediaType(pMediaType);
+ SetState(value);
+
+ //
+ //Set the event. This event is being waited by an output media/state change operation
+ //
+
+ m_prefferedMediaType = nullptr;
+ SetEvent(m_waitInputMediaTypeWaiter);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+//
+//Output Pin Implementation
+//
+COutPin::COutPin(
+ _In_ ULONG ulPinId,
+ _In_opt_ CMultipinMft *pparent,
+ _In_ IKsControl* pIksControl
+ )
+ : CBasePin( ulPinId, pparent ),
+ m_firstSample( false )
+{
+ HRESULT hr = S_OK;
+ CPinState* pState = NULL;
+ ComPtr<IMFAttributes> spAttributes;
+
+ for ( ULONG ulIndex = 0; ulIndex <= DeviceStreamState_Disabled; ulIndex++ )
+ {
+ switch ( ulIndex )
+ {
+
+ case DeviceStreamState_Run:
+ pState = ( CPinState* )new CPinOpenState(this);
+ DMFTCHECKNULL_GOTO(pState, done, E_OUTOFMEMORY);
+ break;
+ case DeviceStreamState_Pause:
+ case DeviceStreamState_Stop:
+ case DeviceStreamState_Disabled:
+ //Currently both the closed and the drain state behave similarly
+ pState = ( CPinState* )new CPinClosedState();
+ DMFTCHECKNULL_GOTO(pState, done, E_OUTOFMEMORY);
+ break;
+ }
+
+ m_states.push_back( pState );
+
+ m_state = m_states[ DeviceStreamState_Stop ];
+ }
+ //
+ //Get the input pin IKS control.. the pin IKS control talks to sourcetransform's IKS control
+ //
+ m_spIkscontrol = pIksControl;
+
+ MFCreateAttributes( &spAttributes, 3 ); //Create the space for the attribute store!!
+ setAttributes( spAttributes.Get());
+ DMFTCHECKHR_GOTO( SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ), done );
+ DMFTCHECKHR_GOTO( SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft" ),done );
+ DMFTCHECKHR_GOTO( SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done );
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+}
+
+COutPin::~COutPin()
+{
+ CPinQueue *que = NULL;
+ m_spAttributes = nullptr;
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG)m_queues.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ que = m_queues[ ulIndex ];
+ delete(que);
+ que = NULL;
+ }
+ CPinState *pinState = NULL;
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_states.size(); ulIndex < ulSize; ulIndex++)
+ {
+ pinState = m_states[ ulIndex ];
+ delete( pinState );
+ pinState = NULL;
+ }
+ m_states.clear();
+ m_queues.clear();
+}
+
+/*++
+COutPin::AddPin
+Description:
+Called from AddSample if the Output Pin is in open state. This function looks for the queue
+corresponding to the input pin and adds it in the queue.
+--*/
+STDMETHODIMP COutPin::AddPin(
+ _In_ DWORD inputPinId
+ )
+{
+ //
+ //Add a new queue corresponding to the input pin
+ //
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+
+ CPinQueue *que = new (std::nothrow) CPinQueue(inputPinId);
+ DMFTCHECKNULL_GOTO( que, done, E_OUTOFMEMORY );
+ hr = ExceptionBoundary([&]()
+ {
+ (void)m_queues.push_back(que);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ //
+ //Just ramdonmize media types for odd numbered pins
+ //
+ if ( streamId() != 0 && streamId() % 2 != 0 )
+ {
+ RandomnizeMediaTypes(m_listOfMediaTypes);
+ }
+
+done:
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return S_OK;
+}
+
+/*++
+COutPin::AddSampleInternal
+Description:
+Called from AddSample if the Output Pin is in open state. This function looks for the queue
+corresponding to the input pin and adds it in the queue.
+--*/
+
+STDMETHODIMP COutPin::AddSampleInternal( _In_ IMFSample *pSample, _In_ CBasePin *pPin )
+{
+ BOOL res = true;
+ CAutoLock Lock( lock() );
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_queues.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ //
+ //This output pin maybe connected to multiple input pins
+ //Only insert into the corresponding queue to the input pin on which the
+ //sample is received
+ //
+ if (m_queues[dwIndex]->pinStreamId() == pPin->streamId())
+ {
+ if (! m_queues[ dwIndex ]->Insert( pSample ) )
+ {
+ res |= false;
+ }
+
+ }
+ }
+ return res ? S_OK : E_FAIL;
+}
+
+/*++
+COutPin::AddSample
+Description:
+Called when ProcessInput is called on the Device Transform. The Input Pin puts the samples
+in the pins connected. If the Output pins are in open state the sample lands in the queues
+--*/
+
+STDMETHODIMP COutPin::AddSample( _In_ IMFSample *pSample, _In_ CBasePin *pPin)
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock( lock() );
+
+ DMFTCHECKHR_GOTO( m_state->Open(), done );
+
+ DMFTCHECKHR_GOTO( AddSampleInternal( pSample, pPin ),done );
+
+done:
+ return hr;
+}
+
+/*++
+COutPin::SetState
+Description:
+State setter for the output pin
+--*/
+STDMETHODIMP_(VOID) COutPin::SetFirstSample(
+ _In_ BOOL fisrtSample )
+{
+ m_firstSample = fisrtSample;
+}
+
+/*++
+COutPin::GetState
+Description:
+State getter for the output pin
+--*/
+DeviceStreamState COutPin::GetState()
+{
+ return m_state->State();
+}
+
+/*++
+COutPin::SetState
+Description:
+State setter for the output pin
+--*/
+
+DeviceStreamState COutPin::SetState(DeviceStreamState state)
+{
+ CAutoLock Lock(lock());
+ DeviceStreamState oldState = m_state->State();
+ m_state = m_states[state];
+ return oldState;
+
+}
+
+/*++
+COutPin::FlushQueues
+Description:
+Called from the device Transform when the output queues have to be flushed
+
+--*/
+HRESULT COutPin::FlushQueues()
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock( lock() );
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ CPinQueue *que = m_queues[ dwIndex ];
+ que->Clear();
+ }
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+/*++
+COutPin::ChangeMediaTypeFromInpin
+Description:
+called from the Device Transfrom When the input media type is changed. This will result in
+the xvp being possibly installed in the queue if the media types set on the input
+and the output dont match
+--*/
+HRESULT COutPin::ChangeMediaTypeFromInpin(
+ _In_ CInPin* inPin,
+ _In_ IMFMediaType *pInMediatype,
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state)
+{
+ HRESULT hr = S_OK;
+ CPinQueue *que = NULL;
+ CAutoLock Lock(lock());
+ //
+ //Set the state to disabled and while going out we will reset the state back to the requested state
+ //Flush so that we drop any samples we have in store!!
+ //
+ SetState(DeviceStreamState_Disabled);
+ FlushQueues();
+
+ for (DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++)
+ {
+ que = m_queues[ dwIndex ];
+ if (inPin->streamId() == que->pinStreamId())
+ {
+ break;
+ }
+ que = NULL;
+ }
+
+ if ( que )
+ {
+ //
+ //recreate the tee, pass the D3D Manager to the Tee which will use DX if D3D manager is present
+ //
+ IUnknown *pD3DManagerUnk = NULL;
+
+ (VOID)Parent()->GetD3DDeviceManager( &pD3DManagerUnk );
+ hr = que->RecreateTee( pInMediatype, pOutMediaType, pD3DManagerUnk );
+ if ( SUCCEEDED( hr ) )
+ {
+ (VOID)setMediaType( pOutMediaType );
+ (VOID)SetState( state );
+ }
+ SAFE_RELEASE(pD3DManagerUnk);
+ }
+ return hr;
+}
+
+/*++
+Description:
+ called from the IMFdeviceTransform's
+--*/
+
+STDMETHODIMP COutPin::GetOutputStreamInfo(
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+ )
+{
+ HRESULT hr = S_OK;
+ IMFMediaType* pMediatype = nullptr;
+
+ getMediaType( &pMediatype );
+
+ if (SUCCEEDED(hr) && !pMediatype) {
+ pMediatype->Release();
+ pStreamInfo->cbAlignment = 0;
+ pStreamInfo->cbSize = 0;
+ pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
+ pStreamInfo->dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
+ //We provide our samples..
+ }
+ else {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+ return hr;
+}
+
+/*++
+COutPin::ProcessOutput
+Description:
+ called from the Device Transfrom when the transform manager demands output samples..
+ If we have samples we forward it.
+ If we are a photo pin then we forward only if trigger is sent. We ask the devicetransform if we have recieved the transform or not.
+ If we have recieved the sample and we are passing out a sample we should reset the trigger set on the Device Transform
+--*/
+
+STDMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ )
+{
+ HRESULT hr = S_OK;
+ IMFSample* pSample = nullptr;
+ GUID pinClsid = GUID_NULL;
+ BOOL IsImagePin = FALSE;
+ BOOL IsSkipSample = FALSE;
+ UNREFERENCED_PARAMETER(pdwStatus);
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock lock(lock());
+ DMFTCHECKHR_GOTO(m_state->Open(), done);
+
+ //
+ //Check if we are an image photo pin. The process output in that case should only proceed if trigger has been sent
+ //Candidate for subclass!
+ //
+
+ if (SUCCEEDED(GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinClsid))
+ && ((IsEqualCLSID(pinClsid, PINNAME_IMAGE)) || IsEqualCLSID(pinClsid, PINNAME_VIDEO_STILL)))
+ {
+ IsImagePin = TRUE;
+ }
+
+ if (IsImagePin && !Parent()->isPhotoTriggerSent())
+ {
+ IsSkipSample = TRUE;
+ }
+
+
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ CPinQueue *que = m_queues[dwIndex];
+
+ pOutputSample->dwStatus = S_OK;
+
+ if (!que->Remove(&pSample))
+ {
+ break;
+ }
+
+ MFTIME llTime = 0L;
+
+ if (FAILED(pSample->GetSampleTime(&llTime)))
+ {
+ llTime = MFGetSystemTime();
+ pSample->SetSampleTime(llTime);
+ }
+
+ if (!IsSkipSample)
+ {
+ if (m_firstSample)
+ {
+ pSample->SetUINT32(MFSampleExtension_Discontinuity,TRUE);
+ SetFirstSample(FALSE);
+ }
+
+ //
+ // Any processing before we pass the sample to further in the pipeline should be done here
+ // PROCESSSAMPLE(pSample);
+ //
+
+ pOutputSample->pSample = pSample;
+ pOutputSample->dwStatus = S_OK;
+ }
+ else
+ {
+ SAFERELEASE(pSample);
+ }
+ }
+ if (!IsSkipSample && IsImagePin && pSample)
+ {
+ //
+ //A sample has been sent over so image pin should exit
+ //
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ if (Parent()->IsPhotoConfirmationEnabled())
+ {
+ //
+ // Photo confirmation is enabled i.e. the pipeline has set up photo confirmation
+ // Service photo confirmation.
+ //
+ ComPtr<IMFMediaType> spMediaType = nullptr;
+
+ DMFTCHECKHR_GOTO(getMediaType(spMediaType.GetAddressOf()), done);
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Calling PhotoConfirmation %p, is passed", pSample);
+
+ DMFTCHECKHR_GOTO(Parent()->ProcessCapturePhotoConfirmationCallBack(spMediaType.Get(), pSample), done);
+ }
+#endif
+ if (!Parent()->isPhotoModePhotoSequence())
+ {
+ //
+ //A sample has been sent over so image pin should exit
+ //
+ Parent()->setPhotoTriggerSent(FALSE);
+ }
+ }
+done:
+ return hr;
+}
+
+/*++
+ COutPin::KsProperty
+Description:
+The KsProperty for the Pin.. this is to reroute all pin kscontrols to the input pin
+--*/
+STDMETHODIMP COutPin::KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+{
+ //
+ //Route it to input pin
+ //
+ return m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pPropertyData,
+ ulDataLength,
+ pBytesReturned);
+}
+
+
+
diff --git a/AVStream/sampledevicemft/basepin.h b/AVStream/sampledevicemft/basepin.h
new file mode 100644
index 00000000..9b254e2a
--- /dev/null
+++ b/AVStream/sampledevicemft/basepin.h
@@ -0,0 +1,596 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+#pragma once
+#include "stdafx.h"
+#include "common.h"
+
+
+extern DeviceStreamState pinStateTransition[][4];
+
+
+class CPinQueue;
+class CPinState;
+class CMultipinMft;
+
+class CBasePin:
+ public IMFAttributes,
+ public IKsControl
+{
+public:
+ CBasePin( _In_ ULONG _id=0, _In_ CMultipinMft *parent=NULL);
+
+ virtual ~CBasePin() = 0;
+ virtual STDMETHODIMP_(DeviceStreamState) GetState() = 0;
+ virtual STDMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState State) = 0;
+
+
+ //
+ //IUnknown Interface functions
+ //
+
+ STDMETHODIMP_(ULONG) AddRef(
+ void
+ )
+ {
+ return InterlockedIncrement(&m_nRefCount);
+ }
+ STDMETHODIMP_(ULONG) Release(
+ void
+ )
+ {
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+ if (uCount == 0)
+ {
+ delete this;
+ }
+ return uCount;
+ }
+
+ STDMETHODIMP_(HRESULT) QueryInterface(
+ _In_ REFIID riid,
+ _Outptr_result_maybenull_ void **ppvObject
+ );
+ //
+ // IKsControl Interface functions
+ //
+
+ STDMETHOD(KsProperty)(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+ {
+ if ( m_spIkscontrol!=nullptr )
+ {
+ return m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pPropertyData,
+ ulDataLength,
+ pBytesReturned);
+ }
+ else
+ {
+ return E_NOTIMPL;
+ }
+ }
+ //
+ //NOOPs for this iteration..
+ //
+ STDMETHOD(KsMethod)(
+ _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod,
+ _In_ ULONG ulMethodLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pMethodData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+ {
+ UNREFERENCED_PARAMETER(pBytesReturned);
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pMethodData);
+ UNREFERENCED_PARAMETER(pMethod);
+ UNREFERENCED_PARAMETER(ulMethodLength);
+ return S_OK;
+ }
+
+ STDMETHOD(KsEvent)(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+ {
+ UNREFERENCED_PARAMETER(pBytesReturned);
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pEventData);
+ UNREFERENCED_PARAMETER(pEvent);
+ UNREFERENCED_PARAMETER(ulEventLength);
+ return S_OK;
+ }
+
+ //
+ //IMFAttributes implementation
+ //
+ STDMETHOD(GetItem)(
+ _In_ REFGUID guidKey,
+ _Inout_opt_ PROPVARIANT* pValue
+ )
+ {
+ return m_spAttributes->GetItem(guidKey, pValue);
+ }
+
+ STDMETHOD(GetItemType)(
+ _In_ REFGUID guidKey,
+ _Out_ MF_ATTRIBUTE_TYPE* pType
+ )
+ {
+ return m_spAttributes->GetItemType(guidKey, pType);
+ }
+
+ STDMETHOD(CompareItem)(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_spAttributes->CompareItem(guidKey, Value, pbResult);
+ }
+
+ STDMETHOD(Compare)(
+ _In_ IMFAttributes* pTheirs,
+ _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_spAttributes->Compare(pTheirs, MatchType, pbResult);
+ }
+
+ STDMETHOD(GetUINT32)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* punValue
+ )
+ {
+ return m_spAttributes->GetUINT32(guidKey, punValue);
+ }
+
+ STDMETHOD(GetUINT64)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT64* punValue
+ )
+ {
+ return m_spAttributes->GetUINT64(guidKey, punValue);
+ }
+
+ STDMETHOD(GetDouble)(
+ _In_ REFGUID guidKey,
+ _Out_ double* pfValue
+ )
+ {
+ return m_spAttributes->GetDouble(guidKey, pfValue);
+ }
+
+ STDMETHOD(GetGUID)(
+ _In_ REFGUID guidKey,
+ _Out_ GUID* pguidValue
+ )
+ {
+ return m_spAttributes->GetGUID(guidKey, pguidValue);
+ }
+
+ STDMETHOD(GetStringLength)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetStringLength(guidKey, pcchLength);
+ }
+
+ STDMETHOD(GetString)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cchBufSize) LPWSTR pwszValue,
+ _In_ UINT32 cchBufSize,
+ _Inout_opt_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
+ }
+
+ STDMETHOD(GetAllocatedString)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue,
+ _Inout_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
+ }
+
+ STDMETHOD(GetBlobSize)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcbBlobSize
+ )
+ {
+ return m_spAttributes->GetBlobSize(guidKey, pcbBlobSize);
+ }
+
+ STDMETHOD(GetBlob)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cbBufSize) UINT8* pBuf,
+ UINT32 cbBufSize,
+ _Inout_ UINT32* pcbBlobSize
+ )
+ {
+ return m_spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
+ }
+
+ STDMETHOD(GetAllocatedBlob)(
+ __RPC__in REFGUID guidKey,
+ __RPC__deref_out_ecount_full_opt(*pcbSize) UINT8** ppBuf,
+ __RPC__out UINT32* pcbSize
+ )
+ {
+ return m_spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
+ }
+
+ STDMETHOD(GetUnknown)(
+ __RPC__in REFGUID guidKey,
+ __RPC__in REFIID riid,
+ __RPC__deref_out_opt LPVOID *ppv
+ )
+ {
+ return m_spAttributes->GetUnknown(guidKey, riid, ppv);
+ }
+
+ STDMETHOD(SetItem)(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value
+ )
+ {
+ return m_spAttributes->SetItem(guidKey, Value);
+ }
+
+ STDMETHOD(DeleteItem)(
+ _In_ REFGUID guidKey
+ )
+ {
+ return m_spAttributes->DeleteItem(guidKey);
+ }
+
+ STDMETHOD(DeleteAllItems)()
+ {
+ return m_spAttributes->DeleteAllItems();
+ }
+
+ STDMETHOD(SetUINT32)(
+ _In_ REFGUID guidKey,
+ _In_ UINT32 unValue
+ )
+ {
+ return m_spAttributes->SetUINT32(guidKey, unValue);
+ }
+
+ STDMETHOD(SetUINT64)(
+ _In_ REFGUID guidKey,
+ _In_ UINT64 unValue
+ )
+ {
+ return m_spAttributes->SetUINT64(guidKey, unValue);
+ }
+
+ STDMETHOD(SetDouble)(
+ _In_ REFGUID guidKey,
+ _In_ double fValue
+ )
+ {
+ return m_spAttributes->SetDouble(guidKey, fValue);
+ }
+
+ STDMETHOD(SetGUID)(
+ _In_ REFGUID guidKey,
+ _In_ REFGUID guidValue
+ )
+ {
+ return m_spAttributes->SetGUID(guidKey, guidValue);
+ }
+
+ STDMETHOD(SetString)(
+ _In_ REFGUID guidKey,
+ _In_ LPCWSTR wszValue
+ )
+ {
+ return m_spAttributes->SetString(guidKey, wszValue);
+ }
+
+ STDMETHOD(SetBlob)(
+ _In_ REFGUID guidKey,
+ _In_reads_(cbBufSize) const UINT8* pBuf,
+ UINT32 cbBufSize
+ )
+ {
+ return m_spAttributes->SetBlob(guidKey, pBuf, cbBufSize);
+ }
+
+ STDMETHOD(SetUnknown)(
+ _In_ REFGUID guidKey,
+ _In_ IUnknown* pUnknown
+ )
+ {
+ return m_spAttributes->SetUnknown(guidKey, pUnknown);
+ }
+
+ STDMETHOD(LockStore)()
+ {
+ return m_spAttributes->LockStore();
+ }
+
+ STDMETHOD(UnlockStore)()
+ {
+ return m_spAttributes->UnlockStore();
+ }
+
+ STDMETHOD(GetCount)(
+ _Out_ UINT32* pcItems
+ )
+ {
+ return m_spAttributes->GetCount(pcItems);
+ }
+
+ STDMETHOD(GetItemByIndex)(
+ UINT32 unIndex,
+ _Out_ GUID* pguidKey,
+ _Inout_ PROPVARIANT* pValue
+ )
+ {
+ return m_spAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
+ }
+
+ STDMETHOD(CopyAllItems)(
+ _In_ IMFAttributes* pDest
+ )
+ {
+ return m_spAttributes->CopyAllItems(pDest);
+ }
+
+ //
+ //Helper Functions
+ //
+ __inline DWORD streamId()
+ {
+ return m_StreamId;
+ }
+
+ __inline VOID setMediaType(_In_opt_ IMFMediaType *pMediaType)
+ {
+ m_setMediaType = pMediaType;
+ }
+
+ __inline HRESULT getMediaType(_Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType)
+ {
+ HRESULT hr = S_OK;
+ if (!ppMediaType)
+ return E_INVALIDARG;
+
+ if (m_setMediaType != nullptr)
+ {
+ hr = m_setMediaType.CopyTo(ppMediaType);
+ }
+ else
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+ return hr;
+ }
+
+ __inline STDMETHOD (getPinAttributes) (_In_ IMFAttributes **ppAttributes)
+ {
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ DMFTCHECKHR_GOTO ( QueryInterface( IID_PPV_ARGS(ppAttributes) ), done );
+ done:
+ return hr;
+ }
+
+ STDMETHODIMP AddMediaType(
+ _Inout_ DWORD *pos,
+ _In_ IMFMediaType *pMediatype); /*Filling the media types data structure*/
+ STDMETHODIMP GetMediaTypeAt(
+ _In_ DWORD pos,
+ _Outptr_result_maybenull_ IMFMediaType **pMediaType); /* getting the data from the data structure*/
+ STDMETHODIMP_(BOOL) IsMediaTypeSupported(
+ _In_ IMFMediaType *pMediaType,
+ _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
+ IMFMediaType **ppIMFMediaTypeFull);
+ STDMETHODIMP GetOutputAvailableType(
+ _In_ DWORD dwTypeIndex,
+ _Out_opt_ IMFMediaType **ppType);
+
+protected:
+ //
+ //Inline helper functions
+ //
+ _inline CMultipinMft* Parent()
+ {
+ return m_Parent.Get();
+ }
+ __inline HRESULT setAttributes(_In_ IMFAttributes* _pAttributes)
+ {
+ m_spAttributes = _pAttributes;
+ return S_OK;
+ }
+ __inline CCritSec& lock()
+ {
+ return m_lock;
+ }
+ IMFMediaTypeArray m_listOfMediaTypes;
+ ComPtr<IMFAttributes> m_spAttributes;
+ ComPtr<IKsControl> m_spIkscontrol;
+
+private:
+ ULONG m_StreamId; /*Device Stream Id*/
+ CCritSec m_lock; /*This is only used to change the reference count i.e. active users of this stream*/
+ ComPtr<IMFMediaType> m_setMediaType;
+ ComPtr<CMultipinMft> m_Parent;
+ ULONG m_nRefCount;
+};
+
+
+
+class CInPin: public CBasePin{
+public:
+ CInPin( _In_opt_ IMFAttributes*, _In_ ULONG ulPinId = 0, _In_ CMultipinMft *pParent=NULL);
+ ~CInPin();
+
+ STDMETHOD ( Init )(
+ _In_ IMFTransform *
+ );
+ STDMETHOD_( VOID, ConnectPin)(
+ _In_ CBasePin *
+ );
+ STDMETHOD (SendSample)(
+ _In_ IMFSample *
+ );
+ STDMETHODIMP GenerateMFMediaTypeListFromDevice(
+ _In_ UINT uiStreamId
+ );
+ STDMETHODIMP WaitForSetInputPinMediaChange(
+ );
+ STDMETHOD_ (DeviceStreamState, SetState)(
+ _In_ DeviceStreamState
+ ); /*True for Active and False for Stop*/
+ STDMETHOD_(DeviceStreamState, GetState)(
+ VOID
+ );
+ //
+ //Corresponding IMFDeviceTransform functions for the Pin
+ //
+ STDMETHODIMP_(HRESULT) GetInputStreamPreferredState(
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType
+ );
+ STDMETHODIMP_(HRESULT) SetInputStreamState(
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ );
+
+ //
+ //Inline functions
+ //
+ __inline IMFMediaType* getPreferredMediaType()
+ {
+ return m_prefferedMediaType.Get();
+ }
+ __inline VOID setPreferredMediaType( _In_ IMFMediaType *pMediaType)
+ {
+ m_prefferedMediaType = pMediaType;
+ }
+ __inline DeviceStreamState setPreferredStreamState(_In_ DeviceStreamState streamState)
+ {
+ return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_preferredStreamState, (LONG)streamState, (LONG)m_preferredStreamState);
+ }
+ __inline DeviceStreamState getPreferredStreamState()
+ {
+ return m_preferredStreamState;
+ }
+
+protected:
+ ComPtr<IMFTransform> m_spSourceTransform; /*Source Transform*/
+private:
+ GUID m_stStreamType; /*GUID representing the GUID*/
+ ULONG m_activeStreamCount; /*Set when this stream is active*/
+ vector<CBasePin*> m_outpins;
+ DeviceStreamState m_state;
+ DeviceStreamState m_preferredStreamState;
+ ComPtr<IMFMediaType> m_prefferedMediaType;
+ HANDLE m_waitInputMediaTypeWaiter; /*Set when the input media type is changed*/
+};
+
+
+
+class COutPin: public CBasePin{
+public:
+ COutPin( _In_ ULONG id = 0,
+ _In_opt_ CMultipinMft *pparent = NULL,
+ _In_ IKsControl* iksControl=NULL);
+ ~COutPin();
+ STDMETHODIMP AddPin(
+ _In_ DWORD pinId
+ );
+ STDMETHODIMP AddSample(
+ _In_ IMFSample *pSample,
+ _In_ CBasePin *inPin
+ );
+ STDMETHODIMP AddSampleInternal(
+ _In_ IMFSample *pSample,
+ _In_ CBasePin *inPin
+ );
+ STDMETHODIMP RemoveSample(
+ _Out_ IMFSample **
+ );
+ STDMETHODIMP_(DeviceStreamState) SetState(
+ _In_ DeviceStreamState
+ ); /*True for Active and False for Stop*/
+ STDMETHODIMP_(DeviceStreamState) GetState(
+ );
+ STDMETHODIMP FlushQueues(
+ );
+ STDMETHODIMP GetOutputStreamInfo(
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+ );
+ STDMETHODIMP ChangeMediaTypeFromInpin(
+ _In_ CInPin* inPin,
+ _In_ IMFMediaType *pInMediatype,
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state );
+ STDMETHODIMP ProcessOutput (
+ _In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ );
+ STDMETHODIMP KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ );
+ STDMETHODIMP_(VOID) SetD3Dmanager(
+ _In_opt_ IUnknown *
+ );
+ STDMETHODIMP_(VOID) SetFirstSample(
+ _In_ BOOL
+ );
+
+
+private:
+ vector< CPinState *> m_states; /*Array of possible states*/
+ CPinState* m_state; /*Current state*/
+ vector< CPinQueue *> m_queues; /*List of Queues corresponding to input pins*/
+ BOOL m_firstSample;
+ friend class CPinState;
+};
+
+//
+//Not Implemented!!!
+//
+
+class CImagePin : public COutPin{
+private:
+ BOOL isTriggerSent;
+public:
+ CImagePin();
+ ~CImagePin();
+ STDMETHODIMP ProcessOutput(
+ _In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ );
+};
+
+
diff --git a/AVStream/sampledevicemft/common.h b/AVStream/sampledevicemft/common.h
new file mode 100644
index 00000000..238decfb
--- /dev/null
+++ b/AVStream/sampledevicemft/common.h
@@ -0,0 +1,717 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#pragma once
+
+#define GUID_STRING_LENGTH 36
+#define GUID_BUFFER_SIZE 37
+#define SLEEP_5MILLISEC 5
+#define SLEEP_ONE_SECOND 1000 // One second in milli seconds.
+
+#ifndef MF_WPP
+#define DMFTRACE(...)
+#endif
+
+//TP_NORMAL
+//TP_LOWEST
+//TP_LOW
+//TP_HIGH
+//TP_HIGHEST
+//TP_ERROR
+//TP_MUTED = 0x00070000
+
+
+
+#define mf_assert(a) if(!a) DebugBreak()
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(CtlGUID_DMFTTrace, (CBCCA12E, 9472, 409D, A1B1, 753C98BF03C0), \
+ WPP_DEFINE_BIT(DMFT_INIT) \
+ WPP_DEFINE_BIT(DMFT_CONTROL) \
+ WPP_DEFINE_BIT(DMFT_GENERAL) \
+ )
+
+#define WPP_LEVEL_FLAG_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)
+#define WPP_LEVEL_FLAG_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+#define WPP_FLAG_LEVEL_LOGGER(flags,lvl) WPP_LEVEL_LOGGER(flags)
+#define WPP_FLAG_LEVEL_ENABLED(flags, lvl) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+#define SAFE_ADDREF(p) if( NULL != p ) { ( p )->AddRef(); }
+#define SAFE_DELETE(p) delete p; p = NULL;
+#define SAFE_SHUTDELETE(p) if( NULL != p ) { ( p )->Shutdown(); delete p; p = NULL; }
+#define SAFE_RELEASE(p) if( NULL != p ) { ( p )->Release(); p = NULL; }
+#define SAFE_SHUTRELEASE(p) if( NULL != p ) { ( p )->Shutdown(); ( p )->Release(); p = NULL; }
+#define SAFE_CLOSERELEASE(p) if( NULL != p ) { ( p )->Close( TRUE ); ( p )->Release(); p = NULL; }
+#define SAFE_COTASKMEMFREE(p) CoTaskMemFree( p ); p = NULL;
+#define SAFE_SYSFREESTRING(p) SysFreeString( p ); p = NULL;
+#define SAFE_ARRAYDELETE(p) delete [] p; p = NULL;
+#define SAFE_BYTEARRAYDELETE(p) delete [] (BYTE*) p; p = NULL;
+
+
+
+#define DMFTCHECKHR_GOTO(val,label) \
+ hr = (val); \
+if (FAILED(hr)) {\
+ /*DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); */\
+ goto label; \
+}
+
+
+#define DMFTCHECKNULL_GOTO( val, label, err) \
+if( (val) == NULL ) { \
+ hr = (err); \
+ /*DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);*/\
+ goto label; \
+}
+
+#define TP_SCOPE_TRACE TP_NORMAL
+#define DH_THIS_FILE DH_DEVPROXY
+
+#define SAFERELEASE(x) \
+if (x) {\
+ x->Release(); \
+ x = NULL; \
+}
+
+#define CHK_LOG_BRK(exp) \
+if (FAILED(hr = (exp))) {\
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ /*MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MULTIPINERROR File: %s Ln:%d",__FILE__,__LINE__);*/\
+ break; \
+}
+
+
+#define CHK_NULL_BRK(exp) \
+if ((exp) == NULL) {\
+hr = E_OUTOFMEMORY; \
+wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+break; \
+}
+
+#define CHK_NULL_PTR_BRK(exp) \
+if ((exp) == NULL) {\
+hr = E_INVALIDARG; \
+wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+break; \
+}
+
+#define CHK_BOOL_BRK(exp) \
+if (!exp) {\
+ hr = E_FAIL; \
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ break; \
+}
+
+
+//
+// The Below type definitions are added for this iteration. It will taken out in the
+// next one when we will have the windows headers modified to include the interfaces
+// externally.
+//
+
+
+#if !defined(_IKsControl_)
+#define _IKsControl_
+interface DECLSPEC_UUID("28F54685-06FD-11D2-B27A-00A0C9223196") IKsControl;
+#undef INTERFACE
+#define INTERFACE IKsControl
+DECLARE_INTERFACE_(IKsControl, IUnknown)
+{
+ STDMETHOD(KsProperty)(
+ THIS_
+ IN PKSPROPERTY Property,
+ IN ULONG PropertyLength,
+ IN OUT LPVOID PropertyData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+ STDMETHOD(KsMethod)(
+ THIS_
+ IN PKSMETHOD Method,
+ IN ULONG MethodLength,
+ IN OUT LPVOID MethodData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+ STDMETHOD(KsEvent)(
+ THIS_
+ IN PKSEVENT Event OPTIONAL,
+ IN ULONG EventLength,
+ IN OUT LPVOID EventData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+};
+#endif //!defined(_IKsControl_)
+
+
+
+#if !defined(__IMFDeviceTransform_INTERFACE_DEFINED__)
+//
+//These definitions will have to be taken out when the
+//internal defines are made public
+//
+
+EXTERN_GUID(MEDeviceStreamCreated, 0x0252a1cf, 0x3540, 0x43b4, 0x91, 0x64, 0xd7, 0x2e, 0xb4, 0x05, 0xfa, 0x40);
+
+typedef
+enum _DeviceStreamState
+{
+ DeviceStreamState_Stop = 0,
+ DeviceStreamState_Pause = (DeviceStreamState_Stop + 1),
+ DeviceStreamState_Run = (DeviceStreamState_Pause + 1),
+ DeviceStreamState_Disabled = (DeviceStreamState_Run + 1)
+} DeviceStreamState;
+
+/* size is 4, align is 4*/
+typedef enum _DeviceStreamState *PDeviceStreamState;
+
+EXTERN_C const IID IID_IMFDeviceTransform;
+MIDL_INTERFACE("D818FBD8-FC46-42F2-87AC-1EA2D1F9BF32")
+IMFDeviceTransform : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE InitializeTransform(
+ /* [annotation][in] */
+ _In_ IMFAttributes *pAttributes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputAvailableType(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][in] */
+ _In_ DWORD dwTypeIndex,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputCurrentType(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputStreamAttributes(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFAttributes **ppAttributes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputAvailableType(
+ /* [annotation][in] */
+ _In_ DWORD dwOutputStreamID,
+ /* [annotation][in] */
+ _In_ DWORD dwTypeIndex,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputCurrentType(
+ /* [annotation][in] */
+ _In_ DWORD dwOutputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputStreamAttributes(
+ /* [annotation][in] */
+ _In_ DWORD dwOutputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFAttributes **ppAttributes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStreamCount(
+ /* [annotation][out] */
+ _Out_ DWORD *pcInputStreams,
+ /* [annotation][out] */
+ _Out_ DWORD *pcOutputStreams) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStreamIDs(
+ /* [annotation][in] */
+ _In_ DWORD dwInputIDArraySize,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwInputStreamIds,
+ /* [annotation][in] */
+ _In_ DWORD dwOutputIDArraySize,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwOutputStreamIds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessEvent(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][in] */
+ _In_ IMFMediaEvent *pEvent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessInput(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][in] */
+ _In_ IMFSample *pSample,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
+ /* [annotation][in] */
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ /* [annotation][in] */
+ _In_ ULONG_PTR ulParam) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessOutput(
+ /* [annotation][in] */
+ _In_ DWORD dwFlags,
+ /* [annotation][in] */
+ _In_ DWORD cOutputBufferCount,
+ /* [size_is][annotation][out][in] */
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetInputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][in] */
+ _In_ IMFMediaType *pMediaType,
+ /* [annotation][in] */
+ _In_ DeviceStreamState value,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][out] */
+ _Out_ DeviceStreamState *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetOutputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][in] */
+ _In_ IMFMediaType *pMediaType,
+ /* [annotation][in] */
+ _In_ DeviceStreamState value,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][out] */
+ _Out_ DeviceStreamState *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputStreamPreferredState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][out] */
+ _Out_ DeviceStreamState *value,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **ppMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushInputStream(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamIndex,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushOutputStream(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamIndex,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+};
+
+#endif
+
+
+interface IDirect3DDeviceManager9;
+//Forward defintion
+class CBasePin;
+//////////////////////////////////////////////////////////////////////////
+// CCritSec
+// Description: Wraps a critical section.
+//////////////////////////////////////////////////////////////////////////
+
+class CCritSec
+{
+private:
+ CRITICAL_SECTION m_criticalSection;
+public:
+ CCritSec();
+ ~CCritSec();
+ _Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection)
+ void Lock();
+ _Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection)
+ void Unlock();
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// CAutoLock
+// Description: Provides automatic locking and unlocking of a
+// of a critical section.
+//////////////////////////////////////////////////////////////////////////
+
+class CAutoLock
+{
+protected:
+ CCritSec *m_pCriticalSection;
+public:
+ _Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+ CAutoLock(CCritSec& crit);
+ _Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+ CAutoLock(CCritSec* crit);
+ _Releases_lock_(this->m_pCriticalSection->m_criticalSection)
+ ~CAutoLock();
+};
+
+//////////////////////////////////////////////////////////////////////////
+// CMediaTypePrinter
+// Description: Rudimentary class for printing media type!
+//////////////////////////////////////////////////////////////////////////
+
+#define MEDIAPRINTER_STARTLEN (512)
+
+class CMediaTypePrinter{
+private:
+ IMFMediaType *pMediaType;
+ PCHAR m_pBuffer;
+ ULONG buffLen;
+public:
+ CMediaTypePrinter( _In_ IMFMediaType *_pMediaType );
+ ~CMediaTypePrinter( );
+ STDMETHODIMP_(PCHAR) ToCompleteString( );
+ STDMETHODIMP_(PCHAR) ToString();
+};
+
+
+//
+//The below guid is used to register the GUID as the Device Transform. This should be adeed to the
+//HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\ and under the
+//GLOBAL#\Device Parameters key, add a CameraDeviceMFTCLSID value, and set its value to
+// {0E313280-3169-4F41-A329-9E854169634F} for the Pipeline to pick up the Transform.
+//
+DEFINE_GUID(CLSID_MultiPinMFT,
+ 0xe313280, 0x3169, 0x4f41, 0xa3, 0x29, 0x9e, 0x85, 0x41, 0x69, 0x63, 0x4f);
+
+
+typedef enum _MF_TRANSFORM_XVP_OPERATION{
+ DeviceMftTransformXVPDisruptiveIn, //Break the XVP tranform and go to the new Media Type
+ DeviceMftTransformXVPDisruptiveOut, //Keep the old transform
+ DeviceMftTransformXVPCurrent, //Don't need an XVP
+ DeviceMftTransformXVPIllegal //Either of the media types NULL, Major types don't match
+}MF_TRANSFORM_XVP_OPERATION,*PMF_TRANSFORM_XVP_OPERATION;
+
+typedef std::vector< IMFMediaType *> IMFMediaTypeArray;
+typedef std::vector< CBasePin *> CBasePinArray;
+typedef std::vector< IMFSample *> IMFSampleList;
+typedef std::pair< std::multimap<int, int>::iterator, std::multimap<int, int>::iterator > MMFTMMAPITERATOR;
+
+
+HRESULT CreateCodec(
+ _In_opt_ IMFMediaType * inMediaType,
+ _In_opt_ IMFMediaType *outMediaType,
+ _In_ BOOL operation /*True = Encode, False = Decode*/,
+ _Out_ IMFTransform **pTransform
+ );
+
+STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair(
+ _In_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *outMediaType,
+ _Out_ bool *optimized,
+ _Out_ bool *optimizedxvpneeded
+ );
+
+STDMETHODIMP CompareMediaTypesForXVP(_In_opt_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *newMediaType,
+ _Inout_ MF_TRANSFORM_XVP_OPERATION *operation
+ );
+
+STDMETHODIMP RandomnizeMediaTypes(
+ _In_ IMFMediaTypeArray &pMediaTypeArray
+ );
+
+STDMETHODIMP IsInputDxSample(
+ _In_ IMFSample* pSample,
+ _Inout_ BOOL *isDxSample
+ );
+
+STDMETHODIMP_(BOOL) IsPinStateInActive(
+ _In_ DeviceStreamState state
+ );
+
+STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(
+ _In_ GUID guidSubType
+ );
+LPSTR DumpGUIDA(
+ _In_ REFGUID guid
+ );
+
+
+void printMessageEvent(MFT_MESSAGE_TYPE msg);
+
+
+template <typename Lambda>
+HRESULT ExceptionBoundary(Lambda&& lambda)
+{
+ try
+ {
+ lambda();
+ return S_OK;
+ }
+ catch (const _com_error& e)
+ {
+ return e.Error();
+ }
+ catch (const std::bad_alloc&)
+ {
+ return E_OUTOFMEMORY;
+ }
+ catch (const std::out_of_range&)
+ {
+ return MF_E_INVALIDINDEX;
+ }
+ catch (...)
+ {
+ return E_FAIL;
+ }
+}
+
+
+//
+// Custom Pin GUID. The avstream driver should define a PIN_DESCRIPTOR with this GUID
+// defined in cateogory. This will lead to devproxy creating this pin. This pin however
+// cannot be used by the pipeline as it may share a custom media type and pipeline could
+// fail. Moreover pipeline can currently (when this sample is written) only deal with
+// the known pins (PREVIEW/CAPTURE/IMAGE). This code snippet creates a custom pin
+// and
+//
+DEFINE_GUID(AVSTREAM_CUSTOM_PIN_IMAGE,
+ 0x888c4105, 0xb328, 0x4ed6, 0xa3, 0xca, 0x2f, 0xf4, 0xc0, 0x3a, 0x9f, 0x33);
+
+
+//
+// The Below redirections are to support MFT0. Implement this only if you need to load
+// MFT0 and DeviceMft simultaneously.
+//
+
+#define _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__ \
+ STDMETHOD(MFTGetStreamLimits)( \
+ _Inout_ DWORD *pdwInputMinimum, \
+ _Inout_ DWORD *pdwInputMaximum, \
+ _Inout_ DWORD *pdwOutputMinimum, \
+ _Inout_ DWORD *pdwOutputMaximum \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(pdwInputMinimum); \
+ UNREFERENCED_PARAMETER(pdwInputMaximum); \
+ UNREFERENCED_PARAMETER(pdwOutputMinimum); \
+ UNREFERENCED_PARAMETER(pdwOutputMaximum); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetStreamCount)( \
+ _Inout_ DWORD* pdwInputStreams, \
+ _Inout_ DWORD* pdwOutputStreams \
+ ) \
+{ \
+ return GetStreamCount(pdwInputStreams, pdwOutputStreams); \
+} \
+ STDMETHOD(MFTGetStreamIDs)( \
+ _In_ DWORD dwInputIDArraySize, \
+ _Inout_updates_(dwInputIDArraySize) DWORD* pdwInputIDs, \
+ _In_ DWORD dwOutputIDArraySize, \
+ _Inout_updates_(dwOutputIDArraySize) DWORD* pdwOutputIDs \
+ ) \
+{ \
+ return GetStreamIDs(dwInputIDArraySize, \
+ pdwInputIDs, \
+ dwOutputIDArraySize, \
+ pdwOutputIDs); \
+} \
+ STDMETHOD(MFTGetInputStreamInfo)( \
+ _In_ DWORD dwInputStreamID, \
+ _Inout_ MFT_INPUT_STREAM_INFO* pStreamInfo \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pStreamInfo); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetOutputStreamInfo)( \
+ _In_ DWORD dwOutputStreamID, \
+ _Inout_ MFT_OUTPUT_STREAM_INFO* pStreamInfo \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwOutputStreamID); \
+ UNREFERENCED_PARAMETER(pStreamInfo); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetInputStreamAttributes)( \
+ _In_ DWORD dwInputStreamID, \
+ _Out_ IMFAttributes** ppAttributes \
+ ) \
+{ \
+ return GetInputStreamAttributes( \
+ dwInputStreamID, \
+ ppAttributes); \
+} \
+ STDMETHOD(MFTGetOutputStreamAttributes)( \
+ _In_ DWORD dwOutputStreamID, \
+ _Out_ IMFAttributes** ppAttributes \
+ ) \
+{ \
+ return GetOutputStreamAttributes( \
+ dwOutputStreamID, ppAttributes); \
+} \
+ STDMETHOD(MFTDeleteInputStream)( \
+ _In_ DWORD dwStreamID \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwStreamID); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTAddInputStreams)( \
+ _In_ DWORD cStreams, \
+ _In_ DWORD* adwStreamIDs \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(cStreams); \
+ UNREFERENCED_PARAMETER(adwStreamIDs); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetInputAvailableType)( \
+ _In_ DWORD dwInputStreamID, \
+ _In_ DWORD dwTypeIndex, \
+ _Out_ IMFMediaType** ppType \
+ ) \
+{ \
+ return GetInputAvailableType( \
+ dwInputStreamID, dwTypeIndex, ppType); \
+} \
+ STDMETHOD(MFTGetOutputAvailableType)( \
+ _In_ DWORD dwOutputStreamID, \
+ _In_ DWORD dwTypeIndex, \
+ _Out_ IMFMediaType** ppMediaType \
+ ) \
+{ \
+ return GetOutputAvailableType( \
+ dwOutputStreamID, dwTypeIndex, ppMediaType); \
+} \
+ STDMETHOD(MFTSetInputType)( \
+ _In_ DWORD dwInputStreamID, \
+ _In_ IMFMediaType* pMediaType, \
+ _In_ DWORD dwFlags \
+ ) \
+{\
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pMediaType); \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTSetOutputType)( \
+ _In_ DWORD dwOutputStreamID, \
+ _In_ IMFMediaType* pMediaType, \
+ _In_ DWORD dwFlags \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwOutputStreamID); \
+ UNREFERENCED_PARAMETER(pMediaType); \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetInputCurrentType)( \
+ _In_ DWORD dwInputStreamID, \
+ _Out_ IMFMediaType** ppMediaType \
+ ) \
+{\
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(ppMediaType); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetOutputCurrentType)( \
+ _In_ DWORD dwOutputStreamID, \
+ _Out_ IMFMediaType** ppMediaType \
+ ) \
+{ \
+ return GetOutputCurrentType(dwOutputStreamID, ppMediaType); \
+} \
+ STDMETHOD(MFTGetInputStatus)( \
+ _In_ DWORD dwInputStreamID, \
+ _Inout_ DWORD* pdwFlags \
+ )\
+{\
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pdwFlags); \
+ return E_NOTIMPL; \
+}\
+ STDMETHOD(MFTGetOutputStatus)( \
+ _Inout_ DWORD *pdwFlags \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(pdwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTSetOutputBounds)( \
+ _In_ LONGLONG hnsLowerBound, \
+ _In_ LONGLONG hnsUpperBound \
+ ) \
+{\
+ UNREFERENCED_PARAMETER(hnsLowerBound); \
+ UNREFERENCED_PARAMETER(hnsUpperBound); \
+ return E_NOTIMPL; \
+}\
+ STDMETHOD(MFTProcessMessage)( \
+ _In_ MFT_MESSAGE_TYPE eMessage, \
+ _In_ ULONG_PTR ulParam \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(eMessage); \
+ UNREFERENCED_PARAMETER(ulParam); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTProcessInput)( \
+ _In_ DWORD dwInputStreamID, \
+ _In_ IMFSample* pSample, \
+ _In_ DWORD dwFlags \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pSample); \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTProcessOutput)( \
+ _In_ DWORD dwFlags, \
+ _In_ DWORD cOutputBufferCount, \
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, \
+ _Inout_ DWORD *pdwStatus \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ UNREFERENCED_PARAMETER(cOutputBufferCount); \
+ UNREFERENCED_PARAMETER(pOutputSamples); \
+ UNREFERENCED_PARAMETER(pdwStatus); \
+ return E_NOTIMPL; \
+}
+
+//
+// Object LifeTime manager. The Class has a global variable which
+// maintains a reference count of the number of objects in the
+// system managed by the DLL.
+//
+class CDMFTModuleLifeTimeManager{
+public:
+ CDMFTModuleLifeTimeManager()
+ {
+ InterlockedIncrement(&s_lObjectCount);
+ }
+ ~CDMFTModuleLifeTimeManager()
+ {
+ InterlockedDecrement(&s_lObjectCount);
+ }
+ static long GetDMFTObjCount()
+ {
+ return s_lObjectCount;
+ }
+private:
+ static volatile long s_lObjectCount;
+};
diff --git a/AVStream/sampledevicemft/custompin.cpp b/AVStream/sampledevicemft/custompin.cpp
new file mode 100644
index 00000000..00edb329
--- /dev/null
+++ b/AVStream/sampledevicemft/custompin.cpp
@@ -0,0 +1,98 @@
+#include "stdafx.h"
+#include "multipinmft.h"
+#include "basepin.h"
+#include "custompin.h"
+#ifdef MF_WPP
+#include "custompin.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+
+//
+// Implementation notes
+// Implement this file only if you have custom media pins streaming
+// This implementation just streams from the driver and sends it back
+// to the pipeline. This method can be used to stream 3A/Statistic Pins.
+//
+
+CCustomPin::CCustomPin(
+ _In_ IMFAttributes *pAttributes,
+ _In_ ULONG PinId,
+ _In_ CMultipinMft *pParent
+ )
+ :CInPin( pAttributes, PinId, pParent )
+{
+
+}
+//
+// Process input calls the pin here.. In this code sample we
+// don't send it anywhere. It is simply shortcircuited back to the pipeline
+//
+STDMETHODIMP CCustomPin::SendSample(
+ _In_ IMFSample *pSample
+ )
+{
+ //
+ // Log sample and exit.. The pipeline will just keep on churning more samples till
+ // We go into the stop state
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin %d recieved Sample %p", streamId(), pSample);
+
+ return S_OK;
+}
+
+//
+// State change transitions on the custom pins are different than the other pins
+// The other known pins i.e. preview, record, image etc are exposed out to the pipeline
+// and the pipeline will set state on it, reset state, For the other pins we tell the
+// pipeline that we have samples and the pipeline picks it up.
+//
+// The CUSTOM pin differs in that it's state has to be managed to by the device MFT.
+// This code snippet just varies state transitions on the custom pin when the Device MFT
+// changes state to STREAMING/END_STREAMING on it's exposed pins.
+//
+// The below function tells the pipeline to change the state on the custom pin by sending
+// METransformInputStreamStateChanged event with the streamid attribute. The pipeline will
+// call back in the custom pin at getprefferedmediatype and finally setinputstreamstate
+// which will signal back here singnalling sucessful state transition.
+//
+
+STDMETHODIMP_(DeviceStreamState) CCustomPin::SetState(
+ _In_ DeviceStreamState State
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Id:%d Transition into state: %d ", streamId(), State);
+
+ DeviceStreamState oldState = setPreferredStreamState( State );
+
+ if ( oldState != State )
+ {
+ ComPtr<IMFMediaType> preferredMediaType = nullptr;
+
+ if (State == DeviceStreamState_Run)
+ {
+ GetMediaTypeAt(0, preferredMediaType.ReleaseAndGetAddressOf());
+ }
+
+ setPreferredMediaType(preferredMediaType.Get());
+ setPreferredStreamState( State );
+
+ {
+ //
+ // Notify the device transform manager that we have changed state
+ //
+ ComPtr<IMFMediaEvent> pEvent = nullptr;
+ DMFTCHECKHR_GOTO( MFCreateMediaEvent(METransformInputStreamStateChanged, GUID_NULL, S_OK, NULL, pEvent.ReleaseAndGetAddressOf()), done );
+ DMFTCHECKHR_GOTO( pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, streamId()), done );
+ DMFTCHECKHR_GOTO( Parent()->QueueEvent(pEvent.Get()), done );
+ }
+ //
+ // Wait to be notified back from the pipeline.
+ //
+ DMFTCHECKHR_GOTO( WaitForSetInputPinMediaChange(),done );
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return oldState;
+}
diff --git a/AVStream/sampledevicemft/custompin.h b/AVStream/sampledevicemft/custompin.h
new file mode 100644
index 00000000..c0c3c35f
--- /dev/null
+++ b/AVStream/sampledevicemft/custompin.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "stdafx.h"
+#include "common.h"
+
+//
+// Custom Pin is only an input pin in this sample..It is short circuited back
+// to the pipeline. This can have uses in implementing depth pins etc.
+// It is not exposed to the down stream i.e. captureengine or the
+// WinRT code.
+//
+class CCustomPin : public CInPin{
+public:
+
+ CCustomPin(
+ _In_ IMFAttributes *pAttributes,
+ _In_ ULONG PinId,
+ _In_ CMultipinMft *pParent
+ );
+ STDMETHODIMP SendSample(
+ _In_ IMFSample *pSample
+ );
+ STDMETHODIMP_( DeviceStreamState )SetState(
+ _In_ DeviceStreamState
+ );
+};
+
+STDMETHODIMP CheckCustomPin(
+ _In_ CInPin * pin,
+ _Inout_ PBOOL isCustom
+ );
diff --git a/AVStream/sampledevicemft/dllmain.cpp b/AVStream/sampledevicemft/dllmain.cpp
new file mode 100644
index 00000000..6978a9d5
--- /dev/null
+++ b/AVStream/sampledevicemft/dllmain.cpp
@@ -0,0 +1,354 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// dllmain.cpp : Implements DLL exports and COM class factory
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Note: This source file implements the class factory for the transform,
+// plus the following DLL functions:
+// - DllMain
+// - DllCanUnloadNow
+// - DllRegisterServer
+// - DllUnregisterServer
+// - DllGetClassObject
+//
+//////////////////////////////////////////////////////////////////////////
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmft.h"
+#include <initguid.h>
+
+#ifdef MF_WPP
+#include "dllmain.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+//
+// The static variable needed to check the object count of the deviceMFts loaded.
+//
+
+volatile long CDMFTModuleLifeTimeManager::s_lObjectCount = 0;
+
+
+
+HRESULT RegisterObject(HMODULE hModule, REFGUID guid, PCWSTR pszDescription, PCWSTR pszThreadingModel);
+
+HRESULT UnregisterObject(const GUID& guid);
+
+
+// Module Ref count
+long g_cRefModule = 0;
+
+// Handle to the DLL's module
+HMODULE g_hModule = NULL;
+
+void DllAddRef()
+{
+ InterlockedIncrement(&g_cRefModule);
+}
+
+void DllRelease()
+{
+ InterlockedDecrement(&g_cRefModule);
+}
+
+//
+// IClassFactory implementation
+//
+
+typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
+struct CLASS_OBJECT_INIT
+{
+ const CLSID *pClsid;
+ PFNCREATEINSTANCE pfnCreate;
+};
+
+// Classes supported by this module:
+const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
+{
+ { &CLSID_MultiPinMFT, MFT_CreateInstance },
+};
+
+class CClassFactory : public IClassFactory
+{
+public:
+
+ static HRESULT CreateInstance(
+ REFCLSID clsid, // The CLSID of the object to create (from DllGetClassObject)
+ const CLASS_OBJECT_INIT *pClassObjectInits, // Array of class factory data.
+ size_t cClassObjectInits, // Number of elements in the array.
+ REFIID riid, // The IID of the interface to retrieve (from DllGetClassObject)
+ void **ppv // Receives a pointer to the interface.
+ )
+ {
+ *ppv = NULL;
+
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ for (size_t i = 0; i < cClassObjectInits; i++)
+ {
+ if (clsid == *pClassObjectInits[i].pClsid)
+ {
+ IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate);
+
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ break; // match found
+ }
+ }
+ return hr;
+ }
+
+ // IUnknown methods
+ IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv)
+ {
+#if 0
+ static const QITAB qit[] =
+ {
+ QITABENT(CClassFactory, IClassFactory),
+ { 0 }
+ };
+ return QISearch(this, qit, riid, ppv);
+
+#else
+ if (riid == __uuidof(IClassFactory))
+ {
+ *ppv = static_cast< IClassFactory* >(this);
+ AddRef();
+ }
+ return S_OK;
+#endif
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0)
+ {
+ delete this;
+ }
+ return cRef;
+ }
+
+ // IClassFactory methods
+
+ IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
+ {
+ return punkOuter ? CLASS_E_NOAGGREGATION : m_pfnCreate(riid, ppv);
+ }
+
+ IFACEMETHODIMP LockServer(BOOL fLock)
+ {
+ if (fLock)
+ {
+ DllAddRef();
+ }
+ else
+ {
+ DllRelease();
+ }
+ return S_OK;
+ }
+
+private:
+
+ CClassFactory(PFNCREATEINSTANCE pfnCreate) : m_cRef(1), m_pfnCreate(pfnCreate)
+ {
+ DllAddRef();
+ }
+
+ ~CClassFactory()
+ {
+ DllRelease();
+ }
+
+ long m_cRef;
+ PFNCREATEINSTANCE m_pfnCreate;
+};
+
+
+
+//
+// Standard DLL functions
+//
+
+STDMETHODIMP_(BOOL) WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void *)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hModule = (HMODULE)hInstance;
+ DisableThreadLibraryCalls(hInstance);
+#ifdef MF_WPP
+ WPP_INIT_TRACING(L"MultiPinMft");
+#endif
+ }
+ else
+ if (dwReason == DLL_PROCESS_DETACH)
+ {
+#ifdef MF_WPP
+ WPP_CLEANUP();
+#endif
+ }
+ return TRUE;
+}
+
+STDMETHODIMP DllCanUnloadNow()
+{
+ HRESULT hr = ((g_cRefModule == 0) && (CDMFTModuleLifeTimeManager::GetDMFTObjCount() == 0)) ? S_OK : S_FALSE;
+ //
+ // Debug object lifetimes
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! returning %d %d %!HRESULT!",
+ g_cRefModule,
+ CDMFTModuleLifeTimeManager::GetDMFTObjCount(),
+ hr);
+
+ return hr;
+
+}
+
+_Check_return_
+STDAPI DllGetClassObject(_In_ REFCLSID clsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv)
+{
+ return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
+}
+
+STDMETHODIMP DllRegisterServer()
+{
+ assert(g_hModule != NULL);
+
+ // Register the CLSID for CoCreateInstance.
+ HRESULT hr = RegisterObject(g_hModule, CLSID_MultiPinMFT, TEXT("Multiple MFTs"), TEXT("Both"));
+
+ return hr;
+}
+
+STDMETHODIMP DllUnregisterServer()
+{
+ // Unregister the CLSID.
+ UnregisterObject(CLSID_MultiPinMFT);
+
+ return S_OK;
+}
+
+
+// Converts a CLSID into a string with the form "CLSID\{clsid}"
+STDMETHODIMP CreateObjectKeyName(REFGUID guid, _Out_writes_(cchMax) PWSTR pszName, DWORD cchMax)
+{
+ const DWORD chars_in_guid = 39;
+
+ // convert CLSID uuid to string
+ OLECHAR szCLSID[chars_in_guid];
+ HRESULT hr = StringFromGUID2(guid, szCLSID, chars_in_guid);
+ if (SUCCEEDED(hr))
+ {
+ // Create a string of the form "CLSID\{clsid}"
+ hr = StringCchPrintf((STRSAFE_LPWSTR)pszName, cchMax, TEXT("Software\\Classes\\CLSID\\%ls"), szCLSID);
+ }
+ return hr;
+}
+
+// Creates a registry key (if needed) and sets the default value of the key
+STDMETHODIMP CreateRegKeyAndValue(HKEY hKey, PCWSTR pszSubKeyName, PCWSTR pszValueName,
+ PCWSTR pszData, PHKEY phkResult)
+{
+ *phkResult = NULL;
+ LONG lRet = RegCreateKeyExW(
+ hKey, pszSubKeyName,
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL, phkResult, NULL);
+
+ if (lRet == ERROR_SUCCESS)
+ {
+ lRet = RegSetValueExW(
+ (*phkResult),
+ pszValueName, 0, REG_SZ,
+ (LPBYTE) pszData,
+ ((DWORD) wcslen(pszData) + 1) * sizeof(WCHAR)
+ );
+
+ if (lRet != ERROR_SUCCESS)
+ {
+ RegCloseKey(*phkResult);
+ }
+ }
+
+ return HRESULT_FROM_WIN32(lRet);
+}
+
+// Creates the registry entries for a COM object.
+
+HRESULT RegisterObject(HMODULE hModule, const GUID& guid, const TCHAR *pszDescription, const TCHAR *pszThreadingModel)
+{
+ HKEY hKey = NULL;
+ HKEY hSubkey = NULL;
+ TCHAR achTemp[MAX_PATH];
+
+ // Create the name of the key from the object's CLSID
+ HRESULT hr = CreateObjectKeyName(guid, achTemp, MAX_PATH);
+
+ // Create the new key.
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateRegKeyAndValue(HKEY_LOCAL_MACHINE, achTemp, NULL, pszDescription,&hKey);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ (void)GetModuleFileName(hModule, achTemp, MAX_PATH);
+
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ // Create the "InprocServer32" subkey
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateRegKeyAndValue(hKey, L"InProcServer32", NULL, achTemp, &hSubkey);
+ RegCloseKey(hSubkey);
+ }
+
+ // Add a new value to the subkey, for "ThreadingModel" = <threading model>
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateRegKeyAndValue(hKey, L"InProcServer32", L"ThreadingModel", pszThreadingModel, &hSubkey);
+ RegCloseKey(hSubkey);
+ }
+
+ // close hkeys
+ RegCloseKey(hKey);
+ return hr;
+}
+
+// Deletes the registry entries for a COM object.
+
+HRESULT UnregisterObject(const GUID& guid)
+{
+ WCHAR achTemp[MAX_PATH];
+
+ HRESULT hr = CreateObjectKeyName(guid, achTemp, MAX_PATH);
+ if (SUCCEEDED(hr))
+ {
+ // Delete the key recursively.
+ LONG lRes = RegDeleteTree(HKEY_LOCAL_MACHINE, achTemp);
+ hr = HRESULT_FROM_WIN32(lRes);
+ }
+ return hr;
+}
+
+
diff --git a/AVStream/sampledevicemft/mftpeventgenerator.cpp b/AVStream/sampledevicemft/mftpeventgenerator.cpp
new file mode 100644
index 00000000..72b395ff
--- /dev/null
+++ b/AVStream/sampledevicemft/mftpeventgenerator.cpp
@@ -0,0 +1,250 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "common.h"
+#include "mftpeventgenerator.h"
+
+
+#define TP_SCOPE_TRACE TP_NORMAL
+#define DH_THIS_FILE DH_DEVPROXY
+
+#ifdef MF_WPP
+#include "mftpeventgenerator.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+CMediaEventGenerator::CMediaEventGenerator () :
+ m_nRefCount(0),
+ m_pQueue(NULL),
+ m_bShutdown(FALSE)
+{
+ //Call this explicit...
+ InitMediaEventGenerator();
+}
+
+STDMETHODIMP CMediaEventGenerator::InitMediaEventGenerator(
+ void
+ )
+{
+
+ return MFCreateEventQueue(&m_pQueue);
+
+}
+
+STDMETHODIMP_(ULONG) CMediaEventGenerator::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CMediaEventGenerator::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if (uCount == 0)
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv)
+{
+ HRESULT hr = S_OK;
+
+ *ppv = NULL;
+
+ if (iid == __uuidof(IUnknown) || iid == __uuidof(IMFMediaEventGenerator))
+ {
+ *ppv = static_cast<IMFMediaEventGenerator*>(this);
+ AddRef();
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+
+done:
+
+ return hr;
+}
+
+//
+// IMediaEventGenerator methods
+//
+STDMETHODIMP CMediaEventGenerator::BeginGetEvent(
+ _In_ IMFAsyncCallback* pCallback,
+ _In_ IUnknown* pState
+ )
+{
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT BeginGetEvent called");
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pQueue->BeginGetEvent(pCallback, pState);
+ }
+
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::EndGetEvent(
+ _In_ IMFAsyncResult* pResult,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ )
+{
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT EndGetEvent called");
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pQueue->EndGetEvent(pResult, ppEvent);
+ }
+
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::GetEvent(
+ _In_ DWORD dwFlags,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ )
+{
+ //
+ // Because GetEvent can block indefinitely, it requires
+ // a slightly different locking strategy.
+ //
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT GetEvent called");
+ IMFMediaEventQueue *pQueue = NULL;
+
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+ //
+ // Store the pointer in a local variable, so that another thread
+ // does not release it after we leave the critical section.
+ //
+ if (SUCCEEDED(hr))
+ {
+ pQueue = m_pQueue;
+ }
+
+ m_critSec.Unlock();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pQueue->GetEvent(dwFlags, ppEvent);
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueueEvent(
+ _In_ MediaEventType met,
+ _In_ REFGUID extendedType,
+ _In_ HRESULT hrStatus,
+ _In_opt_ const PROPVARIANT* pvValue
+ )
+{
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT QueueEvent called");
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+
+ hr = m_pQueue->QueueEventParamVar(
+ met,
+ extendedType,
+ hrStatus,
+ pvValue
+ );
+ }
+
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::ShutdownEventGenerator(
+ void
+ )
+{
+ HRESULT hr = S_OK;
+
+ // MFWMITRACE( DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : entering ...");
+
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ if (m_pQueue)
+ {
+ hr = m_pQueue->Shutdown();
+ //MFWMITRACE( DH_THIS_FILE, TP_NORMAL, __FUNCTION__ "Event Generator Queue shutdown hr = %x", hr);
+ }
+ SAFE_RELEASE(m_pQueue);
+ m_bShutdown = TRUE;
+ }
+ m_critSec.Unlock();
+
+ // MFWMITRACE( DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : exiting...");
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueueEvent(
+ _In_ IMFMediaEvent* pEvent
+ )
+{
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : QueueEvent 1 ...");
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ if (m_pQueue)
+ {
+ hr = m_pQueue->QueueEvent(pEvent);
+ }
+ }
+
+ m_critSec.Unlock();
+ return hr;
+}
+
+CMediaEventGenerator::~CMediaEventGenerator (
+ void
+ )
+{
+ ShutdownEventGenerator();
+ //MFASSERT(m_bShutdown);
+ //MFASSERT(m_nRefCount == 0);
+}
diff --git a/AVStream/sampledevicemft/mftpeventgenerator.h b/AVStream/sampledevicemft/mftpeventgenerator.h
new file mode 100644
index 00000000..2ddae218
--- /dev/null
+++ b/AVStream/sampledevicemft/mftpeventgenerator.h
@@ -0,0 +1,94 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+#pragma once
+
+class CMediaEventGenerator :
+ public IMFMediaEventGenerator
+{
+
+public:
+
+ //
+ // IUnknown
+ //
+ STDMETHOD_(ULONG, AddRef)(
+ void
+ );
+
+ STDMETHOD_(ULONG, Release)(
+ void
+ );
+
+ STDMETHOD(QueryInterface)(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv);
+
+
+ //
+ // IMFMediaEventGenerator
+ //
+ STDMETHOD(BeginGetEvent)(
+ _In_ IMFAsyncCallback* pCallback,
+ _In_ IUnknown* pState
+ );
+
+ STDMETHOD(EndGetEvent)(
+ _In_ IMFAsyncResult* pResult,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ );
+
+ STDMETHOD(GetEvent)(
+ _In_ DWORD dwFlags,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ );
+
+ STDMETHOD(QueueEvent)(
+ _In_ MediaEventType met,
+ _In_ REFGUID extendedType,
+ _In_ HRESULT hrStatus,
+ _In_opt_ const PROPVARIANT* pvValue
+ );
+
+ STDMETHOD(QueueEvent)(
+ _In_ IMFMediaEvent* pEvent
+ );
+
+protected:
+
+ CMediaEventGenerator(
+ void
+ );
+
+ virtual ~CMediaEventGenerator (
+ void
+ );
+ //
+ // Utility Methods
+ //
+ STDMETHOD(ShutdownEventGenerator)(
+ void
+ );
+
+ STDMETHOD (InitMediaEventGenerator)(
+ void
+ );
+
+ __inline HRESULT (CheckShutdown)(
+ void
+ ) const
+ {
+ return (m_bShutdown? MF_E_SHUTDOWN : S_OK);
+ }
+
+private:
+
+ long m_nRefCount;
+ CCritSec m_critSec;
+ IMFMediaEventQueue* m_pQueue;
+ BOOL m_bShutdown;
+};
diff --git a/AVStream/sampledevicemft/multipinmft.cpp b/AVStream/sampledevicemft/multipinmft.cpp
new file mode 100644
index 00000000..ea7fd892
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.cpp
@@ -0,0 +1,2453 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "multipinmft.h"
+#ifdef MF_WPP
+#include "multipinmft.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+//
+//Note since MFT_UNIQUE_METHOD_NAMES is defined all the functions of IMFTransform have the Mft suffix..
+//
+extern const CLSID CLSID_HwMFTActivate;
+
+#if _NEED_MFTLOCKING_
+#define MFTLOCKED() {\
+ UINT32 punValue = FALSE; \
+ hr = GetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, &punValue);\
+if (FAILED(hr) || punValue == FALSE){\
+ return MF_E_TRANSFORM_ASYNC_LOCKED; \
+}\
+}
+#else
+
+#define MFTLOCKED()
+
+#endif
+
+CMultipinMft::CMultipinMft()
+: m_nRefCount( 0 ),
+ m_InputPinCount( 0 ),
+ m_OutputPinCount( 0 ),
+ m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ),
+ m_lWorkQueuePriority ( 0 ),
+ m_spAttributes( nullptr ),
+ m_spSourceTransform( nullptr ),
+ m_PhotoTriggerSent(false),
+ m_filterHasIndependentPin( false ),
+ m_FilterInPhotoSequence( false ),
+ m_filterInWarmStart(false)
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ , m_spPhotoConfirmationCallback(nullptr)
+#endif
+{
+ ComPtr<IMFAttributes> pAttributes = nullptr;
+ MFCreateAttributes( &pAttributes, 0 );
+ pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE );
+ pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE );
+ pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE );
+ pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" );
+ m_spAttributes = pAttributes;
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ m_guidPhotoConfirmationSubtype = MFVideoFormat_NV12;
+#endif
+}
+
+CMultipinMft::~CMultipinMft( )
+{
+ CBasePin *pioPin = NULL;
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG) m_InPins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ pioPin = m_InPins[ ulIndex ];
+ SAFERELEASE( pioPin );
+ }
+ m_InPins.clear();
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG) m_OutPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ pioPin = m_OutPins[ ulIndex ];
+ SAFERELEASE( pioPin );
+ }
+ m_OutPins.clear();
+ m_spSourceTransform = nullptr;
+
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if ( uCount == 0 )
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+STDMETHODIMP CMultipinMft::QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv
+ )
+{
+
+ HRESULT hr = S_OK;
+ *ppv = NULL;
+
+ if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown)))
+ {
+ *ppv = static_cast< IMFDeviceTransform* >(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFMediaEventGenerator ) )
+ {
+ *ppv = static_cast< IMFMediaEventGenerator* >(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFShutdown ) )
+ {
+ *ppv = static_cast< IMFShutdown* >( this );
+ AddRef();
+ }
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ else
+ if (iid == __uuidof(IMFTransform))
+ {
+ *ppv = static_cast< IMFTransform* >(this);
+ AddRef();
+ }
+#endif
+ else
+ if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFRealTimeClientEx ) )
+ {
+ *ppv = static_cast< IMFRealTimeClientEx* >( this );
+ AddRef();
+ }
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ else
+ if (iid == __uuidof(IMFCapturePhotoConfirmation))
+ {
+ *ppv = static_cast< IMFCapturePhotoConfirmation* >(this);
+ AddRef();
+ }
+ else
+ if (iid == __uuidof(IMFGetService))
+ {
+ *ppv = static_cast< IMFGetService* >(this);
+ AddRef();
+ }
+#endif
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+ return hr;
+}
+
+/*++
+ Description:
+ This function is the entry point of the transform
+ The following things may be initialized here
+ 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied
+ 2) From the IUnknown acquired get the IMFTransform interface.
+ 3) Get the stream count.. The output streams are of consequence to the tranform.
+ The input streams should correspond to the output streams exposed by the source transform
+ acquired from the Attributes supplied.
+ 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class
+ 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire
+ the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins
+ 6) Create the output pins
+
+--*/
+
+STDMETHODIMP CMultipinMft::InitializeTransform (
+ _In_ IMFAttributes *pAttributes
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IUnknown> spFilterUnk = nullptr;
+ DWORD *pcInputStreams = NULL, *pcOutputStreams = NULL;
+ DWORD inputStreams = 0;
+ DWORD outputStreams = 0;
+ GUID* outGuids = NULL;
+ GUID streamCategory = GUID_NULL;
+
+ DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG );
+ //
+ //The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter
+ //This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send
+ //controls to the driver.
+ //
+ DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done );
+
+ DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamCount( &inputStreams, &outputStreams ), done );
+
+ spFilterUnk = nullptr;
+
+ //
+ //The number of input pins created by the device transform should match the pins exposed by
+ //the source transform i.e. outputStreams from SourceTransform or DevProxy = Input pins of the Device MFT
+ //
+
+ if ( inputStreams > 0 || outputStreams > 0 )
+ {
+ pcInputStreams = new DWORD[ inputStreams ];
+ DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY);
+
+ pcOutputStreams = new DWORD[ outputStreams ];
+ DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamIDs( inputStreams, pcInputStreams,
+ outputStreams,
+ pcOutputStreams ),done );
+
+ //
+ // Output pins from DevProxy = Input pins of device MFT.. We are the first transform in the pipeline before MFT0
+ //
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IMFAttributes> pInAttributes = nullptr;
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->GetOutputStreamAttributes(pcOutputStreams[ulIndex], pInAttributes.GetAddressOf()), done);
+
+ DMFTCHECKHR_GOTO( pInAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &streamCategory), done);
+
+ if ( IsEqualCLSID( streamCategory, PINNAME_IMAGE ) )
+ {
+ //We have independent pins..
+ m_filterHasIndependentPin = true;
+ }
+ CInPin *pInPin = nullptr;
+ if (IsEqualCLSID(streamCategory, AVSTREAM_CUSTOM_PIN_IMAGE))
+ {
+ pInPin = new CCustomPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this);
+ DMFTCHECKNULL_GOTO( pInPin, done, E_OUTOFMEMORY);
+ //
+ // Since the custom pin is an input pin too we will push it
+ // in the input pins list. This is however not being connected
+ // to the output in this sample.
+ m_CustomPinCount++;
+ }
+ else
+ {
+ pInPin = new CInPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this);
+ DMFTCHECKNULL_GOTO(pInPin, done, E_OUTOFMEMORY);
+ }
+
+ hr = ExceptionBoundary([this,pInPin]()
+ {
+ m_InPins.push_back(pInPin);
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+ DMFTCHECKHR_GOTO( pInPin->Init(m_spSourceTransform.Get() ), done);
+
+
+ pInPin->AddRef();
+
+ }
+ //
+ // If we have just one output stream exposed off the source transform create a one to three pin
+ //
+ if ( ( outputStreams == 1 ) && IsEqualGUID( streamCategory, PINNAME_VIDEO_CAPTURE ) )
+ {
+ outputStreams = 3;
+ outGuids = new GUID [ outputStreams ];
+ DMFTCHECKNULL_GOTO(outGuids, done, E_OUTOFMEMORY);
+
+ m_OutPins.resize(outputStreams, nullptr);
+
+ CInPin *piPin = (CInPin *)m_InPins[0];
+
+ *outGuids = PINNAME_VIDEO_CAPTURE;
+ *( outGuids + 1 ) = PINNAME_VIDEO_PREVIEW;
+ *(outGuids + 2) = PINNAME_IMAGE; //PINNAME_IMAGE for independent pin and PINNAME_VIDEO_STILL for dependent pin!!
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IKsControl> pKsControl = NULL;
+ COutPin *poPin = nullptr;
+
+ DMFTCHECKHR_GOTO( piPin->QueryInterface(IID_PPV_ARGS( &pKsControl ) ), done);
+
+ hr = ExceptionBoundary([&]()
+ {
+ poPin = new COutPin(ulIndex, this, pKsControl.Get());
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+
+ DMFTCHECKNULL_GOTO( poPin,done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( BridgeInputPinOutputPin( piPin, poPin ),done );
+
+ DMFTCHECKHR_GOTO( poPin->SetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, outGuids[ ulIndex ] ),done );
+
+ DMFTCHECKHR_GOTO( poPin->SetUINT32( MF_DEVICESTREAM_STREAM_ID, ulIndex ),done );
+
+ m_OutPins[ ulIndex ] = poPin;
+ poPin->AddRef();
+
+ }
+ }
+ else
+ {
+ //
+ //Create one on one mapping
+ //
+
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+ ULONG ulPinIndex = 0;
+ GUID pinGuid = GUID_NULL;
+ ComPtr< IKsControl > pKsControl = nullptr;
+
+ CInPin *piPin = ( CInPin * )m_InPins[ ulIndex ];
+
+ if (piPin)
+ {
+ BOOL isCustom = false;
+ if ( SUCCEEDED( CheckCustomPin( piPin, &isCustom )) && ( isCustom ) )
+ {
+ //
+ // In this sample we are not connecting the custom pin to the output
+ // This is because we really have no way of testing the custom pin with the
+ // pipeline.
+ // This however can be changed if the custom media type is converted here in
+ // the device MFT and later exposed to the pipeline..
+ //
+ continue;
+ }
+ ulPinIndex = piPin->streamId();
+
+ DMFTCHECKHR_GOTO(piPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinGuid), done);
+
+ DMFTCHECKHR_GOTO(piPin->QueryInterface(IID_PPV_ARGS(&pKsControl)), done);
+
+ COutPin *poPin = new COutPin(ulPinIndex, this, pKsControl.Get());
+
+ DMFTCHECKNULL_GOTO(poPin, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, pinGuid), done);
+
+ DMFTCHECKHR_GOTO(poPin->SetUINT32(MF_DEVICESTREAM_STREAM_ID, ulPinIndex), done);
+
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ //
+ // If we wish to load MFT0 as well as Device MFT then we should be doing the following
+ // Copy over the GUID attribute MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID from the input
+ // pin to the output pin. This is because Device MFT is the new face of the filter now
+ // and MFT0 will now get loaded for the output pins exposed from Device MFT rather than
+ // DevProxy!
+ //
+
+ GUID guidMFT0 = GUID_NULL;
+
+ hr = piPin->GetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, &guidMFT0);
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // This stream has an MFT0 .. Attach the GUID to the Outpin pin attribute
+ // The downstream will query this attribute on the pins exposed from device MFT
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! setting Mft0 guid on pin %d", ulIndex);
+
+ DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, guidMFT0), done);
+
+ DMFTCHECKHR_GOTO(poPin->SetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT,
+ static_cast< IUnknown* >(static_cast < IKsControl * >(this))), done);
+
+ }
+ else
+ {
+ // Reset Error.. MFT0 absence should not be an error
+ hr = S_OK;
+ }
+#endif
+ DMFTCHECKHR_GOTO(BridgeInputPinOutputPin(piPin, poPin), done);
+ hr = ExceptionBoundary([&]()
+ {
+ m_OutPins.push_back(poPin);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+ }
+ }
+
+ m_InputPinCount = ULONG ( m_InPins.size() );
+ m_OutputPinCount = ULONG ( m_OutPins.size() );
+
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!",hr,hr);
+
+ if ( pcInputStreams )
+ {
+ delete[ ] ( pcInputStreams );
+ }
+ if ( pcOutputStreams )
+ {
+ delete[ ] ( pcOutputStreams );
+ }
+ if ( outGuids )
+ {
+ delete [] ( outGuids );
+ }
+ if ( FAILED( hr ) )
+ {
+ //Release the pins and the resources acquired
+ while ( m_InPins.size() > 0 )
+ {
+ CInPin *pInPin = nullptr;
+ pInPin = ( CInPin* )m_InPins.back();
+ m_InPins.pop_back();
+ SAFERELEASE( pInPin );
+ }
+ while ( m_OutPins.size() > 0 )
+ {
+ COutPin *pin = nullptr;
+ pin = ( COutPin* )m_OutPins.back();
+ m_OutPins.pop_back();
+ SAFERELEASE( pin );
+ }
+ //
+ // Simply clear the custom pins since the input pins must have deleted the pin
+ //
+ m_spSourceTransform = nullptr;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::SetWorkQueueEx(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority
+ )
+/*++
+ Description:
+
+ Implements IMFRealTimeClientEx::SetWorkQueueEx function
+
+--*/
+{
+ CAutoLock lock( m_critSec );
+ //
+ // Cache the WorkQueuId and WorkItemBasePriority
+ //
+ m_dwWorkQueueId = dwWorkQueueId;
+ m_lWorkQueuePriority = lWorkItemBasePriority;
+ return S_OK;
+
+}
+
+//
+// IMFDeviceTransform functions
+//
+STDMETHODIMP CMultipinMft::GetStreamCount(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams
+ )
+/*++
+ Description: Implements IMFTransform::GetStreamCount function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+
+ *pdwInputStreams = m_InputPinCount;
+ *pdwOutputStreams = m_OutputPinCount;
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+//
+//Doesn't striclt conform to GetStreamIDs on IMFTransform Interface!
+//
+STDMETHODIMP CMultipinMft::GetStreamIDs(
+ _In_ DWORD dwInputIDArraySize,
+ _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs,
+ _In_ DWORD dwOutputIDArraySize,
+ _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)),
+ _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs
+ )
+/*++
+ Description:
+ Implements IMFTransform::GetStreamIDs function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+ MFTLOCKED();
+
+ if ( ( dwInputIDArraySize < m_InputPinCount ) && ( dwOutputIDArraySize < m_OutputPinCount ) )
+ {
+ hr = MF_E_BUFFERTOOSMALL;
+ goto done;
+ }
+
+ if ( dwInputIDArraySize )
+ {
+ DMFTCHECKNULL_GOTO( pdwInputIDs, done, E_POINTER );
+ for ( DWORD dwIndex = 0; dwIndex < ((dwInputIDArraySize > m_InputPinCount) ? m_InputPinCount:
+ dwInputIDArraySize); dwIndex++ )
+ {
+ pdwInputIDs[ dwIndex ] = ( m_InPins[dwIndex] )->streamId();
+ }
+ }
+
+ if ( dwOutputIDArraySize )
+ {
+ DMFTCHECKNULL_GOTO( pdwOutputIDs, done, E_POINTER );
+ for ( DWORD dwIndex = 0; dwIndex < ((dwOutputIDArraySize > m_OutputPinCount)? m_OutputPinCount:
+ dwOutputIDArraySize); dwIndex++ )
+ {
+ pdwOutputIDs[ dwIndex ] = (m_OutPins[ dwIndex ])->streamId();
+ }
+ }
+done:
+ return hr;
+}
+
+/*++
+Name: CMultipinMft::GetInputAvailableType
+Description:
+Implements IMFTransform::GetInputAvailableType function. This function
+gets the media type supported by the specified stream based on the
+index dwTypeIndex.
+--*/
+STDMETHODIMP CMultipinMft::GetInputAvailableType(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+
+ CInPin *piPin = ( CInPin* )GetInPin( dwInputStreamID );
+
+ DMFTCHECKNULL_GOTO( piPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = piPin->GetOutputAvailableType( dwTypeIndex,ppMediaType );
+
+ if (FAILED(hr))
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwInputStreamID,
+ dwTypeIndex,
+ hr);
+
+ }
+
+done:
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputAvailableType(
+ _In_ DWORD dwOutputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputAvailableType function. This function
+ gets the media type supported by the specified stream based on the
+ index dwTypeIndex.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+
+ COutPin*poPin = ( COutPin* )GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = poPin->GetOutputAvailableType( dwTypeIndex, ppMediaType );
+
+ if ( FAILED( hr ) )
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwOutputStreamID,
+ dwTypeIndex,
+ hr );
+ }
+
+done:
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputCurrentType(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+ Implements IMFTransform::GetInputCurrentType function. This function
+ returns the current media type set on the specified stream.
+--*/
+{
+ //
+ //The input current types will not come to this transform.
+ //The outputs of this transform matter. The DTM manages the
+ //output of this transform and the inptuts of the source transform
+ //
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(ppMediaType);
+ return S_OK;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputCurrentType(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputCurrentType function. This function
+ returns the current media type set on the specified stream.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+ CAutoLock lock( m_critSec );
+
+ DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG );
+
+ *ppMediaType = nullptr;
+
+ COutPin *poPin = ( COutPin* )GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ DMFTCHECKHR_GOTO( poPin->getMediaType( ppMediaType ),done );
+
+ DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::ProcessEvent(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFMediaEvent* pEvent
+ )
+ /*++
+ Description:
+
+ Implements IMFTransform::ProcessEvent function. This function
+ processes events that come to the MFT.
+
+ --*/
+{
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(pEvent);
+ return S_OK;
+}
+
+
+
+STDMETHODIMP CMultipinMft::ProcessMessage(
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ _In_ ULONG_PTR ulParam
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::ProcessMessage function. This function
+ processes messages coming to the MFT.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ UNREFERENCED_PARAMETER(ulParam);
+
+ CAutoLock _lock( m_critSec );
+
+ printMessageEvent( eMessage );
+
+ switch ( eMessage )
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ //
+ //This is MFT wide flush.. Flush all output pins
+ //
+ (VOID)FlushAllStreams();
+ break;
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ //
+ //There is no draining for Device MFT. Just kept here for reference
+ //
+ break;
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ //
+ //No op for device MFTs
+ //
+ break;
+ case MFT_MESSAGE_SET_D3D_MANAGER:
+ {
+ if ( ulParam )
+ {
+ ComPtr< IDirect3DDeviceManager9 > spD3D9Manager;
+ ComPtr< IMFDXGIDeviceManager > spDXGIManager;
+
+ hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spD3D9Manager ) );
+ if ( SUCCEEDED( hr ) )
+ {
+ m_spDeviceManagerUnk = ( IUnknown* )ulParam;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IDirect3DDeviceManager9 %p, is passed", spD3D9Manager.Get() );
+ }
+ else
+ {
+ hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spDXGIManager ) );
+ if ( SUCCEEDED(hr) )
+ {
+ m_spDeviceManagerUnk = (IUnknown*)ulParam;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IMFDXGIDeviceManager %p, is passed", spDXGIManager.Get());
+ }
+ }
+ }
+ else
+ {
+ m_spDeviceManagerUnk = nullptr;
+ hr = S_OK;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC!IDirect3DDeviceManager9 was not passed in");
+ }
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ {
+ SetStreamingState( DeviceStreamState_Run );
+ //
+ // Start Streaming custom pins if the device transfrom has any
+ //
+ SetStreamingStateCustomPins( DeviceStreamState_Run );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_STREAMING:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ //
+ // Stop streaming custom pins if the device transform has any
+ //
+ SetStreamingStateCustomPins( DeviceStreamState_Stop );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ }
+ break;
+ default:
+ ;
+ }
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::ProcessInput(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFSample* pSample,
+ _In_ DWORD dwFlags
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::ProcessInput function.This function is called
+ when the sourcetransform has input to feed. the pins will try to deliver the
+ samples to the active output pins conencted. if none are connected then just
+ returns the sample back to the source transform
+
+--*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( dwFlags );
+
+ MFTLOCKED();
+
+ CInPin *inPin = ( CInPin* )GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO( inPin, done, E_INVALIDARG );
+
+ if ( !IsStreaming() )
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO( inPin->SendSample( pSample ), done );
+
+ QueueEvent( METransformHaveOutput, GUID_NULL, S_OK, NULL );
+
+done:
+ SAFERELEASE( pSample );
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+
+}
+
+STDMETHODIMP CMultipinMft::ProcessOutput(
+ _In_ DWORD dwFlags,
+ _In_ DWORD cOutputBufferCount,
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ _Out_ DWORD *pdwStatus
+)
+/*++
+Description:
+
+Implements IMFTransform::ProcessOutput function. This is called by the DTM when
+the DT indicates it has samples to give. The DTM will send enough MFT_OUTPUT_DATA_BUFFER
+pointers to be filled up as is the number of output pins available. The DT should traverse its
+output pins and populate the corresponding MFT_OUTPUT_DATA_BUFFER with the samples available
+
+--*/
+{
+ HRESULT hr = S_OK;
+ BOOL gotOne = false;
+ MFTLOCKED();
+ UNREFERENCED_PARAMETER( dwFlags );
+
+ if (cOutputBufferCount > m_OutputPinCount )
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ *pdwStatus = 0;
+
+ for ( DWORD i = 0; i < cOutputBufferCount; i++ )
+ {
+ DWORD dwStreamID = pOutputSamples[i].dwStreamID;
+
+ COutPin *poPin = ( COutPin * )GetOutPin( dwStreamID );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ if ( SUCCEEDED( poPin->ProcessOutput( dwFlags, &pOutputSamples[i],
+ pdwStatus ) ) )
+ {
+ gotOne = true;
+ }
+ }
+ if (gotOne)
+ {
+ hr = S_OK;
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamAttributes(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetInputStreamAttributes function. This function
+ gets the specified input stream's attributes.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ *ppAttributes = nullptr;
+
+ CInPin *piPin = static_cast<CInPin*>(GetInPin( dwInputStreamID ));
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+
+ hr = piPin->getPinAttributes(ppAttributes);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputStreamAttributes(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFAttributes** ppAttributes
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputStreamAttributes function. This function
+ gets the specified output stream's attributes.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+ *ppAttributes = nullptr;
+
+ COutPin *poPin = (COutPin *)GetOutPin(dwOutputStreamID);
+
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ DMFTCHECKHR_GOTO( poPin->getPinAttributes(ppAttributes), done );
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+_Requires_no_locks_held_
+STDMETHODIMP CMultipinMft::SetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::SetInputStreamState function.
+ Sets the input stream state.
+
+ The control lock is not taken here. The lock is taken for operations on
+ output pins. This operation is a result of the DT notifying the DTM that
+ output pin change has resulted in the need for the input to be changed. In
+ this case the DTM sends a getpreferredinputstate and then this call
+
+ --*/
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ DMFTCHECKHR_GOTO(piPin->SetInputStreamState(pMediaType, value, dwFlags),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = piPin->GetState();
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::SetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState state,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::SetOutputStreamState function.
+ Sets the output stream state. This is called whenever the stream
+ is selected or deslected i.e. started or stopped.
+
+ The control lock taken here and this operation should be atomic.
+ This function should check the input pins connected to the output pin
+ switch off the state of the input pin. Check if any other Pin connected
+ to the input pin is in a conflicting state with the state requested on this
+ output pin. Accordinly it calculates the media type to be set on the input pin
+ and the state to transition into. It then might recreate the other output pins
+ connected to it
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock Lock(m_critSec);
+
+ DMFTCHECKHR_GOTO(ChangeMediaTypeEx(dwStreamID, pMediaType, state),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetOutputStreamState function.
+ Gets the output stream state.
+ Called by the DTM to checks states. Atomic operation. needs a lock
+ --*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+ COutPin *poPin = (COutPin *)GetOutPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(poPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = poPin->GetState();
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamPreferredState(
+ _In_ DWORD dwStreamID,
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetInputStreamPreferredState function.
+ Gets the preferred state and the media type to be set on the input pin.
+ The lock is not held as this will always be called only when we notify
+ DTM to call us. We notify DTM only from the context on operations
+ happening on the output pin
+ --*/
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ piPin->GetInputStreamPreferredState(value, ppMediaType);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::FlushInputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::FlushInputStream function.
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwStreamIndex);
+ UNREFERENCED_PARAMETER(dwFlags);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::FlushOutputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::FlushOutputStream function.
+ Called by the DTM to flush streams
+ --*/
+{
+
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock Lock(m_critSec);
+
+ COutPin *poPin = (COutPin*)GetOutPin(dwStreamIndex);
+ DMFTCHECKNULL_GOTO(poPin, done, E_INVALIDARG);
+
+ DeviceStreamState oldState = poPin->SetState(DeviceStreamState_Disabled);
+
+ hr = poPin->FlushQueues();
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! failed %x = %!HRESULT!", hr, hr);
+ }
+ //
+ //Restore state
+ //
+ poPin->SetState(oldState);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+/*++
+ Description:
+
+ Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues.
+ This is called in device source when the source gets end of streaming.
+ --*/
+STDMETHODIMP_(VOID) CMultipinMft::FlushAllStreams(
+ VOID
+ )
+{
+ DeviceStreamState oldState;
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ COutPin *poPin = (COutPin *)m_OutPins[dwIndex];
+ oldState = poPin->SetState(DeviceStreamState_Disabled);
+ poPin->FlushQueues();
+ //
+ //Restore state
+ //
+ poPin->SetState(oldState);
+ }
+}
+
+
+//
+// IKsControl interface functions
+//
+STDMETHODIMP CMultipinMft::KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pulBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsProperty function.
+ used to pass control commands to the driver (generally)
+ This can be used to intercepted the control to figure out
+ if it needs to be propogated to the driver or not
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pulBytesReturned);
+ DMFTCHECKNULL_GOTO(pProperty, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_INVALIDARG);
+
+ //
+ // Enable Warm Start on All filters for the sample. Please comment out this
+ // section if this is not needed
+ //
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART))
+ {
+ DMFTCHECKHR_GOTO(WarmStartHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned),done);
+ goto done;
+ }
+
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Thumbnail sent %d",pProperty->Flags);
+ }
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ &&(!filterHasIndependentPin()))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Extended Control %d Passed ",pProperty->Id);
+ switch (pProperty->Id)
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE:
+ hr = ExtendedPhotoModeHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE:
+ hr = ExtendedPhotoMaxFrameRate(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES:
+ hr = MaxVidFPS_PhotoResHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME:
+ hr = QPCTimeHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE:
+ hr = PhotoFrameRateHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+
+ }
+ }
+ else
+ if ((IsEqualCLSID(pProperty->Set, PROPSETID_VIDCAP_VIDEOCONTROL)) &&
+ (pProperty->Id == KSPROPERTY_VIDEOCONTROL_MODE))
+ {
+ //
+ //A photo trigger was sent!!!
+ //We need to set the event haveoutput
+ //
+ PKSPROPERTY_VIDEOCONTROL_MODE_S VideoControl = NULL;
+ if (sizeof(KSPROPERTY_VIDEOCONTROL_MODE_S) == ulDataLength)
+ {
+ VideoControl = (PKSPROPERTY_VIDEOCONTROL_MODE_S)pvPropertyData;
+ m_PhotoModeIsPhotoSequence = false;
+
+ if (VideoControl->Mode == KS_VideoControlFlag_StartPhotoSequenceCapture)
+ {
+ //
+ //Signalling start of photo sequence
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Starting PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = true;
+ setPhotoTriggerSent(true);
+ }
+ else
+ if (VideoControl->Mode == KS_VideoControlFlag_StopPhotoSequenceCapture)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Stopping PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = false;
+ setPhotoTriggerSent(false);
+ }
+ else
+ {
+ //
+ //Normal trigger sent for single photo acquisition!
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Take Single Photo Trigger");
+ setPhotoTriggerSent(true);
+ }
+
+ }
+
+ if (!filterHasIndependentPin())
+ {
+ goto done;
+ }
+ }
+ hr = m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned);
+
+
+done:
+ LPSTR guidStr = DumpGUIDA(pProperty->Set);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! g:%s p:%d exiting %x = %!HRESULT!", guidStr, pProperty->Id, hr, hr);
+ delete(guidStr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::KsMethod(
+ _In_reads_bytes_(ulPropertyLength) PKSMETHOD pMethod,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pulBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsMethod function.
+ --*/
+{
+ return m_spIkscontrol->KsMethod(
+ pMethod,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned
+ );
+}
+
+STDMETHODIMP CMultipinMft::KsEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsEvent function.
+ --*/
+{
+
+ HRESULT hr = S_OK;
+ if (pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl) &&
+ (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ //
+ // For the Sample the warmstate handlers are supported by Device MFT and not passed to driver
+ //
+ hr = m_eventHandler.KSEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned
+ );
+ goto done;
+ }
+
+ if ((pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl))
+ && (!filterHasIndependentPin()))
+ {
+ //
+ // Important: Extended controls will send events which are strictly
+ // One shot. The event comes first where it should be duped and stored,
+ // the control comes next. The event should be set after control completes
+ // and it should be then closed.
+ // The below code handles only certain events needed for
+ // implementing photo sequence. For a complete exhaustive
+ // list refer documentation.
+ //
+ switch (pEvent->Id)
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE:
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ //
+ // Let the event handler handle the event
+ //
+ DMFTCHECKHR_GOTO(m_eventHandler.KSEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned
+ ),done);
+ goto done;
+ }
+ }
+ }
+ //
+ // All the Events we don't handle should be sent to the driver!
+ //
+ hr = m_spIkscontrol->KsEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+//
+//IMFGetService functions
+//
+
+STDMETHODIMP CMultipinMft::GetService(
+ __in REFGUID guidService,
+ __in REFIID riid,
+ __deref_out LPVOID* ppvObject
+ )
+{
+ //
+ //This doesn't necessarily need to be a GetService function, but this is just so that the
+ //pipeline implementation and the Device transform implementation is consistent.
+ //In this sample the photoconfirmation interface is implementated by the same class
+ //we can delegate it later to any of the pins if needed
+ //
+ UNREFERENCED_PARAMETER(guidService);
+ if (riid == __uuidof(IMFCapturePhotoConfirmation))
+ {
+ return QueryInterface(riid, ppvObject);
+ }
+ else
+ return MF_E_UNSUPPORTED_SERVICE;
+
+
+}
+
+//
+//IMFCapturePhotoConfirmation functions implemented
+//
+
+STDMETHODIMP CMultipinMft::SetPhotoConfirmationCallback(
+ _In_ IMFAsyncCallback* pNotificationCallback
+ )
+{
+ CAutoLock Lock(m_critSec);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting PhotoConfirmation %p, is passed", pNotificationCallback);
+
+ m_spPhotoConfirmationCallback = pNotificationCallback;
+ return S_OK;
+}
+STDMETHODIMP CMultipinMft::SetPixelFormat(
+ _In_ GUID subtype
+ )
+{
+ m_guidPhotoConfirmationSubtype = subtype;
+ return S_OK;
+}
+STDMETHODIMP CMultipinMft::GetPixelFormat(
+ _Out_ GUID* subtype
+ )
+{
+ *subtype = m_guidPhotoConfirmationSubtype;
+ return S_OK;
+}
+
+#endif
+
+
+
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+
+//
+// IMFTransform function(s).
+//
+
+//
+// Note: This is the only IMFTransform function which is not a redirector to the
+// DeviceTransform functions. The rest of IMFTransform functions are in the file common.h
+// This function returns the IMFAttribute created for Device MFT. If DMFT is
+// not loaded (usually )MFT0's call to GetAttributes will get the Attribute store of DevProxy.
+// A device MFT loaded will not pass through the devproxy attribute store, but it will pass
+// the device MFT attributes. This should be similar to the singular DevProxy attribute
+// which the MFT0 providers can use to synchronize across various MFT0's
+//
+
+STDMETHODIMP CMultipinMft::GetAttributes(
+ _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+
+ *ppAttributes = nullptr;
+
+ if (m_spAttributes != nullptr)
+ {
+ m_spAttributes.CopyTo(ppAttributes);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+done:
+ return hr;
+}
+#endif
+
+
+
+
+//
+//HELPER FUNCTIONS
+//
+
+STDMETHODIMP_(CBasePin*) CMultipinMft::GetInPin(
+ _In_ DWORD dwStreamId
+ )
+{
+ CInPin *inPin = NULL;
+ for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++)
+ {
+ inPin = (CInPin *)m_InPins[dwIndex];
+ if (dwStreamId == inPin->streamId())
+ {
+ break;
+ }
+ inPin = NULL;
+ }
+ return inPin;
+}
+
+STDMETHODIMP_(CBasePin*) CMultipinMft::GetOutPin(
+ _In_ DWORD dwStreamId
+ )
+{
+ COutPin *outPin = NULL;
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ outPin = ( COutPin * )m_OutPins[ dwIndex ];
+
+ if ( dwStreamId == outPin->streamId() )
+ {
+ break;
+ }
+
+ outPin = NULL;
+ }
+
+ return outPin;
+}
+
+/*++
+Description:
+This is a critical function which changes the state on an output pin
+This should be called under the control lock of the DT.
+Here the
+--*/
+STDMETHODIMP CMultipinMft::ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState reqState
+ )
+{
+ HRESULT hr = S_OK;
+ DeviceStreamState oldOutPinState;
+ DeviceStreamState newOutStreamState;
+ ComPtr<IMFMediaType> pFullType = nullptr;
+
+ COutPin *poPin = static_cast<COutPin*>( GetOutPin(pinId) );
+
+ MMFTMMAPITERATOR inputPinPos;
+
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ //Check if the media type requested is a supported type
+ //
+ if ( pMediaType )
+ {
+ if ( !poPin->IsMediaTypeSupported( pMediaType, &pFullType ) )
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ }
+ //
+ //First step disable the output pin. store the old state
+ //
+ oldOutPinState = poPin->SetState( DeviceStreamState_Disabled );
+
+ (void)poPin->FlushQueues();
+
+ newOutStreamState = pinStateTransition[oldOutPinState][reqState]; //New state needed
+
+ //
+ //Go through the output pins' maps that has the conencted input pin to the output pin
+ //
+ inputPinPos = m_outputPinMap.equal_range( pinId );
+
+ for (std::multimap<int, int>::iterator piterator = inputPinPos.first; piterator != inputPinPos.second;piterator++)
+ {
+ //
+ //Get the output pins connected to the input pin. The input pin map consists of the output pins connected
+ //
+ ULONG connectedInputPin = (*piterator).second;
+ BOOL isAnyConnectedOutPinActive = false;
+ BOOL isAnyConnectedOutPinPaused = false;
+ BOOL isAnyConnectedOutPinRunning = false;
+ BOOL doWeWaitForSetInput = false;
+ DeviceStreamState oldInputStreamState;
+ MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal;
+ ComPtr<IMFMediaType> pInputMediaType = nullptr;
+ CInPin *pconnectedInPin = (CInPin*)GetInPin( connectedInputPin );
+ oldInputStreamState = pconnectedInPin->SetState( DeviceStreamState_Disabled );
+ DeviceStreamState newRequestedInPinState = pinStateTransition[oldInputStreamState][newOutStreamState];
+
+ if (pFullType)
+ {
+ pconnectedInPin->getMediaType( &pInputMediaType );
+ }
+
+ //
+ // Check if we need an XVP to be inserted between this input and output pins.
+ //
+ CompareMediaTypesForXVP( pInputMediaType.Get(), pFullType.Get(), &operation );
+ DMFTCHECKHR_GOTO( GetConnectOutPinStatus( connectedInputPin,
+ pinId, // pinId = stream which should be excluded from the search. This function searches if
+ &isAnyConnectedOutPinPaused, // there are any other output pins connected other than the ouput pin (on which the change media type is requested)
+ &isAnyConnectedOutPinRunning, //, which is streaming, paused. This way if the output pin is requested to go to Pause, Stop and if any of the
+ &isAnyConnectedOutPinActive ),done ); //other connected output pins are active, then input it not deactivated
+
+ //
+ //Check if we are asked to go to an active state
+ //Check for the new media type. if
+ //
+ if ( !IsPinStateInActive( newRequestedInPinState ) )
+ {
+ //
+ //We are being told to go active
+ //We will request a change in input stream state.
+ //
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going active IN: %d OUT: %d ", this, connectedInputPin, pinId );
+ doWeWaitForSetInput = true;
+ if ( !pFullType )
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ if ( (! pInputMediaType ) || ( operation == DeviceMftTransformXVPDisruptiveIn ) )
+ {
+ pInputMediaType = pFullType;
+ }
+ if ( newRequestedInPinState == DeviceStreamState_Pause && isAnyConnectedOutPinRunning )
+ {
+ newRequestedInPinState = DeviceStreamState_Run;
+ }
+ }
+ else
+ {
+ //
+ //We have been requested to go inactive
+ //
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going Inactive IN: %d OUT: %d ", this, connectedInputPin, pinId );
+
+ if ( operation == DeviceMftTransformXVPDisruptiveIn )
+ {
+ //
+ //Only where we recieve a disruptive media type change and a media type along with it, which is unlikely!!
+ //
+ pInputMediaType = pFullType;
+ doWeWaitForSetInput = true;
+ }
+ if ( isAnyConnectedOutPinActive )
+ {
+ newRequestedInPinState = ( isAnyConnectedOutPinRunning ) ? DeviceStreamState_Run : DeviceStreamState_Pause;
+ }
+ else
+ {
+ //Switch over to the new media type..
+ pInputMediaType = pFullType;
+ if ( !IsPinStateInActive( oldInputStreamState ) )
+ {
+ //It was originall active.. now going down
+ doWeWaitForSetInput = true;
+ }
+ }
+ }
+
+ //
+ // This will happen if we need a change in Input media type, We will send an event
+ // METransformInputStreamStateChanged to the Device transform manager. This will result
+ // in the Device Transform manager calling us back in getprefferedinputstate where
+ // we will give it back the state of the input and the media type to be set.
+ // All this happens when we are holding a lock here in Change output media type. Hence during the
+ // input media type change we don't hold a lock. THE DTM takes care not to send you any more media
+ // type change operations that can cause a deadlock.
+ //
+
+ if ( doWeWaitForSetInput )
+ {
+ pconnectedInPin->setPreferredMediaType( pInputMediaType.Get() );
+ pconnectedInPin->setPreferredStreamState( newRequestedInPinState );
+ SendEventToManager( METransformInputStreamStateChanged, GUID_NULL, pconnectedInPin->streamId() );
+ //
+ //The media type will be set on the input pin by the time we return from the wait
+ //
+ DMFTCHECKHR_GOTO( pconnectedInPin->WaitForSetInputPinMediaChange(), done );
+ }
+ else
+ {
+ pconnectedInPin->SetState( oldInputStreamState );
+ pconnectedInPin->setMediaType( pInputMediaType.Get() );
+ }
+
+ //Now the input type is all set..
+ pInputMediaType = nullptr;
+ (VOID)pconnectedInPin->getMediaType( &pInputMediaType );
+ //
+ //Now propogate the media type change to the output pins
+ //
+ MMFTMMAPITERATOR outputPinPos = m_inputPinMap.equal_range(pconnectedInPin->streamId());
+ for ( std::multimap<int, int>::iterator poutPinsIterator = outputPinPos.first;
+ poutPinsIterator != outputPinPos.second;
+ poutPinsIterator++ )
+ {
+ ComPtr<IMFMediaType> pOutMediatype = nullptr;
+ DeviceStreamState outPinState;
+ ULONG connectedoutPin = (*poutPinsIterator).second;
+ COutPin* pIoPin = static_cast<COutPin*>( GetOutPin ( connectedoutPin ) );
+
+ (VOID)pIoPin->getMediaType( &pOutMediatype );
+ outPinState = pIoPin->GetState();
+
+ if ( pIoPin->streamId() != pinId)
+ {
+ //
+ //This is the pin other than the output pin where the original change media type was recieved.
+ //
+
+ if ( pInputMediaType != nullptr && pOutMediatype != nullptr )
+ {
+ DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(),
+ pOutMediatype.Get(),
+ outPinState ),done);
+ }
+ }
+ else
+ {
+ //
+ //Change the media type of the requested output pin
+ //
+ DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(), pFullType.Get(), newOutStreamState), done);
+ //Also signal to the manager that a stream state change has happened
+ SendEventToManager( MEUnknown, MEDeviceStreamCreated, pIoPin->streamId());
+ //
+ //Set the First Sample Flag. this will get reset when the first sample comes in. We will signal the discontinuity
+ //when we get a Processoutput from the Device Transform Manager
+ //
+ pIoPin->SetFirstSample(TRUE);
+
+ }
+ pOutMediatype = nullptr;
+ }
+
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::SendEventToManager(
+ _In_ MediaEventType eventType,
+ _In_ REFGUID pGuid,
+ _In_ UINT32 context
+ )
+ /*++
+ Description:
+ Used to send the event to DTM.
+ --*/
+ {
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaEvent> pEvent = nullptr;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaEvent(eventType, pGuid, S_OK, NULL, &pEvent ),done);
+ DMFTCHECKHR_GOTO(pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, (ULONG)context),done);
+ DMFTCHECKHR_GOTO(QueueEvent(pEvent.Get()),done);
+ done:
+
+ return hr;
+ }
+
+
+STDMETHODIMP CMultipinMft::GetConnectOutPinStatus(
+ _In_ ULONG ulPinId,
+ _In_ ULONG ulOutPinId,
+ _Inout_ PBOOL pAnyInPauseState,
+ _Inout_ PBOOL pAnyInRunState,
+ _Inout_ PBOOL pAnyActive
+ )
+ /*++
+ Description:
+
+ This function gets the statuses of the output pins other than the one specified
+ The arguments are as follows
+ ulPinId: The input pins which are connected to the ouput pin ulOutPinId
+ ulOutPinId: The pin to be excluded from the check i.e. the input pin from which the request is usually sent.
+ --*/
+{
+ HRESULT hr = S_OK;
+ MMFTMMAPITERATOR outputPinPos;
+ CInPin *pconnectedInPin = (CInPin*)GetInPin(ulPinId);
+ DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_INVALIDARG );
+
+ outputPinPos = m_inputPinMap.equal_range( pconnectedInPin->streamId() );
+ DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_FAIL );
+
+ *pAnyActive = *pAnyInPauseState = *pAnyInRunState = false;
+
+ for ( std::multimap<int, int>::iterator poutPosIterator = outputPinPos.first;
+ poutPosIterator != outputPinPos.second;
+ poutPosIterator++ )
+ {
+ ULONG connectedoutPin = (*poutPosIterator).second;
+ COutPin* pconnectedOutPin = ( COutPin * )GetOutPin( connectedoutPin );
+
+ if (pconnectedOutPin->streamId() != ulOutPinId)
+ {
+ //This is excluding the outpin which requested pin state change
+ *pAnyActive |= !IsPinStateInActive( pconnectedOutPin->GetState() );
+ *pAnyInPauseState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Pause );
+ *pAnyInRunState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Run );
+ }
+
+ }
+ done:
+ return S_OK;
+}
+
+
+/*++
+Description:
+This function connects the input and output pins.
+Any media type filtering can happen here
+--*/
+STDMETHODIMP CMultipinMft::BridgeInputPinOutputPin(
+ _In_ CInPin* piPin,
+ _In_ COutPin* poPin
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG ulIndex = 0;
+ ComPtr<IMFMediaType> pMediaType = nullptr;
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ // Copy over the media types from input pin to output pin. Since there is no
+ // decoder support, only the uncompressed media types are inserted. Please make
+ // sure any pin advertised supports at least one media type. The pipeline doesn't
+ // like pins with no media types
+ //
+ while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, &pMediaType )))
+ {
+ GUID subType = GUID_NULL;
+ DMFTCHECKHR_GOTO( pMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done );
+
+ if ( IsKnownUncompressedVideoType( subType ) )
+ {
+ DMFTCHECKHR_GOTO( poPin->AddMediaType(NULL, pMediaType.Get() ), done );
+ }
+
+ pMediaType = nullptr;
+ }
+ //
+ //Add the Input Pin to the output Pin
+ //
+ DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done);
+ hr = ExceptionBoundary([&](){
+ //
+ //Add the output pin to the input pin.
+ //
+ piPin->ConnectPin(poPin);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ //
+ //Create the map. This will be useful when we have to decide the state transitions of the pins
+ //
+ m_inputPinMap.insert ( std::pair< int,int >( piPin->streamId(), poPin->streamId()) );
+ m_outputPinMap.insert ( std::pair< int, int >( poPin->streamId(), piPin->streamId()) );
+done:
+ //
+ //Failed adding media types
+ //
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+ return hr;
+}
+
+
+//
+//The below routines are used to implement the extended controls needed to implement the photo sequence
+//The photo sequence is enabled for cameras with no independent image pins
+//The extended controls needed to enable photo sequence are discussed in detail in the photo sequence document
+//
+
+/*++
+Extended Photo Mode handler is the extended property handler dealing with the photosequence and single mode capabilities of the camera
+--*/
+STDMETHODIMP CMultipinMft::ExtendedPhotoModeHandler(
+_In_ PKSPROPERTY Property,
+_In_ ULONG ulPropertyLength,
+_In_ LPVOID pData,
+_In_ ULONG ulOutputBufferLength,
+_Inout_ PULONG pulBytesReturned
+)
+
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the below structure to make changes to the Property and thus affect the configuration
+ //PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_PHOTOMODE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ m_FilterInPhotoSequence = pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE;
+ DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_PHOTOMODE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+
+ pExtendedHeader->Capability = ( KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE );
+ pExtendedHeader->Flags = ( m_FilterInPhotoSequence ) ? KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE : KSCAMERA_EXTENDEDPROP_PHOTOMODE_NORMAL;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ pExtendedHeader->Version = 1;
+
+ pExtendedValue->MaxHistoryFrames = 10;
+ pExtendedValue->RequestedHistoryFrames = 0 ;
+ pExtendedValue->SubMode = 0 ;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ }
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+
+ return hr;
+}
+
+/*++
+The Extended Max Frame rate is self explanatory
+--*/
+STDMETHODIMP CMultipinMft::ExtendedPhotoMaxFrameRate(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
+ {
+ //
+ //This is for setting the Max frame rate..
+ //
+ //PBYTE pPayload = (PBYTE)pData;
+ //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload);
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ hr = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ratio.HighPart = 30;
+ pExtendedValue->Value.ratio.LowPart = 1;
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::MaxVidFPS_PhotoResHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ))
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES );
+ }
+
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else if (Property->Flags & KSPROPERTY_TYPE_GET)
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES))
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES))
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )(pPayload );
+ PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(PKSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ pExtendedHeader->Version = 1;
+
+ pExtendedValue->PreviewFPSNum = 30;
+ pExtendedValue->PreviewFPSDenom = 1;
+ pExtendedValue->CaptureFPSNum = 30;
+ pExtendedValue->CaptureFPSDenom = 1;
+ pExtendedValue->PhotoResHeight = 240;
+ pExtendedValue->PhotoResWidth = 320;
+
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::QPCTimeHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ //PBYTE pPayload = (PBYTE)pData;
+ //
+ //If the payload is to be used.. use the below structures
+ //
+ //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload);
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_SET;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ull = 0;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::PhotoFrameRateHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ //
+ //This is a read only property!!!
+ //
+ hr = E_INVALIDARG;
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ratio.HighPart = 30;
+ pExtendedValue->Value.ratio.LowPart = 1;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::WarmStartHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ *pulBytesReturned = 0;
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done);
+ }
+ else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )pPayload;
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ if ( pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED )
+ {
+ m_filterInWarmStart = true;
+ }
+ else
+ {
+ m_filterInWarmStart = false;
+ }
+
+ *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART);
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+ else if (Property->Flags & KSPROPERTY_TYPE_GET)
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED;
+ pExtendedHeader->Flags = 0;
+
+ if (m_filterInWarmStart)
+ {
+ pExtendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED;
+ }
+
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ hr = S_OK;
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+//
+// IMFShutdown interface functions
+//
+
+/*++
+Description:
+Implements the Shutdown from IMFShutdown
+--*/
+STDMETHODIMP CMultipinMft::Shutdown(
+ void
+ )
+{
+ CAutoLock Lock(m_critSec);
+ (VOID) m_eventHandler.Clear();
+ return ShutdownEventGenerator();
+}
+
+//
+// Static method to create an instance of the MFT.
+//
+HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT)
+{
+ HRESULT hr = S_OK;
+ CMultipinMft *pMFT = NULL;
+ DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER);
+ pMFT = new (std::nothrow) CMultipinMft();
+ DMFTCHECKNULL_GOTO(pMFT, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(pMFT->QueryInterface(iid, ppMFT), done);
+
+done:
+ if (FAILED(hr))
+ {
+ SAFERELEASE(pMFT);
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+
+
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+/*
+Desciption:
+This function will be called by the preview pin to execute the photo confirmation stored with the
+MFT.
+*/
+
+STDMETHODIMP CMultipinMft::ProcessCapturePhotoConfirmationCallBack(
+ _In_ IMFMediaType* pMediaType,
+ _In_ IMFSample* pSample
+ )
+{
+ //
+ //PhotoConfirmation Implementation
+ //Note this function doesn't scan the metadata as the pipeline does to find out which buffer is the photoconfirmation buffer
+ //The pipeline treats the preview buffer as the photo confirmation buffer and the driver marks the metadata on the buffer as being so.
+ //This example treats every buffer coming on the pin as the confirmation buffer.
+ //
+
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaType> spMediaType = nullptr;
+ LONGLONG timeStamp = 0;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaType(&spMediaType), done);
+ DMFTCHECKHR_GOTO(pMediaType->CopyAllItems(spMediaType.Get()), done);
+
+ DMFTCHECKHR_GOTO(pSample->SetUnknown(MFSourceReader_SampleAttribute_MediaType_priv, spMediaType.Get()), done);
+
+ DMFTCHECKHR_GOTO(pSample->GetSampleTime(&timeStamp), done);
+ DMFTCHECKHR_GOTO(pSample->SetUINT64(MFSampleExtension_DeviceReferenceSystemTime, timeStamp), done);
+
+ if (m_spPhotoConfirmationCallback)
+ {
+
+ //
+ //We are directly sending the photo sample over to the consumers of the photoconfirmation interface.
+ //
+ ComPtr<IMFAsyncResult> spResult;
+ DMFTCHECKHR_GOTO(MFCreateAsyncResult(pSample, m_spPhotoConfirmationCallback.Get(), NULL, &spResult), done);
+ DMFTCHECKHR_GOTO(MFInvokeCallback(spResult.Get()), done);
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+#endif
+
+//
+// Only worry about this if you have customs pins defined in the driver
+//
+
+STDMETHODIMP CMultipinMft::SetStreamingStateCustomPins(
+ DeviceStreamState State
+ )
+{
+ HRESULT hr = S_OK;
+
+ if ( m_CustomPinCount > 0 )
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin State changing to %d", State);
+
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+ BOOL isCustom = false;
+ CInPin* pInPin = static_cast<CInPin*>(m_InPins[ulIndex]);
+
+ if ( SUCCEEDED( CheckCustomPin(pInPin, &isCustom) )
+ && ( isCustom ) )
+ {
+ pInPin->SetState(State);
+ }
+ }
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
diff --git a/AVStream/sampledevicemft/multipinmft.h b/AVStream/sampledevicemft/multipinmft.h
new file mode 100644
index 00000000..244a47be
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.h
@@ -0,0 +1,477 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#pragma once
+
+#include "common.h"
+#include "mftpeventgenerator.h"
+#include "basepin.h"
+#include "custompin.h"
+#include "multipinmfthelpers.h"
+
+//
+// The Below GUID is needed to transfer photoconfirmation sample successfully in the pipeline
+// It is used to propagate the mediatype of the sample to the pipeline which will consume the sample
+// This attribute is known to the OS, but not publicly defined.
+//
+
+DEFINE_GUID(MFSourceReader_SampleAttribute_MediaType_priv,
+ 0x0ea5c1e8, 0x9845, 0x41e0, 0xa2, 0x43, 0x72, 0x32, 0x07, 0xfc, 0x78, 0x1f);
+
+
+interface IDirect3DDeviceManager9;
+
+//
+// Forward declarations
+//
+class CMFAttributes;
+
+//
+// CMultipinMft class:
+// Implements a device proxy MFT.
+//
+class CMultipinMft :
+ public IMFDeviceTransform
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ , public IMFTransform
+#endif
+ , public IMFShutdown
+ , public CMediaEventGenerator
+ , public IMFRealTimeClientEx
+ , public IKsControl
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ , public IMFCapturePhotoConfirmation
+ , public IMFGetService
+#endif
+{
+public:
+ CMultipinMft(
+ void );
+
+ virtual ~CMultipinMft();
+
+ //
+ // IUnknown
+ //
+ STDMETHOD_(ULONG, AddRef)(
+ void );
+
+ STDMETHOD_(ULONG, Release)(
+ void );
+
+ STDMETHOD(QueryInterface)(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv);
+
+
+ //
+ // IMFDeviceTransform functions
+ //
+ STDMETHOD(GetStreamCount)(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams);
+
+
+ STDMETHOD(GetStreamIDs)(
+ _In_ DWORD dwInputIDArraySize,
+ _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs,
+ _In_ DWORD dwOutputIDArraySize,
+ _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)),
+ _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs
+ );
+
+ STDMETHOD(GetInputStreamAttributes)(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes);
+
+ STDMETHOD(GetOutputStreamAttributes)(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFAttributes** ppAttributes);
+
+ STDMETHOD(GetInputAvailableType)(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppType);
+
+ STDMETHOD(GetOutputAvailableType)(
+ _In_ DWORD dwOutputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType);
+
+ STDMETHOD(GetInputCurrentType)(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType);
+
+ STDMETHOD(GetOutputCurrentType)(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFMediaType** ppMediaType);
+
+ STDMETHOD(ProcessMessage)(
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ _In_ ULONG_PTR ulParam );
+
+ STDMETHOD(ProcessEvent)(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFMediaEvent *pEvent);
+
+
+ STDMETHOD(ProcessInput)(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFSample* pSample,
+ _In_ DWORD dwFlags );
+
+ STDMETHOD(ProcessOutput)(
+ _In_ DWORD dwFlags,
+ _In_ DWORD cOutputBufferCount,
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ _Out_ DWORD *pdwStatus );
+
+ //
+ // IMFRealTimeClientEx
+ //
+ STDMETHOD(RegisterThreadsEx)(
+ _Inout_ DWORD* pdwTaskIndex,
+ _In_ LPCWSTR wszClassName,
+ _In_ LONG lBasePriority )
+ {
+ UNREFERENCED_PARAMETER(pdwTaskIndex);
+ UNREFERENCED_PARAMETER(wszClassName);
+ UNREFERENCED_PARAMETER(lBasePriority);
+ return S_OK;
+ }
+
+ STDMETHOD(UnregisterThreads)()
+ {
+ return S_OK;
+ }
+
+ STDMETHOD(SetWorkQueueEx)(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority );
+
+ //
+ // IMFShutdown
+ //
+ STDMETHOD(Shutdown)(
+ void );
+
+ STDMETHOD(GetShutdownStatus)(
+ MFSHUTDOWN_STATUS *pStatus)
+ {
+ UNREFERENCED_PARAMETER(pStatus);
+ return(m_eShutdownStatus);
+ };
+
+ //
+ // IMFDeviceTransform function declarations
+ //
+ STDMETHODIMP InitializeTransform(
+ _In_ IMFAttributes *pAttributes );
+
+ _Requires_no_locks_held_
+ STDMETHODIMP SetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value );
+
+ STDMETHODIMP SetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value );
+
+ STDMETHODIMP GetInputStreamPreferredState(
+ _In_ DWORD dwStreamID,
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType );
+
+ STDMETHODIMP FlushInputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP FlushOutputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP_(VOID) FlushAllStreams(
+ VOID
+ );
+
+ //
+ //IKSControl Inferface function declarations
+ //
+ STDMETHOD(KsEvent)(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+ STDMETHOD(KsProperty)(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+ STDMETHOD(KsMethod)(
+ _In_reads_bytes_(ulPropertyLength) PKSMETHOD pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ //
+ // The Below functions are needed for photoconfirmation
+ //
+ //
+ STDMETHOD(GetService)(
+ __in REFGUID guidService,
+ __in REFIID riid,
+ __deref_out LPVOID* ppvObject
+ );
+ //
+ //IMFCapturePhotoConfirmation Inferface function declarations
+ //
+ STDMETHOD(SetPhotoConfirmationCallback)(
+ _In_ IMFAsyncCallback* pNotificationCallback
+ );
+ STDMETHOD(SetPixelFormat)(
+ _In_ GUID subtype
+ );
+ STDMETHOD(GetPixelFormat)(
+ _Out_ GUID* subtype
+ );
+
+ __inline BOOL IsPhotoConfirmationEnabled()
+ {
+ return (m_spPhotoConfirmationCallback != nullptr);
+ }
+
+ STDMETHODIMP ProcessCapturePhotoConfirmationCallBack(
+ _In_ IMFMediaType* pMediaType,
+ _In_ IMFSample* pSample
+ );
+
+ __inline VOID SetPhotoConfirmationCallBack(_In_ IMFAsyncCallback *Callback)
+ {
+ m_spPhotoConfirmationCallback = Callback;
+ }
+
+#endif
+
+ static STDMETHODIMP CreateInstance(
+ REFIID iid, void **ppMFT);
+
+ //
+ //Below functions are used by the pins to enquire the state of the Filter for Photo sequence.
+ //A Trigger is a ksproperty sent to the filter.
+ //
+
+ __inline VOID setPhotoTriggerSent(_In_ BOOL Set)
+ {
+ m_PhotoTriggerSent = Set;
+ }
+ __inline BOOL isPhotoTriggerSent()
+ {
+ return m_PhotoTriggerSent;
+ }
+
+ __inline BOOL isPhotoModePhotoSequence()
+ {
+ return m_PhotoModeIsPhotoSequence;
+ }
+ __inline BOOL filterHasIndependentPin()
+ {
+ return m_filterHasIndependentPin;
+ }
+
+ //
+ //Will be used from Pins to get the D3D manager once set!!!
+ //
+ __inline STDMETHODIMP_(VOID) GetD3DDeviceManager(
+ IUnknown** ppDeviceManagerUnk
+ )
+ {
+ m_spDeviceManagerUnk.CopyTo( ppDeviceManagerUnk );
+ }
+
+ STDMETHODIMP SendEventToManager(
+ _In_ MediaEventType,
+ _In_ REFGUID,
+ _In_ UINT32
+ );
+
+protected:
+
+ //
+ //Helper functions
+ //
+
+ STDMETHODIMP SetStreamingStateCustomPins(
+ _In_ DeviceStreamState
+ );
+
+ STDMETHODIMP_(CBasePin*) GetInPin(
+ _In_ DWORD dwStreamID
+ );
+
+ STDMETHODIMP_(CBasePin*) GetOutPin(
+ _In_ DWORD dwStreamID
+ );
+
+ STDMETHODIMP ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState newState
+ );
+
+ STDMETHODIMP GetConnectOutPinStatus(
+ _In_ ULONG ulPinId,
+ _In_ ULONG ulOutPin,
+ _Inout_ PBOOL pAnyInPauseState,
+ _Inout_ PBOOL pAnyInRunState,
+ _Inout_ PBOOL pAnyActive
+ );
+ STDMETHODIMP BridgeInputPinOutputPin(
+ _In_ CInPin* pInPin,
+ _In_ COutPin* pOutPin);
+
+ //
+ //Implementing the below to simulate a photosequence
+ //This is just to show that photosequence can be achieved purely in
+ //the user mode with the device MFT..
+ //
+ STDMETHODIMP ExtendedPhotoModeHandler(
+ _In_ PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+
+ STDMETHODIMP ExtendedPhotoMaxFrameRate(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP MaxVidFPS_PhotoResHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP QPCTimeHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP PhotoFrameRateHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP CMultipinMft::WarmStartHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ STDMETHODIMP CMultipinMft::GetAttributes(
+ _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes
+ );
+#endif
+
+#if (defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES))
+ _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__
+#endif
+
+
+ //
+ //Inline functions
+ //
+
+ __inline IMFTransform* Parent()
+ {
+ return m_spSourceTransform.Get();
+ }
+
+ __inline VOID SetStreamingState(DeviceStreamState state)
+ {
+ InterlockedExchange((LONG*)&m_StreamingState, state);
+ }
+ __inline DeviceStreamState GetStreamingState()
+ {
+ return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_StreamingState, m_StreamingState, m_StreamingState);
+ }
+ __inline BOOL IsStreaming()
+ {
+ return (InterlockedCompareExchange((LONG*)&m_StreamingState, DeviceStreamState_Run, DeviceStreamState_Run) == DeviceStreamState_Run);
+ }
+
+private:
+ ULONG m_InputPinCount;
+ ULONG m_OutputPinCount;
+ ULONG m_CustomPinCount;
+ DeviceStreamState m_StreamingState;
+ CBasePinArray m_OutPins;
+ CBasePinArray m_InPins;
+ BOOL m_PhotoTriggerSent;
+ BOOL m_PhotoModeIsPhotoSequence; // used to store if the filter is in photo sequence or not
+ BOOL m_FilterInPhotoSequence; // This applies for the filter, which is in a photo sequence or not. This is set by the Extended property handler
+ BOOL m_filterHasIndependentPin; // If any of the input pins from the source transform expose an independent photo pin then we will not simluate photoseqeunce
+ BOOL m_filterInWarmStart; // Used to store if the filter is in warm start or not!
+ long m_nRefCount; // Reference count
+ CCritSec m_critSec; // Control lock.. taken only durign state change operations
+ ComPtr <IUnknown> m_spDeviceManagerUnk; // D3D Manager set, when MFT_MESSAGE_SET_D3D_MANAGER is called through ProcessMessage
+ ComPtr<IMFTransform> m_spSourceTransform; // The sources transform
+ MFSHUTDOWN_STATUS m_eShutdownStatus;
+ DWORD m_dwWorkQueueId;
+ LONG m_lWorkQueuePriority;
+ UINT32 m_punValue;
+ ComPtr<IKsControl> m_spIkscontrol;
+ ComPtr<IMFAttributes> m_spAttributes;
+
+ multimap<int, int> m_inputPinMap; // How input pins are connected to output pins o-><0..inpins>
+ multimap<int, int> m_outputPinMap; // How output pins are connected to input pins i-><0..outpins>
+ CDMFTEventHandler m_eventHandler;
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ ComPtr<IMFAsyncCallback> m_spPhotoConfirmationCallback; //Photo Confirmation related definitions
+ GUID m_guidPhotoConfirmationSubtype;
+#endif
+
+};
+
+
+
+inline HRESULT MFT_CreateInstance(REFIID riid, void **ppv)
+{
+ return CMultipinMft::CreateInstance(riid, ppv);
+}
+
+
diff --git a/AVStream/sampledevicemft/multipinmft.vcxproj b/AVStream/sampledevicemft/multipinmft.vcxproj
new file mode 100644
index 00000000..31107772
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.vcxproj
@@ -0,0 +1,263 @@
+<?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>{E77657CD-A270-49E1-823A-8A14FF8596C8}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <SupportsPackaging>false</SupportsPackaging>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{D6CB33D6-DEF2-497E-A72D-6E6E29C67F48}</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 />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="mftpeventgenerator.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="multipinmft.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="basepin.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="multipinmfthelpers.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="multipinmftutils.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="custompin.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="stdafxsrc.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ </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/sampledevicemft/multipinmft.vcxproj.Filters b/AVStream/sampledevicemft/multipinmft.vcxproj.Filters
new file mode 100644
index 00000000..e06f675d
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.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>{39379DB7-5CE0-407A-A6D4-F2F23BB3BF3C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{05E63691-6953-4F79-BEC2-1CF881B618BA}</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>{B10F4398-9892-4AA8-8653-E5A7F4726726}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="basepin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="custompin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mftpeventgenerator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="multipinmft.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="multipinmfthelpers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="multipinmftutils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdafxsrc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="Source.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/sampledevicemft/multipinmfthelpers.cpp b/AVStream/sampledevicemft/multipinmfthelpers.cpp
new file mode 100644
index 00000000..078ca337
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmfthelpers.cpp
@@ -0,0 +1,988 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmfthelpers.h"
+#include "multipinmft.h"
+#include "basepin.h"
+#include <wincodec.h>
+
+#ifdef MF_WPP
+#include "multipinmfthelpers.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+class CMediaTypePrinter;
+//
+//Queue implementation
+//
+
+CPinQueue::CPinQueue( _In_ DWORD _InpinId )
+: m_teer(0),
+ m_discotinuity(0),
+ m_sampleCount(0),
+ m_dwInPinId(_InpinId)
+ /*
+ Description
+ _InpinId is the input pin Id to which this queue corresponds
+ */
+{
+}
+CPinQueue::~CPinQueue( )
+{
+}
+
+/*++
+Description:
+ Insert sample into the list once we reach the open queue
+--*/
+STDMETHODIMP_(VOID) CPinQueue::InsertInternal( _In_ IMFSample *pSample )
+{
+ pSample->AddRef();
+ HRESULT hr = ExceptionBoundary([&]()
+ {
+ m_sampleList.push_back(pSample);
+ });
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ SAFE_RELEASE(pSample);
+ }
+}
+
+STDMETHODIMP_(BOOL) CPinQueue::Insert( _In_ IMFSample *pSample )
+//
+//m_teer is the wraptee.. this could be a null tee which is a passthrough, an xvp tee, which inserts an xvp into the queue
+//
+{
+ return SUCCEEDED( m_teer->PassThrough( pSample, this ) );
+}
+
+
+/*++
+Description:
+ This extracts the first sample from the queue. called from Pin's ProcessOutput
+--*/
+
+STDMETHODIMP_(BOOL) CPinQueue::Remove( _Outptr_result_maybenull_ IMFSample **ppSample)
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO( ppSample, done,E_INVALIDARG );
+ *ppSample = nullptr;
+
+ if ( !m_sampleList.empty() )
+ {
+ *ppSample = m_sampleList.front();
+ }
+
+ DMFTCHECKNULL_GOTO( *ppSample, done, MF_E_TRANSFORM_NEED_MORE_INPUT );
+
+ (*ppSample)->Release( );
+
+ m_sampleList.erase( m_sampleList.begin() );
+done:
+ return SUCCEEDED( hr ) ? TRUE : FALSE;
+}
+
+/*++
+Description:
+ Empties the Queue. used by the flush
+--*/
+VOID CPinQueue::Clear( )
+{
+ IMFSample* pSample = nullptr;
+ while ( !Empty() )
+ {
+ Remove( &pSample );
+ SAFE_RELEASE( pSample );
+ }
+}
+
+/*++
+Description:
+ RecreateTee creates the underlying Tees in the queue. It accepts the input media type
+ which is the media type set on the input pin and the output mediatype, which (duh) is the
+ media type on the output pin
+ It also takes an IUnknown which is the D3D Manager. if it is valid we might use it if we
+ have an xvp in the path i.e. inputMediatype =! outputMediatype
+--*/
+
+STDMETHODIMP CPinQueue::RecreateTee( _In_ IMFMediaType *inMediatype,
+ _In_ IMFMediaType *outMediatype,
+ _In_opt_ IUnknown* punkManager )
+{
+ HRESULT hr = S_OK;
+ MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal;
+
+ DMFTCHECKNULL_GOTO(inMediatype, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(outMediatype, done, E_INVALIDARG);
+
+ SAFE_DELETE(m_teer);
+
+ CNullTee *nulltee = new (std::nothrow) CNullTee();
+ DMFTCHECKNULL_GOTO( nulltee, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO( CompareMediaTypesForXVP(inMediatype, outMediatype, &operation), done);
+
+ if ( (operation != DeviceMftTransformXVPCurrent) && (operation!= DeviceMftTransformXVPIllegal) )
+ {
+ CXvptee* pXvptee = new (std::nothrow) CXvptee(nulltee);
+ DMFTCHECKNULL_GOTO(pXvptee, done, E_OUTOFMEMORY);
+ (void)pXvptee->SetD3DManager( punkManager );
+ (void)pXvptee->SetMediaTypes( inMediatype, outMediatype );
+ m_teer = dynamic_cast< Ctee* >( pXvptee );
+ }
+ else
+ {
+ m_teer = nulltee; /*A simple passthrough*/
+ }
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+
+ if (FAILED(hr))
+ {
+ if (m_teer){
+ delete(m_teer);
+ m_teer = NULL;
+ }
+
+ }
+ return hr;
+}
+
+//
+//State implementation
+//
+CPinOpenState::CPinOpenState(CBasePin *_pin)
+:CPinState(DeviceStreamState_Run), m_pin(_pin)
+{
+
+}
+
+
+
+/*++
+Description:
+ This is the passthrough Tee in the literal sense i.e. It just dumps the sample
+ into the queue qupplied as an argument
+--*/
+STDMETHODIMP CNullTee::PassThrough( _In_ IMFSample *pSample, _In_ CPinQueue *que )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(pSample, done, S_OK); //No OP for a NULL Sample!!!
+ (VOID)que->InsertInternal(pSample);
+
+ done:
+ return hr;
+}
+
+/*++
+Description:
+ This function sets the Media types on the XVP or the decoder transform. Here is where we configure the XVP
+ or the Decoder or the Encoder tee if present. The first iteration only has the XVP added
+--*/
+STDMETHODIMP CWrapTee::SetMediaTypes( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType )
+{
+ HRESULT hr = S_OK;
+ IMFTransform *pTransform = nullptr;
+
+ DMFTCHECKHR_GOTO(Configure( pInMediaType, pOutMediaType, &pTransform ),done);
+ m_videoProcessor = pTransform;
+ m_pInputMediaType = pInMediaType;
+ m_pOutputMediaType = pOutMediaType;
+
+done:
+ SAFE_RELEASE(pTransform);
+ return hr;
+}
+
+/*++
+Description:
+This is used when an XVP is present in the Pin. If the path is a passthrough i.e.
+the media type on the input and the output pins are the same then we will not see
+this path traversed. This function feeds the sample to the XVP or the decoding Tee
+--*/
+STDMETHODIMP CWrapTee::PassThrough(_In_ IMFSample* pInSample, _In_ CPinQueue *pQue)
+{
+ HRESULT hr = S_OK;
+ IMFSample* pOutSample = nullptr;
+
+ DMFTCHECKHR_GOTO(Do(pInSample, &pOutSample),done);
+
+ if (m_objectWrapped)
+ {
+ hr = m_objectWrapped->PassThrough(pOutSample, pQue);
+ }
+
+done:
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+
+ return hr;
+}
+
+
+/*++
+CXvptee::Do
+Description:
+Called to do what an XVP is supposed to do i.e. scaling, resize etc.
+This function is called when the samples are desposited from the input pin to the
+output pin queue during a ProcessInput call on the device transform. Of course the
+outpin should be in Open state for the sample to reach the XVP and consequetively the
+Output Pin.
+
+If the DX manager is set on the Transform and we receieve a DX sample then we will
+undertake the DX transform in the XVP else we will skip it and go the software way
+--*/
+STDMETHODIMP CXvptee::Do(_In_ IMFSample *pSample, _Outptr_ IMFSample** pOutSample)
+{
+ //
+ //Since we are streaming in the software mode we will create a new sample
+ //
+ HRESULT hr = S_OK,pohr = S_OK;
+ MFT_OUTPUT_DATA_BUFFER outputSample;
+ MFT_OUTPUT_STREAM_INFO StreamInfo;
+ IMFSample* spXVPOutputSample = nullptr;
+ IMFMediaType* pOutMediaType = nullptr;
+ ComPtr <IMFMediaBuffer> spIMFMediaBuffer = nullptr;
+ GUID guidOutputSubType = GUID_NULL;
+ pOutMediaType = getOutMediaType();
+
+ DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG);
+
+ DMFTCHECKHR_GOTO(pOutMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done);
+
+ BOOL isDx = false;
+
+ if (SUCCEEDED(IsInputDxSample(pSample, &isDx)) && isDx)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! DX Sample sent to XVP %p", pSample);
+ }
+
+ outputSample.dwStreamID = 0;
+ outputSample.pSample = NULL;
+
+ if (!(isDx && m_spDeviceManagerUnk!=nullptr))
+ {
+ //
+ //Create a new sample for software encoding
+ //
+ DMFTCHECKHR_GOTO(MFCreateSample(&spXVPOutputSample), done);
+
+ DMFTCHECKHR_GOTO(pSample->CopyAllItems(spXVPOutputSample), done);
+
+ outputSample.pSample = spXVPOutputSample;
+
+
+ DMFTCHECKHR_GOTO(Transform()->MFTGetOutputStreamInfo(0, &StreamInfo), done);
+
+ if (!m_isOutPutImage)
+ {
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pOutMediaType, MF_MT_FRAME_SIZE, &m_uWidth, &m_uHeight), done);
+ hr = MFCreate2DMediaBuffer(
+ m_uWidth,
+ m_uHeight,
+ guidOutputSubType.Data1,
+ FALSE, // top-down buffer (DX compatible)
+ &spIMFMediaBuffer);
+ if (FAILED(hr))
+ {
+ spIMFMediaBuffer = nullptr;
+ spXVPOutputSample->Release();
+
+ DMFTCHECKHR_GOTO(MFCreateAlignedMemoryBuffer(
+ StreamInfo.cbSize,
+ StreamInfo.cbAlignment,
+ &spIMFMediaBuffer), done);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured without DX, Created a 1D buffer");
+
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured with DX, Created a 2D buffer");
+ }
+ DMFTCHECKHR_GOTO(spXVPOutputSample->AddBuffer(spIMFMediaBuffer.Get()), done);
+ }
+ }
+
+
+ //
+ //Start streaming the xvp transform..
+ //
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), done); // ulParam set to zero
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), done); // ulParam set to zero
+
+
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessInput(0, pSample, 0),done);
+
+ DWORD dwStatus = 0;
+
+ pohr = Transform()->MFTProcessOutput(0, 1, &outputSample, &dwStatus);
+
+ if (FAILED(pohr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP ProcessOutput,failure %x sample =%p", pohr, &outputSample);
+ SAFERELEASE(spXVPOutputSample);
+ }
+
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), done); // Flush the stream
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0), done); // Notify end of stream
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0), done); // Notify end of streaming
+
+ spXVPOutputSample = outputSample.pSample;
+
+ if ( SUCCEEDED(pohr) )
+ {
+ //Let us copy the timestamps
+ LONGLONG hnsSampleDuration = 0;
+ LONGLONG hnsSampleTime = 0;
+
+ pSample->GetSampleDuration(&hnsSampleDuration);
+ pSample->GetSampleTime(&hnsSampleTime);
+ spXVPOutputSample->SetSampleDuration(hnsSampleDuration);
+ spXVPOutputSample->SetSampleTime(hnsSampleTime);
+ }
+
+ *pOutSample = spXVPOutputSample;
+ //
+ //Release the Sample back to the pipeline
+ //
+ pSample->Release();
+
+done:
+ hr = FAILED(pohr) ? pohr : hr;
+ return hr;
+}
+
+/*++
+Description:
+ Set the D3D Manager on the XVP
+--*/
+STDMETHODIMP_(VOID) CXvptee::SetD3DManager(IUnknown* pUnk)
+{
+ m_spDeviceManagerUnk = pUnk;
+}
+/*++
+Descrtiption:
+ Create the XVP Transform with the media types supplied.
+ This is invoked when an XVP is added to the Queue in the Output pins
+ and the input pins media type and the output pins media type don't match.
+
+--*/
+STDMETHODIMP CXvptee::Configure(
+ _In_opt_ IMFMediaType* inMediaType,
+ _In_opt_ IMFMediaType* outMediaType,
+ _Outptr_ IMFTransform **ppTransform
+ )
+{
+ HRESULT hr = S_OK;
+ GUID inMajorType = GUID_NULL;
+ GUID outMajorType = GUID_NULL;
+ bool imageType = false;
+ bool optimized = false;
+ bool optimizedxvpneeded = false;
+ IMFMediaType *pXvpOutputMediaType = nullptr;
+ ComPtr<IMFAttributes> pXvpTransformAttributes = nullptr;
+ UINT32 width = 0, height = 0;
+
+ DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG);
+
+ m_isOutPutImage = false;
+ m_isoptimizedPlanarInputOutput = false;
+
+ //
+ //Print out the Media type set on the XVP
+ //
+ {
+ CMediaTypePrinter inType(inMediaType);
+ CMediaTypePrinter outType(outMediaType);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Input MediaType %s", inType.ToString());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Output MediaType %s", outType.ToString());
+ }
+
+ DMFTCHECKHR_GOTO( CoCreateInstance(
+ CLSID_VideoProcessorMFT,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(ppTransform)), done);
+
+
+
+ DMFTCHECKHR_GOTO( inMediaType->GetMajorType( &inMajorType ),done );
+ DMFTCHECKHR_GOTO( outMediaType->GetMajorType( &outMajorType ), done );
+ //
+ //Configuring DX Manager in SW mode. We will look to make it DX complaint in the next phase
+ //
+ if ( !IsEqualGUID(MFMediaType_Video, outMajorType ) )
+ {
+ imageType = true;
+ m_isOutPutImage = true;
+ IsOptimizedPlanarVideoInputImageOutputPair(
+ inMediaType,
+ outMediaType,
+ &optimized,
+ &optimizedxvpneeded );
+ }
+
+ //
+ //Disable frame rate conversion
+ //
+ DMFTCHECKHR_GOTO((*ppTransform)->GetAttributes(&pXvpTransformAttributes),done);
+ pXvpTransformAttributes->SetUINT32(MF_XVP_DISABLE_FRC, TRUE);
+ DMFTCHECKHR_GOTO( (*ppTransform)->MFTProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, NULL ), done );
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetInputType(0, inMediaType, 0), done);
+
+
+ DMFTCHECKHR_GOTO(MFCreateMediaType(&pXvpOutputMediaType), done);
+ DMFTCHECKHR_GOTO(outMediaType->CopyAllItems(pXvpOutputMediaType), done);
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), done); //Video propcessor doesn't understand image types
+
+
+ if ( imageType )
+ {
+ GUID guidSub;
+
+ if ( !optimized )
+ {
+ DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done );
+ if ( IsEqualGUID( guidSub, MFVideoFormat_ARGB32 ) )
+ {
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), done);
+ }
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done);
+
+ m_uWidth = width;
+ m_uHeight = height;
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, width * 4), done); //So we always get a top down buffer
+
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done);
+ }
+ else
+ {
+ //*** If we come here we know that the XVP is needed
+ //This case should be for non planar and xvp needed cases which we will always assume
+ LONG cStride = 0;
+ //For now we will just assume that we need the xvp in all cases
+ DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done );
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, guidSub), done);
+
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done);
+
+ DMFTCHECKHR_GOTO( MFGetStrideForBitmapInfoHeader( guidSub.Data1, width, &cStride ), done );
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, cStride), done); //So we always get a top down buffer for Nv12/Yv12
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255), done); //Always set nominal range to 0-255 to feed into a WIC encoder
+
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done);
+ }
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, outMediaType, 0), done);
+ }
+ if ((m_spDeviceManagerUnk != nullptr))
+ {
+ //
+ //Set the D3D Manager on the XVP if present
+ //
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER,
+ reinterpret_cast<ULONG_PTR>(m_spDeviceManagerUnk.Get())), done);
+ }
+done:
+ SAFE_RELEASE(pXvpOutputMediaType);
+ return hr;
+
+}
+
+
+CXvptee::CXvptee( _In_ Ctee *tee) :
+CWrapTee(tee),
+ m_isOutPutImage(false),
+ m_isoptimizedPlanarInputOutput(true),
+ m_spDeviceManagerUnk(nullptr),
+ m_uHeight(0),
+ m_uWidth(0)
+
+{
+
+}
+
+
+CXvptee::~CXvptee()
+{
+ m_spDeviceManagerUnk = nullptr;
+}
+
+//To be implemented..Not needed for the sample!!
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+STDMETHODIMP CDecoderTee::Do(_In_ IMFSample* pSample, _Out_ IMFSample **pOutSample )
+{
+ UNREFERENCED_PARAMETER(pSample);
+ UNREFERENCED_PARAMETER(pOutSample);
+ return S_OK;
+}
+STDMETHODIMP CDecoderTee::Configure( _In_opt_ IMFMediaType *inMediaType, _In_opt_ IMFMediaType *outMediaType, _Outptr_ IMFTransform** ppTransform)
+{
+ HRESULT hr = S_OK;
+ GUID guidcategory = GUID_NULL;
+ BOOL IsDecoder = true;
+ UINT32 unFlags = 0;
+ MFT_REGISTER_TYPE_INFO in;
+ MFT_REGISTER_TYPE_INFO out;
+ UINT32 cActivates = 0;
+ UINT32 unMFTFlags = 0;
+ ComPtr<IMFMediaType> pInputMediaType = nullptr;
+ ComPtr<IMFMediaType> pOutputMediaType = nullptr;
+ IMFActivate **ppActivates = nullptr;
+ DWORD dwInputStreams;
+ DWORD dwOutputStreams;
+ UNREFERENCED_PARAMETER(outMediaType);
+ UNREFERENCED_PARAMETER(inMediaType);
+ UNREFERENCED_PARAMETER(ppTransform);
+
+ guidcategory = (IsDecoder)?MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_ENCODER;
+
+ if (IsDecoder)
+ {
+ DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &in.guidMajorType), done);
+ DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_SUBTYPE, &in.guidSubtype), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &out.guidMajorType), done);
+ DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &out.guidSubtype), done);
+ }
+
+ //
+ //Use all possible plugins
+ //
+
+ unFlags = MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_SORTANDFILTER_WEB_ONLY;
+ DMFTCHECKHR_GOTO(MFTEnumEx(guidcategory,
+ unFlags,
+ IsDecoder ? &in : NULL,
+ IsDecoder ? NULL : &out,
+ &ppActivates,
+ &cActivates
+ ),done);
+ if (cActivates!=0)
+ {
+ DMFTCHECKHR_GOTO(MF_E_TOPO_CODEC_NOT_FOUND, done);
+ }
+ for (DWORD dwIndex = 0; dwIndex < cActivates; dwIndex++)
+ {
+ //
+ //Check if this MFT requires an unlocking.. skip if it does
+ //
+ unMFTFlags = MFGetAttributeUINT32(ppActivates[dwIndex], MF_TRANSFORM_FLAGS_Attribute, 0);
+ if (unMFTFlags & MFT_ENUM_FLAG_FIELDOFUSE)
+ {
+ //
+ //If you have the unlocking key set MFT_FIELDOFUSE_UNLOCK_Attribute on the activate
+ //
+ continue;
+ }
+
+ hr = ppActivates[dwIndex]->ActivateObject(IID_PPV_ARGS(ppTransform));
+ if (FAILED(hr))
+ continue; //hope the next activate is activable
+ ppActivates[dwIndex]->DetachObject();
+
+ hr = (*ppTransform)->MFTGetStreamCount(&dwInputStreams, &dwOutputStreams);
+
+ if (FAILED(hr) || dwInputStreams != 1 || dwOutputStreams > 127)//remove the hardcoding
+ {
+ //
+ //Exception.. we can't use a stream that doesn't give us an idea about it's streams
+ //
+ continue;
+ }
+ if (IsDecoder)
+ {
+ hr = ConfigureDecoder(*ppTransform);
+ }
+ else
+ {
+ hr = ConfigureEncoder(*ppTransform);
+ }
+ if (FAILED(hr))
+ {
+ SAFE_RELEASE(*ppTransform);
+ }
+ }
+
+done:
+ return hr;
+}
+
+/*++
+
+--*/
+
+STDMETHODIMP CDecoderTee::ConfigureEncoder( _In_ IMFTransform *pTransform )
+{
+ HRESULT hr = S_OK;
+ //
+ //Set the input media type and the output media type and that should be pretty much it
+ //
+ ComPtr<IMFMediaType> pInputType = nullptr;
+ ComPtr<IMFMediaType> pOutputType = nullptr;
+
+ pInputType = getInMediaType();
+ pOutputType = getOutMediaType();
+
+ if (pInputType && pOutputType)
+ {
+ //We should be good by now
+ DMFTCHECKHR_GOTO( pTransform->MFTSetInputType( 0,pInputType.Get(), 0), done);
+ //If we have D3D enabled then try again with D3D disabled and see the result
+ //
+ DMFTCHECKHR_GOTO(pTransform->MFTSetOutputType(0,pOutputType.Get(), 0), done);
+ //
+ //If the above operation fails and we are allowing partial media types then
+ //we have to find the full media type and then check again
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+done:
+ return hr;
+}
+
+STDMETHODIMP CDecoderTee::ConfigureDecoder( _In_ IMFTransform *pTransform)
+{
+ UNREFERENCED_PARAMETER( pTransform );
+ return S_OK;
+}
+
+/*++
+Descrtiption:
+ Handles events sent by the pipeline
+ --*/
+STDMETHODIMP CDMFTEventHandler::KSEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned)
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pBytesReturned);
+
+ if (pEvent == nullptr)
+ {
+ //
+ // We can have an Event Reset here
+ //
+ if (pEventData == nullptr)
+ {
+ //
+ // Invalid input. KSEVENT and KSEVENTDATA cannot both be null
+ //
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ //
+ // The way KSevents work are, KSEVENT and KSEVENTDATA both have to be non null for events to be Set
+ // on the driver. If the pipeline wishes to reset the event we pass the KSEVENT structure as NULL and
+ // the KSEVENTDATA to be nonnull.
+ // ********** EVENT RESET here since KSEVENT is null and KSEVENTDATA is not**********
+ // We will never get Event Reset for One shot events
+ // Search the list of regular events to find the KSEVENTDATA pointer and then free the entry
+ //
+ for ( vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it )
+ {
+ PDMFTEventEntry pEntry = nullptr;
+ pEntry = *it;
+ DMFTCHECKNULL_GOTO(pEntry, done, E_UNEXPECTED); // We should never see a null data structure entry
+ if (pEntry->m_pEventData == pEventData)
+ {
+ it = m_RegularEventList.erase(it);
+ delete(pEntry); // Delete the entry!
+ goto done;
+ }
+ }
+
+ DMFTCHECKHR_GOTO(E_NOT_SET, done);
+ }
+ else
+ {
+ //
+ // If we are here the pipeline wants to do the following things
+ // 1) Store a regular event
+ // 2) Store a oneshot event
+ //
+ HANDLE evtHandle = nullptr;
+ PKSEVENT pEvt = pEvent;
+ PKSEVENTDATA pEvtdata = reinterpret_cast<PKSEVENTDATA>(pEventData);
+
+ if (ulEventLength < sizeof(KSEVENT))
+ {
+ DMFTCHECKNULL_GOTO(pBytesReturned, done, E_INVALIDARG);
+ *pBytesReturned = sizeof(KSEVENT);
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+
+ if (!pEvtdata)
+ {
+ //
+ // Need the event data to be present to service the call properly!
+ //
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+
+ if (pEvt->Flags & KSEVENT_TYPE_ENABLE) // Regular/ Manual Reset Event
+ {
+ vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin();
+ for (; it != m_RegularEventList.end(); it++)
+ {
+ PDMFTEventEntry pEntry = *it;
+ DMFTCHECKNULL_GOTO(pEntry, done, E_FAIL);
+ if (pEntry->m_pEventData == pEventData)
+ {
+ break;
+ }
+ }
+ if (it != m_RegularEventList.end())
+ {
+ //
+ // Duplicate entry found.
+ //
+ DMFTCHECKHR_GOTO(E_NOT_VALID_STATE, done);
+ }
+ }
+ else if (pEvt->Flags & KSEVENT_TYPE_ONESHOT)
+ {
+ ULONG ulEventCommand = pEvt->Id;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventCommand);
+ if (it != m_OneShotEventMap.end())
+ {
+ //
+ // Duplicate entry found.
+ //
+ hr = E_NOT_VALID_STATE;
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_NOTIMPL, done);
+ }
+
+ //
+ // Duplicate the handle
+ //
+ DMFTCHECKHR_GOTO(Dupe(pEvtdata->EventHandle.Event, &evtHandle),done);
+ ULONG ulEventCommand = pEvt->Id;
+
+ if (pEvt->Flags & KSEVENT_TYPE_ENABLE)
+ {
+ // ************** REGULAR EVENT ****************************
+ // Regualar event. When this needs to be cleqared we will geta call with KSEVENT = null
+ // and KSEVENTDATA with the same address as this call(pEvtdata). Hence store it
+ // To set the event all we need is the EVENT id.
+ //
+ PDMFTEventEntry pEntry = new DMFTEventEntry(ulEventCommand, pEvtdata, evtHandle);
+ DMFTCHECKNULL_GOTO(pEntry, done, E_OUTOFMEMORY);
+ hr = ExceptionBoundary([&]()
+ {
+ (VOID)m_RegularEventList.push_back(pEntry);
+ });
+ }
+ else if(pEvt->Flags & KSEVENT_TYPE_ONESHOT)
+ {
+ // *************** SINGLE SHOT EVENT ************************
+ // Single Shot event store. Store the event Id and the Handle.
+ //
+ hr = ExceptionBoundary([&]()
+ {
+ (VOID)m_OneShotEventMap.insert(std::pair<ULONG, HANDLE>(ulEventCommand, evtHandle));
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+
+done:
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Used to set the One shot events sent by the pipeline.
+ One shot events should be closed by the component after firing. The Pipeline
+ will not send a reset or a clear for one shot events
+--*/
+
+STDMETHODIMP CDMFTEventHandler::SetOneShot( ULONG ulEventId )
+{
+ HRESULT hr = S_OK;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventId);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! trying to Set OneShot %d ", ulEventId);
+
+ if (it != m_OneShotEventMap.end())
+ {
+ // Found the event
+ HANDLE hOneShot = it->second;
+ if (SetEvent(hOneShot))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d Succeeded",
+ ulEventId);
+ CloseHandle(hOneShot);
+ m_OneShotEventMap.erase(it);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x",
+ ulEventId,
+ HRESULT_FROM_WIN32(GetLastError()));
+ }
+ }
+ else
+ {
+ hr = E_NOT_SET;
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x",
+ ulEventId,
+ HRESULT_FROM_WIN32(GetLastError()));
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Used to set the Regular events sent by the pipeline.
+ Regular events unlike the one shot events must be persisted
+ until the pipeline explicitly needs the event to be unset.
+--*/
+
+STDMETHODIMP CDMFTEventHandler::SetRegularEvent(ULONG ulEventId)
+{
+ BOOL bEvtFound = FALSE;
+ HRESULT hr = ExceptionBoundary([&]()
+ {
+
+ for (vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it)
+ {
+ PDMFTEventEntry pEntry = *it;
+ if (ulEventId == pEntry->m_ulEventId)
+ {
+ // Found the event
+ bEvtFound = TRUE;
+ if (!::SetEvent(pEntry->m_hHandle))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d Failed 0x%x",
+ ulEventId, hr);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d s",
+ ulEventId);
+ }
+ }
+ }
+ });
+ if (!bEvtFound)
+ {
+ DMFTCHECKHR_GOTO(E_NOT_SET, done);
+ }
+done:
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Duplicates the handle passed.
+--*/
+
+STDMETHODIMP CDMFTEventHandler::Dupe(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle)
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO(hEventHandle, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(lpTargetHandle, done, E_INVALIDARG);
+ //
+ // Duplicate handle and store it for when it needs to be fired
+ //
+ if (!DuplicateHandle(GetCurrentProcess(), hEventHandle,
+ GetCurrentProcess(), lpTargetHandle,
+ 0,
+ false,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Duplicating Event Handle failed %x",
+ hr);
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+done:
+ return hr;
+}
+
+/*++
+
+Descrtiption:
+ Cleans the event lists, both the Single shot and the Regular ones
+
+--*/
+STDMETHODIMP CDMFTEventHandler::Clear()
+{
+ HRESULT hr = S_OK;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.begin();
+ for (; it != m_OneShotEventMap.end(); ++it)
+ {
+ //
+ // Delete the one shot entries. We should not see this path usually
+ // as the pipeline will send a one shot event and set it soon. We
+ // should remore the entry then.
+ //
+ CloseHandle(it->second);
+ it = m_OneShotEventMap.erase(it);
+ if (it == m_OneShotEventMap.end())
+ {
+ // We've reached the end break
+ break;
+ }
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ hr = ExceptionBoundary([=]()
+ {
+ vector<PDMFTEventEntry>::iterator it2 = m_RegularEventList.begin();
+ for (; it2 != m_RegularEventList.end(); ++it2)
+ {
+ //
+ // Delete the entries. This will be traversed
+ //
+ PDMFTEventEntry pEntry = *it2;
+ it2 = m_RegularEventList.erase(it2);
+ SAFE_DELETE(pEntry);
+ if (it2 == m_RegularEventList.end())
+ {
+ break;
+ }
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+done:
+ return hr;
+}
diff --git a/AVStream/sampledevicemft/multipinmfthelpers.h b/AVStream/sampledevicemft/multipinmfthelpers.h
new file mode 100644
index 00000000..25d87eb8
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmfthelpers.h
@@ -0,0 +1,291 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+#pragma once
+#include "stdafx.h"
+#include "common.h"
+
+
+
+//
+//Queue class!!!
+//
+class Ctee;
+//typedef CMFAttributesTrace CMediaTypeTrace; /* Only used for debug. take this out*/
+
+
+class CPinQueue{
+public:
+ CPinQueue(_In_ DWORD _inPinId);
+ ~CPinQueue();
+
+ STDMETHODIMP_(BOOL) SetState ( _In_ BOOL state );
+ STDMETHODIMP_(VOID) InsertInternal ( _In_ IMFSample *pSample = nullptr );
+ STDMETHODIMP_(BOOL) Insert ( _In_ IMFSample *pSample );
+ STDMETHODIMP_(BOOL) Remove (_Outptr_result_maybenull_ IMFSample **pSample);
+ STDMETHODIMP RecreateTee ( _In_ IMFMediaType *inMediatype, _In_ IMFMediaType *outMediatype, _In_opt_ IUnknown* punkManager );
+ STDMETHODIMP_(VOID) Clear();
+
+ //
+ //Inline functions
+ //
+ __inline BOOL Empty()
+ {
+ return (!m_sampleList.size());
+ }
+
+ __inline DWORD pinStreamId()
+ {
+ return m_dwInPinId;
+ }
+
+private:
+ DWORD m_dwInPinId; /*This is the input pin */
+ IMFSampleList m_sampleList; /*List storing the samples */
+ ULONG m_sampleCount; /*Numebr of sampels */
+ Ctee* m_teer; /*Tee that acts as a passthrough or an XVP */
+ BOOL m_discotinuity; /*Set after the queue is emptied or flushed */
+
+};
+
+class CPinState{
+public:
+ virtual STDMETHODIMP Open() = 0;
+ CPinState( _In_ DeviceStreamState _state = DeviceStreamState_Disabled) :m_State( _state )
+ {
+
+ }
+ STDMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState ); /*True for Active and False for Stop*/
+ STDMETHODIMP_(DeviceStreamState) GetState();
+
+ __inline STDMETHODIMP_(DeviceStreamState) State()
+ {
+ return m_State;
+ }
+ virtual ~CPinState() = 0
+ {
+ }
+protected:
+ DeviceStreamState m_State;
+};
+
+class CPinOpenState :public CPinState{
+public:
+ CPinOpenState( _In_ CBasePin *p = NULL );
+ //
+ //Inline
+ //
+ __inline STDMETHODIMP Open()
+ {
+ return S_OK;
+ }
+
+private:
+ CBasePin *m_pin;
+};
+class CPinClosedState : public CPinState{
+public:
+ CPinClosedState(DeviceStreamState _state = DeviceStreamState_Stop)
+ :CPinState(_state)
+ {
+
+ }
+ //
+ //Inline
+ //
+ __inline STDMETHODIMP Open()
+ {
+ return MF_INVALID_STATE_ERR;
+ }
+};
+
+
+
+//
+// Define these in different components
+// The below classes are used to add the
+// XVP and the Decoder components
+//
+class Ctee{
+public:
+ virtual STDMETHODIMP PassThrough( _In_ IMFSample *, _In_ CPinQueue * ) = 0;
+};
+
+
+class CNullTee:public Ctee{
+public:
+ STDMETHODIMP PassThrough( _In_ IMFSample*, _In_ CPinQueue * );
+};
+
+
+class CWrapTee : public Ctee{
+public:
+ CWrapTee(_In_ Ctee *tee=nullptr)
+: m_objectWrapped(tee)
+ , m_pInputMediaType(nullptr)
+ , m_pOutputMediaType(nullptr)
+ {
+
+ }
+ virtual ~CWrapTee()=0
+ {
+ m_videoProcessor = nullptr;
+ if (m_objectWrapped)
+ {
+ delete(m_objectWrapped);
+ }
+ }
+
+ STDMETHODIMP PassThrough ( _In_ IMFSample*, _In_ CPinQueue * );
+ virtual STDMETHODIMP Configure ( _In_ IMFMediaType *, _In_ IMFMediaType *, _Inout_ IMFTransform** ) = 0;
+ virtual STDMETHODIMP Do ( _In_ IMFSample* pSample, _Out_ IMFSample ** ) = 0;
+ STDMETHODIMP SetMediaTypes ( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType );
+
+ //
+ //Inline functions
+ //
+protected:
+ __inline IMFTransform* Transform()
+ {
+ return m_videoProcessor.Get();
+ }
+ __inline IMFMediaType* getInMediaType()
+ {
+ IMFMediaType* pmediaType = nullptr;
+ m_pInputMediaType.CopyTo(&pmediaType);
+ return pmediaType;
+ }
+ __inline IMFMediaType* getOutMediaType()
+ {
+ IMFMediaType* pmediaType = nullptr;
+ m_pOutputMediaType.CopyTo(&pmediaType);
+ return pmediaType;
+ }
+
+private:
+ ComPtr< IMFTransform > m_videoProcessor;
+ ComPtr< IMFMediaType > m_pInputMediaType;
+ ComPtr< IMFMediaType > m_pOutputMediaType;
+ Ctee *m_objectWrapped;
+};
+
+
+class CXvptee :public CWrapTee{
+public:
+ CXvptee( _In_ Ctee * );
+ ~CXvptee();
+ STDMETHODIMP Do ( _In_ IMFSample* pSample, _Outptr_ IMFSample ** );
+ STDMETHODIMP Configure ( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** );
+ STDMETHODIMP_(VOID) SetD3DManager( IUnknown* punk );
+
+private:
+ BOOL m_isoptimizedPlanarInputOutput;
+ BOOL m_isOutPutImage;
+ UINT32 m_uWidth;
+ UINT32 m_uHeight;
+ ComPtr<IUnknown> m_spDeviceManagerUnk;
+};
+
+class CDecoderTee : public CWrapTee{
+public:
+ CDecoderTee(Ctee* *);
+ ~CDecoderTee();
+
+ STDMETHODIMP Do( _In_ IMFSample* pSample, _Out_ IMFSample ** );
+ STDMETHODIMP Configure( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** );
+ STDMETHODIMP ConfigureEncoder( _In_ IMFTransform *pTransform );
+ STDMETHODIMP ConfigureDecoder( _In_ IMFTransform *pTransform );
+private:
+ ComPtr<IUnknown> m_spDeviceManagerUnk;
+};
+
+
+/*
+################## EVENT HANDLING #############################################
+Events are usually divided into two categories by the Capture Pipeline
+1) Regular Event / Manual Reset Event
+2) One Shot Event
+
+Regular events are set and cleared by the pipeline
+One shot Events will only be set by the pipeline and it should be cleared
+by the Component managing the Event Store i.e. KS or DMFT. For Redstone
+The pipeline should not send any Non One shot events.This sample however
+does show the handling of Regular/ Manual Reset events
+
+This clearing of One shot events is done when the event is fired..
+E.g before sending the warm start command The pipeline will send a one shot event
+KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART and when the operation completes the
+event should be fired.
+The Device MFT should usually keep a watch for one shot events sent by the Pipeline
+for Async Extended controls..The list of Asynchronous controls are as follows..
+
+KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE
+KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID
+KSPROPERTY_CAMERACONTROL_EXTENDED_ISO
+KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED
+KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION
+KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL
+KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART
+KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL
+KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE
+The complete list can be found from the Camera DDI spec
+###############################################################################
+*/
+
+typedef struct _DMFTEventEntry{
+ ULONG m_ulEventId; // KSEVENT->Id
+ PVOID m_pEventData; // Lookup for events in the data structure
+ HANDLE m_hHandle; // The duplicate handle stored from the event
+ //
+ // Constructor. We simply cache the handles, the property id and the KSEVENTDATA buffer sent from the user mode
+ //
+ _DMFTEventEntry( _In_ ULONG ulEventId, _In_ PVOID pEventData, _In_ HANDLE pHandle):m_pEventData(pEventData)
+ , m_ulEventId(ulEventId)
+ , m_hHandle(pHandle)
+ {
+ }
+ ~_DMFTEventEntry()
+ {
+ if ( m_hHandle != nullptr )
+ {
+ CloseHandle(m_hHandle);
+ m_hHandle = nullptr;
+ }
+ }
+
+}DMFTEventEntry, *PDMFTEventEntry;
+
+//
+// Handler for one shot events and Normal events
+//
+class CDMFTEventHandler{
+public:
+ //
+ // Handle the events here
+ //
+ STDMETHOD(KSEvent)(_In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned);
+ STDMETHOD(SetOneShot)(ULONG);
+ STDMETHOD(SetRegularEvent)(ULONG);
+ STDMETHOD(Clear)();
+protected:
+ STDMETHOD(Dupe)(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle);
+private:
+ map< ULONG, HANDLE > m_OneShotEventMap;
+ vector< PDMFTEventEntry > m_RegularEventList;
+};
+
+
+
diff --git a/AVStream/sampledevicemft/multipinmftutils.cpp b/AVStream/sampledevicemft/multipinmftutils.cpp
new file mode 100644
index 00000000..6f5735b5
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmftutils.cpp
@@ -0,0 +1,877 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmft.h"
+#include "basepin.h"
+
+#pragma comment(lib, "d2d1")
+#ifdef MF_WPP
+#include "multipinmftutils.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+// Critical sections
+
+CCritSec::CCritSec()
+{
+ InitializeCriticalSection(&m_criticalSection);
+}
+
+CCritSec::~CCritSec()
+{
+ DeleteCriticalSection(&m_criticalSection);
+}
+
+_Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection)
+void CCritSec::Lock()
+{
+ EnterCriticalSection(&m_criticalSection);
+}
+
+_Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection)
+void CCritSec::Unlock()
+{
+ LeaveCriticalSection(&m_criticalSection);
+}
+
+
+_Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+CAutoLock::CAutoLock(CCritSec& crit)
+{
+ m_pCriticalSection = &crit;
+ m_pCriticalSection->Lock();
+}
+_Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+CAutoLock::CAutoLock(CCritSec* crit)
+{
+ m_pCriticalSection = crit;
+ m_pCriticalSection->Lock();
+}
+_Releases_lock_(this->m_pCriticalSection->m_criticalSection)
+CAutoLock::~CAutoLock()
+{
+ m_pCriticalSection->Unlock();
+}
+
+//
+//Some utility functions..
+//
+
+/*++
+ Description:
+ Used to check if the input and the output Image types are optinmized or not
+--*/
+
+STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair(
+ _In_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *outMediaType,
+ _Out_ bool *optimized,
+ _Out_ bool *optimizedxvpneeded )
+{
+ HRESULT hr = S_OK;
+ GUID guidInputSubType = GUID_NULL;
+ GUID guidOutputSubType = GUID_NULL;
+ UINT32 uWidthIn = 0, uHeightIn = 0, uWidthOut = 0, uHeightOut = 0;
+
+
+ DMFTCHECKHR_GOTO(inMediaType->GetGUID(MF_MT_SUBTYPE, &guidInputSubType), done);
+
+ DMFTCHECKHR_GOTO(outMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done);
+
+ *optimized = false; //Assume we aren't optimized . Optimized = (ip = YU12|NV12 and op = JPEG)
+ *optimizedxvpneeded = true; //Assume we need xvps
+
+ if (IsEqualGUID(guidInputSubType, MFVideoFormat_YV12) || IsEqualGUID(guidInputSubType, MFVideoFormat_NV12))
+ {
+ if (IsEqualGUID(guidOutputSubType, GUID_ContainerFormatJpeg))
+ {
+ *optimized = true;
+ }
+ }
+
+ if (!*optimized)
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(inMediaType, MF_MT_FRAME_SIZE, &uWidthIn, &uHeightIn), done);
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(outMediaType, MF_MT_FRAME_SIZE, &uWidthOut, &uHeightOut), done);
+
+ if ((uWidthIn == uWidthOut) && (uHeightIn == uHeightOut))
+ {
+ *optimizedxvpneeded = false;
+ }
+ if (!*optimizedxvpneeded)
+ {
+ UINT32 nominalRange;
+ hr = inMediaType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange);
+
+ if (FAILED(hr) || nominalRange != MFNominalRange_0_255)
+ {
+ //XVP needed since nominal range is not 0-255 for YV12 or NV12 fed into WIC
+ *optimizedxvpneeded = true;
+ }
+ hr = S_OK;
+ }
+
+done:
+ return hr;
+}
+
+
+/*
+Description:
+
+ This is used whenever there is a media type change on an output pin and the
+ Output queue is being reconfigured.
+ The possible return values for the function are as follows
+
+ DeviceMftTransformXVPIllegal -> If either of the mediatypes or both are NULL
+ DeviceMftTransformXVPDisruptiveIn -> If the mediatype at the output pin is greater than the input pin. This will result in change of the media type on the input
+ DeviceMftTransformXVPDisruptiveOut -> This is a reconfiguration or addition of the XVP in the Output pin queue
+ DeviceMftTransformXVPCurrent -> No XVP needed at all
+ Note: This iteration doesn't support decoder. The next one will and this function will accordingly change
+*/
+STDMETHODIMP CompareMediaTypesForXVP(
+ _In_opt_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *newMediaType,
+ _Inout_ MF_TRANSFORM_XVP_OPERATION *operation
+ )
+{
+ UINT32 unWidthin, unHeightin, unWidthNew, unHeightNew = 0;
+ HRESULT hr = S_OK;
+ GUID guidTypeA = GUID_NULL;
+ GUID guidTypeB = GUID_NULL;
+
+ *operation = DeviceMftTransformXVPIllegal;
+ if ((!inMediaType) || (!newMediaType))
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO( MFGetAttributeSize( inMediaType, MF_MT_FRAME_SIZE, &unWidthin, &unHeightin ), done );
+ DMFTCHECKHR_GOTO( MFGetAttributeSize( newMediaType, MF_MT_FRAME_SIZE, &unWidthNew, &unHeightNew ), done );
+
+
+ if ( SUCCEEDED( inMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeA ) ) &&
+ SUCCEEDED( newMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeB ) ) &&
+ IsEqualGUID( guidTypeA, guidTypeB ) )
+ {
+ if ( SUCCEEDED( inMediaType->GetGUID ( MF_MT_SUBTYPE, &guidTypeA ) ) &&
+ SUCCEEDED( newMediaType->GetGUID( MF_MT_SUBTYPE, &guidTypeB ) ) &&
+ IsEqualGUID( guidTypeA, guidTypeB ) )
+ {
+ //Comparing the MF_MT_AM_FORMAT_TYPE for the directshow format guid
+#if 0
+ if (SUCCEEDED(inMediaType->GetGUID(MF_MT_AM_FORMAT_TYPE, &guidTypeA)) &&
+ SUCCEEDED(newMediaType->GetGUID(MF_MT_AM_FORMAT_TYPE, &guidTypeB)) &&
+ IsEqualGUID(guidTypeA, guidTypeB))
+#endif
+ {
+
+ if (!(( unWidthin == unWidthNew ) &&
+ ( unHeightin == unHeightNew ) ) )
+ {
+ if ( ( unWidthNew > unWidthin ) || ( unHeightNew > unHeightin ) )
+ {
+ *operation = DeviceMftTransformXVPDisruptiveIn; //Media type needs to change at input
+ }
+ else
+ {
+ *operation = DeviceMftTransformXVPDisruptiveOut; //Media type needs to change at output
+ }
+ goto done;
+ }
+
+ if ( MFGetAttributeUINT32( inMediaType, MF_MT_SAMPLE_SIZE, 0 ) !=
+ MFGetAttributeUINT32( newMediaType, MF_MT_SAMPLE_SIZE, 0 ) )
+ {
+ hr = S_FALSE; //Sample sizes differ.
+ goto done;
+ }
+ else
+ {
+ //Same media type.. No XVP needed or the current XVP is fine!
+ *operation = DeviceMftTransformXVPCurrent;
+ }
+ }
+ }
+ else
+ {
+ //This is a disruptive operation. Actually a decoder operation!
+ *operation = DeviceMftTransformXVPDisruptiveIn;
+ }
+ }
+ done:
+ return hr;
+}
+
+/*++
+Description:
+ A Simple function to randomnize the media types supplied in an array
+--*/
+STDMETHODIMP RandomnizeMediaTypes(_In_ IMFMediaTypeArray &pMediaTypeArray)
+{
+ HRESULT hr = S_OK;
+ IMFMediaType *pTempMediaType = nullptr;
+ UNREFERENCED_PARAMETER(pTempMediaType);
+ if (pMediaTypeArray.empty())
+ {
+ goto done;
+ }
+
+ srand(static_cast<unsigned long>(GetTickCount64()));
+
+ for (DWORD dwIndex = (DWORD)pMediaTypeArray.size() - 1; dwIndex > 0; dwIndex--)
+ {
+ DWORD fromIndex = rand() % ( dwIndex + 1 );
+ pTempMediaType = pMediaTypeArray[dwIndex];
+ pMediaTypeArray [ dwIndex ] = pMediaTypeArray[fromIndex] ;
+ pMediaTypeArray [ fromIndex ] = pTempMediaType;
+ }
+ //
+ //Just reverse the array
+ //
+ for (DWORD dwIndex = (DWORD)pMediaTypeArray.size() - 1, fromIndex = 0; dwIndex > 0; dwIndex--, fromIndex++)
+ {
+
+ pTempMediaType = pMediaTypeArray[dwIndex];
+ pMediaTypeArray [ dwIndex ] = pMediaTypeArray[fromIndex];
+ pMediaTypeArray [ fromIndex ] = pTempMediaType;
+ }
+ done:
+ return hr;
+
+}
+
+/*++
+Description: Used to test if the sample passed is a DX sample or not?
+--*/
+STDMETHODIMP IsInputDxSample(
+ _In_ IMFSample* pSample,
+ _Inout_ BOOL *isDxSample
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaBuffer> spBuffer = nullptr;
+ DMFTCHECKNULL_GOTO( pSample, done, E_INVALIDARG );
+
+ *isDxSample = false;
+ if ( SUCCEEDED( pSample->GetBufferByIndex( 0, &spBuffer ) ) )
+ {
+ ComPtr<IMFDXGIBuffer> spDXGIBuffer;
+ ComPtr<ID3D11Texture2D> spResourceTexture;
+ if ( SUCCEEDED( spBuffer.As(&spDXGIBuffer ) ) &&
+ SUCCEEDED( spDXGIBuffer-> GetResource( IID_PPV_ARGS( &spResourceTexture ) ) ) )
+ {
+ *isDxSample = true;
+ }
+ }
+done:
+ return hr;
+}
+
+
+/*++
+ Description:
+ Helper function to return back if the Pin is in stopped stateo or not
+--*/
+STDMETHODIMP_(BOOL) IsPinStateInActive( _In_ DeviceStreamState state)
+{
+ if ((state == DeviceStreamState_Disabled) ||
+ (state == DeviceStreamState_Stop))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+Description:
+ A Helper function to return if the Mediatype is a compressed video type or not!
+*/
+STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(_In_ GUID guidSubType)
+{
+ if (guidSubType == MFVideoFormat_ARGB32 ||
+ guidSubType == MFVideoFormat_RGB24 ||
+ guidSubType == MFVideoFormat_RGB555 ||
+ guidSubType == MFVideoFormat_RGB565 ||
+ guidSubType == MFVideoFormat_RGB32 ||
+ guidSubType == MFVideoFormat_RGB8 ||
+ guidSubType == MFVideoFormat_AI44 ||
+ guidSubType == MFVideoFormat_AYUV ||
+ guidSubType == MFVideoFormat_YUY2 ||
+ guidSubType == MFVideoFormat_YVYU ||
+ guidSubType == MFVideoFormat_YVU9 ||
+ guidSubType == MFVideoFormat_UYVY ||
+ guidSubType == MFVideoFormat_NV11 ||
+ guidSubType == MFVideoFormat_NV12 ||
+ guidSubType == MFVideoFormat_YV12 ||
+ guidSubType == MFVideoFormat_I420 ||
+ guidSubType == MFVideoFormat_IYUV ||
+ guidSubType == MFVideoFormat_Y210 ||
+ guidSubType == MFVideoFormat_Y216 ||
+ guidSubType == MFVideoFormat_Y410 ||
+ guidSubType == MFVideoFormat_Y416 ||
+ guidSubType == MFVideoFormat_Y41P ||
+ guidSubType == MFVideoFormat_Y41T ||
+ guidSubType == MFVideoFormat_Y42T ||
+ guidSubType == MFVideoFormat_P210 ||
+ guidSubType == MFVideoFormat_P216 ||
+ guidSubType == MFVideoFormat_P010 ||
+ guidSubType == MFVideoFormat_P016 ||
+ guidSubType == MFVideoFormat_v210 ||
+ guidSubType == MFVideoFormat_v216 ||
+ guidSubType == MFVideoFormat_v410 ||
+ guidSubType == MFVideoFormat_L8 ||
+ guidSubType == MFVideoFormat_L16 ||
+ guidSubType == MFVideoFormat_D16)
+ {
+ return( TRUE );
+ }
+
+ return( FALSE );
+}
+
+/*++
+Description:
+ Function used to lock the MFT.
+--*/
+
+STDMETHODIMP UnLockAsynMFT(IMFTransform* pTransform)
+{
+ HRESULT hr = S_OK;
+ IMFAttributes *pAttributes;
+ UINT32 unValue;
+
+ DMFTCHECKNULL_GOTO(pTransform,done, E_INVALIDARG);
+ DMFTCHECKHR_GOTO(pTransform->GetAttributes(&pAttributes),done);
+ DMFTCHECKHR_GOTO(pAttributes->GetUINT32(MF_TRANSFORM_ASYNC, &unValue), done);
+
+ if (unValue)
+ {
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_TRANSFORM_ASYNC, true), done);
+ }
+
+done:
+ return hr;
+}
+
+
+#ifndef IF_EQUAL_RETURN
+#define IF_EQUAL_RETURN(param, val) if(val == param) return #val
+#endif
+
+#define checkAdjustBufferCap(a,len){\
+ char* tStore = NULL; \
+if (a && strlen(a) > ((len * 7) / 10)){\
+ tStore = a; \
+ len *= 2; \
+ a = new char[len]; \
+if (!a){\
+goto done;}\
+ a[0] = 0; \
+ strcat_s(a, len, tStore); \
+ delete(tStore); }\
+}
+
+
+/*++
+Description:
+ returns an ascii buffer for the GUID passed. The Caller should release the memory allocated
+--*/
+LPSTR DumpGUIDA(_In_ REFGUID guid)
+{
+ LPOLESTR lpszGuidString = NULL;
+ char *ansiguidStr = NULL;
+ if (SUCCEEDED(StringFromCLSID(guid, &lpszGuidString)))
+ {
+ int mbGuidLen = 0;
+ mbGuidLen = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, NULL, 0, NULL, NULL);
+ if (mbGuidLen > 0)
+ {
+ mf_assert(mbGuidLen == (int)wcslen(lpszGuidString));
+ ansiguidStr = new char[mbGuidLen];
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, ansiguidStr, mbGuidLen, NULL, NULL);
+ CoTaskMemFree(lpszGuidString);
+ ansiguidStr[mbGuidLen - 1] = 0;
+ }
+ }
+ return ansiguidStr;
+}
+
+//
+//Borrrowed from MDSN sample
+//
+LPCSTR GetGUIDNameConst(const GUID& guid)
+{
+ IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT);
+ IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES);
+ IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED);
+ IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE);
+ IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX);
+ IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN);
+ IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO);
+ IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS);
+ IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS);
+ IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING);
+ IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE);
+ IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES);
+ IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
+ IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE);
+ IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE);
+ IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE);
+ IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE);
+ IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED);
+ IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE);
+ IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE);
+ IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING);
+ IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE);
+ IF_EQUAL_RETURN(guid, MF_MT_PALETTE);
+ IF_EQUAL_RETURN(guid, MF_MT_USER_DATA);
+ IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK);
+ IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER);
+ IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT);
+ IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY);
+ IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC);
+ IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG);
+
+ // Media types
+
+ IF_EQUAL_RETURN(guid, MFMediaType_Audio);
+ IF_EQUAL_RETURN(guid, MFMediaType_Video);
+ IF_EQUAL_RETURN(guid, MFMediaType_Protected);
+ IF_EQUAL_RETURN(guid, MFMediaType_SAMI);
+ IF_EQUAL_RETURN(guid, MFMediaType_Script);
+ IF_EQUAL_RETURN(guid, MFMediaType_Image);
+ IF_EQUAL_RETURN(guid, MFMediaType_HTML);
+ IF_EQUAL_RETURN(guid, MFMediaType_Binary);
+ IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer);
+
+ IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8
+ IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU);
+
+ IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM
+ IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT
+ IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS
+ IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF
+ IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF
+ IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9
+ IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3
+ IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG
+ IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC
+ IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC
+
+ return NULL;
+}
+
+
+LPSTR DumpAttribute( _In_ const MF_ATTRIBUTE_TYPE& type,
+ _In_ REFPROPVARIANT var)
+{
+ CHAR *tempStr = NULL;
+ tempStr = new CHAR[256];
+ switch (type)
+ {
+ case MF_ATTRIBUTE_UINT32:
+ if (var.vt == VT_UI4)
+ {
+ sprintf_s(tempStr, 256, "%u", var.ulVal);
+ }
+ break;
+ case MF_ATTRIBUTE_UINT64:
+ if (var.vt == VT_UI8)
+ {
+ sprintf_s(tempStr, 256, "%I64d (high: %d low: %d)", var.uhVal.QuadPart, var.uhVal.HighPart, var.uhVal.LowPart);
+ }
+ break;
+ case MF_ATTRIBUTE_DOUBLE:
+ if (var.vt == VT_R8)
+ {
+ sprintf_s(tempStr, 256, "%.4f", var.dblVal);
+ }
+ break;
+ case MF_ATTRIBUTE_GUID:
+ if (var.vt == VT_CLSID)
+ {
+ return DumpGUIDA(*var.puuid);
+ }
+ break;
+ case MF_ATTRIBUTE_STRING:
+ if (var.vt == VT_LPWSTR)
+ {
+ sprintf_s(tempStr, 256, "%S", var.pwszVal);
+ }
+ break;
+ case MF_ATTRIBUTE_IUNKNOWN:
+ break;
+ default:
+ printf("(Unknown Attribute Type = %d) ", type);
+ break;
+ }
+ return tempStr;
+}
+
+CMediaTypePrinter::CMediaTypePrinter(
+ _In_ IMFMediaType *_pMediaType )
+ : pMediaType(_pMediaType),
+ m_pBuffer(NULL)
+{
+}
+
+CMediaTypePrinter::~CMediaTypePrinter()
+{
+ if (m_pBuffer)
+ {
+ delete(m_pBuffer);
+ }
+}
+
+/*++
+Description:
+Rudimentary function to print the complete Media type
+--*/
+PCHAR CMediaTypePrinter::ToCompleteString( )
+{
+ HRESULT hr = S_OK;
+ UINT32 attrCount = 0;
+ GUID attrGuid = { 0 };
+ char *tempStore = nullptr;
+ PROPVARIANT var;
+ LPSTR pTempBaseStr;
+ MF_ATTRIBUTE_TYPE pType;
+
+ if ( pMediaType && !m_pBuffer )
+ {
+ DMFTCHECKHR_GOTO(pMediaType->GetCount(&attrCount), done);
+ buffLen = MEDIAPRINTER_STARTLEN;
+ m_pBuffer = new char[buffLen];
+ m_pBuffer[0] = 0;
+ for ( UINT32 ulIndex = 0; ulIndex < attrCount; ulIndex++ )
+ {
+ PropVariantInit( &var );
+ checkAdjustBufferCap( m_pBuffer, buffLen );
+ DMFTCHECKHR_GOTO( pMediaType->GetItemByIndex( ulIndex, &attrGuid, &var ), done );
+ DMFTCHECKHR_GOTO( pMediaType->GetItemType( attrGuid, &pType ), done );
+ if ( ulIndex > 0 )
+ strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : ");
+ strcat_s( m_pBuffer, buffLen, GetGUIDNameConst( attrGuid ) );
+ strcat_s( m_pBuffer, buffLen, "=" );
+ pTempBaseStr = DumpAttribute( pType, var );
+ strcat_s( m_pBuffer, buffLen, pTempBaseStr );
+ delete( pTempBaseStr );
+ PropVariantClear( &var );
+ }
+ done:
+ if ( tempStore )
+ {
+ delete( tempStore );
+ }
+ }
+ return m_pBuffer;
+}
+
+/*++
+Description:
+Rudimentary function to print the Media type
+--*/
+
+PCHAR CMediaTypePrinter::ToString()
+{
+ //
+ //Following are the important ones of Mediatype attributes
+ //
+
+ HRESULT hr = S_OK;
+ PROPVARIANT var;
+ LPSTR pTempBaseStr;
+ MF_ATTRIBUTE_TYPE pType;
+ GUID attrGuid;
+ GUID impGuids[] = {
+ MF_MT_SUBTYPE,
+ MF_MT_FRAME_SIZE,
+ MF_MT_SAMPLE_SIZE,
+ MF_MT_FRAME_RATE,
+ MF_MT_DEFAULT_STRIDE,
+ MF_XVP_DISABLE_FRC
+ };
+
+ if (pMediaType && !m_pBuffer)
+ {
+ buffLen = MEDIAPRINTER_STARTLEN;
+ m_pBuffer = new char[buffLen];
+ m_pBuffer[0] = 0;
+ for (UINT32 ulIndex = 0; ulIndex < ARRAYSIZE(impGuids); ulIndex++)
+ {
+ PropVariantInit(&var);
+ checkAdjustBufferCap(m_pBuffer, buffLen);
+ attrGuid = impGuids[ulIndex];
+ DMFTCHECKHR_GOTO(pMediaType->GetItemType(attrGuid, &pType), done);
+ DMFTCHECKHR_GOTO(pMediaType->GetItem(attrGuid, &var), done);
+ if (ulIndex > 0)
+ strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : ");
+ strcat_s(m_pBuffer, buffLen, GetGUIDNameConst(attrGuid));
+ strcat_s(m_pBuffer, buffLen, "=");
+ pTempBaseStr = DumpAttribute(pType, var);
+ strcat_s(m_pBuffer, buffLen, pTempBaseStr);
+ delete(pTempBaseStr);
+ PropVariantClear(&var);
+ }
+ }
+done:
+ return m_pBuffer;
+}
+/*++
+Description:
+ Debug message printer to print the message passed through WPP
+--*/
+void printMessageEvent(MFT_MESSAGE_TYPE msg)
+{
+ switch (msg)
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_FLUSH");
+ break;
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_DRAIN");
+ break;
+ case MFT_MESSAGE_COMMAND_MARKER:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_MARKER");
+ break;
+ case MFT_MESSAGE_COMMAND_TICK:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_TICK");
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_END_OF_STREAM");
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_BEGIN_STREAMING");
+ break;
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_START_OF_STREAM");
+ break;
+ case MFT_MESSAGE_DROP_SAMPLES:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_DROP_SAMPLES");
+ break;
+ case MFT_MESSAGE_SET_D3D_MANAGER:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_SET_D3D_MANAGER");
+ break;
+
+ }
+}
+
+/*++
+Below functions not used in the current iteration..
+--*/
+HRESULT CreateCodec(
+ _In_opt_ IMFMediaType* inMediaType,
+ _In_opt_ IMFMediaType *outMediaType,
+ _In_ BOOL operation /*True = Encode, False = Decode*/,
+ _Out_ IMFTransform **pTransform)
+{
+ UNREFERENCED_PARAMETER(inMediaType);
+ UNREFERENCED_PARAMETER(outMediaType);
+ UNREFERENCED_PARAMETER(operation);
+ UNREFERENCED_PARAMETER(pTransform);
+ HRESULT hr = S_OK;
+ *pTransform = nullptr;
+ return hr;
+}
+
+
+HRESULT CheckDX9RotationSupport(_In_ ID3D11VideoDevice* pVideoDevice)
+{
+ HRESULT hr = S_OK;
+ //
+ // check if the DX9 device is ok
+ // New drivers should have an DXVA-HD rotation cap set
+ //
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {};
+ D3D11_VIDEO_PROCESSOR_CAPS caps;
+ ComPtr<ID3D11VideoProcessorEnumerator> spVideoProcEnum = nullptr;
+
+ DMFTCHECKNULL_GOTO(pVideoDevice, done, E_NOTIMPL);
+ desc.InputWidth = 640;
+ desc.InputHeight = 480;
+ desc.OutputWidth = 640;
+ desc.OutputHeight = 480;
+
+ DMFTCHECKHR_GOTO(pVideoDevice->CreateVideoProcessorEnumerator(&desc, &spVideoProcEnum), done);
+ DMFTCHECKHR_GOTO(spVideoProcEnum->GetVideoProcessorCaps(&caps), done);
+
+ if (!(caps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION))
+ {
+ hr = E_NOTIMPL;
+ }
+done:
+ return hr;
+}
+
+
+
+HRESULT IsDXOptimal(_In_ IUnknown *pDeviceManager, _Out_ BOOL *pIsOptimal)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFDXGIDeviceManager> spDXGIDeviceManager = nullptr;
+ ComPtr<ID3D11Device> spD3D11 = nullptr;
+ ComPtr<ID3D11VideoDevice> spVideoDevice = nullptr;
+ HANDLE hDevice = NULL;
+ BOOL locked = FALSE;
+
+ *pIsOptimal = false;
+ DMFTCHECKNULL_GOTO( pDeviceManager, done, E_INVALIDARG );
+ DMFTCHECKHR_GOTO( pDeviceManager->QueryInterface(IID_PPV_ARGS( &spDXGIDeviceManager )), done );
+ DMFTCHECKHR_GOTO( spDXGIDeviceManager->OpenDeviceHandle( &hDevice ), done );
+ DMFTCHECKHR_GOTO( spDXGIDeviceManager->LockDevice( hDevice, IID_PPV_ARGS( &spD3D11 ), TRUE), done );
+ locked = TRUE;
+ DMFTCHECKHR_GOTO( spD3D11.As(&spVideoDevice), done );
+
+ if (spD3D11->GetFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ {
+ if (FAILED(CheckDX9RotationSupport(spVideoDevice.Get())))
+ {
+ goto done;
+ }
+ }
+ *pIsOptimal = TRUE;
+done:
+ if (hDevice)
+ {
+ if (locked)
+ {
+ spDXGIDeviceManager->UnlockDevice(hDevice, false);
+ }
+ spDXGIDeviceManager->CloseDeviceHandle(hDevice);
+ }
+ return hr;
+}
+
+
+//
+// Used to check if the pin is a custom pin or not!!
+//
+
+STDMETHODIMP CheckCustomPin(
+ _In_ CInPin * pPin,
+ _Inout_ PBOOL pIsCustom
+ )
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO( pPin, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO( pIsCustom, done, E_INVALIDARG);
+
+ *pIsCustom = false;
+
+#if defined _CPPRTTI
+ if (dynamic_cast<CCustomPin*>(pPin) != nullptr)
+ {
+ *pIsCustom = true;
+ }
+ else
+#endif
+ {
+ GUID categoryGUID = GUID_NULL;
+ if (SUCCEEDED(pPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &categoryGUID))
+ && IsEqualCLSID(categoryGUID, AVSTREAM_CUSTOM_PIN_IMAGE))
+ {
+ *pIsCustom = true;
+ }
+ }
+done:
+ return hr;
+}
+
diff --git a/AVStream/sampledevicemft/stdafx.h b/AVStream/sampledevicemft/stdafx.h
new file mode 100644
index 00000000..9f4bab9f
--- /dev/null
+++ b/AVStream/sampledevicemft/stdafx.h
@@ -0,0 +1,39 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#pragma once
+
+
+#include <SDKDDKVer.h>
+#include <windows.h>
+#include <winnt.h>
+#include <tchar.h>
+#include <comdef.h>
+#include <initguid.h>
+#include <ks.h>
+#include <ksmedia.h>
+#include <Strsafe.h>
+#include <wchar.h>
+#include <stdio.h>
+#include <assert.h>
+#include <mfidl.h>
+#include <wincodec.h>
+#include <mfapi.h>
+#include <mftransform.h>
+#include <mfidl.h>
+#include <mferror.h>
+#include <mftransform.h>
+#include <time.h>
+#include <initguid.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+#include <d3d11.h>
+#include <mfcaptureengine.h>
+#include <new>
+#include <vector>
+#include <map>
+using namespace std;
+#include <Windows.Foundation.h>
+#include <wrl\client.h>
+using namespace ABI::Windows::Foundation;
+using namespace Microsoft::WRL;
diff --git a/AVStream/sampledevicemft/stdafxsrc.cpp b/AVStream/sampledevicemft/stdafxsrc.cpp
new file mode 100644
index 00000000..1577c4e3
--- /dev/null
+++ b/AVStream/sampledevicemft/stdafxsrc.cpp
@@ -0,0 +1 @@
+#include "stdafx.h" \ No newline at end of file
diff --git a/AVStream/samplemft0/Mft0.cpp b/AVStream/samplemft0/Mft0.cpp
new file mode 100644
index 00000000..044a4e71
--- /dev/null
+++ b/AVStream/samplemft0/Mft0.cpp
@@ -0,0 +1,975 @@
+// Mft0.cpp : Implementation of CMft0
+
+#include "stdafx.h"
+#include "Mft0.h"
+#include "SampleHelpers.h"
+#include <WinString.h>
+
+// CMft0
+STDMETHODIMP CMft0::UpdateDsp(UINT32 uiPercentOfScreen)
+{
+ m_percentOfScreen = uiPercentOfScreen;
+ return S_OK;
+}
+
+STDMETHODIMP CMft0::Enable(void)
+{
+ m_bEnableEffects = TRUE;
+ return S_OK;
+}
+
+STDMETHODIMP CMft0::Disable(void)
+{
+ m_bEnableEffects = FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP CMft0::GetDspSetting(UINT* puiPercentOfScreen, BOOL* pIsEnabled)
+{
+ HRESULT hr = S_OK;
+ do {
+ CHK_NULL_PTR_BRK(puiPercentOfScreen);
+ CHK_NULL_PTR_BRK(pIsEnabled);
+ *puiPercentOfScreen = m_percentOfScreen;
+ *pIsEnabled = m_bEnableEffects;
+ } while (FALSE);
+
+ return S_OK;
+}
+
+STDMETHODIMP CMft0::GetIids(
+ /* [out] */ _Out_ ULONG *iidCount,
+ /* [size_is][size_is][out] */ _Outptr_result_buffer_maybenull_(*iidCount) IID **iids)
+{
+ HRESULT hr = S_OK;
+ do {
+ CHK_NULL_PTR_BRK(iidCount);
+ CHK_NULL_PTR_BRK(iids);
+ *iids = NULL;
+ *iidCount = 0;
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetRuntimeClassName(
+ /* [out] */ _Outptr_result_maybenull_ HSTRING *className)
+{
+ HRESULT hr = S_OK;
+ if(className != nullptr)
+ {
+ hr = WindowsCreateString(NULL, 0, className);
+ if(FAILED(hr)){
+ hr = E_OUTOFMEMORY;
+ }
+ }else {
+ hr = E_INVALIDARG;
+ }
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetTrustLevel(
+ /* [out] */ _Out_ TrustLevel *trustLevel)
+{
+ HRESULT hr = S_OK;
+ do {
+ CHK_NULL_PTR_BRK(trustLevel);
+ *trustLevel = TrustLevel::BaseTrust;
+ } while (FALSE);
+
+ return hr;
+}
+
+
+STDMETHODIMP CMft0::GetStreamLimits(
+ /* [out] */ _Out_ DWORD *pdwInputMinimum,
+ /* [out] */ _Out_ DWORD *pdwInputMaximum,
+ /* [out] */ _Out_ DWORD *pdwOutputMinimum,
+ /* [out] */ _Out_ DWORD *pdwOutputMaximum)
+{
+ HRESULT hr = S_OK;
+ do {
+ if ((pdwInputMinimum == NULL) ||
+ (pdwInputMaximum == NULL) ||
+ (pdwOutputMinimum == NULL) ||
+ (pdwOutputMaximum == NULL))
+ {
+ hr = E_POINTER;
+ break;
+ }
+
+ // This MFT has a fixed number of streams.
+ *pdwInputMinimum = 1;
+ *pdwInputMaximum = 1;
+ *pdwOutputMinimum = 1;
+ *pdwOutputMaximum = 1;
+ } while (FALSE);
+
+ return hr;
+}
+
+
+STDMETHODIMP CMft0::GetStreamCount(
+ /* [out] */ _Out_ DWORD *pcInputStreams,
+ /* [out] */ _Out_ DWORD *pcOutputStreams)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ if ((pcInputStreams == NULL) || (pcOutputStreams == NULL))
+
+ {
+ hr = E_POINTER;
+ break;
+ }
+
+ // This MFT has a fixed number of streams.
+ *pcInputStreams = 1;
+ *pcOutputStreams = 1;
+ } while (FALSE);
+
+ return hr;
+}
+STDMETHODIMP CMft0::GetStreamIDs(
+ DWORD dwInputIDArraySize,
+ /* [size_is][out] */ _Out_writes_(dwInputIDArraySize) DWORD *pdwInputIDs,
+ DWORD dwOutputIDArraySize,
+ /* [size_is][out] */ _Out_writes_(dwOutputIDArraySize) DWORD *pdwOutputIDs)
+{
+ dwOutputIDArraySize = 0;
+ dwInputIDArraySize = 0;
+ pdwInputIDs = NULL;
+ pdwOutputIDs = NULL;
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CMft0::GetInputStreamInfo(
+ DWORD dwInputStreamID,
+ /* [out] */ _Out_ MFT_INPUT_STREAM_INFO *pStreamInfo)
+{
+ HRESULT hr = S_OK;
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_NULL_BRK(pStreamInfo);
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ CHK_LOG_BRK(MF_E_INVALIDSTREAMNUMBER);
+ }
+ if(m_pInputType) {
+ pStreamInfo->cbAlignment = 0;
+ pStreamInfo->cbSize = 0;
+ pStreamInfo->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER ;
+ pStreamInfo->hnsMaxLatency = 0;
+ } else {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+
+STDMETHODIMP CMft0::GetOutputStreamInfo(
+ DWORD dwOutputStreamID,
+ /* [out] */ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo)
+{
+ HRESULT hr = S_OK;
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_NULL_BRK(pStreamInfo);
+ if (!IsValidInputStream(dwOutputStreamID))
+ {
+ CHK_LOG_BRK(MF_E_INVALIDSTREAMNUMBER);
+ }
+ if(m_pOutputType) {
+ pStreamInfo->cbAlignment = 0;
+ pStreamInfo->cbSize = 0;
+ pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
+ } else {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetAttributes(
+ /* [out] */ _Outptr_result_maybenull_ IMFAttributes **ppAttributes)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ CHK_NULL_PTR_BRK(ppAttributes);
+ if(!m_pGlobalAttributes) {
+ CHK_LOG_BRK(MFCreateAttributes(&m_pGlobalAttributes, 3));
+ CHK_LOG_BRK(m_pGlobalAttributes->SetUINT32(MF_TRANSFORM_ASYNC, FALSE));
+ CHK_LOG_BRK(m_pGlobalAttributes->SetString(MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft"));
+ CHK_LOG_BRK(m_pGlobalAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE));
+ }
+ *ppAttributes = m_pGlobalAttributes;
+ (*ppAttributes)->AddRef();
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetInputStreamAttributes(
+ DWORD dwInputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFAttributes **ppAttributes)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ if(dwInputStreamID > 0) {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ break;
+ }
+ CHK_NULL_PTR_BRK(ppAttributes);
+ if(!m_pInputAttributes){
+ CHK_LOG_BRK(MFCreateAttributes(&m_pInputAttributes, 2));
+ CHK_LOG_BRK(m_pInputAttributes->SetUINT32(MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE));
+ CHK_LOG_BRK(m_pInputAttributes->SetString(MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft"));
+ }
+ *ppAttributes = m_pInputAttributes;
+ (*ppAttributes)->AddRef();
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetOutputStreamAttributes(
+ DWORD dwOutputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFAttributes **ppAttributes)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ if(dwOutputStreamID > 0) {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ break;
+ }
+ CHK_NULL_PTR_BRK(ppAttributes);
+ CHK_NULL_PTR_BRK(m_pInputAttributes);
+
+ *ppAttributes = m_pInputAttributes;
+ (*ppAttributes)->AddRef();
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::DeleteInputStream(
+ DWORD dwStreamID)
+{
+ HRESULT hr = S_OK;
+ if(dwStreamID > 0) {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ } else {
+ hr = E_NOTIMPL;
+ }
+ return hr;
+}
+
+STDMETHODIMP CMft0::AddInputStreams(
+ DWORD cStreams,
+ /* [in] */ _In_ DWORD *adwStreamIDs)
+{
+ HRESULT hr = S_OK;
+
+ if( !adwStreamIDs || cStreams > 0) {
+ hr = E_INVALIDARG;
+ } else {
+ hr = E_NOTIMPL;
+ }
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetInputAvailableType(
+ DWORD dwInputStreamID,
+ DWORD dwTypeIndex,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType)
+{
+ HRESULT hr = S_OK;
+ IUnknown *pUnk = NULL;
+ IMFAttributes *pSourceAttributes = NULL;
+ UINT32 uiSourceStreamId = 0;
+ wchar_t *pszName;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_BOOL_BRK(IsValidInputStream(dwInputStreamID));
+
+ if(!m_pSourceTransform && m_pInputAttributes) {
+ CHK_LOG_BRK(m_pInputAttributes->GetUnknown(MFT_CONNECTED_STREAM_ATTRIBUTE, IID_PPV_ARGS(&pSourceAttributes)));
+ CHK_LOG_BRK(pSourceAttributes->GetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, IID_PPV_ARGS(&pUnk)));
+ CHK_LOG_BRK(pUnk->QueryInterface(__uuidof(IMFTransform), (void**)&m_pSourceTransform));
+ CHK_LOG_BRK(pSourceAttributes->GetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType));
+ CHK_LOG_BRK(pSourceAttributes->GetUINT32( MF_DEVICESTREAM_STREAM_ID, &uiSourceStreamId));
+
+ if(m_stStreamType == PINNAME_VIDEO_CAPTURE) {
+ wprintf(L"Stream type: PINNAME_VIDEO_CAPTURE\n");
+ } else if(m_stStreamType == PINNAME_VIDEO_PREVIEW) {
+ wprintf(L"Stream type: PINNAME_VIDEO_PREVIEW\n");
+ } else if(m_stStreamType == PINNAME_VIDEO_STILL) {
+ wprintf(L"Stream type: PINNAME_VIDEO_STILL\n");
+ } else if(m_stStreamType == PINNAME_IMAGE) {
+ wprintf(L"Stream type: PINNAME_IMAGE\n");
+ } else {
+ StringFromCLSID(m_stStreamType, &pszName);
+ if(pszName){
+ wprintf(L"Stream type: %s\n", pszName);
+ CoTaskMemFree(pszName);
+ }
+ }
+ CHK_LOG_BRK((m_stStreamType == PINNAME_VIDEO_PREVIEW || m_stStreamType == PINNAME_VIDEO_CAPTURE) ? S_OK : E_UNEXPECTED);
+ CHK_LOG_BRK(GenerateMFMediaTypeListFromDevice(uiSourceStreamId));
+ }
+
+ CHK_LOG_BRK(GetMediaType(dwInputStreamID, dwTypeIndex, ppType));
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ SAFERELEASE(pUnk);
+ SAFERELEASE(pSourceAttributes);
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetOutputAvailableType(
+ DWORD dwOutputStreamID,
+ DWORD dwTypeIndex,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType)
+{
+ HRESULT hr = S_OK;
+ IUnknown *pUnk = NULL;
+ IMFAttributes *pSourceAttributes = NULL;
+ UINT32 uiSourceStreamId = 0;
+ wchar_t *pszName;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_BOOL_BRK(IsValidOutputStream(dwOutputStreamID));
+ if(!m_pSourceTransform && m_pInputAttributes) {
+ CHK_LOG_BRK(m_pInputAttributes->GetUnknown(MFT_CONNECTED_STREAM_ATTRIBUTE, IID_PPV_ARGS(&pSourceAttributes)));
+ CHK_LOG_BRK(pSourceAttributes->GetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT, IID_PPV_ARGS(&pUnk)));
+ CHK_LOG_BRK(pUnk->QueryInterface(__uuidof(IMFTransform), (void**)&m_pSourceTransform));
+ CHK_LOG_BRK(pSourceAttributes->GetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType));
+ CHK_LOG_BRK(pSourceAttributes->GetUINT32( MF_DEVICESTREAM_STREAM_ID, &uiSourceStreamId));
+ if(m_stStreamType == PINNAME_VIDEO_CAPTURE) {
+ wprintf(L"Stream type: PINNAME_VIDEO_CAPTURE\n");
+ } else if(m_stStreamType == PINNAME_VIDEO_PREVIEW) {
+ wprintf(L"Stream type: PINNAME_VIDEO_PREVIEW\n");
+ } else if(m_stStreamType == PINNAME_VIDEO_STILL) {
+ wprintf(L"Stream type: PINNAME_VIDEO_STILL\n");
+ } else if(m_stStreamType == PINNAME_IMAGE) {
+ wprintf(L"Stream type: PINNAME_IMAGE\n");
+ } else {
+ StringFromCLSID(m_stStreamType, &pszName);
+ wprintf(L"Stream type: %s\n", pszName);
+ }
+ CHK_LOG_BRK((m_stStreamType == PINNAME_VIDEO_PREVIEW || m_stStreamType == PINNAME_VIDEO_CAPTURE) ? S_OK : E_UNEXPECTED);
+ CHK_LOG_BRK(GenerateMFMediaTypeListFromDevice(uiSourceStreamId));
+ }
+
+ CHK_LOG_BRK(GetMediaType(dwOutputStreamID, dwTypeIndex, ppType));
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ SAFERELEASE(pUnk);
+ SAFERELEASE(pSourceAttributes);
+ return hr;
+}
+
+STDMETHODIMP CMft0::SetInputType(
+ DWORD dwInputStreamID,
+ /* [in] */ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ BOOL bReallySet = ((dwFlags & MFT_SET_TYPE_TEST_ONLY) == 0);
+ // Validate flags.
+ do {
+ if(bReallySet) {
+ CComPtr<IMFMediaType> pFullType;
+ CHK_LOG_BRK(IsMediaTypeSupported(dwInputStreamID, pType, &pFullType));
+ SAFERELEASE(m_pInputType);
+ SAFERELEASE(m_pOutputType);
+ m_pOutputType = pFullType;
+ m_pOutputType->AddRef();
+ m_pInputType = pFullType;
+ m_pInputType->AddRef();
+ } else {
+ CHK_LOG_BRK(IsMediaTypeSupported(dwInputStreamID, pType));
+ }
+ } while(FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::SetOutputType(
+ DWORD dwOutputStreamID,
+ /* [in] */ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ CHK_LOG_BRK(SetInputType(dwOutputStreamID, pType, dwFlags));
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetInputCurrentType(
+ DWORD dwInputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_NULL_BRK(ppType);
+
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ CHK_LOG_BRK(MF_E_INVALIDSTREAMNUMBER);
+ }
+ else if(m_pInputType)
+ {
+ *ppType = m_pInputType;
+ (*ppType)->AddRef();
+ }
+ else
+ {
+ CHK_LOG_BRK(MF_E_TRANSFORM_TYPE_NOT_SET);
+ }
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetOutputCurrentType(
+ DWORD dwOutputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_NULL_BRK(ppType);
+
+ if (!IsValidOutputStream(dwOutputStreamID))
+ {
+ CHK_LOG_BRK(MF_E_INVALIDSTREAMNUMBER);
+ }
+ else if(m_pOutputType)
+ {
+ *ppType = m_pOutputType;
+ (*ppType)->AddRef();
+ }
+ else
+ {
+ CHK_LOG_BRK(MF_E_TRANSFORM_TYPE_NOT_SET);
+ }
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetInputStatus(
+ DWORD dwInputStreamID,
+ /* [out] */ _Out_ DWORD *pdwFlags)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_BOOL_BRK(pdwFlags);
+
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ CHK_LOG_BRK(MF_E_INVALIDSTREAMNUMBER);
+ }
+
+ // If we already have an input sample, we don't accept
+ // another one until the client calls ProcessOutput or Flush.
+ if (m_pSample == NULL)
+ {
+ *pdwFlags = MFT_INPUT_STATUS_ACCEPT_DATA;
+ }
+ else
+ {
+ *pdwFlags = 0;
+ }
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetOutputStatus(
+ /* [out] */ _Out_ DWORD *pdwFlags)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_NULL_BRK(pdwFlags);
+ // We can produce an output sample if (and only if)
+ // we have an input sample.
+ if (m_pSample != NULL)
+ {
+ *pdwFlags = MFT_OUTPUT_STATUS_SAMPLE_READY;
+ }
+ else
+ {
+ *pdwFlags = 0;
+ }
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::SetOutputBounds(
+ LONGLONG hnsLowerBound,
+ LONGLONG hnsUpperBound)
+{
+ UNREFERENCED_PARAMETER(hnsLowerBound);
+ UNREFERENCED_PARAMETER(hnsUpperBound);
+ return S_OK;
+}
+
+STDMETHODIMP CMft0::ProcessEvent(
+ DWORD dwInputStreamID,
+ /* [in] */ _In_opt_ IMFMediaEvent *pEvent)
+{
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(pEvent);
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CMft0::ProcessMessage(
+ MFT_MESSAGE_TYPE eMessage,
+ ULONG_PTR ulParam)
+{
+ UNREFERENCED_PARAMETER(ulParam);
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ switch (eMessage)
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ // Flush the MFT.
+ hr = OnFlush();
+ break;
+
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ // Drain: Tells the MFT not to accept any more input until
+ // all of the pending output has been processed. That is our
+ // default behevior already, so there is nothing to do.
+ break;
+
+ case MFT_MESSAGE_SET_D3D_MANAGER:
+ // The pipeline should never send this message unless the MFT
+ // has the MF_SA_D3D_AWARE attribute set to TRUE. However, if we
+ // do get this message, it's invalid and we don't implement it.
+ hr = E_NOTIMPL;
+ break;
+
+ // The remaining messages do not require any action from this MFT.
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ case MFT_MESSAGE_NOTIFY_END_STREAMING:
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ break;
+ }
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::ProcessInput(
+ DWORD dwInputStreamID,
+ IMFSample *pSample,
+ DWORD dwFlags)
+{
+ HRESULT hr = S_OK;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_NULL_BRK(pSample);
+
+ CHK_BOOL_BRK(dwFlags == 0)
+
+ DWORD dwBufferCount = 0;
+
+ if (!IsValidInputStream(dwInputStreamID))
+ {
+ CHK_LOG_BRK(hr = MF_E_INVALIDSTREAMNUMBER);
+ }
+
+ if (!m_pInputType || !m_pOutputType)
+ {
+ CHK_LOG_BRK(MF_E_NOTACCEPTING); // Client must set input and output types.
+ }
+
+ if (m_pSample != NULL)
+ {
+ CHK_LOG_BRK(MF_E_NOTACCEPTING); // We already have an input sample.
+ }
+
+ // Validate the number of buffers. There should only be a single buffer to hold the video frame.
+ CHK_LOG_BRK(pSample->GetBufferCount(&dwBufferCount));
+
+ if (dwBufferCount == 0)
+ {
+ CHK_LOG_BRK(E_FAIL);
+ }
+ if (dwBufferCount > 1)
+ {
+ CHK_LOG_BRK(MF_E_SAMPLE_HAS_TOO_MANY_BUFFERS);
+ }
+
+ // Cache the sample. We do the actual work in ProcessOutput.
+ m_pSample = pSample;
+ pSample->AddRef(); // Hold a reference count on the sample.
+ } while (FALSE);
+
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+STDMETHODIMP CMft0::ProcessOutput(
+ DWORD dwFlags,
+ DWORD cOutputBufferCount,
+ /* [size_is][out][in] */ MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ /* [out] */ DWORD *pdwStatus)
+{
+ HRESULT hr = S_OK;
+
+ IMFMediaBuffer *pMediaBufInput = NULL,
+ *pMediaBufOutput = NULL;
+ IMFSample *pOutputIMFSample = NULL;
+ LONGLONG hnsDuration = 0,
+ hnsTime = 0;
+
+ EnterCriticalSection(&m_critSec);
+
+ do {
+ CHK_BOOL_BRK(dwFlags == 0);
+ CHK_NULL_BRK(pOutputSamples);
+ CHK_NULL_BRK(pdwStatus);
+
+ // Must be exactly one output buffer.
+ CHK_BOOL_BRK(cOutputBufferCount == 1);
+
+ // If we don't have an input sample, we need some input before
+ // we can generate any output.
+ if (m_pSample == NULL)
+ {
+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT;
+ break;
+ }
+
+ CHK_LOG_BRK(m_pSample->ConvertToContiguousBuffer(&pMediaBufInput));
+
+ MFCreateSample(&pOutputIMFSample);
+
+ if(!pOutputSamples[0].pSample){
+ CHK_LOG_BRK(m_pSample->ConvertToContiguousBuffer(&pMediaBufOutput));
+
+ } else {
+ CHK_LOG_BRK(pOutputSamples[0].pSample->ConvertToContiguousBuffer(&pMediaBufOutput));
+ }
+
+ pOutputIMFSample->AddBuffer(pMediaBufOutput);
+
+ CHK_LOG_BRK(OnProcessOutput(pMediaBufInput, pMediaBufOutput));
+ pOutputSamples[0].pSample = pOutputIMFSample;
+ pOutputIMFSample->AddRef();
+
+ pOutputSamples[0].dwStatus = 0;
+ *pdwStatus = 0;
+ if (SUCCEEDED(m_pSample->GetSampleDuration(&hnsDuration)))
+ {
+ CHK_LOG_BRK(pOutputSamples[0].pSample->SetSampleDuration(hnsDuration));
+ }
+
+ if (SUCCEEDED(m_pSample->GetSampleTime(&hnsTime)))
+ {
+ CHK_LOG_BRK(pOutputSamples[0].pSample->SetSampleTime(hnsTime));
+ }
+ } while (FALSE);
+
+ SAFERELEASE(pOutputIMFSample);
+ SAFERELEASE(pMediaBufInput);
+ SAFERELEASE(pMediaBufOutput);
+ SAFERELEASE(m_pSample); // Release our input sample.
+ LeaveCriticalSection(&m_critSec);
+ return hr;
+}
+
+BOOL CMft0::IsValidInputStream(DWORD dwInputStreamID)
+{
+ return dwInputStreamID == 0;
+}
+
+// IsValidOutputStream: Returns TRUE if dwOutputStreamID is a valid output stream identifier.
+BOOL CMft0::IsValidOutputStream(DWORD dwOutputStreamID)
+{
+ //update
+ return dwOutputStreamID == 0;
+}
+
+
+STDMETHODIMP CMft0::OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut)
+{
+ HRESULT hr = S_OK;
+ LONG lDefaultStride = 0,
+ lSrcStride = 0,
+ lDestStride = 0;
+ UINT uiWidth = 0,
+ uiHeight = 0;
+ BYTE *pDest = NULL,
+ *pSrc = NULL;
+ //BOOL bCompressed = TRUE;
+ GUID stSubType = {0};
+
+ do {
+ CHK_NULL_PTR_BRK(m_pSample);
+ CHK_NULL_PTR_BRK(m_pInputType);
+
+ CHK_LOG_BRK(m_pInputType->GetGUID(MF_MT_SUBTYPE, &stSubType));
+
+ if(((stSubType == MFVideoFormat_RGB8) || (stSubType == MFVideoFormat_RGB555) ||
+ (stSubType == MFVideoFormat_RGB565) || (stSubType == MFVideoFormat_RGB24) ||
+ (stSubType == MFVideoFormat_RGB32) || (stSubType == MFVideoFormat_ARGB32) ||
+ (stSubType == MFVideoFormat_AI44) || (stSubType == MFVideoFormat_AYUV) ||
+ (stSubType == MFVideoFormat_I420) || (stSubType == MFVideoFormat_IYUV) ||
+ (stSubType == MFVideoFormat_NV11) || (stSubType == MFVideoFormat_NV12) ||
+ (stSubType == MFVideoFormat_UYVY) || (stSubType == MFVideoFormat_Y41P) ||
+ (stSubType == MFVideoFormat_Y41T) || (stSubType == MFVideoFormat_Y42T) ||
+ (stSubType == MFVideoFormat_YUY2) || (stSubType == MFVideoFormat_YV12) ||
+ (stSubType == MFVideoFormat_P010) || (stSubType == MFVideoFormat_P016) ||
+ (stSubType == MFVideoFormat_P210) || (stSubType == MFVideoFormat_P216) ||
+ (stSubType == MFVideoFormat_v210) || (stSubType == MFVideoFormat_v216) ||
+ (stSubType == MFVideoFormat_v410) || (stSubType == MFVideoFormat_Y210) ||
+ (stSubType == MFVideoFormat_Y216) || (stSubType == MFVideoFormat_Y410) ||
+ (stSubType == MFVideoFormat_Y416)) && m_bEnableEffects)
+ {
+ CHK_LOG_BRK(GetDefaultStride(&lDefaultStride));
+ CHK_LOG_BRK(MFGetAttributeSize(m_pInputType, MF_MT_FRAME_SIZE, &uiWidth, &uiHeight));
+ VideoBufferLock inputLock(pIn);
+ VideoBufferLock outputLock(pOut);
+
+ // Lock the input buffer.
+ CHK_LOG_BRK(inputLock.LockBuffer(lDefaultStride, uiHeight, &pSrc, &lSrcStride));
+
+ // Lock the output buffer.
+ CHK_LOG_BRK(outputLock.LockBuffer(lDefaultStride, uiHeight, &pDest, &lDestStride));
+ long lines = uiHeight;
+ if(m_percentOfScreen != -1 && m_percentOfScreen != 0) {
+ lines = (UINT)(uiHeight * (1.0- m_percentOfScreen/100.00));
+ }
+ for(long i = 0; i < (long)uiHeight; i++) {
+ if(lDestStride < 0) {
+ if(i >= lines) {
+ memset(pDest+i*lDestStride, 0, abs(lDefaultStride));
+ } else {
+ memcpy(pDest+i*lDestStride, pSrc+i*lDefaultStride, abs(lDefaultStride));
+ }
+ } else {
+ if(i >= lines) {
+ memset(pDest+i*lDestStride, 0, lDestStride);
+ } else {
+ memcpy(pDest+i*lDestStride, pSrc+i*lDestStride, lDestStride);
+ }
+ }
+ }
+ }
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetDefaultStride(LONG *plStride)
+{
+ LONG lStride = 0;
+
+ // Try to get the default stride from the media type.
+ HRESULT hr = m_pInputType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
+ if (FAILED(hr))
+ {
+ // Attribute not set. Try to calculate the default stride.
+ GUID subtype = GUID_NULL;
+ UINT32 width = 0;
+ UINT32 height = 0;
+
+ // Get the subtype and the image size.
+ hr = m_pInputType->GetGUID(MF_MT_SUBTYPE, &subtype);
+ if (SUCCEEDED(hr))
+ {
+ hr = MFGetAttributeSize(m_pInputType, MF_MT_FRAME_SIZE, &width, &height);
+ }
+ if (SUCCEEDED(hr))
+ {
+ hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride);
+ }
+
+ // Set the attribute for later reference.
+ if (SUCCEEDED(hr))
+ {
+ (void)m_pInputType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride));
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ *plStride = lStride;
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::OnFlush()
+{
+ HRESULT hr = S_OK;
+
+ // For this MFT, flushing just means releasing the input sample.
+ SAFERELEASE(m_pSample);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GetMediaType( DWORD dwStreamId, DWORD dwTypeIndex, IMFMediaType **ppType)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ CHK_NULL_PTR_BRK(ppType);
+ if(dwStreamId != 0)
+ CHK_LOG_BRK(MF_E_INVALIDSTREAMNUMBER);
+ if(dwTypeIndex >= m_listOfMediaTypes.GetCount())
+ CHK_LOG_BRK(MF_E_NO_MORE_TYPES);
+
+ *ppType = m_listOfMediaTypes[dwTypeIndex];
+ (*ppType)->AddRef();
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::IsMediaTypeSupported(UINT uiStreamId, IMFMediaType *pIMFMediaType, IMFMediaType **ppIMFMediaTypeFull)
+{
+ HRESULT hr = S_OK;
+
+ do {
+ CHK_NULL_PTR_BRK(pIMFMediaType);
+
+ if(uiStreamId != 0)
+ {
+ CHK_LOG_BRK(MF_E_INVALIDINDEX);
+ }
+ BOOL bFound =FALSE;
+ for(UINT i = 0; i< m_listOfMediaTypes.GetCount(); i++)
+ {
+ DWORD dwResult = 0;
+ hr = m_listOfMediaTypes[i]->IsEqual(pIMFMediaType, &dwResult);
+ if(hr == S_FALSE)
+ {
+
+ if((dwResult & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_DATA))
+ {
+ hr = S_OK;
+ }
+ }
+ if(hr == S_OK)
+ {
+ bFound = TRUE;
+ if(ppIMFMediaTypeFull) {
+ *ppIMFMediaTypeFull = m_listOfMediaTypes[i];
+ (*ppIMFMediaTypeFull)->AddRef();
+ }
+ break;
+ }
+ else if(FAILED(hr))
+ {
+ CHK_LOG_BRK(hr);
+ }
+
+ }
+ if(bFound == FALSE)
+ {
+ CHK_LOG_BRK(MF_E_INVALIDMEDIATYPE);
+ }
+ } while (FALSE);
+
+ return hr;
+}
+
+STDMETHODIMP CMft0::GenerateMFMediaTypeListFromDevice(UINT uiStreamId)
+{
+ HRESULT hr = S_OK;
+ GUID stSubType = {0};
+
+ do {
+ CHK_NULL_PTR_BRK(m_pSourceTransform);
+
+ m_listOfMediaTypes.RemoveAll();
+ for(UINT iMediaType = 0; TRUE; iMediaType++)
+ {
+ CComPtr<IMFMediaType> pMediaType;
+ hr = m_pSourceTransform->GetOutputAvailableType(uiStreamId, iMediaType, &pMediaType);
+ if(hr != S_OK)
+ break;
+ CHK_LOG_BRK(pMediaType->GetGUID(MF_MT_SUBTYPE, &stSubType));
+
+ if(((stSubType == MFVideoFormat_RGB8) || (stSubType == MFVideoFormat_RGB555) ||
+ (stSubType == MFVideoFormat_RGB565) || (stSubType == MFVideoFormat_RGB24) ||
+ (stSubType == MFVideoFormat_RGB32) || (stSubType == MFVideoFormat_ARGB32) ||
+ (stSubType == MFVideoFormat_AI44) || (stSubType == MFVideoFormat_AYUV) ||
+ (stSubType == MFVideoFormat_I420) || (stSubType == MFVideoFormat_IYUV) ||
+ (stSubType == MFVideoFormat_NV11) || (stSubType == MFVideoFormat_NV12) ||
+ (stSubType == MFVideoFormat_UYVY) || (stSubType == MFVideoFormat_Y41P) ||
+ (stSubType == MFVideoFormat_Y41T) || (stSubType == MFVideoFormat_Y42T) ||
+ (stSubType == MFVideoFormat_YUY2) || (stSubType == MFVideoFormat_YV12) ||
+ (stSubType == MFVideoFormat_P010) || (stSubType == MFVideoFormat_P016) ||
+ (stSubType == MFVideoFormat_P210) || (stSubType == MFVideoFormat_P216) ||
+ (stSubType == MFVideoFormat_v210) || (stSubType == MFVideoFormat_v216) ||
+ (stSubType == MFVideoFormat_v410) || (stSubType == MFVideoFormat_Y210) ||
+ (stSubType == MFVideoFormat_Y216) || (stSubType == MFVideoFormat_Y410) ||
+ (stSubType == MFVideoFormat_Y416)) && m_bEnableEffects)
+ {
+ m_listOfMediaTypes[(ULONG)(m_listOfMediaTypes.GetCount())] = pMediaType;
+ }
+ }
+
+ } while (FALSE);
+
+ if(hr == MF_E_NO_MORE_TYPES) {
+ hr = S_OK;
+ }
+
+ return hr;
+} \ No newline at end of file
diff --git a/AVStream/samplemft0/Mft0.h b/AVStream/samplemft0/Mft0.h
new file mode 100644
index 00000000..0cc85733
--- /dev/null
+++ b/AVStream/samplemft0/Mft0.h
@@ -0,0 +1,224 @@
+// Mft0.h : Declaration of the CMft0
+
+#pragma once
+#include "resource.h" // main symbols
+#include "SampleMft0.h"
+#include "SampleHelpers.h"
+
+#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
+#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
+#endif
+
+using namespace ATL;
+
+// CMft0
+
+class ATL_NO_VTABLE CMft0 :
+ public CComObjectRootEx<CComMultiThreadModel>,
+ public CComCoClass<CMft0, &CLSID_Mft0>,
+ public IMft0,
+ public IMFTransform,
+ public IInspectable
+{
+public:
+ CMft0() : m_pSample(NULL),
+ m_pInputType(NULL),
+ m_pOutputType(NULL),
+ m_pInputAttributes(0),
+ m_pGlobalAttributes(0),
+ m_pSourceTransform(0),
+ m_bEnableEffects(TRUE),
+ m_uiStreamId(0),
+ m_percentOfScreen(50),
+ m_nRefCount(1)
+ {
+ InitializeCriticalSection(&m_critSec);
+ }
+
+ DECLARE_REGISTRY_RESOURCEID(IDR_MFT0)
+
+ DECLARE_NOT_AGGREGATABLE(CMft0)
+
+ BEGIN_COM_MAP(CMft0)
+ COM_INTERFACE_ENTRY(IMft0)
+ COM_INTERFACE_ENTRY(IMFTransform)
+ COM_INTERFACE_ENTRY(IInspectable)
+ END_COM_MAP()
+
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ HRESULT FinalConstruct()
+ {
+ return S_OK;
+ }
+
+ void FinalRelease()
+ {
+ }
+
+public:
+ STDMETHOD(UpdateDsp)(UINT32 uiPercentOfScreen);
+ STDMETHOD(Enable)(void);
+ STDMETHOD(Disable)(void);
+ STDMETHOD(GetDspSetting)(UINT* puiPercentOfScreen, BOOL* pIsEnabled);
+
+ STDMETHODIMP GetIids(
+ /* [out] */ _Out_ ULONG *iidCount,
+ /* [size_is][size_is][out] */ _Outptr_result_buffer_maybenull_(*iidCount) IID **iids);
+
+ STDMETHODIMP GetRuntimeClassName(
+ /* [out] */ _Outptr_result_maybenull_ HSTRING *className);
+
+ STDMETHODIMP GetTrustLevel(
+ /* [out] */ _Out_ TrustLevel *trustLevel);
+
+ STDMETHODIMP GetStreamLimits(
+ /* [out] */ _Out_ DWORD *pdwInputMinimum,
+ /* [out] */ _Out_ DWORD *pdwInputMaximum,
+ /* [out] */ _Out_ DWORD *pdwOutputMinimum,
+ /* [out] */ _Out_ DWORD *pdwOutputMaximum);
+
+ STDMETHODIMP GetStreamCount(
+ /* [out] */ _Out_ DWORD *pcInputStreams,
+ /* [out] */ _Out_ DWORD *pcOutputStreams);
+
+ STDMETHODIMP GetStreamIDs(
+ DWORD dwInputIDArraySize,
+ /* [size_is][out] */ _Out_writes_(dwInputIDArraySize) DWORD *pdwInputIDs,
+ DWORD dwOutputIDArraySize,
+ /* [size_is][out] */ _Out_writes_(dwOutputIDArraySize) DWORD *pdwOutputIDs);
+
+ STDMETHODIMP GetInputStreamInfo(
+ DWORD dwInputStreamID,
+ /* [out] */ _Out_ MFT_INPUT_STREAM_INFO *pStreamInfo);
+
+ STDMETHODIMP GetOutputStreamInfo(
+ DWORD dwOutputStreamID,
+ /* [out] */ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo);
+
+ STDMETHODIMP GetAttributes(
+ /* [out] */ _Outptr_result_maybenull_ IMFAttributes **pAttributes);
+
+ STDMETHODIMP GetInputStreamAttributes(
+ DWORD dwInputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFAttributes **pAttributes);
+
+ STDMETHODIMP GetOutputStreamAttributes(
+ DWORD dwOutputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFAttributes **pAttributes);
+
+ STDMETHODIMP DeleteInputStream(
+ DWORD dwStreamID);
+
+ STDMETHODIMP AddInputStreams(
+ DWORD cStreams,
+ /* [in] */ _In_ DWORD *adwStreamIDs);
+
+ STDMETHODIMP GetInputAvailableType(
+ DWORD dwInputStreamID,
+ DWORD dwTypeIndex,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType);
+
+ STDMETHODIMP GetOutputAvailableType(
+ DWORD dwOutputStreamID,
+ DWORD dwTypeIndex,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType);
+
+ STDMETHODIMP SetInputType(
+ DWORD dwInputStreamID,
+ /* [in] */ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags);
+
+ STDMETHODIMP SetOutputType(
+ DWORD dwOutputStreamID,
+ /* [in] */ _In_opt_ IMFMediaType *pType,
+ DWORD dwFlags);
+
+ STDMETHODIMP GetInputCurrentType(
+ DWORD dwInputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType);
+
+ STDMETHODIMP GetOutputCurrentType(
+ DWORD dwOutputStreamID,
+ /* [out] */ _Outptr_result_maybenull_ IMFMediaType **ppType);
+
+ STDMETHODIMP GetInputStatus(
+ DWORD dwInputStreamID,
+ /* [out] */ _Out_ DWORD *pdwFlags);
+
+ STDMETHODIMP GetOutputStatus(
+ /* [out] */ _Out_ DWORD *pdwFlags);
+
+ STDMETHODIMP SetOutputBounds(
+ LONGLONG hnsLowerBound,
+ LONGLONG hnsUpperBound);
+
+ STDMETHODIMP ProcessEvent(
+ DWORD dwInputStreamID,
+ /* [in] */ _In_opt_ IMFMediaEvent *pEvent);
+
+ STDMETHODIMP ProcessMessage(
+ MFT_MESSAGE_TYPE eMessage,
+ ULONG_PTR ulParam);
+
+ STDMETHODIMP ProcessInput(
+ DWORD dwInputStreamID,
+ IMFSample *pSample,
+ DWORD dwFlags);
+
+ STDMETHODIMP ProcessOutput(
+ DWORD dwFlags,
+ DWORD cOutputBufferCount,
+ /* [size_is][out][in] */ MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ /* [out] */ DWORD *pdwStatus);
+
+protected:
+ virtual ~CMft0()
+ {
+ SAFERELEASE(m_pInputAttributes);
+ SAFERELEASE(m_pGlobalAttributes);
+ SAFERELEASE(m_pSourceTransform);
+ SAFERELEASE(m_pInputType);
+ SAFERELEASE(m_pOutputType);
+ SAFERELEASE(m_pSample);
+ DeleteCriticalSection(&m_critSec);
+ }
+
+ STDMETHODIMP GetMediaType(DWORD dwStreamID, DWORD dwTypeIndex, IMFMediaType **ppType);
+ STDMETHODIMP IsMediaTypeSupported(UINT uiStreamId, IMFMediaType *pIMFMediaType, IMFMediaType **ppIMFMediaTypeFull = NULL);
+ STDMETHODIMP GenerateMFMediaTypeListFromDevice(UINT uiStreamId);
+
+ // HasPendingOutput: Returns TRUE if the MFT is holding an input sample.
+ BOOL HasPendingOutput() const { return m_pSample != NULL; }
+
+ // IsValidInputStream: Returns TRUE if dwInputStreamID is a valid input stream identifier.
+ BOOL IsValidInputStream(DWORD dwInputStreamID);
+
+ // IsValidOutputStream: Returns TRUE if dwOutputStreamID is a valid output stream identifier.
+ BOOL IsValidOutputStream(DWORD dwOutputStreamID);
+
+ STDMETHODIMP GetDefaultStride(LONG *plStride);
+
+ STDMETHODIMP OnProcessOutput(IMFMediaBuffer *pIn, IMFMediaBuffer *pOut);
+
+ STDMETHODIMP OnFlush();
+
+ CRITICAL_SECTION m_critSec;
+
+ IMFSample *m_pSample; // Input sample.
+ IMFMediaType *m_pInputType; // Input media type.
+ IMFMediaType *m_pOutputType; // Output media type.
+
+ // Image transform function. (Changes based on the media type.)
+ IMFAttributes *m_pInputAttributes;
+ IMFAttributes *m_pGlobalAttributes;
+ GUID m_stStreamType;
+ IMFTransform *m_pSourceTransform;
+ volatile BOOL m_bEnableEffects;
+ UINT m_uiStreamId;
+ UINT m_percentOfScreen;
+ UINT m_nRefCount;
+ CAtlMap<DWORD, CComPtr<IMFMediaType>> m_listOfMediaTypes;
+};
+
+OBJECT_ENTRY_AUTO(__uuidof(Mft0), CMft0)
diff --git a/AVStream/samplemft0/Mft0.rgs b/AVStream/samplemft0/Mft0.rgs
new file mode 100644
index 00000000..9ff876f4
--- /dev/null
+++ b/AVStream/samplemft0/Mft0.rgs
@@ -0,0 +1,15 @@
+HKCR
+{
+ NoRemove CLSID
+ {
+ ForceRemove {7BB640D9-33A4-4759-B290-F41A31DCF848} = s 'Mft0 Class'
+ {
+ InprocServer32 = s '%MODULE%'
+ {
+ val ThreadingModel = s 'Both'
+ }
+ TypeLib = s '{DE05674A-C564-4C0E-9B7C-E1519F7AA767}'
+ Version = s '1.0'
+ }
+ }
+}
diff --git a/AVStream/samplemft0/README.md b/AVStream/samplemft0/README.md
new file mode 100644
index 00000000..7f6e50f6
--- /dev/null
+++ b/AVStream/samplemft0/README.md
@@ -0,0 +1,28 @@
+Driver MFT Sample
+=================
+
+Provides a *driver MFT* for use with a camera's Windows Store device app.A *driver MFT* is a Media Foundation Transform that's used with a specific camera when capturing video. The driver MFT is also known as MFT0 because it is the first MFT applied to the video stream captured from the camera. This MFT can provide a video effect or other processing when capturing photos or video from the camera. It can be distributed along with the driver package for a camera.
+
+In this sample, the driver MFT, when enabled, replaces a portion of the captured video with a green box. To test this sample, download the [Windows Store device app for camera sample](http://go.microsoft.com/fwlink/p/?linkid=249442) and the [Camera Capture UI sample](http://go.microsoft.com/fwlink/p/?linkid=249441). The [Windows Store device app for camera sample](http://go.microsoft.com/fwlink/p/?linkid=249442) provides a *Windows Store device app* that controls the effect implemented by the driver MFT. The [Camera Capture UI sample](http://go.microsoft.com/fwlink/p/?linkid=249441) provides a way to invoke the *Windows Store device app*.
+
+This sample is designed to be used with a specific camera. To run the sample, you need the your camera's device ID and device metadata package.
+
+
+Related topics
+--------------
+
+**Concepts**
+
+[Windows Store device apps for cameras](http://go.microsoft.com/fwlink/p/?LinkId=306683)
+
+[Media Foundation Transforms](http://msdn.microsoft.com/en-us/library/windows/hardware/ms703138)
+
+[Roadmap for Developing Streaming Media Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff568130)
+
+[Universal camera driver design guide for Windows 10](https://msdn.microsoft.com/en-us/Library/Windows/Hardware/dn937080)
+
+**Samples**
+
+[Windows Store device app for camera sample](http://go.microsoft.com/fwlink/p/?linkid=249442)
+
+[Camera Capture UI sample](http://go.microsoft.com/fwlink/p/?linkid=249441%20)
diff --git a/AVStream/samplemft0/SampleHelpers.h b/AVStream/samplemft0/SampleHelpers.h
new file mode 100644
index 00000000..870e2cd3
--- /dev/null
+++ b/AVStream/samplemft0/SampleHelpers.h
@@ -0,0 +1,143 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+
+#pragma once
+#include "stdafx.h"
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+#define __WFILE__ WIDEN(__FILE__)
+
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(WPPCameraExtensionMFt_Sample, \
+ (31A88041,BBF0,4D2C,A752,16EB1E51859C), \
+ WPP_DEFINE_BIT(AllMessages) \
+ )
+
+#define SAFEFREE(x) \
+ if(x) { \
+ free(x); \
+ x = NULL; \
+ }
+#define SAFERELEASE(x) \
+ if(x) { \
+ x->Release(); \
+ x = NULL; \
+ }
+
+#define CHK_LOG_BRK(exp) \
+ if(FAILED(hr = (exp))) { \
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ break; \
+ }
+
+#define CHK_NULL_BRK(exp) \
+ if((exp) == NULL) { \
+ hr = E_OUTOFMEMORY; \
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ break; \
+ }
+#define CHK_NULL_PTR_BRK(exp) \
+ if((exp) == NULL) { \
+ hr = E_INVALIDARG; \
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ break; \
+ }
+
+#define CHK_BOOL_BRK(exp) \
+ if(!exp) { \
+ hr = E_FAIL; \
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ break; \
+ }
+
+
+class VideoBufferLock
+{
+public:
+ VideoBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL)
+ {
+ m_pBuffer = pBuffer;
+ m_pBuffer->AddRef();
+
+ // Query for the 2-D buffer interface. OK if this fails.
+ m_pBuffer->QueryInterface(IID_IMF2DBuffer, (void**)&m_p2DBuffer);
+ }
+
+ ~VideoBufferLock()
+ {
+ UnlockBuffer();
+ SAFERELEASE(m_pBuffer);
+ SAFERELEASE(m_p2DBuffer);
+ }
+
+ // LockBuffer:
+ // Locks the buffer. Returns a pointer to scan line 0 and returns the stride.
+
+ // The caller must provide the default stride as an input parameter, in case
+ // the buffer does not expose IMF2DBuffer. You can calculate the default stride
+ // from the media type.
+
+ HRESULT LockBuffer(
+ LONG lDefaultStride, // Minimum stride (with no padding).
+ DWORD dwHeightInPixels, // Height of the image, in pixels.
+ BYTE **ppbScanLine0, // Receives a pointer to the start of scan line 0.
+ LONG *plStride // Receives the actual stride.
+ )
+ {
+ HRESULT hr = S_OK;
+
+ // Use the 2-D version if available.
+ if (m_p2DBuffer)
+ {
+ hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride);
+ }
+ else
+ {
+ // Use non-2D version.
+ BYTE *pData = NULL;
+
+ hr = m_pBuffer->Lock(&pData, NULL, NULL);
+ if (SUCCEEDED(hr))
+ {
+ *plStride = lDefaultStride;
+ if (lDefaultStride < 0)
+ {
+ // Bottom-up orientation. Return a pointer to the start of the
+ // last row *in memory* which is the top row of the image.
+ *ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1);
+ }
+ else
+ {
+ // Top-down orientation. Return a pointer to the start of the
+ // buffer.
+ *ppbScanLine0 = pData;
+ }
+ }
+ }
+ return hr;
+ }
+
+ HRESULT UnlockBuffer()
+ {
+ if (m_p2DBuffer)
+ {
+ return m_p2DBuffer->Unlock2D();
+ }
+ else
+ {
+ return m_pBuffer->Unlock();
+ }
+ }
+
+private:
+ IMFMediaBuffer *m_pBuffer;
+ IMF2DBuffer *m_p2DBuffer;
+};
+
diff --git a/AVStream/samplemft0/SampleMft0.cpp b/AVStream/samplemft0/SampleMft0.cpp
new file mode 100644
index 00000000..997f05af
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.cpp
@@ -0,0 +1,83 @@
+// SampleMft0.cpp : Implementation of DLL Exports.
+
+
+#include "stdafx.h"
+#include "resource.h"
+#include "SampleMft0.h"
+#include "dllmain.h"
+
+
+// Used to determine whether the DLL can be unloaded by OLE.
+STDAPI DllCanUnloadNow(void)
+{
+#ifdef _MERGE_PROXYSTUB
+ HRESULT hr = PrxDllCanUnloadNow();
+ if (hr != S_OK)
+ return hr;
+#endif
+ return _AtlModule.DllCanUnloadNow();
+}
+
+// Returns a class factory to create an object of the requested type.
+STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv)
+{
+#ifdef _MERGE_PROXYSTUB
+ if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
+ return S_OK;
+#endif
+ return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
+}
+
+// DllRegisterServer - Adds entries to the system registry.
+STDAPI DllRegisterServer(void)
+{
+ // registers object, typelib and all interfaces in typelib
+ HRESULT hr = _AtlModule.DllRegisterServer();
+#ifdef _MERGE_PROXYSTUB
+ if (FAILED(hr))
+ return hr;
+ hr = PrxDllRegisterServer();
+#endif
+ return hr;
+}
+
+// DllUnregisterServer - Removes entries from the system registry.
+STDAPI DllUnregisterServer(void)
+{
+ HRESULT hr = _AtlModule.DllUnregisterServer();
+#ifdef _MERGE_PROXYSTUB
+ if (FAILED(hr))
+ return hr;
+ hr = PrxDllRegisterServer();
+ if (FAILED(hr))
+ return hr;
+ hr = PrxDllUnregisterServer();
+#endif
+ return hr;
+}
+
+// DllInstall - Adds/Removes entries to the system registry per user per machine.
+STDAPI DllInstall(BOOL bInstall, _In_opt_ LPCWSTR pszCmdLine)
+{
+ UNREFERENCED_PARAMETER(pszCmdLine);
+ HRESULT hr = E_FAIL;
+ static const wchar_t szUserSwitch[] = L"user";
+
+
+ if (bInstall)
+ {
+ hr = DllRegisterServer();
+ if (FAILED(hr))
+ {
+ DllUnregisterServer();
+ }
+ }
+ else
+ {
+ hr = DllUnregisterServer();
+ }
+
+ return hr;
+}
+
+
diff --git a/AVStream/samplemft0/SampleMft0.def b/AVStream/samplemft0/SampleMft0.def
new file mode 100644
index 00000000..f4c9fe1c
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.def
@@ -0,0 +1,16 @@
+; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+; PARTICULAR PURPOSE.
+; Copyright (c) Microsoft Corporation. All rights reserved
+
+; SampleMft0.def : Declares the module parameters.
+
+LIBRARY
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DllInstall PRIVATE
diff --git a/AVStream/samplemft0/SampleMft0.idl b/AVStream/samplemft0/SampleMft0.idl
new file mode 100644
index 00000000..3b59f79a
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.idl
@@ -0,0 +1,48 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+// SampleMft0.idl : IDL source for SampleMft0
+//
+
+// This file will be processed by the MIDL tool to
+// produce the type library (SampleMft0.tlb) and marshalling code.
+
+import "oaidl.idl";
+import "ocidl.idl";
+import "Inspectable.idl";
+import "mftransform.idl";
+[
+ object,
+ uuid(F5208B72-A37A-457E-A309-AE3060780E21),
+ oleautomation,
+ nonextensible,
+ pointer_default(unique)
+]
+interface IMft0 : IUnknown{
+ [id(1)] HRESULT UpdateDsp([in] UINT32 uiPercentOfScreen);
+ [id(2)] HRESULT Enable(void);
+ [id(3)] HRESULT Disable(void);
+ [id(4)] HRESULT GetDspSetting([out] UINT* puiPercentOfScreen, [out] BOOL* pIsEnabled);
+};
+[
+ uuid(DE05674A-C564-4C0E-9B7C-E1519F7AA767),
+ version(1.0),
+]
+library SampleMft0Lib
+{
+ importlib("stdole2.tlb");
+ [
+ uuid(7BB640D9-33A4-4759-B290-F41A31DCF848)
+ ]
+ coclass Mft0
+ {
+ [default] interface IMft0;
+ interface IInspectable;
+ interface IMFTransform;
+ };
+};
+
diff --git a/AVStream/samplemft0/SampleMft0.rc b/AVStream/samplemft0/SampleMft0.rc
new file mode 100644
index 00000000..60d75128
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.rc
Binary files differ
diff --git a/AVStream/samplemft0/SampleMft0.rgs b/AVStream/samplemft0/SampleMft0.rgs
new file mode 100644
index 00000000..e7d37400
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.rgs
@@ -0,0 +1,3 @@
+HKCR
+{
+}
diff --git a/AVStream/samplemft0/SampleMft0.sln b/AVStream/samplemft0/SampleMft0.sln
new file mode 100644
index 00000000..8084fbc7
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.sln
@@ -0,0 +1,41 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 11
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{D5FD28DE-8407-4B27-8785-9839775E254A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{07664D04-E5E5-4249-8382-4D97E3E5557D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleMft0", "SampleMft0.vcxproj", "{DCF923F6-7164-4A0E-9486-B8A140234CCA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Debug|Win32.Build.0 = Debug|Win32
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Debug|x64.ActiveCfg = Debug|x64
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Debug|x64.Build.0 = Debug|x64
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Release|Win32.ActiveCfg = Release|Win32
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Release|Win32.Build.0 = Release|Win32
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Release|x64.ActiveCfg = Release|x64
+ {07664D04-E5E5-4249-8382-4D97E3E5557D}.Release|x64.Build.0 = Release|x64
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Debug|Win32.Build.0 = Debug|Win32
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Debug|x64.ActiveCfg = Debug|x64
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Debug|x64.Build.0 = Debug|x64
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Release|Win32.ActiveCfg = Release|Win32
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Release|Win32.Build.0 = Release|Win32
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Release|x64.ActiveCfg = Release|x64
+ {DCF923F6-7164-4A0E-9486-B8A140234CCA}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {07664D04-E5E5-4249-8382-4D97E3E5557D} = {D5FD28DE-8407-4B27-8785-9839775E254A}
+ EndGlobalSection
+EndGlobal
diff --git a/AVStream/samplemft0/SampleMft0.vcxproj b/AVStream/samplemft0/SampleMft0.vcxproj
new file mode 100644
index 00000000..90c623ba
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.vcxproj
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="PropertySheets">
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <Configuration>Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <DebuggerFlavor Condition="'$(PlatformToolset)' == 'WindowsKernelModeDriver8.0'">DbgengKernelDebugger</DebuggerFlavor>
+ <DebuggerFlavor Condition="'$(PlatformToolset)' == 'WindowsUserModeDriver8.0'">DbgengRemoteDebugger</DebuggerFlavor>
+ <SampleGuid>{0D23004B-9844-4510-ABA0-E60F720528B8}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DCF923F6-7164-4A0E-9486-B8A140234CCA}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Win8</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Win8</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Win8</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Win8</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ </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>
+ <TargetName>SampleMft0</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <PropertyGroup>
+ <UseOfAtl>Static</UseOfAtl>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(IntDir)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(IntDir)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(IntDir)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);kernel32.lib;gdi32.lib;ntdll.lib;user32.lib;advapi32.lib;ole32.lib;uuid.lib;version.lib;winmm.lib;comdlg32.lib;Oleaut32.lib;Shlwapi.lib;comctl32.lib;mfuuid.lib;mf.lib;mfplat.lib;runtimeobject.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>SampleMft0.def</ModuleDefinitionFile>
+ </Link>
+ <ClCompile>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="$(IntDir)\SampleMft0_i.c" />
+ <ClCompile Include="dllmain.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="Mft0.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="SampleMft0.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <ClCompile Include="stdafxsrc.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ <Midl Include="SampleMft0.idl" />
+ <ResourceCompile Include="SampleMft0.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" />
+ </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/samplemft0/SampleMft0.vcxproj.Filters b/AVStream/samplemft0/SampleMft0.vcxproj.Filters
new file mode 100644
index 00000000..945f6fa5
--- /dev/null
+++ b/AVStream/samplemft0/SampleMft0.vcxproj.Filters
@@ -0,0 +1,99 @@
+<?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>{0EBBD007-C6C8-40FA-9163-D9AE2629FA55}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{63FE7C31-9F1C-4BA9-9D75-64A0A33E2CE7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ <UniqueIdentifier>{18AC824E-5296-4263-BF1C-82692203056E}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="$(IntDir)\SampleMft0_i.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Mft0.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SampleMft0.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdafxsrc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="dllmain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mft0.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SampleHelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="dllmain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mft0.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SampleHelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="dllmain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mft0.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SampleHelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="dllmain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mft0.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SampleHelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="dllmain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mft0.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SampleHelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="dllmain.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Mft0.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="SampleHelpers.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="SampleMft0.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Midl Include="SampleMft0.idl">
+ <Filter>Source Files</Filter>
+ </Midl>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="*.def;*.bat;*.hpj;*.asmx">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/AVStream/samplemft0/dllmain.cpp b/AVStream/samplemft0/dllmain.cpp
new file mode 100644
index 00000000..df86088a
--- /dev/null
+++ b/AVStream/samplemft0/dllmain.cpp
@@ -0,0 +1,19 @@
+// dllmain.cpp : Implementation of DllMain.
+
+#include "stdafx.h"
+#include "resource.h"
+#include "SampleMft0.h"
+#include "dllmain.h"
+
+CSampleMft0Module _AtlModule;
+
+// DLL Entry Point
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+#ifdef _MERGE_PROXYSTUB
+ if (!PrxDllMain(hInstance, dwReason, lpReserved))
+ return FALSE;
+#endif
+ hInstance;
+ return _AtlModule.DllMain(dwReason, lpReserved);
+}
diff --git a/AVStream/samplemft0/dllmain.h b/AVStream/samplemft0/dllmain.h
new file mode 100644
index 00000000..04e95ab3
--- /dev/null
+++ b/AVStream/samplemft0/dllmain.h
@@ -0,0 +1,10 @@
+// dllmain.h : Declaration of module class.
+
+class CSampleMft0Module : public ATL::CAtlDllModuleT< CSampleMft0Module >
+{
+public :
+ DECLARE_LIBID(LIBID_SampleMft0Lib)
+ DECLARE_REGISTRY_APPID_RESOURCEID(IDR_SAMPLEMFT0, "{F9ED475B-DC47-458A-A138-55D7E8A57AF0}")
+};
+
+extern class CSampleMft0Module _AtlModule;
diff --git a/AVStream/samplemft0/resource.h b/AVStream/samplemft0/resource.h
new file mode 100644
index 00000000..d20cf5a1
--- /dev/null
+++ b/AVStream/samplemft0/resource.h
Binary files differ
diff --git a/AVStream/samplemft0/stdafx.cpp b/AVStream/samplemft0/stdafx.cpp
new file mode 100644
index 00000000..feacb859
--- /dev/null
+++ b/AVStream/samplemft0/stdafx.cpp
@@ -0,0 +1,13 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+
+// stdafx.cpp : source file that includes just the standard includes
+// SampleMft0.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/AVStream/samplemft0/stdafx.h b/AVStream/samplemft0/stdafx.h
new file mode 100644
index 00000000..86d812ec
--- /dev/null
+++ b/AVStream/samplemft0/stdafx.h
@@ -0,0 +1,42 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#ifndef STRICT
+#define STRICT
+#endif
+
+#include "targetver.h"
+
+#define _ATL_APARTMENT_THREADED
+
+#define _ATL_NO_AUTOMATIC_NAMESPACE
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
+
+
+#define ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW
+
+#include "resource.h"
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlctl.h>
+#include <atlcoll.h>
+#include <DbgHelp.h>
+
+#include <mfapi.h>
+#include <mfidl.h>
+#include <mferror.h>
+#include <ks.h>
+#include <ksmedia.h>
+
+#include <inspectable.h> \ No newline at end of file
diff --git a/AVStream/samplemft0/stdafxsrc.cpp b/AVStream/samplemft0/stdafxsrc.cpp
new file mode 100644
index 00000000..1577c4e3
--- /dev/null
+++ b/AVStream/samplemft0/stdafxsrc.cpp
@@ -0,0 +1 @@
+#include "stdafx.h" \ No newline at end of file
diff --git a/AVStream/samplemft0/targetver.h b/AVStream/samplemft0/targetver.h
new file mode 100644
index 00000000..fc349fa5
--- /dev/null
+++ b/AVStream/samplemft0/targetver.h
@@ -0,0 +1,15 @@
+//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+//// PARTICULAR PURPOSE.
+////
+//// Copyright (c) Microsoft Corporation. All rights reserved
+
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <SDKDDKVer.h>