Android CameraServer PreviewFrameSpacer梳理
PreviewFrameSpacer 设计与实现
文件位置:device3/PreviewFrameSpacer.h/PreviewFrameSpacer.cpp
1. 问题背景
理想情况下,预览帧应按传感器输出节奏呈现给用户。但实际中,CPU 负载、请求设置差异等因素导致帧处理延迟不均匀,造成预览帧间距忽大忽小,用户感知到卡顿。
2. 核心设计
PreviewFrameSpacer 继承Thread,运行在独立线程中:
Camera3OutputStream::returnBufferCheckedLocked() │ (HAL 返回 buffer) ▼ PreviewFrameSpacer::queuePreviewBuffer() │ 入队到 mPendingBuffers ▼ PreviewFrameSpacer::threadLoop() [独立线程] ├── 等待 buffer 到达 ├── 计算 readoutInterval = 当前帧 readoutTimestamp - 上一帧 readoutTimestamp ├── if readoutInterval >= 80ms: 直接入队(帧间距过大,不等待) ├── else: 按 readoutInterval 节奏等待后入队 └── queueBufferToClientLocked() → mConsumer->queueBuffer()3. 关键常量
| 常量 | 值 | 含义 |
|---|---|---|
kWaitDuration | 50ms | 无 buffer 时的等待超时 |
kFrameIntervalThreshold | 80ms | 帧间距阈值,超过则直接入队 |
kMaxFrameWaitTime | 10ms | 最大等待时间,避免过度延迟 |
kFrameAdjustThreshold | 2ms | 提前量,补偿代码执行时间 |
4. threadLoop() 核心逻辑
boolPreviewFrameSpacer::threadLoop(){// 1. 无 buffer 时等待 50msif(mPendingBuffers.empty()){mBufferCond.waitRelative(mLock,kWaitDuration);returntrue;}// 2. 计算与上一帧的 readout 间隔nsecs_t readoutInterval=buffer.readoutTimestamp-mLastCameraReadoutTime;// 3. 间隔 >= 80ms: 直接入队(非连续预览帧)if(readoutInterval>=kFrameIntervalThreshold){queueBufferToClientLocked(buffer,currentTime);returntrue;