实现音视频录制功能鸿蒙示例代码

鸿蒙场景化示例代码技术工程师
发布于 2025-3-19 11:14
浏览
0收藏

本文原创发布在华为开发者社区

介绍

本示例基于AVRecorder实现音视频录制,包括开始录制、暂停、结束、上一个等几乎所有录制音视频的基本操作。

实现音视频录制功能源码链接

效果预览

实现音视频录制功能鸿蒙示例代码-鸿蒙开发者社区

使用说明

  • 打开应用,展示视频录制和音频录制两个按钮。
  • 点击视频录制即可录制视频,并会保存视频。
    点击音频录制按钮即可开始录制音频,并会保留音频文件,点击文件可以进行播放。

实现思路

构建音频录制页面

  1. 构造setAudioRecorderCallback()函数,用于为音频录制相关的对象(this.avRecorder)设置回调函数,以处理音频录制过程中出现的状态变化以及错误上报这两种情况。通过注册对应的回调函数,使得在相应事件发生时能够执行特定的日志记录操作,方便后续对音频录制状态进行监控和错误排查。
  setAudioRecorderCallback() {
    if (this.avRecorder != undefined) {
      // 状态机变化回调函数
      this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
      })
      // 错误上报回调函数
      this.avRecorder.on('error', (err: BusinessError) => {
      })
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  1. 构造getFile()函数,用以获取一个文件对象(fs.File 类型),用于后续对文件进行读写等操作。它通过调用 fs.openSync 函数,按照指定的模式(可读可写且若文件不存在则创建)打开一个特定路径下的文件,并返回这个打开后的文件对象。
  getFile(): fs.File {
    let file: fs.File = fs.openSync(fileUri.getUriFromPath(this.filesDir + '/Audio_' + new Date().getTime() + '.mp3'), fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    return file;
  }
  • 1.
  • 2.
  • 3.
  • 4.
  1. 构造startRecordingProcess()函数,用于实现音频录制的完整启动流程。涵盖从创建音频录制实例、设置相关回调、获取录制文件描述符并配置录制参数,到最终启动录制的一系列操作,并且对过程中可能出现的错误进行基本的捕获和日志记录处理。
  async startRecordingProcess() {
      if (this.avRecorder == undefined) {
        this.avRecorder = await media.createAVRecorder();
      }

      this.setAudioRecorderCallback();
      this.curFile = this.getFile();
      this.avConfig.url = 'fd://' + this.curFile.fd;
      await this.avRecorder.prepare(this.avConfig);
      this.textTimerController.start()
      await this.avRecorder.start();
      this.recordFlag = true;
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  1. 构造pauseRecordingProcess()函数,主要用于暂停正在进行的音频录制过程。首先判断音频录制实例是否存在且当前处于 “started”(已开始)状态,只有满足这一前提条件时,才会执行暂停相关的操作,包括设置继续标志、暂停相关的计时器以及调用音频录制实例的暂停方法。
  async pauseRecordingProcess() {
    if (this.avRecorder != undefined && this.avRecorder.state === 'started') { 
      this.continueFlag = false;
      this.textTimerController.pause()
      await this.avRecorder.pause();
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  1. 构造resumeRecordingProcess()函数,主要负责在音频录制处于暂停状态时将其恢复继续进行。首先对音频录制实例的存在性以及当前所处的暂停状态进行判断,只有满足相应条件,才会执行后续恢复录制的相关操作,比如更新继续标志、重启相关计时器以及调用音频录制实例的恢复方法。
  async resumeRecordingProcess() {
    if (this.avRecorder != undefined && this.avRecorder.state === 'paused') { 
      this.continueFlag = true;
      this.textTimerController.start()
      await this.avRecorder.resume();
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  1. 构造stopRecordingProcess()函数,用于完成音频录制停止的一系列相关操作,涵盖了停止当前正在进行或处于暂停状态的录制、重置相关状态和组件、释放录制实例资源以及关闭用于录制的文件描述符等操作,整体实现了音频录制结束后的资源清理和状态复位功能。
  async stopRecordingProcess() {
    if (this.avRecorder != undefined) {

      if (this.avRecorder.state === 'started'
        || this.avRecorder.state === 'paused') { 
        await this.avRecorder.stop();
      }

      this.recordFlag = false;
      await this.avRecorder.reset();
      this.textTimerController.reset();

      await this.avRecorder.release();

      fs.closeSync(this.curFile)
      this.avRecorder = undefined;
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

视频录制页面的实现

  1. 构造startCameraOutput()函数,用以启动视频输出相关操作,具体是通过调用 VideoOutput 实例(由 this.videoOutput 表示)的 start 接口来开启录像输出功能,并且对调用过程中可能出现的错误进行了基本的捕获与日志记录处理。
  async startCameraOutput() {
    // 调用VideoOutput的start接口开始录像输出
    if (this.videoOutput !== undefined) {
      try {
        await this.videoOutput.start();
      } catch (error) {
        let err = error as BusinessError;
        logger.error(`AVRecorderVideoDemo videoOutput start error: ${JSON.stringify(err)}`);
      }
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  1. 构造stopCameraOutput()函数,调用 VideoOutput 实例(通过 this.videoOutput 表示)的 stop 接口,以此来停止录像输出操作,同时对执行过程中可能出现的错误进行了捕获,并记录相应的错误日志,方便后续排查问题。
  async stopCameraOutput() {
    // 调用VideoOutput的stop接口停止录像输出
    if (this.videoOutput !== undefined) {
      try {
        await this.videoOutput.stop();
      } catch (error) {
        let err = error as BusinessError;
        logger.error(`AVRecorderVideoDemo videoOutput stop error: ${JSON.stringify(err)}`);
      }
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  1. 启动画中画:调用pipController.startPiP()可以开启画中画,在开启前可以设置返回桌面时是否自动启动画中画pipController.setAutoStartEnabled(true/false)。
  startPipWindow() {
    if (this.pipController) {
      this.pipController.setAutoStartEnabled(true)
      this.pipController.startPiP().then(() => {
        ···
      });
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  1. 构造releaseCamera()函数,用于释放相机相关的各类资源,涵盖相机会话、相机输入流、预览输出流以及录像输出流等方面。通过一系列的条件判断与对应资源释放操作,并对每个操作中可能出现的错误进行捕获和记录日志,以此来确保相机相关资源能被妥善清理,避免资源泄漏等问题。
  async releaseCamera() {
    // 释放相机准备阶段创建出的实例
    // 1、停止当前会话
    if (this.cameraSession !== undefined) {
      try {
        await this.cameraSession.stop();
      } catch (error) {
        let err = error as BusinessError;
        logger.error(`AVRecorderVideoDemo cameraSession stop error: ${JSON.stringify(err)}`);
      }
    }
    ···
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  1. 构造startRecordingProcess()函数,实现启动录制的完整流程。涵盖创建录制实例、准备相机相关工作、启动相机输出流以及正式启动录制等关键操作,同时对整个过程中可能出现的错误进行了捕获,并记录相应的错误日志,方便后续排查问题。
  async startRecordingProcess() {
    try {
      if (this.avRecorder === undefined) {
        // 1、创建录制实例
        await this.createAVRecorder();
        // 2.完成相机相关准备工作
        await this.prepareCamera();
      }

      if (this.avRecorder !== undefined) {
        // 3.启动相机出流
        // await this.startCameraOutput();
        // 4. 启动录制
        if (this.avRecorder.state === 'prepared') {
          await this.avRecorder.start();
        }
        this.textTimerController.start();
        this.recording = true;
        this.pausing = false;
        this.isFinished = false;
      }
    }
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  1. 构造prepareCamera()函数,主要负责相机相关的一系列准备工作,涵盖获取相机设备信息、设置音视频录制参数、创建各种相机相关的输入输出流、配置相机会话以及启动会话和相关输出流等诸多操作,同时对各个操作过程中可能出现的错误进行捕获与日志记录,以此保障相机准备工作能尽可能顺利完成,为后续的录制等操作奠定基础。
  async prepareCamera() {
    if (!this.cameraManager || !this.avRecorder) {
      logger.error('AVRecorderVideoDemo cameraManager is undefined or avRecorder is undefined.')
      return;
    }
    // 获取支持指定的相机设备对象
    let cameraDevices: Array<camera.CameraDevice> = [];
    try {
      cameraDevices = this.cameraManager.getSupportedCameras();
    } catch (error) {
      let err = error as BusinessError;
      logger.error(`AVRecorderVideoDemo The getSupportedCameras call failed. error: ${JSON.stringify(err)}`)
    }

  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

分类
收藏
回复
举报
回复
    相关推荐