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 {&AVVideoScalingModeKey_, "AVVideoScalingModeKey"},
49 {&AVVideoScalingModeResizeAspectFill_,
50 "AVVideoScalingModeResizeAspectFill"},
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();
59 NSBundle* bundle() const { return bundle_; }
60 void* library_handle() const { return library_handle_; }
62 NSString* AVCaptureDeviceWasConnectedNotification() const {
63 return AVCaptureDeviceWasConnectedNotification_;
65 NSString* AVCaptureDeviceWasDisconnectedNotification() const {
66 return AVCaptureDeviceWasDisconnectedNotification_;
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_;
74 NSString* AVCaptureSessionDidStopRunningNotification() const {
75 return AVCaptureSessionDidStopRunningNotification_;
77 NSString* AVCaptureSessionErrorKey() const {
78 return AVCaptureSessionErrorKey_;
80 NSString* AVVideoScalingModeKey() const { return AVVideoScalingModeKey_; }
81 NSString* AVVideoScalingModeResizeAspectFill() const {
82 return AVVideoScalingModeResizeAspectFill_;
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_;
100 DISALLOW_COPY_AND_ASSIGN(AVFoundationInternal);
105 static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle =
106 LAZY_INSTANCE_INITIALIZER;
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 static bool is_av_foundation_supported = base::mac::IsOSLionOrLater() &&
114 ((command_line->HasSwitch(switches::kEnableAVFoundation) &&
115 !command_line->HasSwitch(switches::kForceQTKit)) ||
116 base::FieldTrialList::FindFullName("AVFoundationMacVideoCapture")
117 == "Enabled") && [AVFoundationBundle() load];
118 return is_av_foundation_supported;
121 NSBundle const* AVFoundationGlue::AVFoundationBundle() {
122 return g_avfoundation_handle.Get().bundle();
125 void* AVFoundationGlue::AVFoundationLibraryHandle() {
126 return g_avfoundation_handle.Get().library_handle();
129 NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() {
130 return g_avfoundation_handle.Get().AVCaptureDeviceWasConnectedNotification();
133 NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() {
135 g_avfoundation_handle.Get().AVCaptureDeviceWasDisconnectedNotification();
138 NSString* AVFoundationGlue::AVMediaTypeVideo() {
139 return g_avfoundation_handle.Get().AVMediaTypeVideo();
142 NSString* AVFoundationGlue::AVMediaTypeAudio() {
143 return g_avfoundation_handle.Get().AVMediaTypeAudio();
146 NSString* AVFoundationGlue::AVMediaTypeMuxed() {
147 return g_avfoundation_handle.Get().AVMediaTypeMuxed();
150 NSString* AVFoundationGlue::AVCaptureSessionRuntimeErrorNotification() {
151 return g_avfoundation_handle.Get().AVCaptureSessionRuntimeErrorNotification();
154 NSString* AVFoundationGlue::AVCaptureSessionDidStopRunningNotification() {
156 g_avfoundation_handle.Get().AVCaptureSessionDidStopRunningNotification();
159 NSString* AVFoundationGlue::AVCaptureSessionErrorKey() {
160 return g_avfoundation_handle.Get().AVCaptureSessionErrorKey();
163 NSString* AVFoundationGlue::AVVideoScalingModeKey() {
164 return g_avfoundation_handle.Get().AVVideoScalingModeKey();
167 NSString* AVFoundationGlue::AVVideoScalingModeResizeAspectFill() {
168 return g_avfoundation_handle.Get().AVVideoScalingModeResizeAspectFill();
171 Class AVFoundationGlue::AVCaptureSessionClass() {
172 return [AVFoundationBundle() classNamed:@"AVCaptureSession"];
175 Class AVFoundationGlue::AVCaptureVideoDataOutputClass() {
176 return [AVFoundationBundle() classNamed:@"AVCaptureVideoDataOutput"];
179 @implementation AVCaptureDeviceGlue
181 + (NSArray*)devices {
183 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
184 if ([avcClass respondsToSelector:@selector(devices)]) {
185 return [avcClass performSelector:@selector(devices)];
190 + (CrAVCaptureDevice*)deviceWithUniqueID:(NSString*)deviceUniqueID {
192 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
193 return [avcClass performSelector:@selector(deviceWithUniqueID:)
194 withObject:deviceUniqueID];
197 @end // @implementation AVCaptureDeviceGlue
199 @implementation AVCaptureDeviceInputGlue
201 + (CrAVCaptureDeviceInput*)deviceInputWithDevice:(CrAVCaptureDevice*)device
202 error:(NSError**)outError {
203 return [[AVFoundationGlue::AVFoundationBundle()
204 classNamed:@"AVCaptureDeviceInput"] deviceInputWithDevice:device
208 @end // @implementation AVCaptureDeviceInputGlue