鸿蒙相机预览功能全面实现:从基础到高级应用

49 阅读8分钟

鸿蒙相机预览功能全面实现:从基础到高级应用

1. 相机预览功能概述与架构设计

1.1 预览功能在相机应用中的核心地位

相机预览是用户与相机应用交互的第一界面,它不仅仅是简单的画面显示,更是整个相机系统的性能瓶颈和用户体验的关键点。一个优秀的预览实现需要平衡性能、功耗和画质。

预览功能的核心价值:

  • 实时反馈:为用户提供即时的拍摄画面反馈
  • 交互基础:对焦、曝光、手势操作等功能的载体
  • 性能指标:直接影响应用的响应速度和流畅度
  • 用户体验:决定用户对相机应用的第一印象

1.2 预览系统架构深度解析

鸿蒙相机预览采用Surface模型,其核心架构如下:

Camera Hardware → Camera HDI → Camera Service → PreviewOutput → Surface → XComponent

数据流向详解:

  1. 相机硬件采集原始图像数据
  2. 通过HDI层进行初步处理
  3. 相机服务管理数据流和权限
  4. PreviewOutput将数据写入Surface
  5. 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集成到高级的双路预览架构,涵盖了:

  1. XComponent深度集成 - 完整的Surface管理和UI交互
  2. 预览管理器高级实现 - 智能配置选择和状态管理
  3. 双路预览架构 - 同时支持显示和图像处理
  4. 会话管理 - 完整的相机流水线控制
  5. 性能监控与优化 - 实时性能数据和错误恢复
  6. 企业级实现 - 生产环境可用的完整方案

这些技术为构建高性能、高稳定性的相机应用奠定了坚实基础。在下一篇文章中,我们将深入探讨高级拍照功能的实现,包括分段式拍照、高性能拍照和动态照片等技术。