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 14namespace { 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. 20class 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 43static base::LazyInstance<AVFoundationInternal> g_avfoundation_handle = 44 LAZY_INSTANCE_INITIALIZER; 45 46namespace media { 47 48// TODO(mcasas):http://crbug.com/323536 cache the string pointers. 49static 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 58bool AVFoundationGlue::IsAVFoundationSupported() { 59 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 60 return cmd_line->HasSwitch(switches::kEnableAVFoundation) && 61 base::mac::IsOSLionOrLater() && [AVFoundationBundle() load]; 62} 63 64NSBundle const* AVFoundationGlue::AVFoundationBundle() { 65 return g_avfoundation_handle.Get().bundle(); 66} 67 68void* AVFoundationGlue::AVFoundationLibraryHandle() { 69 return g_avfoundation_handle.Get().library_handle(); 70} 71 72NSString* AVFoundationGlue::AVCaptureDeviceWasConnectedNotification() { 73 return media::ReadNSStringPtr("AVCaptureDeviceWasConnectedNotification"); 74} 75 76NSString* AVFoundationGlue::AVCaptureDeviceWasDisconnectedNotification() { 77 return media::ReadNSStringPtr("AVCaptureDeviceWasDisconnectedNotification"); 78} 79 80NSString* AVFoundationGlue::AVMediaTypeVideo() { 81 return media::ReadNSStringPtr("AVMediaTypeVideo"); 82} 83 84NSString* AVFoundationGlue::AVMediaTypeAudio() { 85 return media::ReadNSStringPtr("AVMediaTypeAudio"); 86} 87 88NSString* AVFoundationGlue::AVMediaTypeMuxed() { 89 return media::ReadNSStringPtr("AVMediaTypeMuxed"); 90} 91 92NSString* AVFoundationGlue::AVCaptureSessionRuntimeErrorNotification() { 93 return media::ReadNSStringPtr("AVCaptureSessionRuntimeErrorNotification"); 94} 95 96NSString* AVFoundationGlue::AVCaptureSessionDidStopRunningNotification() { 97 return media::ReadNSStringPtr("AVCaptureSessionDidStopRunningNotification"); 98} 99 100NSString* AVFoundationGlue::AVCaptureSessionErrorKey() { 101 return media::ReadNSStringPtr("AVCaptureSessionErrorKey"); 102} 103 104NSString* AVFoundationGlue::AVCaptureSessionPreset320x240() { 105 return media::ReadNSStringPtr("AVCaptureSessionPreset320x240"); 106} 107 108NSString* AVFoundationGlue::AVCaptureSessionPreset640x480() { 109 return media::ReadNSStringPtr("AVCaptureSessionPreset640x480"); 110} 111 112NSString* AVFoundationGlue::AVCaptureSessionPreset1280x720() { 113 return media::ReadNSStringPtr("AVCaptureSessionPreset1280x720"); 114} 115 116NSString* AVFoundationGlue::AVVideoScalingModeKey() { 117 return media::ReadNSStringPtr("AVVideoScalingModeKey"); 118} 119 120NSString* AVFoundationGlue::AVVideoScalingModeResizeAspect() { 121 return media::ReadNSStringPtr("AVVideoScalingModeResizeAspect"); 122} 123 124Class AVFoundationGlue::AVCaptureSessionClass() { 125 return [AVFoundationBundle() classNamed:@"AVCaptureSession"]; 126} 127 128Class 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