Camera2 API架构基础:Android视频系统的大门

引言:Camera1已死,Camera2当立

你有没有在面试中被问过这样的问题:"为什么Android要废弃Camera1 API?Camera2到底改进了什么?"

如果你的回答只是"因为Camera1太旧了"------那这篇文章正是为你准备的。

Camera1(android.hardware.Camera)在2014年被正式废弃,取而代之的是 Camera2android.hardware.camera2)。两者的差别不只是API名字换了几个字母,而是底层设计哲学的彻底重构。Camera1是命令式的------"拍照!""录像!";Camera2是声明式流式的------你描述你想要什么样的数据管道,系统帮你搭好,然后数据自动流淌。

用一个比喻:Camera1像是在餐厅点单(每次拍照都是单独下单),Camera2像是设置一条自动化流水线(配置好了,数据就按你期望的方式持续流出)。

本文是 Android 15 视频子系统系列的第一篇,带你从架构层面彻底理解 Camera2 API 的设计理念和核心概念。

本文内容

  • Camera2 相比 Camera1 的本质改进
  • Camera2 五层架构全景解析
  • 五大核心组件:CameraManager / CameraDevice / CameraCaptureSession / CaptureRequest / CaptureResult
  • CameraCharacteristics 特性查询
  • Android 15 相机新特性(Ultra HDR、10-bit视频)
  • 调试工具速查

一、Camera1 的问题在哪里?

在深入 Camera2 之前,先理解为何需要改变。

1.1 Camera1 的三大痛点

痛点1:单流输出,无法同时预览+拍照+录像

Camera1 只支持一路输出流(预览到 SurfaceView),想同时录像和高分辨率预览?对不起,做不到。

痛点2:同步阻塞式 API,延迟不可控

java 复制代码
// Camera1 的拍照 API - 同步阻塞,你无法精确控制时序
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
// 从这一行到 jpegCallback 被调用,中间发生了什么?你不知道。

同步阻塞模型意味着你无法知道快门何时精确触发、曝光何时结束,导致连拍性能差、零快门延迟(ZSL)难以实现。

痛点3:3A 控制粗糙

Camera1 的自动对焦、自动曝光、自动白平衡(3A)无法精细控制,不支持手动 ISO、快门速度等专业参数。这对专业拍照 APP(如相机 APP、手动相机)来说是致命缺陷。

1.2 Camera2 的核心改进

维度 Camera1 Camera2
输出流数量 1路 多路并发(预览+拍照+录像同时输出)
控制模型 同步命令式 异步 Pipeline 流式
3A 控制 粗粒度 精细手动控制(ISO/快门/白平衡色温)
时间戳精度 不可靠 纳秒级时间戳,可精确同步
RAW 格式 不支持 支持 RAW10/RAW12/RAW16
多摄像头 不支持 支持逻辑相机(多摄融合)

二、Camera2 五层架构全景

Camera2 的技术栈由五层组成,从 Java API 到物理传感器,每层职责清晰:

2.1 应用层(Application Layer)

最顶层,开发者直接打交道的地方:

java 复制代码
// 典型的 Camera2 开发入口
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
String[] cameraIds = manager.getCameraIdList(); // 获取所有相机ID

Camera2 包路径:android.hardware.camera2.*

核心类一览:

  • CameraManager --- 相机设备管理器(系统服务门口)
  • CameraDevice --- 单个相机设备的抽象
  • CameraCaptureSession --- 相机捕获会话
  • CaptureRequest --- 单次或重复捕获请求
  • CaptureResult --- 捕获结果元数据
  • CameraCharacteristics --- 相机静态特性(只读,出厂就定了)

2.2 Java Framework 层

android.hardware.camera2.* 这些 Java 类并非凭空运行,它们背后是 Java Framework 层:

bash 复制代码
frameworks/base/core/java/android/hardware/camera2/

关键类:

  • CameraManager.java --- 通过 Binder 调用 CameraService,管理相机设备列表
  • CameraDevice.java --- Binder 代理,真正的实现在 Native 的 Camera3Device
  • CameraCaptureSession.java --- 会话管理,对应 Native 的 CaptureSession

💡 设计模式 :Java 层的这些类本质上都是 Binder 代理 (Proxy),真正的逻辑在 Native 层的 CameraService 中执行。Java API 负责 "参数校验 + IPC 调用",性能敏感的代码在 C++ 里跑。

2.3 Native 层(CameraService)

CameraService 是 Android 相机的核心 Native 服务,运行在独立进程 cameraserver 中:

bash 复制代码
frameworks/av/services/camera/libcameraservice/   # CameraService 实现
frameworks/av/camera/                             # Camera Native 客户端库

核心组件:

组件 职责
CameraService 相机服务入口,多应用仲裁,权限管理
Camera3Device 单个相机设备的完整抽象,管理 Stream 和 Request
CameraDeviceClient Binder 服务端,对接 Java 层的请求
CameraProviderManager 管理所有 Camera HAL Provider

2.4 HAL 层(Camera HAL3)

HAL(Hardware Abstraction Layer)是 Android 框架与芯片厂商驱动之间的隔离层。Camera HAL3 使用 AIDL 接口定义(Android 13+,旧版为 HIDL):

bash 复制代码
hardware/interfaces/camera/   # HAL 接口定义

关键接口:

aidl 复制代码
// hardware/interfaces/camera/provider/aidl/ICameraProvider.aidl
interface ICameraProvider {
    // 获取相机设备列表
    CameraIdAndStreamCombination[] getCameraIdList();
    // 获取相机设备接口
    ICameraDevice getCameraDeviceInterface(in String cameraDeviceName);
}

// hardware/interfaces/camera/device/aidl/ICameraDevice.aidl
interface ICameraDevice {
    // 获取相机特性
    CameraMetadata getCameraCharacteristics();
    // 打开相机
    ICameraDeviceSession open(in ICameraDeviceCallback callback);
}

HAL3 与旧版 HAL1 的关键区别:从命令式改为 Request/Result 流水线模型------框架层发送 CaptureRequest,HAL 层流水线处理后返回 CaptureResult,完全异步。

2.5 驱动与硬件层

最底层与物理硬件交互:

  • V4L2(Video4Linux2):Linux 内核标准视频驱动接口
  • ISP(Image Signal Processor):图像信号处理器,负责 RAW → RGB 的图像处理
  • Camera Sensor:CMOS/CCD 传感器,实际光电转换
bash 复制代码
# 查看系统中的 V4L2 设备
adb shell ls /dev/video*
# 通常输出类似:/dev/video0  /dev/video1

三、Camera2 五大核心概念

理解了整体架构,深入看五个核心类的设计意图和关系。

3.1 CameraManager:相机的管理总入口

CameraManager 是系统服务,通过 getSystemService() 获取,作用是:

  1. 列举所有相机设备(前置、后置、外接 USB 相机)
  2. 查询相机静态特性(CameraCharacteristics
  3. 打开指定相机设备
  4. 监听相机可用性变化
java 复制代码
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

// 1. 获取相机列表
String[] ids = manager.getCameraIdList();
for (String id : ids) {
    CameraCharacteristics chars = manager.getCameraCharacteristics(id);
    // 判断前/后置
    Integer facing = chars.get(CameraCharacteristics.LENS_FACING);
    if (facing == CameraCharacteristics.LENS_FACING_BACK) {
        Log.d(TAG, "后置摄像头 ID: " + id);
    }
}

// 2. 打开相机(异步,结果通过回调返回)
manager.openCamera(backCameraId, new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        // 相机已打开,camera 就是 CameraDevice 对象
        mCameraDevice = camera;
        createCaptureSession(); // 下一步:创建会话
    }

    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
        camera.close(); // 相机断开(被其他 App 抢占)
    }

    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
        // 错误处理,error 值参见 CameraDevice.StateCallback.ERROR_*
        camera.close();
    }
}, backgroundHandler);

⚠️ 注意openCamera() 需要 android.permission.CAMERA 运行时权限。Android 12+ 还需要处理 隐私指示器(摄像头使用时顶部绿点)。

CameraManager 监听相机可用性(适用于多应用竞争场景):

java 复制代码
manager.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() {
    @Override
    public void onCameraAvailable(@NonNull String cameraId) {
        // 相机变为可用(之前被其他 App 占用,现在释放了)
    }

    @Override
    public void onCameraUnavailable(@NonNull String cameraId) {
        // 相机变为不可用(被其他 App 抢占)
    }
}, null);

3.2 CameraCharacteristics:静态特性查询

CameraCharacteristics 是相机的"说明书",保存了相机硬件的所有静态属性。它是只读的,在相机打开之前就能查询。

java 复制代码
CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId);

// 1. 硬件支持级别(能力越强,支持的功能越多)
int hwLevel = chars.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
// LEGACY(0) < LIMITED(0) < FULL(1) < LEVEL_3(3)
// Android 15 主流旗舰基本都是 FULL 或 LEVEL_3

// 2. 支持的输出格式和分辨率
StreamConfigurationMap map = chars.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

// 查询 JPEG 拍照支持的尺寸
Size[] jpegSizes = map.getOutputSizes(ImageFormat.JPEG);
for (Size size : jpegSizes) {
    Log.d(TAG, "支持 JPEG 尺寸: " + size.getWidth() + "x" + size.getHeight());
}

// 查询 YUV_420_888 预览支持的尺寸
Size[] yuvSizes = map.getOutputSizes(ImageFormat.YUV_420_888);

// 3. 焦距信息(用于判断广角/长焦)
float[] focalLengths = chars.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);

// 4. 传感器物理尺寸(用于计算视角 FOV)
SizeF sensorSize = chars.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE);

// 5. 支持的 AE 模式(自动曝光)
int[] aeModes = chars.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES);
// 包含 CONTROL_AE_MODE_OFF(手动曝光)则支持手动控制

// 6. 最大数字变焦比例
float maxZoom = chars.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);

// Android 11+:逻辑相机下的物理相机列表(多摄系统)
Set<String> physicalCameras = chars.getPhysicalCameraIds();

硬件级别说明

级别 常量值 典型能力 代表设备
LEGACY 0 最基础,主要保证兼容性 旧设备软件模拟
LIMITED 0 部分 Camera2 特性 中低端设备
FULL 1 完整 Camera2 支持,含手动控制 主流旗舰
LEVEL_3 3 最高级别,支持 RAW 重处理等高级特性 旗舰+专业机型

3.3 CameraDevice:相机设备抽象

CameraDevice 代表一个已打开的物理(或逻辑)相机设备,职责是:

  1. 创建捕获会话(CameraCaptureSession
  2. 创建捕获请求(CaptureRequest.Builder
  3. 关闭设备(close()
java 复制代码
// 创建捕获请求的 Builder
// TEMPLATE_PREVIEW: 预览优化(持续 AF、AE)
// TEMPLATE_STILL_CAPTURE: 拍照优化(高质量,可能较慢)
// TEMPLATE_RECORD: 录像优化(稳定帧率优先)
// TEMPLATE_VIDEO_SNAPSHOT: 录像中插拍(兼顾帧率和质量)
// TEMPLATE_MANUAL: 完全手动控制
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(
    CameraDevice.TEMPLATE_PREVIEW
);

// 添加输出目标(可以多个!这是 Camera2 相比 Camera1 的核心优势)
builder.addTarget(previewSurface);   // 预览
builder.addTarget(imageReaderSurface); // 同时输出给 ImageReader

// 创建会话(Android 10- 的旧方式)
cameraDevice.createCaptureSession(outputSurfaces, stateCallback, handler);

// Android 10+ 的新方式(SessionConfiguration,更灵活)
SessionConfiguration sessionConfig = new SessionConfiguration(
    SessionConfiguration.SESSION_REGULAR,
    outputConfigurations,
    executor,
    stateCallback
);
cameraDevice.createCaptureSession(sessionConfig);

3.4 CameraCaptureSession:捕获会话

CameraCaptureSession 是 Camera2 最关键的概念之一,代表一次相机流配置:你告诉相机"我要这几路输出流,按这些参数输出",会话就建立了。

一次只能有一个活跃的会话(创建新会话会自动关闭旧会话)。

java 复制代码
cameraDevice.createCaptureSession(Arrays.asList(previewSurface, imageReaderSurface),
    new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            mCaptureSession = session;

            // 设置重复请求(持续预览)
            try {
                CaptureRequest.Builder previewBuilder =
                    cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                previewBuilder.addTarget(previewSurface);

                // ---- 核心 3A 设置 ----
                // 自动对焦(连续对焦,适合视频预览)
                previewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                // 自动曝光(开启防抖)
                previewBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                // 自动白平衡
                previewBuilder.set(CaptureRequest.CONTROL_AWB_MODE,
                    CaptureRequest.CONTROL_AWB_MODE_AUTO);

                // 启动重复请求(预览开始持续运行)
                session.setRepeatingRequest(
                    previewBuilder.build(),
                    mCaptureCallback, // 每帧回调
                    mBackgroundHandler
                );
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            // 会话配置失败(通常是请求的输出格式/尺寸组合不支持)
            Log.e(TAG, "会话配置失败");
        }
    }, null);

两种请求方式的区别

方式 API 用途
单次请求 session.capture() 拍一张照片
重复请求 session.setRepeatingRequest() 持续预览/录像
批量请求 session.captureBurst() 连拍
批量重复 session.setRepeatingBurst() 每帧用不同参数(罕见)

3.5 CaptureRequest & CaptureResult:请求与结果

这是 Camera2 Pipeline 模型的核心:你发送 Request,硬件处理后返回 Result

java 复制代码
// ===== CaptureRequest:控制每一帧的拍摄参数 =====
CaptureRequest.Builder builder = session.getDevice()
    .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

// 手动 ISO(感光度)
builder.set(CaptureRequest.SENSOR_SENSITIVITY, 800); // ISO 800

// 手动快门速度(纳秒)
builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 1_000_000_000L / 60); // 1/60s

// 手动对焦距离(0=无穷远,1/最近对焦距离=最近)
builder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0.0f); // 无穷远

// JPEG 质量
builder.set(CaptureRequest.JPEG_QUALITY, (byte) 95);

// 数字变焦(Android 11+ 推荐用 CONTROL_ZOOM_RATIO,旧版用 SCALER_CROP_REGION)
builder.set(CaptureRequest.CONTROL_ZOOM_RATIO, 2.0f); // 2x 变焦

session.capture(builder.build(), captureCallback, handler);
java 复制代码
// ===== CaptureResult:每帧的实际拍摄结果 =====
CameraCaptureSession.CaptureCallback captureCallback =
    new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                       @NonNull CaptureRequest request,
                                       @NonNull TotalCaptureResult result) {
            // 实际 ISO(可能与请求不同,因为 AE 算法可能覆盖)
            Integer iso = result.get(CaptureResult.SENSOR_SENSITIVITY);

            // 实际快门速度(纳秒)
            Long exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);

            // AF 状态(是否对焦成功)
            Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
            if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED) {
                Log.d(TAG, "对焦成功!");
            }

            // 帧的精确时间戳(纳秒,来自传感器)
            Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);
        }

        @Override
        public void onCaptureFailed(@NonNull CameraCaptureSession session,
                                    @NonNull CaptureRequest request,
                                    @NonNull CaptureFailure failure) {
            Log.e(TAG, "捕获失败: " + failure.getReason());
        }
    };

💡 Request 和 Result 的关系:Request 是你的"期望",Result 是硬件实际执行的"结果"。两者可能不同------例如你请求 ISO 200,但当前光线太暗,AE 算法将实际 ISO 提升到了 800,Result 里就会反映真实值。


四、Camera2 Pipeline 模型深度解析

Camera2 真正的精髓在于其 Pipeline(流水线) 模型。理解这个模型,才能真正掌握 Camera2。

4.1 什么是 Pipeline 模型

Camera2 将相机的工作抽象成一条流水线:

ini 复制代码
应用层: CaptureRequest ──→ [Camera Pipeline] ──→ CaptureResult + 帧数据
                              ↑
                         (硬件按Pipeline顺序处理)
                         1. 传感器曝光
                         2. RAW数据读取
                         3. ISP处理(去噪、锐化、色彩)
                         4. 编码输出(JPEG/YUV)
                         5. 元数据生成(CaptureResult)

关键特性:

  • 多帧并发:Pipeline 中可以同时有多个请求在处理(类似 CPU 的指令流水线)
  • 精确时序:每帧都有纳秒级时间戳,可以与音频帧精确同步
  • 多路输出:一个 Request 可以同时产生 JPEG(拍照)+ YUV(预览)+ RAW(原始数据)

4.2 多路输出流

Camera2 支持同时配置多路输出流,这是其最重要的能力之一:

java 复制代码
// 典型的三路输出配置:预览 + 拍照 + 视频录制
List<Surface> outputs = new ArrayList<>();

// 1. 预览 Surface(TextureView 或 SurfaceView)
SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(previewWidth, previewHeight);
Surface previewSurface = new Surface(surfaceTexture);
outputs.add(previewSurface);

// 2. 拍照 ImageReader(接收 JPEG 数据)
ImageReader jpegImageReader = ImageReader.newInstance(
    4032, 3024,           // 12MP 分辨率
    ImageFormat.JPEG,
    2                     // Buffer 数量(推荐 2 个,避免卡顿)
);
jpegImageReader.setOnImageAvailableListener(reader -> {
    Image image = reader.acquireLatestImage();
    // 处理 JPEG 数据...
    image.close(); // 必须 close!否则 Buffer 泄漏
}, handler);
outputs.add(jpegImageReader.getSurface());

// 3. 视频录制 Surface(MediaRecorder 或 MediaCodec 提供)
Surface recorderSurface = mediaRecorder.getSurface();
outputs.add(recorderSurface);

// 创建会话(同时支持三路输出)
cameraDevice.createCaptureSession(outputs, stateCallback, handler);

⚠️ 多路流约束 :并非任意组合都被支持。SCALER_STREAM_CONFIGURATION_MAP 定义了哪些格式+尺寸的组合可以同时使用。一般规则:1路大分辨率JPEG + 1路预览 + 1路录像是旗舰机型都支持的标准配置。

4.3 Repeating Request 的精确控制

连续预览的本质是一个无限循环的 setRepeatingRequest,每一帧都执行一次:

vbscript 复制代码
帧1: Request₁ → [Pipeline] → Result₁ + YUVFrame₁
帧2: Request₂ → [Pipeline] → Result₂ + YUVFrame₂  (Request₂ 通常与Request₁相同)
帧3: Request₃ → [Pipeline] → Result₃ + YUVFrame₃
...

当需要改变参数(例如用户点击屏幕触发对焦)时:

java 复制代码
// 触摸对焦示例
// Step 1: 触发 AF(发一帧特殊 Request)
CaptureRequest.Builder afBuilder =
    cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
afBuilder.addTarget(previewSurface);
afBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
    CaptureRequest.CONTROL_AF_TRIGGER_START);  // ← 触发 AF
// 设置 AE/AF 检测区域(触摸位置)
afBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
afBuilder.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
session.capture(afBuilder.build(), captureCallback, handler);

// Step 2: 等待 AF 收敛(通过 captureCallback 监听 CONTROL_AF_STATE)
// Step 3: AF 锁定后拍照

五、Android 15 视频/相机新特性

5.1 Ultra HDR 照片支持

Android 15 正式将 Ultra HDR 带入主流,这是一种可以同时包含 SDR 和 HDR 元数据的 JPEG 格式:

java 复制代码
// 检查是否支持 Ultra HDR 拍照
StreamConfigurationMap map = chars.get(
    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
boolean supportsUltraHdr = false;
int[] formats = map.getOutputFormats();
for (int format : formats) {
    if (format == ImageFormat.JPEG_R) { // JPEG_R 就是 Ultra HDR
        supportsUltraHdr = true;
        break;
    }
}

// 使用 Ultra HDR 拍照
if (supportsUltraHdr) {
    ImageReader ultraHdrReader = ImageReader.newInstance(
        width, height,
        ImageFormat.JPEG_R, // Ultra HDR 格式
        2
    );
    builder.addTarget(ultraHdrReader.getSurface());
}

Ultra HDR 照片在 SDR 显示器上与普通 JPEG 一样显示,但在 HDR 显示器(如旗舰手机屏幕)上可以呈现更高动态范围,且文件兼容性极好(标准 JPEG 格式的超集)。

5.2 10-bit 视频录制(LOG 格式)

Android 15 全面支持 10-bit HDR 视频录制,支持 HLG(Hybrid Log-Gamma)和 HDR10 格式:

java 复制代码
// 查询是否支持 10-bit 视频
boolean supports10Bit = false;
int[] capabilities = chars.get(
    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
for (int cap : capabilities) {
    if (cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
        supports10Bit = true;
        break;
    }
}

if (supports10Bit) {
    // 配置 10-bit HLG 输出
    OutputConfiguration outputConfig = new OutputConfiguration(recorderSurface);
    outputConfig.setDynamicRangeProfile(
        DynamicRangeProfiles.HLG10  // 或 HDR10, HDR10_PLUS
    );
}

10-bit 视频录制对硬件编解码器要求更高,需要同时满足:

  1. 相机传感器支持 10-bit 输出
  2. ISP 支持 10-bit 数据通路
  3. 硬件视频编码器支持 10-bit H.265/AV1

5.3 多摄像头并发支持

Android 11 引入、Android 15 完善的多摄并发(ConcurrentCamera),允许同时开启前置和后置摄像头:

java 复制代码
// 查询支持并发使用的相机组合
Set<Set<String>> concurrentCameraIds = manager.getConcurrentCameraIds();
for (Set<String> cameraSet : concurrentCameraIds) {
    Log.d(TAG, "这些相机可同时使用: " + cameraSet);
    // 通常输出: ["0", "1"] 表示前后置可同时用(用于视频通话等场景)
}

5.4 夜景增强与 Extension API

Android 15 的 Camera Extensions API 提供了系统级的夜景、HDR、散景等拍摄模式,不再需要 App 自己做 ML 处理:

java 复制代码
// 使用 Camera Extensions
CameraExtensionSession.StateCallback extensionStateCallback = ...;

// 创建 Extension Session(替代普通 CameraCaptureSession)
cameraDevice.createExtensionSession(
    new CameraExtensionSessionConfiguration(
        CameraExtensionCharacteristics.EXTENSION_NIGHT,  // 夜景模式
        outputList,
        executor,
        extensionStateCallback
    )
);

六、调试工具速查

6.1 查看相机服务状态

bash 复制代码
# 查看 CameraService 完整状态(相机列表、当前会话、帧率等)
adb shell dumpsys media.camera

# 查看已打开的相机列表和客户端
adb shell dumpsys media.camera | grep -A 5 "Camera module"

# 查看当前活跃的捕获会话
adb shell dumpsys media.camera | grep -A 20 "Active clients"

# 查看相机性能统计(帧率、延迟)
adb shell dumpsys media.camera | grep -E "fps|latency|duration"

6.2 实时日志过滤

bash 复制代码
# 过滤 Camera2 关键日志
adb logcat -s CameraService:V Camera3Device:V CameraDeviceClient:V

# 过滤相机打开/关闭事件
adb logcat | grep -E "openCamera|closeCamera|createSession"

# 过滤 CaptureRequest 发送
adb logcat | grep -E "CaptureRequest|CaptureResult|setRepeatingRequest"

6.3 Systrace 相机性能分析

bash 复制代码
# 使用 Systrace 捕获相机帧率数据
adb shell atrace -b 16384 -t 10 camera hal | gzip > /tmp/camera-trace.gz

# 或使用 Perfetto(更现代的方案)
adb shell perfetto \
  --config - --txt \
  --out /data/local/tmp/camera-trace.pb \
  <<EOF
buffers: { size_kb: 32768 }
data_sources {
  config {
    name: "linux.ftrace"
    ftrace_config {
      ftrace_events: "camera/camera_capture_request_new"
      ftrace_events: "camera/camera_capture_result_received"
    }
  }
}
duration_ms: 5000
EOF

6.4 常见问题诊断

问题1:onConfigureFailed 会话配置失败

bash 复制代码
# 查看失败原因
adb logcat | grep -E "createCaptureSession|ConfigureFailed|stream config"
# 常见原因:
# 1. 请求的输出格式+尺寸组合不被硬件支持
# 2. 同时配置的流数量超出硬件限制
# 3. Surface 在创建会话时已失效(SurfaceTexture/SurfaceHolder 已销毁)

问题2:预览画面黑屏

bash 复制代码
# 检查会话是否正常启动
adb shell dumpsys media.camera | grep -A 10 "Active streams"
# 常见原因:
# 1. setRepeatingRequest 没有调用
# 2. Surface 尺寸与 SurfaceTexture 设置不匹配
# 3. 相机权限被拒绝

问题3:拍照延迟过高(快门慢)

bash 复制代码
# 查看 Camera3Device 的请求队列深度
adb shell dumpsys media.camera | grep -E "In-flight|requestId"
# 优化方案:
# 1. 预先触发 AF/AE(precapture sequence)
# 2. 使用 ZSL(Zero Shutter Lag)模式
# 3. 降低预览分辨率减少管线处理压力

七、Camera2 的设计思想总结

回顾 Camera2 的整体设计,有几个思想值得反复品味:

7.1 Pipeline 胜于命令

Camera1 是"发命令、等结果",Camera2 是"描述管道、让数据流动"。Pipeline 模型天然支持异步、多路输出和精确时序控制,这是现代相机 APP(专业相机、视频创作)所必需的。

7.2 分层解耦

  • Java 层:API 契约,面向开发者
  • Native 层:性能关键路径,C++ 实现
  • HAL 层:硬件解耦,芯片商自由实现

这种分层确保了 Android 相机框架不依赖特定硬件,同时性能也不会被 Java 层拖累。

7.3 元数据驱动

CaptureRequest 和 CaptureResult 本质上都是 Key-Value 元数据表,相机参数通过元数据流传递而非硬编码接口。这带来了极强的可扩展性------新的控制参数(如 Ultra HDR、10-bit 等)只需新增 Key,无需修改接口。


总结

本文介绍了 Android 15 Camera2 API 的整体架构和核心概念:

  1. Camera2 vs Camera1:从命令式→流水线式,支持多路输出、精细 3A 控制、纳秒级时间戳
  2. 五层架构:Java API → Java Framework → CameraService(Native)→ Camera HAL3 → 驱动/硬件
  3. 五大核心类
    • CameraManager:相机管理入口
    • CameraCharacteristics:静态特性查询
    • CameraDevice:已打开的相机设备
    • CameraCaptureSession:流配置和请求发送
    • CaptureRequest/Result:每帧的控制参数和实际结果
  4. Pipeline 模型:多路并发流水线,多路输出同时支持
  5. Android 15 新特性:Ultra HDR、10-bit 视频、多摄并发、Extension API 夜景增强

理解 Camera2 架构,是后续深入 CameraService 资源管理、相机预览流程、HAL3 接口的基础。


参考资料

  • Android Camera Architecture --- 官方架构文档
  • Camera2 API Overview --- Android 开发者文档
  • frameworks/base/core/java/android/hardware/camera2/CameraManager.java --- CameraManager 源码
  • frameworks/base/core/java/android/hardware/camera2/CameraDevice.java --- CameraDevice 源码
  • frameworks/base/core/java/android/hardware/camera2/CameraCaptureSession.java --- Session 源码
  • frameworks/av/services/camera/libcameraservice/CameraService.cpp --- CameraService Native 实现
相关推荐
hnlgzb2 小时前
安卓app kotlin语法,Hilt是什么东西?
android·开发语言·kotlin
Android系统攻城狮4 小时前
Android tinyalsa深度解析之pcm_params_get_periods_min调用流程与实战(一百七十三)
android·pcm·tinyalsa·音频进阶手册
Xempastissimo5 小时前
Android常见界面控件
android
法欧特斯卡雷特5 小时前
从 Kotlin 编译器 API 的变化开始: 2.3.20
android·后端·开源
词元Max6 小时前
1.5 Harness 架构深度解析:Claude Code 为什么强?
android·架构
yy55276 小时前
Mysql 主从复制与读写分离
android·数据库·mysql
zhenxin01227 小时前
万字详解 MySQL MGR 高可用集群搭建
android·mysql·adb
做萤石二次开发的哈哈7 小时前
萤石云硬件接入如何完成云对讲套件低代码集成?
android·低代码·rxjava
恋猫de小郭9 小时前
2026 AI 时代下,Flutter 和 Dart 的机遇和未来发展,AI 一体化
android·前端·flutter