iOS/AVFoundation

AVFoundation: 静止画像やビデオ画像の撮影

デバイス(カメラやマイクなど)からデータをキャプチャ処理するには、 AVCaputeSession を用いる。

  • セッション(入力から出力へのデータの流れ)を管理する AVCaptureSession
  • 入力デバイスを表す AVCaptureDevice
  • 入力デバイスのポートを表す AVCaptureDeviceInput
  • 出力ポートを扱う AVCaptureDeviceOutput
  • セッションにおける入力と出力の接続を表す AVCaptureConnection
  • プレビュー表示を扱う AVCaptureVideoPreviewLayer

セッション AVCaptureSession

  • startRunningメソッド -- セッションの動作を開始する
  • stopRunningメソッド -- セッションの動作を止める
//[Swift]
var session: AVCaptureSession!
session =  AVCaptureSession()
...
session.startRunning()
...
session.stopRunning()
//[Objective-C]
AVCaptureSession *session = [[AVCaptureSession alloc] init];
...
[session startRunning]
...
[session stopRunning]

セッションの設定

シンボル解像度コメント
AVCaptureSessionPresetHigh最高の録画品質。デバイス依存。
AVCaptureSessionPresetMediumWiFi共有に適する。
AVCaptureSessionPresetLow低い3G共有に適する。
AVCaptureSessionPreset640x480640x480VGA
AVCaptureSessionPreset1280x7201280x720720p HD
AVCaptureSessionPresetPhoto写真写真用の最大解像度。ビデオ出力では使えない。
  • セッションのパラメータを変更する場合: 変更処理を beginConfiguration と commitConfiguration メソッドの間に記述する。
  • キャプチャ・セッションの状態監視:
    • running プロパティ: 実行中かどうか
    • interrupted プロパティ: 中断されたか
    • ランタイムエラーを監視するには AVCaptureSessionRuntimeErrorNotification を受ける。
//[Swift]
var session: AVCaptureSession!
...
if session.canSetSesstionPreset(AVCaptureSessionPresetHight) {
    session.sessionPreset = AVCaptureSessionPresetHigh
} else {
   ...
}
...
mySession.beginConfiguration()
...
mySession.commitConfiguration()
//[Objective-C]
if ([session canSetSessionPreset: AVCaptureSessionPreset1280x720]) {
  session.sessionPreset = AVCaptureSessionPreset1280x720;
}
...
[session beginConfiguration]
// 設定変更
[session commitConfiguration]

入力デバイス AVCaptureDevice

  • 使用可能なキャプチャ・デバイスを調べる: device(), devicesWithMediaType()
  • 変更の通知は AVCaptureDeviceWasConnectedNotification, AVCaptureDeviceWasDisconnectedNotification
  • 特定のメディアタイプを提供しているか調べる: hasMediaType()
  • 特定のキャプチャ・プリセットを提供しているか調べる: supportsAVCaptureSessionPreset()
//[Swift] バック・カメラ・デバイスを取り出す
var camera: AVCaptureDevice!
let devices = AVCaptureDevice.devices()
for device in devices {
  if (device.position == AVCaptureDevicePosition.Back) {
    camera = device as! AVCaptureDevice
  }
}
//[Objective-C] バック・カメラ・デバイスを取り出す
NSArray *devices = [AVCaptureDevice devices];
for (AVCaptureDevice* device in devices) {
  NSLog(@"Device name: %@", [device localizedName]);
  if ([device hasMediaType: AVMediaTypeVideo]) {
    if ([device position] == AVCaptureDevicePositionBack) {
      NSLog(@"Device position: back");
    } else {
      NSLog(@"Device position: front");
    }
  }
}
//[Objective-C]トーチ・モードを備え 640x480 のビデオ撮影が可能なデバイスを探す。結果は torchDevices 配列に入れる。
NSArray *devices = [AVCaptureDevice deviceWithMediaType: AVMediaTypeVideo];
NSMutableArray *torchDevices = [[NSMutableArray alloc] init];
for (AVCaptureDevice *device in devices) {
  if ([device hasTorch]
      && [device supportsAVCaptureSessionPreset: AVCaptureSessionPreset640x480]) {
    [touchDevices addObject:device];
  }
}

フォーカス・モード

AVCaptureFocusModeLocked焦点位置を固定する。
AVCaptureFocusModeAutoFocusシングル・スキャン・フォーカスを実行してから焦点位置を固定する。
AVCaptureFocusModeContinuousAutoFocusオート・フォーカスを継続する。
  • isFocusModeSupported(): デバイスがそのフォーカス・モードをサポートしているか調べる
  • focusMode(): フォーカス・モードを設定する
  • focusPointOfInterest(): 焦点を固定する。 座標系は(0,0)が左上、(1,1)が右下。
  • adjustingFocus: 焦点が合っているか

露出モード

AVCaptureExposureModeContinuousAutoExposure露出レベルを自動調節する
AVCaptureExposureModeLocked露出レベルを固定する
  • isExposureModeSupported(): その露出モードをサポートしているか調べる
  • exposurePointOfInterest(): 露出を設定する。座標系は(0,0)が左上、(1,1)が右下。
  • adjustingExposure: 露出が合っているか

フラッシュ・モード

AVCaptureFlashModeOffフラッシュを使わない
AVCaptureFlashModeOnフラッシュが常に点灯する
AVCaptureFlashModeAuto状況に応じてフラッシュが点灯する
  • hasFlash(): フラッシュ機能があるか調べる
  • isFlashModeSupported(): そのフラッシュ・モードをサポートしているか調べる
  • flashMode: フラッシュ・モードを設定するプロパティ。

トーチ・モード

フラッシュが低電力で点灯したままになる。

AVCaptureTorchModeOffトーチを使わない
AVCaptureTorchModeOnトーチが常に点灯する
AVCaptureTorchModeAuto状況に応じてトーチが点灯する
  • hasTorch(): トーチ機能があるか調べる
  • isTorchModeSupported(): そのトーチ・モードをサポートしているか調べる
  • torchMode: トーチ・モードを設定するプロパティ。

デバイスの設定

  • lockForConfiguration: -- デバイスのロックを取得する。設定を変更するにはロックして行う必要がある。
  • unlockForConfiguration -- デバイスのロックを解放する。
//[Objective-C] デバイスの設定を変更する
if ([device isFocusModeSupported: AVCaptureFocusModeLocked]) {
  NSError *error = nil;
  if ([device lockForConfiguration: &error]) {
    device.focusMode = AVCaptureFocusModeLocked;
    [device unlockForConfiguration];
  }
}

デバイスの切り替え

一旦デバイスを削除してから、別のデバイスを追加する。

  • removeInput: -- 入力デバイスをセッションから削除する。
  • addInput: 入力デバイスをセッションに追加する。
//[Swift]
var session: AVCaptureSession!
var frontFacingCameraDeviceInput: AVCaptureDeviceInput!
var backFacingCameraDeviceInput:  AVCaptureDeviceInput!
session.beginConfiguration()
session.removeInput(frontFacingCameraDeviceInput)
session.addInput(backFacingCameraDeviceInput)
session.commitConfiguration()
//[Objective-C]
AVCaptureSession *session = ...;
[session beginConfiguration]
[session removeInput: frontFacingCameraDeviceInput];
[session addInput: backFacingCameraDeviceInput];
[session commitConfiguration]

入力 AVCaptureDeviceInput

セッションが入力として扱うのは、入力デバイスの入力ポートである。

セッションに addInput() を用いて AVCaptureDeviceInputオブジェクトを追加する。 セッションは AVCaptureConnectionオブジェクトを用いて、AVCaptureInputPortとAVCaptureOutputの対応を定義する。

//[Swift]
var session: AVCaptureSession!
var input: AVCaptureDeviceInput!
...
if session.canAddInput(input) {
  session.addInput(input)
}
AVCaptureSession *session = [[AVCaptureSession alloc] init];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice: device error: &error]
...
if ([session canAddInput: input]) {
  [session addInput: input];
}

出力 AVCaptureOutput

セッションに出力として追加するのは AVCaptureOutput クラスのサブクラスである。

AVCaptureVideDataOutputビデオをフレーム単位で処理する場合
AVCaptureStillImageOutput静止画像をキャプチャする場合
AVCaptureMovieFileOutputムービーファイルに保存する場合
AVCaptureAudioDataOutput音声データを処理する場合

セッションの addOutput() メソッドを用いて出力を追加する。

//[Swift]
var session: AVCaptureSession!
var output: AVCaptureMovieFileOutput!
...
if session.canAddOutput(output) {
  session.addOutput(output)
}
//[Objective-C]
AVCaptureSession *session = ...
AVCaptureMovieFileOutput *output = ...
if ([session canAddOutput: output]) {
  [session addOutput: output]
}

ビデオをフレーム単位で処理する場合 AVCaptureVideDataOutput

AVCaptureVideDataOutput オブジェクトは、デリゲートを使用してビデオフレームを提供する。

  • setSampleBufferDelegate: queue: --- デリゲートを設定する。キューには serial queue を指定する(フレームが順番通りに渡されるように)。
  • デリゲートに渡されるクラスは AVCaptureVideoDataOutputSampleBufferDelegate プロトコルに適合している必要がある。
  • デリゲートの captureOutput:didOutputSampleBuffer:fromConnection: メソッドにビデオのフレームが渡される。フレームは不透過型 CMSampleBufferref のインスタンスである。
  • 出力フォーマットは videoSettings プロパティ(辞書型)に指定する。現在サポートされているキーは kCVPixelBufferPixelFormatTypeKey のみ。
    • 推奨するピクセル形式 availableVideoCVPixelFormatTypesプロパティ
    • サポートされているコーデックの値 availableVideoCodecTypesプロパティ

BGRAフォーマットは CoreGraphics でも OpenGL でも正常に動作する。(すなわちこのフォーマットを使えということか...)

//[Swift]
class ViewController: UIViewController, AVCaptureVideoDataOutputSampleBufferDelegate {
  ...
  var session: AVCaptureSession!
  ...
  var output: AVCaptureVideoDataOutput!
  output = AVCaptureVideoDataOutput()
  output.videoSettings = [kCVPixelBufferPixelFormatTypeKey : Int(kCVPixelFormatType_32BGRA)]
  output.setSampleBufferDelegate(self,queue:dispatch_get_main_queue())
  output.alwaysDiscardsLateVideoFrames = true
  if (session.canAddOutput(output)) {
    session.addOutput(myVideoOutput)
  }
//[Objective-C]
AVCaptureVideDataOutput *output = [AVCaptureVideDataOutput new];
NSDictionary *dic = @{ (NSString *) kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };
output.videoSettiong = dic;
// 出力queueがブロックされていたら捨てる (静止画を撮影中などの場合)
[output setAlwaysDiscardsLateVideoFrames: YES];
// 同期dispatch queueを作成する。サンプリング・バッファのデリゲートで使うため。
videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
[output setSampleBufferDelegate: self queue: videoDataOutputQueue];
...
AVCaptureSession *session = ...
if ([session canAddOutput: videoDataOutput]) {
  [session addOutput: videoDataOutput];
}

デリゲートのメソッドは captureOutput:didOutputSampleBuffer である。 ビデオ・フレームの方向を整えたあとで、sampleBuffer の内容を UIImage に変換する。 変換方法は以下の通り。

//[Swift]
@IBOutlet weak var imageView: UIImageView!
...
func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
  if connection.supportsVideoOrientation {  // 画像の向きを設定する
    connection.videoOrientation = AVCaptureVideoOrientation.Portrait
  }
  dispatch_async(dispatch_get_main_queue(), {    // メイン・キューの上で実行する
    let image = self.imageFromSampleBuffer(sampleBuffer)  // サンプルバッファをUIImageに変換して
    self.imageView.image = image; // Image View に表示する。
  })
}

ビデオ・フレームの向きを指定する

//[Swift]
if connection.supportsVideoOrientation {
  connection.videoOrientation = AVCaptureVideoOrientation.Portrait
  // .Portrait, .LandscapeRight, .LandscapeLeft or .PortraitUpsideDown
}

ビデオ・フレームをUIImageへ変換する

ビデオ・フレームは CMSampleBufferRef 型で渡されてくる。 これを UIImage に変換する方法は次の通り。

func imageFromSampleBuffer(sampleBuffer: CMSampleBufferRef) -> UIImage {
  let imageBuffer: CVImageBufferRef = CMSampleBufferGetImageBuffer(sampleBuffer)!
  CVPixelBufferLockBaseAddress(imageBuffer, 0)   // Lock Base Address
  let baseAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0)  // Get Original Image Information
  let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
  let width = CVPixelBufferGetWidth(imageBuffer)
  let height = CVPixelBufferGetHeight(imageBuffer)
  let colorSpace = CGColorSpaceCreateDeviceRGB()  // RGB ColorSpace
  let bitmapInfo = (CGBitmapInfo.ByteOrder32Little.rawValue | CGImageAlphaInfo.PremultipliedFirst.rawValue)
  let context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo)
  let imageRef = CGBitmapContextCreateImage(context) // Create Quarts image
  CVPixelBufferUnlockBaseAddress(imageBuffer, 0)    // Unlock Base Address
  let resultImage: UIImage = UIImage(CGImage: imageRef!)
  return resultImage
}

静止画像をキャプチャする場合 AVCaptureStillImageOutput

AVCaptureStillImageOutput 出力を利用する。

静止画像のフォーマットとコーデックの設定

  • availableImageDataCVPixelFormatTypes --- デバイスがサポートする画像フォーマットを調べる
  • availableImageDataCodecTypes --- デバイスがサポートするコーデックを調べる
//[Swift]
var session: AVCaptureSession!
...
var output: AVCaptureStillImageOutput!
output = AVCaptureStillImageOutput()
session.addOutput(output)
//[Objective-C]
AVCaptureStilImageOutput *output = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *dic = @{ AVVideoCodecKey: AVVideoCodecJPEG };
[output setOutputSettings: dic];

静止画像のキャプチャ

出力のメソッド

  • captureStillImageAsynchronouslyFromConnection:completionHandler: --- 入力デバイスを指定して静止画像をキャプチャする。 第1引数はキャプチャに使用するコネクションであり、その入力ポートがビデオをサポートしている必要がある。 第2引数は2個の引数(CMSampleBuffer, NSError)をとるクロージャである。 クロージャの中では変数やメソッドは self 経由でアクセスする。

jpeg画像をキャプチャする場合は、圧縮フォーマットを指定せずデフォルトに任せた方がよい。 そのjpeg 画像に jpegStillImageNSDataRepresentaion: メソッドを使用すると、 再圧縮せずにNSDataオブジェクトが取得できる。

//[Swift]
@IBOutlet weak var imageView; UIImageView!
...
var output : AVCaptureStillImageOutput!
...
var connection: AVCaptureConnecton!
connection = output.connectionWithMediaType(AVMediaTypeVideo)
output.captureStillImageAsynchronouslyFromConnection(connection, completionHandler: {
  (imageDataBuffer,error) -> Void in
  let jpgData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer)
  let image: UIImage! = UIImage(data:jpgData) // このimageを利用すればよい
  self.imageView.image = image
})
//[Objective-C] 入力ポートがビデオをサポートしているコネクションを探す
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *conn in stillImageOutput.connections) {
  for (AVCaptureInputPort *port in [conn inputPorts]) {
    if ([[port mediaType] isEqual: AVMediaTypeVideo]) {
      videoConnection = conn;
      break;
    }
  }
  if (videoConnection) break;
}
...
AVCaptureStillImageOutput *output = ...
[output captureStillImageAsynchronouslyFromConnection: videoConnection completionHandler:
  ^(CMSampleBufferRef buf, NSError *error) {
     CFDictionaryRef exif = CMGetAttachment(buf,kCGImagePropertyExifDictionary,NULL);
     if (exif) {
       // アタッチメントを使う
     }
     ...
   }];

ムービーファイルに保存する場合 AVCaptureMovieFileOutput

出力の解像度とビットレートは sessionPreset によって異なる。 通常のエンコードは、ビデオは H.264、オーディオは AAC である。

//[Objective-C]
AVCaptureMovieFileOutput *output = [[AVCaptureMovieFileOutput alloc] init];
output.maxRecordedDuration = ...
output.minFreeDiskSpaceLimit = ...

録画の開始

  • startRecordingToOutputfileURL:recordingDelegate:メソッド --- quickTimeムービーの録画を開始する。上書きできないので既存のファイルをURLに指定してはいけない。
  • デリゲートは AVCaptureFileOutputRecordingDelegateプロトコルに適合し、 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error: メソッドを実装する。

ファイルの書き込みの確認

  • captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:メソッドの実装では、 エラーをチェックするだけではなく、エラーのユーザ情報に含まれる AVErrorRecordingSuccessfullyFinishedKey の値も確認するべき。 エラーが発生してもファイルが正常に保存されている場合があるため。

よくあるエラーの種類

AVErrorMaximumDurationReached録画時間の上限に達した
AVErrorMaximumFileSizeReached録画がファイルの上限に達した
AVErrorDiskFullディスクの空がなくなった
AVErrorDeviceWasDisconnected録画デバイスが切断された
AVErrorSessionWasInterruptedセッションが中断された(電話がかかってきた場合など)
//[Objective-C]
- (void) captureOutput:(AVCaptureFileOutput *)captureOutput
         didFinishRecordingToOutputFileAtURL: (NSURL *)outputFileURL
	  fromConnections: (NSArray *)connections
	  error: (NSError *) error {
  BOOL success = YES;
  if ([error code] != noErr) {
    id value = [[error userInfo] objectForKey: AVErrorRecordingSuccessfullyFinishedKey];
    if (value) { success = [value boolValue]; }
  }
  // success の値で判断できる
  ...
}

ファイルへメタデータを追加する

ファイル出力のメタデータは AVMetadataItem オブジェクトの配列である。 このサブクラスの AVMutableMetadataItem を用いて独自のメタデータが作成できる。

//[Objective-C]
AVCaptureMovieFileOutput *output = ...
NSArray *oldMeatadata = output.metadata;
NSMutableArray *metadata = nil;
if (oldMetadata) {
  metadata = [oldMetadata mutableCopy];
} else {
  metadata = [[NSMutableArray alloc] init];
}
AVMutableMetadataItem *item = [[AVMutableMetadataItem alloc] init];
item.keySpace = AVMetadataKeySpaceCommon;
item.key  = AVMetadataCommonKeyLocation;
CLLocation *loc = ...
item.value = [NSString stringWithFormat:@"%+08.41f%+09.4lf/" loc.coordinate.latitude, loc.coordinate.longiture];
[metadata addObject: item];
output.metadata = metadata;

音声データを処理する場合 AVCaptureAudioDataOutput

ユーザに対する録画内容の表示

カメラで録画している内容をユーザに提示するには、ブレビューレイヤを使用する。 マイクで録音中の音声をユーザに提示するには、オーディオチャンネルを監視する。

ビデオのプレビュー

CALayer のサブクラスのAVCaptureVideoPreviewLayerオブジェクトを使用してプレビューを表示する。

AVCaptureVideoDataOutputを用いて、表示する前にビデオのピクセルにアクセスできる。

//[Swift] 背景全体にプレビューを表示する
var session: AVCaptureSession!
...
let layer = AVCaptureVideoPreviewLayer(session: session)
layer.frame = view.bounds
layer.videoGravity = AVLayerVideoGravityResizeAspectFill
view.layer.insertSublayer(layer,atIndex:0)
//[Objective-C]
AVCaptureSession *session = ...
CALayer *layer = ...
AVCaptureVidePreviewLayer *preview = [[AVCaptureVideoPreviewLayer alloc] initWithSession: session];
[layer addSublayer: preview];

プレビュー・レイヤは他のレンダリング・ツリー内の他の CALayer オブジェクトと同じように動作し、他のレイヤと同じく拡大縮小・回転・平行移動などができる。 ただひとつ異なる点が、画像の回転方向を指定するためにレイヤのorientationプロパティを設定する必要がある場合があることである。 ミラーリングが可能かどうかは supportsVideoMirroring プロパティで判断でき、 にミラーリングするときは videoMirrored プロパティを設定する (automaticallyAdjustVideoMirroringプロパティがYESならば自動的に設定される)。

videoGravityに次の値を設定できる。

AVLayerVideoGraivtyResizeAspectアスペクト比を維持したままできるだけ大きく表示する。黒いバーが残る場合あり。
AVLayerVideoGraivtyResizeAspectFillアスペクト比を維持したままできるだけ大きく表示する(はみ出た部分はトリミング)
AVLayerVideoGraivtyResize表示領域全体に表示する。アスペクト比は維持されない。

オーディオレベルの表示

オーディオ・チャネルの平均出力レベルやピーク出力レベルを監視するには、AVCaptureAudioChannelオブジェクトを使用する。 値を調べたいタイミングでポーリングする必要がある。

//[Objective-C]
AVCaptureAudioDataOutput *output = ...
NSArray *connections = output.connections;
if ([connections count] > 0) { // AVCaptureAudioDataOutput ではコネクションは1個だけしか持てない
  AVCaptureConnection *conn = [connections objectAtIndex: 0];
  NSArray channels = conn.audioChannels;
  for (AVCaptureAudioChannel) *chan in channels) {
    float avg = chan.averagePower;
    float peak = chan.peakHoldLevel;
    // 平均とピークの値を表示する
  }
}

UIImageオブジェクトとしてのビデオフレームのキャプチャ

ビデオをキャプチャし、取得したフレームをUIImageオブジェクトに変換する方法は以下の通り。

  • AVCaptureSessionオブジェクトを作成して、AV入力デバイスから出力へのデータの流れを調整する。
    //[Swift]
    var session: AVCaptureSession! = AVCaptureSession()
    session.sessionPreset = AVCaptureSessionPresetHigh
    //[Objective-C]
    AVCaptureSession *session = [[AVCaptureSession alloc] init];
    session.sessionPreset = AVCaptureSessionPresetMedium; // 解像度:中
  • 必要な入力タイプの AVCaptureDevice オブジェクトを見つける。
    //[Swift]
    var device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
    //[Objective-C]
    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
  • デバイスのAVCaptureDeviceInputオブジェクトを生成する。
    //[Swift]
    do {
      var input = try AVCaptureDeviceInput(device)
      session.addInput(input)
      ...
    } catch let error as NSError {
      ...
    }
    //[Objective-C]
    NSError *error = nil;
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice: device error:&error];
    if (!input) { /* エラー処理 */ }
    [session addInput:input]
  • AVCaptureDeviceDataOutputオブジェクトを生成して、ビデオフレームを生成する。
    キャプチャ中のビデオから非圧縮フレームにアクセスするには AVCaptureVideoDataOutputを使う。
    //[Swift]
    do {
      ...
      var output = AVCaptureVideoDataOutput()
      out.videoSettings = [kCVPixelBufferPixelFormatTypeKey : Int(kCVPixelFormatType_32BGRA)]
      ...
    } catch let error as NSError {
      ...
    }
    //[Objective-C]
    AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
    [session addOutput: output]
    output.videoSettings = @{ (NSString*) kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA) };
    output.minFrameDuration = CMTimeMake(1,15);  // 1/15 seconds
  • AVCaptureVideoDataOutputオブジェクトのデリゲートを実装して、ビデオフレームを処理する。
    //[Swift]
    output.setSampleBufferDelegate(self, queue: dispatch_get_main_queue())
    output.alwaysDiscardsLateVideoFrames = true
    //[Objective-C]
    dispach_queue_t = dispatch_queue_create("MyQueue", NULL);
    [output setSampleBufferDelegate: self queue: queue];
    dispatch_release(queue);
  • デリゲートから受け取った CMSampleBuffer を UIImage オブジェクトに変換する関数を実装する。
    デリゲートを処理するクラスにはサンプル・バッファが書き込まれたときに呼び出されるメソッド captureOutput:didOutputSampleBuffer:fromConnection: を実装する。フレームはVideDataOutputオブジェクトから CMSampleBuffer として渡されるのでUIImageに変換する。
    //[Swift]
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
      dispatch_async(dispatch_get_main_queue(), {
        let image = self.imageFromSampleBuffer(sampleBuffer)
        ...
      })
    }
    
    //[Objective-C]
    - (void) captureOutput:(AVCaptureOutput *)captureOutput
                 didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
    	      fromConnection: (AVCaptureConnection *)connection {
      UIImage *image = imageFromSampleBuffer(sampleBuffer);
      ...
    }
    このデリゲート・メソッドはqueue: に指定したキュー上で呼び出される。 ユーザインターフェイスを更新する場合は、関連するコードをメインスレッド上で呼び出す必要がある。

録画の開始と停止

録画が許可されているか調べる

//[Objective-C]
NSString *type = AVMediaTypeVideo;
[AVCaptureDevice requestAccessForMediaType: type completionHander:
  ^(BOOL granted) {
    if (granted) {
      [self setDeviceAuthorized: YES]
    } else {
      dispatch_sync(dispatch_get_main_queue(), ^{
        [[[UIAlertView alloc] initWithTitle: @"Caution"
	                             message: @"permission denied to use Camera"
				    delegate: self
		           cancelButtonTitle: @"OK"
			   otherButtonTitles: nil] show]
        [self setDeviceAuthorized: NO];
      });
    }
  }]

カメラセッションが設定されていて、ユーザがアクセスを承認している場合は、startRunning で録画を開始する。 startRunningメソッドはブロック型で多少時間がかかるため、 セッションの設定処理を同期キュー(synchronized queue)上で実行し、 メインキューがブロックされないようにする必要がある。

録画の停止には stopRunning メソッドを使う。

再生

AVPayerのインスタンスは setRate: メソッドで値を設定して再生速度を変更することができる。

AVPlayerItemオブジェクトの audioTimePitchAlgorithm プロパティには、 音声再生方法(Time Pitch Algorithm Settings)を示す定数を設定する。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-06-23 (木) 09:25:40 (400d)