前回、Raspberry Pi Zero 2WとAI Camera(Sony IMX500搭載)を使ったAIカメラシステムのセットアップ方法を紹介しました。Raspberry Pi Zero 2Wは超小型・超低消費電力(約2W)で、内蔵GPUのH.264エンコード機能がエッジ環境での動画処理に優れています。IMX500カメラにはAI推論エンジンが内蔵されており、オンボードで物体検出を実行可能です。
前回記事:その2
https://techietechnology.co.jp/2025/03/11/make-aicamera-02/
次は簡単なアプリケーションを使って動作を試してゆきましょう。その前にRaspberry Pi Zero 2Wのハードウェアエンコードがどれほどのものか気になります。
限られたリソース環境下では、映像処理のパフォーマンス効率が実用性を決定づけます。特にH.264エンコーディングのようなCPU負荷の高い処理では、ハードウェアアクセラレーションの効果が顕著です。VideoCore GPUに統合されたハードウェアエンコーダは理論上1080p30fpsの処理が可能ですが、実際のシステム全体のパフォーマンスを検証する必要があります。
Raspberry Piプラットフォームにおけるカメラインターフェースは複数の実装が並存しており混乱が生じやすいです。カメラデータの取得・制御方法としてV4L2という標準的なLinuxカメラインターフェース、raspivid/raspistillというレガシーなコマンドラインツール、そして現在のlibcameraがあります。
現在はRaspberry Pi OS Bullseye以降の標準としてlibcameraを使うのが標準です。v4l2も試したのですが上手くゆきませんでした。
https://www.raspberrypi.com/documentation/computers/camera_software.html
https://github.com/libcamera-org/libcamera
https://www.raspberrypi.com/news/raspberry-pi-os-debian-bullseye/
Raspberry Pi Zero 2 Wには、Broadcom製BCM2710A1が搭載されています。このSoCはVideoCore GPUを内蔵しており、H.264ハードウェアエンコード機能を実装しています。このハードウェアエンコーダにより、CPU負荷を最小限に抑えながら効率的な動画圧縮処理が可能になりました。
Raspberry Pi OS Bullseye以降では、カメラシステムアーキテクチャに重要な変更が導入され、従来のraspividコマンドからlibcameraへの移行しました。同時にMedia Controllerシステムの導入によるデバイストポロジー管理の変更やGPUハードウェアアクセラレーションのサポートが実装されました。シンプルになり使いやすくなりました。
この新しい導入により、従来のV4L2 APIは正常に動作しなくなりました。V4L2 APIを通じてハードウェアエンコーダを利用するには、Media Controller対応の実装、サブデバイスのフォーマット設定、DMABUFバッファ管理の適切な実装などが必要となります。実装の複雑性が大幅に増加しました。こちらのフォーラム投稿からも明らかなように、ドキュメント不足により開発者の負担が大きくなっています。
https://forums.raspberrypi.com/viewtopic.php?t=358611
V4L2 APIを直接使用する技術的メリットとしては、ハードウェアへの低レベルアクセスと細粒度の制御、中間レイヤーを排除したオーバーヘッドの最小化、標準Linuxカーネルインターフェースとの互換性などが挙げられます。
しかしこれらのメリットより、実装の複雑性と開発時間の大幅な増加、未文書化の制約と振る舞いへの対応、継続的なカーネル/ドライバ変更への追従といった課題と比較検討する必要があります。
現状では、GStreamerやffmpegのようなマルチメディアフレームワークと組み合わせる場合も、libcamera-vidなどを中間層として使用し、ハードウェアエンコード済みのH.264ストリームをパイプで受け渡す構成を選択することになります。v4l2が使えない理由がわかってすっきりしました。
どうしてv4l2が使えないのだろう。気になってしらべました。
システムに認識されているカメラの情報を確認するためlibcamera-still –list-camerasでカメラリストを取得してみます。IMX500センサーに対して公式に設定されている解像度モードは以下の2つだけのように見えます。少ないですね。
libcamera-still –list-cameras
Available cameras
—————–
0 : imx500 [4056×3040 10-bit RGGB] (/base/soc/i2c0mux/i2c@1/imx500@1a)
Modes: ‘SRGGB10_CSI2P’ : 2028×1520 [30.02 fps – (0, 0)/4056×3040 crop]
4056×3040 [10.00 fps – (0, 0)/4056×3040 crop]
これはセンサーハードウェアが直接サポートしているネイティブモードであり、実際には他の解像度も使用できます。libcameraアプリケーションでは、コマンドライン引数で任意の解像度を指定できます。
libcamera-vidとGStreamerで映像を取得して送信します。2028×1520、4056×3040を指定するとエラーが起きてしました。1080@30サポートなのでVideoCore GPUエンコーダが対応していないのでしょう。当たり前ですね。ちなみに2028×1520、4056×3040は4:3です。センサーサイズは7.857mm(1/2.3型)、解像度は12.3メガピクセル(4056×3040)というわけです。
1080@30を超えていますが、1920×1440ピクセルにしてみます。同じくエラーが発生します。1080@30サポートなので×1440がダメなのかもしれません。違うかもしれません。
1920×1080 = 2073600 ピクセル
1660×1245 = 2066700 ピクセル
1660×1245で試してみましょう。色などがおかしくなりました。奇抜な解像度は駄目なのかもしれません。考えを改めて1600×1200ピクセルにしました。4:3であり、総ピクセル数も収まるものです。上手く動作しました。
さて準備が整いました。CPU(ソフトウェア)とGPU(ハードウェア)エンコードの比較テストをしてみましょう。軽くテストした段階でCPU処理では1600×1200では動かないことがわかりました。
ある意味で結果が出ておりますが、より厳密な比較データを取得するため、両方の方式で安定して動作する1280×720@30fpsの解像度設定で比較テストを実施することにしました。
CPU処理(1280×720@30)実行結果(htop)
GPU処理(1280×720@30)実行結果(htop)
Raspberry Pi Zero 2W エンコーディング比較テストの簡単なコマンドを作りました。ソフトウェアエンコーディングは、libcamera-vidを使用してYUV420形式で映像を取得し、x264encを用いてCPUリソースによるH.264エンコード処理を実行します。ハードウェアエンコーダーでは、libcamera-vidの–inlineオプションを活用し、VideoCore GPUに内蔵されたハードウェアエンコーダーを使用して直接H.264形式へのエンコードを行います。これにより、専用ハードウェアの効率性を評価します。
パフォーマンス測定のため、各エンコード方式を30秒間連続して実行し、1秒間隔でシステムリソースの使用状況を記録しました。精度の高い測定を実現するため、/proc/statファイルを直接読み取ることで各CPUコアの使用率を高精度で算出しています。
結果としてGPUハードウェアエンコーディングはCPUエンコーディングと比較してCPU使用率を約46.00%削減できました。メモリもGPU処理のほうが若干すくないようです。以下実行結果です。上記のhtopのグラフと同じ結果であり、大きな間違いはなさそうです。
測定時間: 30秒, サンプリング間隔: 1秒
—————————————-
CPU エンコーディング開始
—————————————-
パイプラインを一時停止 (PAUSED) にしています…
Pipeline is PREROLLING …
[2:33:51.174640684] [18636] INFO Camera camera_manager.cpp:327 libcamera v0.4.0+53-29156679
[2:33:51.292435995] [18643] WARN RPiSdn sdn.cpp:40 Using legacy SDN tuning – please consider moving SDN inside rpi.denoise
[2:33:51.297269953] [18643] INFO RPI vc4.cpp:447 Registered camera /base/soc/i2c0mux/i2c@1/imx500@1a to Unicam device /dev/media2 and ISP device /dev/media0
[2:33:51.297418286] [18643] INFO RPI pipeline_base.cpp:1121 Using configuration file ‘/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml’
Made DRM preview window
Mode selection for 1280:720:12:P(30)
SRGGB10_CSI2P,2028×1520/30.0219 – Score: 2717.7
SRGGB10_CSI2P,4056×3040/9.9987 – Score: 43607.3
Stream configuration adjusted
[2:33:51.404485836] [18636] INFO Camera camera.cpp:1202 configuring streams: (0) 1280×720-YUV420 (1) 2028×1520-SRGGB10_CSI2P
[2:33:51.405178961] [18643] INFO RPI vc4.cpp:622 Sensor: /base/soc/i2c0mux/i2c@1/imx500@1a – Selected sensor format: 2028×1520-SRGGB10_1X10 – Selected unicam format: 2028×1520-pRAA
Redistribute latency…
Redistribute latency…
Redistribute latency…
Pipeline is PREROLLED …
パイプラインを再生中 (PLAYING) にしています…
Redistribute latency…
New clock: GstSystemClock
—————————————-
CPU エンコーディングのリソースモニタリング開始(30秒間)
—————————————-
進行状況: 30/30秒 99.
CPU モニタリング完了
Received signal 13
Received signal 13
terminate called after throwing an instance of ‘std::runtime_error’
what(): failed to write output bytes
—————————————-
GPU ハードウェアエンコーディング開始
—————————————-
パイプラインを一時停止 (PAUSED) にしています…
Pipeline is PREROLLING …
[2:35:11.811278838] [25145] INFO Camera camera_manager.cpp:327 libcamera v0.4.0+53-29156679
[2:35:11.929042632] [25152] WARN RPiSdn sdn.cpp:40 Using legacy SDN tuning – please consider moving SDN inside rpi.denoise
[2:35:11.933972580] [25152] INFO RPI vc4.cpp:447 Registered camera /base/soc/i2c0mux/i2c@1/imx500@1a to Unicam device /dev/media2 and ISP device /dev/media0
[2:35:11.934204872] [25152] INFO RPI pipeline_base.cpp:1121 Using configuration file ‘/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml’
Made DRM preview window
Mode selection for 1280:720:12:P(30)
SRGGB10_CSI2P,2028×1520/30.0219 – Score: 2717.7
SRGGB10_CSI2P,4056×3040/9.9987 – Score: 43607.3
Stream configuration adjusted
[2:35:12.041398771] [25145] INFO Camera camera.cpp:1202 configuring streams: (0) 1280×720-YUV420 (1) 2028×1520-SRGGB10_CSI2P
[2:35:12.041948094] [25152] INFO RPI vc4.cpp:622 Sensor: /base/soc/i2c0mux/i2c@1/imx500@1a – Selected sensor format: 2028×1520-SRGGB10_1X10 – Selected unicam format: 2028×1520-pRAA
Redistribute latency…
Pipeline is PREROLLED …
パイプラインを再生中 (PLAYING) にしています…
Redistribute latency…
New clock: GstSystemClock
—————————————-
GPU エンコーディングのリソースモニタリング開始(30秒間)
—————————————-
進行状況: 30/30秒 99.
GPU モニタリング完了
Received signal 13
Received signal 13
terminate called after throwing an instance of ‘std::runtime_error’
what(): failed to write output bytes
—————————————-
結果分析
—————————————-
==========================================
Raspberry Pi Zero 2W エンコーディング比較結果
==========================================
測定時間: 30秒, サンプリング間隔: 1秒
| CPU エンコード | GPU ハードウェアエンコード
———-|————–|——————
コア 0 平均 | 71% | 24.53%
コア 0 最大 | 80.0% | 26.3%
コア 1 平均 | 72.41% | 25.0967%
コア 1 最大 | 100.0% | 36.6%
コア 2 平均 | 72.35% | 25.23%
コア 2 最大 | 100.0% | 31.4%
コア 3 平均 | 70.9133% | 24.0567%
コア 3 最大 | 100.0% | 30.5%
全体CPU平均| 70.8333% | 38.0833%
全体CPU最大| 100% | 54.6%
平均メモリ | 50.353% | 46.7259%
最大メモリ | 51.1824% | 47.4103%
———-|————–|——————
CPU使用率削減: 46.00%
結論:
GPUハードウェアエンコーディングはCPUエンコーディングと比較してCPU使用率を約46.00%削減
==========================================
GPUハードウェアエンコーディングが優れている結論
GPUハードウェアエンコーディングが優れている結論が出ていますが、受信側を設定して正しく解像度とフレームレートが出ているか確認してみます。
CPU処理(1280×720@30)→受信側端末
30fpsに到達できずカクカクです。15fpsが限界のようです。フレームレートも安定しません。
GPU処理(1280×720@30)→受信側端末
きっちり30fpsへ到達し、フレームレートも安定です。GPU処理を選ばない理由が何もありません。
動作中の消費電力もざっくりですが調べてみます。詳細に調べるツールがないので、たまたま手元にあったバッテリーに消費電量が表示されるので、それを使って調べてみましょう。まあざっくりです。
スタンバイ:5.1V:0.2A=1W
CPUエンコード実行時:5.1V:0.6A=3W
GPUエンコード実行時:5.1V:0.5A=2.5W
テスト結果から、GPUハードウェアエンコードのほうがCPUソフトウェアエンコードと比較して若干消費電力が少ないことが観察されました。ただし、この簡易的な計測方法では偶然の誤差の可能性も否定できません。
スタンバイ時の消費電力(約1W)のさらなる削減可能性について検証するため、以下の省電力化手法を試行しました。
LEDなし
sudo sh -c ‘echo none > /sys/class/leds/ACT/trigger’
sudo sh -c ‘echo mmc0 > /sys/class/leds/ACT/trigger’
無線なし
sudo rfkill block wifi
sudo rfkill unblock wifi
bluetoothなし
sudo rfkill block bluetooth
sudo rfkill unblock bluetooth
CPUコア数制限
sudo nano /boot/firmware/cmdline.txt
末尾に maxcpus=1
などしても5V0.2Aと大きくは変わりませんでした。0.15Aぐらいにはなってるのかもしれません。もっとカリカリに不要なサービスなどを止め切ればもう少しさがるのかもです。さらに調べるには計測機器が必要です。それを考慮しても0.1Wより超消費電力にすることは難しそうです。より少ない電力にする場合は、Arduino、ESP32、STM32などいわゆるマイコンを用意するべきでしょう。
また別の機会に低消費電力にチャレンジしてみようと思います。趣旨とは大きく脱線しましたがRaspberry Pi Zero 2W+Raspberry Pi AI Cameraの映像動作について理解が深まりました。
その4につづく
https://techietechnology.co.jp/2025/03/12/make-aicamera-04/