| /* |
| * Copyright (C) 2004-2021 Savoir-faire Linux Inc. |
| * |
| * Author: Rafaël Carré <rafael.carre@savoirfairelinux.com> |
| * Author: Vivien Didelot <vivien.didelot@savoirfairelinux.com> |
| * Author: Andreas Traczyk <andreas.traczyk@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. |
| */ |
| |
| #include <array> |
| |
| extern "C" { |
| #include <libavutil/pixfmt.h> |
| } |
| |
| #include "logger.h" |
| #include "../video_device.h" |
| |
| #include "client/ring_signal.h" |
| |
| namespace jami { |
| namespace video { |
| |
| typedef struct |
| { |
| std::string name; |
| enum AVPixelFormat pixfmt; |
| } ios_fmt; |
| |
| static const std::array<ios_fmt, 4> ios_formats {ios_fmt {"RGBA", AV_PIX_FMT_RGBA}, |
| ios_fmt {"BGRA", AV_PIX_FMT_BGRA}, |
| ios_fmt {"YUV420P", AV_PIX_FMT_YUV420P}}; |
| |
| class VideoDeviceImpl |
| { |
| public: |
| VideoDeviceImpl(const std::string& path, |
| const std::vector<std::map<std::string, std::string>>& devInfo); |
| |
| std::string name; |
| |
| DeviceParams getDeviceParams() const; |
| |
| void setDeviceParams(const DeviceParams&); |
| void selectFormat(); |
| |
| std::vector<VideoSize> getSizeList() const; |
| std::vector<FrameRate> getRateList() const; |
| |
| private: |
| VideoSize getSize(VideoSize size) const; |
| FrameRate getRate(FrameRate rate) const; |
| |
| std::vector<std::string> formats_ {}; |
| std::vector<VideoSize> sizes_ {}; |
| std::vector<FrameRate> rates_ {}; |
| |
| const ios_fmt* fmt_ {nullptr}; |
| VideoSize size_ {}; |
| FrameRate rate_ {}; |
| }; |
| |
| void |
| VideoDeviceImpl::selectFormat() |
| { |
| unsigned best = UINT_MAX; |
| for (auto fmt : formats_) { |
| auto f = ios_formats.begin(); |
| for (; f != ios_formats.end(); ++f) { |
| if (f->name == fmt) { |
| auto pos = std::distance(ios_formats.begin(), f); |
| if (pos < best) |
| best = pos; |
| break; |
| } |
| } |
| if (f == ios_formats.end()) |
| JAMI_WARN("Video: No format matching %s", fmt.c_str()); |
| } |
| |
| if (best != UINT_MAX) { |
| fmt_ = &ios_formats[best]; |
| JAMI_DBG("Video: picked format %s", fmt_->name.c_str()); |
| } else { |
| fmt_ = &ios_formats[0]; |
| JAMI_ERR("Video: Could not find a known format to use"); |
| } |
| } |
| |
| VideoDeviceImpl::VideoDeviceImpl(const std::string& path, |
| const std::vector<std::map<std::string, std::string>>& devInfo) |
| : name(path) |
| { |
| for (auto& setting : devInfo) { |
| formats_.emplace_back(setting.at("format")); |
| sizes_.emplace_back(std::stoi(setting.at("width")), std::stoi(setting.at("height"))); |
| rates_.emplace_back(std::stoi(setting.at("rate")), 1); |
| } |
| selectFormat(); |
| } |
| |
| VideoSize |
| VideoDeviceImpl::getSize(VideoSize size) const |
| { |
| for (const auto& iter : sizes_) { |
| if (iter == size) |
| return iter; |
| } |
| |
| return sizes_.empty() ? VideoSize {0, 0} : sizes_.back(); |
| } |
| |
| FrameRate |
| VideoDeviceImpl::getRate(FrameRate rate) const |
| { |
| for (const auto& iter : rates_) { |
| if (iter == rate) |
| return iter; |
| } |
| |
| return rates_.empty() ? FrameRate {0, 0} : rates_.back(); |
| } |
| |
| std::vector<VideoSize> |
| VideoDeviceImpl::getSizeList() const |
| { |
| return sizes_; |
| } |
| |
| std::vector<FrameRate> |
| VideoDeviceImpl::getRateList() const |
| { |
| return rates_; |
| } |
| |
| DeviceParams |
| VideoDeviceImpl::getDeviceParams() const |
| { |
| DeviceParams params; |
| std::stringstream ss1, ss2; |
| |
| ss1 << fmt_->pixfmt; |
| ss1 >> params.format; |
| |
| params.name = name; |
| params.input = name; |
| params.unique_id = name; |
| params.channel = 0; |
| params.pixel_format = "nv12"; |
| params.width = size_.first; |
| params.height = size_.second; |
| params.framerate = rate_; |
| |
| return params; |
| } |
| |
| void |
| VideoDeviceImpl::setDeviceParams(const DeviceParams& params) |
| { |
| size_ = getSize({params.width, params.height}); |
| rate_ = getRate(params.framerate); |
| emitSignal<DRing::VideoSignal::ParametersChanged>(name); |
| } |
| |
| VideoDevice::VideoDevice(const std::string& path, |
| const std::vector<std::map<std::string, std::string>>& devInfo) |
| : deviceImpl_(new VideoDeviceImpl(path, devInfo)) |
| { |
| id_ = path; |
| name = deviceImpl_->name; |
| } |
| |
| DeviceParams |
| VideoDevice::getDeviceParams() const |
| { |
| return deviceImpl_->getDeviceParams(); |
| } |
| |
| void |
| VideoDevice::setDeviceParams(const DeviceParams& params) |
| { |
| return deviceImpl_->setDeviceParams(params); |
| } |
| |
| std::vector<std::string> |
| VideoDevice::getChannelList() const |
| { |
| return {"default"}; |
| } |
| |
| std::vector<VideoSize> |
| VideoDevice::getSizeList(const std::string& channel) const |
| { |
| return deviceImpl_->getSizeList(); |
| } |
| |
| std::vector<FrameRate> |
| VideoDevice::getRateList(const std::string& channel, VideoSize size) const |
| { |
| return deviceImpl_->getRateList(); |
| } |
| |
| VideoDevice::~VideoDevice() {} |
| |
| } // namespace video |
| } // namespace jami |