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>
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.
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.
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.
20
* Additional permission under GNU GPL version 3 section 7:
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.
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
50
#include <sys/ioctl.h>
54
#include "../video_device.h"
56
#define ZEROVAR(x) memset(&(x), 0, sizeof(x))
62
VideoV4l2Size(unsigned height, unsigned width);
65
* @throw std::runtime_error
67
void getFrameRates(int fd, unsigned int pixel_format);
68
std::vector<std::string> getRateList() const;
69
float getRate(const std::string &name) const;
75
std::vector<float> rates_;
78
class VideoV4l2Channel {
80
VideoV4l2Channel(unsigned idx, const char *s);
83
* @throw std::runtime_error
85
void getFormat(int fd);
87
* @throw std::runtime_error
89
unsigned int getSizes(int fd, unsigned int pixel_format);
91
void setFourcc(unsigned code);
92
const char * getFourcc() const;
94
std::vector<std::string> getSizeList() const;
95
const VideoV4l2Size& getSize(const std::string &name) const;
102
std::vector<VideoV4l2Size> sizes_;
106
class VideoDeviceImpl {
109
* @throw std::runtime_error
111
VideoDeviceImpl(const std::string& path);
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;
120
VideoSettings getSettings() const;
121
void applySettings(VideoSettings settings);
124
std::vector<VideoV4l2Channel> channels_;
125
const VideoV4l2Channel& getChannel(const std::string& name) const;
128
VideoV4l2Channel channel_;
133
static const unsigned pixelformats_supported[] = {
134
/* pixel format depth description */
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 */
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 */
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 */
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 */
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 */
185
/* Palette formats */
186
V4L2_PIX_FMT_PAL8, /* 8 8-bit palette */
190
/* Returns a score for the given pixelformat
192
* Lowest score is the best, the first entries in the array are the formats
193
* supported as an input for the video encoders.
195
* Other entries in the array are YUV formats
197
* RGB / grey / palette formats are not supported because most cameras support
203
unsigned int pixelformat_score(unsigned pixelformat)
205
for (const auto &item : pixelformats_supported)
206
if (item == pixelformat)
215
using std::stringstream;
217
VideoV4l2Size::VideoV4l2Size(unsigned height, unsigned width) :
218
height(height), width(width), rates_() {}
220
vector<string> VideoV4l2Size::getRateList() const
224
for (const auto &item : rates_) {
227
v.push_back(ss.str());
233
void VideoV4l2Size::getFrameRates(int fd, unsigned int pixel_format)
235
v4l2_frmivalenum frmival;
237
frmival.pixel_format = pixel_format;
238
frmival.width = width;
239
frmival.height = height;
241
if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival)) {
242
rates_.push_back(25);
243
ERROR("could not query frame interval for size");
247
switch(frmival.type) {
248
case V4L2_FRMIVAL_TYPE_DISCRETE:
250
rates_.push_back(frmival.discrete.denominator/frmival.discrete.numerator);
252
} while (!ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival));
254
case V4L2_FRMIVAL_TYPE_CONTINUOUS:
255
rates_.push_back(25);
257
ERROR("Continuous Frame Intervals not supported");
259
case V4L2_FRMIVAL_TYPE_STEPWISE:
260
rates_.push_back(25);
262
ERROR("Stepwise Frame Intervals not supported");
268
VideoV4l2Size::getRate(const string &name) const
270
for (const auto& item : rates_) {
273
if (ss.str() == name)
277
// fallback to last size
278
assert(not rates_.empty());
279
return rates_.back();
282
VideoV4l2Channel::VideoV4l2Channel(unsigned idx, const char *s) :
283
idx(idx), name(s), sizes_(), fourcc_() {}
285
void VideoV4l2Channel::setFourcc(unsigned code)
288
fourcc_[1] = code >> 8;
289
fourcc_[2] = code >> 16;
290
fourcc_[3] = code >> 24;
295
VideoV4l2Channel::getFourcc() const
300
vector<string> VideoV4l2Channel::getSizeList() const
304
for (const auto &item : sizes_) {
306
ss << item.width << "x" << item.height;
307
v.push_back(ss.str());
314
VideoV4l2Channel::getSizes(int fd, unsigned int pixelformat)
316
v4l2_frmsizeenum frmsize;
319
frmsize.pixel_format = pixelformat;
320
if (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) {
322
switch (frmsize.type) {
323
case V4L2_FRMSIZE_TYPE_DISCRETE:
325
VideoV4l2Size size(frmsize.discrete.height, frmsize.discrete.width);
326
size.getFrameRates(fd, frmsize.pixel_format);
327
sizes_.push_back(size);
329
} while (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize));
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");
339
case V4L2_FRMSIZE_TYPE_STEPWISE:
340
ERROR("Stepwise Frame sizes not supported");
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");
351
VideoV4l2Size size(fmt.fmt.pix.height, fmt.fmt.pix.width);
352
size.getFrameRates(fd, fmt.fmt.pix.pixelformat);
353
sizes_.push_back(size);
355
return fmt.fmt.pix.pixelformat;
359
bool isCIF(const VideoV4l2Size &size)
361
const unsigned CIF_WIDTH = 352;
362
const unsigned CIF_HEIGHT = 288;
363
return size.width == CIF_WIDTH and size.height == CIF_HEIGHT;
367
// Put CIF resolution (352x288) first in the list since it is more prevalent in
369
void VideoV4l2Channel::putCIFFirst()
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());
376
void VideoV4l2Channel::getFormat(int fd)
378
if (ioctl(fd, VIDIOC_S_INPUT, &idx))
379
throw std::runtime_error("VIDIOC_S_INPUT failed");
384
fmt.index = fmt_index = 0;
385
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
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)
394
unsigned int score = pixelformat_score(fmt.pixelformat);
395
if (score < best_score) {
396
pixelformat = fmt.pixelformat;
397
best_idx = fmt_index;
401
fmt.index = ++fmt_index;
404
throw std::runtime_error("Could not enumerate formats");
406
fmt.index = best_idx;
407
pixelformat = getSizes(fd, pixelformat);
410
setFourcc(pixelformat);
414
VideoV4l2Channel::getSize(const string &name) const
416
for (const auto &item : sizes_) {
418
ss << item.width << "x" << item.height;
419
if (ss.str() == name)
423
// fallback to last size
424
assert(not sizes_.empty());
425
return sizes_.back();
428
VideoDeviceImpl::VideoDeviceImpl(const string& path) :
429
device(path), name(), channels_(),
430
channel_(-1, ""), size_(-1, -1), rate_(-1)
432
int fd = open(device.c_str(), O_RDWR);
434
throw std::runtime_error("could not open device");
437
if (ioctl(fd, VIDIOC_QUERYCAP, &cap))
438
throw std::runtime_error("could not query capabilities");
440
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
441
throw std::runtime_error("not a capture device");
443
name = string(reinterpret_cast<const char*>(cap.card));
448
input.index = idx = 0;
449
while (!ioctl(fd, VIDIOC_ENUMINPUT, &input)) {
450
if (idx != input.index)
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);
464
// Set default settings
465
applySettings(VideoSettings());
468
vector<string> VideoDeviceImpl::getChannelList() const
472
for (const auto &itr : channels_)
473
v.push_back(itr.name);
479
VideoDeviceImpl::getSizeList(const string& channel) const
481
return getChannel(channel).getSizeList();
485
VideoDeviceImpl::getRateList(const string& channel, const string& size) const
487
return getChannel(channel).getSize(size).getRateList();
490
const VideoV4l2Channel&
491
VideoDeviceImpl::getChannel(const string &name) const
493
for (const auto &item : channels_)
494
if (item.name == name)
497
assert(not channels_.empty());
498
return channels_.back();
502
VideoDeviceImpl::applySettings(VideoSettings settings)
504
// Set preferences or fallback to defaults.
505
channel_ = getChannel(settings["channel"]);
506
size_ = channel_.getSize(settings["size"]);
507
rate_ = size_.getRate(settings["rate"]);
511
static inline string to_string(const T& t)
513
std::stringstream ss;
519
* FIXME the result map has duplicated value, for backward compatibility with
520
* old methods getPreferences() and getSettings().
522
* A VideoSettings struct might be created with eventually a to_map() method.
525
VideoDeviceImpl::getSettings() const
527
VideoSettings settings;
529
settings["name"] = name;
531
// Device path (e.g. /dev/video0)
532
settings["input"] = device;
535
settings["channel_num"] = to_string(channel_.idx);
536
settings["channel"] = channel_.name;
539
settings["width"] = to_string(size_.width);
540
settings["height"] = to_string(size_.height);
541
stringstream video_size;
542
video_size << settings["width"];
544
video_size << settings["height"];
545
settings["video_size"] = video_size.str();
546
settings["size"] = video_size.str();
549
settings["framerate"] = to_string(rate_);
550
settings["rate"] = to_string(rate_);
555
VideoDevice::VideoDevice(const string& path) :
556
deviceImpl_(new VideoDeviceImpl(path))
559
name = deviceImpl_->name;
563
VideoDevice::applySettings(VideoSettings settings)
565
deviceImpl_->applySettings(settings);
569
VideoDevice::getSettings() const
571
return deviceImpl_->getSettings();
575
VideoDevice::getCapabilities() const
577
VideoCapabilities cap;
579
for (const auto& chan : deviceImpl_->getChannelList())
580
for (const auto& size : deviceImpl_->getSizeList(chan))
581
cap[chan][size] = deviceImpl_->getRateList(chan, size);
586
VideoDevice::~VideoDevice()
589
} // namespace sfl_video