OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 #import "media/video/capture/mac/avfoundation_glue.h" | |
6 | |
7 #include <dlfcn.h> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "base/mac/mac_util.h" | |
12 #include "base/metrics/field_trial.h" | |
13 #include "media/base/media_switches.h" | |
14 | |
15 namespace { | |
16 | |
17 // This class is used to retrieve AVFoundation NSBundle and library handle. It | |
18 // must be used as a LazyInstance so that it is initialised once and in a | |
19 // thread-safe way. Normally no work is done in constructors: LazyInstance is | |
20 // an exception. | |
21 class AVFoundationInternal { | |
22 public: | |
23 AVFoundationInternal() { | |
24 bundle_ = [NSBundle | |
25 bundleWithPath:@"/System/Library/Frameworks/AVFoundation.framework"]; | |
26 | |
27 const char* path = [[bundle_ executablePath] fileSystemRepresentation]; | |
28 CHECK(path); | |
29 library_handle_ = dlopen(path, RTLD_LAZY | RTLD_LOCAL); | |
30 CHECK(library_handle_) << dlerror(); | |
31 | |
32 struct { | |
33 NSString** loaded_string; | |
34 const char* symbol; | |
35 } av_strings[] = { | |
36 {&AVCaptureDeviceWasConnectedNotification_, | |
37 "AVCaptureDeviceWasConnectedNotification"}, | |
38 {&AVCaptureDeviceWasDisconnectedNotification_, | |
39 "AVCaptureDeviceWasDisconnectedNotification"}, | |
40 {&AVMediaTypeVideo_, "AVMediaTypeVideo"}, | |
41 {&AVMediaTypeAudio_, "AVMediaTypeAudio"}, | |
42 {&AVMediaTypeMuxed_, "AVMediaTypeMuxed"}, | |
43 {&AVCaptureSessionRuntimeErrorNotification_, | |
44 "AVCaptureSessionRuntimeErrorNotification"}, | |
45 {&AVCaptureSessionDidStopRunningNotification_, | |
46 "AVCaptureSessionDidStopRunningNotification"}, | |
47 {&AVCaptureSessionErrorKey_, "AVCaptureSessionErrorKey"}, | |
48 {&AVVideoScalingModeKey_, "AVVideoScalingModeKey"}, | |
49 {&AVVideoScalingModeResizeAspectFill_, | |
50 "AVVideoScalingModeResizeAspectFill"}, | |
51 }; | |
52 for (size_t i = 0; i < arraysize(av_strings); ++i) { | |
53 *av_strings[i].loaded_string = *reinterpret_cast<NSString**>( | |
54 dlsym(library_handle_, av_strings[i].symbol)); | |
55 DCHECK(*av_strings[i].loaded_string) << dlerror(); | |
56 } | |
57 } | |
58 | |
59 NSBundle* bundle() const { return bundle_; } | |
60 void* library_handle() const { return library_handle_; } | |
61 | |
62 NSString* AVCaptureDeviceWasConnectedNotification() const { | |
63 return AVCaptureDeviceWasConnectedNotification_; | |
64 } | |
65 NSString* AVCaptureDeviceWasDisconnectedNotification() const { | |
66 return AVCaptureDeviceWasDisconnectedNotification_; | |
67 } | |
68 NSString* AVMediaTypeVideo() const { return AVMediaTypeVideo_; } | |
69 NSString* AVMediaTypeAudio() const { return AVMediaTypeAudio_; } | |
70 NSString* AVMediaTypeMuxed() const { return AVMediaTypeMuxed_; } | |
71 NSString* AVCaptureSessionRuntimeErrorNotification() const { | |
72 return AVCaptureSessionRuntimeErrorNotification_; | |
73 } | |
74 NSString* AVCaptureSessionDidStopRunningNotification() const { | |
75 return AVCaptureSessionDidStopRunningNotification_; | |
76 } | |
77 NSString* AVCaptureSessionErrorKey() const { | |
78 return AVCaptureSessionErrorKey_; | |
79 } | |
80 NSString* AVVideoScalingModeKey() const { return AVVideoScalingModeKey_; } | |
81 NSString* AVVideoScalingModeResizeAspectFill() const { | |
82 return AVVideoScalingModeResizeAspectFill_; | |
83 } | |
84 | |
85 private: | |
86 NSBundle* bundle_; | |
87 void* library_handle_; | |
88 // The following members are replicas of the respectives in AVFoundation. | |
89 NSString* AVCaptureDeviceWasConnectedNotification_; | |
90 NSString* AVCaptureDeviceWasDisconnectedNotification_; | |
91 NSString* AVMediaTypeVideo_; | |
92 NSString* AVMediaTypeAudio_; | |
93 NSString* AVMediaTypeMuxed_; | |
94 NSString* AVCaptureSessionRuntimeErrorNotification_; | |
95 NSString* AVCaptureSessionDidStopRunningNotification_; | |
96 NSString* AVCaptureSessionErrorKey_; | |
97 NSString* AVVideoScalingModeKey_; | |
98 NSString* AVVideoScalingModeResizeAspectFill_; | |
99 | |
100 DISALLOW_COPY_AND_ASSIGN(AVFoundationInternal); | |
101 }; | |
102 | |
103 } // namespace | |
104 | |
105 static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle = | |
106 LAZY_INSTANCE_INITIALIZER; | |
107 | |
108 bool AVFoundationGlue::IsAVFoundationSupported() { | |
109 // DeviceMonitorMac will initialize this static bool from the main UI thread | |
110 // once, during Chrome startup so this construction is thread safe. | |
111 // Use AVFoundation if possible, enabled, and QTKit is not explicitly forced. | |
112 static CommandLine* command_line = CommandLine::ForCurrentProcess(); | |
113 | |
114 // AVFoundation is only available on OS Lion and above. | |
115 if (!base::mac::IsOSLionOrLater()) | |
116 return false; | |
117 | |
118 // The force-qtkit flag takes precedence over enable-avfoundation. | |
119 if (command_line->HasSwitch(switches::kForceQTKit)) | |
120 return false; | |
121 | |
122 // Next in precedence is the enable-avfoundation flag. | |
123 // TODO(vrk): Does this really need to be static? | |
124 static bool should_enable_avfoundation = | |
125 command_line->HasSwitch(switches::kEnableAVFoundation) || | |
126 base::FieldTrialList::FindFullName("AVFoundationMacVideoCapture") | |
127 == "Enabled"; | |
128 // Try to load AVFoundation. Save result in static bool to avoid loading | |
129 // AVFoundationBundle every call. | |
130 static bool loaded_successfully = [AVFoundationBundle() load]; | |
131 return should_enable_avfoundation && loaded_successfully; | |
132 } | |
133 | |
134 NSBundle const* AVFoundationGlue::AVFoundationBundle() { | |
135 return g_avfoundation_handle.Get().bundle(); | |
136 } | |
137 | |
138 void* AVFoundationGlue::AVFoundationLibraryHandle() { | |
139 return g_avfoundation_handle.Get().library_handle(); | |
140 } | |
141 | |
142 NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() { | |
143 return g_avfoundation_handle.Get().AVCaptureDeviceWasConnectedNotification(); | |
144 } | |
145 | |
146 NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() { | |
147 return | |
148 g_avfoundation_handle.Get().AVCaptureDeviceWasDisconnectedNotification(); | |
149 } | |
150 | |
151 NSString* AVFoundationGlue::AVMediaTypeVideo() { | |
152 return g_avfoundation_handle.Get().AVMediaTypeVideo(); | |
153 } | |
154 | |
155 NSString* AVFoundationGlue::AVMediaTypeAudio() { | |
156 return g_avfoundation_handle.Get().AVMediaTypeAudio(); | |
157 } | |
158 | |
159 NSString* AVFoundationGlue::AVMediaTypeMuxed() { | |
160 return g_avfoundation_handle.Get().AVMediaTypeMuxed(); | |
161 } | |
162 | |
163 NSString* AVFoundationGlue::AVCaptureSessionRuntimeErrorNotification() { | |
164 return g_avfoundation_handle.Get().AVCaptureSessionRuntimeErrorNotification(); | |
165 } | |
166 | |
167 NSString* AVFoundationGlue::AVCaptureSessionDidStopRunningNotification() { | |
168 return | |
169 g_avfoundation_handle.Get().AVCaptureSessionDidStopRunningNotification(); | |
170 } | |
171 | |
172 NSString* AVFoundationGlue::AVCaptureSessionErrorKey() { | |
173 return g_avfoundation_handle.Get().AVCaptureSessionErrorKey(); | |
174 } | |
175 | |
176 NSString* AVFoundationGlue::AVVideoScalingModeKey() { | |
177 return g_avfoundation_handle.Get().AVVideoScalingModeKey(); | |
178 } | |
179 | |
180 NSString* AVFoundationGlue::AVVideoScalingModeResizeAspectFill() { | |
181 return g_avfoundation_handle.Get().AVVideoScalingModeResizeAspectFill(); | |
182 } | |
183 | |
184 Class AVFoundationGlue::AVCaptureSessionClass() { | |
185 return [AVFoundationBundle() classNamed:@"AVCaptureSession"]; | |
186 } | |
187 | |
188 Class AVFoundationGlue::AVCaptureVideoDataOutputClass() { | |
189 return [AVFoundationBundle() classNamed:@"AVCaptureVideoDataOutput"]; | |
190 } | |
191 | |
192 @implementation AVCaptureDeviceGlue | |
193 | |
194 + (NSArray*)devices { | |
195 Class avcClass = | |
196 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"]; | |
197 if ([avcClass respondsToSelector:@selector(devices)]) { | |
198 return [avcClass performSelector:@selector(devices)]; | |
199 } | |
200 return nil; | |
201 } | |
202 | |
203 + (CrAVCaptureDevice*)deviceWithUniqueID:(NSString*)deviceUniqueID { | |
204 Class avcClass = | |
205 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"]; | |
206 return [avcClass performSelector:@selector(deviceWithUniqueID:) | |
207 withObject:deviceUniqueID]; | |
208 } | |
209 | |
210 @end // @implementation AVCaptureDeviceGlue | |
211 | |
212 @implementation AVCaptureDeviceInputGlue | |
213 | |
214 + (CrAVCaptureDeviceInput*)deviceInputWithDevice:(CrAVCaptureDevice*)device | |
215 error:(NSError**)outError { | |
216 return [[AVFoundationGlue::AVFoundationBundle() | |
217 classNamed:@"AVCaptureDeviceInput"] deviceInputWithDevice:device | |
218 error:outError]; | |
219 } | |
220 | |
221 @end // @implementation AVCaptureDeviceInputGlue | |
OLD | NEW |