video_capture_v4l2.cc (15993B)
1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 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 11 #include "modules/video_capture/linux/video_capture_v4l2.h" 12 13 #include <fcntl.h> 14 #if defined(__NetBSD__) || defined(__OpenBSD__) // WEBRTC_BSD 15 #include <sys/videoio.h> 16 #elif defined(__sun) 17 #include <sys/videodev2.h> 18 #else 19 #include <linux/videodev2.h> 20 #endif 21 #include <poll.h> 22 #include <sys/ioctl.h> 23 #include <sys/mman.h> 24 #include <sys/select.h> 25 #include <unistd.h> 26 27 #include <cerrno> 28 #include <cstdint> 29 #include <cstdio> 30 #include <cstring> 31 #include <new> 32 33 #include "api/sequence_checker.h" 34 #include "common_video/libyuv/include/webrtc_libyuv.h" 35 #include "media/base/video_common.h" 36 #include "modules/video_capture/video_capture_defines.h" 37 #include "modules/video_capture/video_capture_impl.h" 38 #include "rtc_base/checks.h" 39 #include "rtc_base/logging.h" 40 #include "rtc_base/platform_thread.h" 41 #include "rtc_base/race_checker.h" 42 #include "rtc_base/synchronization/mutex.h" 43 #include "system_wrappers/include/clock.h" 44 45 // These defines are here to support building on kernel 3.16 which some 46 // downstream projects, e.g. Firefox, use. 47 // TODO(apehrson): Remove them and their undefs when no longer needed. 48 #ifndef V4L2_PIX_FMT_ABGR32 49 #define ABGR32_OVERRIDE 1 50 #define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4') 51 #endif 52 53 #ifndef V4L2_PIX_FMT_ARGB32 54 #define ARGB32_OVERRIDE 1 55 #define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4') 56 #endif 57 58 #ifndef V4L2_PIX_FMT_RGBA32 59 #define RGBA32_OVERRIDE 1 60 #define V4L2_PIX_FMT_RGBA32 v4l2_fourcc('A', 'B', '2', '4') 61 #endif 62 63 namespace webrtc { 64 namespace videocapturemodule { 65 VideoCaptureModuleV4L2::VideoCaptureModuleV4L2(Clock* clock) 66 : VideoCaptureImpl(clock), 67 _deviceId(-1), 68 _deviceFd(-1), 69 _buffersAllocatedByDevice(-1), 70 _streaming(false), 71 _captureStarted(false), 72 _pool(nullptr) {} 73 74 int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) { 75 RTC_DCHECK_RUN_ON(&api_checker_); 76 77 int len = strlen((const char*)deviceUniqueIdUTF8); 78 _deviceUniqueId = new (std::nothrow) char[len + 1]; 79 if (_deviceUniqueId) { 80 memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1); 81 } 82 83 int fd; 84 char device[32]; 85 bool found = false; 86 87 /* detect /dev/video [0-63] entries */ 88 int n; 89 for (n = 0; n < 64; n++) { 90 snprintf(device, sizeof(device), "/dev/video%d", n); 91 if ((fd = open(device, O_RDONLY)) != -1) { 92 // query device capabilities 93 struct v4l2_capability cap; 94 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) { 95 if (cap.bus_info[0] != 0) { 96 if (strncmp((const char*)cap.bus_info, 97 (const char*)deviceUniqueIdUTF8, 98 strlen((const char*)deviceUniqueIdUTF8)) == 99 0) { // match with device id 100 close(fd); 101 found = true; 102 break; // fd matches with device unique id supplied 103 } 104 } 105 } 106 close(fd); // close since this is not the matching device 107 } 108 } 109 if (!found) { 110 RTC_LOG(LS_INFO) << "no matching device found"; 111 return -1; 112 } 113 _deviceId = n; // store the device id 114 return 0; 115 } 116 117 VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2() { 118 RTC_DCHECK_RUN_ON(&api_checker_); 119 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 120 121 StopCapture(); 122 if (_deviceFd != -1) 123 close(_deviceFd); 124 } 125 126 int32_t VideoCaptureModuleV4L2::StartCapture( 127 const VideoCaptureCapability& capability) { 128 RTC_DCHECK_RUN_ON(&api_checker_); 129 130 if (_captureStarted) { 131 if (capability == _requestedCapability) { 132 return 0; 133 } else { 134 StopCapture(); 135 } 136 } 137 138 { 139 // We don't want members above to be guarded by capture_checker_ as 140 // it's meant to be for members that are accessed on the API thread 141 // only when we are not capturing. The code above can be called many 142 // times while sharing instance of VideoCaptureV4L2 between websites 143 // and therefore it would not follow the requirements of this checker. 144 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 145 146 // Set a baseline of configured parameters. It is updated here during 147 // configuration, then read from the capture thread. 148 configured_capability_ = capability; 149 150 MutexLock lock(&capture_lock_); 151 // first open /dev/video device 152 char device[20]; 153 snprintf(device, sizeof(device), "/dev/video%d", _deviceId); 154 155 if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0) { 156 RTC_LOG(LS_INFO) << "error in opening " << device << " errono = " << errno; 157 return -1; 158 } 159 160 // Supported video formats in preferred order. 161 // If the requested resolution is larger than VGA, we prefer MJPEG. Go for 162 // I420 otherwise. 163 unsigned int hdFmts[] = { 164 V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, 165 V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV12, 166 V4L2_PIX_FMT_ABGR32, V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_RGBA32, 167 V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, 168 V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_JPEG, 169 }; 170 unsigned int sdFmts[] = { 171 V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUYV, 172 V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_ABGR32, 173 V4L2_PIX_FMT_ARGB32, V4L2_PIX_FMT_RGBA32, V4L2_PIX_FMT_BGR32, 174 V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_BGR24, V4L2_PIX_FMT_RGB24, 175 V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_JPEG, 176 }; 177 const bool isHd = capability.width > 640 || capability.height > 480; 178 unsigned int* fmts = isHd ? hdFmts : sdFmts; 179 static_assert(sizeof(hdFmts) == sizeof(sdFmts)); 180 constexpr int nFormats = sizeof(hdFmts) / sizeof(unsigned int); 181 182 // Enumerate image formats. 183 struct v4l2_fmtdesc fmt; 184 int fmtsIdx = nFormats; 185 memset(&fmt, 0, sizeof(fmt)); 186 fmt.index = 0; 187 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 188 RTC_LOG(LS_INFO) << "Video Capture enumerats supported image formats:"; 189 while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) { 190 RTC_LOG(LS_INFO) << " { pixelformat = " << GetFourccName(fmt.pixelformat) 191 << ", description = '" << fmt.description << "' }"; 192 // Match the preferred order. 193 for (int i = 0; i < nFormats; i++) { 194 if (fmt.pixelformat == fmts[i] && i < fmtsIdx) 195 fmtsIdx = i; 196 } 197 // Keep enumerating. 198 fmt.index++; 199 } 200 201 if (fmtsIdx == nFormats) { 202 RTC_LOG(LS_INFO) << "no supporting video formats found"; 203 return -1; 204 } else { 205 RTC_LOG(LS_INFO) << "We prefer format " << GetFourccName(fmts[fmtsIdx]); 206 } 207 208 struct v4l2_format video_fmt; 209 memset(&video_fmt, 0, sizeof(struct v4l2_format)); 210 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 211 video_fmt.fmt.pix.sizeimage = 0; 212 video_fmt.fmt.pix.width = capability.width; 213 video_fmt.fmt.pix.height = capability.height; 214 video_fmt.fmt.pix.pixelformat = fmts[fmtsIdx]; 215 216 if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) 217 configured_capability_.videoType = VideoType::kYUY2; 218 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) 219 configured_capability_.videoType = VideoType::kI420; 220 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) 221 configured_capability_.videoType = VideoType::kYV12; 222 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) 223 configured_capability_.videoType = VideoType::kUYVY; 224 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) 225 configured_capability_.videoType = VideoType::kNV12; 226 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) 227 configured_capability_.videoType = VideoType::kRGB24; 228 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) 229 configured_capability_.videoType = VideoType::kBGR24; 230 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) 231 configured_capability_.videoType = VideoType::kRGB565; 232 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_ABGR32 || 233 video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) 234 configured_capability_.videoType = VideoType::kARGB; 235 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_ARGB32 || 236 video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) 237 configured_capability_.videoType = VideoType::kBGRA; 238 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_RGBA32) 239 configured_capability_.videoType = VideoType::kABGR; 240 else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG || 241 video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG) 242 configured_capability_.videoType = VideoType::kMJPEG; 243 else 244 RTC_DCHECK_NOTREACHED(); 245 246 // set format and frame size now 247 if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0) { 248 RTC_LOG(LS_INFO) << "error in VIDIOC_S_FMT, errno = " << errno; 249 return -1; 250 } 251 252 // initialize current width and height 253 configured_capability_.width = video_fmt.fmt.pix.width; 254 configured_capability_.height = video_fmt.fmt.pix.height; 255 256 // Trying to set frame rate, before check driver capability. 257 bool driver_framerate_support = true; 258 struct v4l2_streamparm streamparms; 259 memset(&streamparms, 0, sizeof(streamparms)); 260 streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 261 if (ioctl(_deviceFd, VIDIOC_G_PARM, &streamparms) < 0) { 262 RTC_LOG(LS_INFO) << "error in VIDIOC_G_PARM errno = " << errno; 263 driver_framerate_support = false; 264 // continue 265 } else { 266 // check the capability flag is set to V4L2_CAP_TIMEPERFRAME. 267 if (streamparms.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { 268 // driver supports the feature. Set required framerate. 269 memset(&streamparms, 0, sizeof(streamparms)); 270 streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 271 streamparms.parm.capture.timeperframe.numerator = 1; 272 streamparms.parm.capture.timeperframe.denominator = capability.maxFPS; 273 if (ioctl(_deviceFd, VIDIOC_S_PARM, &streamparms) < 0) { 274 RTC_LOG(LS_INFO) << "Failed to set the framerate. errno=" << errno; 275 driver_framerate_support = false; 276 } 277 } 278 } 279 // If driver doesn't support framerate control, need to hardcode. 280 // Hardcoding the value based on the frame size. 281 if (!driver_framerate_support) { 282 if (configured_capability_.width >= 800 && 283 configured_capability_.videoType != VideoType::kMJPEG) { 284 configured_capability_.maxFPS = 15; 285 } else { 286 configured_capability_.maxFPS = 30; 287 } 288 } 289 290 if (!AllocateVideoBuffers()) { 291 RTC_LOG(LS_INFO) << "failed to allocate video capture buffers"; 292 return -1; 293 } 294 295 // Needed to start UVC camera - from the uvcview application 296 enum v4l2_buf_type type; 297 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 298 if (ioctl(_deviceFd, VIDIOC_STREAMON, &type) == -1) { 299 RTC_LOG(LS_INFO) << "Failed to turn on stream"; 300 return -1; 301 } 302 303 _requestedCapability = capability; 304 _captureStarted = true; 305 _streaming = true; 306 307 // start capture thread; 308 if (!_captureThread.empty()) { 309 return 0; 310 } 311 312 quit_ = false; 313 } 314 315 _captureThread = PlatformThread::SpawnJoinable( 316 [self = scoped_refptr(this)] { 317 while (self->CaptureProcess()) { 318 } 319 }, 320 "CaptureThread", ThreadAttributes().SetPriority(ThreadPriority::kHigh)); 321 return 0; 322 } 323 324 int32_t VideoCaptureModuleV4L2::StopCapture() { 325 RTC_DCHECK_RUN_ON(&api_checker_); 326 327 if (!_captureThread.empty()) { 328 { 329 MutexLock lock(&capture_lock_); 330 quit_ = true; 331 } 332 // Make sure the capture thread stops using the mutex. 333 _captureThread.Finalize(); 334 } 335 336 _captureStarted = false; 337 338 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 339 MutexLock lock(&capture_lock_); 340 if (_streaming) { 341 _streaming = false; 342 343 DeAllocateVideoBuffers(); 344 close(_deviceFd); 345 _deviceFd = -1; 346 347 _requestedCapability = configured_capability_ = VideoCaptureCapability(); 348 } 349 350 return 0; 351 } 352 353 // critical section protected by the caller 354 355 bool VideoCaptureModuleV4L2::AllocateVideoBuffers() { 356 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 357 struct v4l2_requestbuffers rbuffer; 358 memset(&rbuffer, 0, sizeof(v4l2_requestbuffers)); 359 360 rbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 361 rbuffer.memory = V4L2_MEMORY_MMAP; 362 rbuffer.count = kNoOfV4L2Bufffers; 363 364 if (ioctl(_deviceFd, VIDIOC_REQBUFS, &rbuffer) < 0) { 365 RTC_LOG(LS_INFO) << "Could not get buffers from device. errno = " << errno; 366 return false; 367 } 368 369 if (rbuffer.count > kNoOfV4L2Bufffers) 370 rbuffer.count = kNoOfV4L2Bufffers; 371 372 _buffersAllocatedByDevice = rbuffer.count; 373 374 // Map the buffers 375 _pool = new Buffer[rbuffer.count]; 376 377 for (unsigned int i = 0; i < rbuffer.count; i++) { 378 struct v4l2_buffer buffer; 379 memset(&buffer, 0, sizeof(v4l2_buffer)); 380 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 381 buffer.memory = V4L2_MEMORY_MMAP; 382 buffer.index = i; 383 384 if (ioctl(_deviceFd, VIDIOC_QUERYBUF, &buffer) < 0) { 385 return false; 386 } 387 388 _pool[i].start = mmap(nullptr, buffer.length, PROT_READ | PROT_WRITE, 389 MAP_SHARED, _deviceFd, buffer.m.offset); 390 391 if (MAP_FAILED == _pool[i].start) { 392 for (unsigned int j = 0; j < i; j++) 393 munmap(_pool[j].start, _pool[j].length); 394 return false; 395 } 396 397 _pool[i].length = buffer.length; 398 399 if (ioctl(_deviceFd, VIDIOC_QBUF, &buffer) < 0) { 400 return false; 401 } 402 } 403 return true; 404 } 405 406 bool VideoCaptureModuleV4L2::DeAllocateVideoBuffers() { 407 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 408 // unmap buffers 409 for (int i = 0; i < _buffersAllocatedByDevice; i++) 410 munmap(_pool[i].start, _pool[i].length); 411 412 delete[] _pool; 413 414 // turn off stream 415 enum v4l2_buf_type type; 416 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 417 if (ioctl(_deviceFd, VIDIOC_STREAMOFF, &type) < 0) { 418 RTC_LOG(LS_INFO) << "VIDIOC_STREAMOFF error. errno: " << errno; 419 } 420 421 return true; 422 } 423 424 bool VideoCaptureModuleV4L2::CaptureStarted() { 425 RTC_DCHECK_RUN_ON(&api_checker_); 426 return _captureStarted; 427 } 428 429 bool VideoCaptureModuleV4L2::CaptureProcess() { 430 RTC_CHECK_RUNS_SERIALIZED(&capture_checker_); 431 432 int retVal = 0; 433 struct pollfd rSet; 434 435 rSet.fd = _deviceFd; 436 rSet.events = POLLIN; 437 rSet.revents = 0; 438 439 retVal = poll(&rSet, 1, 1000); 440 441 { 442 MutexLock lock(&capture_lock_); 443 444 if (quit_) { 445 return false; 446 } 447 448 if (retVal < 0 && errno != EINTR) { // continue if interrupted 449 // poll failed 450 return false; 451 } else if (retVal == 0) { 452 // poll timed out 453 return true; 454 } else if (!(rSet.revents & POLLIN)) { 455 // not event on camera handle 456 return true; 457 } 458 459 if (_streaming) { 460 struct v4l2_buffer buf; 461 memset(&buf, 0, sizeof(struct v4l2_buffer)); 462 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 463 buf.memory = V4L2_MEMORY_MMAP; 464 // dequeue a buffer - repeat until dequeued properly! 465 while (ioctl(_deviceFd, VIDIOC_DQBUF, &buf) < 0) { 466 if (errno != EINTR) { 467 RTC_LOG(LS_INFO) << "could not sync on a buffer on device " 468 << strerror(errno); 469 return true; 470 } 471 } 472 473 // convert to to I420 if needed 474 IncomingFrame(reinterpret_cast<uint8_t*>(_pool[buf.index].start), 475 buf.bytesused, configured_capability_); 476 // enqueue the buffer again 477 if (ioctl(_deviceFd, VIDIOC_QBUF, &buf) == -1) { 478 RTC_LOG(LS_INFO) << "Failed to enqueue capture buffer"; 479 } 480 } 481 } 482 usleep(0); 483 return true; 484 } 485 486 int32_t VideoCaptureModuleV4L2::CaptureSettings( 487 VideoCaptureCapability& settings) { 488 RTC_DCHECK_RUN_ON(&api_checker_); 489 settings = _requestedCapability; 490 491 return 0; 492 } 493 } // namespace videocapturemodule 494 } // namespace webrtc 495 496 #ifdef ABGR32_OVERRIDE 497 #undef ABGR32_OVERRIDE 498 #undef V4L2_PIX_FMT_ABGR32 499 #endif 500 501 #ifdef ARGB32_OVERRIDE 502 #undef ARGB32_OVERRIDE 503 #undef V4L2_PIX_FMT_ARGB32 504 #endif 505 506 #ifdef RGBA32_OVERRIDE 507 #undef RGBA32_OVERRIDE 508 #undef V4L2_PIX_FMT_RGBA32 509 #endif