Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / media / video / capture / mac / avfoundation_glue.mm
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