LCOV - code coverage report
Current view: top level - src/media/video/v4l2 - video_device_impl.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 24.8 % 274 68
Test Date: 2026-06-13 09:18:46 Functions: 44.4 % 36 16

            Line data    Source code
       1              : /*
       2              :  *  Copyright (C) 2004-2026 Savoir-faire Linux Inc.
       3              :  *
       4              :  *  This program is free software: you can redistribute it and/or modify
       5              :  *  it under the terms of the GNU General Public License as published by
       6              :  *  the Free Software Foundation, either version 3 of the License, or
       7              :  *  (at your option) any later version.
       8              :  *
       9              :  *  This program is distributed in the hope that it will be useful,
      10              :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12              :  *  GNU General Public License for more details.
      13              :  *
      14              :  *  You should have received a copy of the GNU General Public License
      15              :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #include <algorithm>
      19              : #include <cassert>
      20              : #include <climits>
      21              : #include <cstring>
      22              : #include <map>
      23              : #include <sstream>
      24              : #include <stdexcept>
      25              : #include <string>
      26              : #include <vector>
      27              : 
      28              : extern "C" {
      29              : #include <linux/videodev2.h>
      30              : #if !defined(VIDIOC_ENUM_FRAMESIZES) || !defined(VIDIOC_ENUM_FRAMEINTERVALS)
      31              : #error You need at least Linux 2.6.19
      32              : #endif
      33              : 
      34              : #include <fcntl.h>
      35              : #include <unistd.h>
      36              : #include <sys/ioctl.h>
      37              : }
      38              : 
      39              : #include "logger.h"
      40              : #include "../video_device.h"
      41              : #include "string_utils.h"
      42              : 
      43              : #define ZEROVAR(x) std::memset(&(x), 0, sizeof(x))
      44              : 
      45              : namespace jami {
      46              : namespace video {
      47              : 
      48              : class VideoV4l2Rate
      49              : {
      50              : public:
      51           32 :     VideoV4l2Rate(unsigned rate_numerator = 0, unsigned rate_denominator = 0, unsigned format = 0)
      52           32 :         : frame_rate(rate_denominator, rate_numerator)
      53              :     {
      54           32 :         if (format)
      55            0 :             pixel_formats.push_back(format);
      56           32 :     }
      57              : 
      58              :     FrameRate frame_rate;
      59              :     std::vector<unsigned> pixel_formats;
      60              :     std::string libAvPixelformat(bool passthrough = false) const;
      61              : };
      62              : 
      63              : class VideoV4l2Size
      64              : {
      65              : public:
      66           32 :     VideoV4l2Size(const unsigned width, const unsigned height)
      67           32 :         : width(width)
      68           32 :         , height(height)
      69           32 :         , rates_()
      70           32 :     {}
      71              : 
      72              :     /**
      73              :      * @throw std::runtime_error
      74              :      */
      75              :     void readFrameRates(int fd, unsigned int pixel_format);
      76              : 
      77              :     std::vector<FrameRate> getRateList() const;
      78              :     VideoV4l2Rate getRate(const FrameRate& rate) const;
      79              : 
      80              :     unsigned width;
      81              :     unsigned height;
      82              : 
      83              : private:
      84              :     void addRate(VideoV4l2Rate proposed_rate);
      85              :     std::vector<VideoV4l2Rate> rates_;
      86              : };
      87              : 
      88              : bool
      89            0 : operator==(VideoV4l2Size& a, VideoV4l2Size& b)
      90              : {
      91            0 :     return a.height == b.height && a.width == b.width;
      92              : }
      93              : 
      94              : class VideoV4l2Channel
      95              : {
      96              : public:
      97              :     VideoV4l2Channel(unsigned idx, const char* s);
      98              : 
      99              :     /**
     100              :      * @throw std::runtime_error
     101              :      */
     102              :     void readFormats(int fd);
     103              : 
     104              :     /**
     105              :      * @throw std::runtime_error
     106              :      */
     107              :     unsigned int readSizes(int fd, unsigned int pixel_format);
     108              : 
     109              :     std::vector<VideoSize> getSizeList() const;
     110              :     const VideoV4l2Size& getSize(VideoSize name) const;
     111              : 
     112              :     unsigned idx;
     113              :     std::string name;
     114              : 
     115              : private:
     116              :     void putCIFFirst();
     117              :     std::vector<VideoV4l2Size> sizes_;
     118              : };
     119              : 
     120              : class VideoDeviceImpl
     121              : {
     122              : public:
     123              :     /**
     124              :      * @throw std::runtime_error
     125              :      */
     126              :     VideoDeviceImpl(const std::string& id, const std::string& path);
     127              : 
     128              :     std::string unique_id;
     129              :     std::string path;
     130              :     std::string name;
     131              : 
     132              :     std::vector<std::string> getChannelList() const;
     133              :     std::vector<VideoSize> getSizeList(const std::string& channel) const;
     134              :     std::vector<FrameRate> getRateList(const std::string& channel, VideoSize size) const;
     135              : 
     136              :     DeviceParams getDeviceParams() const;
     137              :     void setDeviceParams(const DeviceParams&);
     138              : 
     139              : private:
     140              :     std::vector<VideoV4l2Channel> channels_;
     141              :     const VideoV4l2Channel& getChannel(const std::string& name) const;
     142              : 
     143              :     /* Preferences */
     144              :     VideoV4l2Channel channel_;
     145              :     VideoV4l2Size size_;
     146              :     VideoV4l2Rate rate_;
     147              :     bool passthrough_ = false;
     148              : };
     149              : 
     150              : static const unsigned pixelformats_supported[] = {
     151              :     /* pixel format        depth  description   */
     152              : 
     153              :     /* preferred formats, they can be fed directly to the video encoder */
     154              :     V4L2_PIX_FMT_YUV420,  /* 12  YUV 4:2:0     */
     155              :     V4L2_PIX_FMT_YUV422P, /* 16  YVU422 planar */
     156              :     V4L2_PIX_FMT_YUV444,  /* 16  xxxxyyyy uuuuvvvv */
     157              : 
     158              :     /* Luminance+Chrominance formats */
     159              :     V4L2_PIX_FMT_YVU410,  /*  9  YVU 4:1:0     */
     160              :     V4L2_PIX_FMT_YVU420,  /* 12  YVU 4:2:0     */
     161              :     V4L2_PIX_FMT_YUYV,    /* 16  YUV 4:2:2     */
     162              :     V4L2_PIX_FMT_YYUV,    /* 16  YUV 4:2:2     */
     163              :     V4L2_PIX_FMT_YVYU,    /* 16 YVU 4:2:2 */
     164              :     V4L2_PIX_FMT_UYVY,    /* 16  YUV 4:2:2     */
     165              :     V4L2_PIX_FMT_VYUY,    /* 16  YUV 4:2:2     */
     166              :     V4L2_PIX_FMT_YUV411P, /* 16  YVU411 planar */
     167              :     V4L2_PIX_FMT_Y41P,    /* 12  YUV 4:1:1     */
     168              :     V4L2_PIX_FMT_YUV555,  /* 16  YUV-5-5-5     */
     169              :     V4L2_PIX_FMT_YUV565,  /* 16  YUV-5-6-5     */
     170              :     V4L2_PIX_FMT_YUV32,   /* 32  YUV-8-8-8-8   */
     171              :     V4L2_PIX_FMT_YUV410,  /*  9  YUV 4:1:0     */
     172              :     V4L2_PIX_FMT_HI240,   /*  8  8-bit color   */
     173              :     V4L2_PIX_FMT_HM12,    /*  8  YUV 4:2:0 16x16 macroblocks */
     174              : 
     175              :     /* two planes -- one Y, one Cr + Cb interleaved  */
     176              :     V4L2_PIX_FMT_NV12, /* 12  Y/CbCr 4:2:0  */
     177              :     V4L2_PIX_FMT_NV21, /* 12  Y/CrCb 4:2:0  */
     178              :     V4L2_PIX_FMT_NV16, /* 16  Y/CbCr 4:2:2  */
     179              :     V4L2_PIX_FMT_NV61, /* 16  Y/CrCb 4:2:2  */
     180              : 
     181              :     /* Compressed formats */
     182              :     V4L2_PIX_FMT_MJPEG,
     183              :     V4L2_PIX_FMT_JPEG,
     184              :     V4L2_PIX_FMT_DV,
     185              :     V4L2_PIX_FMT_MPEG,
     186              :     V4L2_PIX_FMT_H264,
     187              :     V4L2_PIX_FMT_H264_NO_SC,
     188              :     V4L2_PIX_FMT_H264_MVC,
     189              :     V4L2_PIX_FMT_H263,
     190              :     V4L2_PIX_FMT_MPEG1,
     191              :     V4L2_PIX_FMT_MPEG2,
     192              :     V4L2_PIX_FMT_MPEG4,
     193              :     V4L2_PIX_FMT_XVID,
     194              :     V4L2_PIX_FMT_VC1_ANNEX_G,
     195              :     V4L2_PIX_FMT_VC1_ANNEX_L,
     196              :     V4L2_PIX_FMT_VP8,
     197              : 
     198              : #if 0
     199              :     /* RGB formats */
     200              :     V4L2_PIX_FMT_RGB332,   /*  8  RGB-3-3-2     */
     201              :     V4L2_PIX_FMT_RGB444,   /* 16  xxxxrrrr ggggbbbb */
     202              :     V4L2_PIX_FMT_RGB555,   /* 16  RGB-5-5-5     */
     203              :     V4L2_PIX_FMT_RGB565,   /* 16  RGB-5-6-5     */
     204              :     V4L2_PIX_FMT_RGB555X,  /* 16  RGB-5-5-5 BE  */
     205              :     V4L2_PIX_FMT_RGB565X,  /* 16  RGB-5-6-5 BE  */
     206              :     V4L2_PIX_FMT_BGR666,   /* 18  BGR-6-6-6     */
     207              :     V4L2_PIX_FMT_BGR24,    /* 24  BGR-8-8-8     */
     208              :     V4L2_PIX_FMT_RGB24,    /* 24  RGB-8-8-8     */
     209              :     V4L2_PIX_FMT_BGR32,    /* 32  BGR-8-8-8-8   */
     210              :     V4L2_PIX_FMT_RGB32,    /* 32  RGB-8-8-8-8   */
     211              : 
     212              :     /* Grey formats */
     213              :     V4L2_PIX_FMT_GREY,     /*  8  Greyscale     */
     214              :     V4L2_PIX_FMT_Y4,       /*  4  Greyscale     */
     215              :     V4L2_PIX_FMT_Y6,       /*  6  Greyscale     */
     216              :     V4L2_PIX_FMT_Y10,      /* 10  Greyscale     */
     217              :     V4L2_PIX_FMT_Y16,      /* 16  Greyscale     */
     218              : 
     219              :     /* Palette formats */
     220              :     V4L2_PIX_FMT_PAL8,     /*  8  8-bit palette */
     221              : #endif
     222              : };
     223              : 
     224              : /* Returns a score for the given pixelformat
     225              :  *
     226              :  * Lowest score is the best, the first entries in the array are the formats
     227              :  * supported as an input for the video encoders.
     228              :  *
     229              :  * See pixelformats_supported array for the support list.
     230              :  */
     231              : static unsigned int
     232            0 : pixelformat_score(unsigned pixelformat)
     233              : {
     234            0 :     unsigned int formats_count = std::size(pixelformats_supported);
     235            0 :     for (unsigned int i = 0; i < formats_count; ++i) {
     236            0 :         if (pixelformats_supported[i] == pixelformat)
     237            0 :             return i;
     238              :     }
     239            0 :     return UINT_MAX - 1;
     240              : }
     241              : 
     242              : using std::vector;
     243              : using std::string;
     244              : 
     245              : vector<FrameRate>
     246            0 : VideoV4l2Size::getRateList() const
     247              : {
     248            0 :     vector<FrameRate> rates;
     249            0 :     rates.reserve(rates_.size());
     250            0 :     for (const auto& r : rates_)
     251            0 :         rates.emplace_back(r.frame_rate);
     252            0 :     return rates;
     253            0 : }
     254              : 
     255              : void
     256            0 : VideoV4l2Size::readFrameRates(int fd, unsigned int pixel_format)
     257              : {
     258            0 :     VideoV4l2Rate fallback_rate {1, 25, pixel_format};
     259              : 
     260              :     v4l2_frmivalenum frmival;
     261            0 :     ZEROVAR(frmival);
     262            0 :     frmival.pixel_format = pixel_format;
     263            0 :     frmival.width = width;
     264            0 :     frmival.height = height;
     265              : 
     266            0 :     if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival)) {
     267            0 :         addRate(fallback_rate);
     268            0 :         JAMI_ERROR("Unable to query frame interval for size");
     269            0 :         return;
     270              :     }
     271              : 
     272            0 :     if (frmival.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
     273            0 :         addRate(fallback_rate);
     274            0 :         JAMI_ERROR("Continuous and stepwise Frame Intervals are not supported");
     275            0 :         return;
     276              :     }
     277              : 
     278              :     do {
     279            0 :         addRate({frmival.discrete.numerator, frmival.discrete.denominator, pixel_format});
     280            0 :         ++frmival.index;
     281            0 :     } while (!ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival));
     282            0 : }
     283              : 
     284              : VideoV4l2Rate
     285            0 : VideoV4l2Size::getRate(const FrameRate& rate) const
     286              : {
     287            0 :     for (const auto& item : rates_) {
     288            0 :         if (std::fabs((item.frame_rate - rate).real()) < 0.0001)
     289            0 :             return item;
     290              :     }
     291            0 :     return rates_.back();
     292              : }
     293              : 
     294              : void
     295            0 : VideoV4l2Size::addRate(VideoV4l2Rate new_rate)
     296              : {
     297            0 :     for (auto& item : rates_) {
     298            0 :         if (item.frame_rate == new_rate.frame_rate) {
     299            0 :             for (auto fmt : new_rate.pixel_formats) {
     300            0 :                 if (std::find(item.pixel_formats.begin(), item.pixel_formats.end(), fmt) == item.pixel_formats.end())
     301            0 :                     item.pixel_formats.push_back(fmt);
     302              :             }
     303            0 :             return;
     304              :         }
     305              :     }
     306              : 
     307            0 :     rates_.push_back(new_rate);
     308              : }
     309              : 
     310           32 : VideoV4l2Channel::VideoV4l2Channel(unsigned idx, const char* s)
     311           32 :     : idx(idx)
     312           64 :     , name(s)
     313           32 :     , sizes_()
     314           32 : {}
     315              : 
     316              : std::vector<VideoSize>
     317            0 : VideoV4l2Channel::getSizeList() const
     318              : {
     319            0 :     vector<VideoSize> v;
     320            0 :     v.reserve(sizes_.size());
     321            0 :     for (const auto& item : sizes_)
     322            0 :         v.emplace_back(item.width, item.height);
     323              : 
     324            0 :     return v;
     325            0 : }
     326              : 
     327              : unsigned int
     328            0 : VideoV4l2Channel::readSizes(int fd, unsigned int pixelformat)
     329              : {
     330              :     v4l2_frmsizeenum frmsize;
     331            0 :     ZEROVAR(frmsize);
     332              : 
     333            0 :     frmsize.index = 0;
     334            0 :     frmsize.pixel_format = pixelformat;
     335              : 
     336            0 :     if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) < 0) {
     337              :         v4l2_format fmt;
     338            0 :         ZEROVAR(fmt);
     339              : 
     340            0 :         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     341            0 :         if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
     342            0 :             throw std::runtime_error("Unable to get format");
     343              : 
     344            0 :         VideoV4l2Size size(fmt.fmt.pix.width, fmt.fmt.pix.height);
     345            0 :         size.readFrameRates(fd, fmt.fmt.pix.pixelformat);
     346            0 :         sizes_.push_back(size);
     347              : 
     348            0 :         return fmt.fmt.pix.pixelformat;
     349            0 :     }
     350              : 
     351            0 :     if (frmsize.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
     352              :         // We do not take care of V4L2_FRMSIZE_TYPE_CONTINUOUS or V4L2_FRMSIZE_TYPE_STEPWISE
     353            0 :         JAMI_ERROR("Continuous Frame sizes not supported");
     354            0 :         return pixelformat;
     355              :     }
     356              : 
     357              :     // Real work starts here: attach framerates to sizes and update pixelformat information
     358              :     do {
     359            0 :         bool size_exists = false;
     360            0 :         VideoV4l2Size size(frmsize.discrete.width, frmsize.discrete.height);
     361              : 
     362            0 :         for (auto& item : sizes_) {
     363            0 :             if (item == size) {
     364            0 :                 size_exists = true;
     365              :                 // If a size already exist we add frame rates since there may be some
     366              :                 // frame rates available in one format that are not availabe in another.
     367            0 :                 item.readFrameRates(fd, frmsize.pixel_format);
     368              :             }
     369              :         }
     370              : 
     371            0 :         if (!size_exists) {
     372            0 :             size.readFrameRates(fd, frmsize.pixel_format);
     373            0 :             sizes_.push_back(size);
     374              :         }
     375              : 
     376            0 :         ++frmsize.index;
     377            0 :     } while (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize));
     378              : 
     379            0 :     return pixelformat;
     380              : }
     381              : 
     382              : // Put CIF resolution (352x288) first in the list since it is more prevalent in
     383              : // VoIP
     384              : void
     385            0 : VideoV4l2Channel::putCIFFirst()
     386              : {
     387            0 :     const auto iter = std::find_if(sizes_.begin(), sizes_.end(), [](const VideoV4l2Size& size) {
     388            0 :         return size.width == 352 and size.height == 258;
     389              :     });
     390              : 
     391            0 :     if (iter != sizes_.end() and iter != sizes_.begin())
     392            0 :         std::swap(*iter, *sizes_.begin());
     393            0 : }
     394              : 
     395              : void
     396            0 : VideoV4l2Channel::readFormats(int fd)
     397              : {
     398            0 :     if (ioctl(fd, VIDIOC_S_INPUT, &idx))
     399            0 :         throw std::runtime_error("VIDIOC_S_INPUT failed");
     400              : 
     401              :     v4l2_fmtdesc fmt;
     402            0 :     ZEROVAR(fmt);
     403            0 :     unsigned fmt_index = 0;
     404              : 
     405            0 :     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
     406            0 :     while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmt)) {
     407            0 :         if (fmt_index != fmt.index)
     408            0 :             break;
     409            0 :         readSizes(fd, fmt.pixelformat);
     410            0 :         fmt.index = ++fmt_index;
     411              :     }
     412              : 
     413            0 :     if (fmt_index == 0)
     414            0 :         throw std::runtime_error("Unable to enumerate formats");
     415              : 
     416            0 :     putCIFFirst();
     417            0 : }
     418              : 
     419              : const VideoV4l2Size&
     420            0 : VideoV4l2Channel::getSize(VideoSize s) const
     421              : {
     422            0 :     for (const auto& item : sizes_) {
     423            0 :         if (item.width == s.first && item.height == s.second)
     424            0 :             return item;
     425              :     }
     426              : 
     427            0 :     assert(not sizes_.empty());
     428            0 :     return sizes_.front();
     429              : }
     430              : 
     431           32 : VideoDeviceImpl::VideoDeviceImpl(const string& id, const std::string& path)
     432           32 :     : unique_id(id)
     433           32 :     , path(path)
     434           32 :     , name()
     435           32 :     , channels_()
     436           32 :     , channel_(-1, "")
     437           32 :     , size_(-1, -1)
     438           32 :     , rate_(-1, 1, 0)
     439              : {
     440           32 :     if (id == DEVICE_DESKTOP) {
     441           32 :         name = DEVICE_DESKTOP;
     442           32 :         rate_.frame_rate = 30;
     443           32 :         return;
     444              :     }
     445            0 :     int fd = open(path.c_str(), O_RDWR);
     446            0 :     if (fd == -1)
     447            0 :         throw std::runtime_error("Unable to open device");
     448              : 
     449              :     v4l2_capability cap;
     450            0 :     if (ioctl(fd, VIDIOC_QUERYCAP, &cap))
     451            0 :         throw std::runtime_error("Unable to query capabilities");
     452              : 
     453            0 :     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
     454            0 :         throw std::runtime_error("Not a capture device");
     455              : 
     456            0 :     if (cap.capabilities & V4L2_CAP_TOUCH)
     457            0 :         throw std::runtime_error("Touch device, ignoring it");
     458              : 
     459            0 :     name = string(reinterpret_cast<const char*>(cap.card));
     460              : 
     461              :     v4l2_input input;
     462            0 :     ZEROVAR(input);
     463              :     unsigned idx;
     464            0 :     input.index = idx = 0;
     465            0 :     while (!ioctl(fd, VIDIOC_ENUMINPUT, &input)) {
     466            0 :         if (idx != input.index)
     467            0 :             break;
     468              : 
     469            0 :         if (input.type & V4L2_INPUT_TYPE_CAMERA) {
     470            0 :             VideoV4l2Channel channel(idx, (const char*) input.name);
     471            0 :             channel.readFormats(fd);
     472            0 :             if (not channel.getSizeList().empty())
     473            0 :                 channels_.push_back(channel);
     474            0 :         }
     475              : 
     476            0 :         input.index = ++idx;
     477              :     }
     478              : 
     479            0 :     ::close(fd);
     480            0 : }
     481              : 
     482              : string
     483            0 : VideoV4l2Rate::libAvPixelformat(bool passthrough) const
     484              : {
     485            0 :     unsigned best_fmt = 0;
     486            0 :     unsigned best_score = UINT_MAX;
     487              : 
     488            0 :     for (const auto& fmt : pixel_formats) {
     489            0 :         if (passthrough) {
     490              :             // Favor H264 > HEVC > MJPEG if passthrough
     491            0 :             if (fmt == V4L2_PIX_FMT_H264 || fmt == V4L2_PIX_FMT_H264_NO_SC || fmt == V4L2_PIX_FMT_H264_MVC)
     492            0 :                 return "h264";
     493            0 :             if (fmt == V4L2_PIX_FMT_H263)
     494            0 :                 return "h263";
     495            0 :             if (fmt == V4L2_PIX_FMT_VP8)
     496            0 :                 return "vp8";
     497              :         }
     498            0 :         auto score = pixelformat_score(fmt);
     499            0 :         if (score < best_score) {
     500            0 :             best_score = score;
     501            0 :             best_fmt = fmt;
     502              :         }
     503              :     }
     504              : 
     505              :     /* If passthrough was requested but no compressed format found, fallback to best found format */
     506              : 
     507            0 :     switch (best_fmt) {
     508              :     // Set codec name for those pixelformats.
     509              :     // Those  names can be found in libavcodec/codec_desc.c
     510            0 :     case V4L2_PIX_FMT_MJPEG:
     511            0 :         return "mjpeg";
     512            0 :     case V4L2_PIX_FMT_DV:
     513            0 :         return "dvvideo";
     514            0 :     case V4L2_PIX_FMT_MPEG:
     515              :     case V4L2_PIX_FMT_MPEG1:
     516            0 :         return "mpeg1video";
     517            0 :     case V4L2_PIX_FMT_H264:
     518              :     case V4L2_PIX_FMT_H264_NO_SC:
     519              :     case V4L2_PIX_FMT_H264_MVC:
     520            0 :         return "h264";
     521            0 :     case V4L2_PIX_FMT_H263:
     522            0 :         return "h263";
     523            0 :     case V4L2_PIX_FMT_MPEG2:
     524            0 :         return "mpeg2video";
     525            0 :     case V4L2_PIX_FMT_MPEG4:
     526            0 :         return "mpeg4";
     527            0 :     case V4L2_PIX_FMT_VC1_ANNEX_G:
     528              :     case V4L2_PIX_FMT_VC1_ANNEX_L:
     529            0 :         return "vc1";
     530            0 :     case V4L2_PIX_FMT_VP8:
     531            0 :         return "vp8";
     532            0 :     default: // Most pixel formats do not need any codec
     533            0 :         return "";
     534              :     }
     535              : }
     536              : 
     537              : vector<string>
     538           96 : VideoDeviceImpl::getChannelList() const
     539              : {
     540           96 :     if (unique_id == DEVICE_DESKTOP)
     541          288 :         return {"default"};
     542            0 :     vector<string> v;
     543            0 :     v.reserve(channels_.size());
     544            0 :     for (const auto& itr : channels_)
     545            0 :         v.push_back(itr.name);
     546              : 
     547            0 :     return v;
     548            0 : }
     549              : 
     550              : vector<VideoSize>
     551           93 : VideoDeviceImpl::getSizeList(const string& channel) const
     552              : {
     553           93 :     if (unique_id == DEVICE_DESKTOP) {
     554          279 :         return {VideoSize(0, 0)};
     555              :     }
     556            0 :     return getChannel(channel).getSizeList();
     557              : }
     558              : 
     559              : vector<FrameRate>
     560           93 : VideoDeviceImpl::getRateList(const string& channel, VideoSize size) const
     561              : {
     562           93 :     if (unique_id == DEVICE_DESKTOP) {
     563              :         return {FrameRate(1),
     564              :                 FrameRate(5),
     565              :                 FrameRate(10),
     566              :                 FrameRate(15),
     567              :                 FrameRate(20),
     568              :                 FrameRate(25),
     569              :                 FrameRate(30),
     570              :                 FrameRate(60),
     571              :                 FrameRate(120),
     572          279 :                 FrameRate(144)};
     573              :     }
     574            0 :     return getChannel(channel).getSize(size).getRateList();
     575              : }
     576              : 
     577              : const VideoV4l2Channel&
     578            0 : VideoDeviceImpl::getChannel(const string& name) const
     579              : {
     580            0 :     for (const auto& item : channels_)
     581            0 :         if (item.name == name)
     582            0 :             return item;
     583              : 
     584            0 :     assert(not channels_.empty());
     585            0 :     return channels_.front();
     586              : }
     587              : 
     588              : DeviceParams
     589          365 : VideoDeviceImpl::getDeviceParams() const
     590              : {
     591          365 :     DeviceParams params;
     592          365 :     params.name = name;
     593          365 :     params.unique_id = unique_id;
     594          365 :     params.input = path;
     595          365 :     if (unique_id == DEVICE_DESKTOP) {
     596          365 :         const auto* env = std::getenv("WAYLAND_DISPLAY");
     597          365 :         if (!env || strlen(env) == 0) {
     598          365 :             params.format = "x11grab";
     599              :         } else {
     600            0 :             params.format = "lavfi";
     601            0 :             params.input = "pipewiregrab";
     602              :         }
     603          365 :         params.framerate = rate_.frame_rate;
     604          365 :         return params;
     605              :     }
     606            0 :     params.format = "video4linux2";
     607            0 :     params.channel_name = channel_.name;
     608            0 :     params.channel = channel_.idx;
     609            0 :     params.width = size_.width;
     610            0 :     params.height = size_.height;
     611            0 :     params.framerate = rate_.frame_rate;
     612            0 :     params.pixel_format = rate_.libAvPixelformat(passthrough_);
     613            0 :     params.passthrough = passthrough_;
     614              : 
     615              :     // If passthrough was requested but we got a raw format, disable passthrough
     616            0 :     if (passthrough_ && params.pixel_format != "h264" && params.pixel_format != "vp8" && params.pixel_format != "h263"
     617            0 :         && params.pixel_format != "mjpeg" && params.pixel_format != "hevc") {
     618            0 :         params.passthrough = false;
     619              :     }
     620              : 
     621            0 :     return params;
     622            0 : }
     623              : 
     624              : void
     625           61 : VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
     626              : {
     627           61 :     if (unique_id == DEVICE_DESKTOP) {
     628           61 :         rate_.frame_rate = params.framerate;
     629           61 :         return;
     630              :     }
     631              :     // Set preferences or fallback to defaults.
     632            0 :     channel_ = getChannel(params.channel_name);
     633            0 :     size_ = channel_.getSize({params.width, params.height});
     634              :     try {
     635            0 :         rate_ = size_.getRate(params.framerate);
     636            0 :     } catch (...) {
     637            0 :         rate_ = {};
     638            0 :     }
     639            0 :     passthrough_ = params.passthrough;
     640              : }
     641              : 
     642           32 : VideoDevice::VideoDevice(const std::string& id, const std::vector<std::map<std::string, std::string>>& devInfo)
     643           32 :     : id_(id)
     644              : {
     645           32 :     deviceImpl_ = std::make_shared<VideoDeviceImpl>(id, devInfo.empty() ? id : devInfo.at(0).at("devPath"));
     646           32 :     name = deviceImpl_->name;
     647           32 : }
     648              : 
     649              : DeviceParams
     650          365 : VideoDevice::getDeviceParams() const
     651              : {
     652          365 :     auto params = deviceImpl_->getDeviceParams();
     653          365 :     params.orientation = orientation_;
     654          365 :     return params;
     655              : }
     656              : 
     657              : void
     658           61 : VideoDevice::setDeviceParams(const DeviceParams& params)
     659              : {
     660           61 :     return deviceImpl_->setDeviceParams(params);
     661              : }
     662              : 
     663              : std::vector<std::string>
     664           96 : VideoDevice::getChannelList() const
     665              : {
     666           96 :     return deviceImpl_->getChannelList();
     667              : }
     668              : 
     669              : std::vector<VideoSize>
     670           93 : VideoDevice::getSizeList(const std::string& channel) const
     671              : {
     672           93 :     return deviceImpl_->getSizeList(channel);
     673              : }
     674              : 
     675              : std::vector<FrameRate>
     676           93 : VideoDevice::getRateList(const std::string& channel, VideoSize size) const
     677              : {
     678           93 :     return deviceImpl_->getRateList(channel, size);
     679              : }
     680              : 
     681           64 : VideoDevice::~VideoDevice() {}
     682              : 
     683              : } // namespace video
     684              : } // namespace jami
        

Generated by: LCOV version 2.0-1