root/modules/videoio/src/cap_winrt/MediaStreamSink.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _height
  2. GetMediaSink
  3. GetIdentifier
  4. GetMediaTypeHandler
  5. RequestSample
  6. ProcessSample
  7. PlaceMarker
  8. Flush
  9. GetEvent
  10. BeginGetEvent
  11. EndGetEvent
  12. QueueEvent
  13. IsMediaTypeSupported
  14. GetMediaTypeCount
  15. GetMediaTypeByIndex
  16. SetCurrentMediaType
  17. GetCurrentMediaType
  18. GetMajorType
  19. InternalSetCurrentMediaType
  20. Shutdown
  21. _IsMediaTypeSupported
  22. _UpdateMediaType

// Copyright (c) Microsoft. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "MediaStreamSink.hpp"
#include "MFIncludes.hpp"

using namespace Media;
using namespace Microsoft::WRL;
using namespace Platform;
using namespace Windows::Foundation;

MediaStreamSink::MediaStreamSink(
    __in const MW::ComPtr<IMFMediaSink>& sink,
    __in DWORD id,
    __in const MW::ComPtr<IMFMediaType>& mt,
    __in MediaSampleHandler^ sampleHandler
    )
    : _shutdown(false)
    , _id(-1)
    , _width(0)
    , _height(0)
{
    CHK(MFCreateEventQueue(&_eventQueue));
    CHK(MFCreateMediaType(&_curMT));

    _UpdateMediaType(mt);

    _sink = sink;
    _id = id;
    _sampleHandler = sampleHandler;
}

HRESULT MediaStreamSink::GetMediaSink(__deref_out IMFMediaSink **sink)
{
    return ExceptionBoundary([this, sink]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(sink);
        *sink = nullptr;

        _VerifyNotShutdown();

        CHK(_sink.CopyTo(sink));
    });
}

HRESULT MediaStreamSink::GetIdentifier(__out DWORD *identifier)
{
    return ExceptionBoundary([this, identifier]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(identifier);

        _VerifyNotShutdown();

        *identifier = _id;
    });
}

HRESULT MediaStreamSink::GetMediaTypeHandler(__deref_out IMFMediaTypeHandler **handler)
{
    return ExceptionBoundary([this, handler]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(handler);
        *handler = nullptr;

        _VerifyNotShutdown();

        *handler = this;
        this->AddRef();

    });
}

void MediaStreamSink::RequestSample()
{
    auto lock = _lock.LockExclusive();

    _VerifyNotShutdown();

    CHK(_eventQueue->QueueEventParamVar(MEStreamSinkRequestSample, GUID_NULL, S_OK, nullptr));
}

HRESULT MediaStreamSink::ProcessSample(__in_opt IMFSample *sample)
{
    return ExceptionBoundary([this, sample]()
    {
        MediaSampleHandler^ sampleHandler;
        auto mediaSample = ref new MediaSample();

        {
            auto lock = _lock.LockExclusive();

            _VerifyNotShutdown();

            if (sample == nullptr)
            {
                return;
            }

            mediaSample->Sample = sample;
            sampleHandler = _sampleHandler;
        }

        // Call back without the lock taken to avoid deadlocks
        sampleHandler(mediaSample);
    });
}

HRESULT MediaStreamSink::PlaceMarker(__in MFSTREAMSINK_MARKER_TYPE /*markerType*/, __in const PROPVARIANT * /*markerValue*/, __in const PROPVARIANT * contextValue)
{
    return ExceptionBoundary([this, contextValue]()
    {
        auto lock = _lock.LockExclusive();
        CHKNULL(contextValue);

        _VerifyNotShutdown();

        CHK(_eventQueue->QueueEventParamVar(MEStreamSinkMarker, GUID_NULL, S_OK, contextValue));
    });
}

HRESULT MediaStreamSink::Flush()
{
    return ExceptionBoundary([this]()
    {
        auto lock = _lock.LockExclusive();

        _VerifyNotShutdown();
    });
}

HRESULT MediaStreamSink::GetEvent(__in DWORD flags, __deref_out IMFMediaEvent **event)
{
    return ExceptionBoundary([this, flags, event]()
    {
        CHKNULL(event);
        *event = nullptr;

        ComPtr<IMFMediaEventQueue> eventQueue;

        {
            auto lock = _lock.LockExclusive();

            _VerifyNotShutdown();

            eventQueue = _eventQueue;
        }

        // May block for a while
        CHK(eventQueue->GetEvent(flags, event));
    });
}

HRESULT MediaStreamSink::BeginGetEvent(__in IMFAsyncCallback *callback, __in_opt IUnknown *state)
{
    return ExceptionBoundary([this, callback, state]()
    {
        auto lock = _lock.LockExclusive();

        _VerifyNotShutdown();

        CHK(_eventQueue->BeginGetEvent(callback, state));
    });
}


HRESULT MediaStreamSink::EndGetEvent(__in IMFAsyncResult *result, __deref_out IMFMediaEvent **event)
{
    return ExceptionBoundary([this, result, event]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(event);
        *event = nullptr;

        _VerifyNotShutdown();

        CHK(_eventQueue->EndGetEvent(result, event));
    });
}

HRESULT MediaStreamSink::QueueEvent(
    __in MediaEventType met,
    __in REFGUID extendedType,
    __in HRESULT status,
    __in_opt const PROPVARIANT *value
    )
{
    return ExceptionBoundary([this, met, extendedType, status, value]()
    {
        auto lock = _lock.LockExclusive();

        _VerifyNotShutdown();

        CHK(_eventQueue->QueueEventParamVar(met, extendedType, status, value));
    });
}

HRESULT MediaStreamSink::IsMediaTypeSupported(__in IMFMediaType *mediaType, __deref_out_opt  IMFMediaType **closestMediaType)
{
    bool supported = false;

    HRESULT hr = ExceptionBoundary([this, mediaType, closestMediaType, &supported]()
    {
        auto lock = _lock.LockExclusive();

        if (closestMediaType != nullptr)
        {
            *closestMediaType = nullptr;
        }

        CHKNULL(mediaType);

        _VerifyNotShutdown();

        supported = _IsMediaTypeSupported(mediaType);
    });

    // Avoid throwing an exception to return MF_E_INVALIDMEDIATYPE as this is not a exceptional case
    return FAILED(hr) ? hr : supported ? S_OK : MF_E_INVALIDMEDIATYPE;
}

HRESULT MediaStreamSink::GetMediaTypeCount(__out DWORD *typeCount)
{
    return ExceptionBoundary([this, typeCount]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(typeCount);

        _VerifyNotShutdown();

        // No media type provided by default (app needs to specify it)
        *typeCount = 0;
    });
}

HRESULT MediaStreamSink::GetMediaTypeByIndex(__in DWORD /*index*/, __deref_out  IMFMediaType **mediaType)
{
    HRESULT hr = ExceptionBoundary([this, mediaType]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(mediaType);
        *mediaType = nullptr;

        _VerifyNotShutdown();
    });

    // Avoid throwing an exception to return MF_E_NO_MORE_TYPES as this is not a exceptional case
    return FAILED(hr) ? hr : MF_E_NO_MORE_TYPES;
}

HRESULT MediaStreamSink::SetCurrentMediaType(__in IMFMediaType *mediaType)
{
    return ExceptionBoundary([this, mediaType]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(mediaType);

        _VerifyNotShutdown();

        if (!_IsMediaTypeSupported(mediaType))
        {
            CHK(MF_E_INVALIDMEDIATYPE);
        }

        _UpdateMediaType(mediaType);
    });
}

HRESULT MediaStreamSink::GetCurrentMediaType(__deref_out_opt IMFMediaType **mediaType)
{
    return ExceptionBoundary([this, mediaType]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(mediaType);
        *mediaType = nullptr;

        _VerifyNotShutdown();

        ComPtr<IMFMediaType> mt;
        CHK(MFCreateMediaType(&mt));
        CHK(_curMT->CopyAllItems(mt.Get()));
        *mediaType = mt.Detach();
    });
}

HRESULT MediaStreamSink::GetMajorType(__out GUID *majorType)
{
    return ExceptionBoundary([this, majorType]()
    {
        auto lock = _lock.LockExclusive();

        CHKNULL(majorType);

        _VerifyNotShutdown();

        *majorType = _majorType;
    });
}

void MediaStreamSink::InternalSetCurrentMediaType(__in const ComPtr<IMFMediaType>& mediaType)
{
    auto lock = _lock.LockExclusive();

    CHKNULL(mediaType);

    _VerifyNotShutdown();

    _UpdateMediaType(mediaType);
}

void MediaStreamSink::Shutdown()
{
    auto lock = _lock.LockExclusive();

    if (_shutdown)
    {
        return;
    }
    _shutdown = true;

    (void)_eventQueue->Shutdown();
    _eventQueue = nullptr;

    _curMT = nullptr;
    _sink = nullptr;
    _sampleHandler = nullptr;
}

bool MediaStreamSink::_IsMediaTypeSupported(__in const ComPtr<IMFMediaType>& mt) const
{
    GUID majorType;
    GUID subType;
    if (SUCCEEDED(mt->GetGUID(MF_MT_MAJOR_TYPE, &majorType)) &&
        SUCCEEDED(mt->GetGUID(MF_MT_SUBTYPE, &subType)) &&
        (majorType == _majorType) &&
        (subType == _subType))
    {
        return true;
    }

    return false;
}

void MediaStreamSink::_UpdateMediaType(__in const ComPtr<IMFMediaType>& mt)
{
    CHK(mt->GetGUID(MF_MT_MAJOR_TYPE, &_majorType));
    CHK(mt->GetGUID(MF_MT_SUBTYPE, &_subType));

    if (_majorType == MFMediaType_Video)
    {
        CHK(MFGetAttributeSize(mt.Get(), MF_MT_FRAME_SIZE, &_width, &_height));
    }

    CHK(mt->CopyAllItems(_curMT.Get()));

/* [<][>][^][v][top][bottom][index][help] */