diff options
Diffstat (limited to 'general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp')
| -rw-r--r-- | general/SimpleMediaSource/MediaSource/SimpleMediaSource.cpp | 925 |
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; + } +} |
