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
34using namespace Windows::Foundation;
35using namespace Windows::Media::Capture;
36using namespace Windows::Media::MediaProperties;
37using namespace Windows::Devices::Enumeration;
38
39using namespace Platform;
40
41using namespace Windows::UI::Xaml::Media::Imaging;
42using namespace Microsoft::WRL;
43
44using namespace ::std;
45
46namespace cv {
47
48    /******************************* exported API functions **************************************/
49
50    template <typename ...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>
82    void winrt_startMessageLoop(void callback(Args...), Args... args)
83    {
84        winrt_startMessageLoop(std::function<void(Args...)>(callback), args...);
85    }
86
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
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
123    VideoCapture_WinRT::VideoCapture_WinRT(int device) : started(false)
124    {
125        VideoioBridge::getInstance().setDeviceIndex(device);
126    }
127
128    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
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
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
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