SSブログ

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

QTKit Captureのお勉強の続き。前回でだいだい基本的なところはおさらいした。でもAppleのガイドにある例を書き写して、動いた動いた、ではすぐ忘れてしまうので、ガイドにあることではなく、なにかちょっと違うことをやってみる。

もう少し難しいこと

QTCaptureViewは処理は軽いけど表示の品質は低い。QTCaptureViewのReferenceのOverviewには自分用のQTCaptureVideoPreviewOutputを持っていて、QTCaptureVideoPreviewOutputのOverviewにはフレーム落ちや表示品質を落とすことを許容していると書いてある。

ということで、このプレビューの表示品質を上げることを考えてみよう。ガイドのコード例の通りに書き写して動かしてみると、プレビューの表示品質は入力が圧縮のかかったDVであってもさらに低いことがわかる。

QTCaptureDecompressedVideoOutputを使って表示品質を上げる

QTCaptureDecompressedVideoOutputは、QTCaptureOutputのサブクラスで圧縮を解いた(decompressed)フレームデータを得ることができる。

どうやってデータを得るかと言うと、QTCaptureDecompressedVideoOutputにはデリゲートが設定できて新しいフレームが用意できるとデリゲートメソッド

- (void)captureOutput:(QTCaptureOutput *)captureOutput
  didOutputVideoFrame:(CVImageBufferRef)videoFrame
     withSampleBuffer:(QTSampleBuffer *)sampleBuffer
       fromConnection:(QTCaptureConnection *)connection;
をが呼ばれる。

デリゲートオブジェクトにこのメソッドを実装してこれを使って表示すればよい。このデリゲートメソッドのCVImageBufferRef型のvideoFrameにフレームデータが入っている。CVImageBufferRefはCore Video Frameworkというフレームワークがあって、その中で定義されている型で、Core VideoのCVImageBuffer.hの中に

typedef CVBufferRef CVImageBufferRef;
と書いてあって、じゃあCVBufferRefはというと同じFrameworkの中のCVBuffer.hで
typedef struct __CVBuffer *CVBufferRef;
となっている。これはCoreFoundationのオブジェクトと同じOpaque typeというやつで中身は見られない。

ではどうやってアクセスするかと言うとアクセス専用のCore Videoの関数を使うことになる。これは結構めんどう。だけど、それとはまた別にCore Image FrameworkというフレームワークにCIImageというクラスがあって

+ (CIImage *)imageWithCVImageBuffer:(CVImageBufferRef)imageBuffer;
というCVImageBufferRefからCIImageのインスタンスを作るメソッドがあって、さらにAppKitの中でCIImageに拡張があって
- (void)drawInRect:(NSRect)dstRect
          fromRect:(NSRect)srcRect
         operation:(NSCompositingOperation)op
          fraction:(CGFloat)delta;
という普通のNSImageを描画するのと同じメソッドが定義されている。

ということでQTCatpureViewではなしに、普通のNSViewのサブクラスを作って

  1. QTCaptureDecompressedVideoOutputのデリゲートメソッドからCVImageBufferRefを得る
  2. CVImageBufferRefからCIImageオブジェクトを作る
  3. NSViewのサブクラスの上でCIImageを描画する
ということをフレームごとにやればいいということだろう。ふう。ここまでわかるのにずいぶん苦労した。

ほかの手段としてずっとCore Videoを使って表示する、という手がある。これは描画をOpenGL経由で、つまりCPUではなくGPUを使って(CIImageとNSViewではなく)表示できるようになっている。Core Videoのガイドにはこんな絵

The Core Video pipeline
がある。

Core VideoではフレームデータをOpenGLのテクスチャとして表示する。こっちを使った方が処理はずっと軽く、フレーム落ちなどの問題が出にくいはずだけど、なんせ大変。Core VideoとCore ImageとOpenGLに精通していないといけない。しかもOpenGLはスレッドセーフじゃないと脅かされる。

とりあえず、CIImageを使う方法でフレーム落ちが出るようならCore Videoを勉強してみることにする。

QTKit Captureのガイドの後半には、キャプチャしているデータから一つのフレームをNSImageとして抜き出し、それをQTMovieに継ぎ足して行くことでStill Motion(Stop Motionともいう)のムービーを作る、という例がある(これはこれですごく面白い。ほんの百行ちょっとで単一機能ではあるけどそれなりに使い物になるアプリケーションができている)。このアプリケーションはCIImageを経由しているのでこれを参考にする。

つぎは実際にコードを書いてみる。


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

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

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