video: add implementation for osx

Video device implementation necessary for device
detection and handling on Mac OSX.
New patch for libav to access camera

Refs #66543

Change-Id: I3c315457b46b731c164552d119ea3bb804f873f9
diff --git a/daemon/src/media/video/osxvideo/video_device_impl.mm b/daemon/src/media/video/osxvideo/video_device_impl.mm
new file mode 100644
index 0000000..7d491f9
--- /dev/null
+++ b/daemon/src/media/video/osxvideo/video_device_impl.mm
@@ -0,0 +1,203 @@
+/*
+ *  Copyright (C) 2015 Savoir-Faire Linux Inc.
+ *  Author: Alexandre Lision <alexandre.lision@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.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include <algorithm>
+#include <cassert>
+#include <climits>
+#include <map>
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+#include "logger.h"
+#include "../video_device.h"
+
+#import <AVFoundation/AVFoundation.h>
+
+namespace ring { namespace video {
+
+class VideoDeviceImpl {
+    public:
+        /**
+         * @throw std::runtime_error
+         */
+        VideoDeviceImpl(const std::string& path);
+
+        std::string device;
+        std::string name;
+
+        std::vector<std::string> getChannelList() const;
+        std::vector<std::string> getSizeList(const std::string& channel) const;
+        std::vector<std::string> getSizeList() const;
+        std::vector<std::string> getRateList(const std::string& channel, const std::string& size) const;
+        float getRate(unsigned rate) const;
+
+        VideoSettings getSettings() const;
+        void applySettings(VideoSettings settings);
+
+        DeviceParams getDeviceParams() const;
+
+    private:
+        AVCaptureDevice* avDevice_;
+};
+
+VideoDeviceImpl::VideoDeviceImpl(const std::string& uniqueID)
+    : device(uniqueID)
+    , avDevice_([AVCaptureDevice deviceWithUniqueID:
+        [NSString stringWithCString:uniqueID.c_str() encoding:[NSString defaultCStringEncoding]]])
+{
+    name = [[avDevice_ localizedName] UTF8String];
+    // Set default settings
+    applySettings(VideoSettings());
+}
+
+void
+VideoDeviceImpl::applySettings(VideoSettings settings)
+{
+//TODO: not supported for now on OSX
+// Set preferences or fallback to defaults.
+//    channel_ = getChannel(settings["channel"]);
+//    size_ = channel_.getSize(settings["size"]);
+//    rate_ = size_.getRate(settings["rate"]);
+}
+
+DeviceParams
+VideoDeviceImpl::getDeviceParams() const
+{
+    DeviceParams params;
+    params.input = "[" + device + "]";
+    params.format = "avfoundation";
+// No channel support for now
+//    params.channel = channel_.idx;
+    auto format = [avDevice_ activeFormat];
+    CMVideoDimensions dimensions =
+                CMVideoFormatDescriptionGetDimensions(format.formatDescription);
+    params.width = dimensions.width;
+    params.height = dimensions.height;
+    auto frameRate = (AVFrameRateRange*)
+                    [format.videoSupportedFrameRateRanges objectAtIndex:0];
+    params.framerate = frameRate.maxFrameRate;
+    return params;
+}
+
+VideoSettings
+VideoDeviceImpl::getSettings() const
+{
+    VideoSettings settings;
+
+    settings.name = [[avDevice_ localizedName] UTF8String];
+
+    return settings;
+}
+
+VideoDevice::VideoDevice(const std::string& path) :
+    deviceImpl_(new VideoDeviceImpl(path))
+{
+    node_ = path;
+    name = deviceImpl_->name;
+}
+
+DeviceParams
+VideoDevice::getDeviceParams() const
+{
+    return deviceImpl_->getDeviceParams();
+}
+
+void
+VideoDevice::applySettings(VideoSettings settings)
+{
+    deviceImpl_->applySettings(settings);
+}
+
+VideoSettings
+VideoDevice::getSettings() const
+{
+    return deviceImpl_->getSettings();
+}
+
+std::vector<std::string>
+VideoDeviceImpl::getSizeList() const
+{
+    return getSizeList("default");
+}
+
+std::vector<std::string>
+VideoDeviceImpl::getRateList(const std::string& channel, const std::string& size) const
+{
+    auto format = [avDevice_ activeFormat];
+    auto frameRate = (AVFrameRateRange*)
+                    [format.videoSupportedFrameRateRanges objectAtIndex:0];
+
+    std::vector<std::string> v;
+    std::stringstream ss;
+    ss << frameRate.maxFrameRate;
+    v.push_back(ss.str());
+    return v;
+}
+
+std::vector<std::string>
+VideoDeviceImpl::getSizeList(const std::string& channel) const
+{
+    std::vector<std::string> v;
+
+    auto format = [avDevice_ activeFormat];
+    auto dimensions =
+                CMVideoFormatDescriptionGetDimensions(format.formatDescription);
+
+    std::stringstream ss;
+    ss << dimensions.width << "x" << dimensions.height;
+    v.push_back(ss.str());
+
+    return v;
+}
+
+std::vector<std::string> VideoDeviceImpl::getChannelList() const
+{
+    return {"default"};
+}
+
+DRing::VideoCapabilities
+VideoDevice::getCapabilities() const
+{
+    DRing::VideoCapabilities cap;
+
+    for (const auto& chan : deviceImpl_->getChannelList())
+        for (const auto& size : deviceImpl_->getSizeList(chan))
+            cap[chan][size] = deviceImpl_->getRateList(chan, size);
+
+    return cap;
+}
+
+VideoDevice::~VideoDevice()
+{}
+
+}} // namespace ring::video