たくさんの自由帳

Android NDK 無しで USB Video Class をやりたかった(ギブアップ)

投稿日 : | 0 日前

文字数(だいたい) : 3316

どうもこんばんわ。
最近は数年ぶりにNova Launcherってホームアプリを使ってます。Android 7くらいのときは有料版を買うくらいには気に入ってた。
列や行のサイズを変えたり(今なら標準で出来ますが、上限付き)、ウィジェットの最小幅を無視したり、上から下スワイプで通知領域を展開したり(これも今なら標準で出来ますが)、ページ丸々削除するやつとか、通知バッチとか気に入ってた。

しかしAndroid 10が来てからは、ジェスチャーナビゲーションを使うために標準ホームアプリを使ってました。
正しくはサードパーティのホームアプリでもジェスチャーナビゲーションが使えたのですが、その頃のサードパーティのホームアプリにはホーム画面に戻ったときのアニメーションが実装されて無くて、使うのをやめちゃったんですよね。(そもそもデバイスメーカーによっては標準ホームアプリ以外を使う場合はジェスチャーナビゲーションが無効になるとか)
Androidがそれ用のAPIを提供してくれないのが悪いみたいでサードパーティが対応するのは難しいとか。

が、やっぱりウィジェットを詰め込みたくて舞い戻ってきた。最小幅を無視したい。
今使ってますが、かなり再現度の高いジェスチャーのアニメーションがされるようになってました。
いつから実装されたんだろう?APIがないからサードパーティではもう無理なのかなって思い込んでたんだけど、Nova Launcher側でフルスクラッチしたのか、かなり再現度の高いアニメーションがされるように進化してた、、、

本題

ギブアップです。わかりません。
敗因はUVCどころかUSB自体がわからなかったことかなと思います。

Android NDK、というよりかはC / C++無しでUSB Video Class (UVC)をやりたかった。。。
なんとかJava / Kotlinだけで書けるようになりたかった。

中途半端な成果

だれか続きを書きたいという方がいらっしゃれば。
https://github.com/takusan23/AndroidKotlinUsbVideoClass

見るべきところはMainActivityです。
https://github.com/takusan23/AndroidKotlinUsbVideoClass/blob/master/app/src/main/java/io/github/takusan23/androidkotlinusbvideoclass/MainActivity.kt

一応繋いで、権限を付与した後ボタンを押すと、こんな感じのぐちゃぐちゃな画像ができます。
本当はぐちゃぐちゃにならないはずですが。。

Imgur

Imgur

Xperiaの外部モニターだときれいに出ている。解像度が変なのは私があれこれいじったせい。

Imgur

先駆け者さんを調べる

ぶっちゃけパクリです。すいません

USB Video Class 仕様

仕様がダウンロードできます、が!USBに関しての知識がないと多分わからない。私も分からん。

https://www.usb.org/document-library/video-class-v15-document-set

Android USB ドキュメント

ブロードキャストレシーバーが出てきて懐かしい気持ち。クラスが何個か出てきて複雑

https://developer.android.com/develop/connectivity/usb/host

UVC デバイスからフレームを取得する流れ

多分こんなことをlibuvcがやっている。C言語はわからない

  • UVCのデバイスを探す
  • 探したUVCデバイスに接続する
    • カメラ権限が必要です
  • USBデバイスを操作する権限がなければ、ダイアログを表示し付与してもらう
    • USBデバイスのインターフェースエンドポイントに触れるようになる

これ以降はUVCの仕様書を読んだり、libuvcがやっていることを真似すれば良いはず。理論上は

  • USBには通信路がいくつかある?この通信路をインターフェースとか呼んでいるそう
    • UVCの場合は、仕様書を見ると0番目VideoControl1番目VideoStreamingになってて、映像のフレームが欲しい場合は1番目のインターフェースを使う
  • 1番目のインターフェースを取る。あとエンドポイントも取る
    • エンドポイントが何なのかはよく分かっていない
  • claimInterfaceで、USBデバイスを専有する
  • コントロール転送を使って、UVCデバイスに命令を投げる
  • バルク転送を使って、フレームを取り出す
    • ここもよく分からなくて、多分受け取るバイト配列のサイズをちゃんと出さないといけない
      • 適当にでかい数字を入れていたのも敗因
    • 手に入るのはYUY2(手元のやつだとこれだけっぽい)
      • AndroidだとYuvImageクラスを使うことでJPEGにできます
  • YUY2JPEGとかにする
    • 何もわからないので、ぐちゃぐちゃな画像がここでゲットできる

どうすればいいのかな

libuvclibusbっていうライブラリを叩いてるので、Androidに持ち込むのは先人たちが言うには厳しいそう。(USBデバイスのファイルにアクセスできない)
AndroidUSBを触るにはUsbManagerってのがすでにあるため、それを使わないといけない。

なので、libuvcと同じように命令のバイト配列を組み立てたり、結果をパースしたりして、
libusbを叩いてる部分はAndroidUSB関連のクラス、UsbDeviceConnection#controlTransferUsbDeviceConnection#bulkTransferを使えば、理論上は動くような気がしている

めちゃめちゃ大変そうだけど。

おわりに

内容0で申し訳ない。まずはlibuvcを動かしてみるところからやらないとダメそう。
あとCamera2 APIUVCデバイスにアクセスできるとか書いてありますが、あれはXperiaくらいしか対応した機種がないです。
カメラ連携を謳ってるだけある!!!!