| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_factory_mac.h" | 5 #include "media/capture/video/mac/video_capture_device_factory_mac.h" |
| 6 | 6 |
| 7 #import <IOKit/audio/IOAudioTypes.h> | 7 #import <IOKit/audio/IOAudioTypes.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/profiler/scoped_tracker.h" | 15 #include "base/profiler/scoped_tracker.h" |
| 16 #include "base/strings/string_util.h" | 16 #include "base/strings/string_util.h" |
| 17 #include "base/task_runner_util.h" | 17 #include "base/task_runner_util.h" |
| 18 #import "media/base/mac/avfoundation_glue.h" | 18 #import "media/base/mac/avfoundation_glue.h" |
| 19 #import "media/capture/video/mac/video_capture_device_avfoundation_mac.h" | 19 #import "media/capture/video/mac/video_capture_device_avfoundation_mac.h" |
| 20 #import "media/capture/video/mac/video_capture_device_decklink_mac.h" | 20 #import "media/capture/video/mac/video_capture_device_decklink_mac.h" |
| 21 #include "media/capture/video/mac/video_capture_device_mac.h" | 21 #include "media/capture/video/mac/video_capture_device_mac.h" |
| 22 #import "media/capture/video/mac/video_capture_device_qtkit_mac.h" | |
| 23 | 22 |
| 24 namespace media { | 23 namespace media { |
| 25 | 24 |
| 26 // In QTKit API, some devices are known to crash if VGA is requested, for them | 25 // Blacklisted devices are identified by a characteristic trailing substring of |
| 27 // HD is the only supported resolution (see http://crbug.com/396812). In the | 26 // uniqueId. At the moment these are just Blackmagic devices. |
| 28 // AVfoundation case, we skip enumerating them altogether. These devices are | |
| 29 // identified by a characteristic trailing substring of uniqueId. At the moment | |
| 30 // these are just Blackmagic devices. | |
| 31 const struct NameAndVid { | 27 const struct NameAndVid { |
| 32 const char* unique_id_signature; | 28 const char* unique_id_signature; |
| 33 const int capture_width; | 29 const int capture_width; |
| 34 const int capture_height; | 30 const int capture_height; |
| 35 const float capture_frame_rate; | 31 const float capture_frame_rate; |
| 36 } kBlacklistedCameras[] = {{"-01FDA82C8A9C", 1280, 720, 60.0f}}; | 32 } kBlacklistedCameras[] = {{"-01FDA82C8A9C", 1280, 720, 60.0f}}; |
| 37 | 33 |
| 38 static bool IsDeviceBlacklisted(const VideoCaptureDevice::Name& name) { | 34 static bool IsDeviceBlacklisted(const VideoCaptureDevice::Name& name) { |
| 39 bool is_device_blacklisted = false; | 35 bool is_device_blacklisted = false; |
| 40 for(size_t i = 0; | 36 for(size_t i = 0; |
| 41 !is_device_blacklisted && i < arraysize(kBlacklistedCameras); ++i) { | 37 !is_device_blacklisted && i < arraysize(kBlacklistedCameras); ++i) { |
| 42 is_device_blacklisted = | 38 is_device_blacklisted = |
| 43 base::EndsWith(name.id(), | 39 base::EndsWith(name.id(), |
| 44 kBlacklistedCameras[i].unique_id_signature, | 40 kBlacklistedCameras[i].unique_id_signature, |
| 45 base::CompareCase::INSENSITIVE_ASCII); | 41 base::CompareCase::INSENSITIVE_ASCII); |
| 46 } | 42 } |
| 47 DVLOG_IF(2, is_device_blacklisted) << "Blacklisted camera: " << name.name() | 43 DVLOG_IF(2, is_device_blacklisted) << "Blacklisted camera: " << name.name() |
| 48 << ", id: " << name.id(); | 44 << ", id: " << name.id(); |
| 49 return is_device_blacklisted; | 45 return is_device_blacklisted; |
| 50 } | 46 } |
| 51 | 47 |
| 52 static scoped_ptr<media::VideoCaptureDevice::Names> | 48 VideoCaptureDeviceFactoryMac::VideoCaptureDeviceFactoryMac() { |
| 53 EnumerateDevicesUsingQTKit() { | |
| 54 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458397 is | |
| 55 // fixed. | |
| 56 tracked_objects::ScopedTracker tracking_profile( | |
| 57 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 58 "458397 media::EnumerateDevicesUsingQTKit")); | |
| 59 | |
| 60 scoped_ptr<VideoCaptureDevice::Names> device_names( | |
| 61 new VideoCaptureDevice::Names()); | |
| 62 NSMutableDictionary* capture_devices = | |
| 63 [[[NSMutableDictionary alloc] init] autorelease]; | |
| 64 [VideoCaptureDeviceQTKit getDeviceNames:capture_devices]; | |
| 65 for (NSString* key in capture_devices) { | |
| 66 VideoCaptureDevice::Name name( | |
| 67 [[[capture_devices valueForKey:key] deviceName] UTF8String], | |
| 68 [key UTF8String], VideoCaptureDevice::Name::QTKIT); | |
| 69 if (IsDeviceBlacklisted(name)) | |
| 70 name.set_is_blacklisted(true); | |
| 71 device_names->push_back(name); | |
| 72 } | |
| 73 return device_names; | |
| 74 } | |
| 75 | |
| 76 static void RunDevicesEnumeratedCallback( | |
| 77 const base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>& | |
| 78 callback, | |
| 79 scoped_ptr<media::VideoCaptureDevice::Names> device_names) { | |
| 80 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458397 is | |
| 81 // fixed. | |
| 82 tracked_objects::ScopedTracker tracking_profile( | |
| 83 FROM_HERE_WITH_EXPLICIT_FUNCTION( | |
| 84 "458397 media::RunDevicesEnumeratedCallback")); | |
| 85 callback.Run(std::move(device_names)); | |
| 86 } | |
| 87 | |
| 88 VideoCaptureDeviceFactoryMac::VideoCaptureDeviceFactoryMac( | |
| 89 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | |
| 90 : ui_task_runner_(ui_task_runner) { | |
| 91 thread_checker_.DetachFromThread(); | 49 thread_checker_.DetachFromThread(); |
| 92 } | 50 } |
| 93 | 51 |
| 94 VideoCaptureDeviceFactoryMac::~VideoCaptureDeviceFactoryMac() { | 52 VideoCaptureDeviceFactoryMac::~VideoCaptureDeviceFactoryMac() { |
| 95 } | 53 } |
| 96 | 54 |
| 97 scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create( | 55 scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create( |
| 98 const VideoCaptureDevice::Name& device_name) { | 56 const VideoCaptureDevice::Name& device_name) { |
| 99 DCHECK(thread_checker_.CalledOnValidThread()); | 57 DCHECK(thread_checker_.CalledOnValidThread()); |
| 100 DCHECK_NE(device_name.capture_api_type(), | 58 DCHECK_NE(device_name.capture_api_type(), |
| (...skipping 16 matching lines...) Expand all Loading... |
| 117 void VideoCaptureDeviceFactoryMac::GetDeviceNames( | 75 void VideoCaptureDeviceFactoryMac::GetDeviceNames( |
| 118 VideoCaptureDevice::Names* device_names) { | 76 VideoCaptureDevice::Names* device_names) { |
| 119 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458397 is | 77 // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/458397 is |
| 120 // fixed. | 78 // fixed. |
| 121 tracked_objects::ScopedTracker tracking_profile( | 79 tracked_objects::ScopedTracker tracking_profile( |
| 122 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 80 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
| 123 "458397 VideoCaptureDeviceFactoryMac::GetDeviceNames")); | 81 "458397 VideoCaptureDeviceFactoryMac::GetDeviceNames")); |
| 124 DCHECK(thread_checker_.CalledOnValidThread()); | 82 DCHECK(thread_checker_.CalledOnValidThread()); |
| 125 // Loop through all available devices and add to |device_names|. | 83 // Loop through all available devices and add to |device_names|. |
| 126 NSDictionary* capture_devices; | 84 NSDictionary* capture_devices; |
| 127 if (AVFoundationGlue::IsAVFoundationSupported()) { | 85 DVLOG(1) << "Enumerating video capture devices using AVFoundation"; |
| 128 DVLOG(1) << "Enumerating video capture devices using AVFoundation"; | 86 capture_devices = [VideoCaptureDeviceAVFoundation deviceNames]; |
| 129 capture_devices = [VideoCaptureDeviceAVFoundation deviceNames]; | 87 // Enumerate all devices found by AVFoundation, translate the info for each |
| 130 // Enumerate all devices found by AVFoundation, translate the info for each | 88 // to class Name and add it to |device_names|. |
| 131 // to class Name and add it to |device_names|. | 89 for (NSString* key in capture_devices) { |
| 132 for (NSString* key in capture_devices) { | 90 int transport_type = [[capture_devices valueForKey:key] transportType]; |
| 133 int transport_type = [[capture_devices valueForKey:key] transportType]; | 91 // Transport types are defined for Audio devices and reused for video. |
| 134 // Transport types are defined for Audio devices and reused for video. | 92 VideoCaptureDevice::Name::TransportType device_transport_type = |
| 135 VideoCaptureDevice::Name::TransportType device_transport_type = | 93 (transport_type == kIOAudioDeviceTransportTypeBuiltIn || |
| 136 (transport_type == kIOAudioDeviceTransportTypeBuiltIn || | 94 transport_type == kIOAudioDeviceTransportTypeUSB) |
| 137 transport_type == kIOAudioDeviceTransportTypeUSB) | 95 ? VideoCaptureDevice::Name::USB_OR_BUILT_IN |
| 138 ? VideoCaptureDevice::Name::USB_OR_BUILT_IN | 96 : VideoCaptureDevice::Name::OTHER_TRANSPORT; |
| 139 : VideoCaptureDevice::Name::OTHER_TRANSPORT; | 97 VideoCaptureDevice::Name name( |
| 140 VideoCaptureDevice::Name name( | 98 [[[capture_devices valueForKey:key] deviceName] UTF8String], |
| 141 [[[capture_devices valueForKey:key] deviceName] UTF8String], | 99 [key UTF8String], VideoCaptureDevice::Name::AVFOUNDATION, |
| 142 [key UTF8String], VideoCaptureDevice::Name::AVFOUNDATION, | 100 device_transport_type); |
| 143 device_transport_type); | 101 if (IsDeviceBlacklisted(name)) |
| 144 if (IsDeviceBlacklisted(name)) | 102 continue; |
| 145 continue; | 103 device_names->push_back(name); |
| 146 device_names->push_back(name); | |
| 147 } | |
| 148 // Also retrieve Blackmagic devices, if present, via DeckLink SDK API. | |
| 149 VideoCaptureDeviceDeckLinkMac::EnumerateDevices(device_names); | |
| 150 } else { | |
| 151 // We should not enumerate QTKit devices in Device Thread; | |
| 152 NOTREACHED(); | |
| 153 } | 104 } |
| 105 // Also retrieve Blackmagic devices, if present, via DeckLink SDK API. |
| 106 VideoCaptureDeviceDeckLinkMac::EnumerateDevices(device_names); |
| 154 } | 107 } |
| 155 | 108 |
| 156 void VideoCaptureDeviceFactoryMac::EnumerateDeviceNames(const base::Callback< | 109 void VideoCaptureDeviceFactoryMac::EnumerateDeviceNames(const base::Callback< |
| 157 void(scoped_ptr<media::VideoCaptureDevice::Names>)>& callback) { | 110 void(scoped_ptr<media::VideoCaptureDevice::Names>)>& callback) { |
| 158 DCHECK(thread_checker_.CalledOnValidThread()); | 111 DCHECK(thread_checker_.CalledOnValidThread()); |
| 159 if (AVFoundationGlue::IsAVFoundationSupported()) { | 112 scoped_ptr<VideoCaptureDevice::Names> device_names( |
| 160 scoped_ptr<VideoCaptureDevice::Names> device_names( | 113 new VideoCaptureDevice::Names()); |
| 161 new VideoCaptureDevice::Names()); | 114 GetDeviceNames(device_names.get()); |
| 162 GetDeviceNames(device_names.get()); | 115 callback.Run(std::move(device_names)); |
| 163 callback.Run(std::move(device_names)); | |
| 164 } else { | |
| 165 DVLOG(1) << "Enumerating video capture devices using QTKit"; | |
| 166 base::PostTaskAndReplyWithResult( | |
| 167 ui_task_runner_.get(), FROM_HERE, | |
| 168 base::Bind(&EnumerateDevicesUsingQTKit), | |
| 169 base::Bind(&RunDevicesEnumeratedCallback, callback)); | |
| 170 } | |
| 171 } | 116 } |
| 172 | 117 |
| 173 void VideoCaptureDeviceFactoryMac::GetDeviceSupportedFormats( | 118 void VideoCaptureDeviceFactoryMac::GetDeviceSupportedFormats( |
| 174 const VideoCaptureDevice::Name& device, | 119 const VideoCaptureDevice::Name& device, |
| 175 VideoCaptureFormats* supported_formats) { | 120 VideoCaptureFormats* supported_formats) { |
| 176 DCHECK(thread_checker_.CalledOnValidThread()); | 121 DCHECK(thread_checker_.CalledOnValidThread()); |
| 177 switch (device.capture_api_type()) { | 122 switch (device.capture_api_type()) { |
| 178 case VideoCaptureDevice::Name::AVFOUNDATION: | 123 case VideoCaptureDevice::Name::AVFOUNDATION: |
| 179 DVLOG(1) << "Enumerating video capture capabilities, AVFoundation"; | 124 DVLOG(1) << "Enumerating video capture capabilities, AVFoundation"; |
| 180 [VideoCaptureDeviceAVFoundation getDevice:device | 125 [VideoCaptureDeviceAVFoundation getDevice:device |
| 181 supportedFormats:supported_formats]; | 126 supportedFormats:supported_formats]; |
| 182 break; | 127 break; |
| 183 case VideoCaptureDevice::Name::QTKIT: | |
| 184 // Blacklisted cameras provide their own supported format(s), otherwise no | |
| 185 // such information is provided for QTKit devices. | |
| 186 if (device.is_blacklisted()) { | |
| 187 for (size_t i = 0; i < arraysize(kBlacklistedCameras); ++i) { | |
| 188 if (base::EndsWith(device.id(), | |
| 189 kBlacklistedCameras[i].unique_id_signature, | |
| 190 base::CompareCase::INSENSITIVE_ASCII)) { | |
| 191 supported_formats->push_back(media::VideoCaptureFormat( | |
| 192 gfx::Size(kBlacklistedCameras[i].capture_width, | |
| 193 kBlacklistedCameras[i].capture_height), | |
| 194 kBlacklistedCameras[i].capture_frame_rate, | |
| 195 media::PIXEL_FORMAT_UYVY)); | |
| 196 break; | |
| 197 } | |
| 198 } | |
| 199 } | |
| 200 break; | |
| 201 case VideoCaptureDevice::Name::DECKLINK: | 128 case VideoCaptureDevice::Name::DECKLINK: |
| 202 DVLOG(1) << "Enumerating video capture capabilities " << device.name(); | 129 DVLOG(1) << "Enumerating video capture capabilities " << device.name(); |
| 203 VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities( | 130 VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities( |
| 204 device, supported_formats); | 131 device, supported_formats); |
| 205 break; | 132 break; |
| 206 default: | 133 default: |
| 207 NOTREACHED(); | 134 NOTREACHED(); |
| 208 } | 135 } |
| 209 } | 136 } |
| 210 | 137 |
| 211 // static | 138 // static |
| 212 VideoCaptureDeviceFactory* | 139 VideoCaptureDeviceFactory* |
| 213 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( | 140 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( |
| 214 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | 141 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { |
| 215 return new VideoCaptureDeviceFactoryMac(ui_task_runner); | 142 return new VideoCaptureDeviceFactoryMac(); |
| 216 } | 143 } |
| 217 | 144 |
| 218 } // namespace media | 145 } // namespace media |
| OLD | NEW |