blob: 7888c216640b6a44dd52f25d4f558ec506343329 [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_;
Alexandre Lisionbe732d42015-02-18 11:48:42 -050064};
65
66VideoDeviceImpl::VideoDeviceImpl(const std::string& uniqueID)
Andreas Traczykd6e2b8a2019-10-28 11:10:44 -040067 : id(uniqueID)
Alexandre Lisione0676bf2015-12-08 10:35:27 -050068 , current_size_(-1, -1)
Alexandre Lisionbe732d42015-02-18 11:48:42 -050069 , avDevice_([AVCaptureDevice deviceWithUniqueID:
70 [NSString stringWithCString:uniqueID.c_str() encoding:[NSString defaultCStringEncoding]]])
71{
72 name = [[avDevice_ localizedName] UTF8String];
Alexandre Lisione0676bf2015-12-08 10:35:27 -050073
Adrien Béraudbdd139c2016-02-17 13:52:44 -050074 available_sizes_.reserve(avDevice_.formats.count);
Alexandre Lisione0676bf2015-12-08 10:35:27 -050075 for (AVCaptureDeviceFormat* format in avDevice_.formats) {
Alexandre Lisione0676bf2015-12-08 10:35:27 -050076 auto dimensions = CMVideoFormatDescriptionGetDimensions(format.formatDescription);
Adrien Béraudbdd139c2016-02-17 13:52:44 -050077 available_sizes_.emplace_back(dimensions.width, dimensions.height);
Kateryna Kostiuk08222f22019-02-12 14:43:56 -050078 std::vector<FrameRate> v;
79 v.reserve(format.videoSupportedFrameRateRanges.count);
80 for (AVFrameRateRange* frameRateRange in format.videoSupportedFrameRateRanges) {
81 if(std::find(v.begin(), v.end(), frameRateRange.maxFrameRate) == v.end()) {
82 v.emplace_back(frameRateRange.maxFrameRate);
83 }
84 }
85 // if we have multiple formats with the same resolution use video supported framerates from last one
86 // because this format will be selected by ffmpeg
87 if (available_rates_.find( VideoSize(dimensions.width, dimensions.height) ) == available_rates_.end()) {
88 available_rates_.emplace(VideoSize(dimensions.width, dimensions.height), v);
89 } else {
90 available_rates_.at(VideoSize(dimensions.width, dimensions.height)) = v;
91 }
Alexandre Lisione0676bf2015-12-08 10:35:27 -050092 }
Alexandre Lisionbe732d42015-02-18 11:48:42 -050093}
94
Adrien Béraudbdd139c2016-02-17 13:52:44 -050095VideoSize
96VideoDeviceImpl::extractSize(VideoSize size) const
Alexandre Lisione0676bf2015-12-08 10:35:27 -050097{
98 for (const auto item : available_sizes_) {
Adrien Béraudbdd139c2016-02-17 13:52:44 -050099 if (item.first == size.first && item.second == size.second)
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500100 return item;
101 }
102
103 // fallback to last size
104 if (!available_sizes_.empty()) {
105 return available_sizes_.back();
106 }
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500107 return VideoSize(0, 0);
Alexandre Lisione0676bf2015-12-08 10:35:27 -0500108}
109
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500110DeviceParams
111VideoDeviceImpl::getDeviceParams() const
112{
113 DeviceParams params;
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500114 params.name = [[avDevice_ localizedName] UTF8String];
Andreas Traczykae7c9122020-02-19 12:28:08 -0500115 params.unique_id = id;
Kateryna Kostiuk5e345062019-11-09 16:34:15 -0500116 params.input = id;
Kateryna Kostiuk08222f22019-02-12 14:43:56 -0500117 params.framerate = rate_;
philippegorley14084832017-09-25 14:35:17 -0400118 params.format = "avfoundation";
Kateryna Kostiukdf6abf22019-07-09 14:48:39 -0400119 params.pixel_format = "nv12";
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500120 params.width = current_size_.first;
121 params.height = current_size_.second;
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500122 return params;
123}
124
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500125void
126VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500127{
Kateryna Kostiuk08222f22019-02-12 14:43:56 -0500128 rate_ = params.framerate;
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500129 current_size_ = extractSize({params.width, params.height});
130}
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500131
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500132std::vector<VideoSize>
133VideoDeviceImpl::getSizeList() const
134{
135 return getSizeList("default");
136}
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500137
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500138std::vector<FrameRate>
139VideoDeviceImpl::getRateList(const std::string& channel, VideoSize size) const
140{
Kateryna Kostiuk08222f22019-02-12 14:43:56 -0500141 return available_rates_.at(size);
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500142}
Alexandre Lisiona6d408f2016-02-08 15:29:03 -0500143
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500144std::vector<VideoSize>
145VideoDeviceImpl::getSizeList(const std::string& channel) const
146{
147 return available_sizes_;
148}
149
150std::vector<std::string>
151VideoDeviceImpl::getChannelList() const
152{
153 return {"default"};
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500154}
155
atraczyka1b8b132016-12-28 11:51:56 -0500156VideoDevice::VideoDevice(const std::string& path, const std::vector<std::map<std::string, std::string>>&) :
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500157 deviceImpl_(new VideoDeviceImpl(path))
158{
Andreas Traczykd6e2b8a2019-10-28 11:10:44 -0400159 id_ = path;
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500160 name = deviceImpl_->name;
161}
162
163DeviceParams
164VideoDevice::getDeviceParams() const
165{
166 return deviceImpl_->getDeviceParams();
167}
168
169void
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500170VideoDevice::setDeviceParams(const DeviceParams& params)
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500171{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500172 return deviceImpl_->setDeviceParams(params);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500173}
174
175std::vector<std::string>
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500176VideoDevice::getChannelList() const
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500177{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500178 return deviceImpl_->getChannelList();
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500179}
180
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500181std::vector<VideoSize>
182VideoDevice::getSizeList(const std::string& channel) const
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500183{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500184 return deviceImpl_->getSizeList(channel);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500185}
186
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500187std::vector<FrameRate>
188VideoDevice::getRateList(const std::string& channel, VideoSize size) const
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500189{
Adrien Béraudbdd139c2016-02-17 13:52:44 -0500190 return deviceImpl_->getRateList(channel, size);
Alexandre Lisionbe732d42015-02-18 11:48:42 -0500191}
192
193VideoDevice::~VideoDevice()
194{}
195
Adrien Béraud2130f062019-04-02 17:10:48 -0400196}} // namespace jami::video