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