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