Camera2 の概要
1. まとめ
この記事は Camera2 のレビューで、主に次の部分が含まれます。
- その1:Camera2参考資料
- その2:Camera2の開発経緯
- Part3: Camera2のフレームワークと利用の流れ
この記事はCamera1 のレビュー記事と合わせて読むことができます。説明を完全にするために、この記事は Camera1 のレビュー記事と重複しています。
Part2ではCamera1
と の違いを詳しく紹介しCamera2
、Camera2の開発経緯も紹介します。
Part3では、Camera2にまつわる使用プロセスをフレーム次元、コード次元から詳しく紹介します。ただし、使用手順、詳細で完全なコード開発または説明のみが含まれますCamera2源码分析
および を参照してくださいCamera2开源项目分析
。
関連する Camera2 シリーズの記事を参照できます: Android Camera シリーズの記事の進捗表
2.参考資料
3.開発経緯
まず、次の 2 つの概念を明確にする必要があります。
HAL
API
異なるHAL
合計の中で、特定の合計の違いをAPI
見つけることができます。Camera1
Camera2
3.1 HAL:ハードウェア抽象化レイヤー。
Camera1 のレビュー記事の説明は次のとおりです。
HAL は、カメラ ドライバーと上位レベルの Android フレームワークの間に位置し、アプリがカメラ ハードウェアを適切に操作できるように実装する必要があるインターフェイスを定義します。
HAL は、ハードウェア ベンダーが実装する標準インターフェースを定義し、Android が下位レベルのドライバーの実装を無視できるようにします。HAL の実装は通常、共有ライブラリ モジュール (.so) に組み込まれています。
HAL は主にカメラの; 関連するバージョン履歴のダイナミクスを理解するだけでよく、それを掘り下げる必要はありません. ここに簡単な要約があります. 詳細については、以下を参照してください。
HAL バージョン | 例証する |
---|---|
1.0 | 1. Android カメラ HAL (Android 4.0) [camera.h]; 2. サポートandroid.hardware.Camera API |
2.0 | 1. 拡張機能HALの初期バージョン(Android 4.2) [camera2.h]; 2. 既存のandroid.hardware.Camera APIを実装するのに十分。 |
3.0 | 1. 拡張機能 HAL の最初のリビジョン 2. 重要なバージョン変更、入力要求およびストリーム キュー インターフェイスの再設計など |
3.1 | 1. 拡張機能 HAL のマイナー リビジョン; 2. configure_streams はコンシューマー使用フラグを HAL に渡し、フラッシュ呼び出しを実行して、処理中のすべてのリクエスト/バッファーをできるだけ早く破棄します。 |
3.2 | 1. 拡張機能 HAL のマイナー リビジョン; 2. 非推奨get_metadata_vendor_tag_ops およびregister_stream_buffers ; 双方向および入力ストリーム仕様の再制定; 入力バッファーのリターン パスの変更。 |
3.3 | 1. 拡張機能 HAL のマイナー リビジョン; 2. OPAQUE および YUV 再処理 API の更新; 深度出力バッファーの基本サポート; いくつかのフィールドを追加します。 |
3.4 | 1. サポートされているメタデータへのマイナーな追加と、data_space サポートへの変更。 |
3.5 | 1.Android10.0;ICameraDevice,ICameraDeviceSession,ICameraDeviceCallbackを更新。 |
アンドロイド 8.0 | 1. Treble が導入されました; 2. ベンダー カメラ HAL 実装がバインドされている必要があります。 |
アンドロイド 9.0 | 1.HAL 3.3 ではいくつかのキーとメタデータ タグが追加され、2.HAL 3.4 では ICameraDeviceSession と ICameraDeviceCallback が更新されます。 |
アンドロイド 10.0 | 1. HAL 3.4 は、画像形式、メタデータ フラグ、新しい機能、データ フロー構成などを追加します。 |
3.2 Camera1 と Camera2 の違い
Camera1
とCamera2
はそれぞれ 、つまり相机API1
とに対応します相机API2
。
3.2.1 カメラ API1
Android 5.0 は廃止されCamera API1
、新しいプラットフォームは開発に重点を置いておりCamera API2
、Camera API1
徐々に廃止されます。ただし、フェーズアウト期間は長くなり、新しい Android バージョンはしばらくの間Camera API1
アプリを。これが、Camera1 フレームワークが後続の Android SDK でアプリケーション サポート フレームワークとして使用できる理由です。
3.2.2 カメラ API2
Camera API2
このフレームワークは、効率的なゼロコピー バースト撮影/ストリーミングや、露出、ゲイン、ホワイト バランス ゲイン、色変換、ノイズ除去、シャープ化などのフレームごとのコントロールなど、低レベルに近いカメラ コントロールをアプリに提供します。- Android 5.0 以降のバージョンはカメラ API2 を提供します。つまり、Android 5.0 以降のバージョンはをサポートしていますが、Android 5.0 以降のバージョンはすべてのカメラ API2 機能をサポートしていない場合があります。
Camera2
Camera2
以下のサポートレベルに分かれています
Camera2 対応レベル | 例証する |
---|---|
遺産 | 使用する関数は API1 とほぼ同じです。つまり、最下層はカメラ API2 呼び出しをカメラ API1 呼び出しに変換します。 |
限定 | 一部のカメラ API2 関数、およびカメラ HAL 3.2 以降。 |
満杯 | API2 のすべての主要機能、およびカメラ HAL 3.2 以降をサポートします。 |
レベル3 | YUV 再処理と RAW 画像キャプチャ、およびその他の出力ストリーム構成をサポートします。 |
外部の | LIMITED デバイスと同様に、このレベルは外部カメラに使用されます。 |
互換性のコストを考えると、実際に Camera2 の機能を使用する場合、Android5.0 で Camera2 を直接サポートすることはありません。代わりに、より高いバージョンの HAL3.2 に対応する Android SDK で Camera2 がサポートされます。Android SDK が Camera2 をサポートし始めたのはいつですか?【3.3】
で明らかになります。
3.2.3 カメラ API のバージョン履歴
以下は簡単な要約です。詳細については、
カメラ API のバージョン履歴を参照してください。
API バージョン | 例証する |
---|---|
1.0 | HAL1.0、つまり Camera1 を実装する |
2.0 | HAL2.0 以上、つまり Camera2 を実装する |
2.1 | カメラ HAL モジュールからフレームワークへの非同期コールバックのサポートを追加しました |
2.2 | モジュールベンダータグのサポートを追加 |
2.3 | 従来のカメラ HAL デバイスを開くためのサポートが追加されました。 |
2.4 | API の変更; 1. 懐中電灯モードのサポート; 2. 外部カメラ (USB ホットスワップ可能なカメラなど) のサポート; 3. カメラ調停プロンプト; 4. モジュールの初期化メソッド。 |
3.3 HAL1 と HAL3
3.3.1 HAL1
HAL1 は、現在廃止されている Camera1 に対応します。HAL1 のアーキテクチャは次のとおりです。
ここでは、公式ドキュメントが明確に提唱しています。
注意:由于 Camera HAL1 已弃用,建议在搭载 Android 9 或更高版本的设备上使用 Camera HAL3。
したがって、一般的には、9.0
上記をサポートすることをCamera2
お勧めします。またCamera2
、 のサポートレベルには、それ以上の使用を推奨するレベルもFULL
記載されています。Level3
HAL3.2
3.3.2 HAL3
【3.2】
Camera1
と のCamera2
機能的な違いについてはこちらで説明しています.HAL3
アーキテクチャ図はここに貼り付けています. 詳しい理論知識については
[Android Camera] Android Camera Architecture Design Detailed Explanation の記事を参照してください.
4. フレームワークと使用プロセス
主に、フレームワーク次元とコードレベル次元の2つの次元に分けられます
4.1 フレーム寸法
以下の部品を含む
- Camera2 カメラモデル
- カメラ HAL3 コア オペレーション モデル
- HAL 操作の概要
- カメラセンサー
- Android カメラ API の手順
4.1.1 Camera2 カメラモデル
上の図には、次の 3 つのレイヤーが含まれています。
4.1.1.1 カメラ利用アプリ
モジュール | 例証する |
---|---|
CameraManager.AvailabilityCallback | アプリケーション レイヤーは、このコールバックを通じてカメラ デバイスのステータスを監視します。 |
カメラ特性 | カメラ デバイス情報と関連する設定クラス |
出力ストリームの宛先 | 出力ストリーム構成: 構成可能なプレビュー、写真撮影、記録、およびその他のシナリオ |
折り返し電話 | 次のようないくつかのコールバック メソッド: CameraCaptureSession.CaptureCallBack |
4.1.1.2 カメラ 2 API
モジュール | 例証する |
---|---|
カメラマネージャー | アプリケーション層はデバイスに接続し、このタイプの呼び出しを通じてカメラ情報を取得します |
カメラデバイス | 絵画の作成を提供し、フレーム キャプチャを作成するためのアプリケーション レイヤーを提供します。 |
カメラキャプチャセッション | 特定のフレーム キャプチャが出力ストリーム情報に変換される |
構成された出力 | 出力ストリーム キュー |
4.1.1.3 カメラ デバイス ハードウェア
ハードウェア レベル: レンズ制御、Camera Sensor
フラッシュ設定、後処理、および制御操作を含みます。
4.1.2 カメラ HAL3 コア操作モデル
カメラ モデルのコア操作は、フレーム キャプチャ要求を対応する出力ストリームに出力することです。次のように:
API は、カメラ サブシステムを、CaptureRequest
受信フレーム キャプチャ リクエスト ( ) をフレームに変換するパイプラインとしてモデル化します。リクエストには、フレームのキャプチャと処理に関するすべての構成情報が含まれます。これには、解像度とピクセル フォーマット、手動センサー、レンズ、およびフラッシュ コントロール、3A モードの動作、RAW から YUV への処理コントロール、統計生成などが含まれます。
- 構造
CaptureRequest
- 独身
Capture
request
- Output1: 構成された出力面 [プレビュー、写真など]
- 出力 2:
onCaptureComplete
->CaptureResult
。
コアの処理フローは、上図と上記の 5 つのステップで示されます。これは、単一の要求操作です。Camera2
また、繰り返しの Request 操作プロセスも用意されています。読む。
4.1.3 HAL 操作の概要
如上图,包含如下几个流程:
- 输入和构造
CaptureRequest
Camera HAL
经过配置、帧捕获和后处理- 输出到输出流配置里。
在图片里可以看到CaptureRequest
分为2种:
- 单次
Capture
,直接输出 - 重复
Capture
,重新由4转移到6
几点说明
- 捕获的异步请求来自于框架。
- HAL 设备必须按顺序处理请求。对于每个请求,均生成输出结果元数据以及一个或多个输出图像缓冲区。
- 请求和结果以及后续请求引用的信息流遵守先进先出规则。
- 指定请求的所有输出的时间戳必须完全相同,以便框架可以根据需要将它们匹配在一起。
- 所有捕获配置和状态(不包括 3A 例程)都包含在请求和结果中。
4.1.4 Camera传感器
本小节具体介绍Camera硬件层面即Camera Sensor
如上图为:图像信号处理器(ISP,也称为相机传感器)包含了如下几个模块:
- 3A算法;
- 输出流分辨率和大小以及格式的处理
- 图像处理:Hot Pixel Correction -> Demosaic -> Noise Reduction -> ShadingCorrection -> Geometric Correction -> Color Correction -> Tone Curve Adjustment -> Edge Enhancement。
整个ISP处理流程的简介看参看如下2篇文章:
【Android Camera】1.Camera理论知识和基本原理
这里总结为如下2张图:
4.1.5 Android Camera API步骤
- 监听和枚举相机设备。
- 打开设备并连接监听器。
- 配置目标使用情形的输出(如静态捕获、录制等)。
- 为目标使用情形创建请求。
- 捕获/重复请求和连拍。
- 接收结果元数据和图片数据。
- 切换使用情形时,返回到第 3 步。
4.2 代码维度
这里以【4.1.5里的流程进行阐述】
4.2.1 监听和枚举相机设备。
4.2.1.1监听相机设备
可通过CameraManager
的如下方法:
public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback,
@Nullable Handler handler) {
CameraManagerGlobal.get().registerAvailabilityCallback(callback,
CameraDeviceImpl.checkAndWrapHandler(handler));
}
AvailabilityCallback
次の 3 つのメソッドが含まれています。
public void onCameraAvailable(@NonNull String cameraId) {
}
public void onCameraUnavailable(@NonNull String cameraId) {
}
public void onCameraAccessPrioritiesChanged() {
}
4.2.1.2 カメラデバイスの列挙
カメラ デバイスに 2 つ以上のカメラ デバイスが含まれるようになりました。カメラ デバイスは、次の方法で列挙できます。
val cameraIdList = cameraManager.cameraIdList // may be empty
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
val cameraCompatible = cameraCapabilities?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
次のメソッドは、前面または背面の cameraId へのアクセスを提供します
fun getFirstCameraIdFacing(cameraManager: CameraManager,
facing: Int = CameraMetadata.LENS_FACING_BACK): String? {
// Get list of all compatible cameras
val cameraIds = cameraManager.cameraIdList.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
capabilities?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
}
// Iterate over the list of cameras and return the first one matching desired
// lens-facing configuration
cameraIds.forEach {
val characteristics = cameraManager.getCameraCharacteristics(it)
if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) {
return it
}
}
// If no camera matched desired orientation, return the first one from the list
return cameraIds.firstOrNull()
}
その他の関連する方法:
fun filterCompatibleCameras(cameraIds: Array<String>,
cameraManager: CameraManager): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
}
}
fun filterCameraIdsFacing(cameraIds: List<String>, cameraManager: CameraManager,
facing: Int): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.LENS_FACING) == facing
}
}
fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? {
// Get all front, back and external cameras in 3 separate lists
val cameraIds = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager)
val backCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK)
val frontCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT)
val externalCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL)
// The recommended order of iteration is: all external, first back, first front
val allCameras = (externalCameras + listOf(
backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull()
// Get the index of the currently selected camera in the list
val cameraIndex = allCameras.indexOf(currCameraId)
// The selected camera may not be on the list, for example it could be an
// external camera that has been removed by the user
return if (cameraIndex == -1) {
// Return the first camera from the list
allCameras.getOrNull(0)
} else {
// Return the next camera from the list, wrap around if necessary
allCameras.getOrNull((cameraIndex + 1) % allCameras.size)
}
}
4.2.2 デバイスの電源を入れ、リスナーを接続します。
次の方法で:
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {
openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
USE_CALLING_UID);
}
パラメータの説明:
cameraId
->【4.2.1】
CameraDevice.StateCallback
次のように:
public static abstract class StateCallback {
public abstract void onOpened(@NonNull CameraDevice camera); // Must implement
public void onClosed(@NonNull CameraDevice camera) {
// Default empty implementation
}
public abstract void onDisconnected(@NonNull CameraDevice camera); // Must implement
public abstract void onError(@NonNull CameraDevice camera,
@ErrorCode int error); // Must implement
}
4.2.3 ターゲット ユース ケースの出力 (静的キャプチャ、記録など) を構成し、ターゲット ユース ケースの要求を作成します。.
// Retrieve the target surfaces, which could be coming from a number of places:
// 1. SurfaceView, if you want to display the image directly to the user
// 2. ImageReader, if you want to read each frame or perform frame-by-frame analysis
// 3. OpenGL Texture or TextureView, although discouraged for maintainability reasons
// 4. RenderScript.Allocation, if you want to do parallel processing
val surfaceView = findViewById<SurfaceView>(...)
val imageReader = ImageReader.newInstance(...)
// Remember to call this only *after* SurfaceHolder.Callback.surfaceCreated()
val previewSurface = surfaceView.holder.surface
val imReaderSurface = imageReader.surface
val targets = listOf(previewSurface, imReaderSurface)
// Create a capture session using the predefined targets; this also involves defining the
// session state callback to be notified of when the session is ready
cameraDevice.createCaptureSession(targets, object: CameraCaptureSession.StateCallback() {
override fun onConfigured(session: CameraCaptureSession) {
// Do something with `session`
}
// Omitting for brevity...
override fun onConfigureFailed(session: CameraCaptureSession) = Unit
}, null) // null can be replaced with a Handler, falls back to current thread's Looper
4.2.4 キャプチャ/リピート リクエストとバーストおよび単一および複数のキャプチャの切り替え。
val session: CameraCaptureSession = ... // from CameraCaptureSession.StateCallback
// Create the repeating request and dispatch it
val repeatingRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_PREVIEW)
repeatingRequest.addTarget(previewSurface)
session.setRepeatingRequest(repeatingRequest.build(), null, null)
// Some time later...
// Create the single request and dispatch it
// NOTE: This may disrupt the ongoing repeating request momentarily
val singleRequest = session.device.createCaptureRequest(
CameraDevice.TEMPLATE_STILL_CAPTURE)
singleRequest.addTarget(imReaderSurface)
session.capture(singleRequest.build(), null, null)
シングルとマルチの違いは以下の通りです。
4.2.5 結果のメタデータと画像データを受け取ります。
public abstract int setRepeatingRequest(@NonNull CaptureRequest request,
@Nullable CaptureCallback listener, @Nullable Handler handler)
throws CameraAccessException;
CaptureRequest
->【4.2.4】
CaptureCallback listener
次のように:
public static abstract class CaptureCallback {
public static final int NO_FRAMES_CAPTURED = -1;
public void onCaptureStarted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, long timestamp, long frameNumber) {
// default empty implementation
}
public void onCapturePartial(CameraCaptureSession session,
CaptureRequest request, CaptureResult result) {
// default empty implementation
}
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
// default empty implementation
}
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
// default empty implementation
}
public void onCaptureFailed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
// default empty implementation
}
public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session,
int sequenceId, long frameNumber) {
// default empty implementation
}
public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session,
int sequenceId) {
// default empty implementation
}
public void onCaptureBufferLost(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) {
// default empty implementation
}
}
終わり
関連記事を読み続ける場合は、以下を参照してください: Android カメラ シリーズの記事の進行表.また、Android カメラ シリーズの記事をブックマークして、一緒に学び、進歩させてください。
質問や正誤表がある場合は、コメントするか、次の電子メールで私に連絡してください。
[email protected]