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