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
27 using namespace Media;
28 using namespace Platform;
29 using namespace Windows::Foundation;
30 using namespace Windows::Media;
31 using namespace Windows::Media::Capture;
32 using namespace Windows::Media::MediaProperties;
33 using namespace concurrency;
34 using namespace Microsoft::WRL::Details;
35 using namespace Microsoft::WRL;
36
37 task<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]()
__anon2d1dec7b0102() 55 {
56 reader->_state = State::Started;
57 return reader;
58 });
59 }
60
61 Media::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
~CaptureFrameGrabber()72 Media::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
ShowCameraSettings()95 void 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
FinishAsync()105 task<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
GetFrameAsync()140 task<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
157 void 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 }