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

Generated by: LCOV version 2.0-1