HarmonyOS APP开发中的相机基础

举报
Jack20 发表于 2026/06/20 22:17:55 2026/06/20
【摘要】 HarmonyOS APP开发中的相机基础核心要点:掌握 HarmonyOS 相机开发的基础架构,理解 CameraManager 的核心职责,学会相机设备的枚举与管理,熟悉相机生命周期的状态流转,正确申请相机权限。 一、背景与动机你有没有想过,手机里那个每天被打开几十次的相机 App,背后到底在干什么?想象一下这个场景:周末你和朋友去露营,夕阳西下,你掏出手机准备拍一张绝美日落。打开相机...

HarmonyOS APP开发中的相机基础

核心要点:掌握 HarmonyOS 相机开发的基础架构,理解 CameraManager 的核心职责,学会相机设备的枚举与管理,熟悉相机生命周期的状态流转,正确申请相机权限。


一、背景与动机

你有没有想过,手机里那个每天被打开几十次的相机 App,背后到底在干什么?

想象一下这个场景:周末你和朋友去露营,夕阳西下,你掏出手机准备拍一张绝美日落。打开相机——预览画面秒出,对焦丝滑,按下快门——照片瞬间保存。整个过程不到3秒,但背后却是一整套精密的硬件调度、状态管理和权限控制体系在协同工作。

在 HarmonyOS 上开发相机功能,不像调个 Intent 那么简单。你需要理解相机设备的管理方式,搞清楚会话(Session)的概念,掌握预览、拍照、录像三条数据流的生命周期,还要处理权限申请、设备热插拔、前后台切换等各种边界情况。

如果你一上来就写代码,大概率会踩坑——预览黑屏、权限被拒、相机打不开、切换摄像头崩溃……这些问题,本质上都是对相机基础架构理解不够深入导致的。

这篇文章,我们就从零开始,把 HarmonyOS 相机开发的地基打牢。


二、核心原理

2.1 相机整体架构

HarmonyOS 的相机能力由 @ohos.multimedia.camera 模块提供,整体架构可以分为三层:
图片.png

关键概念解读

概念 说明 类比
CameraManager 相机系统的总管家,负责设备管理和会话创建 物业经理
CameraDevice 物理相机设备(前置/后置/广角等) 房间
CameraInput 相机输入流,连接设备和会话的桥梁 房间门
Session 会话,管理预览/拍照/录像的数据流 租约合同
Output 各种输出通道,决定数据去哪里 快递地址

2.2 相机生命周期状态机

相机的生命周期是理解一切的基础。一个相机设备从被打开到被释放,会经历以下状态流转:
图片.png

状态说明

  • CLOSED:相机设备未打开,初始状态
  • OPENING:正在打开相机,此过程可能耗时
  • OPENED:相机已打开,可以创建会话
  • CLOSING:正在关闭相机
  • 在 OPENED 状态下,会话还有子状态:IDLE → CONFIGURED → READY

2.3 相机权限体系

HarmonyOS 对相机权限的管理非常严格,涉及两个层面:

  1. 声明权限:在 module.json5 中声明 ohos.permission.CAMERA
  2. 运行时授权:首次使用时需要用户动态授权

权限流程如下:

flowchart LR
    classDef primary fill:#4A90D9,stroke:#2C5F8A,color:#fff,font-weight:bold
    classDef warning fill:#E8A838,stroke:#B87A1A,color:#fff,font-weight:bold
    classDef error fill:#D94A4A,stroke:#8A2C2C,color:#fff,font-weight:bold
    classDef info fill:#50B5A9,stroke:#2C7A6F,color:#fff,font-weight:bold
    classDef purple fill:#9B59B6,stroke:#6C3483,color:#fff,font-weight:bold

    A[声明权限]:::primary --> B{检查授权状态}:::warning
    B -->|已授权| C[直接使用相机]:::info
    B -->|未授权| D[请求用户授权]:::purple
    D -->|用户同意| C
    D -->|用户拒绝| E[提示并引导设置]:::error

三、代码实战

3.1 相机权限申请与检查

这是所有相机开发的第一步——确保你拿到了权限,否则后面的代码一行都跑不了。

import { camera } from '@kit.CameraKit';
import { abilityAccessCtrl, bundleManager, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 相机权限管理工具类
 * 封装权限检查与请求的完整流程
 */
export class CameraPermissionHelper {
  private static readonly CAMERA_PERMISSION: Permissions = 'ohos.permission.CAMERA';

  /**
   * 检查相机权限是否已授予
   * @returns true 表示已授权,false 表示未授权
   */
  static async checkPermission(): Promise<boolean> {
    try {
      const atManager = abilityAccessCtrl.createAtManager();
      const bundleInfo = await bundleManager.getBundleInfoForSelf(
        bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
      );
      const grantStatus = await atManager.checkAccessToken(
        bundleInfo.appInfo.accessTokenId,
        CameraPermissionHelper.CAMERA_PERMISSION
      );
      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[权限检查失败] code: ${err.code}, message: ${err.message}`);
      return false;
    }
  }

  /**
   * 请求相机权限
   * @returns true 表示用户授权,false 表示用户拒绝
   */
  static async requestPermission(context: Context): Promise<boolean> {
    // 先检查是否已经授权
    const hasPermission = await CameraPermissionHelper.checkPermission();
    if (hasPermission) {
      console.info('[权限] 相机权限已授予,无需重复申请');
      return true;
    }

    try {
      const atManager = abilityAccessCtrl.createAtManager();
      const result = await atManager.requestPermissionsFromUser(
        context,
        [CameraPermissionHelper.CAMERA_PERMISSION]
      );

      // 判断用户选择结果
      const isGranted = result.authResults[0] === 0;
      if (isGranted) {
        console.info('[权限] 用户授予了相机权限');
      } else {
        console.warn('[权限] 用户拒绝了相机权限');
      }
      return isGranted;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[权限请求失败] code: ${err.code}, message: ${err.message}`);
      return false;
    }
  }

  /**
   * 引导用户前往系统设置页面手动开启权限
   * 当用户拒绝权限后,可以调用此方法引导用户手动开启
   */
  static async openPermissionSettings(context: Context): Promise<void> {
    try {
      const atManager = abilityAccessCtrl.createAtManager();
      await atManager.requestPermissionsFromUser(
        context,
        [CameraPermissionHelper.CAMERA_PERMISSION]
      );
    } catch (error) {
      console.error('[权限] 打开设置页面失败');
    }
  }
}

module.json5 中声明权限

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.CAMERA",
        "reason": "$string:camera_permission_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

3.2 CameraManager 初始化与相机设备枚举

拿到权限后,下一步就是创建 CameraManager 并枚举可用的相机设备。

import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 相机设备管理器
 * 负责初始化CameraManager、枚举设备、管理设备热插拔
 */
export class CameraDeviceManager {
  private cameraManager: camera.CameraManager | null = null;
  private cameraDevices: camera.CameraDevice[] = [];
  private currentDevice: camera.CameraDevice | null = null;

  // 设备变更回调
  private onDeviceChange?: (devices: camera.CameraDevice[]) => void;

  /**
   * 初始化CameraManager
   * 这是所有相机操作的第一步
   */
  async init(context: Context): Promise<boolean> {
    try {
      // 创建CameraManager实例
      this.cameraManager = camera.getCameraManager(context);
      console.info('[CameraManager] 初始化成功');

      // 枚举当前可用的相机设备
      this.cameraDevices = this.cameraManager.getSupportedCameras();
      console.info(`[CameraManager] 检测到 ${this.cameraDevices.length} 个相机设备`);

      // 打印每个设备的信息
      this.cameraDevices.forEach((device, index) => {
        console.info(`[设备${index}] ID: ${device.cameraId}, ` +
          `方向: ${device.cameraOrientation}, ` +
          `位置: ${this.getCameraPositionText(device.cameraPosition)}, ` +
          `类型: ${this.getCameraTypeText(device.cameraType)}`);
      });

      // 注册设备热插拔监听
      this.registerDeviceChangeCallback();

      return true;
    } catch (error) {
      const err = error as BusinessError;
      console.error(`[CameraManager] 初始化失败: code=${err.code}, msg=${err.message}`);
      return false;
    }
  }

  /**
   * 获取所有支持的相机设备
   */
  getDevices(): camera.CameraDevice[] {
    return this.cameraDevices;
  }

  /**
   * 根据位置获取相机设备
   * @param position 相机位置(前置/后置)
   */
  getDeviceByPosition(position: camera.CameraPosition): camera.CameraDevice | null {
    const device = this.cameraDevices.find(d => d.cameraPosition === position);
    if (device) {
      this.currentDevice = device;
      console.info(`[CameraManager] 选中设备: ${device.cameraId}`);
    } else {
      console.warn(`[CameraManager] 未找到位置为 ${position} 的相机设备`);
    }
    return device;
  }

  /**
   * 获取当前设备支持的输出能力
   * 这是创建会话前必须了解的信息
   */
  getSupportedOutputCapability(device: camera.CameraDevice): camera.CameraOutputCapability {
    if (!this.cameraManager) {
      throw new Error('CameraManager 未初始化');
    }
    return this.cameraManager.getSupportedOutputCapability(device);
  }

  /**
   * 注册设备热插拔回调
   * 当有新相机设备接入或移除时,系统会通过此回调通知
   */
  private registerDeviceChangeCallback(): void {
    if (!this.cameraManager) return;

    this.cameraManager.on('cameraStatus', (statusInfo: camera.CameraStatusInfo) => {
      console.info(`[设备变更] 设备: ${statusInfo.camera.cameraId}, ` +
        `状态: ${this.getStatusText(statusInfo.status)}`);

      // 重新枚举设备列表
      this.cameraDevices = this.cameraManager!.getSupportedCameras();

      // 通知外部
      this.onDeviceChange?.(this.cameraDevices);
    });
  }

  /**
   * 注销设备变更监听
   */
  unregisterDeviceChangeCallback(): void {
    if (!this.cameraManager) return;
    this.cameraManager.off('cameraStatus');
  }

  /**
   * 释放CameraManager资源
   */
  release(): void {
    this.unregisterDeviceChangeCallback();
    this.cameraManager = null;
    this.cameraDevices = [];
    this.currentDevice = null;
    console.info('[CameraManager] 资源已释放');
  }

  // ===== 工具方法 =====

  private getCameraPositionText(position: camera.CameraPosition): string {
    const map: Record<number, string> = {
      [camera.CameraPosition.CAMERA_POSITION_UNSPECIFIED]: '未指定',
      [camera.CameraPosition.CAMERA_POSITION_BACK]: '后置',
      [camera.CameraPosition.CAMERA_POSITION_FRONT]: '前置',
    };
    return map[position] || '未知';
  }

  private getCameraTypeText(type: camera.CameraType): string {
    const map: Record<number, string> = {
      [camera.CameraType.CAMERA_TYPE_UNSPECIFIED]: '未指定',
      [camera.CameraType.CAMERA_TYPE_WIDE_ANGLE]: '广角',
      [camera.CameraType.CAMERA_TYPE_ULTRA_WIDE]: '超广角',
      [camera.CameraType.CAMERA_TYPE_TELEPHOTO]: '长焦',
      [camera.CameraType.CAMERA_TYPE_TRUE_DEPTH]: '深感',
    };
    return map[type] || '未知';
  }

  private getStatusText(status: camera.CameraStatus): string {
    const map: Record<number, string> = {
      [camera.CameraStatus.CAMERA_STATUS_APPEAR]: '已接入',
      [camera.CameraStatus.CAMERA_STATUS_DISAPPEAR]: '已移除',
      [camera.CameraStatus.CAMERA_STATUS_AVAILABLE]: '可用',
      [camera.CameraStatus.CAMERA_STATUS_UNAVAILABLE]: '不可用',
    };
    return map[status] || '未知';
  }
}

3.3 完整的相机初始化流程(含生命周期管理)

这个示例把权限申请、CameraManager 初始化、CameraInput 创建、会话配置串起来,形成一个完整的相机启动流程。

import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';

/**
 * 相机控制器 - 完整生命周期管理
 * 演示从权限申请到相机启动的完整流程
 */
@Entry
@Component
struct CameraBasicPage {
  // 相机核心对象
  private cameraManager: camera.CameraManager | null = null;
  private cameraInput: camera.CameraInput | null = null;
  private previewOutput: camera.PreviewOutput | null = null;
  private photoSession: camera.PhotoSession | null = null;
  private surfaceId: string = '';

  // UI 状态
  @State cameraStatus: string = '未初始化';
  @State deviceList: string[] = [];
  @State currentDeviceIndex: number = 0;
  @State errorMessage: string = '';

  // XComponent 回调,用于获取预览的 Surface
  private xComponentController: XComponentController = new XComponentController();

  aboutToAppear(): void {
    // 页面即将显示时,执行初始化
    this.initCamera();
  }

  aboutToDisappear(): void {
    // 页面即将消失时,释放所有资源
    this.releaseCamera();
  }

  /**
   * 相机初始化主流程
   * 严格按照:权限 → Manager → 设备 → Input → Session 的顺序
   */
  async initCamera(): Promise<void> {
    this.cameraStatus = '正在初始化...';
    this.errorMessage = '';

    try {
      // 第一步:检查并申请权限
      const hasPermission = await CameraPermissionHelper.requestPermission(this.context);
      if (!hasPermission) {
        this.cameraStatus = '权限被拒绝';
        this.errorMessage = '请授予相机权限后重试';
        return;
      }

      // 第二步:创建 CameraManager
      this.cameraManager = camera.getCameraManager(this.context);
      this.cameraStatus = 'CameraManager 已创建';

      // 第三步:枚举相机设备
      const devices = this.cameraManager.getSupportedCameras();
      this.deviceList = devices.map((d, i) =>
        `设备${i}: ${this.getCameraPositionText(d.cameraPosition)} ${this.getCameraTypeText(d.cameraType)}`
      );

      if (devices.length === 0) {
        this.cameraStatus = '未检测到相机设备';
        this.errorMessage = '当前设备不支持相机功能';
        return;
      }

      // 第四步:创建 CameraInput(默认使用后置摄像头)
      const targetDevice = devices[this.currentDeviceIndex];
      this.cameraInput = this.cameraManager.createCameraInput(targetDevice);
      this.cameraStatus = 'CameraInput 已创建';

      // 第五步:打开相机
      await this.cameraInput.open();
      this.cameraStatus = '相机已打开';

      // 第六步:获取输出能力并创建预览输出
      const outputCapability = this.cameraManager.getSupportedOutputCapability(targetDevice);
      const previewProfiles = outputCapability.previewProfiles;
      if (previewProfiles.length === 0) {
        this.cameraStatus = '不支持预览';
        return;
      }

      // 使用第一个预览配置(实际开发中应选择最合适的)
      this.previewOutput = this.cameraManager.createPreviewOutput(previewProfiles[0], this.surfaceId);

      // 第七步:创建并配置会话
      this.photoSession = this.cameraManager.createPhotoSession(
        this.cameraInput,
        this.previewOutput
      );
      this.cameraStatus = '会话已创建,准备就绪';

      console.info('[相机初始化] 全部完成');

    } catch (error) {
      const err = error as BusinessError;
      this.cameraStatus = '初始化失败';
      this.errorMessage = `错误码: ${err.code}, 消息: ${err.message}`;
      console.error(`[相机初始化失败] ${this.errorMessage}`);
    }
  }

  /**
   * 切换前后摄像头
   */
  async switchCamera(): Promise<void> {
    if (!this.cameraManager) return;

    try {
      // 先释放当前会话和输入
      this.photoSession?.stop();
      this.cameraInput?.close();

      // 切换设备索引
      const devices = this.cameraManager.getSupportedCameras();
      this.currentDeviceIndex = (this.currentDeviceIndex + 1) % devices.length;
      const targetDevice = devices[this.currentDeviceIndex];

      // 重新创建 CameraInput
      this.cameraInput = this.cameraManager.createCameraInput(targetDevice);
      await this.cameraInput.open();

      // 重新创建会话
      const outputCapability = this.cameraManager.getSupportedOutputCapability(targetDevice);
      this.previewOutput = this.cameraManager.createPreviewOutput(
        outputCapability.previewProfiles[0],
        this.surfaceId
      );
      this.photoSession = this.cameraManager.createPhotoSession(
        this.cameraInput,
        this.previewOutput
      );

      this.cameraStatus = `已切换到${this.getCameraPositionText(targetDevice.cameraPosition)}摄像头`;
      console.info(`[切换摄像头] ${this.cameraStatus}`);

    } catch (error) {
      const err = error as BusinessError;
      this.errorMessage = `切换失败: ${err.message}`;
      console.error(`[切换摄像头失败] ${this.errorMessage}`);
    }
  }

  /**
   * 释放所有相机资源
   * 严格按照逆序释放:Session → Output → Input → Manager
   */
  releaseCamera(): void {
    try {
      // 1. 停止并释放会话
      if (this.photoSession) {
        this.photoSession.stop();
        this.photoSession.release();
        this.photoSession = null;
      }

      // 2. 释放预览输出
      if (this.previewOutput) {
        this.previewOutput.release();
        this.previewOutput = null;
      }

      // 3. 关闭并释放相机输入
      if (this.cameraInput) {
        this.cameraInput.close();
        this.cameraInput.release();
        this.cameraInput = null;
      }

      this.cameraStatus = '资源已释放';
      console.info('[相机资源] 全部释放完成');

    } catch (error) {
      console.error(`[资源释放失败] ${error}`);
    }
  }

  build() {
    Column() {
      // 状态显示
      Text(`相机状态: ${this.cameraStatus}`)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 20, bottom: 10 })

      // 预览区域
      XComponent({
        id: 'cameraPreview',
        type: XComponentType.SURFACE,
        controller: this.xComponentController
      })
        .onLoad(() => {
          // XComponent 加载完成后获取 surfaceId
          this.surfaceId = this.xComponentController.getXComponentSurfaceId();
          console.info(`[XComponent] surfaceId: ${this.surfaceId}`);
          // 获取到 surfaceId 后重新初始化预览
          if (this.cameraManager && this.cameraInput) {
            this.setupPreview();
          }
        })
        .width('100%')
        .height(400)
        .backgroundColor(Color.Black)

      // 设备列表
      List() {
        ForEach(this.deviceList, (item: string, index: number) => {
          ListItem() {
            Text(item)
              .fontSize(14)
              .fontColor(index === this.currentDeviceIndex ? '#4A90D9' : '#999')
              .padding(8)
          }
        })
      }
      .width('90%')
      .height(100)
      .margin({ top: 10 })

      // 操作按钮
      Row() {
        Button('切换摄像头')
          .onClick(() => this.switchCamera())
          .margin({ right: 10 })

        Button('重新初始化')
          .onClick(() => this.initCamera())
      }
      .margin({ top: 10 })

      // 错误信息
      if (this.errorMessage) {
        Text(this.errorMessage)
          .fontSize(14)
          .fontColor(Color.Red)
          .margin({ top: 10 })
          .padding(10)
          .backgroundColor('#FFF0F0')
          .borderRadius(8)
      }
    }
    .width('100%')
    .height('100%')
  }

  // ===== 工具方法 =====

  private get context(): Context {
    return getContext(this);
  }

  private getCameraPositionText(position: camera.CameraPosition): string {
    if (position === camera.CameraPosition.CAMERA_POSITION_BACK) return '后置';
    if (position === camera.CameraPosition.CAMERA_POSITION_FRONT) return '前置';
    return '未指定';
  }

  private getCameraTypeText(type: camera.CameraType): string {
    if (type === camera.CameraType.CAMERA_TYPE_WIDE_ANGLE) return '广角';
    if (type === camera.CameraType.CAMERA_TYPE_ULTRA_WIDE) return '超广角';
    if (type === camera.CameraType.CAMERA_TYPE_TELEPHOTO) return '长焦';
    return '';
  }

  /**
   * 配置预览(在 XComponent 加载后调用)
   */
  private async setupPreview(): Promise<void> {
    try {
      const devices = this.cameraManager!.getSupportedCameras();
      const targetDevice = devices[this.currentDeviceIndex];
      const outputCapability = this.cameraManager!.getSupportedOutputCapability(targetDevice);

      this.previewOutput = this.cameraManager!.createPreviewOutput(
        outputCapability.previewProfiles[0],
        this.surfaceId
      );

      this.photoSession = this.cameraManager!.createPhotoSession(
        this.cameraInput!,
        this.previewOutput
      );

      console.info('[预览配置] 完成');
    } catch (error) {
      console.error(`[预览配置失败] ${error}`);
    }
  }
}

四、踩坑与注意事项

4.1 权限被拒绝后的处理

:用户拒绝了相机权限,App 直接崩溃或卡死。

:一定要在调用相机 API 之前检查权限,被拒绝后给用户友好的提示,引导去设置页面手动开启。

// ❌ 错误做法:不检查权限直接用
const cameraManager = camera.getCameraManager(context); // 可能崩溃

// ✅ 正确做法:先检查再使用
const hasPermission = await CameraPermissionHelper.checkPermission();
if (!hasPermission) {
  // 显示提示对话框,引导用户授权
  return;
}

4.2 CameraManager 重复创建问题

:多次调用 camera.getCameraManager(context) 可能导致资源泄漏。

:CameraManager 是单例模式,同一个 context 多次调用返回的是同一个实例。但建议在应用层做缓存,避免不必要的调用。

4.3 CameraInput 忘记 open()

:创建了 CameraInput 但忘记调用 open(),导致后续创建会话时报错。

:CameraInput 创建后必须显式调用 open() 方法,这是一个异步操作,需要 await

// ❌ 错误:忘记 open
const cameraInput = cameraManager.createCameraInput(device);
// 直接创建会话 → 报错!

// ✅ 正确:先 open 再使用
const cameraInput = cameraManager.createCameraInput(device);
await cameraInput.open();
// 然后创建会话

4.4 设备热插拔导致崩溃

:外接 USB 相机被拔出时,如果还在使用该设备,App 会崩溃。

:注册 cameraStatus 回调,在设备消失时及时释放资源。

cameraManager.on('cameraStatus', (statusInfo: camera.CameraStatusInfo) => {
  if (statusInfo.status === camera.CameraStatus.CAMERA_STATUS_DISAPPEAR) {
    // 设备消失了,立即释放相关资源
    this.releaseCamera();
  }
});

4.5 surfaceId 为空字符串

:XComponent 的 onLoad 回调还没执行,surfaceId 还是空字符串,就传给了 createPreviewOutput

:确保在 onLoad 回调中获取到 surfaceId 后,再进行预览输出的创建。

4.6 资源释放顺序

:先释放 CameraInput,再释放 Session,导致 Session 中引用了已释放的 Input,报错。

:严格按照创建的逆序释放:Session → Output → Input。


五、HarmonyOS 6 适配

5.1 API 变更

变更项 HarmonyOS 5.0 HarmonyOS 6.0
CameraManager 创建 camera.getCameraManager(context) 保持不变
设备枚举 getSupportedCameras() 保持不变,新增 getSupportedCamerasSync() 同步方法
权限模型 @ohos.abilityAccessCtrl 保持不变,但新增了更细粒度的权限控制
错误码 数字错误码 新增了结构化错误信息 CameraError

5.2 迁移要点

  1. 同步 API 使用:HarmonyOS 6.0 新增了部分同步方法,如 getSupportedCamerasSync(),在性能敏感场景可以优先使用。

  2. 错误处理增强:6.0 中错误信息更加详细,建议更新错误处理逻辑:

// HarmonyOS 6.0 增强的错误处理
try {
  const cameraManager = camera.getCameraManager(context);
} catch (error) {
  const cameraError = error as camera.CameraError;
  // 新增了更详细的错误分类
  console.error(`[相机错误] 类型: ${cameraError.code}, 描述: ${cameraError.message}`);
}
  1. 生命周期感知增强:6.0 中 CameraInput 的状态回调更加完善,新增了 on('error') 回调,可以监听相机设备的硬件异常。

六、总结

mindmap
  root((相机基础))
    权限管理
      声明 ohos.permission.CAMERA
      运行时动态授权
      被拒后引导设置
    CameraManager
      创建与初始化
      枚举相机设备
      设备热插拔监听
      获取输出能力
    CameraInput
      创建并绑定设备
      必须显式 open
      状态回调监听
      使用后必须 close
    相机生命周期
      CLOSEDOPENINGOPENED
      会话子状态 IDLECONFIGUREDREADY
      释放顺序 Session → Output → Input
    踩坑要点
      权限检查前置
      surfaceId 非空校验
      资源释放逆序
      设备热插拔处理

核心记忆口诀

权限先申请,Manager 再创建;设备要枚举,Input 必须 open;Session 管数据流,释放要逆序。

下篇文章我们将深入「拍照」功能,讲解 PhotoSession 的使用、拍照参数配置、闪光灯控制等实战内容。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。