AVFoundationといえばOS3.xではAVAudioPlayerとAVAudioRecorderくらいだったのですが、iOS4.0から一気にいろんなものが増えてます。僕が以前予想していたように、オーディオだけじゃなくて映像関係も扱えるように進化していますね。なんかいろいろありすぎて、かつ自分がAudioUnitでやりたいことを置き換えるようなものじゃなさそうなので基本的にはスルーしているのですが、一番手軽で役に立ちそうだったけどちょっと使い方にハマったAVPlayerを取り上げたいと思います。
AVAudioPlayerはサウンドファイルを再生するだけでしたが、AVPlayerはサウンドもムービーも関係なくこれひとつで再生できます。サウンドはファイルパス渡してプレイってするだけでなんとなく鳴ってしまうのであえて説明する必要はないと思いますが、ちょっと使い方を知らないと厄介なのがムービーの再生です。
僕がハマってしまったのは、AppleのAVPlayerLayerのリファレンスに嘘が書いてあるところです。いや嘘というよりも、OS4.0のベータが進んでいくうちに使い方が変わってしまっているのにリファレンスがそのまま残っているというところです。
以下が、AVPlayerLayerのリファレンスに書いてあるコードです。
AVPlayer *player = <#A configured AVPlayer object#>; CALayer *superlayer = <#Get a CALayer#>; AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]; [superlayer addSublayer:playerLayer];
どっかのCALayerのサブレイヤーにAVPlayerLayerをのせろと書いてあります。ですが、この通りにやっても正常にムービーは映し出されないようです。一瞬だけ映像が見えることもありますが、音だけが鳴り、映像が再生されることはありません。最初この状態になったときには、きっとGMの頃には再生できるようになるだろうとおもっていたのですが、GMになっても再生できず、じゃあ別のやり方に変わったんだろうと妄想を膨らませて解決しました。
ではどうするかというと、UIViewのサブクラスを作り、そのlayerClassメソッドをオーバーライドして、UIViewのlayerをAVPlayerLayerに差し替えます。OpenGLのEAGLViewでやっているのと同じ手法です。
さっそく、その方法でムービーを再生するサンプルを作ってみたいと思います。まずは、XcodeでWindow-based Applicationを「AVPlayerTest」とかの名前で作成して、AVFoundationをインポートしてください。
次に、UIViewのサブクラスを作成してください。名前は「AVPlayerView」としておきます。コードを以下のような感じで書き換えてください。
// // AVPlayerView.h // #import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> @interface AVPlayerView : UIView { } @end // // AVPlayerView.m // #import "AVPlayerView.h" @implementation AVPlayerView + (Class)layerClass { return [AVPlayerLayer class]; } @end
AVPlayerViewを書き換えたら、今度はAVPlayerTestAppDelegateのapplication:didFinishLaunchingWithOptions:メソッドにもろもろセットアップする処理を記述します。以下のようなコードをAppDelegateに書き足してください。
// // AVPlayerTestAppDelegate.m // #import "AVPlayerView.h" - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [UIApplication sharedApplication].statusBarHidden = YES; CGRect viewFrame = CGRectMake(0, 0, window.frame.size.height, window.frame.size.width); AVPlayerView *view = [[AVPlayerView alloc] initWithFrame:viewFrame]; view.center = CGPointMake(window.frame.size.width / 2.0, window.frame.size.height / 2.0); view.transform = CGAffineTransformMakeRotation(M_PI_2); [window addSubview:view]; [view release]; // ↓m4vのところを再生したいムービーの拡張子に変更してください NSArray *paths = [[NSBundle mainBundle] pathsForResourcesOfType:@"m4v" inDirectory:nil]; NSURL *url = [NSURL fileURLWithPath:[paths objectAtIndex:0]]; AVPlayer *player = [AVPlayer playerWithURL:url]; AVPlayerLayer *playerLayer = (AVPlayerLayer *)view.layer; playerLayer.player = player; [player play]; [window makeKeyAndVisible]; return YES; }
コードはこんなところでしょうか。あとはバンドルになにかひとつムービーを入れてアプリを起動させればムービーが再生されると思います。上のコードではムービーの拡張子をm4vとしているので、違う拡張子のムービーであれば変更してください。
あと、AVPlayerを使ってみて気になったのが、ムービーの元のサイズとかの情報が、AVPlayerを生成したときには取得できなさそうだということです。どうもAVPlayerの中での初期化処理がバックグラウンドで行われているような感じで、それが終わってAVPlayerのstatusがReadyToPlayになってはじめて情報が取得できるという感じです。それなのに、その初期化終わった通知とかが無さそうなのが、いまいちわからないところです。