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.
5 #import "media/video/capture/mac/avfoundation_glue.h"
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"
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
21 class AVFoundationInternal {
23 AVFoundationInternal() {
25 bundleWithPath:@"/System/Library/Frameworks/AVFoundation.framework"];
27 const char* path = [[bundle_ executablePath] fileSystemRepresentation];
29 library_handle_ = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
30 CHECK(library_handle_) << dlerror();
33 NSString** loaded_string;
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 {&AVCaptureSessionPreset320x240_, "AVCaptureSessionPreset320x240"},
49 {&AVCaptureSessionPreset640x480_, "AVCaptureSessionPreset640x480"},
50 {&AVCaptureSessionPreset1280x720_, "AVCaptureSessionPreset1280x720"},
51 {&AVVideoScalingModeKey_, "AVVideoScalingModeKey"},
52 {&AVVideoScalingModeResizeAspect_, "AVVideoScalingModeResizeAspect"},
54 for (size_t i = 0; i < arraysize(av_strings); ++i) {
55 *av_strings[i].loaded_string = *reinterpret_cast<NSString**>(
56 dlsym(library_handle_, av_strings[i].symbol));
57 DCHECK(*av_strings[i].loaded_string) << dlerror();
61 NSBundle* bundle() const { return bundle_; }
62 void* library_handle() const { return library_handle_; }
64 NSString* AVCaptureDeviceWasConnectedNotification() const {
65 return AVCaptureDeviceWasConnectedNotification_;
67 NSString* AVCaptureDeviceWasDisconnectedNotification() const {
68 return AVCaptureDeviceWasDisconnectedNotification_;
70 NSString* AVMediaTypeVideo() const { return AVMediaTypeVideo_; }
71 NSString* AVMediaTypeAudio() const { return AVMediaTypeAudio_; }
72 NSString* AVMediaTypeMuxed() const { return AVMediaTypeMuxed_; }
73 NSString* AVCaptureSessionRuntimeErrorNotification() const {
74 return AVCaptureSessionRuntimeErrorNotification_;
76 NSString* AVCaptureSessionDidStopRunningNotification() const {
77 return AVCaptureSessionDidStopRunningNotification_;
79 NSString* AVCaptureSessionErrorKey() const {
80 return AVCaptureSessionErrorKey_;
82 NSString* AVCaptureSessionPreset320x240() const {
83 return AVCaptureSessionPreset320x240_;
85 NSString* AVCaptureSessionPreset640x480() const {
86 return AVCaptureSessionPreset640x480_;
88 NSString* AVCaptureSessionPreset1280x720() const {
89 return AVCaptureSessionPreset1280x720_;
91 NSString* AVVideoScalingModeKey() const { return AVVideoScalingModeKey_; }
92 NSString* AVVideoScalingModeResizeAspect() const {
93 return AVVideoScalingModeResizeAspect_;
98 void* library_handle_;
99 // The following members are replicas of the respectives in AVFoundation.
100 NSString* AVCaptureDeviceWasConnectedNotification_;
101 NSString* AVCaptureDeviceWasDisconnectedNotification_;
102 NSString* AVMediaTypeVideo_;
103 NSString* AVMediaTypeAudio_;
104 NSString* AVMediaTypeMuxed_;
105 NSString* AVCaptureSessionRuntimeErrorNotification_;
106 NSString* AVCaptureSessionDidStopRunningNotification_;
107 NSString* AVCaptureSessionErrorKey_;
108 NSString* AVCaptureSessionPreset320x240_;
109 NSString* AVCaptureSessionPreset640x480_;
110 NSString* AVCaptureSessionPreset1280x720_;
111 NSString* AVVideoScalingModeKey_;
112 NSString* AVVideoScalingModeResizeAspect_;
114 DISALLOW_COPY_AND_ASSIGN(AVFoundationInternal);
119 static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle =
120 LAZY_INSTANCE_INITIALIZER;
122 bool AVFoundationGlue::IsAVFoundationSupported() {
123 // DeviceMonitorMac will initialize this static bool from the main UI thread
124 // once, during Chrome startup so this construction is thread safe.
125 static bool is_av_foundation_supported = base::mac::IsOSLionOrLater() &&
126 (CommandLine::ForCurrentProcess()->HasSwitch(
127 switches::kEnableAVFoundation) ||
128 base::FieldTrialList::FindFullName("AVFoundationMacVideoCapture")
129 == "Enabled") && [AVFoundationBundle() load];
130 return is_av_foundation_supported;
133 NSBundle const* AVFoundationGlue::AVFoundationBundle() {
134 return g_avfoundation_handle.Get().bundle();
137 void* AVFoundationGlue::AVFoundationLibraryHandle() {
138 return g_avfoundation_handle.Get().library_handle();
141 NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() {
142 return g_avfoundation_handle.Get().AVCaptureDeviceWasConnectedNotification();
145 NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() {
147 g_avfoundation_handle.Get().AVCaptureDeviceWasDisconnectedNotification();
150 NSString* AVFoundationGlue::AVMediaTypeVideo() {
151 return g_avfoundation_handle.Get().AVMediaTypeVideo();
154 NSString* AVFoundationGlue::AVMediaTypeAudio() {
155 return g_avfoundation_handle.Get().AVMediaTypeAudio();
158 NSString* AVFoundationGlue::AVMediaTypeMuxed() {
159 return g_avfoundation_handle.Get().AVMediaTypeMuxed();
162 NSString* AVFoundationGlue::AVCaptureSessionRuntimeErrorNotification() {
163 return g_avfoundation_handle.Get().AVCaptureSessionRuntimeErrorNotification();
166 NSString* AVFoundationGlue::AVCaptureSessionDidStopRunningNotification() {
168 g_avfoundation_handle.Get().AVCaptureSessionDidStopRunningNotification();
171 NSString* AVFoundationGlue::AVCaptureSessionErrorKey() {
172 return g_avfoundation_handle.Get().AVCaptureSessionErrorKey();
175 NSString* AVFoundationGlue::AVCaptureSessionPreset320x240() {
176 return g_avfoundation_handle.Get().AVCaptureSessionPreset320x240();
179 NSString* AVFoundationGlue::AVCaptureSessionPreset640x480() {
180 return g_avfoundation_handle.Get().AVCaptureSessionPreset640x480();
183 NSString* AVFoundationGlue::AVCaptureSessionPreset1280x720() {
184 return g_avfoundation_handle.Get().AVCaptureSessionPreset1280x720();
187 NSString* AVFoundationGlue::AVVideoScalingModeKey() {
188 return g_avfoundation_handle.Get().AVVideoScalingModeKey();
191 NSString* AVFoundationGlue::AVVideoScalingModeResizeAspect() {
192 return g_avfoundation_handle.Get().AVVideoScalingModeResizeAspect();
195 Class AVFoundationGlue::AVCaptureSessionClass() {
196 return [AVFoundationBundle() classNamed:@"AVCaptureSession"];
199 Class AVFoundationGlue::AVCaptureVideoDataOutputClass() {
200 return [AVFoundationBundle() classNamed:@"AVCaptureVideoDataOutput"];
203 @implementation AVCaptureDeviceGlue
205 + (NSArray*)devices {
207 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
208 if ([avcClass respondsToSelector:@selector(devices)]) {
209 return [avcClass performSelector:@selector(devices)];
214 + (CrAVCaptureDevice*)deviceWithUniqueID:(NSString*)deviceUniqueID {
216 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
217 return [avcClass performSelector:@selector(deviceWithUniqueID:)
218 withObject:deviceUniqueID];
221 @end // @implementation AVCaptureDeviceGlue
223 @implementation AVCaptureDeviceInputGlue
225 + (CrAVCaptureDeviceInput*)deviceInputWithDevice:(CrAVCaptureDevice*)device
226 error:(NSError**)outError {
227 return [[AVFoundationGlue::AVFoundationBundle()
228 classNamed:@"AVCaptureDeviceInput"] deviceInputWithDevice:device
232 @end // @implementation AVCaptureDeviceInputGlue