blob: 5795fb999badf0726cd9e2362f59c2a5d4a1f88a [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
Alexandre Lisiona6d408f2016-02-08 15:29:03 -0500145 auto format = [avDevice_ activeFormat];
146 auto frameRate = (AVFrameRateRange*)
147 [format.videoSupportedFrameRateRanges objectAtIndex:0];
148 settings.framerate = frameRate.maxFrameRate;
149 settings.video_size = std::to_string(current_size_.width) +
150 "x" + std::to_string(current_size_.height);
151
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500152 return settings;
153}
154
155VideoDevice::VideoDevice(const std::string& path) :
156 deviceImpl_(new VideoDeviceImpl(path))
157{
158 node_ = path;
159 name = deviceImpl_->name;
160}
161
162DeviceParams
163VideoDevice::getDeviceParams() const
164{
165 return deviceImpl_->getDeviceParams();
166}
167
168void
169VideoDevice::applySettings(VideoSettings settings)
170{
171 deviceImpl_->applySettings(settings);
172}
173
174VideoSettings
175VideoDevice::getSettings() const
176{
177 return deviceImpl_->getSettings();
178}
179
180std::vector<std::string>
181VideoDeviceImpl::getSizeList() const
182{
183 return getSizeList("default");
184}
185
186std::vector<std::string>
187VideoDeviceImpl::getRateList(const std::string& channel, const std::string& size) const
188{
189 auto format = [avDevice_ activeFormat];
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500190 std::vector<std::string> v;
Alexandre Lision4bb2a502015-03-25 15:49:27 -0400191
192 for (AVFrameRateRange* frameRateRange in format.videoSupportedFrameRateRanges) {
193 std::stringstream ss;
194 ss << frameRateRange.maxFrameRate;
195 v.push_back(ss.str());
196 }
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500197 return v;
198}
199
200std::vector<std::string>
201VideoDeviceImpl::getSizeList(const std::string& channel) const
202{
203 std::vector<std::string> v;
204
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500205 for (const auto &item : available_sizes_) {
206 std::stringstream ss;
207 ss << item.width << "x" << item.height;
Alexandre Lision4bb2a502015-03-25 15:49:27 -0400208 v.push_back(ss.str());
209 }
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500210
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500211 return v;
212}
213
214std::vector<std::string> VideoDeviceImpl::getChannelList() const
215{
216 return {"default"};
217}
218
219DRing::VideoCapabilities
220VideoDevice::getCapabilities() const
221{
222 DRing::VideoCapabilities cap;
223
224 for (const auto& chan : deviceImpl_->getChannelList())
225 for (const auto& size : deviceImpl_->getSizeList(chan))
226 cap[chan][size] = deviceImpl_->getRateList(chan, size);
227
228 return cap;
229}
230
231VideoDevice::~VideoDevice()
232{}
233
234}} // namespace ring::video