Commit a1b8b13a authored by atraczyk's avatar atraczyk Committed by gerrit2

video: add video device implementation for UWP

- adds a video device implementation and a barebones video device
  montior implementation for UWP.

Change-Id: I69108c688f0e55fea1776708919b881afae42552
Tuleap: #790
parent 441a84b6
......@@ -93,9 +93,11 @@ getSignalHandlers()
#ifdef __ANDROID__
exported_callback<DRing::VideoSignal::GetCameraInfo>(),
exported_callback<DRing::VideoSignal::SetParameters>(),
#endif
exported_callback<DRing::VideoSignal::StartCapture>(),
exported_callback<DRing::VideoSignal::StopCapture>(),
#endif
exported_callback<DRing::VideoSignal::DeviceAdded>(),
exported_callback<DRing::VideoSignal::ParametersChanged>(),
#endif
};
......
......@@ -82,6 +82,22 @@ setDefaultDevice(const std::string& name)
ring::Manager::instance().saveConfig();
}
std::map<std::string, std::string>
getDeviceParams(const std::string& name)
{
auto params = ring::Manager::instance().getVideoManager().videoDeviceMonitor.getDeviceParams(name);
std::stringstream width, height, rate;
width << params.width;
height << params.height;
rate << params.framerate;
return {
{"format", params.format},
{"width", width.str()},
{"height", height.str()},
{"rate", rate.str()}
};
}
std::map<std::string, std::string>
getSettings(const std::string& name)
{
......@@ -146,11 +162,11 @@ registerSinkTarget(const std::string& sinkId, const SinkTarget& target)
RING_WARN("No sink found for id '%s'", sinkId.c_str());
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(RING_UWP)
void
addVideoDevice(const std::string &node)
addVideoDevice(const std::string &node, std::vector<std::map<std::string, std::string>> const * devInfo)
{
ring::Manager::instance().getVideoManager().videoDeviceMonitor.addDevice(node);
ring::Manager::instance().getVideoManager().videoDeviceMonitor.addDevice(node, devInfo);
}
void
......
......@@ -58,6 +58,9 @@ VideoCapabilities getCapabilities(const std::string& name);
std::map<std::string, std::string> getSettings(const std::string& name);
void applySettings(const std::string& name, const std::map<std::string, std::string>& settings);
void setDefaultDevice(const std::string& name);
std::map<std::string, std::string> getDeviceParams(const std::string& name);
std::string getDefaultDevice();
std::string getCurrentCodecName(const std::string& callID);
void startCamera();
......@@ -67,8 +70,8 @@ bool switchInput(const std::string& resource);
bool switchToCamera();
void registerSinkTarget(const std::string& sinkId, const SinkTarget& target);
#ifdef __ANDROID__
void addVideoDevice(const std::string &node);
#if defined(__ANDROID__) || defined(RING_UWP)
void addVideoDevice(const std::string &node, const std::vector<std::map<std::string, std::string>>* devInfo=nullptr);
void removeVideoDevice(const std::string &node);
void* obtainFrame(int length);
void releaseFrame(void* frame);
......@@ -88,24 +91,32 @@ struct VideoSignal {
constexpr static const char* name = "DecodingStopped";
using cb_type = void(const std::string& /*id*/, const std::string& /*shm_path*/, bool /*is_mixer*/);
};
#ifdef __ANDROID__
struct GetCameraInfo {
constexpr static const char* name = "GetCameraInfo";
using cb_type = void(const std::string& device, std::vector<int> *formats, std::vector<unsigned> *sizes, std::vector<unsigned> *rates);
};
#if __ANDROID__
struct SetParameters {
constexpr static const char* name = "SetParameters";
using cb_type = void(const std::string& device, const int format, const int width, const int height, const int rate);
};
struct GetCameraInfo {
constexpr static const char* name = "GetCameraInfo";
using cb_type = void(const std::string& device, std::vector<int> *formats, std::vector<unsigned> *sizes, std::vector<unsigned> *rates);
};
#endif
struct StartCapture {
constexpr static const char* name = "StartCapture";
using cb_type = void(const std::string& device);
using cb_type = void(const std::string& /*device*/);
};
struct StopCapture {
constexpr static const char* name = "StopCapture";
using cb_type = void(void);
};
#endif
struct DeviceAdded {
constexpr static const char* name = "DeviceAdded";
using cb_type = void(const std::string& /*device*/);
};
struct ParametersChanged {
constexpr static const char* name = "ParametersChanged";
using cb_type = void(const std::string& /*device*/);
};
};
} // namespace DRing
......
......@@ -187,7 +187,7 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
emitSignal<DRing::VideoSignal::SetParameters>(name, fmt_->code, size_.first, size_.second, rate_.real());
}
VideoDevice::VideoDevice(const std::string& path) :
VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>&) :
deviceImpl_(new VideoDeviceImpl(path))
{
name = deviceImpl_->name;
......
......@@ -146,7 +146,7 @@ VideoDeviceImpl::getChannelList() const
return {"default"};
}
VideoDevice::VideoDevice(const std::string& path) :
VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>&) :
deviceImpl_(new VideoDeviceImpl(path))
{
node_ = path;
......
/*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc.
*
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <array>
#include "logger.h"
#include "../video_device.h"
#include "ring_signal.h"
//#include <ciso646>
namespace ring { namespace video {
typedef struct
{
std::string name;
enum VideoPixelFormat ring_format;
} uwp_fmt;
// have all formats map to bgra
static const std::array<uwp_fmt, 4> uwp_formats
{
uwp_fmt { "MJPG", VIDEO_PIXFMT_BGRA },
uwp_fmt { "RGB24", VIDEO_PIXFMT_BGRA },
uwp_fmt { "NV12", VIDEO_PIXFMT_BGRA },
uwp_fmt { "YUY2", VIDEO_PIXFMT_BGRA }
};
class VideoDeviceImpl
{
public:
VideoDeviceImpl(const std::string& path, const std::vector<std::map<std::string, std::string>>& devInfo);
std::string name;
DeviceParams getDeviceParams() const;
void setDeviceParams(const DeviceParams&);
void selectFormat();
std::vector<VideoSize> getSizeList() const;
std::vector<FrameRate> getRateList() const;
private:
VideoSize getSize(VideoSize size) const;
FrameRate getRate(FrameRate rate) const;
std::vector<std::string> formats_ {};
std::vector<VideoSize> sizes_ {};
std::vector<FrameRate> rates_ {};
const uwp_fmt* fmt_ {nullptr};
VideoSize size_ {};
FrameRate rate_ {};
};
void
VideoDeviceImpl::selectFormat()
{
unsigned best = UINT_MAX;
for(auto fmt : formats_) {
auto f = uwp_formats.begin();
for (; f != uwp_formats.end(); ++f) {
if (f->name == fmt) {
auto pos = std::distance(uwp_formats.begin(), f);
if (pos < best)
best = pos;
break;
}
}
if (f == uwp_formats.end())
RING_WARN("Video: No format matching %s", fmt.c_str());
}
if (best != UINT_MAX) {
fmt_ = &uwp_formats[best];
RING_DBG("Video: picked format %s", fmt_->name.c_str());
}
else {
fmt_ = &uwp_formats[0];
RING_ERR("Video: Could not find a known format to use");
}
}
VideoDeviceImpl::VideoDeviceImpl(const std::string& path, const std::vector<std::map<std::string, std::string>>& devInfo)
: name(path)
{
for (auto& setting : devInfo) {
formats_.emplace_back(setting.at("format"));
sizes_.emplace_back(std::stoi(setting.at("width")), std::stoi(setting.at("height")));
rates_.emplace_back(std::stoi(setting.at("rate")), 1);
}
selectFormat();
}
VideoSize
VideoDeviceImpl::getSize(VideoSize size) const
{
for (const auto &iter : sizes_) {
if (iter == size)
return iter;
}
return sizes_.empty() ? VideoSize{0, 0} : sizes_.back();
}
FrameRate
VideoDeviceImpl::getRate(FrameRate rate) const
{
for (const auto &iter : rates_) {
if (iter == rate)
return iter;
}
return rates_.empty() ? FrameRate{0, 0} : rates_.back();
}
std::vector<VideoSize>
VideoDeviceImpl::getSizeList() const
{
return sizes_;
}
std::vector<FrameRate>
VideoDeviceImpl::getRateList() const
{
return rates_;
}
DeviceParams
VideoDeviceImpl::getDeviceParams() const
{
DeviceParams params;
std::stringstream ss1, ss2;
ss1 << fmt_->ring_format;
ss1 >> params.format;
params.format = fmt_->name;
params.name = name;
params.input = name;
params.channel = 0;
params.width = size_.first;
params.height = size_.second;
params.framerate = rate_;
return params;
}
void
VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
{
size_ = getSize({params.width, params.height});
rate_ = getRate(params.framerate);
emitSignal<DRing::VideoSignal::ParametersChanged>(name);
}
VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>& devInfo)
: deviceImpl_(new VideoDeviceImpl(path, devInfo))
{
node_ = path;
name = deviceImpl_->name;
}
DeviceParams
VideoDevice::getDeviceParams() const
{
return deviceImpl_->getDeviceParams();
}
void
VideoDevice::setDeviceParams(const DeviceParams& params)
{
return deviceImpl_->setDeviceParams(params);
}
std::vector<std::string>
VideoDevice::getChannelList() const
{
return {"default"};
}
std::vector<VideoSize>
VideoDevice::getSizeList(const std::string& channel) const
{
return deviceImpl_->getSizeList();
}
std::vector<FrameRate>
VideoDevice::getRateList(const std::string& channel, VideoSize size) const
{
return deviceImpl_->getRateList();
}
VideoDevice::~VideoDevice()
{}
}} // namespace ring::video
/*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
* Author: Edric Milaret <edric.ladent-milaret@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <mutex>
#include <thread>
#include "../video_device_monitor.h"
#include "logger.h"
#include "noncopyable.h"
namespace ring { namespace video {
class VideoDeviceMonitorImpl
{
public:
/*
* This is the only restriction to the pImpl design:
* as the Linux implementation has a thread, it needs a way to notify
* devices addition and deletion.
*
* This class should maybe inherit from VideoDeviceMonitor instead of
* being its pImpl.
*/
VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor);
~VideoDeviceMonitorImpl();
void start();
private:
NON_COPYABLE(VideoDeviceMonitorImpl);
VideoDeviceMonitor* monitor_;
void run();
mutable std::mutex mutex_;
bool probing_;
std::thread thread_;
};
VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor)
: monitor_(monitor)
, mutex_()
, thread_()
{}
void
VideoDeviceMonitorImpl::start()
{
probing_ = true;
thread_ = std::thread(&VideoDeviceMonitorImpl::run, this);
}
VideoDeviceMonitorImpl::~VideoDeviceMonitorImpl()
{
probing_ = false;
if (thread_.joinable())
thread_.join();
}
void
VideoDeviceMonitorImpl::run()
{
}
VideoDeviceMonitor::VideoDeviceMonitor()
: preferences_()
, devices_()
, monitorImpl_(new VideoDeviceMonitorImpl(this))
{
monitorImpl_->start();
}
VideoDeviceMonitor::~VideoDeviceMonitor()
{}
}} // namespace ring::video
......@@ -569,7 +569,7 @@ VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
}
}
VideoDevice::VideoDevice(const string& path)
VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>&)
: deviceImpl_(new VideoDeviceImpl(path))
{
node_ = path;
......
......@@ -31,6 +31,7 @@
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
#include "videomanager_interface.h"
#include "string_utils.h"
......@@ -46,7 +47,7 @@ class VideoDeviceImpl;
class VideoDevice {
public:
VideoDevice(const std::string& path);
VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>& devInfo);
~VideoDevice();
/*
......
......@@ -186,14 +186,15 @@ notify()
}
void
VideoDeviceMonitor::addDevice(const string& node)
VideoDeviceMonitor::addDevice(const string& node, const std::vector<std::map<std::string, std::string>>* devInfo)
{
if (findDeviceByNode(node) != devices_.end())
return;
// instantiate a new unique device
try {
VideoDevice dev {node};
VideoDevice dev {node, *devInfo};
if (dev.getChannelList().empty())
return;
......@@ -214,6 +215,7 @@ VideoDeviceMonitor::addDevice(const string& node)
devices_.emplace_back(std::move(dev));
notify();
} catch (const std::exception& e) {
RING_ERR("Failed to add device %s: %s", node.c_str(), e.what());
return;
......
......@@ -57,7 +57,7 @@ class VideoDeviceMonitor : public Serializable
std::string getMRLForDefaultDevice() const;
void setDefaultDevice(const std::string& name);
void addDevice(const std::string &node);
void addDevice(const std::string &node, const std::vector<std::map<std::string, std::string>>* devInfo=nullptr);
void removeDevice(const std::string &node);
/**
......
......@@ -39,7 +39,11 @@
#include <string>
#include <sstream>
#include <cassert>
#ifdef RING_UWP
#include <io.h> // for access
#else
#include <unistd.h>
#endif
namespace ring { namespace video {
......@@ -49,21 +53,17 @@ static constexpr unsigned default_grab_height = 480;
VideoInput::VideoInput()
: VideoGenerator::VideoGenerator()
, sink_ {Manager::instance().createSinkClient("local")}
#ifndef __ANDROID__
, loop_(std::bind(&VideoInput::setup, this),
std::bind(&VideoInput::process, this),
std::bind(&VideoInput::cleanup, this))
#else
, loop_(std::bind(&VideoInput::setup, this),
std::bind(&VideoInput::processAndroid, this),
std::bind(&VideoInput::cleanupAndroid, this))
#if defined(__ANDROID__) || defined(RING_UWP)
, mutex_(), frame_cv_(), buffers_(8)
#endif
{}
VideoInput::~VideoInput()
{
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(RING_UWP)
/* we need to stop the loop and notify the condition variable
* to unblock the process loop */
loop_.stop();
......@@ -72,7 +72,7 @@ VideoInput::~VideoInput()
loop_.join();
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(RING_UWP)
bool VideoInput::waitForBufferFull()
{
for(auto& buffer : buffers_) {
......@@ -84,7 +84,7 @@ bool VideoInput::waitForBufferFull()
return !isCapturing();
}
void VideoInput::processAndroid()
void VideoInput::process()
{
foundDecOpts(decOpts_);
......@@ -132,7 +132,7 @@ void VideoInput::processAndroid()
}
}
void VideoInput::cleanupAndroid()
void VideoInput::cleanup()
{
emitSignal<DRing::VideoSignal::StopCapture>();
......@@ -149,21 +149,7 @@ void VideoInput::cleanupAndroid()
}
}
}
#endif
bool VideoInput::setup()
{
if (not attach(sink_.get())) {
RING_ERR("attach sink failed");
return false;
}
if (!sink_->start())
RING_ERR("start sink failed");
RING_DBG("VideoInput ready to capture");
return true;
}
#else
void
VideoInput::process()
......@@ -186,6 +172,21 @@ VideoInput::cleanup()
RING_DBG("VideoInput closed");
}
#endif
bool VideoInput::setup()
{
if (not attach(sink_.get())) {
RING_ERR("attach sink failed");
return false;
}
if (!sink_->start())
RING_ERR("start sink failed");
RING_DBG("VideoInput ready to capture");
return true;
}
void VideoInput::clearOptions()
{
decOpts_ = {};
......@@ -230,7 +231,7 @@ bool VideoInput::captureFrame()
}
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(RING_UWP)
int VideoInput::allocateOneBuffer(struct VideoFrameBuffer& b, int length)
{
b.data = std::malloc(length);
......@@ -542,7 +543,7 @@ VideoInput::switchInput(const std::string& resource)
return futureDecOpts_;
}
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(RING_UWP)
int VideoInput::getWidth() const
{ return decOpts_.width; }
......
......@@ -74,10 +74,10 @@ public:
DeviceParams getParams() const;
std::shared_future<DeviceParams> switchInput(const std::string& resource);
#ifdef __ANDROID__
#if defined(__ANDROID__) || defined(RING_UWP)
/*
* these fonctions are used to pass buffer from/to the daemon
* to the Java application
* these functions are used to pass buffer from/to the daemon
* on the Android and UWP builds
*/
void* obtainFrame(int length);
void releaseFrame(void *frame);
......@@ -120,9 +120,7 @@ private:
bool captureFrame();
bool isCapturing() const noexcept;
#ifdef __ANDROID__
void processAndroid();
void cleanupAndroid();
#if defined(__ANDROID__) || defined(RING_UWP)
int allocateOneBuffer(struct VideoFrameBuffer& b, int length);
void freeOneBuffer(struct VideoFrameBuffer& b);
bool waitForBufferFull();
......
......@@ -283,7 +283,7 @@ VideoDeviceImpl::getChannelList() const
return {"default"};
}
VideoDevice::VideoDevice(const std::string& path)
VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>&)
: deviceImpl_(new VideoDeviceImpl(path))
{
node_ = path;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment