2. 预览流性能调优
任务说明
本案例针对Android相机HAL层预览流延迟问题,通过两项核心调整——缓冲区管理与线程优先级——实现端到端延迟的降低。你将基于一个最小可复现的HAL预览流实现,完成以下目标:
- 实现预览请求的缓冲区提前排队机制,减少帧等待时间;
- 将预览流处理线程设置为实时优先级,降低调度延迟;
- 通过时间戳测量验证端到端延迟的改善。
核心实现
// preview_latency_optimizer.h
#ifndef PREVIEW_LATENCY_OPTIMIZER_H
#define PREVIEW_LATENCY_OPTIMIZER_H
#include <system/camera_metadata.h>
#include <utils/Mutex.h>
#include <utils/Thread.h>
#include <list>
#include <chrono>
namespace android {
// 预览流延迟优化器
class PreviewLatencyOptimizer : public Thread {
public:
PreviewLatencyOptimizer();
~PreviewLatencyOptimizer();
// 初始化缓冲区池和线程参数
status_t initialize(size_t bufferCount, int priority);
// 提交预览请求(由HAL调用)
status_t submitPreviewRequest(buffer_handle_t buffer, nsecs_t timestamp);
// 获取当前平均端到端延迟(纳秒)
nsecs_t getAverageLatency() const;
// 线程循环
virtual bool threadLoop() override;
private:
// 缓冲区提前排队:维护待处理请求队列
struct PendingRequest {
buffer_handle_t buffer;
nsecs_t requestTime;
};
std::list<PendingRequest> mPendingQueue;
Mutex mQueueLock;
Condition mQueueCond;
// 延迟统计
mutable Mutex mLatencyLock;
nsecs_t mTotalLatencyNs;
size_t mFrameCount;
// 配置参数
size_t mBufferCount;
int mThreadPriority;
// 处理单个预览请求
void processRequest(const PendingRequest& req);
};
} // namespace android
#endif // PREVIEW_LATENCY_OPTIMIZER_H
// preview_latency_optimizer.cpp
#include "preview_latency_optimizer.h"
#include <utils/Log.h>
#include <cutils/sched_policy.h>
#include <sys/resource.h>
namespace android {
PreviewLatencyOptimizer::PreviewLatencyOptimizer()
: Thread(/*canCallJava*/ false),
mTotalLatencyNs(0),
mFrameCount(0),
mBufferCount(0),
mThreadPriority(0) {}
PreviewLatencyOptimizer::~PreviewLatencyOptimizer() {
requestExit();
}
status_t PreviewLatencyOptimizer::initialize(size_t bufferCount, int priority) {
mBufferCount = bufferCount;
mThreadPriority = priority;
// 启动处理线程
status_t err = run("preview_latency_opt", priority);
if (err != OK) {
ALOGE("Failed to start preview latency optimizer thread: %d", err);
return err;
}
// 设置线程调度策略为实时(需要root或相应权限)
if (priority > 0) {
set_sched_policy(getTid(), SP_FOREGROUND);
setpriority(PRIO_PROCESS, getTid(), priority);
}
return OK;
}
status_t PreviewLatencyOptimizer::submitPreviewRequest(buffer_handle_t buffer, nsecs_t timestamp) {
Mutex::Autolock lock(mQueueLock);
// 缓冲区管理:当队列满时丢弃最旧请求,保证延迟可控
if (mPendingQueue.size() >= mBufferCount) {
mPendingQueue.pop_front();
ALOGV("Preview queue full, dropping oldest request");
}
PendingRequest req;
req.buffer = buffer;
req.requestTime = timestamp;
mPendingQueue.push_back(req);
mQueueCond.signal();
return OK;
}
nsecs_t PreviewLatencyOptimizer::getAverageLatency() const {
Mutex::Autolock lock(mLatencyLock);
if (mFrameCount == 0) return 0;
return mTotalLatencyNs / mFrameCount;
}
bool PreviewLatencyOptimizer::threadLoop() {
Mutex::Autolock lock(mQueueLock);
while (mPendingQueue.empty()) {
mQueueCond.wait(mQueueLock);
}
PendingRequest req = mPendingQueue.front();
mPendingQueue.pop_front();
lock.unlock();
processRequest(req);
return true;
}
void PreviewLatencyOptimizer::processRequest(const PendingRequest& req) {
// 模拟帧处理完成时间点
nsecs_t completionTime = systemTime(SYSTEM_TIME_MONOTONIC);
nsecs_t latency = completionTime - req.requestTime;
// 更新延迟统计
Mutex::Autolock lock(mLatencyLock);
mTotalLatencyNs += latency;
mFrameCount++;
}
} // namespace android
// 测试驱动:验证延迟优化效果
#include "preview_latency_optimizer.h"
#include <utils/SystemClock.h>
#include <cstdio>
using namespace android;
int main() {
PreviewLatencyOptimizer optimizer;
// 初始化:4个缓冲区,线程优先级-8(实时范围-20~19)
if (optimizer.initialize(4, -8) != OK) {
printf("Failed to initialize optimizer\n");
return -1;
}
// 模拟提交20帧预览请求,间隔10ms
const int kFrameCount = 20;
const nsecs_t kFrameIntervalMs = 10;
for (int i = 0; i < kFrameCount; i++) {
nsecs_t requestTime = systemTime(SYSTEM_TIME_MONOTONIC);
optimizer.submitPreviewRequest(nullptr, requestTime);
usleep(kFrameIntervalMs * 1000);
}
// 等待所有请求处理完成
usleep(500 * 1000);
// 输出平均延迟
nsecs_t avgLatency = optimizer.getAverageLatency();
printf("Average preview latency: %.2f ms\n", avgLatency / 1000000.0);
return 0;
}
编译与运行
# 编译(需Android源码环境或NDK)
c++ -std=c++17 -I./include \
preview_latency_optimizer.cpp test_preview_latency.cpp \
-lutils -lcutils -lpthread \
-o preview_latency_test
# 运行(需要root权限以设置实时优先级)
adb root
adb push preview_latency_test /data/local/tmp/
adb shell /data/local/tmp/preview_latency_test
验证方法与判定标准
运行测试程序后,观察输出结果。判定标准如下:
- 功能正确性:程序正常退出,无崩溃或死锁;
- 延迟指标:平均延迟应小于帧间隔(10ms),即输出值应小于10.00ms。若大于该值,说明缓冲区排队或线程优先级设置未生效;
- 缓冲区管理验证:在代码中增加日志输出(ALOGV),观察当提交速度超过处理速度时,队列是否按预期丢弃最旧请求,且不出现内存泄漏或野指针;
- 线程优先级验证:在运行期间通过
cat /proc/<pid>/task/<tid>/stat查看线程优先级,确认其nice值已设置为-8。
若以上条件均满足,则说明通过缓冲区提前排队和实时线程优先级调整,预览流端到端延迟已得到有效控制。实际部署到相机HAL时,可将submitPreviewRequest接入HAL的processCaptureRequest入口,并将processRequest替换为真实的帧处理逻辑。