#author("2016-06-20T13:11:12+00:00","default:nitta","nitta") [[iOS/AVFoundation]] *AVFoundation: 静止画像やビデオ画像の撮影 [#r846c8c9] デバイス(カメラやマイクなど)からデータをキャプチャ処理するには、 AVCaputeSession を用いる。 -セッション(入力から出力へのデータの流れ)を管理する AVCaptureSession -入力デバイスを表す AVCaptureDevice -入力デバイスのポートを表す AVCaptureDeviceInput -出力ポートを扱う AVCaptureDeviceOutput -セッションにおける入力と出力の接続を表す AVCaptureConnection -プレビュー表示を扱う AVCaptureVideoPreviewLayer *セッション AVCaptureSession [#me03b908] -startRunningメソッド -- セッションの動作を開始する -stopRunningメソッド -- セッションの動作を止める //[Swift] var session: AVCaptureSession! session = AVCaptureSession() ... session.startRunning() ... session.stopRunning() //[Objective-C] AVCaptureSession *session = [[AVCaptureSession alloc] init]; ... [session startRunning] ... [session stopRunning] **セッションの設定 [#h26db6c4] |シンボル|解像度|コメント| |AVCaptureSessionPresetHigh|高|最高の録画品質。デバイス依存。| |AVCaptureSessionPresetMedium|中|WiFi共有に適する。| |AVCaptureSessionPresetLow|低い|3G共有に適する。| |AVCaptureSessionPreset640x480|640x480|VGA| |AVCaptureSessionPreset1280x720|1280x720|720p 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 [#bdd9801a] -使用可能なキャプチャ・デバイスを調べる: 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]; } } **フォーカス・モード [#k9a9f37f] |AVCaptureFocusModeLocked| 焦点位置を固定する。| |AVCaptureFocusModeAutoFocus| シングル・スキャン・フォーカスを実行してから焦点位置を固定する。| |AVCaptureFocusModeContinuousAutoFocus| オート・フォーカスを継続する。| -isFocusModeSupported(): デバイスがそのフォーカス・モードをサポートしているか調べる -focusMode(): フォーカス・モードを設定する -focusPointOfInterest(): 焦点を固定する。 座標系は(0,0)が左上、(1,1)が右下。 -adjustingFocus: 焦点が合っているか **露出モード [#n6088088] |AVCaptureExposureModeContinuousAutoExposure|露出レベルを自動調節する| |AVCaptureExposureModeLocked|露出レベルを固定する| -isExposureModeSupported(): その露出モードをサポートしているか調べる -exposurePointOfInterest(): 露出を設定する。座標系は(0,0)が左上、(1,1)が右下。 -adjustingExposure: 露出が合っているか **フラッシュ・モード [#o39d6524] |AVCaptureFlashModeOff|フラッシュを使わない| |AVCaptureFlashModeOn|フラッシュが常に点灯する| |AVCaptureFlashModeAuto|状況に応じてフラッシュが点灯する| -hasFlash(): フラッシュ機能があるか調べる -isFlashModeSupported(): そのフラッシュ・モードをサポートしているか調べる -flashMode: フラッシュ・モードを設定するプロパティ。 **トーチ・モード [#ec4c0df9] フラッシュが低電力で点灯したままになる。 |AVCaptureTorchModeOff|トーチを使わない| |AVCaptureTorchModeOn|トーチが常に点灯する| |AVCaptureTorchModeAuto|状況に応じてトーチが点灯する| -hasTorch(): トーチ機能があるか調べる -isTorchModeSupported(): そのトーチ・モードをサポートしているか調べる -torchMode: トーチ・モードを設定するプロパティ。 **デバイスの設定 [#na0a4324] -lockForConfiguration: -- デバイスのロックを取得する。設定を変更するにはロックして行う必要がある。 -unlockForConfiguration -- デバイスのロックを解放する。 //[Objective-C] デバイスの設定を変更する if ([device isFocusModeSupported: AVCaptureFocusModeLocked]) { NSError *error = nil; if ([device lockForConfiguration: &error]) { device.focusMode = AVCaptureFocusModeLocked; [device unlockForConfiguration]; } } **デバイスの切り替え [#mbed1b55] 一旦デバイスを削除してから、別のデバイスを追加する。 -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 [#lc3580bd] セッションが入力として扱うのは、入力デバイスの入力ポートである。 セッションに addInput() を用いて AVCaptureDeviceInputオブジェクトを追加する。 セッションは AVCaptureConnectionオブジェクトを用いて、AVCaptureInputPortとAVCaptureOutputの対応を定義する。 //[Swift] var session: AVCaptureSession! var input: AVCaptureDeviceInput! ... if session.canAddInput(input) { session.addInput(input) } //[Objective-C] AVCaptureSession *session = [[AVCaptureSession alloc] init]; AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice: device error: &error] ... if ([session canAddInput: input]) { [session addInput: input]; } *出力 AVCaptureOutput [#v13ad437] セッションに出力として追加するのは 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 [#ud0c5163] 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 に表示する。 }) } ***ビデオ・フレームの向きを指定する [#n046a764] //[Swift] if connection.supportsVideoOrientation { connection.videoOrientation = AVCaptureVideoOrientation.Portrait // .Portrait, .LandscapeRight, .LandscapeLeft or .PortraitUpsideDown } ***ビデオ・フレームをUIImageへ変換する [#eb0754cb] ビデオ・フレームは 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 [#n508b4b9] 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 [#d4af6861] 出力の解像度とビットレートは sessionPreset によって異なる。 通常のエンコードは、ビデオは H.264、オーディオは AAC である。 //[Objective-C] AVCaptureMovieFileOutput *output = [[AVCaptureMovieFileOutput alloc] init]; output.maxRecordedDuration = ... output.minFreeDiskSpaceLimit = ... ***録画の開始 [#n520f20b] -startRecordingToOutputfileURL:recordingDelegate:メソッド --- quickTimeムービーの録画を開始する。上書きできないので既存のファイルをURLに指定してはいけない。 -デリゲートは AVCaptureFileOutputRecordingDelegateプロトコルに適合し、 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error: メソッドを実装する。 ***ファイルの書き込みの確認 [#k2eeb045] -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 の値で判断できる ... } ***ファイルへメタデータを追加する [#d1be8841] ファイル出力のメタデータは 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; **音声データを処理する場合 AVCapture&65;udio&68;ataOutput [#hd4320e2] 略 *ユーザに対する録画内容の表示 [#f4fb75d8] カメラで録画している内容をユーザに提示するには、ブレビューレイヤを使用する。 マイクで録音中の音声をユーザに提示するには、オーディオチャンネルを監視する。 **ビデオのプレビュー [#n41b750e] 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|表示領域全体に表示する。アスペクト比は維持されない。| **オーディオレベルの表示 [#dc2386d7] オーディオ・チャネルの平均出力レベルやピーク出力レベルを監視するには、AVCaptureAudioChannelオブジェクトを使用する。 値を調べたいタイミングでポーリングする必要がある。 //[Objective-C] AVCaptureAudioDataOutput *output = ... NSArray *connections = output.connections; if ([connections count] > 0) { AVCaptureConnection *conn = [connections objectAtIndex: 0]; NSArray channels = conn.audioChannels; for (AVCaptureAudioChannel) *chan in channels) { float avg = chan.averagePower; float peak = chan.peakHoldLevel; // 平均とピークの値を表示する } } *UIImageオブジェクトとしてのビデオフレームのキャプチャ [#uc67b955] ビデオをキャプチャし、取得したフレームを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: に指定したキュー上で呼び出される。 ユーザインターフェイスを更新する場合は、関連するコードをメインスレッド上で呼び出す必要がある。 **録画の開始と停止 [#i686677c] 録画が許可されているか調べる //[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 メソッドを使う。 *再生 [#se47739b] AVPayerのインスタンスは setRate: メソッドで値を設定して再生速度を変更することができる。 AVPlayerItemオブジェクトの audioTimePitchAlgorithm プロパティには、 音声再生方法(Time Pitch Algorithm Settings)を示す定数を設定する。