• スポンサードリンク

USB接続のWebカメラから動画をキャプチャした〜い(^o^)/〜その1

Android Camera NDK USB

USB接続のWebカメラからの動画を表示出来るようになったらキャプチャして保存したいと思いませんか?
と言う事で、AndroidにUSBでカメラを繋ぎた〜い(^o^)/の続編です(笑)

AndroidにUSBでカメラを繋ぎた〜い(^o^)/〜その1
AndroidにUSBでカメラを繋ぎた〜い(^o^)/〜その2
AndroidにUSBでカメラを繋ぎた〜い(^o^)/〜その3
AndroidにUSBでカメラを繋ぎた〜い(^o^)/〜番外編
と4回に渡って載せてきましたが、動画のキャプチャはどうしたらええねんと言う話を頂いたので、記事にしま〜す(^o^)/

公開しているアプリ(こちらとかこちら)に使っているのはかなり複雑になってしまったので、そこから抜粋して出来るだけシンプルでわかりやすいようにする予定(^^)v とは言ってもかなりのボリュームなので覚悟してくださいね。

始めに

Androidで動画(や音声)をキャプチャする方法をグルグル先生に聞いてみると、

  1. MediaRecorderを使う
  2. MediaCodec+MediaMuxerを使う
  3. MediaCodec+ffmpegのMuxerを使う
  4. MediaCodec+αを使う
  5. ffmpegを使う
  6. gstreamerを使う
  7. stagefrightを使う

とかとか色々出てきます。下へ行くほどマニアックと言う感じですかね?7に至っては完全に端末メーカーの仕事ですよね。

取得するフォーマットをMJPEG限定にしてデコードせずにファイルへ流しこむだけならHardwareエンコーディングは要らないんですが、H.264で保存したかったのと、YUV2からの動画キャプチャを諦めきれなかったので、何らかの形でエンコードしてから保存することになります。一方で、カメラへのアクセスがlibusb/libuvc経由・・・カーネルサイドではなくユーザーサイドのコードでの処理・・・と言うことで、処理がタイトなので、CPU負荷は極力下げたいところです。と言う事でHardwareエンコーディングは必須です。

1. MediaRecorder

1つ目のMediaRecorderは一番お手軽ですが、これは内蔵のカメラやマイクしか相手にしてくれません。
Usbで接続したWebカメラからキャプチャするのも条件を限定すれば不可能ではなさそうですがはかなり面倒そうです。rootがあるのならともかく任意の市販の端末で動くようにするのはほぼ無理そうです。ちょっとは試してみたんだけどね。

2. MediaCodec+MediaMuxer

MediaCodec+MediaMuxerを使うは、ちょっと癖は有りますがわかってしまえばそんなに難しくはありませんし、ほとんどの場合でHardwareエンコーディング出来ます。でも、残念ながらMediaMuxerはAPI>=18(Android4.3以上)でしか使えません。

3. MediaCodec+ffmpegのMuxer

MediaCodec自体はAPI>=16で使えるにも関わらずMediaMuxerがAPI>=18なのでファイルへの書き込みだけをffmpegにお願いする方法です。ffmpegのライセンスを許容可能であれば選択肢の1つになると思います。API>=16(Surface経由でフレームデータを書き込むならAPI>=18)の対応になります。

4. MediaCodec+Muxerを自前実装

こちらは、ファイルへの書き込みを自前で何とかしてAPI>=16対応にしようってことです。ちなみに、公開しているアプリではこの方法をとってます。なので、公開しているアプリはAPI>=16(Android4.1.2以上)のみ対応です。まぁ自前実装と言っても、AOSPから持ってきてゴニョゴニョするだけですけど。

5. ffmpeg

ffmpeg…これはライセンスとHardwareエンコーディングを考えなければいいんですけど…
Hardwareエンコーディングをしようとすると、色々問題が有るらしいです。ライセンスの件も含めて下調べの段階で断念しました。

6. gstreamer

gstreamer…結局試しませんでした。あんまり資料がなさそうでした。

7. stagefright

Android内部でMedia関係の処理を行っているライブラリがstagefrightです。SDK/NDKにはexportされていないので互換性の問題が発生する可能性が高いです。実際にこれはかなり頑張ってみましたが、機種・OS毎の差を吸収出来ず、数少ない手持ちの機種でもうまく動くのとクラッシュしてどうしようも無いのとが混在するので諦めました。リソースをぶっこめるお金持ちなところなら出来るのかな?ちなみに、MediaCodecも最終的に内部ではstagefrightを使っているのですが、そこは端末メーカー・Androidが吸収してくれています。有り難やぁ〜(。-人-。)

と言う事で、その4を記事にして・・・と言いたいところですが、かなりボリュームが大きいのと大人の事情で、その2について書きます(^o^)/その代わりAPI>=18ね。

ちなみに見て頂いているかどうかはわかりませんが、以前NDKからRenderScriptを使う記事を書いた時に、RenderScriptを結局使わない事にしましたって書いたのは、RenderScriptを使うと、現時点ではほとんどの機種でCPUコアを全部使って処理してしまって、使用するCPUコア数を制御出来ないので、USB/UVCの処理に影響が出てしまうからなのでした。
v4l2経由でアクセスしていればUSB/UVCの通信周りはカーネルサイドでの処理になるので、影響は少ないとは思うのですが、残念なことに現状ではAndroidでv4l2を使うには多くの機種でルートアクセスが必要になってしまいます。閑話休題。

めでたく?MediaCodec+MediaMuxerを使うことになったわけですが、上で書いた通り少し癖があって一筋縄では行きません。そこで下調べです。

MediaCodecって

何やねんって言うと、動画や音声をエンコード/デコードするためののクラスです。
デコードについては今回は関係ないので省略するとして、エンコードです。Android DevelopersでMediaCodecの項を読むと簡単に使うことが出来ま・・・せん(-_-;)ムリムリ
Android Developersだけを見てプログラム出来るのは超絶魔法使いだけでしょう(-_-;)中年魔法使い・・・間違ったっ(^_^;)中堅魔法使いの自分ではあっちこっち引っかかりまくりでした。
結局のところ、4月の終わりにはUSB接続のWebカメラからイメージを取得できるようになっていたのにもかかわらず、6月末近くまで公開できなかったのは原因の1つはここにありました。2週間ぐらいで出来るつもりだったんだけどなぁ(´・ω・`)

だからどうしたらええねん

Webをウロウロして細切れの情報を色々集めたり、自分で試した結果を簡単にまとめてみました。

  1. たぶん一番役に立つサンプルはGrafikaだと思います。ここにあります: GitHub
    ただ、ある程度わかってから参考にする分にはすごく役に立つのですが、MediaCodec初心者には色んなサンプルが入りすぎててどれをどう使っていいのかがわかりにくいです。あと、基本的にAPI>=18対応なので、それ以下ではどうすんねんというところに関しては参考になりませんでした
  2. Surfaceとしてフレームデータを渡す事も出来るし簡単だけど、API>=18のみ対応
  3. バイト配列としてフレームデータを渡すことももちろん出来る。超絶魔法使い的には推奨では無いみたいだけど
  4. 初期化・実行の順序・終了方法とかにちょっと癖があって、最悪の場合端末丸ごとクラッシュ・フリーズしたりする事もある。ガ━━(;゚Д゚)━━ン!!
    大抵はアプリがクラッシュするだけやけど、それでもガ━━(;゚Д゚)━━ン!!
  5. マルチスレッド化すべき
    エンコーディング処理が重いのが一番の理由ですが、他の理由も後で出てきます。

何が出来るかはともかく何をどうしたら良いかはまだまださっぱりですね。でもとりあえず、これでわかったつもりになってもらって(^_^;)したい事をもう少し具体化しましょう。開き直りモード全開v(^^)v
次ページからいっぱいコードが出てきますよぉ〜

« »

  • スポンサードリンク