IT戦記

プログラミング、起業などについて書いているプログラマーのブログです😚

Mac OSX で Web カメラのリストを取る

iMovie がカメラを認識しない

でも、何をどう解決すればいいのかも分からない><

という訳で

色々調べながらカメラを検出するコードを書いてみた
もちろん、エラー処理はない。

#import <Cocoa/Cocoa.h>
#import <QuickTime/QuickTime.h>

int main(int argc, char *argv[]) {
    // メモリプール
    NSAutoreleasePool* arp = [[NSAutoreleasePool alloc] init];

    // 準備
    SeqGrabComponent sg = OpenDefaultComponent(SeqGrabComponentType, 0);
    SGInitialize(sg);
    SGChannel ch = nil;
    SGNewChannel(sg, VideoMediaType, &ch);

    // デバイスリストの取得
    SGDeviceList list = nil;
    SGGetChannelDeviceList(ch, sgDeviceListIncludeInputs, &list);

    // リストの走査
    int i;
    for (i = 0; i < sgDeviceListIncludeInputs; i++) {
        short n;
        SGGetChannelDeviceAndInputNames(ch, nil, nil, &n);

        // デバイス名の取得
        SGDeviceName name = (SGDeviceName) (*list)->entry[i];
        SGDeviceInputList inputs = name.inputs;
        char* str = (inputs == nil) ? name.name : (*inputs)->entry[n].name;

        // 表示
        NSLog([NSString
            stringWithCString:  str + 1
            length:             str[0]
        ]);
    }

    // 後始末
    SGDisposeDeviceList(sg, list);
    SGDisposeChannel(sg, ch);
    [arp release];

    return 0;
}

で実行すると

ファイル名は、 hoge.m だとして

$ gcc -lobjc hoge.m -framework Cocoa -framework QuickTime
$ ./a.out
2008-06-09 19:21:53.879 a.out[2933:10b] Opening shmem segment /com.allocinit.CTCtrl
2008-06-09 19:21:53.881 a.out[2933:10b] Opening shmem segment /com.allocinit.CTImg0
2008-06-09 19:21:53.882 a.out[2933:10b] Opening shmem segment /com.allocinit.CTImg1
2008-06-09 19:21:53.888 a.out[2933:10b] CamTwist
2008-06-09 19:21:53.889 a.out[2933:10b] DV Video
2008-06-09 19:21:53.898 a.out[2933:10b] IIDC FireWire Video
2008-06-09 19:21:53.906 a.out[2933:10b] Built-in iSight

おおお!

ちゃんと CamTwist とか Built-in iSight とか表示されていますね。

さて

SGGetChannelDeviceList という関数でデバイスの一覧を取得していると分かった!
でも、これが分かったところでどうすればいいんだ><!

dtrace?

dtrace で以下のスクリプトを試してみたけどダメだった><

pid$target::SGGetChannelDeviceList:entry 

Objective-C めも

Hello world!

#import <stdio.h>
#import <objc/Object.h>

@interface Test : Object
- (void) msg;
@end

@implementation Test
- (void) msg {
    printf("Hello world!\n");
}
@end

int main(int argc, char** argv) {
    id obj = [Test alloc];
    [obj msg];
    return 0;
}
$ gcc hello.m -lobjc
  • include ではなく、 import を使う。
    • import は一回しか include しない。include once 。ifndef とかで、やってたのがいらない
  • @interface でインタフェースを定義
  • @implementation で、メソッドの実装を書く
  • 継承した Object の alloc メソッドオブジェクトを作る。 id はポインタみたいなもの?
  • 角括弧で、メソッドにメッセージを送る
  • /usr/lib/libobjc.A.dylib が必要(-lobj)

NSString を使ってみる

#import <stdio.h>
#import <objc/Object.h>
#import <Foundation/NSString.h>

@interface Test : Object
{
    id name;
}
- (void) msg;
@end

@implementation Test
- (void) setName:(NSString*)name_ {
    [name release];
    name = name_;
}
- (void) msg {
    NSLog(@"Hello %@!\n", name);
}
@end

int main(int argc, char** argv) {
    id obj0 = [Test alloc];
    [obj0 setName:@"amachang"];

    id obj1 = [Test alloc];
    [obj1 setName:@"prochang"];

    [obj0 msg];
    [obj1 msg];

    return 0;
}
$ gcc hello.m -lobjc -framework Foundation
  • NSString は @"hoge" って感じでつくれる
  • インスタンス変数は中括弧で、 @interface の中で宣言する
  • NSString や NSLog を使うにはは Foundation フレームワークが要る(-framework Foundation)
  • id はやっぱりポインタ? id のところを NSString* にしても同じ結果だった。
  • NSString は release メッセージで参照カウンタを下げる(あげるときは retain 、alloc 時には自動で retain される)

Object より NSObject のほうがいいのかな?

  • Object で release を呼び出してみると warning が出た
  • NSObject にしたら大丈夫だった

NSAutoreleasePool と autorelease

#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>

@interface Foo : NSObject @end
@implementation Foo 
-(void) dealloc {
    NSLog(@"dealloc Foo");
    [super dealloc];
}
@end

int main(int argc, char** argv) {
    id arp = [[NSAutoreleasePool alloc] init];

    id obj0 = [[Foo alloc] init];
    [obj0 autorelease];
    id obj1 = [[Foo alloc] init];
    [obj1 autorelease];

    NSLog(@"release arp");

    [arp release];

    return 0;
}
$ gcc hello.m -lobjc -framework Foundation && ./a.out
2008-04-21 17:20:03.198 a.out[30050:10b] release arp
2008-04-21 17:20:03.200 a.out[30050:10b] dealloc Foo
2008-04-21 17:20:03.201 a.out[30050:10b] dealloc Foo
  • NSAutoreleasePool を作っておいて release ではなくて autorelease を送っておくと NSAutoreleasePool が解放されるタイミングで解放される。
  • release で参照カウンタが 0 になると dealloc が呼ばれる
  • dealloc をオーバーライドすればデストラクタとして使える
  • super にメッセージを遅れば、継承もとのメソッドを呼べる

id

オブジェクトを入れる変数の型が id でいいのは、あくまでメソッドとメッセージだから。
C++ の関数のように強く結びついているものではないので、コンパイラが型を知らなくていい。

ダックタイピング

#import <Foundation/NSObject.h>
#import <Foundation/NSAutoreleasePool.h>

@interface Foo : NSObject @end
@implementation Foo 
-(id) msg {
    NSLog(@"foo");
    return self;
}
@end

@interface Bar : NSObject @end
@implementation Bar 
-(id) msg {
    NSLog(@"bar");
    return self;
}
@end

int main(int argc, char** argv) {
    srand(time(NULL));

    [[[[rand()%2 ? [Foo class] : [Bar class]
                        alloc] init] msg] release];

    return 0;
}
  • メソッドの呼び出しはメッセージなので、ダックタイピングな書き方ができる(上の例の Foo と Bar)
  • this じゃなくて self
  • [Bar alloc] と [[Bar class] alloc] は同じ(?)。 Bar は式の中に書けないけど、 [Bar class] は式の中に書ける