| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/capture/video/mac/video_capture_device_mac.h" | 5 #include "device/capture/video/mac/video_capture_device_mac.h" |
| 6 | 6 |
| 7 #include <IOKit/IOCFPlugIn.h> | 7 #include <IOKit/IOCFPlugIn.h> |
| 8 #include <IOKit/usb/IOUSBLib.h> | 8 #include <IOKit/usb/IOUSBLib.h> |
| 9 #include <IOKit/usb/USBSpec.h> | 9 #include <IOKit/usb/USBSpec.h> |
| 10 #include <stddef.h> | 10 #include <stddef.h> |
| 11 #include <stdint.h> | 11 #include <stdint.h> |
| 12 | 12 |
| 13 #include <limits> | 13 #include <limits> |
| 14 #include <utility> | 14 #include <utility> |
| 15 | 15 |
| 16 #include "base/bind.h" | 16 #include "base/bind.h" |
| 17 #include "base/location.h" | 17 #include "base/location.h" |
| 18 #include "base/logging.h" | 18 #include "base/logging.h" |
| 19 #include "base/mac/scoped_ioobject.h" | 19 #include "base/mac/scoped_ioobject.h" |
| 20 #include "base/mac/scoped_ioplugininterface.h" | 20 #include "base/mac/scoped_ioplugininterface.h" |
| 21 #include "base/macros.h" | 21 #include "base/macros.h" |
| 22 #include "base/single_thread_task_runner.h" | 22 #include "base/single_thread_task_runner.h" |
| 23 #include "base/strings/string_number_conversions.h" | 23 #include "base/strings/string_number_conversions.h" |
| 24 #include "base/threading/thread_task_runner_handle.h" | 24 #include "base/threading/thread_task_runner_handle.h" |
| 25 #include "base/time/time.h" | 25 #include "base/time/time.h" |
| 26 #import "device/capture/video/mac/video_capture_device_avfoundation_mac.h" |
| 26 #import "media/base/mac/avfoundation_glue.h" | 27 #import "media/base/mac/avfoundation_glue.h" |
| 27 #include "media/base/timestamp_constants.h" | 28 #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" | 29 #include "ui/gfx/geometry/size.h" |
| 30 | 30 |
| 31 @implementation DeviceNameAndTransportType | 31 @implementation DeviceNameAndTransportType |
| 32 | 32 |
| 33 - (id)initWithName:(NSString*)deviceName transportType:(int32_t)transportType { | 33 - (id)initWithName:(NSString*)deviceName transportType:(int32_t)transportType { |
| 34 if (self = [super init]) { | 34 if (self = [super init]) { |
| 35 deviceName_.reset([deviceName copy]); | 35 deviceName_.reset([deviceName copy]); |
| 36 transportType_ = transportType; | 36 transportType_ = transportType; |
| 37 } | 37 } |
| 38 return self; | 38 return self; |
| 39 } | 39 } |
| 40 | 40 |
| 41 - (NSString*)deviceName { | 41 - (NSString*)deviceName { |
| 42 return deviceName_; | 42 return deviceName_; |
| 43 } | 43 } |
| 44 | 44 |
| 45 - (int32_t)transportType { | 45 - (int32_t)transportType { |
| 46 return transportType_; | 46 return transportType_; |
| 47 } | 47 } |
| 48 | 48 |
| 49 @end // @implementation DeviceNameAndTransportType | 49 @end // @implementation DeviceNameAndTransportType |
| 50 | 50 |
| 51 namespace media { | 51 namespace device { |
| 52 | 52 |
| 53 // Mac specific limits for minimum and maximum frame rate. | 53 // Mac specific limits for minimum and maximum frame rate. |
| 54 const float kMinFrameRate = 1.0f; | 54 const float kMinFrameRate = 1.0f; |
| 55 const float kMaxFrameRate = 30.0f; | 55 const float kMaxFrameRate = 30.0f; |
| 56 | 56 |
| 57 // In device identifiers, the USB VID and PID are stored in 4 bytes each. | 57 // In device identifiers, the USB VID and PID are stored in 4 bytes each. |
| 58 const size_t kVidPidSize = 4; | 58 const size_t kVidPidSize = 4; |
| 59 | 59 |
| 60 // The following constants are extracted from the specification "Universal | 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. | 61 // Serial Bus Device Class Definition for Video Devices", Rev. 1.1 June 1, 2005. |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 DLOG(ERROR) << "IOCreatePlugInInterfaceForService"; | 155 DLOG(ERROR) << "IOCreatePlugInInterfaceForService"; |
| 156 return false; | 156 return false; |
| 157 } | 157 } |
| 158 return true; | 158 return true; |
| 159 } | 159 } |
| 160 | 160 |
| 161 // Creates a control interface for |plugin_interface| and produces a command to | 161 // Creates a control interface for |plugin_interface| and produces a command to |
| 162 // set the appropriate Power Line frequency for flicker removal. | 162 // set the appropriate Power Line frequency for flicker removal. |
| 163 static void SetAntiFlickerInVideoControlInterface( | 163 static void SetAntiFlickerInVideoControlInterface( |
| 164 IOCFPlugInInterface** plugin_interface, | 164 IOCFPlugInInterface** plugin_interface, |
| 165 const PowerLineFrequency frequency) { | 165 const media::PowerLineFrequency frequency) { |
| 166 // Create, the control interface for the found plugin, and release | 166 // Create, the control interface for the found plugin, and release |
| 167 // the intermediate plugin. | 167 // the intermediate plugin. |
| 168 IOUSBInterfaceInterface** control_interface = NULL; | 168 IOUSBInterfaceInterface** control_interface = NULL; |
| 169 HRESULT res = | 169 HRESULT res = |
| 170 (*plugin_interface) | 170 (*plugin_interface) |
| 171 ->QueryInterface(plugin_interface, | 171 ->QueryInterface(plugin_interface, |
| 172 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), | 172 CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), |
| 173 reinterpret_cast<LPVOID*>(&control_interface)); | 173 reinterpret_cast<LPVOID*>(&control_interface)); |
| 174 if (!SUCCEEDED(res) || !control_interface) { | 174 if (!SUCCEEDED(res) || !control_interface) { |
| 175 DLOG(ERROR) << "Couldn’t create control interface"; | 175 DLOG(ERROR) << "Couldn’t create control interface"; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 command.bRequest = kVcRequestCodeSetCur; | 216 command.bRequest = kVcRequestCodeSetCur; |
| 217 UInt8 interface_number; | 217 UInt8 interface_number; |
| 218 (*control_interface) | 218 (*control_interface) |
| 219 ->GetInterfaceNumber(control_interface, &interface_number); | 219 ->GetInterfaceNumber(control_interface, &interface_number); |
| 220 command.wIndex = (real_unit_id << 8) | interface_number; | 220 command.wIndex = (real_unit_id << 8) | interface_number; |
| 221 const int selector = kPuPowerLineFrequencyControl; | 221 const int selector = kPuPowerLineFrequencyControl; |
| 222 command.wValue = (selector << 8); | 222 command.wValue = (selector << 8); |
| 223 command.wLength = kPuPowerLineFrequencyControlCommandSize; | 223 command.wLength = kPuPowerLineFrequencyControlCommandSize; |
| 224 command.wLenDone = 0; | 224 command.wLenDone = 0; |
| 225 int power_line_flag_value = | 225 int power_line_flag_value = |
| 226 (frequency == PowerLineFrequency::FREQUENCY_50HZ) ? k50Hz : k60Hz; | 226 (frequency == media::PowerLineFrequency::FREQUENCY_50HZ) ? k50Hz : k60Hz; |
| 227 command.pData = &power_line_flag_value; | 227 command.pData = &power_line_flag_value; |
| 228 | 228 |
| 229 IOReturn ret = | 229 IOReturn ret = |
| 230 (*control_interface)->ControlRequest(control_interface, 0, &command); | 230 (*control_interface)->ControlRequest(control_interface, 0, &command); |
| 231 DLOG_IF(ERROR, ret != kIOReturnSuccess) << "Anti-flicker control request" | 231 DLOG_IF(ERROR, ret != kIOReturnSuccess) << "Anti-flicker control request" |
| 232 << " failed (0x" << std::hex << ret | 232 << " failed (0x" << std::hex << ret |
| 233 << "), unit id: " << real_unit_id; | 233 << "), unit id: " << real_unit_id; |
| 234 DVLOG_IF(1, ret == kIOReturnSuccess) << "Anti-flicker set to " | 234 DVLOG_IF(1, ret == kIOReturnSuccess) << "Anti-flicker set to " |
| 235 << static_cast<int>(frequency) << "Hz"; | 235 << static_cast<int>(frequency) << "Hz"; |
| 236 | 236 |
| 237 (*control_interface)->USBInterfaceClose(control_interface); | 237 (*control_interface)->USBInterfaceClose(control_interface); |
| 238 } | 238 } |
| 239 | 239 |
| 240 // Sets the flicker removal in a USB webcam identified by |vendor_id| and | 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 | 241 // |product_id|, if available. The process includes first finding all USB |
| 242 // devices matching the specified |vendor_id| and |product_id|; for each | 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 | 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. | 244 // are created. The latter is used to a send a power frequency setting command. |
| 245 static void SetAntiFlickerInUsbDevice(const int vendor_id, | 245 static void SetAntiFlickerInUsbDevice( |
| 246 const int product_id, | 246 const int vendor_id, |
| 247 const PowerLineFrequency frequency) { | 247 const int product_id, |
| 248 if (frequency == PowerLineFrequency::FREQUENCY_DEFAULT) | 248 const media::PowerLineFrequency frequency) { |
| 249 if (frequency == media::PowerLineFrequency::FREQUENCY_DEFAULT) |
| 249 return; | 250 return; |
| 250 DVLOG(1) << "Setting Power Line Frequency to " << static_cast<int>(frequency) | 251 DVLOG(1) << "Setting Power Line Frequency to " << static_cast<int>(frequency) |
| 251 << " Hz, device " << std::hex << vendor_id << "-" << product_id; | 252 << " Hz, device " << std::hex << vendor_id << "-" << product_id; |
| 252 | 253 |
| 253 // Compose a search dictionary with vendor and product ID. | 254 // Compose a search dictionary with vendor and product ID. |
| 254 CFMutableDictionaryRef query_dictionary = | 255 CFMutableDictionaryRef query_dictionary = |
| 255 IOServiceMatching(kIOUSBDeviceClassName); | 256 IOServiceMatching(kIOUSBDeviceClassName); |
| 256 CFDictionarySetValue( | 257 CFDictionarySetValue( |
| 257 query_dictionary, CFSTR(kUSBVendorName), | 258 query_dictionary, CFSTR(kUSBVendorName), |
| 258 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id)); | 259 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor_id)); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 SetErrorState(FROM_HERE, "Could not open capture device."); | 327 SetErrorState(FROM_HERE, "Could not open capture device."); |
| 327 return; | 328 return; |
| 328 } | 329 } |
| 329 | 330 |
| 330 capture_format_.frame_size = params.requested_format.frame_size; | 331 capture_format_.frame_size = params.requested_format.frame_size; |
| 331 capture_format_.frame_rate = | 332 capture_format_.frame_rate = |
| 332 std::max(kMinFrameRate, | 333 std::max(kMinFrameRate, |
| 333 std::min(params.requested_format.frame_rate, kMaxFrameRate)); | 334 std::min(params.requested_format.frame_rate, kMaxFrameRate)); |
| 334 // Leave the pixel format selection to AVFoundation. The pixel format | 335 // Leave the pixel format selection to AVFoundation. The pixel format |
| 335 // will be passed to |ReceiveFrame|. | 336 // will be passed to |ReceiveFrame|. |
| 336 capture_format_.pixel_format = PIXEL_FORMAT_UNKNOWN; | 337 capture_format_.pixel_format = media::PIXEL_FORMAT_UNKNOWN; |
| 337 | 338 |
| 338 if (!UpdateCaptureResolution()) | 339 if (!UpdateCaptureResolution()) |
| 339 return; | 340 return; |
| 340 | 341 |
| 341 // Try setting the power line frequency removal (anti-flicker). The built-in | 342 // Try setting the power line frequency removal (anti-flicker). The built-in |
| 342 // cameras are normally suspended so the configuration must happen right | 343 // cameras are normally suspended so the configuration must happen right |
| 343 // before starting capture and during configuration. | 344 // before starting capture and during configuration. |
| 344 const std::string device_model = GetDeviceModelId( | 345 const std::string device_model = GetDeviceModelId( |
| 345 device_descriptor_.device_id, device_descriptor_.capture_api, | 346 device_descriptor_.device_id, device_descriptor_.capture_api, |
| 346 device_descriptor_.transport_type); | 347 device_descriptor_.transport_type); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 | 421 |
| 421 void VideoCaptureDeviceMac::OnPhotoTaken(const uint8_t* image_data, | 422 void VideoCaptureDeviceMac::OnPhotoTaken(const uint8_t* image_data, |
| 422 size_t image_length, | 423 size_t image_length, |
| 423 const std::string& mime_type) { | 424 const std::string& mime_type) { |
| 424 DCHECK(photo_callback_); | 425 DCHECK(photo_callback_); |
| 425 if (!image_data || !image_length) { | 426 if (!image_data || !image_length) { |
| 426 OnPhotoError(); | 427 OnPhotoError(); |
| 427 return; | 428 return; |
| 428 } | 429 } |
| 429 | 430 |
| 430 mojom::BlobPtr blob = mojom::Blob::New(); | 431 media::mojom::BlobPtr blob = media::mojom::Blob::New(); |
| 431 blob->data.assign(image_data, image_data + image_length); | 432 blob->data.assign(image_data, image_data + image_length); |
| 432 blob->mime_type = mime_type; | 433 blob->mime_type = mime_type; |
| 433 photo_callback_->Run(std::move(blob)); | 434 photo_callback_->Run(std::move(blob)); |
| 434 photo_callback_.reset(); | 435 photo_callback_.reset(); |
| 435 } | 436 } |
| 436 | 437 |
| 437 void VideoCaptureDeviceMac::OnPhotoError() { | 438 void VideoCaptureDeviceMac::OnPhotoError() { |
| 438 DLOG(ERROR) << __FUNCTION__ << " error taking picture"; | 439 DLOG(ERROR) << __FUNCTION__ << " error taking picture"; |
| 439 photo_callback_.reset(); | 440 photo_callback_.reset(); |
| 440 } | 441 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { | 489 bool VideoCaptureDeviceMac::UpdateCaptureResolution() { |
| 489 if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height() | 490 if (![capture_device_ setCaptureHeight:capture_format_.frame_size.height() |
| 490 width:capture_format_.frame_size.width() | 491 width:capture_format_.frame_size.width() |
| 491 frameRate:capture_format_.frame_rate]) { | 492 frameRate:capture_format_.frame_rate]) { |
| 492 ReceiveError(FROM_HERE, "Could not configure capture device."); | 493 ReceiveError(FROM_HERE, "Could not configure capture device."); |
| 493 return false; | 494 return false; |
| 494 } | 495 } |
| 495 return true; | 496 return true; |
| 496 } | 497 } |
| 497 | 498 |
| 498 } // namespace media | 499 } // namespace device |
| OLD | NEW |