summaryrefslogtreecommitdiff
path: root/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp
diff options
context:
space:
mode:
authorj-leungyy <[email protected]>2021-05-25 09:06:09 -0700
committerGitHub <[email protected]>2021-05-25 09:06:09 -0700
commit4fe5787f122fdfc45253b45f9fad3983f53d86df (patch)
treea11e06f8951d4b7b847f6f5a708f86df87d637db /general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp
parent53afd12aadb8aff15097f1546d4f80c6074e0bdc (diff)
update simplemediasource sample (#614)
* update simplemediasource wrl to winrtcpp COM, add mediatype NV12 (SimpleFrameGenerator), fix Mediatype missing attribute (bitrate), add IMFActivate, IMFSampleAllocator interface and implementation, update hardcode arg with named variables, cleanup sample for StreamIndex and StreamId, add sample KSControl * address PR-it1 comments * address comment from PR-it2, replace manual define of IKSControl by ksproxy.h * remove unuse header * address comment from PR * fix sdk to latest, add driversign algorithm * remove nudget, use submodule
Diffstat (limited to 'general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp')
-rw-r--r--general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp925
1 files changed, 525 insertions, 400 deletions
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;
+ }
+}