6d968f3401fff34f267ee516eab17feeaa4a3bbe
[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         {&AVCaptureSessionPreset320x240_, "AVCaptureSessionPreset320x240"},
49         {&AVCaptureSessionPreset640x480_, "AVCaptureSessionPreset640x480"},
50         {&AVCaptureSessionPreset1280x720_, "AVCaptureSessionPreset1280x720"},
51         {&AVVideoScalingModeKey_, "AVVideoScalingModeKey"},
52         {&AVVideoScalingModeResizeAspect_, "AVVideoScalingModeResizeAspect"},
53     };
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();
58     }
59   }
60
61   NSBundle* bundle() const { return bundle_; }
62   void* library_handle() const { return library_handle_; }
63
64   NSString* AVCaptureDeviceWasConnectedNotification() const {
65     return AVCaptureDeviceWasConnectedNotification_;
66   }
67   NSString* AVCaptureDeviceWasDisconnectedNotification() const {
68     return AVCaptureDeviceWasDisconnectedNotification_;
69   }
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_;
75   }
76   NSString* AVCaptureSessionDidStopRunningNotification() const {
77     return AVCaptureSessionDidStopRunningNotification_;
78   }
79   NSString* AVCaptureSessionErrorKey() const {
80     return AVCaptureSessionErrorKey_;
81   }
82   NSString* AVCaptureSessionPreset320x240() const {
83     return AVCaptureSessionPreset320x240_;
84   }
85   NSString* AVCaptureSessionPreset640x480() const {
86     return AVCaptureSessionPreset640x480_;
87   }
88   NSString* AVCaptureSessionPreset1280x720() const {
89     return AVCaptureSessionPreset1280x720_;
90   }
91   NSString* AVVideoScalingModeKey() const { return AVVideoScalingModeKey_; }
92   NSString* AVVideoScalingModeResizeAspect() const {
93     return AVVideoScalingModeResizeAspect_;
94   }
95
96  private:
97   NSBundle* bundle_;
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_;
113
114   DISALLOW_COPY_AND_ASSIGN(AVFoundationInternal);
115 };
116
117 }  // namespace
118
119 static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle =
120     LAZY_INSTANCE_INITIALIZER;
121
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;
131 }
132
133 NSBundle const* AVFoundationGlue::AVFoundationBundle() {
134   return g_avfoundation_handle.Get().bundle();
135 }
136
137 void* AVFoundationGlue::AVFoundationLibraryHandle() {
138   return g_avfoundation_handle.Get().library_handle();
139 }
140
141 NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() {
142   return g_avfoundation_handle.Get().AVCaptureDeviceWasConnectedNotification();
143 }
144
145 NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() {
146   return
147       g_avfoundation_handle.Get().AVCaptureDeviceWasDisconnectedNotification();
148 }
149
150 NSString* AVFoundationGlue::AVMediaTypeVideo() {
151   return g_avfoundation_handle.Get().AVMediaTypeVideo();
152 }
153
154 NSString* AVFoundationGlue::AVMediaTypeAudio() {
155   return g_avfoundation_handle.Get().AVMediaTypeAudio();
156 }
157
158 NSString* AVFoundationGlue::AVMediaTypeMuxed() {
159   return g_avfoundation_handle.Get().AVMediaTypeMuxed();
160 }
161
162 NSString* AVFoundationGlue::AVCaptureSessionRuntimeErrorNotification() {
163   return g_avfoundation_handle.Get().AVCaptureSessionRuntimeErrorNotification();
164 }
165
166 NSString* AVFoundationGlue::AVCaptureSessionDidStopRunningNotification() {
167   return
168       g_avfoundation_handle.Get().AVCaptureSessionDidStopRunningNotification();
169 }
170
171 NSString* AVFoundationGlue::AVCaptureSessionErrorKey() {
172   return g_avfoundation_handle.Get().AVCaptureSessionErrorKey();
173 }
174
175 NSString* AVFoundationGlue::AVCaptureSessionPreset320x240() {
176   return g_avfoundation_handle.Get().AVCaptureSessionPreset320x240();
177 }
178
179 NSString* AVFoundationGlue::AVCaptureSessionPreset640x480() {
180   return g_avfoundation_handle.Get().AVCaptureSessionPreset640x480();
181 }
182
183 NSString* AVFoundationGlue::AVCaptureSessionPreset1280x720() {
184   return g_avfoundation_handle.Get().AVCaptureSessionPreset1280x720();
185 }
186
187 NSString* AVFoundationGlue::AVVideoScalingModeKey() {
188   return g_avfoundation_handle.Get().AVVideoScalingModeKey();
189 }
190
191 NSString* AVFoundationGlue::AVVideoScalingModeResizeAspect() {
192   return g_avfoundation_handle.Get().AVVideoScalingModeResizeAspect();
193 }
194
195 Class AVFoundationGlue::AVCaptureSessionClass() {
196   return [AVFoundationBundle() classNamed:@"AVCaptureSession"];
197 }
198
199 Class AVFoundationGlue::AVCaptureVideoDataOutputClass() {
200   return [AVFoundationBundle() classNamed:@"AVCaptureVideoDataOutput"];
201 }
202
203 @implementation AVCaptureDeviceGlue
204
205 + (NSArray*)devices {
206   Class avcClass =
207       [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
208   if ([avcClass respondsToSelector:@selector(devices)]) {
209     return [avcClass performSelector:@selector(devices)];
210   }
211   return nil;
212 }
213
214 + (CrAVCaptureDevice*)deviceWithUniqueID:(NSString*)deviceUniqueID {
215   Class avcClass =
216       [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"];
217   return [avcClass performSelector:@selector(deviceWithUniqueID:)
218                         withObject:deviceUniqueID];
219 }
220
221 @end  // @implementation AVCaptureDeviceGlue
222
223 @implementation AVCaptureDeviceInputGlue
224
225 + (CrAVCaptureDeviceInput*)deviceInputWithDevice:(CrAVCaptureDevice*)device
226                                            error:(NSError**)outError {
227   return [[AVFoundationGlue::AVFoundationBundle()
228       classNamed:@"AVCaptureDeviceInput"] deviceInputWithDevice:device
229                                                           error:outError];
230 }
231
232 @end  // @implementation AVCaptureDeviceInputGlue