summaryrefslogtreecommitdiff
path: root/general/SimpleMediaSource
diff options
context:
space:
mode:
authorPeihsun Yeh <[email protected]>2018-08-01 16:58:31 -0700
committerPeihsun Yeh <[email protected]>2018-08-01 16:58:31 -0700
commitedcb51e041d612e3fb8a0c0a9135d989c881ccc9 (patch)
treec30b3e38242aac68061556481ddace96bee1a9ca /general/SimpleMediaSource
parenta49f6121e1976979af7d6d8fc1f9af7acec9bcb2 (diff)
Creating custom media source solution and project (still needs driver)
Diffstat (limited to 'general/SimpleMediaSource')
-rw-r--r--general/SimpleMediaSource/MediaSource/MediaSource.vcxproj141
-rw-r--r--general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters44
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp506
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleMediaSource.h128
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp407
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleMediaStream.h54
-rw-r--r--general/SimpleMediaSource/MediaSource/dllMain.cpp35
-rw-r--r--general/SimpleMediaSource/MediaSource/module.def6
-rw-r--r--general/SimpleMediaSource/MediaSource/stdafx.cpp11
-rw-r--r--general/SimpleMediaSource/MediaSource/stdafx.h27
-rw-r--r--general/SimpleMediaSource/SimpleMediaSource.sln31
11 files changed, 1390 insertions, 0 deletions
diff --git a/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj
new file mode 100644
index 00000000..b1f8a7f4
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <VCProjectVersion>15.0</VCProjectVersion>
+ <ProjectGuid>{43AD9BF7-E765-48FE-9826-71A8F2CB12DD}</ProjectGuid>
+ <RootNamespace>MediaSource</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v141</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </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')" Label="LocalAppDataPlatform" />
+ </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')" Label="LocalAppDataPlatform" />
+ </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')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>mfplat.lib;RuntimeObject.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <SDLCheck>true</SDLCheck>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>mfplat.lib;RuntimeObject.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>mfplat.lib;RuntimeObject.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>mfplat.lib;RuntimeObject.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="module.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="SimpleMediaSource.cpp" />
+ <ClCompile Include="SimpleMediaStream.cpp" />
+ <ClCompile Include="stdafx.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="SimpleMediaSource.h" />
+ <ClInclude Include="SimpleMediaStream.h" />
+ <ClInclude Include="stdafx.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters
new file mode 100644
index 00000000..ce4a1433
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="module.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="SimpleMediaSource.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SimpleMediaStream.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdafx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="SimpleMediaSource.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SimpleMediaStream.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="stdafx.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp
new file mode 100644
index 00000000..34b6f2e2
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp
@@ -0,0 +1,506 @@
+#include "SimpleMediaSource.h"
+#include "SimpleMediaStream.h"
+
+///////////////////////////////////////////////////////////////////////////////
+HRESULT SimpleMediaSource::RuntimeClassInitialize()
+{
+ HRESULT hr = S_OK;
+
+ if (SUCCEEDED(hr))
+ {
+ hr = MFCreateAttributes(&_spAttributes, 10);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = MFCreateEventQueue(&_spEventQueue);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = MakeAndInitialize<SimpleMediaStream>(&_stream, this);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IMFStreamDescriptor> streamDescriptor(_stream.Get()->_spStreamDesc.Get());
+ hr = MFCreatePresentationDescriptor(NUM_STREAMS, streamDescriptor.GetAddressOf(), &_spPresentationDescriptor);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ _wasStreamPreviouslySelected = false;
+ _sourceState = SourceState::Stopped;
+ }
+
+ return hr;
+}
+
+// IMFMediaEventGenerator methods.
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::BeginGetEvent(IMFAsyncCallback *pCallback, IUnknown *punkState)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->BeginGetEvent(pCallback, punkState);
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::EndGetEvent(IMFAsyncResult *pResult, IMFMediaEvent **ppEvent)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->EndGetEvent(pResult, ppEvent);
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::GetEvent(DWORD dwFlags, IMFMediaEvent **ppEvent)
+{
+ // NOTE:
+ // GetEvent can block indefinitely, so we don't hold the lock.
+ // This requires some juggling with the event queue pointer.
+
+ HRESULT hr = S_OK;
+
+ ComPtr<IMFMediaEventQueue> spQueue;
+
+ {
+ auto lock = _critSec.Lock();
+
+ hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ spQueue = _spEventQueue;
+ }
+ }
+
+ // Now get the event.
+ if (SUCCEEDED(hr))
+ {
+ hr = spQueue->GetEvent(dwFlags, ppEvent);
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::QueueEvent(
+ MediaEventType eventType,
+ REFGUID guidExtendedType,
+ HRESULT hrStatus,
+ _In_opt_ PROPVARIANT const *pvValue)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue);
+ }
+
+ return hr;
+}
+
+// IMFMediaSource methods
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::CreatePresentationDescriptor(
+ IMFPresentationDescriptor **ppPresentationDescriptor)
+{
+ if (ppPresentationDescriptor == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ *ppPresentationDescriptor = nullptr;
+
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ hr = _spPresentationDescriptor->Clone(ppPresentationDescriptor);
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::GetCharacteristics(DWORD *pdwCharacteristics)
+{
+ *pdwCharacteristics = 0;
+
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ *pdwCharacteristics = MFMEDIASOURCE_IS_LIVE;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::Pause()
+{
+ // Pause() not required/needed for live sources
+ HRESULT hr = MF_E_INVALID_STATE_TRANSITION;
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::Shutdown()
+{
+ HRESULT hr = S_OK;
+ {
+ auto lock = _critSec.Lock();
+
+ _sourceState = SourceState::Shutdown;
+
+ _spAttributes.Reset();
+ _spPresentationDescriptor.Reset();
+
+ if (_spEventQueue != nullptr)
+ {
+ _spEventQueue->Shutdown();
+ _spEventQueue.Reset();
+ }
+
+ if (_stream != nullptr)
+ {
+ _stream.Get()->Shutdown();
+ _stream.Reset();
+ }
+ }
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::Start(
+ _In_ IMFPresentationDescriptor *pPresentationDescriptor,
+ _In_opt_ const GUID *pguidTimeFormat,
+ _In_ const PROPVARIANT *pvarStartPos)
+{
+ HRESULT hr = S_OK;
+
+ if (pPresentationDescriptor == nullptr || pvarStartPos == nullptr)
+ {
+ hr = E_INVALIDARG;
+ }
+ else if (pguidTimeFormat != nullptr && *pguidTimeFormat != GUID_NULL)
+ {
+ hr = MF_E_UNSUPPORTED_TIME_FORMAT;
+ }
+
+ do
+ {
+ BREAK_ON_FAIL(hr);
+
+ auto lock = _critSec.Lock();
+ BREAK_ON_FAIL(hr = _CheckShutdownRequiresLock());
+
+ if (_sourceState != SourceState::Stopped)
+ {
+ hr = MF_E_INVALID_STATE_TRANSITION;
+ break;
+ }
+
+ _sourceState = SourceState::Started;
+
+ // This checks the passed in PresentationDescriptor matches the member of streams we
+ // have defined internally and that at least one stream is selected
+ BREAK_ON_FAIL(hr = _ValidatePresentationDescriptor(pPresentationDescriptor));
+
+ DWORD count = 0;
+ BREAK_ON_FAIL(hr = pPresentationDescriptor->GetStreamDescriptorCount(&count));
+
+ PROPVARIANT startTime;
+ BREAK_ON_FAIL(hr = InitPropVariantFromInt64(MFGetSystemTime(), &startTime));
+
+ // Send event that the source started. Include error code in case it failed.
+ BREAK_ON_FAIL(hr = _spEventQueue->QueueEventParamVar(MESourceStarted, GUID_NULL, hr, &startTime));
+
+ // Open and un-pause the selected stream(s)
+ BOOL selected = false;
+ ComPtr<IMFStreamDescriptor> spStreamDescriptor;
+ BREAK_ON_FAIL(hr = pPresentationDescriptor->GetStreamDescriptorByIndex(0, &selected, &spStreamDescriptor));
+
+ DWORD streamIndex = 0;
+ BREAK_ON_FAIL(hr = spStreamDescriptor->GetStreamIdentifier(&streamIndex));
+
+ if (streamIndex >= NUM_STREAMS)
+ {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ break;
+ }
+
+ if (selected)
+ {
+ // Update our internal PresentationDescriptor
+ BREAK_ON_FAIL(hr = _spPresentationDescriptor->SelectStream(streamIndex));
+ BREAK_ON_FAIL(hr = _stream.Get()->SetStreamState(MF_STREAM_STATE_RUNNING));
+
+ ComPtr<IUnknown> spunkStream;
+ BREAK_ON_FAIL(hr = _stream.As(&spunkStream));
+
+ BREAK_ON_FAIL(hr = _spEventQueue->QueueEventParamUnk(_wasStreamPreviouslySelected ? MEUpdatedStream : MENewStream,
+ GUID_NULL, S_OK, spunkStream.Get()));
+ BREAK_ON_FAIL(hr = _stream.Get()->QueueEvent(MEStreamStarted, GUID_NULL, S_OK, &startTime));
+ }
+ _wasStreamPreviouslySelected = selected;
+
+ } while (false);
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::Stop()
+{
+ HRESULT hr = S_OK;
+
+ do
+ {
+ auto lock = _critSec.Lock();
+
+ if (_sourceState != SourceState::Started)
+ {
+ BREAK_ON_FAIL(hr = MF_E_INVALID_STATE_TRANSITION);
+ }
+
+ BREAK_ON_FAIL(hr = _CheckShutdownRequiresLock());
+
+ PROPVARIANT stopTime;
+ BREAK_ON_FAIL(hr = InitPropVariantFromInt64(MFGetSystemTime(), &stopTime));
+
+ DWORD count = 0;
+ BREAK_ON_FAIL(hr = _spPresentationDescriptor->GetStreamDescriptorCount(&count));
+ // Deselect the streams and send the stream stopped events.
+ MF_STREAM_STATE state;
+ hr = _stream.Get()->GetStreamState(&state);
+ if (FAILED(hr))
+ {
+ continue;
+ }
+ _wasStreamPreviouslySelected = (state == MF_STREAM_STATE_RUNNING);
+ hr = _stream.Get()->SetStreamState(MF_STREAM_STATE_STOPPED);
+ if (FAILED(hr))
+ {
+ continue;
+ }
+ _spPresentationDescriptor->DeselectStream(0);
+ hr = _stream.Get()->QueueEvent(MEStreamStopped, GUID_NULL, hr, &stopTime);
+ if (FAILED(hr))
+ {
+ continue;
+ }
+
+ BREAK_ON_FAIL(hr = _spEventQueue->QueueEventParamVar(MESourceStopped, GUID_NULL, hr, &stopTime));
+
+ } while (false);
+
+ return hr;
+}
+
+// IMFMediaSourceEx
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::GetSourceAttributes(_Outptr_ IMFAttributes **ppAttributes)
+{
+ if (ppAttributes == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ *ppAttributes = _spAttributes.Get();
+ (*ppAttributes)->AddRef();
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::GetStreamAttributes(DWORD dwStreamIdentifier, _Outptr_ IMFAttributes **ppAttributes)
+{
+ if (ppAttributes == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ auto lock = _critSec.Lock();
+
+ *ppAttributes = nullptr;
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ if (dwStreamIdentifier >= NUM_STREAMS)
+ {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ }
+ else
+ {
+ *ppAttributes = _stream.Get()->_spAttributes.Get();
+ (*ppAttributes)->AddRef();
+ }
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+
+ return hr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+IFACEMETHODIMP SimpleMediaSource::SetD3DManager(_In_opt_ IUnknown* /*pManager*/)
+{
+ // No need to implement this method in our case.
+ HRESULT hr = E_NOTIMPL;
+ return hr;
+}
+
+// IMFGetService methods
+///////////////////////////////////////////////////////////////////////////////
+_Use_decl_annotations_
+IFACEMETHODIMP SimpleMediaSource::GetService(REFGUID guidService, REFIID riid, LPVOID * ppvObject)
+{
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ if (!ppvObject)
+ {
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ *ppvObject = NULL;
+ }
+
+ hr = MF_E_UNSUPPORTED_SERVICE;
+ }
+
+ return hr;
+}
+
+// IKsControl methods
+_Use_decl_annotations_
+IFACEMETHODIMP SimpleMediaSource::KsProperty(
+ PKSPROPERTY pProperty,
+ ULONG ulPropertyLength,
+ LPVOID pPropertyData,
+ ULONG ulDataLength,
+ ULONG* pBytesReturned)
+{
+ return E_NOTIMPL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+_Use_decl_annotations_
+IFACEMETHODIMP SimpleMediaSource::KsMethod(
+ PKSMETHOD pMethod,
+ ULONG ulMethodLength,
+ LPVOID pMethodData,
+ ULONG ulDataLength,
+ ULONG* pBytesReturned)
+{
+ return E_NOTIMPL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+_Use_decl_annotations_
+IFACEMETHODIMP SimpleMediaSource::KsEvent(
+ _In_opt_ PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_opt_ LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned)
+{
+ return E_NOTIMPL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+HRESULT SimpleMediaSource::_CheckShutdownRequiresLock()
+{
+ if (_sourceState == SourceState::Shutdown)
+ {
+ return MF_E_SHUTDOWN;
+ }
+
+ if (_spEventQueue == nullptr || _stream == nullptr)
+ {
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+HRESULT SimpleMediaSource::_ValidatePresentationDescriptor(IMFPresentationDescriptor *pPD)
+{
+ if (pPD == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr = S_OK;
+ DWORD cStreams = 0;
+ bool anySelected = false;
+
+ // The caller's PD must have the same number of streams as ours.
+ hr = pPD->GetStreamDescriptorCount(&cStreams);
+
+ if (SUCCEEDED(hr) && (cStreams != NUM_STREAMS))
+ {
+ hr = E_INVALIDARG;
+ }
+
+ // The caller must select at least one stream.
+ for (UINT32 i = 0; SUCCEEDED(hr) && i < cStreams; ++i)
+ {
+ ComPtr<IMFStreamDescriptor> spSD;
+ BOOL fSelected = FALSE;
+ hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &spSD);
+
+ if (SUCCEEDED(hr))
+ {
+ anySelected |= !!fSelected;
+
+ DWORD dwId = 0;
+ hr = spSD->GetStreamIdentifier(&dwId);
+
+ if (SUCCEEDED(hr) && dwId >= NUM_STREAMS)
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ }
+
+ if (!anySelected)
+ {
+ hr = E_INVALIDARG;
+ }
+
+ return hr;
+} \ No newline at end of file
diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h
new file mode 100644
index 00000000..85b9227f
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h
@@ -0,0 +1,128 @@
+#pragma once
+
+// Represents a simple media source that only has one stream and outputs a static image
+
+#include "stdafx.h"
+#include "SimpleMediaStream.h"
+
+#define BREAK_ON_FAIL(value) if FAILED(value) break;
+
+#if !defined(_IKsControl_)
+#define _IKsControl_
+interface DECLSPEC_UUID("28F54685-06FD-11D2-B27A-00A0C9223196") IKsControl;
+#undef INTERFACE
+#define INTERFACE IKsControl
+DECLARE_INTERFACE_(IKsControl, IUnknown)
+{
+ STDMETHOD(KsProperty)(
+ THIS_
+ IN PKSPROPERTY Property,
+ IN ULONG PropertyLength,
+ IN OUT LPVOID PropertyData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+ STDMETHOD(KsMethod)(
+ THIS_
+ IN PKSMETHOD Method,
+ IN ULONG MethodLength,
+ IN OUT LPVOID MethodData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+ STDMETHOD(KsEvent)(
+ THIS_
+ IN PKSEVENT Event OPTIONAL,
+ IN ULONG EventLength,
+ IN OUT LPVOID EventData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+};
+#endif //!defined(_IKsControl_)
+
+class SimpleMediaStream;
+
+class __declspec(uuid("{9812588D-5CE9-4E4C-ABC1-049138D10DCE}"))
+SimpleMediaSource : public RuntimeClass<
+ RuntimeClassFlags<WinRtClassicComMix>,
+ IMFMediaEventGenerator,
+ IMFMediaSource,
+ IMFMediaSourceEx,
+ IMFGetService,
+ IKsControl>
+{
+
+ enum class SourceState
+ {
+ Invalid, Stopped, Started, Shutdown
+ };
+
+public:
+ // IMFMediaEventGenerator
+ IFACEMETHOD(BeginGetEvent)(_In_ IMFAsyncCallback *pCallback, _In_ IUnknown *punkState);
+ IFACEMETHOD(EndGetEvent)(_In_ IMFAsyncResult *pResult, _Out_ IMFMediaEvent **ppEvent);
+ IFACEMETHOD(GetEvent)(DWORD dwFlags, _Out_ IMFMediaEvent **ppEvent);
+ IFACEMETHOD(QueueEvent)(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, _In_ const PROPVARIANT *pvValue);
+
+ // IMFMediaSource
+ IFACEMETHOD(CreatePresentationDescriptor)(_Out_ IMFPresentationDescriptor **ppPresentationDescriptor);
+ IFACEMETHOD(GetCharacteristics)(_Out_ DWORD *pdwCharacteristics);
+ IFACEMETHOD(Pause)();
+ IFACEMETHOD(Shutdown)();
+ IFACEMETHOD(Start)(
+ _In_ IMFPresentationDescriptor *pPresentationDescriptor,
+ _In_ const GUID *pguidTimeFormat,
+ _In_ const PROPVARIANT *pvarStartPosition);
+ IFACEMETHOD(Stop)();
+
+ // IMFMediaSourceEx
+ IFACEMETHOD(GetSourceAttributes)(_Outptr_ IMFAttributes **ppAttributes);
+ IFACEMETHOD(GetStreamAttributes)(DWORD dwStreamIdentifier, _Outptr_ IMFAttributes **ppAttributes);
+ IFACEMETHOD(SetD3DManager)(_In_opt_ IUnknown *pManager);
+
+ // IMFGetService
+ IFACEMETHOD(GetService)(REFGUID guidService, REFIID riid, _Out_opt_ LPVOID *ppvObject);
+
+ // IKsControl
+ IFACEMETHOD(KsProperty)(
+ _In_ PKSPROPERTY pProperty,
+ ULONG ulPropertyLength,
+ _Inout_ LPVOID pPropertyData,
+ ULONG ulDataLength,
+ _Out_ ULONG* pBytesReturned);
+
+ IFACEMETHOD(KsMethod)(
+ _In_ PKSMETHOD pMethod,
+ ULONG ulMethodLength,
+ _Inout_ LPVOID pMethodData,
+ ULONG ulDataLength,
+ _Out_ ULONG* pBytesReturned
+ );
+
+ IFACEMETHOD(KsEvent)(
+ _In_opt_ PKSEVENT pEvent,
+ ULONG ulEventLength,
+ _Inout_opt_ LPVOID pEventData,
+ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ );
+public:
+ HRESULT RuntimeClassInitialize();
+
+private:
+ HRESULT _CheckShutdownRequiresLock();
+ HRESULT _ValidatePresentationDescriptor(IMFPresentationDescriptor *pPresentationDescriptor);
+
+ CriticalSection _critSec;
+ SourceState _sourceState{ SourceState::Invalid };
+ ComPtr<IMFMediaEventQueue> _spEventQueue;
+ ComPtr<IMFPresentationDescriptor> _spPresentationDescriptor;
+ ComPtr<IMFAttributes> _spAttributes;
+
+ bool _wasStreamPreviouslySelected; // maybe makes more sense as a property of the stream
+ const DWORD NUM_STREAMS = 1;
+ ComPtr<SimpleMediaStream> _stream;
+};
+
+CoCreatableClass(SimpleMediaSource);
diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp
new file mode 100644
index 00000000..2f8b603b
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp
@@ -0,0 +1,407 @@
+#include "SimpleMediaStream.h"
+
+#define NUM_IMAGE_ROWS 240
+#define NUM_IMAGE_COLS 320
+#define BYTES_PER_PIXEL 4
+#define IMAGE_BUFFER_SIZE_BYTES (NUM_IMAGE_ROWS * NUM_IMAGE_COLS * BYTES_PER_PIXEL)
+#define IMAGE_ROW_SIZE_BYTES (NUM_IMAGE_COLS * BYTES_PER_PIXEL)
+
+#define CHECKHR_GOTO( val, label ) \
+hr = (val); \
+if( FAILED( hr ) ) { \
+ goto label; \
+}
+
+HRESULT SimpleMediaStream::RuntimeClassInitialize(_In_ SimpleMediaSource *pSource)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaTypeHandler> spTypeHandler;
+ ComPtr<IMFAttributes> attrs;
+
+ AsWeak(pSource, &_wpSource);
+
+ // Initialize media type and set the video output media type.
+ CHECKHR_GOTO(MFCreateMediaType(&_spMediaType), done);
+ _spMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
+ _spMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
+ _spMediaType->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
+ _spMediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+ MFSetAttributeSize(_spMediaType.Get(), MF_MT_FRAME_SIZE, NUM_IMAGE_COLS, NUM_IMAGE_ROWS);
+ MFSetAttributeRatio(_spMediaType.Get(), MF_MT_FRAME_RATE, 30, 1);
+ MFSetAttributeRatio(_spMediaType.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
+
+ CHECKHR_GOTO(MFCreateAttributes(&_spAttributes, 10), done);
+ CHECKHR_GOTO(this->_SetStreamAttributes(_spAttributes.Get()), done);
+ CHECKHR_GOTO(MFCreateEventQueue(&_spEventQueue), done);
+
+ // Initialize stream descriptors
+ CHECKHR_GOTO(MFCreateStreamDescriptor(0, 1, _spMediaType.GetAddressOf(), &_spStreamDesc), done);
+
+ CHECKHR_GOTO(_spStreamDesc->GetMediaTypeHandler(&spTypeHandler), done);
+ CHECKHR_GOTO(spTypeHandler->SetCurrentMediaType(_spMediaType.Get()), done);
+ CHECKHR_GOTO(this->_SetStreamDescriptorAttributes(_spStreamDesc.Get()), done);
+
+done:
+ return hr;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// IMFMediaEventGenerator
+IFACEMETHODIMP SimpleMediaStream::BeginGetEvent(IMFAsyncCallback *pCallback, IUnknown *punkState)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->BeginGetEvent(pCallback, punkState);
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP SimpleMediaStream::EndGetEvent(IMFAsyncResult *pResult, IMFMediaEvent **ppEvent)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->EndGetEvent(pResult, ppEvent);
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP SimpleMediaStream::GetEvent(DWORD dwFlags, IMFMediaEvent **ppEvent)
+{
+ // NOTE:
+ // GetEvent can block indefinitely, so we don't hold the lock.
+ // This requires some juggling with the event queue pointer.
+
+ HRESULT hr = S_OK;
+
+ ComPtr<IMFMediaEventQueue> spQueue;
+
+ {
+ auto lock = _critSec.Lock();
+
+ // Check shutdown
+ hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ spQueue = _spEventQueue;
+ }
+ }
+
+ // Now get the event.
+ if (SUCCEEDED(hr))
+ {
+ hr = spQueue->GetEvent(dwFlags, ppEvent);
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP SimpleMediaStream::QueueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT *pvValue)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
+ }
+
+ return hr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// IMFMediaStream
+IFACEMETHODIMP SimpleMediaStream::GetMediaSource(IMFMediaSource **ppMediaSource)
+{
+ if (ppMediaSource == nullptr)
+ {
+ return E_POINTER;
+ }
+ *ppMediaSource = nullptr;
+
+ auto lock = _critSec.Lock();
+ HRESULT hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<SimpleMediaSource> spSource;
+ _wpSource.As(&spSource);
+ if (spSource != nullptr)
+ {
+ hr = spSource->QueryInterface(IID_PPV_ARGS(ppMediaSource));
+ }
+ else
+ {
+ hr = E_UNEXPECTED;
+ }
+ }
+
+ return hr;
+}
+
+IFACEMETHODIMP SimpleMediaStream::GetStreamDescriptor(IMFStreamDescriptor **ppStreamDescriptor)
+{
+ if (ppStreamDescriptor == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ *ppStreamDescriptor = nullptr;
+
+ auto lock = _critSec.Lock();
+ HRESULT hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ if (_spStreamDesc != nullptr)
+ {
+ *ppStreamDescriptor = _spStreamDesc.Get();
+ (*ppStreamDescriptor)->AddRef();
+ }
+ else
+ {
+ return E_UNEXPECTED;
+ }
+ }
+
+ return hr;
+}
+
+/*
+ Writes to a buffer representing a 2D image.
+ Writes a different constant to each line based on row number and current time.
+
+ Assumes top down image, no negative stride and pBuf points to the begnning of the buffer of length len.
+
+ Param:
+ pBuf - pointer to beginning of buffer
+ pitch - line length in bytes
+ len - length of buffer in bytes
+*/
+HRESULT WriteSampleData(BYTE *pBuf, LONG pitch, DWORD len)
+{
+ if (pBuf == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ const int NUM_ROWS = len / abs(pitch);
+
+ LONGLONG curSysTimeInS = MFGetSystemTime() / (MFTIME)10000000;
+ int offset = curSysTimeInS % NUM_ROWS;
+
+ for (int r = 0; r < NUM_ROWS; r++)
+ {
+ int grayColor = r + offset;
+ memset(pBuf + (pitch * r), (BYTE)(grayColor % NUM_ROWS), pitch);
+ }
+
+ return S_OK;
+}
+
+IFACEMETHODIMP SimpleMediaStream::RequestSample(IUnknown *pToken)
+{
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ ComPtr<IMFSample> spSample;
+
+ ComPtr<IMFMediaBuffer> spOutputBuffer;
+ hr = MFCreate2DMediaBuffer(NUM_IMAGE_COLS, NUM_IMAGE_ROWS, D3DFMT_X8R8G8B8, false, &spOutputBuffer);
+
+ LONG pitch = IMAGE_ROW_SIZE_BYTES;
+ BYTE *bufferStart = nullptr; // not used, since in this example we know the image will be top down, so bufferStart == pBuf
+ DWORD bufferLength = IMAGE_BUFFER_SIZE_BYTES;
+
+ BYTE *pBuf = nullptr;
+ ComPtr<IMF2DBuffer2> spBuffer2D;
+ if (SUCCEEDED(hr))
+ {
+ hr = spOutputBuffer.As(&spBuffer2D);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (spBuffer2D != nullptr)
+ {
+ hr = spBuffer2D->Lock2DSize(MF2DBuffer_LockFlags_Write, &pBuf, &pitch, &bufferStart, &bufferLength);
+ }
+ else
+ {
+ hr = spOutputBuffer->Lock(&pBuf, nullptr, nullptr);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = WriteSampleData(pBuf, pitch, bufferLength);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = spOutputBuffer->SetCurrentLength(bufferLength);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = spBuffer2D->Unlock2D();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = MFCreateSample(&spSample);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = spSample->AddBuffer(spOutputBuffer.Get());
+ }
+
+ // set timestamp
+ if (SUCCEEDED(hr))
+ {
+ hr = spSample->SetSampleTime(MFGetSystemTime());
+ }
+ if (SUCCEEDED(hr))
+ {
+ hr = spSample->SetSampleDuration(330000);
+ }
+
+ if (pToken != nullptr)
+ {
+ hr = spSample->SetUnknown(MFSampleExtension_Token, pToken);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = _spEventQueue->QueueEventParamUnk(MEMediaSample, GUID_NULL, S_OK, spSample.Get());
+ }
+ }
+
+ return hr;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// IMFMediaStream2
+IFACEMETHODIMP SimpleMediaStream::SetStreamState(MF_STREAM_STATE state)
+{
+ bool runningState = false;
+ auto lock = _critSec.Lock();
+
+ HRESULT hr = S_OK;
+
+ CHECKHR_GOTO(_CheckShutdownRequiresLock(), done);
+
+ switch (state)
+ {
+ case MF_STREAM_STATE_PAUSED:
+ goto done; // because not supported
+ case MF_STREAM_STATE_RUNNING:
+ runningState = true;
+ break;
+ case MF_STREAM_STATE_STOPPED:
+ runningState = false;
+ break;
+ default:
+ hr = MF_E_INVALID_STATE_TRANSITION;
+ break;
+ }
+
+ _isSelected = runningState;
+
+done:
+ return hr;
+}
+
+IFACEMETHODIMP SimpleMediaStream::GetStreamState(_Out_ MF_STREAM_STATE *pState)
+{
+ auto lock = _critSec.Lock();
+ BOOLEAN pauseState = false;
+
+ HRESULT hr = _CheckShutdownRequiresLock();
+
+ if (SUCCEEDED(hr))
+ {
+ *pState = (_isSelected ? MF_STREAM_STATE_RUNNING : MF_STREAM_STATE_STOPPED);
+ }
+
+ return hr;
+}
+
+HRESULT SimpleMediaStream::Shutdown()
+{
+ HRESULT hr = S_OK;
+ auto lock = _critSec.Lock();
+
+ _isShutdown = true;
+
+ if (_spEventQueue != nullptr)
+ {
+ hr = _spEventQueue->Shutdown();
+ _spEventQueue.Reset();
+ }
+
+ _spAttributes.Reset();
+ _spMediaType.Reset();
+ _spStreamDesc.Reset();
+
+ _isSelected = false;
+
+ _wpSource.Reset();
+
+ return hr;
+}
+
+HRESULT SimpleMediaStream::_CheckShutdownRequiresLock()
+{
+ if (_isShutdown)
+ {
+ return MF_E_SHUTDOWN;
+ }
+
+ if (_spEventQueue == nullptr)
+ {
+ return E_UNEXPECTED;
+
+ }
+ return S_OK;
+}
+
+HRESULT SimpleMediaStream::_SetStreamAttributes(IMFAttributes *pAttributeStore)
+{
+ HRESULT hr = S_OK;
+
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE); }
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, STREAMINDEX); }
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1); }
+
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, _MFFrameSourceTypes::MFFrameSourceTypes_Color); }
+
+ return hr;
+}
+
+HRESULT SimpleMediaStream::_SetStreamDescriptorAttributes(IMFAttributes *pAttributeStore)
+{
+ HRESULT hr = S_OK;
+
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE); }
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, STREAMINDEX); }
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1); }
+
+ if (SUCCEEDED(hr)) { hr = pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, _MFFrameSourceTypes::MFFrameSourceTypes_Color); }
+
+ return hr;
+} \ No newline at end of file
diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h
new file mode 100644
index 00000000..b804b1ea
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#include "stdafx.h"
+#include "SimpleMediaSource.h"
+
+class SimpleMediaSource;
+
+class SimpleMediaStream : public RuntimeClass<
+ RuntimeClassFlags<ClassicCom>,
+ IMFMediaEventGenerator,
+ IMFMediaStream,
+ IMFMediaStream2>
+{
+ friend class SimpleMediaSource;
+
+public:
+ // IMFMediaEventGenerator
+ IFACEMETHOD(BeginGetEvent)(IMFAsyncCallback *pCallback, IUnknown *punkState);
+ IFACEMETHOD(EndGetEvent)(IMFAsyncResult *pResult, IMFMediaEvent **ppEvent);
+ IFACEMETHOD(GetEvent)(DWORD dwFlags, IMFMediaEvent **ppEvent);
+ IFACEMETHOD(QueueEvent)(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT *pvValue);
+
+ // IMFMediaStream
+ IFACEMETHOD(GetMediaSource)(IMFMediaSource **ppMediaSource);
+ IFACEMETHOD(GetStreamDescriptor)(IMFStreamDescriptor **ppStreamDescriptor);
+ IFACEMETHOD(RequestSample)(IUnknown *pToken);
+
+ // IMFMediaStream2
+ IFACEMETHOD(SetStreamState)(MF_STREAM_STATE state);
+ IFACEMETHOD(GetStreamState)(_Out_ MF_STREAM_STATE *pState);
+
+public:
+ HRESULT RuntimeClassInitialize(_In_ SimpleMediaSource* pSource);
+ HRESULT Shutdown();
+private:
+ HRESULT _CheckShutdownRequiresLock();
+
+ HRESULT _SetStreamAttributes(IMFAttributes* pAttributeStore);
+ HRESULT _SetStreamDescriptorAttributes(IMFAttributes* pAttributeStore);
+private:
+ CriticalSection _critSec;
+
+ WeakRef _wpSource;
+
+ ComPtr<IMFMediaEventQueue> _spEventQueue;
+ ComPtr<IMFAttributes> _spAttributes;
+ ComPtr<IMFMediaType> _spMediaType;
+ ComPtr<IMFStreamDescriptor> _spStreamDesc;
+ bool _isShutdown = false;
+ bool _isSelected = false;
+
+ const DWORD STREAMINDEX = 0; // since there is only one stream
+};
+
diff --git a/general/SimpleMediaSource/MediaSource/dllMain.cpp b/general/SimpleMediaSource/MediaSource/dllMain.cpp
new file mode 100644
index 00000000..aed44eb0
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/dllMain.cpp
@@ -0,0 +1,35 @@
+/// <copyright file="dllmain.cpp" company="Microsoft">
+/// Copyright (c) Microsoft Corporation. All rights reserved.
+/// </copyright>
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "stdafx.h"
+
+#include <wrl\module.h>
+
+#if !defined(__WRL_CLASSIC_COM__)
+STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _COM_Outptr_ IActivationFactory** factory)
+{
+ return Module<InProc>::GetModule().GetActivationFactory(activatibleClassId, factory);
+}
+#endif
+
+#if !defined(__WRL_WINRT_STRICT__)
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
+{
+ return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
+}
+#endif
+
+STDAPI DllCanUnloadNow()
+{
+ return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
+}
+
+STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ DisableThreadLibraryCalls(hinst);
+ }
+ return TRUE;
+}
diff --git a/general/SimpleMediaSource/MediaSource/module.def b/general/SimpleMediaSource/MediaSource/module.def
new file mode 100644
index 00000000..ddeb3eac
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/module.def
@@ -0,0 +1,6 @@
+LIBRARY
+
+EXPORTS
+ DllGetActivationFactory PRIVATE
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
diff --git a/general/SimpleMediaSource/MediaSource/stdafx.cpp b/general/SimpleMediaSource/MediaSource/stdafx.cpp
new file mode 100644
index 00000000..dc97a45b
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/stdafx.cpp
@@ -0,0 +1,11 @@
+/// <copyright file="stdafx.cpp" company="Microsoft">
+/// Copyright (c) Microsoft Corporation. All rights reserved.
+/// </copyright>
+// stdafx.cpp : source file that includes just the standard includes
+// KinectMFMediaSource.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/general/SimpleMediaSource/MediaSource/stdafx.h b/general/SimpleMediaSource/MediaSource/stdafx.h
new file mode 100644
index 00000000..4702e47e
--- /dev/null
+++ b/general/SimpleMediaSource/MediaSource/stdafx.h
@@ -0,0 +1,27 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+// Windows Header Files:
+#include <windows.h>
+#include <minwindef.h>
+#include <ks.h>
+#include <propvarutil.h>
+//#include <mfstd.h> // Must be included before <initguid.h>, or else DirectDraw GUIDs will be defined twice. See the comment in <uuids.h>.
+#include <ole2.h>
+#include <initguid.h>
+#include <mfapi.h>
+#include <mferror.h>
+#include <mfidl.h>
+#include <mfreadwrite.h>
+#include <nserror.h>
+#include <winmeta.h>
+#include <wrl.h>
+#include <d3d9types.h>
+#include <ksmedia.h>
+
+using namespace Microsoft::WRL;
+using namespace Microsoft::WRL::Wrappers; \ No newline at end of file
diff --git a/general/SimpleMediaSource/SimpleMediaSource.sln b/general/SimpleMediaSource/SimpleMediaSource.sln
new file mode 100644
index 00000000..dd03ec69
--- /dev/null
+++ b/general/SimpleMediaSource/SimpleMediaSource.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2026
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MediaSource", "MediaSource\MediaSource.vcxproj", "{43AD9BF7-E765-48FE-9826-71A8F2CB12DD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Debug|x64.ActiveCfg = Debug|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Debug|x64.Build.0 = Debug|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Debug|x86.ActiveCfg = Debug|Win32
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Debug|x86.Build.0 = Debug|Win32
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Release|x64.ActiveCfg = Release|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Release|x64.Build.0 = Release|x64
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Release|x86.ActiveCfg = Release|Win32
+ {43AD9BF7-E765-48FE-9826-71A8F2CB12DD}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {2205BF4A-ACC2-4A73-8C1E-C3D9AF0F8B24}
+ EndGlobalSection
+EndGlobal