QTKit Captureを使ってみる - その6 [プログラミング - QTKit Capture]
もう少し難しいこと
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のサブクラスを作って
- QTCaptureDecompressedVideoOutputのデリゲートメソッドからCVImageBufferRefを得る
- CVImageBufferRefからCIImageオブジェクトを作る
- NSViewのサブクラスの上でCIImageを描画する
ほかの手段としてずっとCore Videoを使って表示する、という手がある。これは描画をOpenGL経由で、つまりCPUではなくGPUを使って(CIImageとNSViewではなく)表示できるようになっている。Core Videoのガイドにはこんな絵
Core VideoではフレームデータをOpenGLのテクスチャとして表示する。こっちを使った方が処理はずっと軽く、フレーム落ちなどの問題が出にくいはずだけど、なんせ大変。Core VideoとCore ImageとOpenGLに精通していないといけない。しかもOpenGLはスレッドセーフじゃないと脅かされる。
とりあえず、CIImageを使う方法でフレーム落ちが出るようならCore Videoを勉強してみることにする。
QTKit Captureのガイドの後半には、キャプチャしているデータから一つのフレームをNSImageとして抜き出し、それをQTMovieに継ぎ足して行くことでStill Motion(Stop Motionともいう)のムービーを作る、という例がある(これはこれですごく面白い。ほんの百行ちょっとで単一機能ではあるけどそれなりに使い物になるアプリケーションができている)。このアプリケーションはCIImageを経由しているのでこれを参考にする。
つぎは実際にコードを書いてみる。
コメント 0