その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

AV Foundationで120fpsスローモーション動画撮影を実装する

iPhone5sだけのスペシャルな機能として、秒間120コマでの高速撮影 があり、標準カメラアプリではこれを利用した スローモーション動画撮影機能 が可能となっています。



これに類する機能をAVFoundationで実装できないかやってみたところ、うまくいったので、その方法を紹介します。

できたもの

サンプルアプリをGitHubにアップしております。



スクショ下部にあるように、 デフォルト / 60fps / 120fps を切り替えられるようになっています。


このアプリを使って撮ったものがこちら *1


120fps Slow-Motion video recorded using AVFoundation.


(中盤をスローモーションにしています *2。)

実装方法

わりと複雑な処理になったので、AVFoundation関連の処理を全部ラップしたクラスをつくりました。


そのラッパークラス『AVCaptureManager』を使うと、下記のように3行で実装できます。

1. 初期化
self.captureManager = [[AVCaptureManager alloc] initWithPreviewView:self.view];
2. 録画開始
[self.captureManager startRecording];
3. 録画停止
[self.captureManager stopRecording];


停止したときに撮影した動画を保存する、とかはデリゲートメソッドを使用します。そのあたりはサンプルをご参照ください。


また今はこのサンプルの用途しか考慮されてないAPIになっているのですが、これから動画処理とかは積極的にやっていくので、随時拡張していく所存です。

ラッパーを使わない実装

大部分はAVCapture〜で動画撮影する場合の一般的な処理で、120fps実装ならではのポイントは AVCaptureManager の次の部分に集約されています。

AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceFormat *selectedFormat = nil;
int32_t maxWidth = 0;
AVFrameRateRange *frameRateRange = nil;

for (AVCaptureDeviceFormat *format in [videoDevice formats]) {
    
    for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) {
        
        CMFormatDescriptionRef desc = format.formatDescription;
        CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(desc);
        int32_t width = dimensions.width;

        if (range.minFrameRate <= desiredFPS && desiredFPS <= range.maxFrameRate && width >= maxWidth) {
            
            selectedFormat = format;
            frameRateRange = range;
            maxWidth = width;
        }
    }
}

if (selectedFormat) {
    
    if ([videoDevice lockForConfiguration:nil]) {
        
        NSLog(@"selected format:%@", selectedFormat);
        videoDevice.activeFormat = selectedFormat;
        videoDevice.activeVideoMinFrameDuration = CMTimeMake(1, (int32_t)desiredFPS);
        videoDevice.activeVideoMaxFrameDuration = CMTimeMake(1, (int32_t)desiredFPS);
        [videoDevice unlockForConfiguration];
    }
}


処理の内容としては、

  • AVCaptureDevice の formats プロパティから使用可能なフォーマットのリストを取得
  • その中から所望のfpsを満たすものを探索
    • 同じfpsなら幅がより大きい方をとる
  • 見つかれば AVCaptureDevice の activeFormat プロパティにセットする

ということを行っています。

Special Thanks!!

@hkato193 さんにTwitterで諸々教えていただきました。ありがとうございました!


上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編
加藤 寛人 西方 夏子 藤川 宏之 鈴木 晃 高丘 知央
インプレスジャパン
売り上げランキング: 2,641

*1:寒かったので外に出てすぐ目の前にあったこれを撮影しました。

*2:本当に120fpsなのかというのはわかりづらいかもしれませんが、Photoshopにimportして確認もしたので間違いないです。