1 // Capture support for WinRT
2 
3 // Copyright (c) Microsoft Open Technologies, Inc.
4 // All rights reserved.
5 //
6 // (3 - clause BSD License)
7 //
8 // Redistribution and use in source and binary forms, with or without modification, are permitted provided that
9 // the following conditions are met:
10 //
11 // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
12 // following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
14 // following disclaimer in the documentation and/or other materials provided with the distribution.
15 // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
16 // promote products derived from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
19 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 // PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
22 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26 
27 
28 #include "precomp.hpp"
29 #include "cap_winrt_capture.hpp"
30 #include "cap_winrt_bridge.hpp"
31 #include "cap_winrt_video.hpp"
32 #include <opencv2\videoio\cap_winrt.hpp>
33 
34 using namespace Windows::Foundation;
35 using namespace Windows::Media::Capture;
36 using namespace Windows::Media::MediaProperties;
37 using namespace Windows::Devices::Enumeration;
38 
39 using namespace Platform;
40 
41 using namespace Windows::UI::Xaml::Media::Imaging;
42 using namespace Microsoft::WRL;
43 
44 using namespace ::std;
45 
46 namespace cv {
47 
48     /******************************* exported API functions **************************************/
49 
50     template <typename ...Args>
winrt_startMessageLoop(std::function<void (Args...)> && callback,Args...args)51     void winrt_startMessageLoop(std::function<void(Args...)>&& callback, Args... args)
52     {
53         auto asyncTask = ::concurrency::create_async([=](::concurrency::progress_reporter<int> reporter)
54         {
55             VideoioBridge::getInstance().setReporter(reporter);
56 
57             // frame reading loop
58             callback(args...);
59         });
60 
61         asyncTask->Progress = ref new AsyncActionProgressHandler<int>([=](IAsyncActionWithProgress<int>^ act, int progress)
62         {
63             int action = progress;
64 
65             // these actions will be processed on the UI thread asynchronously
66             switch (action)
67             {
68             case OPEN_CAMERA:
69                 VideoioBridge::getInstance().openCamera();
70                 break;
71             case CLOSE_CAMERA:
72                 Video::getInstance().closeGrabber();
73                 break;
74             case UPDATE_IMAGE_ELEMENT:
75                 VideoioBridge::getInstance().updateFrameContainer();
76                 break;
77             }
78         });
79     }
80 
81     template <typename ...Args>
winrt_startMessageLoop(void callback (Args...),Args...args)82     void winrt_startMessageLoop(void callback(Args...), Args... args)
83     {
84         winrt_startMessageLoop(std::function<void(Args...)>(callback), args...);
85     }
86 
winrt_onVisibilityChanged(bool visible)87     void winrt_onVisibilityChanged(bool visible)
88     {
89         if (visible)
90         {
91             VideoioBridge& bridge = VideoioBridge::getInstance();
92 
93             // only start the grabber if the camera was opened in OpenCV
94             if (bridge.backInputPtr != nullptr)
95             {
96                 if (Video::getInstance().isStarted()) return;
97 
98                 int device = bridge.getDeviceIndex();
99                 int width = bridge.getWidth();
100                 int height = bridge.getHeight();
101 
102                 Video::getInstance().initGrabber(device, width, height);
103             }
104         } else
105         {
106             //grabberStarted = false;
107             Video::getInstance().closeGrabber();
108         }
109     }
110 
winrt_imshow()111     void winrt_imshow()
112     {
113         VideoioBridge::getInstance().imshow();
114     }
115 
116     void winrt_setFrameContainer(::Windows::UI::Xaml::Controls::Image^ image)
117     {
118         VideoioBridge::getInstance().cvImage = image;
119     }
120 
121     /********************************* VideoCapture_WinRT class ****************************/
122 
VideoCapture_WinRT(int device)123     VideoCapture_WinRT::VideoCapture_WinRT(int device) : started(false)
124     {
125         VideoioBridge::getInstance().setDeviceIndex(device);
126     }
127 
isOpened() const128     bool VideoCapture_WinRT::isOpened() const
129     {
130         return true; // started;
131     }
132 
133     // grab a frame:
134     // this will NOT block per spec
135     // should be called on the image processing thread, not the UI thread
grabFrame()136     bool VideoCapture_WinRT::grabFrame()
137     {
138         // if device is not started we must return true so retrieveFrame() is called to start device
139         // nb. we cannot start the device here because we do not know the size of the input Mat
140         if (!started) return true;
141 
142         if (VideoioBridge::getInstance().bIsFrameNew)
143         {
144             return true;
145         }
146 
147         // nb. if blocking is to be added:
148         // unique_lock<mutex> lock(VideoioBridge::getInstance().frameReadyMutex);
149         // VideoioBridge::getInstance().frameReadyEvent.wait(lock);
150         return false;
151     }
152 
153     // should be called on the image processing thread after grabFrame
154     // see VideoCapture::read
retrieveFrame(int channel,cv::OutputArray outArray)155     bool VideoCapture_WinRT::retrieveFrame(int channel, cv::OutputArray outArray)
156     {
157         if (!started) {
158 
159             int width, height;
160             width = outArray.size().width;
161             height = outArray.size().height;
162             if (width == 0) width = 640;
163             if (height == 0) height = 480;
164 
165             VideoioBridge::getInstance().setWidth(width);
166             VideoioBridge::getInstance().setHeight(height);
167 
168             // nb. Mats will be alloc'd on UI thread
169 
170             // request device init on UI thread - this does not block, and is async
171             VideoioBridge::getInstance().requestForUIthreadAsync(OPEN_CAMERA);
172 
173             started = true;
174             return false;
175         }
176 
177         if (!started) return false;
178 
179         return VideoioBridge::getInstance().bIsFrameNew;
180     }
181 
182 
setProperty(int property_id,double value)183     bool VideoCapture_WinRT::setProperty(int property_id, double value)
184     {
185         switch (property_id)
186         {
187         case CAP_PROP_FRAME_WIDTH:
188             size.width = (int)value;
189             break;
190         case CAP_PROP_FRAME_HEIGHT:
191             size.height = (int)value;
192             break;
193         default:
194             return false;
195         }
196         return true;
197     }
198 }
199 
200 // end