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 "media/base/media_switches.h" 13 14 namespace { 15 16 // This class is used to retrieve AVFoundation NSBundle and library handle. It 17 // must be used as a LazyInstance so that it is initialised once and in a 18 // thread-safe way. Normally no work is done in constructors: LazyInstance is 19 // an exception. 20 class AVFoundationInternal { 21 public: 22 AVFoundationInternal() { 23 bundle_ = [NSBundle 24 bundleWithPath:@"/System/Library/Frameworks/AVFoundation.framework"]; 25 26 const char* path = [[bundle_ executablePath] fileSystemRepresentation]; 27 CHECK(path); 28 library_handle_ = dlopen(path, RTLD_LAZY | RTLD_LOCAL); 29 CHECK(library_handle_) << dlerror(); 30 } 31 NSBundle* bundle() const { return bundle_; } 32 void* library_handle() const { return library_handle_; } 33 34 private: 35 NSBundle* bundle_; 36 void* library_handle_; 37 38 DISALLOW_COPY_AND_ASSIGN(AVFoundationInternal); 39 }; 40 41 } // namespace 42 43 static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle = 44 LAZY_INSTANCE_INITIALIZER; 45 46 namespace media { 47 48 // TODO(mcasas):http://crbug.com/323536 cache the string pointers. 49 static NSString* ReadNSStringPtr(const char* symbol) { 50 NSString** string_pointer = reinterpret_cast<NSString**>( 51 dlsym(AVFoundationGlue::AVFoundationLibraryHandle(), symbol)); 52 DCHECK(string_pointer) << dlerror(); 53 return *string_pointer; 54 } 55 56 } // namespace media 57 58 bool AVFoundationGlue::IsAVFoundationSupported() { 59 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 60 return cmd_line->HasSwitch(switches::kEnableAVFoundation) && 61 base::mac::IsOSLionOrLater() && [AVFoundationBundle() load]; 62 } 63 64 NSBundle const* AVFoundationGlue::AVFoundationBundle() { 65 return g_avfoundation_handle.Get().bundle(); 66 } 67 68 void* AVFoundationGlue::AVFoundationLibraryHandle() { 69 return g_avfoundation_handle.Get().library_handle(); 70 } 71 72 NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() { 73 return media::ReadNSStringPtr("AVCaptureDeviceWasConnectedNotification"); 74 } 75 76 NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() { 77 return media::ReadNSStringPtr("AVCaptureDeviceWasDisconnectedNotification"); 78 } 79 80 NSString* AVFoundationGlue::AVMediaTypeVideo() { 81 return media::ReadNSStringPtr("AVMediaTypeVideo"); 82 } 83 84 NSString* AVFoundationGlue::AVMediaTypeAudio() { 85 return media::ReadNSStringPtr("AVMediaTypeAudio"); 86 } 87 88 NSString* AVFoundationGlue::AVMediaTypeMuxed() { 89 return media::ReadNSStringPtr("AVMediaTypeMuxed"); 90 } 91 92 NSString* AVFoundationGlue::AVCaptureSessionRuntimeErrorNotification() { 93 return media::ReadNSStringPtr("AVCaptureSessionRuntimeErrorNotification"); 94 } 95 96 NSString* AVFoundationGlue::AVCaptureSessionDidStopRunningNotification() { 97 return media::ReadNSStringPtr("AVCaptureSessionDidStopRunningNotification"); 98 } 99 100 NSString* AVFoundationGlue::AVCaptureSessionErrorKey() { 101 return media::ReadNSStringPtr("AVCaptureSessionErrorKey"); 102 } 103 104 NSString* AVFoundationGlue::AVCaptureSessionPreset320x240() { 105 return media::ReadNSStringPtr("AVCaptureSessionPreset320x240"); 106 } 107 108 NSString* AVFoundationGlue::AVCaptureSessionPreset640x480() { 109 return media::ReadNSStringPtr("AVCaptureSessionPreset640x480"); 110 } 111 112 NSString* AVFoundationGlue::AVCaptureSessionPreset1280x720() { 113 return media::ReadNSStringPtr("AVCaptureSessionPreset1280x720"); 114 } 115 116 NSString* AVFoundationGlue::AVVideoScalingModeKey() { 117 return media::ReadNSStringPtr("AVVideoScalingModeKey"); 118 } 119 120 NSString* AVFoundationGlue::AVVideoScalingModeResizeAspect() { 121 return media::ReadNSStringPtr("AVVideoScalingModeResizeAspect"); 122 } 123 124 Class AVFoundationGlue::AVCaptureSessionClass() { 125 return [AVFoundationBundle() classNamed:@"AVCaptureSession"]; 126 } 127 128 Class AVFoundationGlue::AVCaptureVideoDataOutputClass() { 129 return [AVFoundationBundle() classNamed:@"AVCaptureVideoDataOutput"]; 130 } 131 132 @implementation AVCaptureDeviceGlue 133 134 + (NSArray*)devices { 135 Class avcClass = 136 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"]; 137 if ([avcClass respondsToSelector:@selector(devices)]) { 138 return [avcClass performSelector:@selector(devices)]; 139 } 140 return nil; 141 } 142 143 + (CrAVCaptureDevice*)deviceWithUniqueID:(NSString*)deviceUniqueID { 144 Class avcClass = 145 [AVFoundationGlue::AVFoundationBundle() classNamed:@"AVCaptureDevice"]; 146 return [avcClass performSelector:@selector(deviceWithUniqueID:) 147 withObject:deviceUniqueID]; 148 } 149 150 @end // @implementation AVCaptureDeviceGlue 151 152 @implementation AVCaptureDeviceInputGlue 153 154 + (CrAVCaptureDeviceInput*)deviceInputWithDevice:(CrAVCaptureDevice*)device 155 error:(NSError**)outError { 156 return [[AVFoundationGlue::AVFoundationBundle() 157 classNamed:@"AVCaptureDeviceInput"] deviceInputWithDevice:device 158 error:outError]; 159 } 160 161 @end // @implementation AVCaptureDeviceInputGlue 162