blob: f298e1549a709bed7c2fb1f407f7645e0ab13899 [file] [log] [blame]
Alexandre Lisionbe732d42015-02-18 11:48:42 -05001/*
Guillaume Roguez5236ab02015-09-21 12:44:55 -04002 * Copyright (C) 2015 Savoir-faire Linux Inc.
3 *
Alexandre Lisionbe732d42015-02-18 11:48:42 -05004 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Alexandre Lisionbe732d42015-02-18 11:48:42 -050019 */
20
21#include <algorithm>
22#include <cassert>
23#include <climits>
24#include <map>
25#include <string>
26#include <sstream>
27#include <stdexcept>
28#include <string>
29#include <vector>
30
31#include "logger.h"
32#include "../video_device.h"
33
34#import <AVFoundation/AVFoundation.h>
35
36namespace ring { namespace video {
37
Alexandre Lisione0676bf2015-12-08 10:35:27 -050038class OSXVideoSize {
39 public:
40 OSXVideoSize(const unsigned width, const unsigned height);
41 unsigned width;
42 unsigned height;
43};
44
Alexandre Lisionbe732d42015-02-18 11:48:42 -050045class VideoDeviceImpl {
46 public:
47 /**
48 * @throw std::runtime_error
49 */
50 VideoDeviceImpl(const std::string& path);
51
52 std::string device;
53 std::string name;
54
55 std::vector<std::string> getChannelList() const;
56 std::vector<std::string> getSizeList(const std::string& channel) const;
57 std::vector<std::string> getSizeList() const;
58 std::vector<std::string> getRateList(const std::string& channel, const std::string& size) const;
59 float getRate(unsigned rate) const;
60
61 VideoSettings getSettings() const;
62 void applySettings(VideoSettings settings);
63
64 DeviceParams getDeviceParams() const;
65
66 private:
Alexandre Lisione0676bf2015-12-08 10:35:27 -050067 const OSXVideoSize extractSize(const std::string &name) const;
68
Alexandre Lisionbe732d42015-02-18 11:48:42 -050069 AVCaptureDevice* avDevice_;
Alexandre Lisione0676bf2015-12-08 10:35:27 -050070 std::vector<OSXVideoSize> available_sizes_;
71 OSXVideoSize current_size_;
Alexandre Lisionbe732d42015-02-18 11:48:42 -050072};
73
74VideoDeviceImpl::VideoDeviceImpl(const std::string& uniqueID)
75 : device(uniqueID)
Alexandre Lisione0676bf2015-12-08 10:35:27 -050076 , current_size_(-1, -1)
Alexandre Lisionbe732d42015-02-18 11:48:42 -050077 , avDevice_([AVCaptureDevice deviceWithUniqueID:
78 [NSString stringWithCString:uniqueID.c_str() encoding:[NSString defaultCStringEncoding]]])
79{
80 name = [[avDevice_ localizedName] UTF8String];
Alexandre Lisione0676bf2015-12-08 10:35:27 -050081
82 for (AVCaptureDeviceFormat* format in avDevice_.formats) {
83 std::stringstream ss;
84 auto dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
85 OSXVideoSize size(dimensions.width, dimensions.height);
86 available_sizes_.push_back(size);
87 }
Alexandre Lisionbe732d42015-02-18 11:48:42 -050088 // Set default settings
89 applySettings(VideoSettings());
90}
91
Alexandre Lisione0676bf2015-12-08 10:35:27 -050092OSXVideoSize::OSXVideoSize(const unsigned width, const unsigned height) :
93 width(width), height(height) {}
94
Alexandre Lisionbe732d42015-02-18 11:48:42 -050095void
96VideoDeviceImpl::applySettings(VideoSettings settings)
97{
Alexandre Lisione0676bf2015-12-08 10:35:27 -050098//TODO: add framerate
Alexandre Lisionbe732d42015-02-18 11:48:42 -050099// rate_ = size_.getRate(settings["rate"]);
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500100 current_size_ = extractSize(settings.video_size);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500101}
102
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500103const OSXVideoSize
104VideoDeviceImpl::extractSize(const std::string &name) const
105{
106 for (const auto item : available_sizes_) {
107 std::stringstream ss;
108 ss << item.width << "x" << item.height;
109 if (ss.str() == name)
110 return item;
111 }
112
113 // fallback to last size
114 if (!available_sizes_.empty()) {
115 return available_sizes_.back();
116 }
117 return OSXVideoSize(-1, -1);
118}
119
120
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500121DeviceParams
122VideoDeviceImpl::getDeviceParams() const
123{
124 DeviceParams params;
125 params.input = "[" + device + "]";
126 params.format = "avfoundation";
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500127
128 params.width = current_size_.width;
129 params.height = current_size_.height;
130
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500131 auto format = [avDevice_ activeFormat];
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500132 auto frameRate = (AVFrameRateRange*)
133 [format.videoSupportedFrameRateRanges objectAtIndex:0];
134 params.framerate = frameRate.maxFrameRate;
135 return params;
136}
137
138VideoSettings
139VideoDeviceImpl::getSettings() const
140{
141 VideoSettings settings;
142
143 settings.name = [[avDevice_ localizedName] UTF8String];
144
145 return settings;
146}
147
148VideoDevice::VideoDevice(const std::string& path) :
149 deviceImpl_(new VideoDeviceImpl(path))
150{
151 node_ = path;
152 name = deviceImpl_->name;
153}
154
155DeviceParams
156VideoDevice::getDeviceParams() const
157{
158 return deviceImpl_->getDeviceParams();
159}
160
161void
162VideoDevice::applySettings(VideoSettings settings)
163{
164 deviceImpl_->applySettings(settings);
165}
166
167VideoSettings
168VideoDevice::getSettings() const
169{
170 return deviceImpl_->getSettings();
171}
172
173std::vector<std::string>
174VideoDeviceImpl::getSizeList() const
175{
176 return getSizeList("default");
177}
178
179std::vector<std::string>
180VideoDeviceImpl::getRateList(const std::string& channel, const std::string& size) const
181{
182 auto format = [avDevice_ activeFormat];
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500183 std::vector<std::string> v;
Alexandre Lision4bb2a502015-03-25 15:49:27 -0400184
185 for (AVFrameRateRange* frameRateRange in format.videoSupportedFrameRateRanges) {
186 std::stringstream ss;
187 ss << frameRateRange.maxFrameRate;
188 v.push_back(ss.str());
189 }
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500190 return v;
191}
192
193std::vector<std::string>
194VideoDeviceImpl::getSizeList(const std::string& channel) const
195{
196 std::vector<std::string> v;
197
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500198 for (const auto &item : available_sizes_) {
199 std::stringstream ss;
200 ss << item.width << "x" << item.height;
Alexandre Lision4bb2a502015-03-25 15:49:27 -0400201 v.push_back(ss.str());
202 }
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500203
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500204 return v;
205}
206
207std::vector<std::string> VideoDeviceImpl::getChannelList() const
208{
209 return {"default"};
210}
211
212DRing::VideoCapabilities
213VideoDevice::getCapabilities() const
214{
215 DRing::VideoCapabilities cap;
216
217 for (const auto& chan : deviceImpl_->getChannelList())
218 for (const auto& size : deviceImpl_->getSizeList(chan))
219 cap[chan][size] = deviceImpl_->getRateList(chan, size);
220
221 return cap;
222}
223
224VideoDevice::~VideoDevice()
225{}
226
227}} // namespace ring::video