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]()
__anona083a9760102() 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 }