Added WinRT support for videoio.
Signed-off-by: Maxim Kostin <v-maxkos@microsoft.com>
This commit is contained in:
279
modules/videoio/src/cap_winrt_capture.cpp
Normal file
279
modules/videoio/src/cap_winrt_capture.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
// Capture support for WinRT
|
||||
|
||||
// Copyright (c) Microsoft Open Technologies, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// (3 - clause BSD License)
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
|
||||
// the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
|
||||
// following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
// following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
|
||||
// promote products derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
// PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "cap_winrt_capture.hpp"
|
||||
#include "cap_winrt_bridge.hpp"
|
||||
#include "cap_winrt_video.hpp"
|
||||
#include <opencv2\videoio\cap_winrt.hpp>
|
||||
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Media::Capture;
|
||||
using namespace Windows::Media::MediaProperties;
|
||||
using namespace Windows::Devices::Enumeration;
|
||||
|
||||
using namespace Platform;
|
||||
|
||||
using namespace Windows::UI::Xaml::Media::Imaging;
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
using namespace ::std;
|
||||
|
||||
|
||||
// nb. VideoCapture_WinRT is not a singleton, so the Mats are made file statics
|
||||
// we do not support more than one capture device simultaneously with the
|
||||
// design at this time
|
||||
|
||||
// nb. inputBufferMutex was not able to guarantee that OpenCV Mats were
|
||||
// ready to accept data in the UI thread (memory access exceptions were thrown
|
||||
// even though buffer address was good).
|
||||
// Therefore allocation of Mats is also done on the UI thread before the video
|
||||
// device is initialized.
|
||||
|
||||
static cv::Mat frontInputMat;
|
||||
static cv::Mat backInputMat;
|
||||
|
||||
namespace cv {
|
||||
|
||||
/***************************** exported control functions ******************************/
|
||||
|
||||
template <typename ...Args>
|
||||
void winrt_startMessageLoop(std::function<void(Args...)>&& callback, Args... args)
|
||||
{
|
||||
auto asyncTask = ::concurrency::create_async([=](::concurrency::progress_reporter<int> reporter)
|
||||
{
|
||||
VideoioBridge::getInstance().setReporter(reporter);
|
||||
|
||||
// frame reading loop
|
||||
callback(args...);
|
||||
});
|
||||
|
||||
asyncTask->Progress = ref new AsyncActionProgressHandler<int>([=](IAsyncActionWithProgress<int>^ act, int progress)
|
||||
{
|
||||
int action = progress;
|
||||
|
||||
// these actions will be processed on the UI thread asynchronously
|
||||
switch (action)
|
||||
{
|
||||
case OPEN_CAMERA:
|
||||
winrt_openCamera();
|
||||
break;
|
||||
case CLOSE_CAMERA:
|
||||
winrt_closeGrabber();
|
||||
break;
|
||||
case UPDATE_IMAGE_ELEMENT:
|
||||
winrt_updateFrameContainer();
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename ...Args>
|
||||
void winrt_startMessageLoop(void callback(Args...), Args... args)
|
||||
{
|
||||
winrt_startMessageLoop(std::function<void(Args...)>(callback), args...);
|
||||
}
|
||||
|
||||
void winrt_onVisibilityChanged(bool visible) {
|
||||
if (visible)
|
||||
{
|
||||
VideoioBridge& bridge = VideoioBridge::getInstance();
|
||||
|
||||
// only start the grabber if the camera was opened in OpenCV
|
||||
if (bridge.backInputPtr != nullptr)
|
||||
{
|
||||
if (Video::getInstance().isStarted()) return;
|
||||
|
||||
int device = bridge.deviceIndex;
|
||||
int width = bridge.width;
|
||||
int height = bridge.height;
|
||||
|
||||
winrt_initGrabber(device, width, height);
|
||||
}
|
||||
} else
|
||||
{
|
||||
//grabberStarted = false;
|
||||
winrt_closeGrabber();
|
||||
}
|
||||
}
|
||||
|
||||
void winrt_imshow() {
|
||||
VideoioBridge::getInstance().imshow();
|
||||
}
|
||||
|
||||
void winrt_setFrameContainer(::Windows::UI::Xaml::Controls::Image^ image) {
|
||||
VideoioBridge::getInstance().cvImage = image;
|
||||
}
|
||||
|
||||
|
||||
/********************************* Internal helpers ************************************/
|
||||
|
||||
void winrt_updateFrameContainer()
|
||||
{
|
||||
// copy output Mat to WBM
|
||||
winrt_copyOutput();
|
||||
|
||||
// set XAML image element with image WBM
|
||||
VideoioBridge::getInstance().cvImage->Source = VideoioBridge::getInstance().backOutputBuffer;
|
||||
}
|
||||
|
||||
// performed on UI thread
|
||||
bool winrt_openCamera()
|
||||
{
|
||||
VideoioBridge& bridge = VideoioBridge::getInstance();
|
||||
|
||||
int device = bridge.deviceIndex;
|
||||
int width = bridge.width;
|
||||
int height = bridge.height;
|
||||
|
||||
// buffers must alloc'd on UI thread
|
||||
winrt_allocateBuffers(width, height);
|
||||
|
||||
// nb. video capture device init must be done on UI thread;
|
||||
if (!Video::getInstance().isStarted())
|
||||
{
|
||||
winrt_initGrabber(device, width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// performed on UI thread
|
||||
void winrt_allocateBuffers(int width, int height)
|
||||
{
|
||||
VideoioBridge& bridge = VideoioBridge::getInstance();
|
||||
|
||||
// allocate input Mats (bgra8 = CV_8UC4, RGB24 = CV_8UC3)
|
||||
frontInputMat.create(height, width, CV_8UC3);
|
||||
backInputMat.create(height, width, CV_8UC3);
|
||||
|
||||
bridge.frontInputPtr = frontInputMat.ptr(0);
|
||||
bridge.backInputPtr = backInputMat.ptr(0);
|
||||
|
||||
bridge.allocateOutputBuffers();
|
||||
}
|
||||
|
||||
// non-blocking
|
||||
bool winrt_initGrabber(int device, int w, int h) {
|
||||
// nb. Video class is not exported outside of this DLL
|
||||
// due to complexities in the CaptureFrameGrabber ref class
|
||||
// as written in the header not mixing well with pure C++ classes
|
||||
return Video::getInstance().initGrabber(device, w, h);
|
||||
}
|
||||
|
||||
void winrt_closeGrabber() {
|
||||
Video::getInstance().closeGrabber();
|
||||
}
|
||||
|
||||
// nb on UI thread
|
||||
void winrt_copyOutput() {
|
||||
Video::getInstance().CopyOutput();
|
||||
}
|
||||
|
||||
|
||||
/********************************* VideoCapture_WinRT class ****************************/
|
||||
|
||||
VideoCapture_WinRT::VideoCapture_WinRT(int device) : started(false)
|
||||
{
|
||||
VideoioBridge::getInstance().deviceIndex = device;
|
||||
}
|
||||
|
||||
bool VideoCapture_WinRT::isOpened() const
|
||||
{
|
||||
return true; // started;
|
||||
}
|
||||
|
||||
// grab a frame:
|
||||
// this will NOT block per spec
|
||||
// should be called on the image processing thread, not the UI thread
|
||||
bool VideoCapture_WinRT::grabFrame()
|
||||
{
|
||||
// if device is not started we must return true so retrieveFrame() is called to start device
|
||||
// nb. we cannot start the device here because we do not know the size of the input Mat
|
||||
if (!started) return true;
|
||||
|
||||
if (VideoioBridge::getInstance().bIsFrameNew)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// nb. if blocking is to be added:
|
||||
// unique_lock<mutex> lock(VideoioBridge::getInstance().frameReadyMutex);
|
||||
// VideoioBridge::getInstance().frameReadyEvent.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
// should be called on the image processing thread after grabFrame
|
||||
// see VideoCapture::read
|
||||
bool VideoCapture_WinRT::retrieveFrame(int channel, cv::OutputArray outArray)
|
||||
{
|
||||
if (!started) {
|
||||
|
||||
int width, height;
|
||||
width = outArray.size().width;
|
||||
height = outArray.size().height;
|
||||
if (width == 0) width = 640;
|
||||
if (height == 0) height = 480;
|
||||
|
||||
VideoioBridge::getInstance().width = width;
|
||||
VideoioBridge::getInstance().height = height;
|
||||
|
||||
// nb. Mats will be alloc'd on UI thread
|
||||
|
||||
// request device init on UI thread - this does not block, and is async
|
||||
VideoioBridge::getInstance().requestForUIthreadAsync(OPEN_CAMERA,
|
||||
outArray.size().width, outArray.size().height);
|
||||
|
||||
started = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!started) return false;
|
||||
|
||||
return VideoioBridge::getInstance().bIsFrameNew;
|
||||
}
|
||||
|
||||
|
||||
bool VideoCapture_WinRT::setProperty(int property_id, double value)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
case CAP_PROP_FRAME_WIDTH:
|
||||
size.width = (int)value;
|
||||
break;
|
||||
case CAP_PROP_FRAME_HEIGHT:
|
||||
size.height = (int)value;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
Reference in New Issue
Block a user