| OLD | NEW |
| (Empty) |
| 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/capture/video/mac/video_capture_device_mac.h" | |
| 6 | |
| 7 #include <IOKit/IOCFPlugIn.h> | |
| 8 #include <IOKit/usb/IOUSBLib.h> | |
| 9 #include <IOKit/usb/USBSpec.h> | |
| 10 #include <stddef.h> | |
| 11 #include <stdint.h> | |
| 12 | |
| 13 #include <limits> | |
| 14 #include <utility> | |
| 15 | |
| 16 #include "base/bind.h" | |
| 17 #include "base/location.h" | |
| 18 #include "base/logging.h" | |
| 19 #include "base/mac/scoped_ioobject.h" | |
| 20 #include "base/mac/scoped_ioplugininterface.h" | |
| 21 #include "base/macros.h" | |
| 22 #include "base/single_thread_task_runner.h" | |
| 23 #include "base/strings/string_number_conversions.h" | |
| 24 #include "base/threading/thread_task_runner_handle.h" | |
| 25 #include "base/time/time.h" | |
| 26 #import "media/base/mac/avfoundation_glue.h" | |
| 27 #include "media/base/timestamp_constants.h" | |
| 28 #import "media/capture/video/mac/video_capture_device_avfoundation_mac.h" | |
| 29 #include "ui/gfx/geometry/size.h" | |
| 30 | |
| 31 @implementation DeviceNameAndTransportType | |
| 32 | |
| 33 - (id)initWithName:(NSString*)deviceName transportType:(int32_t)transportType { | |
| 34 if (self = [super init]) { | |
| 35 deviceName_.reset([deviceName copy]); | |
| 36 transportType_ = transportType; | |
| 37 } | |
| 38 return self; | |
| 39 } | |
| 40 | |
| 41 - (NSString*)deviceName { | |
| 42 return deviceName_; | |
| 43 } | |
| 44 | |
| 45 - (int32_t)transportType { | |
| 46 return transportType_; | |
| 47 } | |
| 48 | |
| 49 @end // @implementation DeviceNameAndTransportType | |
| 50 | |
| 51 namespace media { | |
| 52 | |
| 53 // Mac specific limits for minimum and maximum frame rate. | |
| 54 const float kMinFrameRate = 1.0f; | |
| 55 const float kMaxFrameRate = 30.0f; | |
| 56 | |
| 57 // In device identifiers, the USB VID and PID are stored in 4 bytes each. | |
| 58 const size_t kVidPidSize = 4; | |
| 59 | |
| 60 // The following constants are extracted from the specification "Universal | |
| 61 // Serial Bus Device Class Definition for Video Devices", Rev. 1.1 June 1, 2005. | |
| 62 // http://www.usb.org/developers/devclass_docs/USB_Video_Class_1_1.zip | |
| 63 // CS_INTERFACE: Sec. A.4 "Video Class-Specific Descriptor Types". | |
| 64 const int kVcCsInterface = 0x24; | |
| 65 // VC_PROCESSING_UNIT: Sec. A.5 "Video Class-Specific VC Interface Descriptor | |
| 66 // Subtypes". | |
| 67 const int kVcProcessingUnit = 0x5; | |
| 68 // SET_CUR: Sec. A.8 "Video Class-Specific Request Codes". | |
| 69 const int kVcRequestCodeSetCur = 0x1; | |
| 70 // PU_POWER_LINE_FREQUENCY_CONTROL: Sec. A.9.5 "Processing Unit Control | |
| 71 // Selectors". | |
| 72 const int kPuPowerLineFrequencyControl = 0x5; | |
| 73 // Sec. 4.2.2.3.5 Power Line Frequency Control. | |
| 74 const int k50Hz = 1; | |
| 75 const int k60Hz = 2; | |
| 76 const int kPuPowerLineFrequencyControlCommandSize = 1; | |
| 77 | |
| 78 // Addition to the IOUSB family of structures, with subtype and unit ID. | |
| 79 typedef struct IOUSBInterfaceDescriptor { | |
| 80 IOUSBDescriptorHeader header; | |
| 81 UInt8 bDescriptorSubType; | |
| 82 UInt8 bUnitID; | |
| 83 } IOUSBInterfaceDescriptor; | |
| 84 | |
| 85 // Tries to create a user-side device interface for a given USB device. Returns | |
| 86 // true if interface was found and passes it back in |device_interface|. The | |
| 87 // caller should release |device_interface|. | |
| 88 static bool FindDeviceInterfaceInUsbDevice( | |
| 89 const int vendor_id, | |
| 90 const int product_id, | |
| 91 const io_service_t usb_device, | |
| 92 IOUSBDeviceInterface*** device_interface) { | |
| 93 // Create a plugin, i.e. a user-side controller to manipulate USB device. | |
| 94 IOCFPlugInInterface** plugin; | |
| 95 SInt32 score; // Unused, but required for IOCreatePlugInInterfaceForService. | |
| 96 kern_return_t kr = IOCreatePlugInInterfaceForService( | |
| 97 usb_device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugin, | |
| 98 &score); | |
| 99 if (kr != kIOReturnSuccess || !plugin) { | |
| 100 DLOG(ERROR) << "IOCreatePlugInInterfaceForService"; | |
| 101 return false; | |
| 102 } | |
| 103 base::mac::ScopedIOPluginInterface<IOCFPlugInInterface> plugin_ref(plugin); | |
| 104 | |
| 105 // Fetch the Device Interface from the plugin. | |
| 106 HRESULT res = (*plugin)->QueryInterface( | |
| 107 plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), | |
| 108 reinterpret_cast<LPVOID*>(device_interface)); | |
| 109 if (!SUCCEEDED(res) || !*device_interface) { | |
| 110 DLOG(ERROR) << "QueryInterface, couldn't create interface to USB"; | |
| 111 return false; | |
| 112 } | |
| 113 return true; | |
| 114 } | |
| 115 | |
| 116 // Tries to find a Video Control type interface inside a general USB device | |
| 117 // interface |device_interface|, and returns it in |video_control_interface| if | |
| 118 // found. The returned interface must be released in the caller. | |
| 119 static bool FindVideoControlInterfaceInDeviceInterface( | |
| 120 IOUSBDeviceInterface** device_interface, | |
| 121 IOCFPlugInInterface*** video_control_interface) { | |
| 122 // Create an iterator to the list of Video-AVControl interfaces of the device, | |
| 123 // then get the first interface in the list. | |
| 124 io_iterator_t interface_iterator; | |
| 125 IOUSBFindInterfaceRequest interface_request = { | |
| 126 .bInterfaceClass = kUSBVideoInterfaceClass, | |
| 127 .bInterfaceSubClass = kUSBVideoControlSubClass, | |
| 128 .bInterfaceProtocol = kIOUSBFindInterfaceDontCare, | |
| 129 .bAlternateSetting = kIOUSBFindInterfaceDontCare}; | |
| 130 kern_return_t kr = | |
| 131 (*device_interface) | |
| 132 ->CreateInterfaceIterator(device_interface, &interface_request, | |
| 133 &interface_iterator); | |
| 134 if (kr != kIOReturnSuccess) { | |
| 135 DLOG(ERROR) << "Could not create an iterator to the device's interfaces."; | |
| 136 return false; | |
| 137 } | |
| 138 base::mac::ScopedIOObject<io_iterator_t> iterator_ref(interface_iterator); | |
| 139 | |
| 140 // There should be just one interface matching the class-subclass desired. | |
| 141 io_service_t found_interface; | |
| 142 found_interface = IOIteratorNext(interface_iterator); | |
| 143 if (!found_interface) { | |
| 144 DLOG(ERROR) << "Could not find a Video-AVControl interface in the device."; | |
| 145 return false; | |
| 146 } | |
| 147 base::mac::ScopedIOObject<io_service_t> found_interface_ref(found_interface); | |
| 148 | |
| 149 // Create a user side controller (i.e. a "plugin") for the found interface. | |
| 150 SInt32 score; | |
| 151 kr = IOCreatePlugInInterfaceForService( | |
| 152 found_interface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, | |
| 153 video_control_interface, &score); | |
| 154 if (kr != kIOReturnSuccess || !*video_control_interface) { | |
| 155 DLOG(ERROR) << "IOCreatePlugInInterfaceForService"; | |
| 156 return false; | |
| 157 } | |
| 158 return true; | |
| 159 } | |
| 160 | |
| 161 // Creates a control interface for |plugin_interface| and produces a command to | |
| 162 // set the appropriate Power Line frequency for flicker removal. | |
| 163 static void SetAntiFlickerInVideoControlInterface( | |
| 164 IOCFPlugInInterface** plugin_interface, | |
| 165 const PowerLineFrequency frequency) { | |
| 166 // Create, the control interface for the found plugin, and release | |
| 167 // the intermediate plugin. | |
| 168 IOUSBInterfaceInterface** control_interface = NULL; | |
| 169 HRESULT res = | |
| 170 (*plugin_interface) | |
| 171 ->QueryInterface(plugin_interface, | |
| 172 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), | |
| 173 reinterpret_cast<LPVOID*>(&control_interface)); | |
| 174 if (!SUCCEEDED(res) || !control_interface) { | |
| 175 DLOG(ERROR) << "Couldn’t create control interface"; | |
| 176 return; | |
| 177 } | |
| 178 base::mac::ScopedIOPluginInterface<IOUSBInterfaceInterface> | |
| 179 control_interface_ref(control_interface); | |
| 180 | |
| 181 // Find the device's unit ID presenting type 0x24 (kVcCsInterface) and | |
| 182 // subtype 0x5 (kVcProcessingUnit). Inside this unit is where we find the | |
| 183 // power line frequency removal setting, and this id is device dependent. | |
| 184 int real_unit_id = -1; | |
| 185 IOUSBDescriptorHeader* descriptor = NULL; | |
| 186 IOUSBInterfaceDescriptor* cs_descriptor = NULL; | |
| 187 IOUSBInterfaceInterface220** interface = | |
| 188 reinterpret_cast<IOUSBInterfaceInterface220**>(control_interface); | |
| 189 while ((descriptor = (*interface) | |
| 190 ->FindNextAssociatedDescriptor(interface, descriptor, | |
| 191 kUSBAnyDesc))) { | |
| 192 cs_descriptor = reinterpret_cast<IOUSBInterfaceDescriptor*>(descriptor); | |
| 193 if ((descriptor->bDescriptorType == kVcCsInterface) && | |
| 194 (cs_descriptor->bDescriptorSubType == kVcProcessingUnit)) { | |
| 195 real_unit_id = cs_descriptor->bUnitID; | |
| 196 break; | |
| 197 } | |
| 198 } | |
| 199 DVLOG_IF(1, real_unit_id == -1) | |
| 200 << "This USB device doesn't seem to have a " | |
| 201 << " VC_PROCESSING_UNIT, anti-flicker not available"; | |
| 202 if (real_unit_id == -1) | |
| 203 return; | |
| 204 | |
| 205 if ((*control_interface)->USBInterfaceOpen(control_interface) != | |
| 206 kIOReturnSuccess) { | |
| 207 DLOG(ERROR) << "Unable to open control interface"; | |
| 208 return; | |
| 209 } | |
| 210 | |
| 211 // Create the control request and launch it to the device's control interface. | |
| 212 // Note how the wIndex needs the interface number OR'ed in the lowest bits. | |
| 213 IOUSBDevRequest command; | |
| 214 command.bmRequestType = | |
| 215 USBmakebmRequestType(kUSBOut, kUSBClass, kUSBInterface); | |
| 216 command.bRequest = kVcRequestCodeSetCur; | |
| 217 UInt8 interface_number; | |
| 218 (*control_interface) | |
| 219 ->GetInterfaceNumber(control_interface, &interface_number); | |
| 220 command.wIndex = (real_unit_id << 8) | interface_number; | |
| 221 const int selector = kPuPowerLineFrequencyControl; | |
| 222 command.wValue = (selector << 8); | |
| 223 command.wLength = kPuPowerLineFrequencyControlCommandSize; | |
| 224 command.wLenDone = 0; | |
| 225 int power_line_flag_value = | |
| 226 (frequency == PowerLineFrequency::FREQUENCY_50HZ) ? k50Hz : k60Hz; | |
| 227 command.pData = &power_line_flag_value; | |
| 228 | |
| 229 IOReturn ret = | |
| 230 (*control_interface)->ControlRequest(control_interface, 0, &command); | |
| 231 DLOG_IF(ERROR, ret != kIOReturnSuccess) << "Anti-flicker control request" | |
| 232 << " failed (0x" << std::hex << ret | |
| 233 << "), unit id: " << real_unit_id; | |
| 234 DVLOG_IF(1, ret == kIOReturnSuccess) << "Anti-flicker set to " | |
| 235 << static_cast<int>(frequency) << "Hz"; | |
| 236 | |
| 237 (*control_interface)->USBInterfaceClose(control_interface); | |
| 238 } | |
| 239 | |
| 240 // Sets the flicker removal in a USB webcam identified by |vendor_id| and | |
| 241 // |product_id|, if available. The process includes first finding all USB | |
| 242 // devices matching the specified |vendor_id| and |product_id|; for each | |
| 243 // matching device, a device interface, and inside it a video control interface | |
| 244 // are created. The latter is used to a send a power frequency setting command. | |
| 245 static void SetAntiFlickerInUsbDevice(const int vendor_id, | |
| 246 const int product_id, | |
| 247 const PowerLineFrequency frequency) { | |
| 248 if (frequency == PowerLineFrequency::FREQUENCY_DEFAULT) | |
| 249 return; | |
| 250 DVLOG(1) << "Setting Power Line Frequency to " << static_cast<int>(frequency) | |
| 251 << " Hz, device " << std::hex << vendor_id << "-" << product_id; | |
| 252 | |
| 253 // Compose a search dictionary with vendor and product ID. | |
| 254 CFMutableDictionaryRef query_dictionary = | |
| 255 IOServiceMatching(kIOUSBDeviceClassName); | |
| 256 CFDictionarySetValue( | |
| 257 query_dictionary, CFSTR(kUSBVendorName), | |
| 258 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id)); | |
| 259 CFDictionarySetValue( | |
| 260 query_dictionary, CFSTR(kUSBProductName), | |
| 261 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product_id)); | |
| 262 | |
| 263 io_iterator_t usb_iterator; | |
| 264 kern_return_t kr = IOServiceGetMatchingServices( | |
| 265 kIOMasterPortDefault, query_dictionary, &usb_iterator); | |
| 266 if (kr != kIOReturnSuccess) { | |
| 267 DLOG(ERROR) << "No devices found with specified Vendor and Product ID."; | |
| 268 return; | |
| 269 } | |
| 270 base::mac::ScopedIOObject<io_iterator_t> usb_iterator_ref(usb_iterator); | |
| 271 | |
| 272 while (io_service_t usb_device = IOIteratorNext(usb_iterator)) { | |
| 273 base::mac::ScopedIOObject<io_service_t> usb_device_ref(usb_device); | |
| 274 | |
| 275 IOUSBDeviceInterface** device_interface = NULL; | |
| 276 if (!FindDeviceInterfaceInUsbDevice(vendor_id, product_id, usb_device, | |
| 277 &device_interface)) { | |
| 278 return; | |
| 279 } | |
| 280 base::mac::ScopedIOPluginInterface<IOUSBDeviceInterface> | |
| 281 device_interface_ref(device_interface); | |
| 282 | |
| 283 IOCFPlugInInterface** video_control_interface = NULL; | |
| 284 if (!FindVideoControlInterfaceInDeviceInterface(device_interface, | |
| 285 &video_control_interface)) { | |
| 286 return; | |
| 287 } | |
| 288 base::mac::ScopedIOPluginInterface<IOCFPlugInInterface> | |
| 289 plugin_interface_ref(video_control_interface); | |
| 290 | |
| 291 SetAntiFlickerInVideoControlInterface(video_control_interface, frequency); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 const std::string VideoCaptureDevice::Name::GetModel() const { | |
| 296 // Skip the AVFoundation's not USB nor built-in devices. | |
| 297 if (capture_api_type() == AVFOUNDATION && transport_type() != USB_OR_BUILT_IN) | |
| 298 return ""; | |
| 299 if (capture_api_type() == DECKLINK) | |
| 300 return ""; | |
| 301 // Both PID and VID are 4 characters. | |
| 302 if (unique_id_.size() < 2 * kVidPidSize) | |
| 303 return ""; | |
| 304 | |
| 305 // The last characters of device id is a concatenation of VID and then PID. | |
| 306 const size_t vid_location = unique_id_.size() - 2 * kVidPidSize; | |
| 307 std::string id_vendor = unique_id_.substr(vid_location, kVidPidSize); | |
| 308 const size_t pid_location = unique_id_.size() - kVidPidSize; | |
| 309 std::string id_product = unique_id_.substr(pid_location, kVidPidSize); | |
| 310 | |
| 311 return id_vendor + ":" + id_product; | |
| 312 } | |
| 313 | |
| 314 VideoCaptureDeviceMac::VideoCaptureDeviceMac(const Name& device_name) | |
| 315 : device_name_(device_name), | |
| 316 task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 317 state_(kNotInitialized), | |
| 318 capture_device_(nil), | |
| 319 weak_factory_(this) { | |
| 320 } | |
| 321 | |
| 322 VideoCaptureDeviceMac::~VideoCaptureDeviceMac() { | |
| 323 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 324 } | |
| 325 | |
| 326 void VideoCaptureDeviceMac::AllocateAndStart( | |
| 327 const VideoCaptureParams& params, | |
| 328 std::unique_ptr<VideoCaptureDevice::Client> client) { | |
| 329 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 330 if (state_ != kIdle) { | |
| 331 return; | |
| 332 } | |
| 333 | |
| 334 client_ = std::move(client); | |
| 335 if (device_name_.capture_api_type() == Name::AVFOUNDATION) | |
| 336 LogMessage("Using AVFoundation for device: " + device_name_.name()); | |
| 337 | |
| 338 NSString* deviceId = | |
| 339 [NSString stringWithUTF8String:device_name_.id().c_str()]; | |
| 340 | |
| 341 [capture_device_ setFrameReceiver:this]; | |
| 342 | |
| 343 if (![capture_device_ setCaptureDevice:deviceId]) { | |
| 344 SetErrorState(FROM_HERE, "Could not open capture device."); | |
| 345 return; | |
| 346 } | |
| 347 | |
| 348 capture_format_.frame_size = params.requested_format.frame_size; | |
| 349 capture_format_.frame_rate = | |
| 350 std::max(kMinFrameRate, | |
| 351 std::min(params.requested_format.frame_rate, kMaxFrameRate)); | |
| 352 // Leave the pixel format selection to AVFoundation. The pixel format | |
| 353 // will be passed to |ReceiveFrame|. | |
| 354 capture_format_.pixel_format = PIXEL_FORMAT_UNKNOWN; | |
| 355 | |
| 356 if (!UpdateCaptureResolution()) | |
| 357 return; | |
| 358 | |
| 359 // Try setting the power line frequency removal (anti-flicker). The built-in | |
| 360 // cameras are normally suspended so the configuration must happen right | |
| 361 // before starting capture and during configuration. | |
| 362 const std::string& device_model = device_name_.GetModel(); | |
| 363 if (device_model.length() > 2 * kVidPidSize) { | |
| 364 std::string vendor_id = device_model.substr(0, kVidPidSize); | |
| 365 std::string model_id = device_model.substr(kVidPidSize + 1); | |
| 366 int vendor_id_as_int, model_id_as_int; | |
| 367 if (base::HexStringToInt(base::StringPiece(vendor_id), &vendor_id_as_int) && | |
| 368 base::HexStringToInt(base::StringPiece(model_id), &model_id_as_int)) { | |
| 369 SetAntiFlickerInUsbDevice(vendor_id_as_int, model_id_as_int, | |
| 370 GetPowerLineFrequency(params)); | |
| 371 } | |
| 372 } | |
| 373 | |
| 374 if (![capture_device_ startCapture]) { | |
| 375 SetErrorState(FROM_HERE, "Could not start capture device."); | |
| 376 return; | |
| 377 } | |
| 378 | |
| 379 state_ = kCapturing; | |
| 380 } | |
| 381 | |
| 382 void VideoCaptureDeviceMac::StopAndDeAllocate() { | |
| 383 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 384 DCHECK(state_ == kCapturing || state_ == kError) << state_; | |
| 385 | |
| 386 [capture_device_ setCaptureDevice:nil]; | |
| 387 [capture_device_ setFrameReceiver:nil]; | |
| 388 client_.reset(); | |
| 389 state_ = kIdle; | |
| 390 } | |
| 391 | |
| 392 void VideoCaptureDeviceMac::TakePhoto(TakePhotoCallback callback) { | |
| 393 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 394 DCHECK(state_ == kCapturing) << state_; | |
| 395 | |
| 396 if (photo_callback_) // Only one picture can be in flight at a time. | |
| 397 return; | |
| 398 | |
| 399 photo_callback_.reset(new TakePhotoCallback(std::move(callback))); | |
| 400 [capture_device_ takePhoto]; | |
| 401 } | |
| 402 | |
| 403 bool VideoCaptureDeviceMac::Init( | |
| 404 VideoCaptureDevice::Name::CaptureApiType capture_api_type) { | |
| 405 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 406 DCHECK_EQ(state_, kNotInitialized); | |
| 407 | |
| 408 if (capture_api_type != Name::AVFOUNDATION) | |
| 409 return false; | |
| 410 | |
| 411 capture_device_.reset( | |
| 412 [[VideoCaptureDeviceAVFoundation alloc] initWithFrameReceiver:this]); | |
| 413 | |
| 414 if (!capture_device_) | |
| 415 return false; | |
| 416 | |
| 417 state_ = kIdle; | |
| 418 return true; | |
| 419 } | |
| 420 | |
| 421 void VideoCaptureDeviceMac::ReceiveFrame(const uint8_t* video_frame, | |
| 422 int video_frame_length, | |
| 423 const VideoCaptureFormat& frame_format, | |
| 424 int aspect_numerator, | |
| 425 int aspect_denominator, | |
| 426 base::TimeDelta timestamp) { | |
| 427 if (capture_format_.frame_size != frame_format.frame_size) { | |
| 428 ReceiveError(FROM_HERE, | |
| 429 "Captured resolution " + frame_format.frame_size.ToString() + | |
| 430 ", and expected " + capture_format_.frame_size.ToString()); | |
| 431 return; | |
| 432 } | |
| 433 | |
| 434 client_->OnIncomingCapturedData(video_frame, video_frame_length, frame_format, | |
| 435 0, base::TimeTicks::Now(), timestamp); | |
| 436 } | |
| 437 | |
| 438 void VideoCaptureDeviceMac::OnPhotoTaken(const uint8_t* image_data, | |
| 439 size_t image_length, | |
| 440 const std::string& mime_type) { | |
| 441 DCHECK(photo_callback_); | |
| 442 if (!image_data || !image_length) { | |
| 443 OnPhotoError(); | |
| 444 return; | |
| 445 } | |
| 446 | |
| 447 photo_callback_->Run(mojo::String::From(mime_type), | |
| 448 mojo::Array<uint8_t>(std::vector<uint8_t>( | |
| 449 image_data, image_data + image_length))); | |
| 450 photo_callback_.reset(); | |
| 451 } | |
| 452 | |
| 453 void VideoCaptureDeviceMac::OnPhotoError() { | |
| 454 DLOG(ERROR) << __FUNCTION__ << " error taking picture"; | |
| 455 photo_callback_.reset(); | |
| 456 } | |
| 457 | |
| 458 void VideoCaptureDeviceMac::ReceiveError( | |
| 459 const tracked_objects::Location& from_here, | |
| 460 const std::string& reason) { | |
| 461 task_runner_->PostTask( | |
| 462 FROM_HERE, base::Bind(&VideoCaptureDeviceMac::SetErrorState, | |
| 463 weak_factory_.GetWeakPtr(), from_here, reason)); | |
| 464 } | |
| 465 | |
| 466 void VideoCaptureDeviceMac::SetErrorState( | |
| 467 const tracked_objects::Location& from_here, | |
| 468 const std::string& reason) { | |
| 469 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 470 state_ = kError; | |
| 471 client_->OnError(from_here, reason); | |
| 472 } | |
| 473 | |
| 474 void VideoCaptureDeviceMac::LogMessage(const std::string& message) { | |
| 475 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 476 if (client_) | |
| 477 client_->OnLog(message); | |
| 478 } | |
| 479 | |
| 480 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { | |
| 481 if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height() | |
| 482 width:capture_format_.frame_size.width() | |
| 483 frameRate:capture_format_.frame_rate]) { | |
| 484 ReceiveError(FROM_HERE, "Could not configure capture device."); | |
| 485 return false; | |
| 486 } | |
| 487 return true; | |
| 488 } | |
| 489 | |
| 490 } // namespace media | |
| OLD | NEW |