AOSP Camera2 APIとHAL3パイプライン構造の解明

来のAndroidカメラ開発において、最大のボトルネックはAPIの抽象度が過度に高く、ハードウェアの能力を直接制御できない点にありました。初期のCamera API (Deprecated) はブラックボックス化されたステートマシンであり、バースト撮影やRAW現像、ゼロシャッターラグ(ZSL)の実装には不向きでした。Android 5.0 (Lollipop) で導入されたCamera2 APIと、それに対応するHAL3 (Hardware Abstraction Layer v3) は、このパラダイムを根本から変えました。本稿では、アプリ開発者およびシステムエンジニア向けに、AOSPにおけるカメラサブシステムの階層構造と、フレーム単位のリクエストパイプライン処理の内部ロジックを分析します。

1. カメラサブシステムの4層アーキテクチャ

Androidのカメラスタックは、アプリケーションフレームワークからカーネルドライバに至るまで、明確に定義された4つのレイヤーで構成されています。この構造を理解することは、パフォーマンス低下の原因が「アプリの実装」にあるのか、「Binder通信のオーバーヘッド」にあるのか、あるいは「HALの実装」にあるのかを切り分けるために不可欠です。

レイヤー コンポーネント 主な役割
Application Camera2 API CaptureRequestの生成と結果の受信
Framework CameraService アプリとHAL間の調停、権限管理、IPC通信
HAL (User Space) Camera HAL3 (HIDL/AIDL) フレームワークからのリクエストをドライバ命令へ変換
Kernel V4L2 Driver / ISP Driver センサー制御、データ転送、ハードウェア割り込み処理

特に重要なのは、フレームワークとHALの境界です。Android 8.0 (Oreo) 以降のProject Trebleにより、HALは独立したプロセスとして分離されました。これにより、CameraServiceとHAL間の通信はBinder IPC(またはhwbinder)を介して行われます。

Architecture Note: レガシーなHAL1と最新のHAL3の決定的な違いは、リクエスト処理の粒度です。HAL1が大まかな「モード」ベースであったのに対し、HAL3は「フレーム単位(Per-frame)」で設定を変更可能です。これにより、フレームごとに露出やフォーカス位置を変えるブラケット撮影が可能になります。

2. リクエストパイプラインモデルの実装

Camera2 APIの中核概念は「パイプライン」です。これは単方向の非同期ストリームとして設計されています。アプリケーションはCaptureRequestを作成し、それをCameraCaptureSessionにキューイングします。システムはこれらを順次処理し、CaptureResultと画像データ(Image)を返却します。

非同期処理とメタデータ同期

各リクエストには、センサー感度(ISO)、露光時間、フォーカス距離などのパラメータを含めることができます。HALはこのメタデータをISP(Image Signal Processor)への命令セットに変換します。

// CaptureRequestの構築例(手動露出制御)
// 物理カメラの特性を考慮したパラメータ設定が必要

try {
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL);

// ターゲットSurfaceの設定(例:ImageReaderやSurfaceView)
builder.addTarget(targetSurface);

// 自動露出(AE)を無効化
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);

// ISO感度を100に固定
builder.set(CaptureRequest.SENSOR_SENSITIVITY, 100);

// 露光時間を設定 (ナノ秒単位: 例 1/50秒)
long exposureTimeNs = 1000000000L / 50;
builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, exposureTimeNs);

// フレームごとの色補正ゲイン設定(AWB無効化時など)
// R, G_even, G_odd, B の順
RggbChannelVector colorGains = new RggbChannelVector(2.0f, 1.0f, 1.0f, 1.5f);
builder.set(CaptureRequest.COLOR_CORRECTION_GAINS, colorGains);

// リクエストの発行
session.capture(builder.build(), captureCallback, backgroundHandler);

} catch (CameraAccessException e) {
// HALとの通信エラーや切断処理
Log.e(TAG, "Camera access failed: " + e.getMessage());
}
Warning: CaptureResultは非同期で返ってきますが、画像データそのものとは別のタイミングで到着する可能性があります。TotalCaptureResultImageReaderからのデータ取得を紐付ける際は、タイムスタンプ(SENSOR_TIMESTAMP)を利用して同期を取るのが鉄則です。

3. HAL3におけるバッファ管理とストリーム構成

システムエンジニアリングの観点において、最も複雑なのがメモリ管理です。高解像度画像(例えば48MPや108MP)の転送は、メモリ帯域幅を大量に消費します。Androidは「Gralloc」と呼ばれるグラフィックスメモリ割り当てシステムを使用し、ゼロコピーでのデータ転送を実現しようと試みます。

Stream Configuration

HAL3では、カメラオープン時にストリーム構成(解像度、フォーマット、用途)を宣言する必要があります。この構成フェーズは重い処理であり、頻繁な変更は避けるべきです。

  • Preview Stream: 通常はSurfaceViewやTextureViewへ送られる、低遅延・連続的なストリーム。HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINEDがよく使われます。
  • Still Capture Stream: JPEGまたはHEIC圧縮を行うストリーム。HAL_PIXEL_FORMAT_BLOBを使用します。
  • Video Record Stream: MediaCodecへ直接渡されるストリーム。

これらのストリームは同時に動作可能です。例えば、プレビューを表示しながら(Stream 1)、動画を録画し(Stream 2)、同時に高画質の静止画を撮影する(Stream 3)場合、HALはリソース競合を管理し、ISPのパイプラインを適切に分割または時分割処理する必要があります。

3A ステートマシンの制御

Auto Exposure (AE), Auto Focus (AF), Auto White Balance (AWB) の3AアルゴリズムはHAL層(またはISPファームウェア)で実行されます。Camera2 APIはこれらの状態遷移を詳細に監視・トリガーできます。

例えば「AFロックしてから撮影」というフローは、単なるAPI呼び出しの連続ではなく、ステートマシンの遷移確認が必要です。

  1. CONTROL_AF_TRIGGER_START を送信。
  2. CaptureResultCONTROL_AF_STATE を監視。
  3. 状態が FOCUSED_LOCKED または NOT_FOCUSED_LOCKED になるまで待機。
  4. 静止画撮影リクエストを発行。
Android Camera 3A State Machine Diagram
図1: HAL内での複雑な3A状態遷移(出典: AOSP Documentation)
Critical: 一部のデバイス実装(特に安価なSoCを採用したもの)では、HALが3A状態の報告を正確に行わない場合があります。厳密な制御が必要な商用アプリでは、タイムアウト処理を必ず実装し、無限待機状態(デッドロックのような挙動)を防ぐ必要があります。

4. パフォーマンスとトレードオフの分析

Camera2 APIとHAL3の柔軟性は、実装の複雑さと引き換えです。特に以下のトレードオフを理解しておく必要があります。

IPCオーバーヘッド

前述の通り、CameraServiceとHALプロセス間の通信にはBinderが使用されます。リクエストごとのメタデータ転送サイズが大きい場合や、高フレームレート(60fps以上)でのリクエスト発行は、CPU負荷を高めます。バースト撮影時は、複数のリクエストをまとめて投げるなどの最適化が必要です。

パイプライン深度とレイテンシ

高画質化のためにHDR+やナイトモードのようなマルチフレーム処理を行う場合、パイプラインの深さ(処理待ち行列の長さ)が増加し、シャッターラグが発生します。ユーザー体験を損なわないためには、処理中であることをUIで明示するか、ZSL(Zero Shutter Lag)技術を用いて、リングバッファにあらかじめ保存されたフレームを利用する設計が求められます。

結論: 抽象化と制御のバランス

AOSPのカメラアーキテクチャは、ハードウェアの進化に対応できる堅牢な設計を持っています。Camera2 APIは強力ですが、すべてのユースケースでこれを直接叩くのが正解とは限りません。Googleが提供するJetpack CameraXライブラリは、このCamera2 APIの複雑さを隠蔽し、デバイスごとの挙動の差異(Compatibility Issues)を吸収してくれます。

しかし、コンピュテーショナルフォトグラフィーのカスタム実装や、特定のハードウェア機能を極限まで引き出す必要がある場合は、Camera2 APIとHAL3のパイプライン構造の深い理解が唯一の解決策となります。ストリーム構成の最適化、リクエストスケジューリングの精密化、そしてメタデータの正確なハンドリングが、プロフェッショナルなカメラアプリケーションの品質を決定づけます。

Post a Comment