鸿蒙相机预览功能全面实现:从基础到高级应用
1. 相机预览功能概述与架构设计
1.1 预览功能在相机应用中的核心地位
相机预览是用户与相机应用交互的第一界面,它不仅仅是简单的画面显示,更是整个相机系统的性能瓶颈和用户体验的关键点。一个优秀的预览实现需要平衡性能、功耗和画质。
预览功能的核心价值:
- 实时反馈:为用户提供即时的拍摄画面反馈
- 交互基础:对焦、曝光、手势操作等功能的载体
- 性能指标:直接影响应用的响应速度和流畅度
- 用户体验:决定用户对相机应用的第一印象
1.2 预览系统架构深度解析
鸿蒙相机预览采用Surface模型,其核心架构如下:
Camera Hardware → Camera HDI → Camera Service → PreviewOutput → Surface → XComponent
数据流向详解:
- 相机硬件采集原始图像数据
- 通过HDI层进行初步处理
- 相机服务管理数据流和权限
- PreviewOutput将数据写入Surface
- XComponent从Surface读取并渲染数据
2. XComponent与Surface深度集成
2.1 XComponent组件深度解析
XComponent是鸿蒙系统中用于高性能图形渲染的核心组件,它提供了与底层图形系统的直接交互能力。
XComponent的核心特性:
- 低延迟渲染:直接与Surface对接,减少中间层
- 硬件加速:利用GPU进行高效渲染
- 灵活控制:支持自定义渲染逻辑
- 多场景适配:适应不同屏幕尺寸和比例
2.2 完整的XComponent实现方案
import { XComponentController, XComponent, XComponentType } from '@ohos.arkui.xcomponent';
import { UIContext } from '@ohos.arkui.UIContext';
@Entry
@Component
struct AdvancedCameraPreview {
private xComponentController: XComponentController = new XComponentController();
private surfaceId: string = '';
// 预览尺寸状态管理
@State previewWidth: number = 1920;
@State previewHeight: number = 1080;
@State aspectRatio: number = 16 / 9;
// 预览状态
@State isPreviewActive: boolean = false;
@State previewStatus: string = 'initializing';
private uiContext: UIContext = this.getUIContext();
private previewManager: PreviewManager | null = null;
build() {
Column() {
// 预览状态指示器
Row() {
Text(`预览状态: ${this.previewStatus}`)
.fontSize(14)
.fontColor(this.getStatusColor())
.padding(8)
.backgroundColor('#CC000000')
.borderRadius(4)
}
.width('100%')
.justifyContent(FlexAlign.Start)
.padding(10)
// 相机预览区域
Stack() {
XComponent({
id: 'camera_preview_surface',
type: XComponentType.SURFACE,
controller: this.xComponentController
})
.onLoad(() => {
this.onXComponentLoad();
})
.onDestroy(() => {
this.onXComponentDestroy();
})
.width(this.getComponentWidth())
.height(this.getComponentHeight())
.backgroundColor('#000000')
.border({ width: 2, color: this.isPreviewActive ? '#00FF00' : '#FF0000' })
// 网格辅助线(可选)
if (this.showGrid) {
this.buildGridOverlay()
}
// 对焦区域指示(可选)
if (this.focusArea) {
this.buildFocusIndicator()
}
}
.width('100%')
.aspectRatio(this.aspectRatio)
.layoutWeight(1)
.onTouch((event: TouchEvent) => {
this.handlePreviewTouch(event);
})
// 预览控制面板
this.buildPreviewControls()
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
.onPageShow(() => {
this.onPageShow();
})
.onPageHide(() => {
this.onPageHide();
})
}
// XComponent加载完成回调
private async onXComponentLoad(): Promise<void> {
try {
this.surfaceId = this.xComponentController.getXComponentSurfaceId();
console.info(`XComponent SurfaceId obtained: ${this.surfaceId}`);
// 设置Surface显示区域
await this.setSurfaceRect();
// 初始化预览管理器
this.previewManager = new PreviewManager(this.surfaceId);
// 开始预览
await this.startPreview();
} catch (error) {
console.error(`XComponent load failed: ${error.message}`);
this.previewStatus = 'failed';
}
}
// 设置Surface显示区域
private async setSurfaceRect(): Promise<void> {
const surfaceRect: SurfaceRect = {
surfaceWidth: this.previewWidth,
surfaceHeight: this.previewHeight
};
try {
this.xComponentController.setXComponentSurfaceRect(surfaceRect);
console.info('Surface rect set successfully');
} catch (error) {
console.error(`Set surface rect failed: ${error.message}`);
}
}
// 计算组件宽度
private getComponentWidth(): Length {
return '100%';
}
// 计算组件高度
private getComponentHeight(): Length {
return this.uiContext.px2vp(this.previewHeight * (this.previewWidth / 360));
}
// 获取状态颜色
private getStatusColor(): Color {
switch (this.previewStatus) {
case 'active': return Color.Green;
case 'initializing': return Color.Orange;
case 'failed': return Color.Red;
default: return Color.Gray;
}
}
// 构建网格覆盖层
@Builder
private buildGridOverlay() {
Canvas(this.uiContext)
.width('100%')
.height('100%')
.onReady(() => {
// 绘制网格线
})
}
// 构建对焦指示器
@Builder
private buildFocusIndicator() {
// 对焦区域UI实现
}
// 构建预览控制面板
@Builder
private buildPreviewControls() {
Row({ space: 20 }) {
Button('切换相机')
.onClick(() => this.switchCamera())
Button(this.isPreviewActive ? '停止预览' : '开始预览')
.onClick(() => this.togglePreview())
Button('调整比例')
.onClick(() => this.changeAspectRatio())
}
.padding(20)
.width('100%')
.justifyContent(FlexAlign.Center)
}
// 处理预览区域触摸事件
private handlePreviewTouch(event: TouchEvent): void {
if (event.type === TouchType.Down) {
const touchX = event.touches[0].x;
const touchY = event.touches[0].y;
// 转换为归一化坐标(0-1)
const normalizedX = touchX / this.previewWidth;
const normalizedY = touchY / this.previewHeight;
this.handleFocus(normalizedX, normalizedY);
}
}
// 对焦处理
private handleFocus(x: number, y: number): void {
if (this.previewManager) {
this.previewManager.setFocusArea(x, y);
}
}
// 页面显示时恢复预览
private async onPageShow(): Promise<void> {
if (this.surfaceId && this.previewManager) {
await this.startPreview();
}
}
// 页面隐藏时停止预览
private async onPageHide(): Promise<void> {
await this.stopPreview();
}
// XComponent销毁时清理资源
private onXComponentDestroy(): void {
this.cleanup();
}
// 开始预览
private async startPreview(): Promise<void> {
if (!this.previewManager) return;
try {
this.previewStatus = 'initializing';
await this.previewManager.startPreview();
this.isPreviewActive = true;
this.previewStatus = 'active';
} catch (error) {
console.error(`Start preview failed: ${error.message}`);
this.previewStatus = 'failed';
}
}
// 停止预览
private async stopPreview(): Promise<void> {
if (!this.previewManager) return;
try {
await this.previewManager.stopPreview();
this.isPreviewActive = false;
this.previewStatus = 'stopped';
} catch (error) {
console.error(`Stop preview failed: ${error.message}`);
}
}
// 切换相机
private async switchCamera(): Promise<void> {
await this.stopPreview();
// 实现相机切换逻辑
await this.startPreview();
}
// 切换预览状态
private async togglePreview(): Promise<void> {
if (this.isPreviewActive) {
await this.stopPreview();
} else {
await this.startPreview();
}
}
// 改变宽高比
private async changeAspectRatio(): Promise<void> {
// 循环切换宽高比
const ratios = [4/3, 16/9, 1/1, 21/9];
const currentIndex = ratios.indexOf(this.aspectRatio);
const nextIndex = (currentIndex + 1) % ratios.length;
this.aspectRatio = ratios[nextIndex];
await this.restartPreviewWithNewRatio();
}
// 使用新比例重启预览
private async restartPreviewWithNewRatio(): Promise<void> {
await this.stopPreview();
// 根据新比例重新配置预览
await this.startPreview();
}
// 清理资源
private async cleanup(): Promise<void> {
await this.stopPreview();
if (this.previewManager) {
await this.previewManager.release();
this.previewManager = null;
}
}
}
// SurfaceRect接口定义
interface SurfaceRect {
surfaceWidth: number;
surfaceHeight: number;
}
3. 预览管理器深度实现
3.1 PreviewOutput的高级配置与管理
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
class PreviewManager {
private previewOutput: camera.PreviewOutput | null = null;
private surfaceId: string;
private isPreviewing: boolean = false;
// 预览状态监听器
private frameStartListener: ((err: BusinessError) => void) | null = null;
private frameEndListener: ((err: BusinessError) => void) | null = null;
private errorListener: ((error: BusinessError) => void) | null = null;
constructor(surfaceId: string) {
this.surfaceId = surfaceId;
}
// 创建预览输出流
async createPreviewOutput(
cameraManager: camera.CameraManager,
capability: camera.CameraOutputCapability,
targetWidth: number,
targetHeight: number
): Promise<boolean> {
try {
const previewProfile = this.selectOptimalPreviewProfile(
capability.previewProfiles,
targetWidth,
targetHeight
);
if (!previewProfile) {
console.error('No suitable preview profile found');
return false;
}
this.previewOutput = cameraManager.createPreviewOutput(previewProfile, this.surfaceId);
// 设置预览监听器
this.setupPreviewListeners();
console.info('PreviewOutput created successfully');
return true;
} catch (error) {
console.error(`Create PreviewOutput failed: ${(error as BusinessError).message}`);
return false;
}
}
// 选择最优预览配置
private selectOptimalPreviewProfile(
profiles: Array<camera.Profile>,
targetWidth: number,
targetHeight: number
): camera.Profile | null {
if (!profiles || profiles.length === 0) {
return null;
}
const targetRatio = targetWidth / targetHeight;
let bestProfile: camera.Profile | null = null;
let bestScore = -1;
for (const profile of profiles) {
let score = 0;
// 计算比例匹配度
const profileRatio = profile.size.width / profile.size.height;
const ratioDiff = Math.abs(profileRatio - targetRatio);
const ratioScore = 1 - Math.min(ratioDiff, 1);
// 计算分辨率匹配度(倾向于选择更高分辨率)
const resolutionScore = Math.min(
profile.size.width / targetWidth,
profile.size.height / targetHeight
);
// 格式偏好(优先选择常用格式)
const formatScore = this.getFormatScore(profile.format);
// 综合评分
score = ratioScore * 0.4 + resolutionScore * 0.4 + formatScore * 0.2;
if (score > bestScore) {
bestScore = score;
bestProfile = profile;
}
}
if (bestProfile) {
console.info(`Selected preview profile: ${bestProfile.size.width}x${bestProfile.size.height}, format: ${bestProfile.format}`);
}
return bestProfile;
}
// 获取格式评分
private getFormatScore(format: number): number {
switch (format) {
case camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP: // NV21
return 1.0;
case camera.CameraFormat.CAMERA_FORMAT_YCBCR_P010: // P010
return 0.8;
case camera.CameraFormat.CAMERA_FORMAT_RGBA_8888: // RGBA
return 0.6;
default:
return 0.5;
}
}
// 设置预览监听器
private setupPreviewListeners(): void {
if (!this.previewOutput) return;
// 帧开始监听
this.frameStartListener = (err: BusinessError) => {
if (err) {
console.error(`Frame start error: ${err.code}`);
return;
}
console.info('Preview frame started');
this.onFrameStart();
};
this.previewOutput.on('frameStart', this.frameStartListener);
// 帧结束监听
this.frameEndListener = (err: BusinessError) => {
if (err) {
console.error(`Frame end error: ${err.code}`);
return;
}
console.info('Preview frame ended');
this.onFrameEnd();
};
this.previewOutput.on('frameEnd', this.frameEndListener);
// 错误监听
this.errorListener = (error: BusinessError) => {
console.error(`Preview output error: ${error.code}`);
this.onPreviewError(error);
};
this.previewOutput.on('error', this.errorListener);
}
// 帧开始回调
private onFrameStart(): void {
// 可以在这里添加帧率统计、性能监控等
this.updateFrameStatistics();
}
// 帧结束回调
private onFrameEnd(): void {
// 帧处理完成后的清理工作
}
// 预览错误处理
private onPreviewError(error: BusinessError): void {
switch (error.code) {
case 5400101:
console.error('Preview surface not available');
break;
case 5400102:
console.error('Preview configuration error');
break;
case 5400103:
console.error('Preview buffer queue error');
break;
default:
console.error(`Unknown preview error: ${error.code}`);
}
// 尝试恢复预览
this.attemptPreviewRecovery();
}
// 尝试恢复预览
private attemptPreviewRecovery(): void {
console.info('Attempting preview recovery...');
// 实现预览恢复逻辑
}
// 更新帧率统计
private updateFrameStatistics(): void {
// 实现帧率监控逻辑
}
// 开始预览
async startPreview(): Promise<void> {
if (this.isPreviewing) {
console.warn('Preview is already active');
return;
}
this.isPreviewing = true;
console.info('Preview started');
}
// 停止预览
async stopPreview(): Promise<void> {
if (!this.isPreviewing) {
return;
}
this.isPreviewing = false;
console.info('Preview stopped');
}
// 设置对焦区域
async setFocusArea(x: number, y: number): Promise<void> {
if (!this.previewOutput) return;
// 将对焦区域坐标转换为相机坐标系
// 实际实现需要结合Session进行对焦设置
console.info(`Setting focus area: (${x}, ${y})`);
}
// 释放资源
async release(): Promise<void> {
await this.stopPreview();
// 移除监听器
if (this.previewOutput) {
if (this.frameStartListener) {
this.previewOutput.off('frameStart', this.frameStartListener);
}
if (this.frameEndListener) {
this.previewOutput.off('frameEnd', this.frameEndListener);
}
if (this.errorListener) {
this.previewOutput.off('error', this.errorListener);
}
await this.previewOutput.release();
this.previewOutput = null;
}
console.info('PreviewManager released');
}
}
4. 多路预览高级实现
4.1 双路预览架构设计
双路预览允许同时使用两个预览流,一路用于显示,一路用于图像处理或其他用途。
import { image } from '@kit.ImageKit';
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
class DualPreviewManager {
private displayPreview: PreviewManager; // 显示用预览
private processingPreview: PreviewManager; // 处理用预览
private imageReceiver: image.ImageReceiver | null = null;
private isActive: boolean = false;
private processingCallback: ((pixelMap: image.PixelMap) => void) | null = null;
constructor(displaySurfaceId: string, processingSurfaceId: string) {
this.displayPreview = new PreviewManager(displaySurfaceId);
this.processingPreview = new PreviewManager(processingSurfaceId);
}
// 初始化双路预览
async initialize(
cameraManager: camera.CameraManager,
capability: camera.CameraOutputCapability,
displayConfig: { width: number; height: number },
processingConfig: { width: number; height: number }
): Promise<boolean> {
try {
// 初始化显示预览
const displaySuccess = await this.displayPreview.createPreviewOutput(
cameraManager,
capability,
displayConfig.width,
displayConfig.height
);
// 初始化处理预览
const processingSuccess = await this.processingPreview.createPreviewOutput(
cameraManager,
capability,
processingConfig.width,
processingConfig.height
);
if (!displaySuccess || !processingSuccess) {
console.error('Failed to initialize dual preview');
return false;
}
// 初始化图像接收器用于处理预览数据
await this.initializeImageReceiver(processingConfig.width, processingConfig.height);
console.info('Dual preview initialized successfully');
return true;
} catch (error) {
console.error(`Dual preview initialization failed: ${(error as BusinessError).message}`);
return false;
}
}
// 初始化图像接收器
private async initializeImageReceiver(width: number, height: number): Promise<void> {
try {
const size: image.Size = { width, height };
this.imageReceiver = image.createImageReceiver(size, image.ImageFormat.JPEG, 8);
const processingSurfaceId = await this.imageReceiver.getReceivingSurfaceId();
// 重新配置处理预览使用ImageReceiver的Surface
// 这里需要重新创建PreviewOutput,实际实现中需要考虑会话管理
// 设置图像到达监听
this.setupImageArrivalListener();
console.info('ImageReceiver initialized successfully');
} catch (error) {
console.error(`ImageReceiver initialization failed: ${(error as BusinessError).message}`);
}
}
// 设置图像到达监听
private setupImageArrivalListener(): void {
if (!this.imageReceiver) return;
this.imageReceiver.on('imageArrival', () => {
this.handleImageArrival();
});
}
// 处理图像到达
private async handleImageArrival(): Promise<void> {
if (!this.imageReceiver) return;
this.imageReceiver.readNextImage((err: BusinessError, nextImage: image.Image) => {
if (err || !nextImage) {
console.error('Read next image failed');
return;
}
this.processImage(nextImage);
});
}
// 处理图像数据
private async processImage(img: image.Image): Promise<void> {
try {
// 获取图像组件
img.getComponent(image.ComponentType.JPEG, async (err: BusinessError, imgComponent: image.Component) => {
if (err || !imgComponent) {
console.error('Get image component failed');
img.release();
return;
}
if (imgComponent.byteBuffer) {
// 创建PixelMap进行处理
const pixelMap = await image.createPixelMap(imgComponent.byteBuffer, {
size: { width: img.size.width, height: img.size.height },
srcPixelFormat: image.PixelMapFormat.RGBA_8888
});
// 调用处理回调
if (this.processingCallback) {
this.processingCallback(pixelMap);
}
// 释放PixelMap(根据业务需求决定)
// pixelMap.release();
}
// 释放图像资源
img.release();
});
} catch (error) {
console.error(`Image processing failed: ${(error as BusinessError).message}`);
img.release();
}
}
// 设置处理回调
setProcessingCallback(callback: (pixelMap: image.PixelMap) => void): void {
this.processingCallback = callback;
}
// 开始双路预览
async startDualPreview(): Promise<void> {
if (this.isActive) return;
await this.displayPreview.startPreview();
await this.processingPreview.startPreview();
this.isActive = true;
console.info('Dual preview started');
}
// 停止双路预览
async stopDualPreview(): Promise<void> {
if (!this.isActive) return;
await this.displayPreview.stopPreview();
await this.processingPreview.stopPreview();
this.isActive = false;
console.info('Dual preview stopped');
}
// 释放资源
async release(): Promise<void> {
await this.stopDualPreview();
await this.displayPreview.release();
await this.processingPreview.release();
if (this.imageReceiver) {
// ImageReceiver的释放逻辑
}
console.info('DualPreviewManager released');
}
}
5. 会话管理与预览集成
5.1 高级会话管理器
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
class AdvancedSessionManager {
private session: camera.PhotoSession | null = null;
private cameraInput: camera.CameraInput | null = null;
private previewOutputs: Array<camera.PreviewOutput> = [];
private isConfigured: boolean = false;
private isStarted: boolean = false;
// 创建并配置会话
async createAndConfigureSession(
cameraManager: camera.CameraManager,
cameraInput: camera.CameraInput,
previewOutputs: Array<camera.PreviewOutput>,
photoOutput?: camera.PhotoOutput
): Promise<boolean> {
try {
this.cameraInput = cameraInput;
this.previewOutputs = previewOutputs;
// 创建会话
this.session = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
// 开始配置
this.session.beginConfig();
// 添加相机输入
this.session.addInput(cameraInput);
// 添加预览输出
for (const previewOutput of previewOutputs) {
this.session.addOutput(previewOutput);
}
// 添加拍照输出(如果提供)
if (photoOutput) {
this.session.addOutput(photoOutput);
}
// 提交配置
await this.session.commitConfig();
this.isConfigured = true;
console.info('Session configured successfully');
return true;
} catch (error) {
console.error(`Session configuration failed: ${(error as BusinessError).message}`);
this.cleanup();
return false;
}
}
// 启动会话
async startSession(): Promise<boolean> {
if (!this.session || !this.isConfigured) {
console.error('Session not configured');
return false;
}
try {
await this.session.start();
this.isStarted = true;
console.info('Session started successfully');
return true;
} catch (error) {
console.error(`Session start failed: ${(error as BusinessError).message}`);
return false;
}
}
// 停止会话
async stopSession(): Promise<void> {
if (!this.session || !this.isStarted) {
return;
}
try {
await this.session.stop();
this.isStarted = false;
console.info('Session stopped successfully');
} catch (error) {
console.error(`Session stop failed: ${(error as BusinessError).message}`);
}
}
// 设置闪光灯模式
async setFlashMode(mode: camera.FlashMode): Promise<void> {
if (!this.session) return;
try {
if (this.session.isFlashModeSupported(mode)) {
this.session.setFlashMode(mode);
console.info(`Flash mode set to: ${mode}`);
} else {
console.warn(`Flash mode ${mode} not supported`);
}
} catch (error) {
console.error(`Set flash mode failed: ${(error as BusinessError).message}`);
}
}
// 设置对焦模式
async setFocusMode(mode: camera.FocusMode): Promise<void> {
if (!this.session) return;
try {
if (this.session.isFocusModeSupported(mode)) {
this.session.setFocusMode(mode);
console.info(`Focus mode set to: ${mode}`);
} else {
console.warn(`Focus mode ${mode} not supported`);
}
} catch (error) {
console.error(`Set focus mode failed: ${(error as BusinessError).message}`);
}
}
// 设置变焦比例
async setZoomRatio(ratio: number): Promise<void> {
if (!this.session) return;
try {
const zoomRange = this.session.getZoomRatioRange();
const validRatio = Math.max(zoomRange[0], Math.min(ratio, zoomRange[1]));
this.session.setZoomRatio(validRatio);
console.info(`Zoom ratio set to: ${validRatio}`);
} catch (error) {
console.error(`Set zoom ratio failed: ${(error as BusinessError).message}`);
}
}
// 获取会话状态
getSessionStatus(): { isConfigured: boolean; isStarted: boolean } {
return {
isConfigured: this.isConfigured,
isStarted: this.isStarted
};
}
// 清理资源
async cleanup(): Promise<void> {
await this.stopSession();
if (this.session) {
try {
await this.session.release();
this.session = null;
} catch (error) {
console.error(`Session release failed: ${(error as BusinessError).message}`);
}
}
this.isConfigured = false;
this.isStarted = false;
console.info('SessionManager cleaned up');
}
}
6. 预览性能优化与监控
6.1 性能监控系统
class PreviewPerformanceMonitor {
private frameCount: number = 0;
private lastFrameTime: number = 0;
private currentFPS: number = 0;
private frameTimes: number[] = [];
private readonly maxFrameSamples: number = 60;
// 帧开始回调
onFrameStart(): void {
const currentTime = Date.now();
if (this.lastFrameTime > 0) {
const frameTime = currentTime - this.lastFrameTime;
this.frameTimes.push(frameTime);
// 保持样本数量
if (this.frameTimes.length > this.maxFrameSamples) {
this.frameTimes.shift();
}
// 计算当前FPS
this.calculateFPS();
}
this.lastFrameTime = currentTime;
this.frameCount++;
}
// 计算FPS
private calculateFPS(): void {
if (this.frameTimes.length === 0) return;
const averageFrameTime = this.frameTimes.reduce((a, b) => a + b) / this.frameTimes.length;
this.currentFPS = 1000 / averageFrameTime;
}
// 获取性能数据
getPerformanceData(): PreviewPerformanceData {
return {
fps: this.currentFPS,
frameCount: this.frameCount,
averageFrameTime: this.frameTimes.length > 0 ?
this.frameTimes.reduce((a, b) => a + b) / this.frameTimes.length : 0,
frameTimeHistory: [...this.frameTimes]
};
}
// 重置监控数据
reset(): void {
this.frameCount = 0;
this.lastFrameTime = 0;
this.currentFPS = 0;
this.frameTimes = [];
}
}
// 性能数据结构
interface PreviewPerformanceData {
fps: number;
frameCount: number;
averageFrameTime: number;
frameTimeHistory: number[];
}
6.2 高级错误处理与恢复
class PreviewErrorHandler {
private errorCount: number = 0;
private lastErrorTime: number = 0;
private readonly maxErrors: number = 5;
private readonly errorWindow: number = 10000; // 10秒
// 处理预览错误
handlePreviewError(error: BusinessError, context: string): ErrorHandlingStrategy {
this.errorCount++;
this.lastErrorTime = Date.now();
console.error(`Preview error in ${context}: code=${error.code}, message=${error.message}`);
// 检查错误频率
if (this.isErrorRateTooHigh()) {
return ErrorHandlingStrategy.STOP_AND_RECOVER;
}
// 根据错误码选择处理策略
return this.getHandlingStrategy(error.code);
}
// 检查错误频率是否过高
private isErrorRateTooHigh(): boolean {
const timeSinceLastError = Date.now() - this.lastErrorTime;
return this.errorCount >= this.maxErrors && timeSinceLastError < this.errorWindow;
}
// 获取处理策略
private getHandlingStrategy(errorCode: number): ErrorHandlingStrategy {
switch (errorCode) {
case 5400101: // 表面不可用
case 5400102: // 配置错误
return ErrorHandlingStrategy.RECONFIGURE;
case 5400103: // 缓冲区错误
return ErrorHandlingStrategy.RESTART;
case 5400104: // 设备错误
return ErrorHandlingStrategy.STOP_AND_RECOVER;
default:
return ErrorHandlingStrategy.CONTINUE;
}
}
// 重置错误计数
resetErrorCount(): void {
this.errorCount = 0;
this.lastErrorTime = 0;
}
}
// 错误处理策略枚举
enum ErrorHandlingStrategy {
CONTINUE = 'continue', // 继续运行
RECONFIGURE = 'reconfigure', // 重新配置
RESTART = 'restart', // 重启预览
STOP_AND_RECOVER = 'stop_and_recover' // 停止并恢复
}
7. 完整示例:企业级相机预览应用
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, Permissions, common } from '@kit.AbilityKit';
@Entry
@Component
struct EnterpriseCameraPreview {
// ... [之前的UI代码保持不变]
private cameraManager: camera.CameraManager | null = null;
private sessionManager: AdvancedSessionManager = new AdvancedSessionManager();
private dualPreviewManager: DualPreviewManager | null = null;
private performanceMonitor: PreviewPerformanceMonitor = new PreviewPerformanceMonitor();
private errorHandler: PreviewErrorHandler = new PreviewErrorHandler();
// 初始化相机预览系统
private async initializeCameraSystem(): Promise<boolean> {
try {
// 1. 获取CameraManager
this.cameraManager = camera.getCameraManager(this.context);
// 2. 选择相机设备
const cameraDevice = this.selectCameraDevice();
if (!cameraDevice) {
throw new Error('No suitable camera device found');
}
// 3. 创建相机输入
const cameraInput = this.cameraManager.createCameraInput(cameraDevice);
await cameraInput.open();
// 4. 获取输出能力
const capability = this.cameraManager.getSupportedOutputCapability(
cameraDevice,
camera.SceneMode.NORMAL_PHOTO
);
// 5. 初始化双路预览
this.dualPreviewManager = new DualPreviewManager(
this.displaySurfaceId,
this.processingSurfaceId
);
await this.dualPreviewManager.initialize(
this.cameraManager,
capability,
{ width: 1920, height: 1080 }, // 显示配置
{ width: 1280, height: 720 } // 处理配置
);
// 6. 配置并启动会话
const success = await this.sessionManager.createAndConfigureSession(
this.cameraManager,
cameraInput,
[/* 预览输出列表 */]
);
if (success) {
await this.sessionManager.startSession();
return true;
}
return false;
} catch (error) {
console.error(`Camera system initialization failed: ${(error as BusinessError).message}`);
await this.cleanupCameraSystem();
return false;
}
}
// 选择相机设备
private selectCameraDevice(): camera.CameraDevice | null {
if (!this.cameraManager) return null;
const cameras = this.cameraManager.getSupportedCameras();
return cameras.length > 0 ? cameras[0] : null;
}
// 清理相机系统
private async cleanupCameraSystem(): Promise<void> {
await this.sessionManager.cleanup();
if (this.dualPreviewManager) {
await this.dualPreviewManager.release();
this.dualPreviewManager = null;
}
this.cameraManager = null;
}
// 帧开始处理(集成性能监控)
private onFrameStart(): void {
this.performanceMonitor.onFrameStart();
// 更新性能显示
this.updatePerformanceDisplay();
}
// 更新性能显示
private updatePerformanceDisplay(): void {
const performanceData = this.performanceMonitor.getPerformanceData();
// 更新UI显示
this.currentFPS = Math.round(performanceData.fps);
this.frameCount = performanceData.frameCount;
// 性能预警
if (performanceData.fps < 24) {
this.performanceStatus = 'warning';
} else if (performanceData.fps < 15) {
this.performanceStatus = 'critical';
} else {
this.performanceStatus = 'normal';
}
}
// 处理预览错误
private async handlePreviewError(error: BusinessError): Promise<void> {
const strategy = this.errorHandler.handlePreviewError(error, 'preview_display');
switch (strategy) {
case ErrorHandlingStrategy.RECONFIGURE:
await this.reconfigurePreview();
break;
case ErrorHandlingStrategy.RESTART:
await this.restartPreview();
break;
case ErrorHandlingStrategy.STOP_AND_RECOVER:
await this.stopAndRecoverPreview();
break;
case ErrorHandlingStrategy.CONTINUE:
default:
// 继续运行,记录错误
break;
}
}
// 重新配置预览
private async reconfigurePreview(): Promise<void> {
console.info('Reconfiguring preview...');
await this.stopPreview();
// 实现重新配置逻辑
await this.startPreview();
}
// 重启预览
private async restartPreview(): Promise<void> {
console.info('Restarting preview...');
await this.stopPreview();
await new Promise(resolve => setTimeout(resolve, 100)); // 短暂延迟
await this.startPreview();
}
// 停止并恢复预览
private async stopAndRecoverPreview(): Promise<void> {
console.info('Stopping and recovering preview...');
await this.stopPreview();
await this.cleanupCameraSystem();
await new Promise(resolve => setTimeout(resolve, 1000)); // 1秒延迟
await this.initializeCameraSystem();
await this.startPreview();
}
}
总结
本篇深入探讨了鸿蒙相机预览功能的完整实现,从基础的XComponent集成到高级的双路预览架构,涵盖了:
- XComponent深度集成 - 完整的Surface管理和UI交互
- 预览管理器高级实现 - 智能配置选择和状态管理
- 双路预览架构 - 同时支持显示和图像处理
- 会话管理 - 完整的相机流水线控制
- 性能监控与优化 - 实时性能数据和错误恢复
- 企业级实现 - 生产环境可用的完整方案
这些技术为构建高性能、高稳定性的相机应用奠定了坚实基础。在下一篇文章中,我们将深入探讨高级拍照功能的实现,包括分段式拍照、高性能拍照和动态照片等技术。