~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/src/video/v4l2/video_device_impl.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2011-2014 Savoir-Faire Linux Inc.
 
3
 *  Author: Rafaël Carré <rafael.carre@savoirfairelinux.com>
 
4
 *  Author: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 3 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 
19
 *
 
20
 *  Additional permission under GNU GPL version 3 section 7:
 
21
 *
 
22
 *  If you modify this program, or any covered work, by linking or
 
23
 *  combining it with the OpenSSL project's OpenSSL library (or a
 
24
 *  modified version of that library), containing parts covered by the
 
25
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 
26
 *  grants you additional permission to convey the resulting work.
 
27
 *  Corresponding Source for a non-source form of such a combination
 
28
 *  shall include the source code for the parts of OpenSSL used as well
 
29
 *  as that of the covered work.
 
30
 */
 
31
 
 
32
#include <algorithm>
 
33
#include <cassert>
 
34
#include <climits>
 
35
#include <cstring>
 
36
#include <map>
 
37
#include <sstream>
 
38
#include <stdexcept>
 
39
#include <string>
 
40
#include <vector>
 
41
 
 
42
extern "C" {
 
43
#include <linux/videodev2.h>
 
44
#if !defined(VIDIOC_ENUM_FRAMESIZES) || !defined(VIDIOC_ENUM_FRAMEINTERVALS)
 
45
#   error You need at least Linux 2.6.19
 
46
#endif
 
47
 
 
48
#include <fcntl.h>
 
49
#include <unistd.h>
 
50
#include <sys/ioctl.h>
 
51
}
 
52
 
 
53
#include "logger.h"
 
54
#include "../video_device.h"
 
55
 
 
56
#define ZEROVAR(x) memset(&(x), 0, sizeof(x))
 
57
 
 
58
namespace sfl_video {
 
59
 
 
60
class VideoV4l2Size {
 
61
    public:
 
62
        VideoV4l2Size(unsigned height, unsigned width);
 
63
 
 
64
        /**
 
65
         * @throw std::runtime_error
 
66
         */
 
67
        void getFrameRates(int fd, unsigned int pixel_format);
 
68
        std::vector<std::string> getRateList() const;
 
69
        float getRate(const std::string &name) const;
 
70
 
 
71
        unsigned height;
 
72
        unsigned width;
 
73
 
 
74
    private:
 
75
        std::vector<float> rates_;
 
76
};
 
77
 
 
78
class VideoV4l2Channel {
 
79
    public:
 
80
        VideoV4l2Channel(unsigned idx, const char *s);
 
81
 
 
82
        /**
 
83
         * @throw std::runtime_error
 
84
         */
 
85
        void getFormat(int fd);
 
86
        /**
 
87
         * @throw std::runtime_error
 
88
         */
 
89
        unsigned int getSizes(int fd, unsigned int pixel_format);
 
90
 
 
91
        void setFourcc(unsigned code);
 
92
        const char * getFourcc() const;
 
93
 
 
94
        std::vector<std::string> getSizeList() const;
 
95
        const VideoV4l2Size& getSize(const std::string &name) const;
 
96
 
 
97
        unsigned idx;
 
98
        std::string name;
 
99
 
 
100
    private:
 
101
        void putCIFFirst();
 
102
        std::vector<VideoV4l2Size> sizes_;
 
103
        char fourcc_[5];
 
104
};
 
105
 
 
106
class VideoDeviceImpl {
 
107
    public:
 
108
        /**
 
109
         * @throw std::runtime_error
 
110
         */
 
111
        VideoDeviceImpl(const std::string& path);
 
112
 
 
113
        std::string device;
 
114
        std::string name;
 
115
 
 
116
        std::vector<std::string> getChannelList() const;
 
117
        std::vector<std::string> getSizeList(const std::string& channel) const;
 
118
        std::vector<std::string> getRateList(const std::string& channel, const std::string& size) const;
 
119
 
 
120
        VideoSettings getSettings() const;
 
121
        void applySettings(VideoSettings settings);
 
122
 
 
123
    private:
 
124
        std::vector<VideoV4l2Channel> channels_;
 
125
        const VideoV4l2Channel& getChannel(const std::string& name) const;
 
126
 
 
127
        /* Preferences */
 
128
        VideoV4l2Channel channel_;
 
129
        VideoV4l2Size size_;
 
130
        float rate_;
 
131
};
 
132
 
 
133
static const unsigned pixelformats_supported[] = {
 
134
    /* pixel format        depth  description   */
 
135
 
 
136
    /* preferred formats, they can be fed directly to the video encoder */
 
137
    V4L2_PIX_FMT_YUV420,   /* 12  YUV 4:2:0     */
 
138
    V4L2_PIX_FMT_YUV422P,  /* 16  YVU422 planar */
 
139
    V4L2_PIX_FMT_YUV444,   /* 16  xxxxyyyy uuuuvvvv */
 
140
 
 
141
    /* Luminance+Chrominance formats */
 
142
    V4L2_PIX_FMT_YVU410,   /*  9  YVU 4:1:0     */
 
143
    V4L2_PIX_FMT_YVU420,   /* 12  YVU 4:2:0     */
 
144
    V4L2_PIX_FMT_YUYV,     /* 16  YUV 4:2:2     */
 
145
    V4L2_PIX_FMT_YYUV,     /* 16  YUV 4:2:2     */
 
146
    V4L2_PIX_FMT_YVYU,     /* 16 YVU 4:2:2 */
 
147
    V4L2_PIX_FMT_UYVY,     /* 16  YUV 4:2:2     */
 
148
    V4L2_PIX_FMT_VYUY,     /* 16  YUV 4:2:2     */
 
149
    V4L2_PIX_FMT_YUV411P,  /* 16  YVU411 planar */
 
150
    V4L2_PIX_FMT_Y41P,     /* 12  YUV 4:1:1     */
 
151
    V4L2_PIX_FMT_YUV555,   /* 16  YUV-5-5-5     */
 
152
    V4L2_PIX_FMT_YUV565,   /* 16  YUV-5-6-5     */
 
153
    V4L2_PIX_FMT_YUV32,    /* 32  YUV-8-8-8-8   */
 
154
    V4L2_PIX_FMT_YUV410,   /*  9  YUV 4:1:0     */
 
155
    V4L2_PIX_FMT_HI240,    /*  8  8-bit color   */
 
156
    V4L2_PIX_FMT_HM12,     /*  8  YUV 4:2:0 16x16 macroblocks */
 
157
 
 
158
    /* two planes -- one Y, one Cr + Cb interleaved  */
 
159
    V4L2_PIX_FMT_NV12,     /* 12  Y/CbCr 4:2:0  */
 
160
    V4L2_PIX_FMT_NV21,     /* 12  Y/CrCb 4:2:0  */
 
161
    V4L2_PIX_FMT_NV16,     /* 16  Y/CbCr 4:2:2  */
 
162
    V4L2_PIX_FMT_NV61,     /* 16  Y/CrCb 4:2:2  */
 
163
 
 
164
#if 0
 
165
    /* RGB formats */
 
166
    V4L2_PIX_FMT_RGB332,   /*  8  RGB-3-3-2     */
 
167
    V4L2_PIX_FMT_RGB444,   /* 16  xxxxrrrr ggggbbbb */
 
168
    V4L2_PIX_FMT_RGB555,   /* 16  RGB-5-5-5     */
 
169
    V4L2_PIX_FMT_RGB565,   /* 16  RGB-5-6-5     */
 
170
    V4L2_PIX_FMT_RGB555X,  /* 16  RGB-5-5-5 BE  */
 
171
    V4L2_PIX_FMT_RGB565X,  /* 16  RGB-5-6-5 BE  */
 
172
    V4L2_PIX_FMT_BGR666,   /* 18  BGR-6-6-6     */
 
173
    V4L2_PIX_FMT_BGR24,    /* 24  BGR-8-8-8     */
 
174
    V4L2_PIX_FMT_RGB24,    /* 24  RGB-8-8-8     */
 
175
    V4L2_PIX_FMT_BGR32,    /* 32  BGR-8-8-8-8   */
 
176
    V4L2_PIX_FMT_RGB32,    /* 32  RGB-8-8-8-8   */
 
177
 
 
178
    /* Grey formats */
 
179
    V4L2_PIX_FMT_GREY,     /*  8  Greyscale     */
 
180
    V4L2_PIX_FMT_Y4,       /*  4  Greyscale     */
 
181
    V4L2_PIX_FMT_Y6,       /*  6  Greyscale     */
 
182
    V4L2_PIX_FMT_Y10,      /* 10  Greyscale     */
 
183
    V4L2_PIX_FMT_Y16,      /* 16  Greyscale     */
 
184
 
 
185
    /* Palette formats */
 
186
    V4L2_PIX_FMT_PAL8,     /*  8  8-bit palette */
 
187
#endif
 
188
};
 
189
 
 
190
/* Returns a score for the given pixelformat
 
191
 *
 
192
 * Lowest score is the best, the first entries in the array are the formats
 
193
 * supported as an input for the video encoders.
 
194
 *
 
195
 * Other entries in the array are YUV formats
 
196
 *
 
197
 * RGB / grey / palette formats are not supported because most cameras support
 
198
 * YUV input
 
199
 *
 
200
 */
 
201
 
 
202
namespace {
 
203
unsigned int pixelformat_score(unsigned pixelformat)
 
204
{
 
205
    for (const auto &item : pixelformats_supported)
 
206
        if (item == pixelformat)
 
207
            return item;
 
208
 
 
209
    return UINT_MAX - 1;
 
210
}
 
211
}
 
212
 
 
213
using std::vector;
 
214
using std::string;
 
215
using std::stringstream;
 
216
 
 
217
VideoV4l2Size::VideoV4l2Size(unsigned height, unsigned width) :
 
218
    height(height), width(width), rates_() {}
 
219
 
 
220
vector<string> VideoV4l2Size::getRateList() const
 
221
{
 
222
    vector<string> v;
 
223
 
 
224
    for (const auto &item : rates_) {
 
225
        stringstream ss;
 
226
        ss << item;
 
227
        v.push_back(ss.str());
 
228
    }
 
229
 
 
230
    return v;
 
231
}
 
232
 
 
233
void VideoV4l2Size::getFrameRates(int fd, unsigned int pixel_format)
 
234
{
 
235
    v4l2_frmivalenum frmival;
 
236
    ZEROVAR(frmival);
 
237
    frmival.pixel_format = pixel_format;
 
238
    frmival.width = width;
 
239
    frmival.height = height;
 
240
 
 
241
    if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival)) {
 
242
        rates_.push_back(25);
 
243
        ERROR("could not query frame interval for size");
 
244
        return;
 
245
    }
 
246
 
 
247
    switch(frmival.type) {
 
248
        case V4L2_FRMIVAL_TYPE_DISCRETE:
 
249
            do {
 
250
                rates_.push_back(frmival.discrete.denominator/frmival.discrete.numerator);
 
251
                ++frmival.index;
 
252
            } while (!ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival));
 
253
            break;
 
254
        case V4L2_FRMIVAL_TYPE_CONTINUOUS:
 
255
            rates_.push_back(25);
 
256
            // TODO
 
257
            ERROR("Continuous Frame Intervals not supported");
 
258
            break;
 
259
        case V4L2_FRMIVAL_TYPE_STEPWISE:
 
260
            rates_.push_back(25);
 
261
            // TODO
 
262
            ERROR("Stepwise Frame Intervals not supported");
 
263
            break;
 
264
    }
 
265
}
 
266
 
 
267
float
 
268
VideoV4l2Size::getRate(const string &name) const
 
269
{
 
270
    for (const auto& item : rates_) {
 
271
        stringstream ss;
 
272
        ss << item;
 
273
        if (ss.str() == name)
 
274
            return item;
 
275
    }
 
276
 
 
277
    // fallback to last size
 
278
    assert(not rates_.empty());
 
279
    return rates_.back();
 
280
}
 
281
 
 
282
VideoV4l2Channel::VideoV4l2Channel(unsigned idx, const char *s) :
 
283
    idx(idx), name(s), sizes_(), fourcc_() {}
 
284
 
 
285
void VideoV4l2Channel::setFourcc(unsigned code)
 
286
{
 
287
    fourcc_[0] = code;
 
288
    fourcc_[1] = code >> 8;
 
289
    fourcc_[2] = code >> 16;
 
290
    fourcc_[3] = code >> 24;
 
291
    fourcc_[4] = '\0';
 
292
}
 
293
 
 
294
const char *
 
295
VideoV4l2Channel::getFourcc() const
 
296
{
 
297
    return fourcc_;
 
298
}
 
299
 
 
300
vector<string> VideoV4l2Channel::getSizeList() const
 
301
{
 
302
    vector<string> v;
 
303
 
 
304
    for (const auto &item : sizes_) {
 
305
        stringstream ss;
 
306
        ss << item.width << "x" << item.height;
 
307
        v.push_back(ss.str());
 
308
    }
 
309
 
 
310
    return v;
 
311
}
 
312
 
 
313
unsigned int
 
314
VideoV4l2Channel::getSizes(int fd, unsigned int pixelformat)
 
315
{
 
316
    v4l2_frmsizeenum frmsize;
 
317
    ZEROVAR(frmsize);
 
318
    frmsize.index = 0;
 
319
    frmsize.pixel_format = pixelformat;
 
320
    if (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) {
 
321
 
 
322
        switch (frmsize.type) {
 
323
            case V4L2_FRMSIZE_TYPE_DISCRETE:
 
324
                do {
 
325
                    VideoV4l2Size size(frmsize.discrete.height, frmsize.discrete.width);
 
326
                    size.getFrameRates(fd, frmsize.pixel_format);
 
327
                    sizes_.push_back(size);
 
328
                    ++frmsize.index;
 
329
                } while (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize));
 
330
                return pixelformat;
 
331
 
 
332
                // TODO, we dont want to display a list of 2000x2000
 
333
                // resolutions if the camera supports continuous framesizes
 
334
                // from 1x1 to 2000x2000
 
335
                // We should limit to a list of known standard sizes
 
336
            case V4L2_FRMSIZE_TYPE_CONTINUOUS:
 
337
                ERROR("Continuous Frame sizes not supported");
 
338
                break;
 
339
            case V4L2_FRMSIZE_TYPE_STEPWISE:
 
340
                ERROR("Stepwise Frame sizes not supported");
 
341
                break;
 
342
        }
 
343
    }
 
344
 
 
345
    v4l2_format fmt;
 
346
    ZEROVAR(fmt);
 
347
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
348
    if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
 
349
        throw std::runtime_error("Could not get format");
 
350
 
 
351
    VideoV4l2Size size(fmt.fmt.pix.height, fmt.fmt.pix.width);
 
352
    size.getFrameRates(fd, fmt.fmt.pix.pixelformat);
 
353
    sizes_.push_back(size);
 
354
 
 
355
    return fmt.fmt.pix.pixelformat;
 
356
}
 
357
 
 
358
namespace {
 
359
    bool isCIF(const VideoV4l2Size &size)
 
360
    {
 
361
        const unsigned CIF_WIDTH = 352;
 
362
        const unsigned CIF_HEIGHT = 288;
 
363
        return size.width == CIF_WIDTH and size.height == CIF_HEIGHT;
 
364
    }
 
365
}
 
366
 
 
367
// Put CIF resolution (352x288) first in the list since it is more prevalent in
 
368
// VoIP
 
369
void VideoV4l2Channel::putCIFFirst()
 
370
{
 
371
    vector<VideoV4l2Size>::iterator iter = std::find_if(sizes_.begin(), sizes_.end(), isCIF);
 
372
    if (iter != sizes_.end() and iter != sizes_.begin())
 
373
        std::swap(*iter, *sizes_.begin());
 
374
}
 
375
 
 
376
void VideoV4l2Channel::getFormat(int fd)
 
377
{
 
378
    if (ioctl(fd, VIDIOC_S_INPUT, &idx))
 
379
        throw std::runtime_error("VIDIOC_S_INPUT failed");
 
380
 
 
381
    v4l2_fmtdesc fmt;
 
382
    ZEROVAR(fmt);
 
383
    unsigned fmt_index;
 
384
    fmt.index = fmt_index = 0;
 
385
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 
386
 
 
387
    unsigned int best_score = UINT_MAX;
 
388
    unsigned int best_idx = 0;
 
389
    unsigned int pixelformat = 0;
 
390
    while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmt)) {
 
391
        if (fmt_index != fmt.index)
 
392
            break;
 
393
 
 
394
        unsigned int score = pixelformat_score(fmt.pixelformat);
 
395
        if (score < best_score) {
 
396
            pixelformat = fmt.pixelformat;
 
397
            best_idx = fmt_index;
 
398
            best_score = score;
 
399
        }
 
400
 
 
401
        fmt.index = ++fmt_index;
 
402
    }
 
403
    if (fmt_index == 0)
 
404
        throw std::runtime_error("Could not enumerate formats");
 
405
 
 
406
    fmt.index = best_idx;
 
407
    pixelformat = getSizes(fd, pixelformat);
 
408
    putCIFFirst();
 
409
 
 
410
    setFourcc(pixelformat);
 
411
}
 
412
 
 
413
const VideoV4l2Size&
 
414
VideoV4l2Channel::getSize(const string &name) const
 
415
{
 
416
    for (const auto &item : sizes_) {
 
417
        stringstream ss;
 
418
        ss << item.width << "x" << item.height;
 
419
        if (ss.str() == name)
 
420
            return item;
 
421
    }
 
422
 
 
423
    // fallback to last size
 
424
    assert(not sizes_.empty());
 
425
    return sizes_.back();
 
426
}
 
427
 
 
428
VideoDeviceImpl::VideoDeviceImpl(const string& path) :
 
429
    device(path), name(), channels_(),
 
430
    channel_(-1, ""), size_(-1, -1), rate_(-1)
 
431
{
 
432
    int fd = open(device.c_str(), O_RDWR);
 
433
    if (fd == -1)
 
434
        throw std::runtime_error("could not open device");
 
435
 
 
436
    v4l2_capability cap;
 
437
    if (ioctl(fd, VIDIOC_QUERYCAP, &cap))
 
438
        throw std::runtime_error("could not query capabilities");
 
439
 
 
440
    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
 
441
        throw std::runtime_error("not a capture device");
 
442
 
 
443
    name = string(reinterpret_cast<const char*>(cap.card));
 
444
 
 
445
    v4l2_input input;
 
446
    ZEROVAR(input);
 
447
    unsigned idx;
 
448
    input.index = idx = 0;
 
449
    while (!ioctl(fd, VIDIOC_ENUMINPUT, &input)) {
 
450
        if (idx != input.index)
 
451
            break;
 
452
 
 
453
        if (input.type & V4L2_INPUT_TYPE_CAMERA) {
 
454
            VideoV4l2Channel channel(idx, (const char*) input.name);
 
455
            channel.getFormat(fd);
 
456
            channels_.push_back(channel);
 
457
        }
 
458
 
 
459
        input.index = ++idx;
 
460
    }
 
461
 
 
462
    ::close(fd);
 
463
 
 
464
    // Set default settings
 
465
    applySettings(VideoSettings());
 
466
}
 
467
 
 
468
vector<string> VideoDeviceImpl::getChannelList() const
 
469
{
 
470
    vector<string> v;
 
471
 
 
472
    for (const auto &itr : channels_)
 
473
        v.push_back(itr.name);
 
474
 
 
475
    return v;
 
476
}
 
477
 
 
478
vector<string>
 
479
VideoDeviceImpl::getSizeList(const string& channel) const
 
480
{
 
481
    return getChannel(channel).getSizeList();
 
482
}
 
483
 
 
484
vector<string>
 
485
VideoDeviceImpl::getRateList(const string& channel, const string& size) const
 
486
{
 
487
    return getChannel(channel).getSize(size).getRateList();
 
488
}
 
489
 
 
490
const VideoV4l2Channel&
 
491
VideoDeviceImpl::getChannel(const string &name) const
 
492
{
 
493
    for (const auto &item : channels_)
 
494
        if (item.name == name)
 
495
            return item;
 
496
 
 
497
    assert(not channels_.empty());
 
498
    return channels_.back();
 
499
}
 
500
 
 
501
void
 
502
VideoDeviceImpl::applySettings(VideoSettings settings)
 
503
{
 
504
    // Set preferences or fallback to defaults.
 
505
    channel_ = getChannel(settings["channel"]);
 
506
    size_ = channel_.getSize(settings["size"]);
 
507
    rate_ = size_.getRate(settings["rate"]);
 
508
}
 
509
 
 
510
template <class T>
 
511
static inline string to_string(const T& t)
 
512
{
 
513
    std::stringstream ss;
 
514
    ss << t;
 
515
    return ss.str();
 
516
}
 
517
 
 
518
/*
 
519
 * FIXME the result map has duplicated value, for backward compatibility with
 
520
 * old methods getPreferences() and getSettings().
 
521
 *
 
522
 * A VideoSettings struct might be created with eventually a to_map() method.
 
523
 */
 
524
VideoSettings
 
525
VideoDeviceImpl::getSettings() const
 
526
{
 
527
    VideoSettings settings;
 
528
 
 
529
    settings["name"] = name;
 
530
 
 
531
    // Device path (e.g. /dev/video0)
 
532
    settings["input"] = device;
 
533
 
 
534
    // Channel number
 
535
    settings["channel_num"] = to_string(channel_.idx);
 
536
    settings["channel"] = channel_.name;
 
537
 
 
538
    // Video size
 
539
    settings["width"] = to_string(size_.width);
 
540
    settings["height"] = to_string(size_.height);
 
541
    stringstream video_size;
 
542
    video_size << settings["width"];
 
543
    video_size << "x";
 
544
    video_size << settings["height"];
 
545
    settings["video_size"] = video_size.str();
 
546
    settings["size"] = video_size.str();
 
547
 
 
548
    // Frame rate
 
549
    settings["framerate"] = to_string(rate_);
 
550
    settings["rate"] = to_string(rate_);
 
551
 
 
552
    return settings;
 
553
}
 
554
 
 
555
VideoDevice::VideoDevice(const string& path) :
 
556
    deviceImpl_(new VideoDeviceImpl(path))
 
557
{
 
558
    node_ = path;
 
559
    name = deviceImpl_->name;
 
560
}
 
561
 
 
562
void
 
563
VideoDevice::applySettings(VideoSettings settings)
 
564
{
 
565
    deviceImpl_->applySettings(settings);
 
566
}
 
567
 
 
568
VideoSettings
 
569
VideoDevice::getSettings() const
 
570
{
 
571
    return deviceImpl_->getSettings();
 
572
}
 
573
 
 
574
VideoCapabilities
 
575
VideoDevice::getCapabilities() const
 
576
{
 
577
    VideoCapabilities cap;
 
578
 
 
579
    for (const auto& chan : deviceImpl_->getChannelList())
 
580
        for (const auto& size : deviceImpl_->getSizeList(chan))
 
581
            cap[chan][size] = deviceImpl_->getRateList(chan, size);
 
582
 
 
583
    return cap;
 
584
}
 
585
 
 
586
VideoDevice::~VideoDevice()
 
587
{}
 
588
 
 
589
} // namespace sfl_video