Home | History | Annotate | Download | only in mac
      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