iPhoneのアプリを作成していてカメラから取得した動画を表示したい。
その時に方法。
必要なFramework
- AVFoundation
- CoreMedia
- CoreMovie
sessionの取得
カメラから動画を取得するにはsessionというものを作成する必要がある。Unixとかでいうstreamみたいなものだと思っている。sessionにはカメラからのInput、ユーザアプリケーションへのOutputの2つの口がある。この2つを弄って、アプリを作ることになる。まず自分の任意のクラスに以下のようにしてsessionをもたせる
@interface VideoCameraViewController (){
AVCaptureSession *_session;
}
このクラスの初期化の際に以下のようにしてsessionを作成する。
-(void)viewDidLoad{
AVCaptureDevice* device;
device = [AVCaptureDevice
defaultDeviceWithMediaType:AVMediaTypeVideo];
// デバイス入力の取得
// カメラからのデータはここから入る
AVCaptureDeviceInput* deviceInput;
deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL];
// ビデオデータ出力の作成
// アプリからはここからデータを取得する
NSMutableDictionary* settings;
AVCaptureVideoDataOutput* dataOutput;
settings = [NSMutableDictionary dictionary];
[settings setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
dataOutput = [[AVCaptureVideoDataOutput alloc] init];
dataOutput.videoSettings = settings;
[dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
// セッションの作成
_session = [[AVCaptureSession alloc] init];
[_session addInput:deviceInput];
[_session addOutput:dataOutput];
// セッションの開始
// ここから撮影が始まる感じ
[_session startRunning];
}
delegateメソッドの実装
AVCaptureSessionを使うならAVCaptureAudioDataOutputSampleBufferDelegate
プロトコルを実装する必要がある。そしてデータがsessionから送られるたびに呼び出されるのが- (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection
だ
-
captureOutput
: さっきのOutputのインスタンス -
sampleBuffer
: キャプチャされたデータが入っている -
connection
: セッションの状態
さてこのメソッドは好きなように実装して大丈夫だけれど、簡単に画面にUIImageとして表示させたい場合は以下のようになる。
// イメージバッファの取得
CVImageBufferRef buffer;
buffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// イメージバッファのロック
// これをしないbufferがカメラから送られてくるデータが書き換えられていってしまう
CVPixelBufferLockBaseAddress(buffer, 0);
// イメージバッファ情報の取得
// 画像の情報を取得する。これが得られればCoreGraphicsを使ってUIImageに変換することができる。
uint8_t* base;
size_t width, height, bytesPerRow;
base = CVPixelBufferGetBaseAddress(buffer);
width = CVPixelBufferGetWidth(buffer);
height = CVPixelBufferGetHeight(buffer);
bytesPerRow = CVPixelBufferGetBytesPerRow(buffer);
// ビットマップコンテキストの作成
CGColorSpaceRef colorSpace;
CGContextRef cgContext;
colorSpace = CGColorSpaceCreateDeviceRGB();
cgContext = CGBitmapContextCreate(
base, width, height, 8, bytesPerRow, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorSpace);
// 画像の作成
CGImageRef cgImage;
UIImage* image;
cgImage = CGBitmapContextCreateImage(cgContext);
image = [UIImage imageWithCGImage:cgImage scale:1.0f
orientation:UIImageOrientationRight];
CGImageRelease(cgImage);
CGContextRelease(cgContext);
// イメージバッファのアンロック
// カメラからまた送られてくるようにするため、忘れずに
CVPixelBufferUnlockBaseAddress(buffer, 0);
// 画像の表示
// 適当に貼っつけたUIImageViewで表示
imageView.image = image;
これでカメラを通した動画をリアルタイムにみることができる。