QTKit Captureを使ってみる - その3 [プログラミング - QTKit Capture]
QTKit Captureを勉強したメモの続き。簡単ですぐ動くのでついつい面白くていじってしまう。今回一番基本的なコードはどういうものかを示す。
手順
まず、初期化の流れを示すと
- QTCaptureSessionのインスタンスを作る
- Macに繋がっている具体的なデバイスを探して対応するQTCaptureDeviceを作る
- QTCaptureInputのインスタンスを作って先のデバイスを指定する
- QTCaptureInputのインスタンスをQTCaptureSessionに繋ぐ
- QTCaptureOutputのインスタンスを作ってQTCaptureSessionに繋ぐ
- QTCaptureSessionにstartRunningメソッドを呼ぶ
外部のデバイスを使うことになるので、エラーが起きる可能性(デバイスが繋がっていない、あってもフォーマットがサポートできていないなど)が多く、エラーハンドリングはまじめにやっておく必要がある。といっても本質的にソフトウェアでは回復の不可能なエラーばかりになるのでユーザにアラートを出す(ケーブルの接続を確認してやり直させるなど)、とかぐらいしかできないのでそれほど複雑ではない。めんどくさいけど。
具体的なコード
流れを示すために具体的なコードを示す。エラー処理はすべて省略する。
QTCaptureView *captureView; // 1 NSError *error; QTCaptureSession *captureSession = [[QTCaptureSession alloc] init]; // 2 QTCaptureDevice *videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];// 3 [videoDevice open:&error]; // 4 QTCaptureDeviceInput *captureVideoDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:videoDevice]; // 5 [captureSession addInput:captureVideoDeviceInput error:&error]; // 6 [captureView setCaptureSession:captureSession]; // 7 [captureSession startRunning]; // 8
(1)のcaptureViewはInterfaceBuilderで、あらかじめウィンドウに貼られているIBOutletだとする。(2)でQTCaptureSessionのインスタンスを作っている。そして(3)で入力デバイスのインスタンスを作って、(4)でデバイスをオープンしている。(5)で作った入力デバイスのインスタンスを使ってQTCaptureInputのインスタンスを作っている。(6)でcaptureSessionにcaptureVideoDeviceInputを繋いでいる。(7)でcaptureViewにcaptureSessionを指定して、(8)でcaptureSessionにstartRunningメソッドを送っている。これだけでウィンドウ内のcaptureViewでプレビューできる。さきに示した流れのままになっていることがわかる。とっても簡単。ただし、このままでは音は出ない。
主なクラス
主なクラスを流れの順に整理してみる。
QTCaptureDevice
入力デバイスのインスタンスを作るとき、Macに何が繋がっていてそのうちどれが使用可能か、というのを調べる必要がある。使用可能なデバイスが複数個ある場合は、ユーザに選ばせる必要があるかもしれない。
そのためにQTKitCaptureDeviceにはいくつかのクラスメソッドが用意されている。まず、指定したデバイスを得るメソッドとして
+ (QTCaptureDevice *)defaultInputDeviceWithMediaType:(NSString *)mediaType;がある。メディアタイプを指定してそれに一致するデバイスを返す。メディアタイプというのは
QTMediaTypeVideo QTMediaTypeSound QTMediaTypeMuxedの三つ。 最初の二つは動画と音。三つ目はそれが一緒くたになっているものでDVビデオがそれにあたる。IIDCカメラを繋いだときはQTMediaTypeVideoを指定する必要がある。またIEEE1394(iLink)でDVカメラを繋いだときはQTMediaTypeMuxedを指定しないとデバイスを得ることができない。
複数個同じメディアタイプのデバイスが繋がっているときは、そのうちの一つだけが返されるみたいだけどよくわからない。Referenceにも言及がない。
利用可能なデバイスをすべて得るには
+ (NSArray *)inputDevices; + (NSArray *)inputDevicesWithMediaType:(NSString *)mediaType;がある。一つ目はとにかく全部をアレイにして返す。二つ目は特定のメディアタイプのものをアレイにする。この中から必要なものを選んでオープンすればいよいと言うことになる。
同じメディアタイプで複数のデバイスがあった場合、UniqueIDと言う文字列を使うことができる。UniqueIDというのは良くわからないけど、繋がっているデバイスを一意に区別できる文字列らしく、これがわかっていればデバイスを特定できる。
+ (QTCaptureDevice *)deviceWithUniqueID:(NSString *)deviceUID;ユーザに選択させるにはすべての使用可能なデバイスからUniqueIDを取得して、例えばポップアップメニューに表示し、それを選択してもらうということが考えられる。
QTCaptureDeviceには
- (NSString *)uniqueIDというメソッドがあるのでinputDevicesクラスメソッドで帰ってきたアレイの要素にこのメソッドを投げればよい。他にも
- (NSString *)localizedDisplayName; - (NSString *)modelUniqueID;などがある。表示にはこういった方が向いているかも知れない。
デバイスは取得するだけでは役に立たず、オープンしなければいけない。
- (BOOL)open:(NSError **)errorPtr;成功すればYESを返す。引数のNSErrorはいつもと同じ。当然クローズも
- (void)close;クローズは絶対失敗しません、というメソッドになっている。デバイスの状態を調べる
- (BOOL)isOpen; - (BOOL)isConnected; - (BOOL)isInUseByAnotherApplication;がある。最後のはそのデバイスを他のアプリケーションがすでにオープンしていた場合YESを返す。
QTCaptureSession
QTCaptureSessionには簡単なメソッドがあるだけ。まず、入力、出力を接続するメソッド。
- (BOOL)addInput:(QTCaptureInput *)input error:(NSError **)errorPtr; - (BOOL)addOutput:(QTCaptureOutput *)output error:(NSError **)errorPtr;接続が成功するか、すでに接続されている場合YESを返す。 うしろにくっついているNSErrorは、例えばNSStringのエンコード変換を伴うファイルの読み書きのメソッドで使うのと同じやりかた。NSErrorへのポインタ(id)だけ作って渡して、呼ばれた方でエラーがおきれば実態のあるNSErrorのインスタンスが作られて帰ってくる。
入出力の接続の関連では入力全部、出力全部をアレイにして返すメソッドと、特定の入力出力を指定して取り除くメソッドがある。
あとは、
- (BOOL)isRunning; - (void)startRunning; - (void)stopRunning;という、データ取得の制御をするメソッドがある。QTCaptureSessionにはこれだけしかない(少なくともドキュメントされているメソッドは)。すごくシンプル。
残りは明日にしよ。
ありがとうございます。大変参考になりました
by みみなし (2011-06-12 22:36)
コメントありがとうございます。
お役に立てたのなら光栄です。
くるくるめまぐるしく変わるMacのAPIの中でQT Kitは比較的平穏なので3年近く前のコードでもちゃんと動作します。
逆に平穏すぎて、ひょっとしたらさらに高レベルのAPIを準備してるのではないか、と勘ぐってしまいますが...
被害妄想的になってしまってます....
by decafish (2011-06-13 22:46)
お返事ありがとうございます。
Macの開発は最近はじめたばかりなのですが、時々昔の話を聞いてぞっとします。
最近ずっとMacで仮想カメラデバイスのようなものを実装する方法を探しているのですが、なかなか見つかりません。
CamTwistのようなものをつくりたい(CamTwistだとDV Streamの映像だけ拾って音声部分を捨てているらしく、DV Streamの音声を他のアプリケーションから利用することができなくなる)のですが・・・。
そもそもOSXの内部でマルチメディアがどう扱われているのかなど、まだまだ知るべきことが多そうです。
by みみなし (2011-06-20 22:26)
なるほど、ネットワーク越しとなるとQT Kit Captureでは役不足です。MacOS X Lionに登場するはずのAV Foundationに期待しましょう。
しかし10.6やその以前であっても、ネットワーク越しのファイルアクセスはCocoaは基本的に持っているので、それをバッファリングしながらQT Kitで表示するという方法がありそうな気がします。今すぐにこうすればいい、という具体的な設計はありませんが...
by decafish (2011-06-21 21:20)