Path: blob/master/modules/videoio/src/cap_winrt/MediaStreamSink.cpp
16348 views
// Copyright (c) Microsoft. All rights reserved.1//2// The MIT License (MIT)3//4// Permission is hereby granted, free of charge, to any person obtaining a copy5// of this software and associated documentation files(the "Software"), to deal6// in the Software without restriction, including without limitation the rights7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell8// copies of the Software, and to permit persons to whom the Software is9// furnished to do so, subject to the following conditions :10//11// The above copyright notice and this permission notice shall be included in12// all copies or substantial portions of the Software.13//14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN20// THE SOFTWARE.2122#include "MediaStreamSink.hpp"23#include "MFIncludes.hpp"2425using namespace Media;26using namespace Microsoft::WRL;27using namespace Platform;28using namespace Windows::Foundation;2930MediaStreamSink::MediaStreamSink(31__in const MW::ComPtr<IMFMediaSink>& sink,32__in DWORD id,33__in const MW::ComPtr<IMFMediaType>& mt,34__in MediaSampleHandler^ sampleHandler35)36: _shutdown(false)37, _id(-1)38, _width(0)39, _height(0)40{41CHK(MFCreateEventQueue(&_eventQueue));42CHK(MFCreateMediaType(&_curMT));4344_UpdateMediaType(mt);4546_sink = sink;47_id = id;48_sampleHandler = sampleHandler;49}5051HRESULT MediaStreamSink::GetMediaSink(__deref_out IMFMediaSink **sink)52{53return ExceptionBoundary([this, sink]()54{55auto lock = _lock.LockExclusive();5657CHKNULL(sink);58*sink = nullptr;5960_VerifyNotShutdown();6162CHK(_sink.CopyTo(sink));63});64}6566HRESULT MediaStreamSink::GetIdentifier(__out DWORD *identifier)67{68return ExceptionBoundary([this, identifier]()69{70auto lock = _lock.LockExclusive();7172CHKNULL(identifier);7374_VerifyNotShutdown();7576*identifier = _id;77});78}7980HRESULT MediaStreamSink::GetMediaTypeHandler(__deref_out IMFMediaTypeHandler **handler)81{82return ExceptionBoundary([this, handler]()83{84auto lock = _lock.LockExclusive();8586CHKNULL(handler);87*handler = nullptr;8889_VerifyNotShutdown();9091*handler = this;92this->AddRef();9394});95}9697void MediaStreamSink::RequestSample()98{99auto lock = _lock.LockExclusive();100101_VerifyNotShutdown();102103CHK(_eventQueue->QueueEventParamVar(MEStreamSinkRequestSample, GUID_NULL, S_OK, nullptr));104}105106HRESULT MediaStreamSink::ProcessSample(__in_opt IMFSample *sample)107{108return ExceptionBoundary([this, sample]()109{110MediaSampleHandler^ sampleHandler;111auto mediaSample = ref new MediaSample();112113{114auto lock = _lock.LockExclusive();115116_VerifyNotShutdown();117118if (sample == nullptr)119{120return;121}122123mediaSample->Sample = sample;124sampleHandler = _sampleHandler;125}126127// Call back without the lock taken to avoid deadlocks128sampleHandler(mediaSample);129});130}131132HRESULT MediaStreamSink::PlaceMarker(__in MFSTREAMSINK_MARKER_TYPE /*markerType*/, __in const PROPVARIANT * /*markerValue*/, __in const PROPVARIANT * contextValue)133{134return ExceptionBoundary([this, contextValue]()135{136auto lock = _lock.LockExclusive();137CHKNULL(contextValue);138139_VerifyNotShutdown();140141CHK(_eventQueue->QueueEventParamVar(MEStreamSinkMarker, GUID_NULL, S_OK, contextValue));142});143}144145HRESULT MediaStreamSink::Flush()146{147return ExceptionBoundary([this]()148{149auto lock = _lock.LockExclusive();150151_VerifyNotShutdown();152});153}154155HRESULT MediaStreamSink::GetEvent(__in DWORD flags, __deref_out IMFMediaEvent **event)156{157return ExceptionBoundary([this, flags, event]()158{159CHKNULL(event);160*event = nullptr;161162ComPtr<IMFMediaEventQueue> eventQueue;163164{165auto lock = _lock.LockExclusive();166167_VerifyNotShutdown();168169eventQueue = _eventQueue;170}171172// May block for a while173CHK(eventQueue->GetEvent(flags, event));174});175}176177HRESULT MediaStreamSink::BeginGetEvent(__in IMFAsyncCallback *callback, __in_opt IUnknown *state)178{179return ExceptionBoundary([this, callback, state]()180{181auto lock = _lock.LockExclusive();182183_VerifyNotShutdown();184185CHK(_eventQueue->BeginGetEvent(callback, state));186});187}188189190HRESULT MediaStreamSink::EndGetEvent(__in IMFAsyncResult *result, __deref_out IMFMediaEvent **event)191{192return ExceptionBoundary([this, result, event]()193{194auto lock = _lock.LockExclusive();195196CHKNULL(event);197*event = nullptr;198199_VerifyNotShutdown();200201CHK(_eventQueue->EndGetEvent(result, event));202});203}204205HRESULT MediaStreamSink::QueueEvent(206__in MediaEventType met,207__in REFGUID extendedType,208__in HRESULT status,209__in_opt const PROPVARIANT *value210)211{212return ExceptionBoundary([this, met, extendedType, status, value]()213{214auto lock = _lock.LockExclusive();215216_VerifyNotShutdown();217218CHK(_eventQueue->QueueEventParamVar(met, extendedType, status, value));219});220}221222HRESULT MediaStreamSink::IsMediaTypeSupported(__in IMFMediaType *mediaType, __deref_out_opt IMFMediaType **closestMediaType)223{224bool supported = false;225226HRESULT hr = ExceptionBoundary([this, mediaType, closestMediaType, &supported]()227{228auto lock = _lock.LockExclusive();229230if (closestMediaType != nullptr)231{232*closestMediaType = nullptr;233}234235CHKNULL(mediaType);236237_VerifyNotShutdown();238239supported = _IsMediaTypeSupported(mediaType);240});241242// Avoid throwing an exception to return MF_E_INVALIDMEDIATYPE as this is not a exceptional case243return FAILED(hr) ? hr : supported ? S_OK : MF_E_INVALIDMEDIATYPE;244}245246HRESULT MediaStreamSink::GetMediaTypeCount(__out DWORD *typeCount)247{248return ExceptionBoundary([this, typeCount]()249{250auto lock = _lock.LockExclusive();251252CHKNULL(typeCount);253254_VerifyNotShutdown();255256// No media type provided by default (app needs to specify it)257*typeCount = 0;258});259}260261HRESULT MediaStreamSink::GetMediaTypeByIndex(__in DWORD /*index*/, __deref_out IMFMediaType **mediaType)262{263HRESULT hr = ExceptionBoundary([this, mediaType]()264{265auto lock = _lock.LockExclusive();266267CHKNULL(mediaType);268*mediaType = nullptr;269270_VerifyNotShutdown();271});272273// Avoid throwing an exception to return MF_E_NO_MORE_TYPES as this is not a exceptional case274return FAILED(hr) ? hr : MF_E_NO_MORE_TYPES;275}276277HRESULT MediaStreamSink::SetCurrentMediaType(__in IMFMediaType *mediaType)278{279return ExceptionBoundary([this, mediaType]()280{281auto lock = _lock.LockExclusive();282283CHKNULL(mediaType);284285_VerifyNotShutdown();286287if (!_IsMediaTypeSupported(mediaType))288{289CHK(MF_E_INVALIDMEDIATYPE);290}291292_UpdateMediaType(mediaType);293});294}295296HRESULT MediaStreamSink::GetCurrentMediaType(__deref_out_opt IMFMediaType **mediaType)297{298return ExceptionBoundary([this, mediaType]()299{300auto lock = _lock.LockExclusive();301302CHKNULL(mediaType);303*mediaType = nullptr;304305_VerifyNotShutdown();306307ComPtr<IMFMediaType> mt;308CHK(MFCreateMediaType(&mt));309CHK(_curMT->CopyAllItems(mt.Get()));310*mediaType = mt.Detach();311});312}313314HRESULT MediaStreamSink::GetMajorType(__out GUID *majorType)315{316return ExceptionBoundary([this, majorType]()317{318auto lock = _lock.LockExclusive();319320CHKNULL(majorType);321322_VerifyNotShutdown();323324*majorType = _majorType;325});326}327328void MediaStreamSink::InternalSetCurrentMediaType(__in const ComPtr<IMFMediaType>& mediaType)329{330auto lock = _lock.LockExclusive();331332CHKNULL(mediaType);333334_VerifyNotShutdown();335336_UpdateMediaType(mediaType);337}338339void MediaStreamSink::Shutdown()340{341auto lock = _lock.LockExclusive();342343if (_shutdown)344{345return;346}347_shutdown = true;348349(void)_eventQueue->Shutdown();350_eventQueue = nullptr;351352_curMT = nullptr;353_sink = nullptr;354_sampleHandler = nullptr;355}356357bool MediaStreamSink::_IsMediaTypeSupported(__in const ComPtr<IMFMediaType>& mt) const358{359GUID majorType;360GUID subType;361if (SUCCEEDED(mt->GetGUID(MF_MT_MAJOR_TYPE, &majorType)) &&362SUCCEEDED(mt->GetGUID(MF_MT_SUBTYPE, &subType)) &&363(majorType == _majorType) &&364(subType == _subType))365{366return true;367}368369return false;370}371372void MediaStreamSink::_UpdateMediaType(__in const ComPtr<IMFMediaType>& mt)373{374CHK(mt->GetGUID(MF_MT_MAJOR_TYPE, &_majorType));375CHK(mt->GetGUID(MF_MT_SUBTYPE, &_subType));376377if (_majorType == MFMediaType_Video)378{379CHK(MFGetAttributeSize(mt.Get(), MF_MT_FRAME_SIZE, &_width, &_height));380}381382CHK(mt->CopyAllItems(_curMT.Get()));383}384385