1// Copyright (c) Microsoft. All rights reserved. 2// 3// The MIT License (MIT) 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files(the "Software"), to deal 7// in the Software without restriction, including without limitation the rights 8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9// copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions : 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21// THE SOFTWARE. 22 23#include "MediaStreamSink.hpp" 24#include "MediaSink.hpp" 25#include "CaptureFrameGrabber.hpp" 26 27using namespace Media; 28using namespace Platform; 29using namespace Windows::Foundation; 30using namespace Windows::Media; 31using namespace Windows::Media::Capture; 32using namespace Windows::Media::MediaProperties; 33using namespace concurrency; 34using namespace Microsoft::WRL::Details; 35using namespace Microsoft::WRL; 36 37task<Media::CaptureFrameGrabber^> Media::CaptureFrameGrabber::CreateAsync(_In_ MediaCapture^ capture, _In_ VideoEncodingProperties^ props, CaptureStreamType streamType) 38{ 39 auto reader = ref new Media::CaptureFrameGrabber(capture, props, streamType); 40 41 auto profile = ref new MediaEncodingProfile(); 42 profile->Video = props; 43 44 task<void> task; 45 if (reader->_streamType == CaptureStreamType::Preview) 46 { 47 task = create_task(capture->StartPreviewToCustomSinkAsync(profile, reader->_mediaExtension)); 48 } 49 else 50 { 51 task = create_task(capture->StartRecordToCustomSinkAsync(profile, reader->_mediaExtension)); 52 } 53 54 return task.then([reader]() 55 { 56 reader->_state = State::Started; 57 return reader; 58 }); 59} 60 61Media::CaptureFrameGrabber::CaptureFrameGrabber(_In_ MediaCapture^ capture, _In_ VideoEncodingProperties^ props, CaptureStreamType streamType) 62: _state(State::Created) 63, _streamType(streamType) 64, _capture(capture) 65{ 66 auto videoSampleHandler = ref new MediaSampleHandler(this, &Media::CaptureFrameGrabber::ProcessSample); 67 68 _mediaSink = Make<MediaSink>(nullptr, props, nullptr, videoSampleHandler); 69 _mediaExtension = reinterpret_cast<IMediaExtension^>(static_cast<AWM::IMediaExtension*>(_mediaSink.Get())); 70} 71 72Media::CaptureFrameGrabber::~CaptureFrameGrabber() 73{ 74 if (_state == State::Started) 75 { 76 if (_streamType == CaptureStreamType::Preview) 77 { 78 (void)_capture->StopPreviewAsync(); 79 } 80 else 81 { 82 (void)_capture->StopRecordAsync(); 83 } 84 } 85 86 if (_mediaSink != nullptr) 87 { 88 (void)_mediaSink->Shutdown(); 89 _mediaSink = nullptr; 90 } 91 _mediaExtension = nullptr; 92 _capture = nullptr; 93} 94 95void Media::CaptureFrameGrabber::ShowCameraSettings() 96{ 97#if WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP 98 if (_state == State::Started) 99 { 100 CameraOptionsUI::Show(_capture.Get()); 101 } 102#endif 103} 104 105task<void> Media::CaptureFrameGrabber::FinishAsync() 106{ 107 auto lock = _lock.LockExclusive(); 108 109 if (_state != State::Started) 110 { 111 throw ref new COMException(E_UNEXPECTED, L"State"); 112 } 113 _state = State::Closing; 114 115 if (_mediaSink != nullptr) 116 { 117 (void)_mediaSink->Shutdown(); 118 _mediaSink = nullptr; 119 } 120 _mediaExtension = nullptr; 121 122 task<void> task; 123 if (_streamType == CaptureStreamType::Preview) 124 { 125 task = create_task(_capture->StopPreviewAsync()); 126 } 127 else 128 { 129 task = create_task(_capture->StopRecordAsync()); 130 } 131 132 return task.then([this]() 133 { 134 auto lock = _lock.LockExclusive(); 135 _state = State::Closed; 136 _capture = nullptr; 137 }); 138} 139 140task<ComPtr<IMF2DBuffer2>> Media::CaptureFrameGrabber::GetFrameAsync() 141{ 142 auto lock = _lock.LockExclusive(); 143 144 if (_state != State::Started) 145 { 146 throw ref new COMException(E_UNEXPECTED, L"State"); 147 } 148 149 _mediaSink->RequestVideoSample(); 150 151 task_completion_event<ComPtr<IMF2DBuffer2>> taskEvent; 152 _videoSampleRequestQueue.push(taskEvent); 153 154 return create_task(taskEvent); 155} 156 157void Media::CaptureFrameGrabber::ProcessSample(_In_ MediaSample^ sample) 158{ 159 task_completion_event<ComPtr<IMF2DBuffer2>> t; 160 161 { 162 auto lock = _lock.LockExclusive(); 163 164 t = _videoSampleRequestQueue.front(); 165 _videoSampleRequestQueue.pop(); 166 } 167 168 ComPtr<IMFMediaBuffer> buffer; 169 CHK(sample->Sample->ConvertToContiguousBuffer(&buffer)); 170 171 // Dispatch without the lock taken to avoid deadlocks 172 t.set(As<IMF2DBuffer2>(buffer)); 173}