• スポンサードリンク

Webカメラからh264動画を取得した〜い〜その3〜

Android Camera USB

前回の記事でUVC規格対応の機器からH.264で圧縮された映像を取得する方法が2種類あること、そのうちの1つがMJPEGペイロードに埋め込んで転送する方法であること、しかもその方法でH.264映像を取得するのが面倒であると書きました。

今回からは何がそんなに面倒なのかってあたりを書きたいと思います。面倒な部分は大きく3つあります。

UVC1.1でのH.264対応ではエクステンションユニットへアクセスがする必要

通常のWebカメラからの映像取得では次のような順序で処理します。ちょっと省略し過ぎ?(汗)。

通常のWebカメラからの映像取得手順

  1. カメラと接続(ファイルオープン)する
  2. デバイスディスクリプタを解析。フォーマットディスクリプタとフレームディスクリプタからカメラが対応している映像フォーマット、解像度、フレームインターバル(フレームレート)等を取得する
  3. 使用したい条件をカメラとネゴシエーションする
  4. カメラから映像を受け取る
  5. 必要なだけ映像を受け取ったらカメラからの映像ストリームを停止する
  6. カメラから切断(ファイルクローズ)する

一方UVC1.1機器からH.264映像を取得しようとすると、フォーマットディスクリプタにもフレームディスクリプタにも定義がないのでUVC機器がH.264に対応しているのかどうか、対応しているのであればどんな解像度やフレームレートが使用できるのかがわかりません。UVC1.1でのH.264対応の場合はエクステンションユニットディスクリプタの解析とエクステンションユニットへのアクセスによって必要な情報を取得しネゴシエーションする必要があります。

MJPEGペイロードに多重化されたH.264映像の取得手順

  1. カメラと接続(ファイルオープン)する
  2. デバイスディスクリプタを解析。フォーマットディスクリプタとフレームディスクリプタからカメラが対応している映像フォーマット、解像度、フレームインターバル(フレームレート)等を取得する
  3. デバイスディスクリプタを解析。エクステンションユニットディスクリプタが存在する場合にはそれがH.264エクステンションユニットかどうかをguidExtensionCodeを使って確認する。
  4. H.264エクステンションユニットが存在する場合には使用可能なH.24 configurationを問い合わせる
  5. H.264エクステンションユニットへネゴシエーションを行う
    これによってMJPEGペイロードにH.264ペイロードが多重化されて転送されてくるようになります
  6. 使用したい条件(MJPEG)をカメラとネゴシエーションする
  7. カメラから映像(MJPEG)を受け取る
  8. MJPEGペイロードを解析してH.264ペイロードを取り出す
    取り出したH.264ペイロードはよきにはからいたもうれ。表示するならごにょごにょしてからMediaCodecのデコーダーに放り込んでSurfaceへ描画させればOKです
  9. 必要なだけ映像を受け取ったらカメラからの映像ストリームを停止する
  10. H.264エクステンションユニットの設定をクリアする
  11. カメラから切断(ファイルクローズ)する

2倍近い手順が必要になります。面倒くさぁ(´・ω・`)

エクステンションユニットディスクリプタの解析

通常通りデバイスディスクリプタを解析するとビデオコントロールインターフェースディスクリプタの下にエクステンションユニットディスクリプタが見つかる事があります。
エクステンションディスクリプタの定義はこんな感じ(Cの構造体としての定義)

UVC1.1機器がH.264に対応しているかどうかは、この構造体のguidExtensionCodeフィールドの値をチェックすることでわかります。

実際の解像度等はH.264エクステンションユニットに対して問い合わせを行うことで取得できます。こんな感じのコードになりまする。

ただですねぇUVC1.1規格ではwConfigurationIndexの値は1〜maxとなっていて、最大値を取得すると対応しているconfigurationの個数がわかるという記述があるのですが、c930eで最大値を取得(GET_MAX)するとwConfigurationIndexがいつも0が返ってくるのです(゜゜) UVC規格にのっとれば対応するconfigurationはゼロ個…つまり対応していないってことになってしまいます。
しかも、現在値(GET_CUR)を呼ぶたびにwConfigurationIndexがインクリメントして対応している数分を順に返すと書いてあるのですが、c930eでは複数回現在値を読み込んでも(GET_CUR)全て同じ値が返ってきます。また最小値(GET_MIN)も同じ値です。

まぁUVC機器…に限らずUSB機器全般でこういった規格外のバギーなディスクリプタを返す機器は沢山、ほんっとに沢山あるのでconfigurationが1個あるとみなして後続の処理を行います。ちなみに、先ほどのコードで最大値取得に成功した際にh264->addConfigを呼んでいるのはこういったバギーデバイス対応のworkaroundです。本来は後のforループ内でaddConfigするだけでいいはずなんですけどね。

前々回の記事で書きましたがH.264対応機器は非常に少ないのとどれも高価なのでなかなか全部確認するってわけにも行かずこういった振る舞いが普通なのかどうか、あるいは違ったworkaroundが必要なのかがよくわからないのが現実です。

しかし困りました、configurationが1つしかありません。これでは解像度・ビットレート等の最大値しかわかりません。いろいろ試した結果c930eの場合はMJPEGで対応している解像度であればh.264でも大丈夫なようです。
でも、バッファーローのBSW50KM02のようにH.264ハードウェアエンコードは1280×720のみってなカメラもあるようなので、ネゴシエーションに失敗した時のフォールバック処理を考えとかないといけないですね。
自分の場合は、解像度は指定値に固定してH.264→H.264多重化モード(これがUVC1.1でのH.264対応)→MJPEG→YUY2の順にネゴシエーションを試みるようにしています。

次回はH.264エクステンションユニットのネゴシエーションです。
まだまだ続く^^/

お疲れ様でした。

« »

  • スポンサードリンク

コメント

  • lemon より:

    Hi
    Depending on your settings, get the h264 file , but with a resolution of 1280 * 720 , the actual output is 1920 * 960 ,Change camera resolution, with VLC player is correct , but has always been to get libuvc 1280 * 720 ,Meanwhile, the video bitrate is not the same,You can not pass libuvc provide api to set the resolution with bitrate frames

%d人のブロガーが「いいね」をつけました。