-
-
Notifications
You must be signed in to change notification settings - Fork 5
新しいカメラをサポートする
Tethrはオープンソースプロジェクトです。お使いのカメラをサポートさせるには、自分でコードを書いてプルリクエストを送るか、誰かに依頼するかのいずれかの方法があります。
もしあなたが開発者であれば、自分で新しいカメラをサポートするためのコードを書くのが最も早い方法です。特にこのテキストを読んでくださっている日本語話者であるあなたは、SonyやCanon、NikonやSigmaといった国産ベンダーのための実装をするにはうってつけかもしれません。なぜなら、カメラのSDKやAPIのドキュメントはまず日本語で書かれていることが多いため、英語のドキュメントよりも自然で読みやすいからです。
Tethrは以下の技術スタックによって成り立っています。
- WebUSB API: USBデバイスをブラウザから制御するためのAPI
- Picture Transfer Protocol (PTP): デジタルカメラを制御したり、画像を取得するためのプロトコル
WebUSBは、USB接続されたデバイスに対し、バイトバッファの送受信などより低レイヤーな通信機能を提供しています。しかしセキュリティの観点から、現時点では限られたブラウザでのみサポートされています。
PTPは2000年代に標準化された通信プロトコルで、そのUSB実装がTethrでは使用されています。しかしながら多くのベンダーはPTPに対して独自の拡張を行なっているため、カメラごとに追加の実装が必要となります。新しいカメラのサポートをするということは、主にそうした拡張に対応するコードを書くことを意味します。gPhoto2といったテザー撮影のためのCLIや、Capture One、Dragonframeといった撮影アプリの内部では、様々なカメラに対応するための個別的な実装が行われています。
Tethrは、USB接続されたカメラに限らず、Webカメラや将来的には無線越しのカメラにも対応するように設計されているため、このようなクラス階層を持っています。
-
Tethr: カメラオブジェクトを表現抽象クラス。全ての設定やオペレーションに
'unsupported'
(非サポート)を返す- TethrWebcam: Webカメラ
- TethrPTPUSB: USB接続されたPTPカメラ
恐らくあなたが追加したいであろうカメラは TethrPTPUSB
のサブクラスとして実装することになります。
リポジトリをforkし、以下の手順に従ってサポートコードの実装を行ってください。デバッグのためのデモ画面は、yarn dev
で起動できます。
-
TethrPTPUSBを継承したサブクラスを作成し、
src/TethrPTPUSB/Tethr{YourCamera}.ts
というファイル名で保存します。 - 新しいクラスのメゾッドを独自拡張に従ってオーバーライドします。
- 例:
open
,close
,set{ConfigName}
,get{ConfigName}Desc
-
get{ConfigName}
は、get{ConfigName}Desc
を元に既に実装されているため、オーバーライドする必要はありません。 - カメラとの通信には多くの場合、PTP規格に準じた通信機能を提供する
this.device: PTPDevice
メンバを使用します。より低レイヤーな通信のためにthis.device.usb: USBDevice
にアクセスすることもできます。
- 例:
-
getVendorSpecificPTPUSBClass
に、新しいカメラを検出し対応するサブクラスを返すコードを追加します。
多くのカメラのSDKは、WindowsやmacOSで読み込むことのできるダイナミックライブラリとして提供されているため、JavaScriptで動作させるために必要な、バイト列の構造といった情報はリバースエンジニアリングによって得る必要があります。そのためには次のような方法があります。
SDKに含まれているドキュメントやライブラリのヘッダーから、独自のOpCodeやEvenCode、DevicePropCodeを推測することが出来ます。たとえば、以下はPanasonic製LUMIXのSDKのヘッダーですが、ここからシャッタースピードのDevicePropCodeが0x02000030
であることが読み取れます。
enum Lmx_event_id : UINT32 {
// Event/Callback registration ID:ISO information
LMX_DEF_LIB_EVENT_ID_ISO = 0x02000020,
// Event/Callback registration ID:ShutterSpeed information
LMX_DEF_LIB_EVENT_ID_SHUTTER = 0x02000030,
// Event/Callback registration ID:Apertuer information
LMX_DEF_LIB_EVENT_ID_APERTURE = 0x02000040,
// Event/Callback registration ID:WhiteBalance information
LMX_DEF_LIB_EVENT_ID_WHITEBALANCE = 0x02000050,
// Event/Callback registration ID:Exposure
LMX_DEF_LIB_EVENT_ID_EXPOSURE = 0x02000060,
};
また、SDKに同梱されているサンプルアプリの中には、通信内容をログ表示するものもあります。以下はSigma fpの例ですが、ここから通信に使われているプロトコルを解析することができます。
libgphoto2からコードリーディングする
例えばptp.hにはベンダー固有のIDやコードの定数が宣言されています。リポジトリから対応したいカメラ名を検索すると、ヒントとなるような実装が見つかるかもしれません。ただし、参考にする場合はソースコードのライセンスを遵守し、必要な場合は適切に参考にしたソースコードへのURLやアトリビュートをコメントとして加えてください。
そのカメラに対応したテザー撮影アプリを操作しながら、[Wireshark]でUSB通信を覗き見する方法方法が、最もローレイヤーかつ確実にパケット解析をすることが出来ます。
起動後、USB通信の解析に必要なモジュールをインストールし、リストからカメラのUSB接続に該当するポート(XHC20
など)を選択します。次に、フィルターに _ws.col.info contains "(completed)"
を入力し、青い右矢印で反映させます。行それぞれがカメラとPCの通信を表しています。
-
URB_BULK out (completed)
: PC → カメラ -
URB_BULK in (completed)
: カメラ → PC
Hexコードのうち、PTPに関わる部分は、Leftover Capture Data(青色でハイライトされている箇所)となります。PTP仕様を参考にしつつ解析してください。
ただしApple Silicon搭載のMacは以下の手順が必要です。
- リカバリーモードで起動し、SIPを無効にする
- Wiresharkに表示されているXHCから始まるポートそれぞれに、
sudo ifconfig XHC# up
を実行する
PTP仕様はPIMA 15740:2000で、USB接続によるPTPの仕様はPDFで公開されています。全てを通読するのは骨が折れるので、大まかに要点を纏めておきます。
PTPには以下の3つの通信タイプがあります。それぞれ、PTPDeviceのメゾッド名に対応しています。
-
sendCommand: カメラに短いコマンドを送信する(例: 露出設定、シャッター)
sequenceDiagram autonumber Host->>+Camera: Command (OpCodeを送信) Camera->>+Host: Response
-
sendData: カメラにまとまったデータを送信する
sequenceDiagram autonumber Host->>+Camera: Command (OpCodeを送信) Host->>+Camera: Data (実データ) Camera->>+Host: Response
-
receiveData: カメラからまとまったデータを取得する
sequenceDiagram autonumber Host->>+Camera: Command (OpCodeを送信) Camera->>+Host: Data (実データ) Camera->>+Host: Response
一方で、カメラ側から設定値の変更などを割り込み通知する通信タイプも存在します。
sequenceDiagram
autonumber
participant Host
Camera->>+Host: Event
カメラからの割り込み通知を受け取るためには、以下のようにonEventCode
メゾッドを実装します。
// TethrPTPUSBのメゾッド内
this.devce.onEventCode(EventCode, (event: PTPEvent) => {
// イベントに応じた処理
})
常にリトルエンディアンが用いられます。 例えば、0x12345678
は 78 56 34 12
としてエンコードされます。
Field | Size | Description |
---|---|---|
Length | 4 | パケット全体のバイト数(Lengthフィールド自体を含む) |
PTPBlockType | 2 | 通信タイプ |
Code | 2 | コマンドの種類 |
Transaction ID | 4 | 通信ごとに割り振られるID |
Payload | ?? | コマンドに応じたデータ |
パケットは、Command, Data, Response, Eventのいずれかに分類されます。それぞれの種類に応じて、CodeとPayloadの内容が異なります。
- PTPBlockType.Command
- Code:
OpCode
- Payload:
Uint32Array(4)
- Code:
- PTPBlockType.Data
- Code:
OpCode
- Payload:
ArrayBuffer
- Code:
- PTPBlockType.Response
- Code:
ResCode
- Payload:
Uint32Array(4)
- Code:
- PTPBlockType.Event
- Code:
EventCode
- Payload:
Uint32Array(4)
- Code:
以下はCommandの例です。
0c 00 00 00 | Length: 0xc = 12 bytes
01 00 | PTPType: `0x0001`= Command
01 10 | OpCode: `0x1001` = GetDeviceInfo
12 00 00 00 | Transaction ID `0x12` = 18
0a 00 00 00 | Payload[0]: 10
0b 00 00 00 | Payload[1]: 11
0c 00 00 00 | Payload[2]: 12
0d 00 00 00 | Payload[3]: 13
-
OpCode
: カメラに対して送信するコマンドの種類。PTP仕様ではOperationCode -
ResCode
: カメラからの応答の種類。PTP仕様ではResponseCode -
EventCode
: カメラからの割り込み通知の種類
露出モードやシャッタースピードといった設定値ははDevicePropと呼ばれており、それぞれに固有の整数値ID DevicePropCodeが割り振られています。また、設定値の範囲やデフォルト値、単位などの情報は、DevicePropDescという構造体によって表現されています。設定値の読み書きには、OpCode.GetDevicePropDesc
、OpCode.SetDevicePropValue
といったコマンドが用いられます。
Note
ドキュメントによってはPropはProperty, DescはDescriptorと表記されることがあります。
以下は、ベンダー拡張仕様を解析する際に役立つかもしれないtipsです。
- TethrPTPUSB内のベンダー毎の実装例を参考にするのも良いかもしれません
- Sigma fpについて
- 割り込み通知がありません。その代わり、
receiveData(OpCodeSigma.GetCamStatus2)
を定期的に送信することで、カメラの状態を更新する必要があります。 - 設定値やDescriptorは、IFDと呼ばれるExifフォーマットに準拠した構造体で表現されています。
- 割り込み通知がありません。その代わり、
- カメラによってはテザー接続すると本体側の操作が無効になるものもあります。
- AF可能なレンズのフォーカス位置設定は、Sigma fpのように絶対値で指定できるものもあれば、LUMIXのように相対値でオフセットさせることしかできないカメラもあります
- ライブビュー表示はPTPの仕様には含まれていません。カメラ固有の仕様を解析する必要があります
- おおよそ、
receiveData(OpCodeVendor.LiveviewImage)
のような拡張コードが存在します。payload内のある特定のオフセットからのバイト列がそのままJPEG画像になっていることが多いです。受信したパケットにマジックナンバーのff 08
が含まれてないか探すと良いかもしれません。
- おおよそ、
- 独自仕様のPayloadの最後の数バイトがChecksumになっていることもあります。
- ブロックの作成には、DataViewを用いるほかに、PTPDataViewを使うと便利です。
開発者ではないものの、KomaなどTethrが使われているアプリで対応してほしいカメラがある場合、issueを立ててみるのも一つの方法です。
商用案件での導入を検討されている場合、作者であるBaku Hashimotoに直接依頼することも可能です。予算規模にもよりますが、私への実機の貸出が可能な場合 >$6000、おおよそ1週間内での対応を考えています。一方で、アニメーション作家や学生の方、自主制作に活かしたい方には、できる限りサポートをさせて頂きたいと考えています。しかしSDKの仕様によっては、ご希望の機能すべての実装が難しい可能性もあることをご留意ください。 気になることがあれば、mail@baku89.com までお気軽にお問い合わせください。