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

iPhone5s以降で登場した機能として、<b>秒間120コマ</b>（2013年当時。最近は240コマ）<b>までの高速撮影</b> があり、標準カメラアプリではこれを利用した <b>スローモーション動画撮影機能</b> が可能となっています。


<img src="http://f.cl.ly/items/0O1E1W3Q3M2339222R1t/slo-mo_r1_c1.jpg">


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


##できたもの

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

- [shu223/SlowMotionVideoRecorder](https://github.com/shu223/SlowMotionVideoRecorder)


<img src="http://f.cl.ly/items/360a271y1G3Q2C2a3p2d/IMG_8907_r1_c1.jpg" width="250">


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


このアプリを使って撮ったものがこちら（寒かったので外に出てすぐ目の前にあったこれを撮影しました）。


![](http://f.cl.ly/items/1b3Q0h0k3k2m261s3R3n/samplemovie__.gif)

<p><a href="http://vimeo.com/82064431">120fps Slow-Motion video recorded using AVFoundation.</a></p>


（中盤をスローモーションにしています。）


##実装方法

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


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

###1. 初期化

````
self.captureManager = [[TTMCaptureManager alloc] initWithPreviewView:self.view];
````

###2. 録画開始

````
[self.captureManager startRecording];
````

###3. 録画停止

````
[self.captureManager stopRecording];
````


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


また今はこのサンプルの用途しか考慮されてないAPIになっているのですが、[これから動画処理とかは積極的にやっていく](http://careerhack.en-japan.com/report/detail/245)ので、随時拡張していく所存です。


##ラッパーを使わない実装

大部分はAVCapture～で動画撮影する場合の一般的な処理で、240fps実装ならではのポイントは 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](https://twitter.com/hkato193) さんにTwitterで諸々教えていただきました。ありがとうございました！


<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;margin:0px 12px 1px 0px;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4844335200/22301-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/41hs%2BPhSMqL._SL160_.jpg" alt="上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編" style="border: none;" /></a></div><div class="amazlet-info" style="line-height:120%; margin-bottom: 10px"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4844335200/22301-22/ref=nosim/" name="amazletlink" target="_blank">上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編</a><div class="amazlet-powered-date" style="font-size:80%;margin-top:5px;line-height:120%">posted with <a href="http://www.amazlet.com/" title="amazlet" target="_blank">amazlet</a> at 13.12.18</div></div><div class="amazlet-detail">加藤 寛人 西方 夏子 藤川 宏之 鈴木 晃 高丘 知央 <br />インプレスジャパン <br />売り上げランキング: 2,641<br /></div><div class="amazlet-sub-info" style="float: left;"><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/4844335200/22301-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jpで詳細を見る</a></div></div></div><div class="amazlet-footer" style="clear: left"></div></div>


##関連

- [iOS のオーディオ／サウンド処理について学べる書籍10冊＋α](http://d.hatena.ne.jp/shu223/20121125/1353877706)
- [シャッター音の鳴らないカメラアプリの実装方法](http://d.hatena.ne.jp/shu223/20121202/1354436478)
- [UIImagePickerController を使わないカメラアプリの実装方法](http://d.hatena.ne.jp/shu223/20121001/1354384097)
- [AVFoundation 使用時のカメラ起動を高速化する](http://d.hatena.ne.jp/shu223/20121203/1356509154)
- [ダウンロード可能な Audio Unit 関連のサンプルコード11個](http://d.hatena.ne.jp/shu223/20130221/1361394373)
- [PerfumeのモーションキャプチャデータをiOSアプリ内で動かしてみる](http://d.hatena.ne.jp/shu223/20131213/1386908558)


AVFoundationを使うレシピは、下記書籍にもいくつか書いたのでもしよろしければ。


<b>[『iOSアプリ開発 達人のレシピ100』という本を書きました](http://d.hatena.ne.jp/shu223/20130528/1369714635)</b>