blob: 09053d3e76ae3dd1a32508684d1ba108a42734b5 [file] [log] [blame]
Alexandre Lisionbe732d42015-02-18 11:48:42 -05001/*
Sébastien Blin31fa5f12021-01-21 16:52:49 -05002 * Copyright (C) 2004-2021 Savoir-faire Linux Inc.
Guillaume Roguez5236ab02015-09-21 12:44:55 -04003 *
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
Adrien Béraud2130f062019-04-02 17:10:48 -040036namespace jami { namespace video {
Alexandre Lisionbe732d42015-02-18 11:48:42 -050037
38class VideoDeviceImpl {
39 public:
40 /**
41 * @throw std::runtime_error
42 */
43 VideoDeviceImpl(const std::string& path);
44
Andreas Traczykd6e2b8a2019-10-28 11:10:44 -040045 std::string id;
Alexandre Lisionbe732d42015-02-18 11:48:42 -050046 std::string name;
47
48 std::vector<std::string> getChannelList() const;
Adrien Béraudbdd139c2016-02-17 13:52:44 -050049 std::vector<VideoSize> getSizeList(const std::string& channel) const;
50 std::vector<VideoSize> getSizeList() const;
51 std::vector<FrameRate> getRateList(const std::string& channel, VideoSize size) const;
Alexandre Lisionbe732d42015-02-18 11:48:42 -050052
53 DeviceParams getDeviceParams() const;
Adrien Béraudbdd139c2016-02-17 13:52:44 -050054 void setDeviceParams(const DeviceParams&);
Alexandre Lisionbe732d42015-02-18 11:48:42 -050055
56 private:
Adrien Béraudbdd139c2016-02-17 13:52:44 -050057 VideoSize extractSize(VideoSize) const;
Alexandre Lisione0676bf2015-12-08 10:35:27 -050058
Alexandre Lisionbe732d42015-02-18 11:48:42 -050059 AVCaptureDevice* avDevice_;
Adrien Béraudbdd139c2016-02-17 13:52:44 -050060 std::vector<VideoSize> available_sizes_;
61 VideoSize current_size_;
Kateryna Kostiuk08222f22019-02-12 14:43:56 -050062 FrameRate rate_ {};
63 std::map<VideoSize, std::vector<FrameRate>> available_rates_;
kkostiukad7284d2021-11-26 17:36:02 -050064 FrameRate desktopFrameRate_ = {30};
65 std::vector<FrameRate> desktopFrameRates_ = {FrameRate(5),
66 FrameRate(10),
67 FrameRate(15),
68 FrameRate(20),
69 FrameRate(25),
70 FrameRate(30),
71 FrameRate(60),
72 FrameRate(120),
73 FrameRate(144)};
Alexandre Lisionbe732d42015-02-18 11:48:42 -050074};
75
76VideoDeviceImpl::VideoDeviceImpl(const std::string& uniqueID)
Andreas Traczykd6e2b8a2019-10-28 11:10:44 -040077 : id(uniqueID)
Alexandre Lisione0676bf2015-12-08 10:35:27 -050078 , current_size_(-1, -1)
Alexandre Lisionbe732d42015-02-18 11:48:42 -050079 , avDevice_([AVCaptureDevice deviceWithUniqueID:
80 [NSString stringWithCString:uniqueID.c_str() encoding:[NSString defaultCStringEncoding]]])
81{
kkostiukad7284d2021-11-26 17:36:02 -050082
83 if (id == DEVICE_DESKTOP) {
84 name = DEVICE_DESKTOP;
85 VideoSize size {0, 0};
86 available_sizes_.emplace_back(size);
87 available_rates_[size] = desktopFrameRates_;
88 return;
89 }
Alexandre Lisionbe732d42015-02-18 11:48:42 -050090 name = [[avDevice_ localizedName] UTF8String];
Alexandre Lisione0676bf2015-12-08 10:35:27 -050091
Adrien Béraudbdd139c2016-02-17 13:52:44 -050092 available_sizes_.reserve(avDevice_.formats.count);
Alexandre Lisione0676bf2015-12-08 10:35:27 -050093 for (AVCaptureDeviceFormat* format in avDevice_.formats) {
Alexandre Lisione0676bf2015-12-08 10:35:27 -050094 auto dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
Adrien Béraudbdd139c2016-02-17 13:52:44 -050095 available_sizes_.emplace_back(dimensions.width, dimensions.height);
Kateryna Kostiuk08222f22019-02-12 14:43:56 -050096 std::vector<FrameRate> v;
97 v.reserve(format.videoSupportedFrameRateRanges.count);
98 for (AVFrameRateRange* frameRateRange in format.videoSupportedFrameRateRanges) {
99 if(std::find(v.begin(), v.end(), frameRateRange.maxFrameRate) == v.end()) {
100 v.emplace_back(frameRateRange.maxFrameRate);
101 }
102 }
103 // if we have multiple formats with the same resolution use video supported framerates from last one
104 // because this format will be selected by ffmpeg
105 if (available_rates_.find( VideoSize(dimensions.width, dimensions.height) ) == available_rates_.end()) {
106 available_rates_.emplace(VideoSize(dimensions.width, dimensions.height), v);
107 } else {
108 available_rates_.at(VideoSize(dimensions.width, dimensions.height)) = v;
109 }
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500110 }
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500111}
112
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500113VideoSize
114VideoDeviceImpl::extractSize(VideoSize size) const
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500115{
116 for (const auto item : available_sizes_) {
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500117 if (item.first == size.first && item.second == size.second)
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500118 return item;
119 }
120
121 // fallback to last size
122 if (!available_sizes_.empty()) {
123 return available_sizes_.back();
124 }
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500125 return VideoSize(0, 0);
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500126}
127
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500128DeviceParams
129VideoDeviceImpl::getDeviceParams() const
130{
131 DeviceParams params;
Andreas Traczykae7c9122020-02-19 12:28:08 -0500132 params.unique_id = id;
Kateryna Kostiuk5e345062019-11-09 16:34:15 -0500133 params.input = id;
kkostiukad7284d2021-11-26 17:36:02 -0500134 if (id == DEVICE_DESKTOP) {
135 params.framerate = desktopFrameRate_;
136 return params;
137 }
138 params.name = [[avDevice_ localizedName] UTF8String];
Kateryna Kostiuk08222f22019-02-12 14:43:56 -0500139 params.framerate = rate_;
philippegorley14084832017-09-25 14:35:17 -0400140 params.format = "avfoundation";
Kateryna Kostiukdf6abf22019-07-09 14:48:39 -0400141 params.pixel_format = "nv12";
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500142 params.width = current_size_.first;
143 params.height = current_size_.second;
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500144 return params;
145}
146
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500147void
148VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500149{
kkostiukad7284d2021-11-26 17:36:02 -0500150 if (id == DEVICE_DESKTOP) {
151 name = DEVICE_DESKTOP;
152 desktopFrameRate_ = params.framerate;
153 return;
154 }
Kateryna Kostiuk08222f22019-02-12 14:43:56 -0500155 rate_ = params.framerate;
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500156 current_size_ = extractSize({params.width, params.height});
157}
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500158
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500159std::vector<VideoSize>
160VideoDeviceImpl::getSizeList() const
161{
162 return getSizeList("default");
163}
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500164
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500165std::vector<FrameRate>
166VideoDeviceImpl::getRateList(const std::string& channel, VideoSize size) const
167{
Kateryna Kostiuk08222f22019-02-12 14:43:56 -0500168 return available_rates_.at(size);
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500169}
Alexandre Lisiona6d408f2016-02-08 15:29:03 -0500170
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500171std::vector<VideoSize>
172VideoDeviceImpl::getSizeList(const std::string& channel) const
173{
174 return available_sizes_;
175}
176
177std::vector<std::string>
178VideoDeviceImpl::getChannelList() const
179{
180 return {"default"};
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500181}
182
atraczyka1b8b132016-12-28 11:51:56 -0500183VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>&) :
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500184 deviceImpl_(new VideoDeviceImpl(path))
185{
Andreas Traczykd6e2b8a2019-10-28 11:10:44 -0400186 id_ = path;
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500187 name = deviceImpl_->name;
188}
189
190DeviceParams
191VideoDevice::getDeviceParams() const
192{
193 return deviceImpl_->getDeviceParams();
194}
195
196void
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500197VideoDevice::setDeviceParams(const DeviceParams& params)
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500198{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500199 return deviceImpl_->setDeviceParams(params);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500200}
201
202std::vector<std::string>
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500203VideoDevice::getChannelList() const
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500204{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500205 return deviceImpl_->getChannelList();
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500206}
207
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500208std::vector<VideoSize>
209VideoDevice::getSizeList(const std::string& channel) const
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500210{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500211 return deviceImpl_->getSizeList(channel);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500212}
213
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500214std::vector<FrameRate>
215VideoDevice::getRateList(const std::string& channel, VideoSize size) const
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500216{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500217 return deviceImpl_->getRateList(channel, size);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500218}
219
220VideoDevice::~VideoDevice()
221{}
222
Adrien Béraud2130f062019-04-02 17:10:48 -0400223}} // namespace jami::video