diff options
18 files changed, 1760 insertions, 938 deletions
diff --git a/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj index 47562ff7..3c5ff0de 100644 --- a/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj +++ b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj @@ -53,7 +53,7 @@ <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> <DriverTargetPlatform>Universal</DriverTargetPlatform> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> @@ -61,7 +61,7 @@ <UseDebugLibraries>false</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> <DriverTargetPlatform>Universal</DriverTargetPlatform> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration"> @@ -69,21 +69,20 @@ <UseDebugLibraries>false</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> <DriverTargetPlatform>Universal</DriverTargetPlatform> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> - <DriverTargetPlatform>Universal</DriverTargetPlatform> + <CharacterSet>Unicode</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> <DriverTargetPlatform>Universal</DriverTargetPlatform> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> @@ -91,15 +90,16 @@ <UseDebugLibraries>false</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> <DriverTargetPlatform>Universal</DriverTargetPlatform> + <Driver_SpectreMitigation>Spectre</Driver_SpectreMitigation> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration"> <ConfigurationType>DynamicLibrary</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>MultiByte</CharacterSet> + <CharacterSet>Unicode</CharacterSet> <DriverTargetPlatform>Universal</DriverTargetPlatform> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> @@ -171,8 +171,13 @@ <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <LanguageStandard>stdcpp17</LanguageStandard> + <CallingConvention>Cdecl</CallingConvention> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <AdditionalDependencies>mfplat.lib;Mfsensorgroup.lib;%(AdditionalDependencies);OneCoreUAP.lib</AdditionalDependencies> @@ -187,8 +192,12 @@ <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <AdditionalDependencies>mfplat.lib;Mfsensorgroup.lib;%(AdditionalDependencies);OneCoreUAP.lib</AdditionalDependencies> @@ -203,8 +212,12 @@ <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <AdditionalDependencies>mfplat.lib;Mfsensorgroup.lib;%(AdditionalDependencies);OneCoreUAP.lib</AdditionalDependencies> @@ -219,8 +232,12 @@ <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <AdditionalDependencies>mfplat.lib;Mfsensorgroup.lib;%(AdditionalDependencies);OneCoreUAP.lib</AdditionalDependencies> @@ -237,8 +254,12 @@ <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -258,8 +279,12 @@ <SDLCheck>true</SDLCheck> <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -281,7 +306,11 @@ <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -301,7 +330,11 @@ <ConformanceMode>true</ConformanceMode> <EnablePREfast>false</EnablePREfast> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> - <ExceptionHandling>false</ExceptionHandling> + <ExceptionHandling>Sync</ExceptionHandling> + <LanguageStandard>stdcpp17</LanguageStandard> + <PrecompiledHeader>Create</PrecompiledHeader> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <AdditionalIncludeDirectories>..\..\..\wil\include;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -316,16 +349,19 @@ </ItemGroup> <ItemGroup> <ClCompile Include="dllMain.cpp" /> + <ClCompile Include="SimpleFrameGenerator.cpp" /> <ClCompile Include="SimpleMediaSource.cpp" /> + <ClCompile Include="SimpleMediaSourceActivate.cpp" /> <ClCompile Include="SimpleMediaStream.cpp" /> - <ClCompile Include="stdafx.cpp" /> + <ClCompile Include="pch.cpp" /> </ItemGroup> <ItemGroup> + <ClInclude Include="SimpleFrameGenerator.h" /> <ClInclude Include="SimpleMediaSource.h" /> + <ClInclude Include="SimpleMediaSourceActivate.h" /> <ClInclude Include="SimpleMediaStream.h" /> - <ClInclude Include="stdafx.h" /> + <ClInclude Include="pch.h" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> + <ImportGroup Label="ExtensionTargets" /> </Project>
\ No newline at end of file diff --git a/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters index ffcc9853..ba0d78a1 100644 --- a/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters +++ b/general/SimpleMediaSource/MediaSource/MediaSource.vcxproj.filters @@ -26,22 +26,34 @@ <ClCompile Include="SimpleMediaStream.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="stdafx.cpp"> + <ClCompile Include="pch.cpp"> <Filter>Source Files</Filter> </ClCompile> <ClCompile Include="dllMain.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="SimpleMediaSourceActivate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="SimpleFrameGenerator.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="SimpleMediaSource.h"> - <Filter>Source Files</Filter> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="SimpleMediaSourceActivate.h"> + <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="SimpleMediaStream.h"> - <Filter>Source Files</Filter> + <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="stdafx.h"> - <Filter>Source Files</Filter> + <ClInclude Include="pch.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="SimpleFrameGenerator.h"> + <Filter>Header Files</Filter> </ClInclude> </ItemGroup> </Project>
\ No newline at end of file diff --git a/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp b/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp new file mode 100644 index 00000000..6adafb44 --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.cpp @@ -0,0 +1,146 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// +#include "pch.h" + +HRESULT SimpleFrameGenerator::Initialize(_In_ IMFMediaType* pMediaType) +{ + RETURN_HR_IF_NULL(E_INVALIDARG, pMediaType); + + RETURN_IF_FAILED(pMediaType->GetGUID(MF_MT_SUBTYPE, &m_subType)); + if (m_subType != MFVideoFormat_RGB32 && m_subType != MFVideoFormat_NV12) + { + RETURN_HR_MSG(MF_E_UNSUPPORTED_FORMAT, "Unsupported format: %s", winrt::to_hstring(m_subType).data()); + } + MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &m_width, &m_height); + + return S_OK; +} + +/*: + 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 SimpleFrameGenerator::CreateFrame( + _Inout_updates_bytes_(len) BYTE* pBuf, + _In_ DWORD len, + _In_ LONG pitch, + _In_ ULONG rgbMask) +{ + if (m_subType == MFVideoFormat_RGB32) + { + DEBUG_MSG(L"RGB32 frames %s\n", winrt::to_hstring(MFVideoFormat_RGB32).data()); + + RETURN_IF_FAILED(_CreateRGB32Frame(pBuf, len, pitch, m_width, m_height, rgbMask)); + } + else if(m_subType == MFVideoFormat_NV12) + { + DEBUG_MSG(L"NV12 frames %s \n", winrt::to_hstring(MFVideoFormat_NV12).data()); + + DWORD frameBuffLen = m_width * m_height * 4; + wil::unique_cotaskmem_ptr<BYTE[]> spBuff = wil::make_unique_cotaskmem_nothrow<BYTE[]>(frameBuffLen); + RETURN_IF_NULL_ALLOC(spBuff.get()); + + RETURN_IF_FAILED(_CreateRGB32Frame(spBuff.get(), frameBuffLen, m_width * 4, m_width, m_height, rgbMask)); + RETURN_IF_FAILED(RGB32ToNV12Frame(spBuff.get(), frameBuffLen, m_width * 4, m_width, m_height, pBuf, len, pitch)); + } + else + { + return MF_E_UNSUPPORTED_FORMAT; + } + + return S_OK; +} + +////////////////////////////////////////////////// +// private + +HRESULT SimpleFrameGenerator::_CreateRGB32Frame( + _Inout_updates_bytes_(len) BYTE* pBuf, + _In_ DWORD len, + _In_ LONG pitch, + _In_ DWORD width, + _In_ DWORD height, + _In_ ULONG rgbMask ) +{ + RETURN_HR_IF_NULL(E_INVALIDARG, pBuf); + + LONGLONG curSysTimeInS = MFGetSystemTime() / (MFTIME)10000000; + int offset = curSysTimeInS % height; + + for (unsigned int r = 0; r < height; r++) + { + uint32_t* p = (uint32_t*)(pBuf + (r * pitch)); + for (unsigned int c = 0; c < width; c++) + { + BYTE gray = (BYTE)r + offset; + *p = ((uint32_t)gray << 16 | (uint32_t)gray << 8 | (uint32_t)gray) & rgbMask; + p++; + } + } + + return S_OK; +} + +////////////////////////////////////////////////// +// pixelFormatConverter + +void SimpleFrameGenerator::RGB24ToYUY2(int R, int G, int B, BYTE* pY, BYTE* pU, BYTE* pV) +{ + *pY = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; + *pU = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; + *pV = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; +} + +void SimpleFrameGenerator::RGB24ToY(int R, int G, int B, BYTE* pY) +{ + *pY = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; +} + +void SimpleFrameGenerator::RGB32ToNV12(BYTE RGB1[8], BYTE RGB2[8], BYTE* pY1, BYTE* pY2, BYTE* pUV) +{ + RGB24ToYUY2(RGB1[2], RGB1[1], RGB1[0], pY1, pUV, pUV + 1); + RGB24ToY(RGB1[6], RGB1[5], RGB1[4], pY1 + 1); + RGB24ToYUY2(RGB2[2], RGB2[1], RGB2[0], pY2, pUV, pUV + 1); + RGB24ToY(RGB2[6], RGB2[5], RGB2[4], pY2 + 1); +}; + +////////////////////////////////////////////////// +// FrameFormatConverter + +HRESULT SimpleFrameGenerator::RGB32ToNV12Frame(_Inout_updates_bytes_(len) BYTE* pbBuff, ULONG cbBuff, long stride, UINT width, UINT height, BYTE* pbBuffOut, ULONG cbBuffOut, long strideOut) +{ + do + { + RETURN_HR_IF(E_UNEXPECTED, width * 4 * height > cbBuff); + RETURN_HR_IF(E_UNEXPECTED, width * 1.5 * height > cbBuffOut); + RETURN_HR_IF_NULL(E_INVALIDARG, pbBuff); + + RETURN_HR_IF_NULL(E_INVALIDARG, pbBuffOut); + for (DWORD h = 0; h < height - 1; h += 2) + { + BYTE* pRGB1 = h * stride + pbBuff; + BYTE* pRGB2 = (h + 1) * stride + pbBuff; + BYTE* pY1 = h * strideOut + pbBuffOut; + BYTE* pY2 = (h + 1) * strideOut + pbBuffOut; + BYTE* pUV = (h / 2 + height) * strideOut + pbBuffOut; + + for (DWORD w = 0; w < width; w += 2) + { + RGB32ToNV12(pRGB1, pRGB2, pY1, pY2, pUV); + pRGB1 += 8; + pRGB2 += 8; + pY1 += 2; + pY2 += 2; + pUV += 2; + } + } + } while (FALSE); + + return S_OK; +} diff --git a/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.h b/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.h new file mode 100644 index 00000000..f481ab61 --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/SimpleFrameGenerator.h @@ -0,0 +1,46 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// + +#pragma once +#ifndef SIMPLE_FRAME_GENERATOR_H +#define SIMPLE_FRAME_GENERATOR_H + +class SimpleFrameGenerator +{ +public: + SimpleFrameGenerator() = default; + ~SimpleFrameGenerator() {}; + + HRESULT Initialize(_In_ IMFMediaType* pMediaType); + + HRESULT CreateFrame( + _Inout_updates_bytes_(len) BYTE* pBuf, + _In_ DWORD len, + _In_ LONG pitch, + _In_ ULONG rgbMask); + + // pixel format converter + static void RGB24ToYUY2(int R, int G, int B, BYTE* pY, BYTE* pU, BYTE* pV); + static void RGB24ToY(int R, int G, int B, BYTE* pY); + static void RGB32ToNV12(BYTE RGB1[8], BYTE RGB2[8], BYTE* pY1, BYTE* pY2, BYTE* pUV); + + static HRESULT RGB32ToNV12Frame(_Inout_updates_bytes_(len) BYTE* pbBuff, ULONG cbBuff, long stride, UINT width, UINT height, BYTE* pbBuffOut, ULONG cbBuffOut, long strideOut); + +private: + HRESULT _CreateRGB32Frame( + _Inout_updates_bytes_(len) BYTE* pBuf, + _In_ DWORD len, + _In_ LONG pitch, + _In_ DWORD width, + _In_ DWORD height, + _In_ ULONG rgbMask); + + UINT32 m_width = 0; + UINT32 m_height = 0; + GUID m_subType = GUID_NULL; + +}; + +#endif + diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp index 162fb1d8..8ff15872 100644 --- a/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp +++ b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp @@ -1,526 +1,651 @@ -#include "stdafx.h" +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// +#include "pch.h" -/////////////////////////////////////////////////////////////////////////////// -HRESULT -SimpleMediaSource::RuntimeClassInitialize( - ) +namespace winrt::WindowsSample::implementation { - HRESULT hr = S_OK; - - RETURN_IF_FAILED (MFCreateAttributes(&_spAttributes, 10)); - RETURN_IF_FAILED (MFCreateEventQueue(&_spEventQueue)); - RETURN_IF_FAILED (MakeAndInitialize<SimpleMediaStream>(&_stream, this)); + ///////////////////////////////////////////////////////////////////////////////// + HRESULT SimpleMediaSource::Initialize() { - ComPtr<IMFStreamDescriptor> streamDescriptor(_stream.Get()->_spStreamDesc.Get()); - RETURN_IF_FAILED (MFCreatePresentationDescriptor(NUM_STREAMS, streamDescriptor.GetAddressOf(), &_spPresentationDescriptor)); - } + winrt::slim_lock_guard lock(m_Lock); - _wasStreamPreviouslySelected = false; - _sourceState = SourceState::Stopped; + RETURN_IF_FAILED(_CreateSourceAttributes()); + RETURN_IF_FAILED(MFCreateEventQueue(&m_spEventQueue)); - return hr; -} + m_streamList = wilEx::make_unique_cotaskmem_array<wil::com_ptr_nothrow<SimpleMediaStream>>(NUM_STREAMS); + RETURN_IF_NULL_ALLOC(m_streamList.get()); -// IMFMediaEventGenerator methods. -IFACEMETHODIMP -SimpleMediaSource::BeginGetEvent( - _In_ IMFAsyncCallback *pCallback, - _In_ IUnknown *punkState - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + wil::unique_cotaskmem_array_ptr<wil::com_ptr_nothrow<IMFStreamDescriptor>> streamDescriptorList = wilEx::make_unique_cotaskmem_array<wil::com_ptr_nothrow<IMFStreamDescriptor>>(NUM_STREAMS); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spEventQueue->BeginGetEvent(pCallback, punkState)); + // This example showcase one stream (i.e. NUM_STREAMS == 1), + // it can be extended to multiple streams by changing NUM_STREAMS + for (unsigned int i = 0; i < NUM_STREAMS; i++) + { + auto ptr = winrt::make_self<SimpleMediaStream>(); + m_streamList[i] = ptr.detach(); + RETURN_IF_FAILED(m_streamList[i]->Initialize(this, i, MFSampleAllocatorUsage_UsesProvidedAllocator)); - return hr; -} + RETURN_IF_FAILED(m_streamList[i]->GetStreamDescriptor(&streamDescriptorList[i])); + } -IFACEMETHODIMP -SimpleMediaSource::EndGetEvent( - _In_ IMFAsyncResult *pResult, - _COM_Outptr_ IMFMediaEvent **ppEvent - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + RETURN_IF_FAILED(MFCreatePresentationDescriptor(m_streamList.size(), streamDescriptorList.get(), &m_spPresentationDescriptor)); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spEventQueue->EndGetEvent(pResult, ppEvent)); + m_sourceState = SourceState::Stopped; - return hr; -} + return S_OK; + } -IFACEMETHODIMP -SimpleMediaSource::GetEvent( - DWORD dwFlags, - _COM_Outptr_ IMFMediaEvent **ppEvent - ) -{ - // NOTE: - // GetEvent can block indefinitely, so we don't hold the lock. - // This requires some juggling with the event queue pointer. + // IMFMediaEventGenerator methods. + IFACEMETHODIMP SimpleMediaSource::BeginGetEvent( + _In_ IMFAsyncCallback* pCallback, + _In_ IUnknown* punkState ) + { + winrt::slim_lock_guard lock(m_Lock); - HRESULT hr = S_OK; + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spEventQueue->BeginGetEvent(pCallback, punkState)); - ComPtr<IMFMediaEventQueue> spQueue; + return S_OK; + } + IFACEMETHODIMP SimpleMediaSource::EndGetEvent( + _In_ IMFAsyncResult* pResult, + _COM_Outptr_ IMFMediaEvent** ppEvent + ) { - auto lock = _critSec.Lock(); + winrt::slim_lock_guard lock(m_Lock); + + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spEventQueue->EndGetEvent(pResult, ppEvent)); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - spQueue = _spEventQueue; + return S_OK; } - // Now get the event. - RETURN_IF_FAILED (_spEventQueue->GetEvent(dwFlags, ppEvent)); + IFACEMETHODIMP SimpleMediaSource::GetEvent( + DWORD dwFlags, + _COM_Outptr_ IMFMediaEvent** ppEvent + ) + { + // NOTE: + // GetEvent can block indefinitely, so we don't hold the lock. + // This requires some juggling with the event queue pointer. - return hr; -} + wil::com_ptr_nothrow<IMFMediaEventQueue> spQueue; -IFACEMETHODIMP -SimpleMediaSource::QueueEvent( - MediaEventType eventType, - REFGUID guidExtendedType, - HRESULT hrStatus, - _In_opt_ PROPVARIANT const *pvValue - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + { + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue)); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + spQueue = m_spEventQueue; + } - return hr; -} + // Now get the event. + RETURN_IF_FAILED(spQueue->GetEvent(dwFlags, ppEvent)); -// IMFMediaSource methods -IFACEMETHODIMP -SimpleMediaSource::CreatePresentationDescriptor( - _COM_Outptr_ IMFPresentationDescriptor **ppPresentationDescriptor - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + return S_OK; + } - if (ppPresentationDescriptor == nullptr) + IFACEMETHODIMP SimpleMediaSource::QueueEvent( + MediaEventType eventType, + REFGUID guidExtendedType, + HRESULT hrStatus, + _In_opt_ PROPVARIANT const* pvValue + ) { - return E_POINTER; - } - *ppPresentationDescriptor = nullptr; + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spPresentationDescriptor->Clone(ppPresentationDescriptor)); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue)); - return hr; -} - -IFACEMETHODIMP -SimpleMediaSource::GetCharacteristics( - _Out_ DWORD *pdwCharacteristics - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + return S_OK; + } - if (nullptr == pdwCharacteristics) + // IMFMediaSource methods + IFACEMETHODIMP SimpleMediaSource::CreatePresentationDescriptor( + _COM_Outptr_ IMFPresentationDescriptor** ppPresentationDescriptor + ) { - return E_POINTER; - } - *pdwCharacteristics = 0; + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - *pdwCharacteristics = MFMEDIASOURCE_IS_LIVE; + RETURN_HR_IF_NULL(E_POINTER, ppPresentationDescriptor); + *ppPresentationDescriptor = nullptr; - return hr; -} + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spPresentationDescriptor->Clone(ppPresentationDescriptor)); -IFACEMETHODIMP -SimpleMediaSource::Pause( - ) -{ - // Pause() not required/needed - return MF_E_INVALID_STATE_TRANSITION; -} + return S_OK; + } + IFACEMETHODIMP SimpleMediaSource::GetCharacteristics( + _Out_ DWORD* pdwCharacteristics + ) + { + winrt::slim_lock_guard lock(m_Lock); -IFACEMETHODIMP -SimpleMediaSource::Shutdown( - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + RETURN_HR_IF_NULL(E_POINTER, pdwCharacteristics); + *pdwCharacteristics = 0; - _sourceState = SourceState::Shutdown; + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + *pdwCharacteristics = MFMEDIASOURCE_IS_LIVE; - _spAttributes.Reset(); - _spPresentationDescriptor.Reset(); + return S_OK; + } - if (_spEventQueue != nullptr) + IFACEMETHODIMP SimpleMediaSource::Pause() { - _spEventQueue->Shutdown(); - _spEventQueue.Reset(); + // Pause() not required/needed + return MF_E_INVALID_STATE_TRANSITION; } - if (_stream != nullptr) + + IFACEMETHODIMP SimpleMediaSource::Shutdown() { - _stream.Get()->Shutdown(); - _stream.Reset(); - } + winrt::slim_lock_guard lock(m_Lock); - return hr; -} + m_sourceState = SourceState::Shutdown; -IFACEMETHODIMP -SimpleMediaSource::Start( - _In_ IMFPresentationDescriptor *pPresentationDescriptor, - _In_opt_ const GUID *pguidTimeFormat, - _In_ const PROPVARIANT *pvarStartPos - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); - DWORD count = 0; - PROPVARIANT startTime; - BOOL selected = false; - ComPtr<IMFStreamDescriptor> streamDesc; - DWORD streamIndex = 0; + m_spAttributes.reset(); + m_spPresentationDescriptor.reset(); - if (pPresentationDescriptor == nullptr || pvarStartPos == nullptr) - { - return E_INVALIDARG; + if (m_spEventQueue != nullptr) + { + m_spEventQueue->Shutdown(); + m_spEventQueue.reset(); + } + + for(unsigned int i = 0; i < m_streamList.size(); i++) + { + m_streamList[i]->Shutdown(); + } + m_streamList.reset(); + + return S_OK; } - else if (pguidTimeFormat != nullptr && *pguidTimeFormat != GUID_NULL) + + IFACEMETHODIMP SimpleMediaSource::Start( + _In_ IMFPresentationDescriptor* pPresentationDescriptor, + _In_opt_ const GUID* pguidTimeFormat, + _In_ const PROPVARIANT* pvarStartPos + ) { - return MF_E_UNSUPPORTED_TIME_FORMAT; - } + winrt::slim_lock_guard lock(m_Lock); + DWORD count = 0; + wil::unique_prop_variant startTime; - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); + if (pPresentationDescriptor == nullptr || pvarStartPos == nullptr) + { + return E_INVALIDARG; + } - if (!(_sourceState != SourceState::Stopped || _sourceState != SourceState::Shutdown)) - { - return MF_E_INVALID_STATE_TRANSITION; - } + if (pguidTimeFormat != nullptr && *pguidTimeFormat != GUID_NULL) + { + return MF_E_UNSUPPORTED_TIME_FORMAT; + } - _sourceState = SourceState::Started; + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); - // This checks the passed in PresentationDescriptor matches the member of streams we - // have defined internally and that at least one stream is selected - RETURN_IF_FAILED (_ValidatePresentationDescriptor(pPresentationDescriptor)); - RETURN_IF_FAILED (pPresentationDescriptor->GetStreamDescriptorCount(&count)); - RETURN_IF_FAILED (InitPropVariantFromInt64(MFGetSystemTime(), &startTime)); + if (!(m_sourceState != SourceState::Stopped || m_sourceState != SourceState::Shutdown)) + { + return MF_E_INVALID_STATE_TRANSITION; + } + m_sourceState = SourceState::Started; - // Send event that the source started. Include error code in case it failed. - RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(MESourceStarted, - GUID_NULL, - hr, - &startTime)); + // This checks the passed in PresentationDescriptor matches the member of streams we + // have defined internally and that at least one stream is selected + RETURN_IF_FAILED(_ValidatePresentationDescriptor(pPresentationDescriptor)); + RETURN_IF_FAILED(pPresentationDescriptor->GetStreamDescriptorCount(&count)); + RETURN_IF_FAILED(InitPropVariantFromInt64(MFGetSystemTime(), &startTime)); - // We're hardcoding this to the first descriptor - // since this sample is a single stream sample. For - // multiple streams, we need to walk the list of streams - // and for each selected stream, send the MEUpdatedStream - // or MENewStream event along with the MEStreamStarted - // event. - RETURN_IF_FAILED (pPresentationDescriptor->GetStreamDescriptorByIndex(0, - &selected, - &streamDesc)); - RETURN_IF_FAILED (streamDesc->GetStreamIdentifier(&streamIndex)); - if (streamIndex >= NUM_STREAMS) - { - return MF_E_INVALIDSTREAMNUMBER; - } + // We're hardcoding this to the first descriptor + // since this sample is a single stream sample. For + // multiple streams, we need to walk the list of streams + // and for each selected stream, send the MEUpdatedStream + // or MENewStream event along with the MEStreamStarted + // event. + for (unsigned int i = 0; i < count; i++) + { + BOOL selected = false; + wil::com_ptr_nothrow<IMFStreamDescriptor> streamDesc; + RETURN_IF_FAILED(pPresentationDescriptor->GetStreamDescriptorByIndex( + i, + &selected, + &streamDesc)); - if (selected) - { - ComPtr<IUnknown> spunkStream; - MediaEventType met = (_wasStreamPreviouslySelected ? MEUpdatedStream : MENewStream); + DWORD streamId = 0; + RETURN_IF_FAILED(streamDesc->GetStreamIdentifier(&streamId)); - // Update our internal PresentationDescriptor - RETURN_IF_FAILED (_spPresentationDescriptor->SelectStream(streamIndex)); - RETURN_IF_FAILED (_stream.Get()->SetStreamState(MF_STREAM_STATE_RUNNING)); - RETURN_IF_FAILED (_stream.As(&spunkStream)); + DWORD streamIdx = 0; + bool wasSelected = false; + wil::com_ptr_nothrow<IMFStreamDescriptor> spLocalStreamDescriptor; + RETURN_IF_FAILED(_GetStreamDescriptorByStreamId(streamId, &streamIdx, &wasSelected, &spLocalStreamDescriptor)); + + if (selected) + { + // Update our internal PresentationDescriptor + RETURN_IF_FAILED(m_spPresentationDescriptor->SelectStream(streamIdx)); - // Send the MEUpdatedStream/MENewStream to our source event - // queue. - RETURN_IF_FAILED (_spEventQueue->QueueEventParamUnk(met, - GUID_NULL, - S_OK, - spunkStream.Get())); + // Update stream state + RETURN_IF_FAILED(m_streamList[streamIdx]->SetStreamState(MF_STREAM_STATE_RUNNING)); + RETURN_IF_FAILED(m_streamList[streamIdx]->Start()); - // But for our stream started (MEStreamStarted), we post to our - // stream event queue. - RETURN_IF_FAILED (_stream.Get()->QueueEvent(MEStreamStarted, - GUID_NULL, - S_OK, - &startTime)); - } - _wasStreamPreviouslySelected = selected; + // Send the MEUpdatedStream/MENewStream to our source event + // queue. + wil::com_ptr_nothrow<IUnknown> spunkStream; + MediaEventType met = (wasSelected ? MEUpdatedStream : MENewStream); + RETURN_IF_FAILED(m_streamList[streamIdx]->QueryInterface(IID_PPV_ARGS(&spunkStream))); + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamUnk( + met, + GUID_NULL, + S_OK, + spunkStream.get())); + } + else if(wasSelected) + { + // stream was previously selected but not selected this time. + RETURN_IF_FAILED(m_spPresentationDescriptor->DeselectStream(streamIdx)); + } + } - return hr; -} + // Send event that the source started. Include error code in case it failed. + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamVar( + MESourceStarted, + GUID_NULL, + S_OK, + &startTime)); -IFACEMETHODIMP -SimpleMediaSource::Stop( - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); - PROPVARIANT stopTime; - DWORD count = 0; - MF_STREAM_STATE state; + return S_OK; + } - if (_sourceState != SourceState::Started) + HRESULT SimpleMediaSource::_GetStreamDescriptorByStreamId(DWORD dwStreamId, DWORD* pdwStreamIdx, bool* pSelected, IMFStreamDescriptor** ppStreamDescriptor) { - return MF_E_INVALID_STATE_TRANSITION; - } + RETURN_HR_IF_NULL(E_POINTER, ppStreamDescriptor); + *ppStreamDescriptor = nullptr; + + RETURN_HR_IF_NULL(E_POINTER, pdwStreamIdx); + *pdwStreamIdx = 0; - _sourceState = SourceState::Stopped; + RETURN_HR_IF_NULL(E_POINTER, pSelected); + *pSelected = false; - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (InitPropVariantFromInt64(MFGetSystemTime(), &stopTime)); - RETURN_IF_FAILED (_spPresentationDescriptor->GetStreamDescriptorCount(&count)); + DWORD streamCount = 0; + RETURN_IF_FAILED(m_spPresentationDescriptor->GetStreamDescriptorCount(&streamCount)); + for (unsigned int i = 0; i < streamCount; i++) + { + wil::com_ptr_nothrow<IMFStreamDescriptor> spStreamDescriptor; + BOOL selected = FALSE; - // Deselect the streams and send the stream stopped events. - RETURN_IF_FAILED (_stream.Get()->GetStreamState(&state)); - _wasStreamPreviouslySelected = (state == MF_STREAM_STATE_RUNNING); - RETURN_IF_FAILED (_stream.Get()->SetStreamState(MF_STREAM_STATE_STOPPED)); - _spPresentationDescriptor->DeselectStream(0); - RETURN_IF_FAILED (_stream.Get()->QueueEvent(MEStreamStopped, GUID_NULL, hr, &stopTime)); - RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(MESourceStopped, GUID_NULL, hr, &stopTime)); + RETURN_IF_FAILED(m_spPresentationDescriptor->GetStreamDescriptorByIndex(i, &selected, &spStreamDescriptor)); - return hr; -} + DWORD id = 0; + RETURN_IF_FAILED(spStreamDescriptor->GetStreamIdentifier(&id)); -// IMFMediaSourceEx -IFACEMETHODIMP -SimpleMediaSource::GetSourceAttributes( - _COM_Outptr_ IMFAttributes** sourceAttributes - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + if (dwStreamId == id) + { + // Found the streamDescriptor with matching streamId + *pdwStreamIdx = i; + *pSelected = !!selected; + RETURN_IF_FAILED(spStreamDescriptor.copy_to(ppStreamDescriptor)); + return S_OK; + } + } - if (nullptr == sourceAttributes) - { - return E_POINTER; + return MF_E_NOT_FOUND; } - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - - *sourceAttributes = nullptr; - if (_spAttributes.Get() == nullptr) + IFACEMETHODIMP SimpleMediaSource::Stop() { - ComPtr<IMFSensorProfileCollection> profileCollection; - ComPtr<IMFSensorProfile> profile; - - // Create our source attribute store. - RETURN_IF_FAILED (MFCreateAttributes(_spAttributes.GetAddressOf(), 1)); + winrt::slim_lock_guard lock(m_Lock); - // Create an empty profile collection... - RETURN_IF_FAILED (MFCreateSensorProfileCollection(&profileCollection)); + if (m_sourceState != SourceState::Started) + { + return MF_E_INVALID_STATE_TRANSITION; + } + m_sourceState = SourceState::Stopped; - // In this example since we have just one stream, we only have one - // pin to add: Pin0. + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); - // Legacy profile is mandatory. This is to ensure non-profile - // aware applications can still function, but with degraded - // feature sets. - RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_Legacy, 0, nullptr, - profile.ReleaseAndGetAddressOf())); - RETURN_IF_FAILED (profile->AddProfileFilter(0, L"((RES==;FRT<=30,1;SUT==))")); - RETURN_IF_FAILED (profileCollection->AddProfile(profile.Get())); + wil::unique_prop_variant stopTime; + RETURN_IF_FAILED(InitPropVariantFromInt64(MFGetSystemTime(), &stopTime)); - // High Frame Rate profile will only allow >=60fps. - RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_HighFrameRate, 0, nullptr, - profile.ReleaseAndGetAddressOf())); - RETURN_IF_FAILED (profile->AddProfileFilter(0, L"((RES==;FRT>=60,1;SUT==))")); - RETURN_IF_FAILED (profileCollection->AddProfile(profile.Get())); + // Deselect the streams and send the stream stopped events. + for (unsigned int i = 0; i < m_streamList.size(); i++) + { + RETURN_IF_FAILED(m_streamList[i]->SetStreamState(MF_STREAM_STATE_STOPPED)); + RETURN_IF_FAILED(m_streamList[i]->Stop()); + RETURN_IF_FAILED(m_spPresentationDescriptor->DeselectStream(i)); + } + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamVar(MESourceStopped, GUID_NULL, S_OK, &stopTime)); - // Se the profile collection to the attribute store of the IMFTransform. - RETURN_IF_FAILED (_spAttributes->SetUnknown(MF_DEVICEMFT_SENSORPROFILE_COLLECTION, - profileCollection.Get())); + return S_OK; } - return _spAttributes.CopyTo(sourceAttributes); -} + // IMFMediaSourceEx + IFACEMETHODIMP SimpleMediaSource::GetSourceAttributes(_COM_Outptr_ IMFAttributes** sourceAttributes) + { + winrt::slim_lock_guard lock(m_Lock); + RETURN_HR_IF_NULL(E_POINTER, sourceAttributes); + *sourceAttributes = nullptr; -IFACEMETHODIMP -SimpleMediaSource::GetStreamAttributes( - DWORD dwStreamIdentifier, - _COM_Outptr_ IMFAttributes **ppAttributes - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); - if (ppAttributes == nullptr) - { - return E_POINTER; + RETURN_IF_FAILED(MFCreateAttributes(sourceAttributes, 1)); + RETURN_IF_FAILED(m_spAttributes->CopyAllItems(*sourceAttributes)); + + return S_OK; } - *ppAttributes = nullptr; - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - if (dwStreamIdentifier >= NUM_STREAMS) + IFACEMETHODIMP SimpleMediaSource::GetStreamAttributes( + _In_ DWORD dwStreamIdentifier, + _COM_Outptr_ IMFAttributes** ppAttributes + ) { - return MF_E_INVALIDSTREAMNUMBER; + winrt::slim_lock_guard lock(m_Lock); + + RETURN_HR_IF_NULL(E_POINTER, ppAttributes); + *ppAttributes = nullptr; + + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + + wil::com_ptr_nothrow<SimpleMediaStream> spStream; + RETURN_IF_FAILED(_GetMediaStreamById(dwStreamIdentifier, &spStream)); + RETURN_IF_FAILED(spStream->m_spAttributes.copy_to(ppAttributes)); + + return S_OK; } - else + + IFACEMETHODIMP SimpleMediaSource::SetD3DManager( + _In_opt_ IUnknown* /*pManager*/ + ) { - *ppAttributes = _stream.Get()->_spAttributes.Get(); - (*ppAttributes)->AddRef(); - } + // Return code is ignored by the frame work, this is a + // best effort attempt to inform the media source of the + // DXGI manager to use if DX surface support is available. - return hr; -} + return E_NOTIMPL; + } -IFACEMETHODIMP -SimpleMediaSource::SetD3DManager( - _In_opt_ IUnknown* /*pManager*/ - ) -{ - // Return code is ignored by the frame work, this is a - // best effort attempt to inform the media source of the - // DXGI manager to use if DX surface support is available. + // IMFGetService methods + _Use_decl_annotations_ + IFACEMETHODIMP SimpleMediaSource::GetService( + _In_ REFGUID guidService, + _In_ REFIID riid, + _Out_ LPVOID* ppvObject + ) + { + winrt::slim_lock_guard lock(m_Lock); - return E_NOTIMPL; -} + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); -// IMFGetService methods -_Use_decl_annotations_ -IFACEMETHODIMP -SimpleMediaSource::GetService( - _In_ REFGUID guidService, - _In_ REFIID riid, - _Out_ LPVOID * ppvObject - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + RETURN_HR_IF_NULL(E_POINTER, ppvObject); + *ppvObject = nullptr; - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); + // We have no supported service, just return + // MF_E_UNSUPPORTED_SERVICE for all calls. + return MF_E_UNSUPPORTED_SERVICE; + } - if (!ppvObject) + // IKsControl methods + _Use_decl_annotations_ + IFACEMETHODIMP SimpleMediaSource::KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Out_ ULONG* pBytesReturned + ) { - return E_POINTER; - } - *ppvObject = NULL; + if (ulPropertyLength < sizeof(KSPROPERTY)) + { + return E_INVALIDARG; + } + + // ERROR_SET_NOT_FOUND is the standard error code returned + // by the AV Stream driver framework when a miniport + // driver does not register a handler for a KS operation. + // We want to mimic the driver behavior here if we don't + // support controls. + if ((pProperty->Set != PROPSETID_SIMPLEMEDIASOURCE_CUSTOMCONTROL) || (pProperty->Id >= KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_END)) + { + return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); + } - // We have no supported service, just return - // MF_E_UNSUPPORTED_SERVICE for all calls. - return MF_E_UNSUPPORTED_SERVICE; -} + if (pPropertyData == NULL && ulDataLength == 0) + { + // + // If both PropertyData and DataLength, this function needs + // to return set BytesReturns to buffer size and + // return HRESULT_FROM_WIN32(ERROR_MORE_DATA) + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ks/nf-ks-ikscontrol-ksproperty + // + RETURN_HR_IF_NULL(E_POINTER, pBytesReturned); -// IKsControl methods -_Use_decl_annotations_ -IFACEMETHODIMP -SimpleMediaSource::KsProperty( - _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, - _In_ ULONG ulPropertyLength, - _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pPropertyData, - _In_ ULONG ulDataLength, - _Out_ ULONG* pBytesReturned - ) -{ - // ERROR_SET_NOT_FOUND is the standard error code returned - // by the AV Stream driver framework when a miniport - // driver does not register a handler for a KS operation. - // We want to mimic the driver behavior here if we don't - // support controls. - return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); -} + switch (pProperty->Id) + { + case KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE: + *pBytesReturned = sizeof(KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S); + break; -_Use_decl_annotations_ -IFACEMETHODIMP SimpleMediaSource::KsMethod( - _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod, - _In_ ULONG ulMethodLength, - _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pMethodData, - _In_ ULONG ulDataLength, - _Out_ ULONG* pBytesReturned - ) -{ - return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); -} + default: + return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); + break; + } + return HRESULT_FROM_WIN32(ERROR_MORE_DATA); + } + else + { + RETURN_HR_IF_NULL(E_POINTER, pPropertyData); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), ulDataLength == 0); + RETURN_HR_IF_NULL(E_POINTER, pBytesReturned); -_Use_decl_annotations_ -IFACEMETHODIMP SimpleMediaSource::KsEvent( - _In_reads_bytes_opt_(ulEventLength) PKSEVENT pEvent, - _In_ ULONG ulEventLength, - _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pEventData, - _In_ ULONG ulDataLength, - _Out_opt_ ULONG* pBytesReturned - ) -{ - return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); -} + // validate properyData length + switch (pProperty->Id) + { + case KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE: + if (ulDataLength < sizeof(KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S)) + { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } -/// Internal methods. -HRESULT -SimpleMediaSource::_CheckShutdownRequiresLock( - ) -{ - if (_sourceState == SourceState::Shutdown) + // Set operation + if (0 != (pProperty->Flags & (KSPROPERTY_TYPE_SET))) + { + DEBUG_MSG(L"Set filter level KSProperty"); + *pBytesReturned = 0; + for (size_t i = 0; i < m_streamList.size(); i++) + { + m_streamList[i]->SetRGBMask(((PKSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S)pPropertyData)->ColorMode); + *pBytesReturned = sizeof(KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S); + } + } + // Get operation + else if (0 != (pProperty->Flags & (KSPROPERTY_TYPE_GET))) + { + DEBUG_MSG(L"Get filter level KSProperty"); + ((PKSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S)pPropertyData)->ColorMode = m_streamList[0]->GetRGBMask(); + *pBytesReturned = sizeof(KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S); + } + else + { + return E_INVALIDARG; + } + break; + + default: + break; + } + } + + return S_OK; + } + + _Use_decl_annotations_ + IFACEMETHODIMP SimpleMediaSource::KsMethod( + _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod, + _In_ ULONG ulMethodLength, + _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pMethodData, + _In_ ULONG ulDataLength, + _Out_ ULONG* pBytesReturned + ) { - return MF_E_SHUTDOWN; + return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); } - if (_spEventQueue == nullptr || _stream == nullptr) + _Use_decl_annotations_ + IFACEMETHODIMP SimpleMediaSource::KsEvent( + _In_reads_bytes_opt_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned + ) { - return E_UNEXPECTED; + return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND); } - return S_OK; -} + IFACEMETHODIMP SimpleMediaSource::SetDefaultAllocator( + _In_ DWORD dwOutputStreamID, + _In_ IUnknown* pAllocator) + { + winrt::slim_lock_guard lock(m_Lock); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); -HRESULT -SimpleMediaSource::_ValidatePresentationDescriptor( - _In_ IMFPresentationDescriptor *pPD - ) -{ - HRESULT hr = S_OK; - DWORD cStreams = 0; - bool anySelected = false; + wil::com_ptr_nothrow<IMFVideoSampleAllocator> spAllocator; + RETURN_IF_FAILED(pAllocator->QueryInterface(IID_PPV_ARGS(&spAllocator))); + + wil::com_ptr_nothrow<SimpleMediaStream> spStream; + RETURN_IF_FAILED(_GetMediaStreamById(dwOutputStreamID, &spStream)); + RETURN_IF_FAILED(spStream->SetSampleAllocator(spAllocator.get())); - if (pPD == nullptr) + return S_OK; + } + + IFACEMETHODIMP SimpleMediaSource::GetAllocatorUsage( + _In_ DWORD dwOutputStreamID, + _Out_ DWORD* pdwInputStreamID, + _Out_ MFSampleAllocatorUsage* peUsage) { - return E_INVALIDARG; + winrt::slim_lock_guard lock(m_Lock); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + + RETURN_HR_IF_NULL(E_POINTER, pdwInputStreamID); + RETURN_HR_IF_NULL(E_POINTER, peUsage); + + wil::com_ptr_nothrow<SimpleMediaStream> spStream; + RETURN_IF_FAILED(_GetMediaStreamById(dwOutputStreamID, &spStream)); + + *peUsage = spStream->SampleAlloactorUsage(); + *pdwInputStreamID = dwOutputStreamID; + + return S_OK; } - // The caller's PD must have the same number of streams as ours. - RETURN_IF_FAILED (pPD->GetStreamDescriptorCount(&cStreams)); - if (SUCCEEDED(hr) && (cStreams != NUM_STREAMS)) + /// Internal methods. + HRESULT SimpleMediaSource::_CheckShutdownRequiresLock() { - return E_INVALIDARG; + if (m_sourceState == SourceState::Shutdown) + { + return MF_E_SHUTDOWN; + } + + if (m_spEventQueue == nullptr || m_streamList.get() == nullptr) + { + return E_UNEXPECTED; + } + + return S_OK; } - // The caller must select at least one stream. - for (UINT32 i = 0; i < cStreams; ++i) + HRESULT SimpleMediaSource::_ValidatePresentationDescriptor(_In_ IMFPresentationDescriptor* pPD) { - ComPtr<IMFStreamDescriptor> spSD; - BOOL fSelected = FALSE; - DWORD dwId = 0; + DWORD cStreams = 0; + bool anySelected = false; + + RETURN_HR_IF_NULL(E_INVALIDARG, pPD); + + // The caller's PD must have the same number of streams as ours. + RETURN_IF_FAILED(pPD->GetStreamDescriptorCount(&cStreams)); + if (cStreams != m_streamList.size()) + { + return E_INVALIDARG; + } - RETURN_IF_FAILED (pPD->GetStreamDescriptorByIndex(i, &fSelected, &spSD)); + // The caller must select at least one stream. + for (UINT32 i = 0; i < cStreams; ++i) + { + wil::com_ptr_nothrow<IMFStreamDescriptor> spSD; + BOOL fSelected = FALSE; - anySelected |= !!fSelected; + RETURN_IF_FAILED(pPD->GetStreamDescriptorByIndex(i, &fSelected, &spSD)); + anySelected |= !!fSelected; + } - RETURN_IF_FAILED (spSD->GetStreamIdentifier(&dwId)); - if (dwId >= NUM_STREAMS) + if (!anySelected) { return E_INVALIDARG; } + + return S_OK; } - if (!anySelected) + HRESULT SimpleMediaSource::_CreateSourceAttributes() { - return E_INVALIDARG; + if (m_spAttributes.get() == nullptr) + { + // Create our source attribute store. + RETURN_IF_FAILED(MFCreateAttributes(&m_spAttributes, 1)); + + wil::com_ptr_nothrow<IMFSensorProfileCollection> profileCollection; + wil::com_ptr_nothrow<IMFSensorProfile> profile; + + // Create an empty profile collection... + RETURN_IF_FAILED(MFCreateSensorProfileCollection(&profileCollection)); + + // In this example since we have just one stream, we only have one + // pin to add: Pin = STREAM_ID. + + // Legacy profile is mandatory. This is to ensure non-profile + // aware applications can still function, but with degraded + // feature sets. + const DWORD STREAM_ID = 0; + RETURN_IF_FAILED(MFCreateSensorProfile(KSCAMERAPROFILE_Legacy, 0 /*ProfileIndex*/, nullptr, + &profile)); + RETURN_IF_FAILED(profile->AddProfileFilter(STREAM_ID, L"((RES==;FRT<=30,1;SUT==))")); + RETURN_IF_FAILED(profileCollection->AddProfile(profile.get())); + + // High Frame Rate profile will only allow >=60fps. + RETURN_IF_FAILED(MFCreateSensorProfile(KSCAMERAPROFILE_HighFrameRate, 0 /*ProfileIndex*/, nullptr, + &profile)); + RETURN_IF_FAILED(profile->AddProfileFilter(STREAM_ID, L"((RES==;FRT>=60,1;SUT==))")); + RETURN_IF_FAILED(profileCollection->AddProfile(profile.get())); + + + // Se the profile collection to the attribute store of the IMFTransform. + RETURN_IF_FAILED(m_spAttributes->SetUnknown( + MF_DEVICEMFT_SENSORPROFILE_COLLECTION, + profileCollection.get())); + } + + return S_OK; } - return hr; -} + HRESULT SimpleMediaSource::_GetMediaStreamById(_In_ DWORD dwStreamId, _COM_Outptr_ SimpleMediaStream** ppStream) + { + RETURN_HR_IF_NULL(E_POINTER, ppStream); + *ppStream = nullptr; + for (unsigned int i = 0; i < m_streamList.size(); i++) + { + if (m_streamList[i]->Id() == dwStreamId) + { + *ppStream = m_streamList[i]; + (*ppStream)->AddRef(); + return S_OK; + } + } + return MF_E_NOT_FOUND; + } +} diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h index 019926c8..10ac200b 100644 --- a/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h +++ b/general/SimpleMediaSource/MediaSource/SimpleMediaSource.h @@ -1,81 +1,120 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// #pragma once +#ifndef SIMPLEMEDIASOURCE_H +#define SIMPLEMEDIASOURCE_H -// Represents a simple media source that only has one stream and outputs a static image +// Example Custom Property implemented by SimpleMediaSource +// +// {0CE2EF73-4800-4F53-9B8E-8C06790FC0C7} +static const GUID PROPSETID_SIMPLEMEDIASOURCE_CUSTOMCONTROL = +{ 0xce2ef73, 0x4800, 0x4f53, { 0x9b, 0x8e, 0x8c, 0x6, 0x79, 0xf, 0xc0, 0xc7 } }; -#include "stdafx.h" +enum +{ + KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE = 0, + KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_END // all ids must define before this. +}; -class SimpleMediaStream; +#define KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_GRAYSCALE 0x00FFFFFFL +#define KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_RED 0x00FF0000L +#define KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_GREEN 0x0000FF00L +#define KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_BLUE 0x000000FFL -class __declspec(uuid("{9812588D-5CE9-4E4C-ABC1-049138D10DCE}")) -SimpleMediaSource : public RuntimeClass< - RuntimeClassFlags<WinRtClassicComMix>, - IMFMediaEventGenerator, - IMFMediaSource, - IMFMediaSourceEx, - IMFGetService, - IKsControl> -{ +typedef struct { + ULONG StremID; + ULONG ColorMode; +} KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S, * PKSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_S; - enum class SourceState +namespace winrt::WindowsSample::implementation +{ + // forward declaration + struct SimpleMediaStream; + + struct SimpleMediaSource : winrt::implements<SimpleMediaSource, IMFMediaSourceEx, IMFGetService, IKsControl, IMFSampleAllocatorControl> { - Invalid, Stopped, Started, Shutdown - }; + SimpleMediaSource() = default; -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); + private: + enum class SourceState + { + Invalid, Stopped, Started, Shutdown + }; - // 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)(); + public: + // IMFMediaEventGenerator (inherits by IMFMediaSource) + IFACEMETHODIMP BeginGetEvent(_In_ IMFAsyncCallback* pCallback, _In_ IUnknown* punkState) override; + IFACEMETHODIMP EndGetEvent(_In_ IMFAsyncResult* pResult, _Out_ IMFMediaEvent** ppEvent) override; + IFACEMETHODIMP GetEvent(DWORD dwFlags, _Out_ IMFMediaEvent** ppEvent) override; + IFACEMETHODIMP QueueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, _In_ const PROPVARIANT* pvValue) override; - // IMFMediaSourceEx - IFACEMETHOD(GetSourceAttributes)(_COM_Outptr_ IMFAttributes **ppAttributes); - IFACEMETHOD(GetStreamAttributes)(DWORD dwStreamIdentifier, _COM_Outptr_ IMFAttributes **ppAttributes); - IFACEMETHOD(SetD3DManager)(_In_opt_ IUnknown *pManager); + // IMFMediaSource (inherits by IMFMediaSourceEx) + IFACEMETHODIMP CreatePresentationDescriptor(_Out_ IMFPresentationDescriptor** ppPresentationDescriptor) override; + IFACEMETHODIMP GetCharacteristics(_Out_ DWORD* pdwCharacteristics) override; + IFACEMETHODIMP Pause() override; + IFACEMETHODIMP Shutdown() override; + IFACEMETHODIMP Start(_In_ IMFPresentationDescriptor* pPresentationDescriptor, _In_ const GUID* pguidTimeFormat, _In_ const PROPVARIANT* pvarStartPosition) override; + IFACEMETHODIMP Stop() override; - // IMFGetService - IFACEMETHOD(GetService)(_In_ REFGUID guidService, _In_ REFIID riid, _Out_ LPVOID *ppvObject); + // IMFMediaSourceEx + IFACEMETHODIMP GetSourceAttributes(_COM_Outptr_ IMFAttributes** ppAttributes) override; + IFACEMETHODIMP GetStreamAttributes(DWORD dwStreamIdentifier, _COM_Outptr_ IMFAttributes** ppAttributes) override; + IFACEMETHODIMP SetD3DManager(_In_opt_ IUnknown* pManager) override; - // IKsControl - IFACEMETHOD(KsProperty)(_In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, - _In_ ULONG ulPropertyLength, - _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pPropertyData, - _In_ ULONG ulDataLength, - _Out_ ULONG* pBytesReturned); - IFACEMETHOD(KsMethod)(_In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod, - _In_ ULONG ulMethodLength, - _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pMethodData, - _In_ ULONG ulDataLength, - _Out_ ULONG* pBytesReturned); - IFACEMETHOD(KsEvent)(_In_reads_bytes_opt_(ulEventLength) PKSEVENT pEvent, - _In_ ULONG ulEventLength, - _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pEventData, - _In_ ULONG ulDataLength, - _Out_opt_ ULONG* pBytesReturned); -public: - HRESULT RuntimeClassInitialize(); + // IMFGetService + IFACEMETHODIMP GetService(_In_ REFGUID guidService, _In_ REFIID riid, _Out_ LPVOID* ppvObject) override; -private: - HRESULT _CheckShutdownRequiresLock(); - HRESULT _ValidatePresentationDescriptor(_In_ IMFPresentationDescriptor *pPresentationDescriptor); + // IKsControl + IFACEMETHODIMP KsProperty( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Out_ ULONG* pBytesReturned) override; + IFACEMETHODIMP KsMethod( + _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod, + _In_ ULONG ulMethodLength, + _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pMethodData, + _In_ ULONG ulDataLength, + _Out_ ULONG* pBytesReturned) override; + IFACEMETHODIMP KsEvent( + _In_reads_bytes_opt_(ulEventLength) PKSEVENT pEvent, + _In_ ULONG ulEventLength, + _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pEventData, + _In_ ULONG ulDataLength, + _Out_opt_ ULONG* pBytesReturned) override; - CriticalSection _critSec; - SourceState _sourceState{ SourceState::Invalid }; - ComPtr<IMFMediaEventQueue> _spEventQueue; - ComPtr<IMFPresentationDescriptor> _spPresentationDescriptor; - ComPtr<IMFAttributes> _spAttributes; + // IMFSampleAllocatorControl + IFACEMETHODIMP SetDefaultAllocator( + _In_ DWORD dwOutputStreamID, + _In_ IUnknown* pAllocator) override; - bool _wasStreamPreviouslySelected; // maybe makes more sense as a property of the stream - const DWORD NUM_STREAMS = 1; - ComPtr<SimpleMediaStream> _stream; -}; + IFACEMETHODIMP GetAllocatorUsage( + _In_ DWORD dwOutputStreamID, + _Out_ DWORD* pdwInputStreamID, + _Out_ MFSampleAllocatorUsage* peUsage) override; + + // Non-Interface functions + HRESULT Initialize(); + + private: + HRESULT _CheckShutdownRequiresLock(); + HRESULT _ValidatePresentationDescriptor(_In_ IMFPresentationDescriptor* pPresentationDescriptor); + HRESULT _CreateSourceAttributes(); + HRESULT _GetStreamDescriptorByStreamId(_In_ DWORD dwStreamId, _Out_ DWORD* pdwStreamIdx, _Out_ bool* pSelected, _COM_Outptr_ IMFStreamDescriptor** ppStreamDescriptor); + HRESULT _GetMediaStreamById(_In_ DWORD dwStreamId, _COM_Outptr_ SimpleMediaStream** ppMediaStream); + + winrt::slim_mutex m_Lock; + SourceState m_sourceState{ SourceState::Invalid }; + + wil::com_ptr_nothrow<IMFMediaEventQueue> m_spEventQueue; + wil::com_ptr_nothrow<IMFPresentationDescriptor> m_spPresentationDescriptor; + wil::com_ptr_nothrow<IMFAttributes> m_spAttributes; + wil::unique_cotaskmem_array_ptr<wil::com_ptr_nothrow<SimpleMediaStream>> m_streamList; + + const DWORD NUM_STREAMS = 1; + }; +} -CoCreatableClass(SimpleMediaSource); +#endif diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaSourceActivate.cpp b/general/SimpleMediaSource/MediaSource/SimpleMediaSourceActivate.cpp new file mode 100644 index 00000000..16abd28d --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/SimpleMediaSourceActivate.cpp @@ -0,0 +1,245 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// +#include "pch.h" + +namespace winrt::WindowsSample::implementation +{ + // IMFActivate + IFACEMETHODIMP SimpleMediaSourceActivate::ActivateObject(REFIID riid, void** ppv) + { + RETURN_HR_IF_NULL(E_POINTER, ppv); + *ppv = nullptr; + + wil::com_ptr_nothrow<IMFAttributes> spAttributes; + RETURN_IF_FAILED(MFCreateAttributes(&spAttributes, 1)); + + DEBUG_MSG(L"Activate SimpleMediaSource"); + m_spSimpleMediaSrc = winrt::make_self<winrt::WindowsSample::implementation::SimpleMediaSource>(); + RETURN_IF_FAILED(m_spSimpleMediaSrc->Initialize()); + RETURN_IF_FAILED(m_spSimpleMediaSrc->QueryInterface(riid, ppv)); + + return S_OK; + } + + IFACEMETHODIMP SimpleMediaSourceActivate::ShutdownObject() + { + return S_OK; + } + + IFACEMETHODIMP SimpleMediaSourceActivate::DetachObject() + { + m_spSimpleMediaSrc = nullptr; + return S_OK; + } + + // IMFAttributes (inherits by IMFActivate) + IFACEMETHODIMP SimpleMediaSourceActivate::GetItem(_In_ REFGUID guidKey, _Inout_opt_ PROPVARIANT* pValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetItem(guidKey, pValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetItemType(_In_ REFGUID guidKey, _Out_ MF_ATTRIBUTE_TYPE* pType) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetItemType(guidKey, pType); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::CompareItem(_In_ REFGUID guidKey, _In_ REFPROPVARIANT Value, _Out_ BOOL* pbResult) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->CompareItem(guidKey, Value, pbResult); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::Compare(_In_ IMFAttributes* pTheirs, _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType, _Out_ BOOL* pbResult) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->Compare(pTheirs, MatchType, pbResult); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetUINT32(_In_ REFGUID guidKey, _Out_ UINT32* punValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetUINT32(guidKey, punValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetUINT64(_In_ REFGUID guidKey, _Out_ UINT64* punValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetUINT64(guidKey, punValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetDouble(_In_ REFGUID guidKey, _Out_ double* pfValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetDouble(guidKey, pfValue); + } + IFACEMETHODIMP SimpleMediaSourceActivate::GetGUID(_In_ REFGUID guidKey, _Out_ GUID* pguidValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetGUID(guidKey, pguidValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetStringLength(_In_ REFGUID guidKey, _Out_ UINT32* pcchLength) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetStringLength(guidKey, pcchLength); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetString(_In_ REFGUID guidKey, _Out_writes_(cchBufSize) LPWSTR pwszValue, _In_ UINT32 cchBufSize, _Inout_opt_ UINT32* pcchLength) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetAllocatedString(_In_ REFGUID guidKey, _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue, _Inout_ UINT32* pcchLength) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetBlobSize(_In_ REFGUID guidKey, _Out_ UINT32* pcbBlobSize) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetBlobSize(guidKey, pcbBlobSize); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetBlob(_In_ REFGUID guidKey, _Out_writes_(cbBufSize) UINT8* pBuf, UINT32 cbBufSize, _Inout_ UINT32* pcbBlobSize) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetAllocatedBlob(__RPC__in REFGUID guidKey, __RPC__deref_out_ecount_full_opt(*pcbSize) UINT8** ppBuf, __RPC__out UINT32* pcbSize) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetUnknown(__RPC__in REFGUID guidKey, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppv) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetUnknown(guidKey, riid, ppv); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetItem(_In_ REFGUID guidKey, _In_ REFPROPVARIANT Value) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetItem(guidKey, Value); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::DeleteItem(_In_ REFGUID guidKey) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->DeleteItem(guidKey); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::DeleteAllItems() + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->DeleteAllItems(); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetUINT32(_In_ REFGUID guidKey, _In_ UINT32 unValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetUINT32(guidKey, unValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetUINT64(_In_ REFGUID guidKey, _In_ UINT64 unValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetUINT64(guidKey, unValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetDouble(_In_ REFGUID guidKey, _In_ double fValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetDouble(guidKey, fValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetGUID(_In_ REFGUID guidKey, _In_ REFGUID guidValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetGUID(guidKey, guidValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetString(_In_ REFGUID guidKey, _In_ LPCWSTR wszValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetString(guidKey, wszValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetBlob(_In_ REFGUID guidKey, _In_reads_(cbBufSize) const UINT8* pBuf, UINT32 cbBufSize) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetBlob(guidKey, pBuf, cbBufSize); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::SetUnknown(_In_ REFGUID guidKey, _In_ IUnknown* pUnknown) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->SetUnknown(guidKey, pUnknown); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::LockStore() + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->LockStore(); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::UnlockStore() + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->UnlockStore(); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetCount(_Out_ UINT32* pcItems) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetCount(pcItems); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::GetItemByIndex(UINT32 unIndex, _Out_ GUID* pguidKey, _Inout_ PROPVARIANT* pValue) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->GetItemByIndex(unIndex, pguidKey, pValue); + } + + IFACEMETHODIMP SimpleMediaSourceActivate::CopyAllItems(_In_ IMFAttributes* pDest) + { + if (!m_spActivateAttributes) + RETURN_IF_FAILED(MFCreateAttributes(&m_spActivateAttributes, 1)); + return m_spActivateAttributes->CopyAllItems(pDest); + } +} diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaSourceActivate.h b/general/SimpleMediaSource/MediaSource/SimpleMediaSourceActivate.h new file mode 100644 index 00000000..f206e6d9 --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/SimpleMediaSourceActivate.h @@ -0,0 +1,82 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// +#pragma once +#ifndef SIMPLEMEDIASOURCEACTIVATE_H +#define SIMPLEMEDIASOURCEACTIVATE_H + +namespace winrt::WindowsSample::implementation +{ + struct __declspec(uuid("9812588D-5CE9-4E4C-ABC1-049138D10DCE")) + SimpleMediaSourceActivate : winrt::implements<SimpleMediaSourceActivate, IMFActivate> + { + SimpleMediaSourceActivate() = default; + + public: + // IMFActivate + IFACEMETHODIMP ActivateObject(REFIID riid, void** ppv) override; + IFACEMETHODIMP ShutdownObject() override; + IFACEMETHODIMP DetachObject() override; + + // IMFAttributes (inherits by IMFActivate) + IFACEMETHODIMP GetItem(_In_ REFGUID guidKey, _Inout_opt_ PROPVARIANT* pValue) override; + IFACEMETHODIMP GetItemType(_In_ REFGUID guidKey, _Out_ MF_ATTRIBUTE_TYPE* pType) override; + IFACEMETHODIMP CompareItem(_In_ REFGUID guidKey, _In_ REFPROPVARIANT Value, _Out_ BOOL* pbResult) override; + IFACEMETHODIMP Compare(_In_ IMFAttributes* pTheirs, _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType, _Out_ BOOL* pbResult) override; + IFACEMETHODIMP GetUINT32(_In_ REFGUID guidKey, _Out_ UINT32* punValue) override; + IFACEMETHODIMP GetUINT64(_In_ REFGUID guidKey, _Out_ UINT64* punValue) override; + IFACEMETHODIMP GetDouble(_In_ REFGUID guidKey, _Out_ double* pfValue) override; + IFACEMETHODIMP GetGUID(_In_ REFGUID guidKey, _Out_ GUID* pguidValue) override; + IFACEMETHODIMP GetStringLength(_In_ REFGUID guidKey, _Out_ UINT32* pcchLength) override; + IFACEMETHODIMP GetString(_In_ REFGUID guidKey, _Out_writes_(cchBufSize) LPWSTR pwszValue, _In_ UINT32 cchBufSize, _Inout_opt_ UINT32* pcchLength) override; + IFACEMETHODIMP GetAllocatedString(_In_ REFGUID guidKey, _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue, _Inout_ UINT32* pcchLength) override; + IFACEMETHODIMP GetBlobSize(_In_ REFGUID guidKey, _Out_ UINT32* pcbBlobSize) override; + IFACEMETHODIMP GetBlob(_In_ REFGUID guidKey, _Out_writes_(cbBufSize) UINT8* pBuf, UINT32 cbBufSize, _Inout_ UINT32* pcbBlobSize) override; + IFACEMETHODIMP GetAllocatedBlob(__RPC__in REFGUID guidKey, __RPC__deref_out_ecount_full_opt(*pcbSize) UINT8** ppBuf, __RPC__out UINT32* pcbSize) override; + IFACEMETHODIMP GetUnknown(__RPC__in REFGUID guidKey, __RPC__in REFIID riid, __RPC__deref_out_opt LPVOID* ppv) override; + IFACEMETHODIMP SetItem(_In_ REFGUID guidKey, _In_ REFPROPVARIANT Value) override; + IFACEMETHODIMP DeleteItem(_In_ REFGUID guidKey) override; + IFACEMETHODIMP DeleteAllItems() override; + IFACEMETHODIMP SetUINT32(_In_ REFGUID guidKey, _In_ UINT32 unValue) override; + IFACEMETHODIMP SetUINT64(_In_ REFGUID guidKey, _In_ UINT64 unValue) override; + IFACEMETHODIMP SetDouble(_In_ REFGUID guidKey, _In_ double fValue) override; + IFACEMETHODIMP SetGUID(_In_ REFGUID guidKey, _In_ REFGUID guidValue) override; + IFACEMETHODIMP SetString(_In_ REFGUID guidKey, _In_ LPCWSTR wszValue) override; + IFACEMETHODIMP SetBlob(_In_ REFGUID guidKey, _In_reads_(cbBufSize) const UINT8* pBuf, UINT32 cbBufSize) override; + IFACEMETHODIMP SetUnknown(_In_ REFGUID guidKey, _In_ IUnknown* pUnknown) override; + IFACEMETHODIMP LockStore() override; + IFACEMETHODIMP UnlockStore() override; + IFACEMETHODIMP GetCount(_Out_ UINT32* pcItems) override; + IFACEMETHODIMP GetItemByIndex(UINT32 unIndex, _Out_ GUID* pguidKey, _Inout_ PROPVARIANT* pValue) override; + IFACEMETHODIMP CopyAllItems(_In_ IMFAttributes* pDest) override; + + private: + wil::com_ptr_nothrow <IMFAttributes> m_spActivateAttributes; + winrt::com_ptr<winrt::WindowsSample::implementation::SimpleMediaSource> m_spSimpleMediaSrc; + }; +} + +// +// cocreatable class +// +struct SimpleMediaSourceActivateFactory : public winrt::implements<SimpleMediaSourceActivateFactory, IClassFactory> +{ +public: + STDMETHODIMP CreateInstance(_In_ IUnknown*, _In_ REFIID riid, _COM_Outptr_ void** result) noexcept final try + { + RETURN_HR_IF_NULL(E_POINTER, result); + *result = nullptr; + + winrt::com_ptr<winrt::WindowsSample::implementation::SimpleMediaSourceActivate> ptr = winrt::make_self<winrt::WindowsSample::implementation::SimpleMediaSourceActivate>(); + return ptr->QueryInterface(riid, result); + } CATCH_RETURN() + + + STDMETHODIMP LockServer(BOOL) noexcept final + { + return S_OK; + } +}; + + +#endif diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp index 7685b12e..c22d7421 100644 --- a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp +++ b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.cpp @@ -1,391 +1,403 @@ -#include "stdafx.h" +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// -#define NUM_IMAGE_ROWS 240 -#define NUM_IMAGE_COLS 320 +#include "pch.h" + +#define NUM_IMAGE_ROWS 480 +#define NUM_IMAGE_COLS 640 #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) -HRESULT -SimpleMediaStream::RuntimeClassInitialize( - _In_ SimpleMediaSource *pSource - ) +namespace winrt::WindowsSample::implementation { - HRESULT hr = S_OK; - ComPtr<IMFMediaTypeHandler> spTypeHandler; - ComPtr<IMFAttributes> attrs; - - if (nullptr == pSource) + HRESULT SimpleMediaStream::Initialize( + _In_ SimpleMediaSource* pSource, + _In_ DWORD dwStreamId, + _In_ MFSampleAllocatorUsage allocatorUsage + ) { - return E_INVALIDARG; - } - RETURN_IF_FAILED (pSource->QueryInterface(IID_PPV_ARGS(&_parent))); + wil::com_ptr_nothrow<IMFMediaTypeHandler> spTypeHandler; + wil::com_ptr_nothrow<IMFAttributes> attrs; - // Initialize media type and set the video output media type. - RETURN_IF_FAILED (MFCreateMediaType(&_spMediaType)); - _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); + RETURN_HR_IF_NULL(E_INVALIDARG, pSource); + m_parent = pSource; - RETURN_IF_FAILED (MFCreateAttributes(&_spAttributes, 10)); - RETURN_IF_FAILED (this->_SetStreamAttributes(_spAttributes.Get())); - RETURN_IF_FAILED (MFCreateEventQueue(&_spEventQueue)); + m_dwStreamId = dwStreamId; + m_allocatorUsage = allocatorUsage; - // Initialize stream descriptors - RETURN_IF_FAILED (MFCreateStreamDescriptor(0, 1, _spMediaType.GetAddressOf(), &_spStreamDesc)); + const uint32_t NUM_MEDIATYPES = 2; + wil::unique_cotaskmem_array_ptr<wil::com_ptr_nothrow<IMFMediaType>> mediaTypeList = wilEx::make_unique_cotaskmem_array<wil::com_ptr_nothrow<IMFMediaType>>(NUM_MEDIATYPES); - RETURN_IF_FAILED (_spStreamDesc->GetMediaTypeHandler(&spTypeHandler)); - RETURN_IF_FAILED (spTypeHandler->SetCurrentMediaType(_spMediaType.Get())); - RETURN_IF_FAILED (this->_SetStreamDescriptorAttributes(_spStreamDesc.Get())); - - return hr; -} + // Initialize media type and set the video output media type. + wil::com_ptr_nothrow<IMFMediaType> spMediaType; + RETURN_IF_FAILED(MFCreateMediaType(&spMediaType)); + spMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); + spMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12); + 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); + // frame size * pixle bit size * framerate + uint32_t bitrate = (uint32_t)(NUM_IMAGE_COLS * 1.5 * NUM_IMAGE_ROWS * 8* 30); + spMediaType->SetUINT32(MF_MT_AVG_BITRATE, bitrate); + MFSetAttributeRatio(spMediaType.get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); + mediaTypeList[0] = spMediaType.detach(); -// IMFMediaEventGenerator -IFACEMETHODIMP -SimpleMediaStream::BeginGetEvent( - _In_ IMFAsyncCallback *pCallback, - _In_ IUnknown *punkState - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + RETURN_IF_FAILED(MFCreateMediaType(&spMediaType)); + 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); + // frame size * pixle bit size * framerate + bitrate = NUM_IMAGE_COLS * NUM_IMAGE_ROWS * 4 * 8* 30; + spMediaType->SetUINT32(MF_MT_AVG_BITRATE, bitrate); + MFSetAttributeRatio(spMediaType.get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1); + mediaTypeList[1] = spMediaType.detach(); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spEventQueue->BeginGetEvent(pCallback, punkState)); + RETURN_IF_FAILED(MFCreateAttributes(&m_spAttributes, 10)); + RETURN_IF_FAILED(_SetStreamAttributes(m_spAttributes.get())); - return hr; -} + RETURN_IF_FAILED(MFCreateEventQueue(&m_spEventQueue)); -IFACEMETHODIMP -SimpleMediaStream::EndGetEvent( - _In_ IMFAsyncResult *pResult, - _COM_Outptr_ IMFMediaEvent **ppEvent - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + // Initialize stream descriptors + RETURN_IF_FAILED(MFCreateStreamDescriptor(m_dwStreamId /*StreamId*/, NUM_MEDIATYPES /*MT count*/, mediaTypeList.get(), &m_spStreamDesc)); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spEventQueue->EndGetEvent(pResult, ppEvent)); + RETURN_IF_FAILED(m_spStreamDesc->GetMediaTypeHandler(&spTypeHandler)); + RETURN_IF_FAILED(spTypeHandler->SetCurrentMediaType(mediaTypeList[0])); + RETURN_IF_FAILED(_SetStreamDescriptorAttributes(m_spStreamDesc.get())); - return hr; -} + return S_OK; + } -IFACEMETHODIMP -SimpleMediaStream::GetEvent( - DWORD dwFlags, - _COM_Outptr_ IMFMediaEvent **ppEvent - ) -{ - // NOTE: - // GetEvent can block indefinitely, so we don't hold the lock. - // This requires some juggling with the event queue pointer. + // IMFMediaEventGenerator + IFACEMETHODIMP SimpleMediaStream::BeginGetEvent( + _In_ IMFAsyncCallback* pCallback, + _In_ IUnknown* punkState + ) + { + winrt::slim_lock_guard lock(m_Lock); - HRESULT hr = S_OK; + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spEventQueue->BeginGetEvent(pCallback, punkState)); - ComPtr<IMFMediaEventQueue> spQueue; + return S_OK; + } + IFACEMETHODIMP SimpleMediaStream::EndGetEvent( + _In_ IMFAsyncResult* pResult, + _COM_Outptr_ IMFMediaEvent** ppEvent + ) { - auto lock = _critSec.Lock(); + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - spQueue = _spEventQueue; + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spEventQueue->EndGetEvent(pResult, ppEvent)); + + return S_OK; } - // Now get the event. - RETURN_IF_FAILED (_spEventQueue->GetEvent(dwFlags, ppEvent)); + IFACEMETHODIMP SimpleMediaStream::GetEvent( + _In_ DWORD dwFlags, + _COM_Outptr_ IMFMediaEvent** ppEvent + ) + { + // NOTE: + // GetEvent can block indefinitely, so we don't hold the lock. + // This requires some juggling with the event queue pointer. - return hr; -} + wil::com_ptr_nothrow<IMFMediaEventQueue> spQueue; -IFACEMETHODIMP -SimpleMediaStream::QueueEvent( - MediaEventType eventType, - REFGUID guidExtendedType, - HRESULT hrStatus, - _In_opt_ PROPVARIANT const *pvValue - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + { + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue)); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + spQueue = m_spEventQueue; + } - return hr; -} + // Now get the event. + RETURN_IF_FAILED(spQueue->GetEvent(dwFlags, ppEvent)); -// IMFMediaStream -IFACEMETHODIMP -SimpleMediaStream::GetMediaSource( - _COM_Outptr_ IMFMediaSource **ppMediaSource - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + return S_OK; + } - if (ppMediaSource == nullptr) + IFACEMETHODIMP SimpleMediaStream::QueueEvent( + _In_ MediaEventType eventType, + _In_ REFGUID guidExtendedType, + _In_ HRESULT hrStatus, + _In_opt_ PROPVARIANT const* pvValue + ) { - return E_POINTER; + winrt::slim_lock_guard lock(m_Lock); + + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue)); + + return S_OK; } - *ppMediaSource = nullptr; - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); + // IMFMediaStream + IFACEMETHODIMP SimpleMediaStream::GetMediaSource( + _COM_Outptr_ IMFMediaSource** ppMediaSource + ) + { + winrt::slim_lock_guard lock(m_Lock); - *ppMediaSource = _parent.Get(); - (*ppMediaSource)->AddRef(); + RETURN_HR_IF_NULL(E_POINTER, ppMediaSource); + *ppMediaSource = nullptr; - return hr; -} + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + RETURN_IF_FAILED(m_parent.copy_to(ppMediaSource)); -IFACEMETHODIMP -SimpleMediaStream::GetStreamDescriptor( - _COM_Outptr_ IMFStreamDescriptor **ppStreamDescriptor - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + return S_OK; + } - if (ppStreamDescriptor == nullptr) + IFACEMETHODIMP SimpleMediaStream::GetStreamDescriptor( + _COM_Outptr_ IMFStreamDescriptor** ppStreamDescriptor + ) { - return E_POINTER; - } - *ppStreamDescriptor = nullptr; + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); + RETURN_HR_IF_NULL(E_POINTER, ppStreamDescriptor); + *ppStreamDescriptor = nullptr; - if (_spStreamDesc != nullptr) - { - *ppStreamDescriptor = _spStreamDesc.Get(); - (*ppStreamDescriptor)->AddRef(); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); + + if (m_spStreamDesc != nullptr) + { + RETURN_IF_FAILED(m_spStreamDesc.copy_to(ppStreamDescriptor)); + } + else + { + return E_UNEXPECTED; + } + + return S_OK; } - else + + IFACEMETHODIMP SimpleMediaStream::RequestSample( + _In_ IUnknown* pToken + ) { - return E_UNEXPECTED; - } + winrt::slim_lock_guard lock(m_Lock); + wil::com_ptr_nothrow<IMFSample> sample; + wil::com_ptr_nothrow<IMFMediaBuffer> outputBuffer; + LONG pitch = 0; + BYTE* bufferStart = nullptr; // not used + DWORD bufferLength = 0; + BYTE* pbuf = nullptr; + wil::com_ptr_nothrow<IMF2DBuffer2> buffer2D; - return hr; -} + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); -/* - Writes to a buffer representing a 2D image. - Writes a different constant to each line based on row number and current time. + if (m_streamState != MF_STREAM_STATE_RUNNING) + { + RETURN_HR_MSG(MF_E_INVALIDREQUEST, "Stream is not in running state, state:%d", m_streamState); + } - Assumes top down image, no negative stride and pBuf points to the begnning of the buffer of length len. + RETURN_IF_FAILED(m_spSampleAllocator->AllocateSample(&sample)); + RETURN_IF_FAILED(sample->GetBufferByIndex(0, &outputBuffer)); + RETURN_IF_FAILED(outputBuffer->QueryInterface(IID_PPV_ARGS(&buffer2D))); + RETURN_IF_FAILED(buffer2D->Lock2DSize(MF2DBuffer_LockFlags_Write, + &pbuf, + &pitch, + &bufferStart, + &bufferLength)); + - Param: - pBuf - pointer to beginning of buffer - pitch - line length in bytes - len - length of buffer in bytes -*/ -HRESULT -WriteSampleData( - _Inout_updates_bytes_(len) BYTE *pBuf, - _In_ LONG pitch, - _In_ DWORD len - ) -{ - if (pBuf == nullptr) - { - return E_INVALIDARG; - } + RETURN_IF_FAILED(m_spFrameGenerator->CreateFrame(pbuf, bufferLength, pitch, m_rgbMask)); + RETURN_IF_FAILED(buffer2D->Unlock2D()); - const int NUM_ROWS = len / abs(pitch); + RETURN_IF_FAILED(sample->SetSampleTime(MFGetSystemTime())); + RETURN_IF_FAILED(sample->SetSampleDuration(333333)); + if (pToken != nullptr) + { + RETURN_IF_FAILED(sample->SetUnknown(MFSampleExtension_Token, pToken)); + } + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamUnk(MEMediaSample, + GUID_NULL, + S_OK, + sample.get())); - LONGLONG curSysTimeInS = MFGetSystemTime() / (MFTIME)10000000; - int offset = curSysTimeInS % NUM_ROWS; + return S_OK; + } - for (int r = 0; r < NUM_ROWS; r++) + ////////////////////////////////////////////////////////////////////////////////////////// + // IMFMediaStream2 + IFACEMETHODIMP SimpleMediaStream::SetStreamState(MF_STREAM_STATE state) { - int grayColor = r + offset; - memset(pBuf + (pitch * r), (BYTE)(grayColor % NUM_ROWS), pitch); - } + winrt::slim_lock_guard lock(m_Lock); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); - return S_OK; -} + switch (state) + { + case MF_STREAM_STATE_PAUSED: + // because not supported + break; -IFACEMETHODIMP -SimpleMediaStream::RequestSample( - _In_ IUnknown *pToken - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); - ComPtr<IMFSample> sample; - ComPtr<IMFMediaBuffer> outputBuffer; - LONG pitch = IMAGE_ROW_SIZE_BYTES; - BYTE *bufferStart = nullptr; // not used - DWORD bufferLength = 0; - BYTE *pbuf = nullptr; - ComPtr<IMF2DBuffer2> buffer2D; + case MF_STREAM_STATE_RUNNING: + m_streamState = state; + break; - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); - RETURN_IF_FAILED (MFCreateSample(&sample)); - RETURN_IF_FAILED (MFCreate2DMediaBuffer(NUM_IMAGE_COLS, - NUM_IMAGE_ROWS, - D3DFMT_X8R8G8B8, - false, - &outputBuffer)); - RETURN_IF_FAILED (outputBuffer.As(&buffer2D)); - RETURN_IF_FAILED (buffer2D->Lock2DSize(MF2DBuffer_LockFlags_Write, - &pbuf, - &pitch, - &bufferStart, - &bufferLength)); - RETURN_IF_FAILED (WriteSampleData(pbuf, pitch, bufferLength)); - RETURN_IF_FAILED (buffer2D->Unlock2D()); - RETURN_IF_FAILED (sample->AddBuffer(outputBuffer.Get())); - RETURN_IF_FAILED (sample->SetSampleTime(MFGetSystemTime())); - RETURN_IF_FAILED (sample->SetSampleDuration(333333)); - if (pToken != nullptr) - { - RETURN_IF_FAILED (sample->SetUnknown(MFSampleExtension_Token, pToken)); - } - RETURN_IF_FAILED (_spEventQueue->QueueEventParamUnk(MEMediaSample, - GUID_NULL, - S_OK, - sample.Get())); + case MF_STREAM_STATE_STOPPED: + m_streamState = state; - return hr; -} + break; -////////////////////////////////////////////////////////////////////////////////////////// -// IMFMediaStream2 -IFACEMETHODIMP -SimpleMediaStream::SetStreamState( - MF_STREAM_STATE state - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); - bool runningState = false; + default: + return MF_E_INVALID_STATE_TRANSITION; + break; + } - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); + return S_OK; + } - switch (state) + IFACEMETHODIMP SimpleMediaStream::GetStreamState( + _Out_ MF_STREAM_STATE* pState + ) { - 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; - } + winrt::slim_lock_guard lock(m_Lock); + RETURN_IF_FAILED(_CheckShutdownRequiresLock()); - _isSelected = runningState; + *pState = m_streamState; -done: - return hr; -} + return S_OK; + } -IFACEMETHODIMP -SimpleMediaStream::GetStreamState( - _Out_ MF_STREAM_STATE *pState - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); - BOOLEAN pauseState = false; + ////////////////////////////////////////////////////////////////////////////////////////// + // Public methods + HRESULT SimpleMediaStream::Start() + { + winrt::slim_lock_guard lock(m_Lock); - RETURN_IF_FAILED (_CheckShutdownRequiresLock()); + // Create the allocator if one doesn't exist + if (m_allocatorUsage == MFSampleAllocatorUsage_UsesProvidedAllocator) + { + RETURN_HR_IF_NULL_MSG(E_POINTER, m_spSampleAllocator, "Sample allocator is not set"); + } + else + { + RETURN_IF_FAILED(MFCreateVideoSampleAllocatorEx(IID_PPV_ARGS(&m_spSampleAllocator))); + } - if (SUCCEEDED(hr)) - { - *pState = (_isSelected ? MF_STREAM_STATE_RUNNING : MF_STREAM_STATE_STOPPED); - } + wil::com_ptr_nothrow<IMFMediaTypeHandler> spMTHandler; + RETURN_IF_FAILED(m_spStreamDesc->GetMediaTypeHandler(&spMTHandler)); - return hr; -} + wil::com_ptr_nothrow<IMFMediaType> spMediaType; + UINT32 width, height; + GUID subType; + RETURN_IF_FAILED(spMTHandler->GetCurrentMediaType(&spMediaType)); + RETURN_IF_FAILED(spMediaType->GetGUID(MF_MT_SUBTYPE, &subType)); + MFGetAttributeSize(spMediaType.get(), MF_MT_FRAME_SIZE, &width, &height); -HRESULT -SimpleMediaStream::Shutdown( - ) -{ - HRESULT hr = S_OK; - auto lock = _critSec.Lock(); + DEBUG_MSG(L"Initialize sample allocator for mediatype: %s, %dx%d ", winrt::to_hstring(subType).data(), width, height); + RETURN_IF_FAILED(m_spSampleAllocator->InitializeSampleAllocator(10, spMediaType.get())); + if (m_spFrameGenerator == nullptr) + { + m_spFrameGenerator = wil::make_unique_nothrow<SimpleFrameGenerator>(); + RETURN_IF_NULL_ALLOC_MSG(m_spFrameGenerator, "Fail to create SimpleFrameGenerator"); + } + RETURN_IF_FAILED(m_spFrameGenerator->Initialize(spMediaType.get())); + + // Post MEStreamStarted event to signal stream has started + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamVar(MEStreamStarted, GUID_NULL, S_OK, nullptr)); - _isShutdown = true; - _parent.Reset(); + return S_OK; + } - if (_spEventQueue != nullptr) + HRESULT SimpleMediaStream::Stop() { - hr = _spEventQueue->Shutdown(); - _spEventQueue.Reset(); + winrt::slim_lock_guard lock(m_Lock); + + // Post MEStreamStopped event to signal stream has stopped + RETURN_IF_FAILED(m_spEventQueue->QueueEventParamVar(MEStreamStopped, GUID_NULL, S_OK, nullptr)); + return S_OK; } - _spAttributes.Reset(); - _spMediaType.Reset(); - _spStreamDesc.Reset(); + HRESULT SimpleMediaStream::Shutdown() + { + winrt::slim_lock_guard lock(m_Lock); - _isSelected = false; + m_bIsShutdown = true; + m_parent.reset(); - return hr; -} + if (m_spEventQueue != nullptr) + { + m_spEventQueue->Shutdown(); + m_spEventQueue.reset(); + } -HRESULT -SimpleMediaStream::_CheckShutdownRequiresLock( - ) -{ - if (_isShutdown) - { - return MF_E_SHUTDOWN; + m_spAttributes.reset(); + m_spStreamDesc.reset(); + + m_streamState = MF_STREAM_STATE_STOPPED; + + return S_OK; } - if (_spEventQueue == nullptr) + HRESULT SimpleMediaStream::SetSampleAllocator(IMFVideoSampleAllocator* pAllocator) { - return E_UNEXPECTED; + winrt::slim_lock_guard lock(m_Lock); + + if (m_streamState == MF_STREAM_STATE_RUNNING) + { + RETURN_HR_MSG(MF_E_INVALIDREQUEST, "Cannot update allocator when the stream is streaming"); + } + m_spSampleAllocator.reset(); + m_spSampleAllocator = pAllocator; + return S_OK; } - return S_OK; -} -HRESULT -SimpleMediaStream::_SetStreamAttributes( - _In_ IMFAttributes *pAttributeStore - ) -{ - HRESULT hr = S_OK; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Private methods - if (nullptr == pAttributeStore) + HRESULT SimpleMediaStream::_CheckShutdownRequiresLock() { - return E_INVALIDARG; + if (m_bIsShutdown) + { + return MF_E_SHUTDOWN; + } + + if (m_spEventQueue == nullptr) + { + return E_UNEXPECTED; + + } + return S_OK; } - RETURN_IF_FAILED (pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE)); - RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, STREAMINDEX)); - RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1)); - RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, _MFFrameSourceTypes::MFFrameSourceTypes_Color)); + HRESULT SimpleMediaStream::_SetStreamAttributes( + _In_ IMFAttributes* pAttributeStore + ) + { + RETURN_HR_IF_NULL(E_INVALIDARG, pAttributeStore); - return hr; -} + RETURN_IF_FAILED(pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE)); + RETURN_IF_FAILED(pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, m_dwStreamId)); + RETURN_IF_FAILED(pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1)); + RETURN_IF_FAILED(pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, MFFrameSourceTypes::MFFrameSourceTypes_Color)); -HRESULT -SimpleMediaStream::_SetStreamDescriptorAttributes( - _In_ IMFAttributes *pAttributeStore - ) -{ - HRESULT hr = S_OK; + return S_OK; + } - if (nullptr == pAttributeStore) + HRESULT SimpleMediaStream::_SetStreamDescriptorAttributes( + _In_ IMFAttributes* pAttributeStore + ) { - return E_INVALIDARG; + RETURN_HR_IF_NULL(E_INVALIDARG, pAttributeStore); + + RETURN_IF_FAILED(pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE)); + RETURN_IF_FAILED(pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, m_dwStreamId)); + RETURN_IF_FAILED(pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1)); + RETURN_IF_FAILED(pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, MFFrameSourceTypes::MFFrameSourceTypes_Color)); + + return S_OK; } - RETURN_IF_FAILED (pAttributeStore->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, PINNAME_VIDEO_CAPTURE)); - RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_STREAM_ID, STREAMINDEX)); - RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_FRAMESERVER_SHARED, 1)); - RETURN_IF_FAILED (pAttributeStore->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, _MFFrameSourceTypes::MFFrameSourceTypes_Color)); - return hr; } - diff --git a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h index 56351f47..70d20ec3 100644 --- a/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h +++ b/general/SimpleMediaSource/MediaSource/SimpleMediaStream.h @@ -1,54 +1,69 @@ -#pragma once +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// -#include "stdafx.h" +#ifndef SIMPLEMEDIASTREAM_H +#define SIMPLEMEDIASTREAM_H -class SimpleMediaSource; +#include "SimpleMediaSource.h" -class SimpleMediaStream : public RuntimeClass< - RuntimeClassFlags<ClassicCom>, - IMFMediaEventGenerator, - IMFMediaStream, - IMFMediaStream2> +namespace winrt::WindowsSample::implementation { - friend class SimpleMediaSource; + struct SimpleMediaStream : winrt::implements<SimpleMediaStream, IMFMediaStream2> + { + friend struct 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); + public: + // IMFMediaEventGenerator + IFACEMETHODIMP BeginGetEvent(IMFAsyncCallback* pCallback, IUnknown* punkState) override; + IFACEMETHODIMP EndGetEvent(IMFAsyncResult* pResult, IMFMediaEvent** ppEvent) override; + IFACEMETHODIMP GetEvent(DWORD dwFlags, IMFMediaEvent** ppEvent) override; + IFACEMETHODIMP QueueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT* pvValue) override; - // IMFMediaStream - IFACEMETHOD(GetMediaSource)(IMFMediaSource **ppMediaSource); - IFACEMETHOD(GetStreamDescriptor)(IMFStreamDescriptor **ppStreamDescriptor); - IFACEMETHOD(RequestSample)(IUnknown *pToken); + // IMFMediaStream + IFACEMETHODIMP GetMediaSource(IMFMediaSource** ppMediaSource) override; + IFACEMETHODIMP GetStreamDescriptor(IMFStreamDescriptor** ppStreamDescriptor) override; + IFACEMETHODIMP RequestSample(IUnknown* pToken) override; - // IMFMediaStream2 - IFACEMETHOD(SetStreamState)(MF_STREAM_STATE state); - IFACEMETHOD(GetStreamState)(_Out_ MF_STREAM_STATE *pState); + // IMFMediaStream2 + IFACEMETHODIMP SetStreamState(_In_ MF_STREAM_STATE state) override; + IFACEMETHODIMP GetStreamState(_Out_ MF_STREAM_STATE* pState) override; - // Non-interface methods. - HRESULT RuntimeClassInitialize(_In_ SimpleMediaSource* pSource); - HRESULT Shutdown(); + // Non-interface methods. + HRESULT Initialize(_In_ SimpleMediaSource* pSource, _In_ DWORD streamId, _In_ MFSampleAllocatorUsage allocatorUsage); + HRESULT Start(); + HRESULT Stop(); + HRESULT Shutdown(); + HRESULT SetSampleAllocator(_In_ IMFVideoSampleAllocator* pAllocator); + DWORD Id() const { return m_dwStreamId; } + MFSampleAllocatorUsage SampleAlloactorUsage() const { return m_allocatorUsage; } -protected: - HRESULT _CheckShutdownRequiresLock(); - HRESULT _SetStreamAttributes(IMFAttributes* pAttributeStore); - HRESULT _SetStreamDescriptorAttributes(IMFAttributes* pAttributeStore); + void SetRGBMask(ULONG rgbMask) { winrt::slim_lock_guard lock(m_Lock); m_rgbMask = rgbMask; } + ULONG GetRGBMask() { winrt::slim_lock_guard lock(m_Lock); return m_rgbMask; } + protected: + HRESULT _CheckShutdownRequiresLock(); + HRESULT _SetStreamAttributes(IMFAttributes* pAttributeStore); + HRESULT _SetStreamDescriptorAttributes(IMFAttributes* pAttributeStore); - CriticalSection _critSec; + private: + winrt::slim_mutex m_Lock; - ComPtr<IMFMediaSource> _parent; - ComPtr<IMFMediaEventQueue> _spEventQueue; - ComPtr<IMFAttributes> _spAttributes; - ComPtr<IMFMediaType> _spMediaType; - ComPtr<IMFStreamDescriptor> _spStreamDesc; - bool _isShutdown = false; - bool _isSelected = false; + wil::com_ptr_nothrow<IMFMediaSource> m_parent; + wil::com_ptr_nothrow<IMFMediaEventQueue> m_spEventQueue; + wil::com_ptr_nothrow<IMFAttributes> m_spAttributes; + wil::com_ptr_nothrow<IMFStreamDescriptor> m_spStreamDesc; + wil::com_ptr_nothrow<IMFVideoSampleAllocator> m_spSampleAllocator; + wistd::unique_ptr<SimpleFrameGenerator> m_spFrameGenerator; - const DWORD STREAMINDEX = 0; // since there is only one stream -}; + bool m_bIsShutdown = false; + MF_STREAM_STATE m_streamState = MF_STREAM_STATE_STOPPED; + ULONG m_rgbMask = KSPROPERTY_SIMPLEMEDIASOURCE_CUSTOMCONTROL_COLORMODE_BLUE; + DWORD m_dwStreamId; + MFSampleAllocatorUsage m_allocatorUsage; + }; +} + +#endif diff --git a/general/SimpleMediaSource/MediaSource/dllMain.cpp b/general/SimpleMediaSource/MediaSource/dllMain.cpp index aed44eb0..f021b4aa 100644 --- a/general/SimpleMediaSource/MediaSource/dllMain.cpp +++ b/general/SimpleMediaSource/MediaSource/dllMain.cpp @@ -1,35 +1,68 @@ -/// <copyright file="dllmain.cpp" company="Microsoft"> -/// Copyright (c) Microsoft Corporation. All rights reserved. -/// </copyright> +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// + // dllmain.cpp : Defines the entry point for the DLL application. -#include "stdafx.h" +#include "pch.h" -#include <wrl\module.h> +HINSTANCE g_hInst; -#if !defined(__WRL_CLASSIC_COM__) -STDAPI DllGetActivationFactory(_In_ HSTRING activatibleClassId, _COM_Outptr_ IActivationFactory** factory) +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) { - return Module<InProc>::GetModule().GetActivationFactory(activatibleClassId, factory); -} + try + { + *ppv = nullptr; + + if (rclsid == __uuidof(winrt::WindowsSample::implementation::SimpleMediaSourceActivate)) + { + return winrt::make_self<SimpleMediaSourceActivateFactory>()->QueryInterface(riid, ppv); + } + +#ifdef _WRL_MODULE_H_ + return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetClassObject(rclsid, riid, ppv); +#else + return winrt::hresult_class_not_available().to_abi(); #endif + } + catch (...) + { + return winrt::to_hresult(); + } +} -#if !defined(__WRL_WINRT_STRICT__) -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv) +bool __stdcall winrt_can_unload_now() noexcept { - return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv); + if (winrt::get_module_lock()) + { + return false; + } + + winrt::clear_factory_cache(); + return true; } -#endif -STDAPI DllCanUnloadNow() +int32_t __stdcall WINRT_CanUnloadNow() noexcept { - return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE; +#ifdef _WRL_MODULE_H_ + if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate()) + { + return 1; + } +#endif + + return winrt_can_unload_now() ? 0 : 1; } STDAPI_(BOOL) DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*) { - if (reason == DLL_PROCESS_ATTACH) + switch (reason) { - DisableThreadLibraryCalls(hinst); + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + g_hInst = hinst; } return TRUE; } diff --git a/general/SimpleMediaSource/MediaSource/module.def b/general/SimpleMediaSource/MediaSource/module.def index ddeb3eac..16e9b4fe 100644 --- a/general/SimpleMediaSource/MediaSource/module.def +++ b/general/SimpleMediaSource/MediaSource/module.def @@ -1,6 +1,3 @@ -LIBRARY - EXPORTS - DllGetActivationFactory PRIVATE + DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE DllGetClassObject PRIVATE - DllCanUnloadNow PRIVATE diff --git a/general/SimpleMediaSource/MediaSource/pch.cpp b/general/SimpleMediaSource/MediaSource/pch.cpp new file mode 100644 index 00000000..e40b6b12 --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/pch.cpp @@ -0,0 +1,26 @@ +// +// Copyright (C) Microsoft Corporation. All rights reserved. +// + +// pch.cpp: source file corresponding to the pre-compiled header +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. + +namespace winrt +{ + template<> bool is_guid_of<IMFMediaSourceEx>(guid const& id) noexcept + { + return is_guid_of<IMFMediaSourceEx, IMFMediaSource, IMFMediaEventGenerator>(id); + } + + template<> bool is_guid_of<IMFMediaStream2>(guid const& id) noexcept + { + return is_guid_of<IMFMediaStream2, IMFMediaStream, IMFMediaEventGenerator>(id); + } + + template<> bool is_guid_of<IMFActivate>(guid const& id) noexcept + { + return is_guid_of<IMFActivate, IMFAttributes>(id); + } +}
\ No newline at end of file diff --git a/general/SimpleMediaSource/MediaSource/pch.h b/general/SimpleMediaSource/MediaSource/pch.h new file mode 100644 index 00000000..dc59629c --- /dev/null +++ b/general/SimpleMediaSource/MediaSource/pch.h @@ -0,0 +1,82 @@ +// pch.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 <unknwn.h> +#include <windows.h> +#include <propvarutil.h> +#include <ole2.h> +#include <initguid.h> +#include <ks.h> +#include <ksproxy.h> +#include <ksmedia.h> +#include <mfapi.h> +#include <mferror.h> +#include <mfidl.h> +#include <mfreadwrite.h> +#include <nserror.h> +#include <winmeta.h> +#include <d3d9types.h> + +#define RESULT_DIAGNOSTICS_LEVEL 4 // include function name + +#include <wil\cppwinrt.h> // must be before the first C++ WinRT header, ref:https://github.com/Microsoft/wil/wiki/Error-handling-helpers +#include <wil\result.h> +#include <wil\com.h> + +#include "SimpleFrameGenerator.h" +#include "SimpleMediaStream.h" +#include "SimpleMediaSource.h" +#include "SimpleMediaSourceActivate.h" + +inline void DebugPrint(LPCWSTR szFormat, ...) +{ + WCHAR szBuffer[MAX_PATH] = { 0 }; + + va_list pArgs; + va_start(pArgs, szFormat); + StringCbVPrintf(szBuffer, sizeof(szBuffer), szFormat, pArgs); + va_end(pArgs); + OutputDebugStringW(szBuffer); +} + +#define DEBUG_MSG(msg,...) \ +{\ + DebugPrint(L"[%s@%d] ", TEXT(__FUNCTION__), __LINE__);\ + DebugPrint(msg, __VA_ARGS__);\ + DebugPrint(L"\n");\ +}\ + +namespace wilEx +{ + //template <typename T> + //using make_unique_cotaskmem_array = unique_any_array_ptr<typename details::element_traits<T>::type>; + + template<typename T> + wil::unique_cotaskmem_array_ptr<T> make_unique_cotaskmem_array(size_t numOfElements) + { + wil::unique_cotaskmem_array_ptr<T> arr; + size_t cb = sizeof(wil::details::element_traits<T>::type) * numOfElements; + void* ptr = ::CoTaskMemAlloc(cb); + if (ptr != nullptr) + { + ZeroMemory(ptr, cb); + arr.reset(reinterpret_cast<typename wil::details::element_traits<T>::type*>(ptr), numOfElements); + } + return arr; + } +}; + +namespace winrt +{ + template<> bool is_guid_of<IMFMediaSourceEx>(guid const& id) noexcept; + + template<> bool is_guid_of<IMFMediaStream2>(guid const& id) noexcept; + + template<> bool is_guid_of<IMFActivate>(guid const& id) noexcept; +}; + + diff --git a/general/SimpleMediaSource/MediaSource/stdafx.cpp b/general/SimpleMediaSource/MediaSource/stdafx.cpp deleted file mode 100644 index dc97a45b..00000000 --- a/general/SimpleMediaSource/MediaSource/stdafx.cpp +++ /dev/null @@ -1,11 +0,0 @@ -/// <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 deleted file mode 100644 index 73bec0b4..00000000 --- a/general/SimpleMediaSource/MediaSource/stdafx.h +++ /dev/null @@ -1,76 +0,0 @@ -// 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 <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 <ks.h> -#include <ksmedia.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> - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; - -#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 // _IKsControl_ - -#include "SimpleMediaStream.h" -#include "SimpleMediaSource.h" - - -// Basic macros to handle HRESULT checks. -// Recommend adding implementation specific logging within the failure case. -#ifndef RETURN_IF_FAILED -#define RETURN_IF_FAILED( val ) \ - hr = (val); \ - if ( FAILED( hr ) ) \ - { \ - return hr; \ - } -#endif - diff --git a/general/SimpleMediaSource/SimpleMediaSource.sln b/general/SimpleMediaSource/SimpleMediaSource.sln index c93b8c42..f6bd620c 100644 --- a/general/SimpleMediaSource/SimpleMediaSource.sln +++ b/general/SimpleMediaSource/SimpleMediaSource.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27703.2026 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31129.286 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleMediaSource", "MediaSource\MediaSource.vcxproj", "{43AD9BF7-E765-48FE-9826-71A8F2CB12DD}" EndProject diff --git a/general/SimpleMediaSource/SimpleMediaSourceDriver/SimpleMediaSourceDriver.vcxproj b/general/SimpleMediaSource/SimpleMediaSourceDriver/SimpleMediaSourceDriver.vcxproj index 38e21ccd..bb32647a 100644 --- a/general/SimpleMediaSource/SimpleMediaSourceDriver/SimpleMediaSourceDriver.vcxproj +++ b/general/SimpleMediaSource/SimpleMediaSourceDriver/SimpleMediaSourceDriver.vcxproj @@ -75,6 +75,7 @@ <Configuration>Debug</Configuration> <Platform Condition="'$(Platform)' == ''">Win32</Platform> <RootNamespace>SimpleMediaSourceDriver</RootNamespace> + <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion> </PropertyGroup> <PropertyGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> @@ -205,6 +206,9 @@ <Link> <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\OneCoreUAP.lib</AdditionalDependencies> </Link> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> @@ -215,6 +219,9 @@ <Link> <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\OneCoreUAP.lib</AdditionalDependencies> </Link> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> @@ -225,6 +232,9 @@ <Link> <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\OneCoreUAP.lib</AdditionalDependencies> </Link> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> @@ -235,6 +245,9 @@ <Link> <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\OneCoreUAP.lib</AdditionalDependencies> </Link> + <DriverSign> + <FileDigestAlgorithm>sha256</FileDigestAlgorithm> + </DriverSign> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'"> <ClCompile> |
