blob: 9c8c051515a863bcb73c18468104bbb4fede7ff6 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mallinath@webrtc.org12984f02012-02-16 18:18:21 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000011#include "webrtc/modules/video_capture/linux/device_info_linux.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <errno.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <fcntl.h>
15#include <stdio.h>
16#include <stdlib.h>
pbos@webrtc.orga9b74ad2013-07-12 10:03:52 +000017#include <sys/ioctl.h>
18#include <sys/stat.h>
19#include <unistd.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000020//v4l includes
21#include <linux/videodev2.h>
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000022
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +020023#include "webrtc/rtc_base/logging.h"
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000024
25
niklase@google.com470e71d2011-07-07 08:21:25 +000026namespace webrtc
27{
perkj@webrtc.org0cc68dc2011-09-12 08:53:36 +000028namespace videocapturemodule
29{
niklase@google.com470e71d2011-07-07 08:21:25 +000030VideoCaptureModule::DeviceInfo*
nisseb29b9c82016-12-12 00:22:56 -080031VideoCaptureImpl::CreateDeviceInfo()
niklase@google.com470e71d2011-07-07 08:21:25 +000032{
nisseb29b9c82016-12-12 00:22:56 -080033 return new videocapturemodule::DeviceInfoLinux();
niklase@google.com470e71d2011-07-07 08:21:25 +000034}
35
nisseb29b9c82016-12-12 00:22:56 -080036DeviceInfoLinux::DeviceInfoLinux()
37 : DeviceInfoImpl()
niklase@google.com470e71d2011-07-07 08:21:25 +000038{
39}
40
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000041int32_t DeviceInfoLinux::Init()
niklase@google.com470e71d2011-07-07 08:21:25 +000042{
43 return 0;
44}
45
46DeviceInfoLinux::~DeviceInfoLinux()
47{
48}
49
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000050uint32_t DeviceInfoLinux::NumberOfDevices()
niklase@google.com470e71d2011-07-07 08:21:25 +000051{
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +020052 LOG(LS_INFO) << __FUNCTION__;
niklase@google.com470e71d2011-07-07 08:21:25 +000053
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000054 uint32_t count = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000055 char device[20];
56 int fd = -1;
57
58 /* detect /dev/video [0-63]VideoCaptureModule entries */
59 for (int n = 0; n < 64; n++)
60 {
niklase@google.com470e71d2011-07-07 08:21:25 +000061 sprintf(device, "/dev/video%d", n);
mallinath@webrtc.org12984f02012-02-16 18:18:21 +000062 if ((fd = open(device, O_RDONLY)) != -1)
niklase@google.com470e71d2011-07-07 08:21:25 +000063 {
mallinath@webrtc.org12984f02012-02-16 18:18:21 +000064 close(fd);
65 count++;
niklase@google.com470e71d2011-07-07 08:21:25 +000066 }
67 }
68
69 return count;
70}
71
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000072int32_t DeviceInfoLinux::GetDeviceName(
73 uint32_t deviceNumber,
leozwang@webrtc.org1745e932012-03-01 16:30:40 +000074 char* deviceNameUTF8,
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000075 uint32_t deviceNameLength,
leozwang@webrtc.org1745e932012-03-01 16:30:40 +000076 char* deviceUniqueIdUTF8,
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000077 uint32_t deviceUniqueIdUTF8Length,
leozwang@webrtc.org1745e932012-03-01 16:30:40 +000078 char* /*productUniqueIdUTF8*/,
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000079 uint32_t /*productUniqueIdUTF8Length*/)
niklase@google.com470e71d2011-07-07 08:21:25 +000080{
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +020081 LOG(LS_INFO) << __FUNCTION__;
niklase@google.com470e71d2011-07-07 08:21:25 +000082
wu@webrtc.org221b5222011-09-21 16:57:15 +000083 // Travel through /dev/video [0-63]
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +000084 uint32_t count = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000085 char device[20];
niklase@google.com470e71d2011-07-07 08:21:25 +000086 int fd = -1;
wu@webrtc.org221b5222011-09-21 16:57:15 +000087 bool found = false;
88 for (int n = 0; n < 64; n++)
niklase@google.com470e71d2011-07-07 08:21:25 +000089 {
wu@webrtc.org221b5222011-09-21 16:57:15 +000090 sprintf(device, "/dev/video%d", n);
mallinath@webrtc.org12984f02012-02-16 18:18:21 +000091 if ((fd = open(device, O_RDONLY)) != -1)
niklase@google.com470e71d2011-07-07 08:21:25 +000092 {
mallinath@webrtc.org12984f02012-02-16 18:18:21 +000093 if (count == deviceNumber) {
94 // Found the device
95 found = true;
96 break;
97 } else {
98 close(fd);
99 count++;
wu@webrtc.org221b5222011-09-21 16:57:15 +0000100 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 }
102 }
103
wu@webrtc.org221b5222011-09-21 16:57:15 +0000104 if (!found)
105 return -1;
106
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 // query device capabilities
108 struct v4l2_capability cap;
109 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
110 {
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200111 LOG(LS_INFO) << "error in querying the device capability for device "
112 << device << ". errno = " << errno;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 close(fd);
114 return -1;
115 }
116
117 close(fd);
118
119 char cameraName[64];
120 memset(deviceNameUTF8, 0, deviceNameLength);
121 memcpy(cameraName, cap.card, sizeof(cap.card));
122
123 if (deviceNameLength >= strlen(cameraName))
124 {
125 memcpy(deviceNameUTF8, cameraName, strlen(cameraName));
126 }
127 else
128 {
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200129 LOG(LS_INFO) << "buffer passed is too small";
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 return -1;
131 }
132
133 if (cap.bus_info[0] != 0) // may not available in all drivers
134 {
phoglund@webrtc.org8ff3ff12012-10-01 10:04:26 +0000135 // copy device id
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 if (deviceUniqueIdUTF8Length >= strlen((const char*) cap.bus_info))
137 {
138 memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
139 memcpy(deviceUniqueIdUTF8, cap.bus_info,
140 strlen((const char*) cap.bus_info));
141 }
142 else
143 {
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200144 LOG(LS_INFO) << "buffer passed is too small";
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 return -1;
146 }
147 }
148
149 return 0;
150}
151
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000152int32_t DeviceInfoLinux::CreateCapabilityMap(
leozwang@webrtc.org1745e932012-03-01 16:30:40 +0000153 const char* deviceUniqueIdUTF8)
niklase@google.com470e71d2011-07-07 08:21:25 +0000154{
155 int fd;
156 char device[32];
157 bool found = false;
158
pbos@webrtc.orgdfc5bb92013-04-10 08:23:13 +0000159 const int32_t deviceUniqueIdUTF8Length =
160 (int32_t) strlen((char*) deviceUniqueIdUTF8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength)
162 {
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200163 LOG(LS_INFO) << "Device name too long";
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 return -1;
165 }
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200166 LOG(LS_INFO) << "CreateCapabilityMap called for device "
167 << deviceUniqueIdUTF8;
niklase@google.com470e71d2011-07-07 08:21:25 +0000168
169 /* detect /dev/video [0-63] entries */
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000170 for (int n = 0; n < 64; ++n)
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 sprintf(device, "/dev/video%d", n);
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000173 fd = open(device, O_RDONLY);
174 if (fd == -1)
175 continue;
176
177 // query device capabilities
178 struct v4l2_capability cap;
179 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 {
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000181 if (cap.bus_info[0] != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 {
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000183 if (strncmp((const char*) cap.bus_info,
184 (const char*) deviceUniqueIdUTF8,
185 strlen((const char*) deviceUniqueIdUTF8)) == 0) //match with device id
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 {
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000187 found = true;
188 break; // fd matches with device unique id supplied
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 }
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000190 }
191 else //match for device name
192 {
193 if (IsDeviceNameMatches((const char*) cap.card,
194 (const char*) deviceUniqueIdUTF8))
195 {
196 found = true;
197 break;
198 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 }
200 }
mallinath@webrtc.org12984f02012-02-16 18:18:21 +0000201 close(fd); // close since this is not the matching device
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 }
203
204 if (!found)
205 {
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200206 LOG(LS_INFO) << "no matching device found";
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 return -1;
208 }
209
210 // now fd will point to the matching device
fischman@webrtc.org69fc3152013-09-25 17:01:42 +0000211 // reset old capability list.
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000212 _captureCapabilities.clear();
niklase@google.com470e71d2011-07-07 08:21:25 +0000213
fischman@webrtc.org69fc3152013-09-25 17:01:42 +0000214 int size = FillCapabilities(fd);
niklase@google.com470e71d2011-07-07 08:21:25 +0000215 close(fd);
216
217 // Store the new used device name
218 _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
leozwang@webrtc.org1745e932012-03-01 16:30:40 +0000219 _lastUsedDeviceName = (char*) realloc(_lastUsedDeviceName,
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 _lastUsedDeviceNameLength + 1);
221 memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8, _lastUsedDeviceNameLength + 1);
222
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200223 LOG(LS_INFO) << "CreateCapabilityMap " << _captureCapabilities.size();
niklase@google.com470e71d2011-07-07 08:21:25 +0000224
225 return size;
226}
227
228bool DeviceInfoLinux::IsDeviceNameMatches(const char* name,
leozwang@webrtc.org1745e932012-03-01 16:30:40 +0000229 const char* deviceUniqueIdUTF8)
niklase@google.com470e71d2011-07-07 08:21:25 +0000230{
231 if (strncmp(deviceUniqueIdUTF8, name, strlen(name)) == 0)
232 return true;
233 return false;
234}
235
fischman@webrtc.org69fc3152013-09-25 17:01:42 +0000236int32_t DeviceInfoLinux::FillCapabilities(int fd)
niklase@google.com470e71d2011-07-07 08:21:25 +0000237{
238
239 // set image format
240 struct v4l2_format video_fmt;
241 memset(&video_fmt, 0, sizeof(struct v4l2_format));
242
243 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
244 video_fmt.fmt.pix.sizeimage = 0;
245
will.newtonc675ddd2015-09-24 01:11:25 -0700246 int totalFmts = 4;
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000247 unsigned int videoFormats[] = {
248 V4L2_PIX_FMT_MJPEG,
249 V4L2_PIX_FMT_YUV420,
will.newtonc675ddd2015-09-24 01:11:25 -0700250 V4L2_PIX_FMT_YUYV,
251 V4L2_PIX_FMT_UYVY };
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
253 int sizes = 13;
254 unsigned int size[][2] = { { 128, 96 }, { 160, 120 }, { 176, 144 },
255 { 320, 240 }, { 352, 288 }, { 640, 480 },
256 { 704, 576 }, { 800, 600 }, { 960, 720 },
257 { 1280, 720 }, { 1024, 768 }, { 1440, 1080 },
258 { 1920, 1080 } };
259
260 int index = 0;
261 for (int fmts = 0; fmts < totalFmts; fmts++)
262 {
263 for (int i = 0; i < sizes; i++)
264 {
265 video_fmt.fmt.pix.pixelformat = videoFormats[fmts];
266 video_fmt.fmt.pix.width = size[i][0];
267 video_fmt.fmt.pix.height = size[i][1];
268
269 if (ioctl(fd, VIDIOC_TRY_FMT, &video_fmt) >= 0)
270 {
271 if ((video_fmt.fmt.pix.width == size[i][0])
272 && (video_fmt.fmt.pix.height == size[i][1]))
273 {
fischman@webrtc.org69fc3152013-09-25 17:01:42 +0000274 VideoCaptureCapability cap;
275 cap.width = video_fmt.fmt.pix.width;
276 cap.height = video_fmt.fmt.pix.height;
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 if (videoFormats[fmts] == V4L2_PIX_FMT_YUYV)
278 {
nisseeb44b392017-04-28 07:18:05 -0700279 cap.videoType = VideoType::kYUY2;
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 }
fischman@webrtc.orgd6134c72013-07-29 20:43:15 +0000281 else if (videoFormats[fmts] == V4L2_PIX_FMT_YUV420)
282 {
nisseeb44b392017-04-28 07:18:05 -0700283 cap.videoType = VideoType::kI420;
fischman@webrtc.orgd6134c72013-07-29 20:43:15 +0000284 }
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000285 else if (videoFormats[fmts] == V4L2_PIX_FMT_MJPEG)
286 {
nisseeb44b392017-04-28 07:18:05 -0700287 cap.videoType = VideoType::kMJPEG;
mflodman@webrtc.org4f9e44f2012-02-23 09:00:26 +0000288 }
will.newtonc675ddd2015-09-24 01:11:25 -0700289 else if (videoFormats[fmts] == V4L2_PIX_FMT_UYVY)
290 {
nisseeb44b392017-04-28 07:18:05 -0700291 cap.videoType = VideoType::kUYVY;
will.newtonc675ddd2015-09-24 01:11:25 -0700292 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000293
294 // get fps of current camera mode
295 // V4l2 does not have a stable method of knowing so we just guess.
nisseeb44b392017-04-28 07:18:05 -0700296 if (cap.width >= 800 &&
297 cap.videoType != VideoType::kMJPEG) {
298 cap.maxFPS = 15;
niklase@google.com470e71d2011-07-07 08:21:25 +0000299 }
300 else
301 {
fischman@webrtc.org69fc3152013-09-25 17:01:42 +0000302 cap.maxFPS = 30;
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 }
304
fischman@webrtc.org69fc3152013-09-25 17:01:42 +0000305 _captureCapabilities.push_back(cap);
niklase@google.com470e71d2011-07-07 08:21:25 +0000306 index++;
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200307 LOG(LS_VERBOSE) << "Camera capability, width:" << cap.width
308 << " height:" << cap.height << " type:"
309 << static_cast<int32_t>(cap.videoType)
310 << " fps:" << cap.maxFPS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000311 }
312 }
313 }
314 }
315
Sam Zackrisson2ed6e4f2017-08-16 13:39:25 +0200316 LOG(LS_INFO) << "CreateCapabilityMap " << _captureCapabilities.size();
pbos@webrtc.org4ca7d3f2013-08-12 19:51:57 +0000317 return _captureCapabilities.size();
niklase@google.com470e71d2011-07-07 08:21:25 +0000318}
319
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000320} // namespace videocapturemodule
321} // namespace webrtc