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
|