summaryrefslogtreecommitdiff
path: root/AVStream/avssamp
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/avssamp
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'AVStream/avssamp')
-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
21 files changed, 6987 insertions, 0 deletions
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;
+ }
+
+};