Commit cbff7d98 authored by Andreas Traczyk's avatar Andreas Traczyk

ios: add video implementation

- adds a slightly altered version of the android video implementation,
  as a swift AVFoundation implementation will be used in the ios client
  to enumerate the video input devices.

Change-Id: I7c16fc39c5d22e54fb146881150b6cbcfddb7806
parent c27d2135
......@@ -692,6 +692,7 @@ AC_CONFIG_FILES([Makefile \
src/media/video/v4l2/Makefile \
src/media/video/androidvideo/Makefile \
src/media/video/osxvideo/Makefile \
src/media/video/iosvideo/Makefile \
src/media/video/winvideo/Makefile \
src/security/Makefile \
src/upnp/Makefile \
......
......@@ -17,6 +17,10 @@ if HAVE_OSX
RING_VIDEO_LIBS+= \
./media/video/osxvideo/libosxvideo.la
endif
if HAVE_IOS
RING_VIDEO_LIBS+= \
./media/video/iosvideo/libiosvideo.la
endif
if HAVE_WIN32
RING_VIDEO_LIBS+= \
./media/video/winvideo/libwinvideo.la
......
......@@ -181,7 +181,7 @@ setDecodingAccelerated(bool state)
#endif
}
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
void
addVideoDevice(const std::string &node, std::vector<std::map<std::string, std::string>> const * devInfo)
{
......
......@@ -31,6 +31,10 @@
#include "dring.h"
#if __APPLE__
#import "TargetConditionals.h"
#endif
namespace DRing {
/* FrameBuffer is a generic video frame container */
......@@ -70,7 +74,7 @@ bool switchInput(const std::string& resource);
bool switchToCamera();
void registerSinkTarget(const std::string& sinkId, const SinkTarget& target);
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
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);
......
......@@ -28,7 +28,7 @@
class AVFrame;
namespace DRing {
class FrameBuffer; // from dring/videomanager_interface.h
struct FrameBuffer; // from dring/videomanager_interface.h
}
namespace ring {
......
......@@ -15,6 +15,11 @@ SUBDIRS= \
osxvideo
endif
if HAVE_IOS
SUBDIRS= \
iosvideo
endif
if HAVE_WIN32
SUBDIRS= \
winvideo
......
include $(top_srcdir)/globals.mk
noinst_LTLIBRARIES = libiosvideo.la
libiosvideo_la_SOURCES = \
video_device_impl.cpp \
video_device_monitor_impl.cpp
#AM_CXXFLAGS = @UDEV_CFLAGS@
#libiosvideo_la_LIBADD = @UDEV_LIBS@
/*
* Copyright (C) 2015-2017 Savoir-faire Linux Inc.
*
* Author: Rafaël Carré <rafael.carre@savoirfairelinux.com>
* Author: Vivien Didelot <vivien.didelot@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 "client/ring_signal.h"
namespace ring { namespace video {
typedef struct
{
std::string name;
enum VideoPixelFormat ring_format;
} ios_fmt;
static const std::array<ios_fmt, 4> ios_formats
{
ios_fmt { "RGBA", VIDEO_PIXFMT_RGBA },
ios_fmt { "BGRA", VIDEO_PIXFMT_BGRA },
ios_fmt { "YUV420P", VIDEO_PIXFMT_YUV420P }
};
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 ios_fmt* fmt_ {nullptr};
VideoSize size_ {};
FrameRate rate_ {};
};
void
VideoDeviceImpl::selectFormat()
{
unsigned best = UINT_MAX;
for(auto fmt : formats_) {
auto f = ios_formats.begin();
for (; f != ios_formats.end(); ++f) {
if (f->name == fmt) {
auto pos = std::distance(ios_formats.begin(), f);
if (pos < best)
best = pos;
break;
}
}
if (f == ios_formats.end())
RING_WARN("Video: No format matching %s", fmt.c_str());
}
if (best != UINT_MAX) {
fmt_ = &ios_formats[best];
RING_DBG("Video: picked format %s", fmt_->name.c_str());
}
else {
fmt_ = &ios_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.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
......@@ -343,7 +343,7 @@ SinkClient::update(Observable<std::shared_ptr<VideoFrame>>* /*obs*/,
VideoScaler scaler;
const int width = f.width();
const int height = f.height();
#if (defined(__ANDROID__) || defined(__APPLE__))
#if (defined(__ANDROID__) || (defined(__APPLE__)) && !defined(TARGET_OS_IPHONE))
const int format = VIDEO_PIXFMT_RGBA;
#else
const int format = VIDEO_PIXFMT_BGRA;
......
......@@ -56,14 +56,14 @@ VideoInput::VideoInput()
, loop_(std::bind(&VideoInput::setup, this),
std::bind(&VideoInput::process, this),
std::bind(&VideoInput::cleanup, this))
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
, mutex_(), frame_cv_(), buffers_()
#endif
{}
VideoInput::~VideoInput()
{
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
/* 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();
}
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
bool VideoInput::waitForBufferFull()
{
for(auto& buffer : buffers_) {
......@@ -238,7 +238,7 @@ bool VideoInput::captureFrame()
}
}
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
int VideoInput::allocateOneBuffer(struct VideoFrameBuffer& b, int length)
{
b.data = std::malloc(length);
......@@ -550,7 +550,7 @@ VideoInput::switchInput(const std::string& resource)
return futureDecOpts_;
}
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
int VideoInput::getWidth() const
{ return decOpts_.width; }
......
......@@ -36,6 +36,10 @@
#include <condition_variable>
#include <array>
#if __APPLE__
#import "TargetConditionals.h"
#endif
namespace ring {
class MediaDecoder;
}
......@@ -75,7 +79,7 @@ public:
DeviceParams getParams() const;
std::shared_future<DeviceParams> switchInput(const std::string& resource);
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
/*
* these functions are used to pass buffer from/to the daemon
* on the Android and UWP builds
......@@ -121,7 +125,7 @@ private:
bool captureFrame();
bool isCapturing() const noexcept;
#if defined(__ANDROID__) || defined(RING_UWP)
#if defined(__ANDROID__) || defined(RING_UWP) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
int allocateOneBuffer(struct VideoFrameBuffer& b, int length);
void freeOneBuffer(struct VideoFrameBuffer& b);
bool waitForBufferFull();
......
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