Haiku OSでUSBウェブカメラに挑む(続々編) — mjpg-streamerとカーネルパニックの応酬

みなさん、こんにちは。

前々回前回と、Logicool C270nとHaiku OSのUSBスタックが織りなす沼を這いずり回ってきました。

前回の挑戦で、Webカメラ診断アプリ「BubiCam」のおかげでなんとか映像が出る(※ただしノイズまみれ)ところまではこぎ着けたわけですが、ここで新たな不満が持ち上がります。

「わざわざデスクトップでGUIアプリを起動しっぱなしにしないと映像が見られないのは地味に不便では?」

今回は、「ブラウザを開くだけでカメラ映像を見たい」という、エンジニアとしてのささやかな(そして結果的にOSを何度も巻き込む)願いから始まった物語です。


ブラウザだけで映像が見たい

Webカメラの映像をHTTP経由で配信する軽量なストリーミングサーバーといえば、定番中の定番である mjpg-streamer です。

通常、Linux環境であれば入力プラグインとして input_uvc を使い、V4L2(Video4Linux2)経由でサクッと映像を取得できます。しかし、ここは異境の地Haiku OS。V4L2なんてモダンなLinux専用APIは当然使えません。input_uvc のビルドに必要な linux/videodev2.h が存在しないため、門前払いをくらいます。

「じゃあ、Haikuの低レベルな Media KitBMediaRosterBBufferGroup など)を自前でゴリゴリ叩いて、input_uvc に代わるHaiku専用プラグインを作るしかないのか……?」という茨の道が一瞬頭をよぎりました。


方針転換 – 車輪の再発明をやめる

「AIに働いてもらえば何とかなるのでは?」

そんな悪魔のささやきが聞こえてきましたが、冷静になって踏みとどまりました。低レベルな Media Kit コードをゼロから組むのはボイラープレートも多く、いくらAIに働いてもらったところで沼が深すぎます。それでサクっと解決するなら前々回で解決してますから。

そこで閃いたのが、「すでに動いているBubiCamの実装をそのまま横取り(再利用)する」 という方針です。

BubiCamが内部で提供している WebcamKitWebcamRoster / WebcamDevice / VideoConsumer)を libwebcam.so としてそのままリンクする形を採用しました。

そして、mjpg-streamer 側には新たに input_haiku_media という薄いブリッジプラグインを作成。処理の流れは以下の通りです。

  1. プラグインからデバイスを列挙して StartCapture() を呼ぶ
  2. 届いた BBitmap をJPEGに変換する
  3. 共有バッファに流し込む

低レベルなカメラ接続処理やバッファ管理は、すでに動作実績のあるBubiCam(WebcamKit)側にすべて丸投げする設計です。

ちなみに、BBitmap からJPEGへのエンコード処理についても、わざわざ libjpegturbojpeg を直接リンクするような野暮な真似はしません。Haikuネイティブな画像変換フレームワークである Translation Kit (BTranslatorRoster) に投げ込む実装にしました。どこまでも「Haikuの標準作法に則り、車輪の再発明を避ける」スタイルです。

この設計により、とりあえず映像がストリーミングされるようになりました。
(※ただし時折、容赦のないKDL(Kernel Debugging Land:カーネルパニック)が飛んできてOSごと道連れに落ちます。BubiCamのベースドライバ自体がまだ不安定なため、こればかりは致し方ありません)


BubiCamのheadlessモードまで直ってしまった

開発の過程でBubiCamのコードを読み込んでいたところ、面白いつっこみどころを発見しました。

BubiCamには --headless というコマンドラインオプションが存在し、ヘルプ文には誇らしげに streaming server only と書かれています。しかし、コードを追ってみると実際にはストリームサーバーを一度も起動していなかったのです。

さらに、無制限実行を意図した --duration 0 オプションを指定しても、起動関数を抜けた瞬間にローカル変数(スタック上)の WebcamRoster がデストラクトされ、RAIIの働きにより道連れでキャプチャが停止してしまうという罠まで潜んでいました。

これは単なるライフタイム管理のバグなので、オブジェクトの保持をヒープ確保(new / std::unique_ptr)に直すだけであっさり解決。ヘルプ文と実装が食い違ったまま放置されていたようです。

ついでにデフォルトでループバック(127.0.0.1)に制限されていたLAN公開設定も修正し、ブラウザから http://<HaikuのIP>:8080/stream にアクセスするだけで、無事にストリーミング映像が拝めるようになりました!


結果 – LinuxでもHaikuでも綺麗にビルドが通る設計へ

今回作成した input_haiku_media 一式(互換ヘッダー、CMakeLists.txt、プラグイン本体)は、#ifdef __HAIKU__ とCMakeの CMAKE_SYSTEM_NAME 判定によって完全に隔離してあります。

そのため、既存のLinux環境でビルドしても一切悪影響を与えません。実際にLinux環境で cmake を走らせると、input_uvc が本物の linux/videodev2.h を正しく検出して有効化されることを確認しました。もちろんHaiku側でも全ターゲットのビルドがクリーンに通ります。

クロスプラットフォームなオープンソースソフトウェアへの貢献としても、非常に美しく収まったのではないかと自負しています。

今回のソースは以下で公開しています。興味があれば覗いてみてください。

BubiCam改修版:https://github.com/taoman26/BubiCam/tree/fix-headless-stream-server

Mjpg-streamer改修版:https://github.com/taoman26/mjpg-streamer


今後の展望とまとめ

画面に映し出される映像のティアリング(チラつきや乱れ)は、前回から引き続きUSB帯域不足(high-bandwidth isochronous転送の壁)に由来するもので未解決です。

しかし、「GUIアプリを立ち上げることなく、ブラウザだけでHaikuのウェブカメラ映像を見る」という当初の目的はしっかりと果たすことができました。

低レベルなMedia Kitコードを血眼になって自作するのではなく、すでにコミュニティで動いている実装を素直に再利用し、足らないブリッジだけを組む——今回学んだのは、そうしたソフトウェア設計における見極めの大切さでした。進歩のために、他人の成果はありがたく活用しましょう。


Haiku OS では不安定すぎて業務用としては適しませんが、LinuxやWindowsで「カメラやセンサーで現場の状況を把握したい。でもブラックボックスなAIは使いたくない」——そう感じている方は少なくないはずです。

ビューローみかみでは、構想段階の壁打ちからPoC・実装・現場導入まで、「使い続けられる」ものづくりを支援しています。

カメラ・マイク・各種センサーで現場を「見て・聴いて・感じて」判断する仕組みを、なぜその判定になったのか説明できる形でご提供します。

▶ AIカメラ・センシング開発サービスの詳細はこちら

気になることがあればお気軽にご相談ください。

本日も最後までお読みいただきありがとうございました。

それでは、よい(そしてたまにOSごとKDLで吹き飛ぶ)Haiku OSライフを!

カテゴリ: Tips, 開発インフラ

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール