AV Foundation Frameworkを利用して動画の結合を行う

( iOS )

こんにちはあのnakajijapanです。 以前、心霊動画アプリで「もう一度ご覧いただこう」 というアプリをリリースしました。 心霊動画アプリなので動画と動画を結合したり動画の上に動画を重ねて実装したりといろいろ やるわけですが今回はじめてということもあり沢山勉強になったのでここいらで自分の頭の整理 がてら情報をまためようと思います。

今回主に利用したのが「AV Foundation」です。

ざっくりいうとメディア情報(動画)を細かく制御できるようにしたフレームワークで、メタ情報の 取得、作成、編集、再エンコードができたりできます。

階層的には以下のような階層に存在して、簡単に動画とか写真の処理をしたい場合は

  • Media Player Framework(MPMoviePlayerController, MPMoviePlayerViewController)
  • UIKit(UIIMagePickerController)

を実装すれば難なく実装できちゃいます。ただ、今回は動画にいろんなエフェクトをいれたいのでもっと細かく制御 できる下の階層のフレームワークを使いました。感覚的に細かい制御できるようになるのでそのぶん面倒くさいのは いうまでもありません。

layer

https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html

では実際にどう実装していけばいいかなのですが、そのために結構なクラスを利用するのでそれぞれざっくり説明していきます。

AVAsset

iPodや写真ライブラリのメディア情報をオブジェクトとして保持することができ、これからいろんなの情報を切り出して取得すること ができます。

AVAsset*                   videoAsset;
videoAsset = [[AVURLAsset alloc] initWithURL:movieUrl options:nil];

AVAssetTrack

アセットの情報からトラックレベルで切り出した情報。(うまく翻訳できなかった・・・) 例えば、アセットから動画と音声に切り分ける。

AVAsset*                   videoAsset;
AVAssetTrack*              videoTrack;
AVAssetTrack*              audioTrack;

videoAsset = [[AVURLAsset alloc] initWithURL:movieUrl options:nil];

// アセットからトラックを取得
videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
audioTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];

AVMutableCompositionTrack

様々なメディア情報を結合したものです。このクラスで様々に編集された動画や音声を結合したり、時間の制御をしたり するクラスです。最終的にAVAssetExportSessionに渡してエキスポート処理(実際にファイルに保存する)します。

AVMutableComposition*      mixComposition;
AVMutableCompositionTrack* compositionVideoTrack;

// コンポジション作成
mixComposition = [AVMutableComposition composition];
compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableVideoComposition

AVMutableCompositionで新しいトラックを追加したときに返り値としてとれるもです。追加されたオブジェクトの参照で空のトラックって感じなんでしょうか。 ここに実際のメディア情報を入れていきます。メディアタイプで動画とか音声とか格納することができます。あと、この動画の何秒 から何秒間を何秒目に結合させるとかできたりします。

compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, timeDuration)
                               ofTrack:_videoTrack
                                atTime:kCMTimeZero
                                 error:nil];
[compositionVideoTrack setPreferredTransform:[videoTrack preferredTransform]];

AVMutableVideoCompositionLayerInstruction

アセットのトラックに対して回転、透過度、クロッピングができます。

// ここでは動画を小さくして指定の位置へ移動させてます。
CGAffineTransform scale      = CGAffineTransformMakeScale(0.30f, 0.30f);
CGAffineTransform trnsration = CGAffineTransformMakeTranslation(30, 406);

AVMutableVideoCompositionLayerInstruction* _layerInstruction;
_layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:_compositionVideoTrack];
[_layerInstruction setTransform:CGAffineTransformConcat(scale, trnsration) atTime:kCMTimeZero];

AVAssetExportSession

さまざまなアセット情報を利用して指定されたフォーマットに変換したり動画のトリミングを行います。 例えば、mov形式、720x720サイズでファイルに保存させたりで

videoComp = [AVMutableVideoComposition videoComposition];
videoComp.renderSize    = CGSizeMake(720, 720);
videoComp.frameDuration = CMTimeMake(1, 24); // framerate

// AVCompositionをベースにAVAssetExportを生成
assetExportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPreset1280x720];

// 合成用のVideoCompositionを設定
assetExportSession.videoComposition = videoComp;

// エクスポートファイルの設定
NSURL *composedMovieUrl = [NSURL fileURLWithPath:composedMoviePath];
assetExportSession.outputFileType = AVFileTypeQuickTimeMovie;
assetExportSession.outputURL = composedMovieUrl;
assetExportSession.shouldOptimizeForNetworkUse = YES;

// エキスポート処理
[assetExportSession exportAsynchronouslyWithCompletionHandler:^{
    switch ([exportSession status]) {
        case AVAssetExportSessionStatusFailed:
            NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
            break;
        case AVAssetExportSessionStatusCancelled:
            NSLog(@"Export canceled");
            break;
        default:
            break;
    }
}];

主に利用するクラスを説明しました。これらを駆使して実装すれば簡単な動画の結合ができるようになります。

だいたいの大枠は以下の図を見ると何となくわかるかもしれませんね。

layer

https://developer.apple.com/library/ios/DOCUMENTATION/AudioVideo/Conceptual/AVFoundationPG/Articles/03_Editing.html

まとめ

どうでしょう。ざっくりとですが動画を結合するのに必要なクラスの説明とどのように実装されていくのかをざっくり 説明しました。本当に最初の方は???となってしまうと思いますが実装していくうちに分かってくるようになります。 あとこれ系の情報はあんまりネット上にはないのでしっかりと学びたいもっと動画カスタマイズしたという人がいれば やはりAV Foundation Programming Guideをじっくり読むのが最短だししっかり理解できるとおもいました。あと困った ことがあったら http://stackoverflow.com/ で同じ人が困っているかもしれないのでみるといいです。

応用編としては動画をスローモーションにさせたり、ワイプのような動画を作成したり、画像をアニメーションさせたりと いろいろありますが説明していこうと思います。というか時間がたったら忘れそうな知識なのでやります。。。

Reference