1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "media/video/capture/linux/video_capture_device_linux.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #if defined(OS_OPENBSD) 10 #include <sys/videoio.h> 11 #else 12 #include <linux/videodev2.h> 13 #endif 14 #include <sys/ioctl.h> 15 #include <sys/mman.h> 16 17 #include <list> 18 #include <string> 19 20 #include "base/bind.h" 21 #include "base/file_util.h" 22 #include "base/files/file_enumerator.h" 23 #include "base/strings/stringprintf.h" 24 25 namespace media { 26 27 // Max number of video buffers VideoCaptureDeviceLinux can allocate. 28 enum { kMaxVideoBuffers = 2 }; 29 // Timeout in microseconds v4l2_thread_ blocks waiting for a frame from the hw. 30 enum { kCaptureTimeoutUs = 200000 }; 31 // The number of continuous timeouts tolerated before treated as error. 32 enum { kContinuousTimeoutLimit = 10 }; 33 // Time to wait in milliseconds before v4l2_thread_ reschedules OnCaptureTask 34 // if an event is triggered (select) but no video frame is read. 35 enum { kCaptureSelectWaitMs = 10 }; 36 // MJPEG is prefered if the width or height is larger than this. 37 enum { kMjpegWidth = 640 }; 38 enum { kMjpegHeight = 480 }; 39 // Typical framerate, in fps 40 enum { kTypicalFramerate = 30 }; 41 42 // V4L2 color formats VideoCaptureDeviceLinux support. 43 static const int32 kV4l2RawFmts[] = { 44 V4L2_PIX_FMT_YUV420, 45 V4L2_PIX_FMT_YUYV 46 }; 47 48 // USB VID and PID are both 4 bytes long. 49 static const size_t kVidPidSize = 4; 50 51 // /sys/class/video4linux/video{N}/device is a symlink to the corresponding 52 // USB device info directory. 53 static const char kVidPathTemplate[] = 54 "/sys/class/video4linux/%s/device/../idVendor"; 55 static const char kPidPathTemplate[] = 56 "/sys/class/video4linux/%s/device/../idProduct"; 57 58 // This function translates Video4Linux pixel formats to Chromium pixel formats, 59 // should only support those listed in GetListOfUsableFourCCs. 60 static VideoPixelFormat V4l2ColorToVideoCaptureColorFormat( 61 int32 v4l2_fourcc) { 62 VideoPixelFormat result = PIXEL_FORMAT_UNKNOWN; 63 switch (v4l2_fourcc) { 64 case V4L2_PIX_FMT_YUV420: 65 result = PIXEL_FORMAT_I420; 66 break; 67 case V4L2_PIX_FMT_YUYV: 68 result = PIXEL_FORMAT_YUY2; 69 break; 70 case V4L2_PIX_FMT_MJPEG: 71 case V4L2_PIX_FMT_JPEG: 72 result = PIXEL_FORMAT_MJPEG; 73 break; 74 default: 75 DVLOG(1) << "Unsupported pixel format " << std::hex << v4l2_fourcc; 76 } 77 return result; 78 } 79 80 static void GetListOfUsableFourCCs(bool favour_mjpeg, std::list<int>* fourccs) { 81 for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i) 82 fourccs->push_back(kV4l2RawFmts[i]); 83 if (favour_mjpeg) 84 fourccs->push_front(V4L2_PIX_FMT_MJPEG); 85 else 86 fourccs->push_back(V4L2_PIX_FMT_MJPEG); 87 88 // JPEG works as MJPEG on some gspca webcams from field reports. 89 // Put it as the least preferred format. 90 fourccs->push_back(V4L2_PIX_FMT_JPEG); 91 } 92 93 static bool HasUsableFormats(int fd) { 94 v4l2_fmtdesc fmtdesc; 95 std::list<int> usable_fourccs; 96 97 GetListOfUsableFourCCs(false, &usable_fourccs); 98 99 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); 100 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 101 102 while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { 103 if (std::find(usable_fourccs.begin(), usable_fourccs.end(), 104 fmtdesc.pixelformat) != usable_fourccs.end()) 105 return true; 106 107 fmtdesc.index++; 108 } 109 return false; 110 } 111 112 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { 113 int fd = -1; 114 115 // Empty the name list. 116 device_names->clear(); 117 118 base::FilePath path("/dev/"); 119 base::FileEnumerator enumerator( 120 path, false, base::FileEnumerator::FILES, "video*"); 121 122 while (!enumerator.Next().empty()) { 123 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); 124 125 std::string unique_id = path.value() + info.GetName().value(); 126 if ((fd = open(unique_id.c_str() , O_RDONLY)) < 0) { 127 // Failed to open this device. 128 continue; 129 } 130 // Test if this is a V4L2 capture device. 131 v4l2_capability cap; 132 if ((ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) && 133 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && 134 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)) { 135 // This is a V4L2 video capture device 136 if (HasUsableFormats(fd)) { 137 Name device_name(base::StringPrintf("%s", cap.card), unique_id); 138 device_names->push_back(device_name); 139 } else { 140 DVLOG(1) << "No usable formats reported by " << info.GetName().value(); 141 } 142 } 143 close(fd); 144 } 145 } 146 147 void VideoCaptureDevice::GetDeviceSupportedFormats( 148 const Name& device, 149 VideoCaptureFormats* supported_formats) { 150 if (device.id().empty()) 151 return; 152 int fd; 153 if ((fd = open(device.id().c_str(), O_RDONLY)) < 0) 154 return; 155 156 supported_formats->clear(); 157 // Retrieve the caps one by one, first get pixel format, then sizes, then 158 // frame rates. See http://linuxtv.org/downloads/v4l-dvb-apis for reference. 159 v4l2_fmtdesc pixel_format = {}; 160 pixel_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 161 while (ioctl(fd, VIDIOC_ENUM_FMT, &pixel_format) == 0) { 162 VideoCaptureFormat supported_format; 163 supported_format.pixel_format = 164 V4l2ColorToVideoCaptureColorFormat((int32)pixel_format.pixelformat); 165 if (supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) { 166 ++pixel_format.index; 167 continue; 168 } 169 170 v4l2_frmsizeenum frame_size = {}; 171 frame_size.pixel_format = pixel_format.pixelformat; 172 while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frame_size) == 0) { 173 if (frame_size.type == V4L2_FRMSIZE_TYPE_DISCRETE) { 174 supported_format.frame_size.SetSize( 175 frame_size.discrete.width, frame_size.discrete.height); 176 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_STEPWISE) { 177 // TODO(mcasas): see http://crbug.com/249953, support these devices. 178 NOTIMPLEMENTED(); 179 } else if (frame_size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) { 180 // TODO(mcasas): see http://crbug.com/249953, support these devices. 181 NOTIMPLEMENTED(); 182 } 183 v4l2_frmivalenum frame_interval = {}; 184 frame_interval.pixel_format = pixel_format.pixelformat; 185 frame_interval.width = frame_size.discrete.width; 186 frame_interval.height = frame_size.discrete.height; 187 while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frame_interval) == 0) { 188 if (frame_interval.type == V4L2_FRMIVAL_TYPE_DISCRETE) { 189 if (frame_interval.discrete.numerator != 0) { 190 supported_format.frame_rate = 191 static_cast<float>(frame_interval.discrete.denominator) / 192 static_cast<float>(frame_interval.discrete.numerator); 193 } else { 194 supported_format.frame_rate = 0; 195 } 196 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) { 197 // TODO(mcasas): see http://crbug.com/249953, support these devices. 198 NOTIMPLEMENTED(); 199 break; 200 } else if (frame_interval.type == V4L2_FRMIVAL_TYPE_STEPWISE) { 201 // TODO(mcasas): see http://crbug.com/249953, support these devices. 202 NOTIMPLEMENTED(); 203 break; 204 } 205 supported_formats->push_back(supported_format); 206 ++frame_interval.index; 207 } 208 ++frame_size.index; 209 } 210 ++pixel_format.index; 211 } 212 213 close(fd); 214 return; 215 } 216 217 static bool ReadIdFile(const std::string path, std::string* id) { 218 char id_buf[kVidPidSize]; 219 FILE* file = fopen(path.c_str(), "rb"); 220 if (!file) 221 return false; 222 const bool success = fread(id_buf, kVidPidSize, 1, file) == 1; 223 fclose(file); 224 if (!success) 225 return false; 226 id->append(id_buf, kVidPidSize); 227 return true; 228 } 229 230 const std::string VideoCaptureDevice::Name::GetModel() const { 231 // |unique_id| is of the form "/dev/video2". |file_name| is "video2". 232 const std::string dev_dir = "/dev/"; 233 DCHECK_EQ(0, unique_id_.compare(0, dev_dir.length(), dev_dir)); 234 const std::string file_name = 235 unique_id_.substr(dev_dir.length(), unique_id_.length()); 236 237 const std::string vidPath = 238 base::StringPrintf(kVidPathTemplate, file_name.c_str()); 239 const std::string pidPath = 240 base::StringPrintf(kPidPathTemplate, file_name.c_str()); 241 242 std::string usb_id; 243 if (!ReadIdFile(vidPath, &usb_id)) 244 return ""; 245 usb_id.append(":"); 246 if (!ReadIdFile(pidPath, &usb_id)) 247 return ""; 248 249 return usb_id; 250 } 251 252 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { 253 VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); 254 if (!self) 255 return NULL; 256 // Test opening the device driver. This is to make sure it is available. 257 // We will reopen it again in our worker thread when someone 258 // allocates the camera. 259 int fd = open(device_name.id().c_str(), O_RDONLY); 260 if (fd < 0) { 261 DVLOG(1) << "Cannot open device"; 262 delete self; 263 return NULL; 264 } 265 close(fd); 266 267 return self; 268 } 269 270 VideoCaptureDeviceLinux::VideoCaptureDeviceLinux(const Name& device_name) 271 : state_(kIdle), 272 device_name_(device_name), 273 device_fd_(-1), 274 v4l2_thread_("V4L2Thread"), 275 buffer_pool_(NULL), 276 buffer_pool_size_(0), 277 timeout_count_(0) {} 278 279 VideoCaptureDeviceLinux::~VideoCaptureDeviceLinux() { 280 state_ = kIdle; 281 // Check if the thread is running. 282 // This means that the device have not been DeAllocated properly. 283 DCHECK(!v4l2_thread_.IsRunning()); 284 285 v4l2_thread_.Stop(); 286 if (device_fd_ >= 0) { 287 close(device_fd_); 288 } 289 } 290 291 void VideoCaptureDeviceLinux::AllocateAndStart( 292 const VideoCaptureParams& params, 293 scoped_ptr<VideoCaptureDevice::Client> client) { 294 if (v4l2_thread_.IsRunning()) { 295 return; // Wrong state. 296 } 297 v4l2_thread_.Start(); 298 v4l2_thread_.message_loop()->PostTask( 299 FROM_HERE, 300 base::Bind(&VideoCaptureDeviceLinux::OnAllocateAndStart, 301 base::Unretained(this), 302 params.requested_format.frame_size.width(), 303 params.requested_format.frame_size.height(), 304 params.requested_format.frame_rate, 305 base::Passed(&client))); 306 } 307 308 void VideoCaptureDeviceLinux::StopAndDeAllocate() { 309 if (!v4l2_thread_.IsRunning()) { 310 return; // Wrong state. 311 } 312 v4l2_thread_.message_loop()->PostTask( 313 FROM_HERE, 314 base::Bind(&VideoCaptureDeviceLinux::OnStopAndDeAllocate, 315 base::Unretained(this))); 316 v4l2_thread_.Stop(); 317 // Make sure no buffers are still allocated. 318 // This can happen (theoretically) if an error occurs when trying to stop 319 // the camera. 320 DeAllocateVideoBuffers(); 321 } 322 323 void VideoCaptureDeviceLinux::OnAllocateAndStart(int width, 324 int height, 325 int frame_rate, 326 scoped_ptr<Client> client) { 327 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 328 329 client_ = client.Pass(); 330 331 // Need to open camera with O_RDWR after Linux kernel 3.3. 332 if ((device_fd_ = open(device_name_.id().c_str(), O_RDWR)) < 0) { 333 SetErrorState("Failed to open V4L2 device driver."); 334 return; 335 } 336 337 // Test if this is a V4L2 capture device. 338 v4l2_capability cap; 339 if (!((ioctl(device_fd_, VIDIOC_QUERYCAP, &cap) == 0) && 340 (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && 341 !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))) { 342 // This is not a V4L2 video capture device. 343 close(device_fd_); 344 device_fd_ = -1; 345 SetErrorState("This is not a V4L2 video capture device"); 346 return; 347 } 348 349 // Get supported video formats in preferred order. 350 // For large resolutions, favour mjpeg over raw formats. 351 std::list<int> v4l2_formats; 352 GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight, 353 &v4l2_formats); 354 355 v4l2_fmtdesc fmtdesc; 356 memset(&fmtdesc, 0, sizeof(v4l2_fmtdesc)); 357 fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 358 359 // Enumerate image formats. 360 std::list<int>::iterator best = v4l2_formats.end(); 361 while (ioctl(device_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) { 362 best = std::find(v4l2_formats.begin(), best, fmtdesc.pixelformat); 363 fmtdesc.index++; 364 } 365 366 if (best == v4l2_formats.end()) { 367 SetErrorState("Failed to find a supported camera format."); 368 return; 369 } 370 371 // Set format and frame size now. 372 v4l2_format video_fmt; 373 memset(&video_fmt, 0, sizeof(video_fmt)); 374 video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 375 video_fmt.fmt.pix.sizeimage = 0; 376 video_fmt.fmt.pix.width = width; 377 video_fmt.fmt.pix.height = height; 378 video_fmt.fmt.pix.pixelformat = *best; 379 380 if (ioctl(device_fd_, VIDIOC_S_FMT, &video_fmt) < 0) { 381 SetErrorState("Failed to set camera format"); 382 return; 383 } 384 385 // Set capture framerate in the form of capture interval. 386 v4l2_streamparm streamparm; 387 memset(&streamparm, 0, sizeof(v4l2_streamparm)); 388 streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 389 // The following line checks that the driver knows about framerate get/set. 390 if (ioctl(device_fd_, VIDIOC_G_PARM, &streamparm) >= 0) { 391 // Now check if the device is able to accept a capture framerate set. 392 if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { 393 streamparm.parm.capture.timeperframe.numerator = 1; 394 streamparm.parm.capture.timeperframe.denominator = 395 (frame_rate) ? frame_rate : kTypicalFramerate; 396 397 if (ioctl(device_fd_, VIDIOC_S_PARM, &streamparm) < 0) { 398 SetErrorState("Failed to set camera framerate"); 399 return; 400 } 401 DVLOG(2) << "Actual camera driverframerate: " 402 << streamparm.parm.capture.timeperframe.denominator << "/" 403 << streamparm.parm.capture.timeperframe.numerator; 404 } 405 } 406 // TODO(mcasas): what should be done if the camera driver does not allow 407 // framerate configuration, or the actual one is different from the desired? 408 409 // Store our current width and height. 410 capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width, 411 video_fmt.fmt.pix.height); 412 capture_format_.frame_rate = frame_rate; 413 capture_format_.pixel_format = 414 V4l2ColorToVideoCaptureColorFormat(video_fmt.fmt.pix.pixelformat); 415 416 // Start capturing. 417 if (!AllocateVideoBuffers()) { 418 // Error, We can not recover. 419 SetErrorState("Allocate buffer failed"); 420 return; 421 } 422 423 // Start UVC camera. 424 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 425 if (ioctl(device_fd_, VIDIOC_STREAMON, &type) == -1) { 426 SetErrorState("VIDIOC_STREAMON failed"); 427 return; 428 } 429 430 state_ = kCapturing; 431 // Post task to start fetching frames from v4l2. 432 v4l2_thread_.message_loop()->PostTask( 433 FROM_HERE, 434 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 435 base::Unretained(this))); 436 } 437 438 void VideoCaptureDeviceLinux::OnStopAndDeAllocate() { 439 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 440 441 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 442 if (ioctl(device_fd_, VIDIOC_STREAMOFF, &type) < 0) { 443 SetErrorState("VIDIOC_STREAMOFF failed"); 444 return; 445 } 446 // We don't dare to deallocate the buffers if we can't stop 447 // the capture device. 448 DeAllocateVideoBuffers(); 449 450 // We need to close and open the device if we want to change the settings 451 // Otherwise VIDIOC_S_FMT will return error 452 // Sad but true. 453 close(device_fd_); 454 device_fd_ = -1; 455 state_ = kIdle; 456 client_.reset(); 457 } 458 459 void VideoCaptureDeviceLinux::OnCaptureTask() { 460 DCHECK_EQ(v4l2_thread_.message_loop(), base::MessageLoop::current()); 461 462 if (state_ != kCapturing) { 463 return; 464 } 465 466 fd_set r_set; 467 FD_ZERO(&r_set); 468 FD_SET(device_fd_, &r_set); 469 timeval timeout; 470 471 timeout.tv_sec = 0; 472 timeout.tv_usec = kCaptureTimeoutUs; 473 474 // First argument to select is the highest numbered file descriptor +1. 475 // Refer to http://linux.die.net/man/2/select for more information. 476 int result = select(device_fd_ + 1, &r_set, NULL, NULL, &timeout); 477 // Check if select have failed. 478 if (result < 0) { 479 // EINTR is a signal. This is not really an error. 480 if (errno != EINTR) { 481 SetErrorState("Select failed"); 482 return; 483 } 484 v4l2_thread_.message_loop()->PostDelayedTask( 485 FROM_HERE, 486 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 487 base::Unretained(this)), 488 base::TimeDelta::FromMilliseconds(kCaptureSelectWaitMs)); 489 } 490 491 // Check if select timeout. 492 if (result == 0) { 493 timeout_count_++; 494 if (timeout_count_ >= kContinuousTimeoutLimit) { 495 SetErrorState(base::StringPrintf( 496 "Continuous timeout %d times", timeout_count_)); 497 timeout_count_ = 0; 498 return; 499 } 500 } else { 501 timeout_count_ = 0; 502 } 503 504 // Check if the driver have filled a buffer. 505 if (FD_ISSET(device_fd_, &r_set)) { 506 v4l2_buffer buffer; 507 memset(&buffer, 0, sizeof(buffer)); 508 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 509 buffer.memory = V4L2_MEMORY_MMAP; 510 // Dequeue a buffer. 511 if (ioctl(device_fd_, VIDIOC_DQBUF, &buffer) == 0) { 512 client_->OnIncomingCapturedFrame( 513 static_cast<uint8*>(buffer_pool_[buffer.index].start), 514 buffer.bytesused, 515 base::Time::Now(), 516 0, 517 capture_format_); 518 519 // Enqueue the buffer again. 520 if (ioctl(device_fd_, VIDIOC_QBUF, &buffer) == -1) { 521 SetErrorState(base::StringPrintf( 522 "Failed to enqueue capture buffer errno %d", errno)); 523 } 524 } else { 525 SetErrorState(base::StringPrintf( 526 "Failed to dequeue capture buffer errno %d", errno)); 527 return; 528 } 529 } 530 531 v4l2_thread_.message_loop()->PostTask( 532 FROM_HERE, 533 base::Bind(&VideoCaptureDeviceLinux::OnCaptureTask, 534 base::Unretained(this))); 535 } 536 537 bool VideoCaptureDeviceLinux::AllocateVideoBuffers() { 538 v4l2_requestbuffers r_buffer; 539 memset(&r_buffer, 0, sizeof(r_buffer)); 540 541 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 542 r_buffer.memory = V4L2_MEMORY_MMAP; 543 r_buffer.count = kMaxVideoBuffers; 544 545 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { 546 return false; 547 } 548 549 if (r_buffer.count > kMaxVideoBuffers) { 550 r_buffer.count = kMaxVideoBuffers; 551 } 552 553 buffer_pool_size_ = r_buffer.count; 554 555 // Map the buffers. 556 buffer_pool_ = new Buffer[r_buffer.count]; 557 for (unsigned int i = 0; i < r_buffer.count; i++) { 558 v4l2_buffer buffer; 559 memset(&buffer, 0, sizeof(buffer)); 560 buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 561 buffer.memory = V4L2_MEMORY_MMAP; 562 buffer.index = i; 563 564 if (ioctl(device_fd_, VIDIOC_QUERYBUF, &buffer) < 0) { 565 return false; 566 } 567 568 // Some devices require mmap() to be called with both READ and WRITE. 569 // See crbug.com/178582. 570 buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE, 571 MAP_SHARED, device_fd_, buffer.m.offset); 572 if (buffer_pool_[i].start == MAP_FAILED) { 573 return false; 574 } 575 buffer_pool_[i].length = buffer.length; 576 // Enqueue the buffer in the drivers incoming queue. 577 if (ioctl(device_fd_, VIDIOC_QBUF, &buffer) < 0) { 578 return false; 579 } 580 } 581 return true; 582 } 583 584 void VideoCaptureDeviceLinux::DeAllocateVideoBuffers() { 585 if (!buffer_pool_) 586 return; 587 588 // Unmaps buffers. 589 for (int i = 0; i < buffer_pool_size_; i++) { 590 munmap(buffer_pool_[i].start, buffer_pool_[i].length); 591 } 592 v4l2_requestbuffers r_buffer; 593 memset(&r_buffer, 0, sizeof(r_buffer)); 594 r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 595 r_buffer.memory = V4L2_MEMORY_MMAP; 596 r_buffer.count = 0; 597 598 if (ioctl(device_fd_, VIDIOC_REQBUFS, &r_buffer) < 0) { 599 SetErrorState("Failed to reset buf."); 600 } 601 602 delete [] buffer_pool_; 603 buffer_pool_ = NULL; 604 buffer_pool_size_ = 0; 605 } 606 607 void VideoCaptureDeviceLinux::SetErrorState(const std::string& reason) { 608 DCHECK(!v4l2_thread_.IsRunning() || 609 v4l2_thread_.message_loop() == base::MessageLoop::current()); 610 DVLOG(1) << reason; 611 state_ = kError; 612 client_->OnError(); 613 } 614 615 } // namespace media 616