summaryrefslogtreecommitdiff
path: root/general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp
diff options
context:
space:
mode:
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;
+ }
+}