SSブログ

QTKit Captureを使ってみる - その4 [プログラミング - QTKit Capture]

仕事が忙しくてほったらかしになってた、動画像入力用のFrameworkであるQTKit Captureを使ってみたメモの続き。集中的にやらないとすぐ忘れてしまう。

閑話休題SGIdle()

SequenceGrabberでは周期的にSGIdle()という関数を呼ばなければいけなかった。ビットレートや圧縮形式などによるみたいだけど、数フレームに1回ぐらいのペースでかなり頻繁に呼ばなければフレーム落ちした。NSTimerで無意味なほど短い周期を設定したり、別のthreadの上で呼んだりした(SequenceGrabberはThread safeではない、というのを後から知ったが、なぜかそのときは問題なかった)。

QTKit Captureではその必要はない。たぶんQTCaptureSessionがそういうことをやっていると思われるが、debuggerで見てもよくわからない。debuggerではやたらとたくさんのthreadが起きていることはわかる。簡単さの影でいったい何をやっているのか?という不安も出てしまう。

とりあえず先を進める。

QTCaptureDeviceInputとQTCaptureInput

入力データのQTCaptureSessionへの接続口を表すQTCaptureDeviceInputには

- (id)initWithDevice:(QTCaptureDevice *)device;
- (QTCaptureDevice *)device;
という入力デバイスに関するメソッドだけがある。あとはinitなんとかのかわりのクラスメソッド
+ (QTCaptureDeviceInput *)deviceInputWithDevice:(QTCaptureDevice *)device;
しかない。ようするにこれはプログラマから見るとデバイスを指定してQTCaptureSessionに繋いでしまえば、もう気にする必要がない、と言うことらしい。

この親クラスであるQTCaptureInputには一つのメソッドしかドキュメントされていない。

- (NSArray *)connections;
これはQTCaptureSessionと接続するためのQTCaptureConnectionのアレイを返すメソッド。

もちろん、class-dump(わかりやすい解説)で見るとQTCaptureSessionやQTCaptureDeviceとやり取りするためのメソッドをいっぱい持っていることがわかる。まあ、そんなものは勝手にやるのでほっといて、と言うことでしょう。

QTCaptureView

QTCaptureViewはNSViewのサブクラスで、入力動画のプレビューを表示する。多分普通の使い方として、InterfaceBuilderを使ってウィンドウにあらかじめ貼っておいて、IBOutletとするのが簡単。

QTCaptureViewには

- (void)setCaptureSession:(QTCaptureSession *)captureSession;
というメソッドがあって、QTCaptureSessionを指定すれば、勝手に接続して表示が行われる。他の出力はQTCaptureSessionにaddOutput:error:メソッドで繋ぐけど、QTCaptureViewだけは違っている。これはおそらくQTCaptureViewの方から能動的にQTCaptureSessionに働きかける必要があるからだと思われる。

他にアスペクト比を保持するかどうか、とアスペクトを保持したときに表示領域の外を何色で塗りつぶすか、なんていうメソッドと、繋がっているQTCaptureConnectionのインスタンスのアレイを返すメソッドがある。

また、QTCaptureViewにはデリゲートが設定できる。

- (void)setDelegate:(id)delegate;
- (id)delegate;
- (CIImage *)view:(QTCaptureView *)view willDisplayImage :(CIImage *)image;
最後のはデリゲートメソッドで、渡されてきたimageに手を加えて返してやればそれが表示される。表示が更新される直前のタイミングでデリゲートメソッドは呼ばれるので、好きなように変形させることができる。もちろんデリゲートメソッドの処理が重いとフレーム落ちする。

画像データのimageはCore Image frameworkのクラスであるCIImageのインスタンスになっている。Core Image frameworkにはいわゆるエフェクトのための機能が山ほどあるのでこれを使えば自由にしかも効率よく画像を変形できる。

ただし、QTCaptureViewはプレビュー用であって、処理効率が優先されているみたいに見える。必ずしも入力データの品質そのままで表示されているわけではないようである。

QTCaptureMovieFileOutputとQTCaptureFileOutput

QTCaptureMovieFileOutputQTCaptureFileOutputのサブクラスで、QuickTime movieのファイルを出力するためのクラス。ただしQTCaptureMovieFileOutputで新しくドキュメントされたメソッドはない。QTCaptureMovieFileOutputを使うときはQTCaptureFileOutputのメソッドを使え、ということらしい。ガイドを読んだだけでは位置づけが理解できないず、わかりにくい。実はQTCaptureFileOutputは抽象クラスで、そのサブクラスで実際の作業をするようになっている。サブクラスは今のところQTCaptureMovieFileOutputしかない、とReferenceにあるのでそのうち増やすつもりらしい。

QTCaptureFileOutputにはURLを指定してファイルを作るメソッドがある。
- (void)recordToOutputFileURL:(NSURL *)outputURL;
QTCaptureFileOutputはこれが呼ばれた時点からのデータをURLに出力する。それまで別のURLを持っていたら出力先が切り替えられることになる。URLとしてnilが渡されると出力をやめる。

その他に
- (QTTime)recordedDuration;
- (UInt64)recordedFileSize;
はそれまで保存したファイルの大きさと時間を得るメソッドがある。また、最大のファイルサイズや時間を指定したり調べたりするメソッドと、圧縮のオプションを指定する
- (void)setCompressionOptions:(QTCompressionOptions *)compressionOptions forConnection:(QTCaptureConnection *)connection;
がある。

QTCaptureFileOutputはデリゲートを持てるが、ファイルに
  1. 書く前
  2. 書き始め
  3. ファイルが切り替わった
  4. 書き終わる前
  5. 書き終わった
なんかのタイミングでデリゲートメソッドが呼ばれる。ファイルサイズが大きくなるのでディスクの空き容量なんかをチェックするためのものだと思われる。特徴的なデリゲートメソッドとして
- (void)captureOutput:(QTCaptureFileOutput *)captureOutput mustChangeOutputFileAtURL:(NSURL *)outputFileURL forConnections:(NSArray *)connections dueToError:(NSError *)error;
がある。これはディスクの容量が足りなくなりそうなときや、入力データストリームのフォーマットが変わって(例えば解像度(フレームサイズ)が変わった、フレームレートが変わった)単一のファイルにできなくなったときに呼ばれる。動画ファイルのサイズは大きくなりがちだし、IIDC規格ではフレームサイズが決めうちになっていないので、このデリゲートメソッドは実装しておく必要がある。

QTCaptureFileOutputのデリゲートメソッドはすべてメインスレッドで実行されると仮定するなと注意書きがある。デリゲートメソッドからユーザインターフェイスを操作するような場合(「ファイルがディスクに収まらないので切り替えてくれ」というダイアログを出す、なんてことがあり得る)には注意が必要である。

QTKit Captureを使うにはこのくらいのクラスがわかっていればいい。つぎはプレビューで音を出すこと。


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立08/29献立08/30 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。