HarmonyOS多媒体开发:音视频播放与录制全解析
本文将全面介绍HarmonyOS 5(API 12)中的多媒体开发能力,重点讲解音视频播放与录制的实现原理、最佳实践和性能优化技巧。
1. 多媒体核心架构
HarmonyOS多媒体子系统采用分层架构设计,提供统一的媒体服务接口。其核心包括媒体播放器(AVPlayer)、媒体录制器(AVRecorder)和屏幕录制(AVScreenCapture)三大模块,支持从简单的音频播放到复杂的屏幕录制等各种场景。
1.1 媒体服务优势
- 轻量级引擎:占用较少系统资源(线程、内存),支持pipeline灵活拼装和插件化扩展
- HDR视频支持:原生支持hdr vivid采集与播放,提供更炫彩的视觉体验
- 音频池技术:针对短促音效播放场景,实现一次加载多次低时延播放
2. 音视频播放实现
2.1 AVPlayer基础使用
AVPlayer是HarmonyOS多媒体框架的核心播放管理类,负责管理和播放媒体资源,支持本地文件和网络流媒体。
import media from '@ohos.multimedia.media';
import common from '@ohos.app.ability.common';@Entry
@Component
struct VideoPlayerDemo {// 播放器实例private avPlayer: media.AVPlayer | null = null;// 播放状态@State isPlaying: boolean = false;// 当前播放进度@State currentTime: number = 0;// 视频总时长@State duration: number = 0;// 组件初始化时创建播放器async aboutToAppear() {await this.initAVPlayer();}// 初始化AVPlayerprivate async initAVPlayer() {try {// 创建AVPlayer实例this.avPlayer = await media.createAVPlayer();// 设置视频源(支持网络和本地路径)await this.avPlayer.setSource({uri: 'https://example.com/sample.mp4', // 网络视频// uri: 'file:///data/media/local.mp4', // 本地视频mediaType: media.MediaType.VIDEO});// 准备播放器await this.avPlayer.prepare();// 获取视频总时长this.duration = await this.avPlayer.getDuration();// 设置时间更新监听this.avPlayer.on('timeUpdate', (time: number) => {this.currentTime = time;});// 设置播放完成监听this.avPlayer.on('end', () => {this.isPlaying = false;console.log('播放完成');});} catch (error) {console.error('AVPlayer初始化失败: ', JSON.stringify(error));}}// 播放/暂停切换private async togglePlay() {if (!this.avPlayer) return;try {if (this.isPlaying) {await this.avPlayer.pause();} else {await this.avPlayer.play();}this.isPlaying = !this.isPlaying;} catch (error) {console.error('播放控制失败: ', JSON.stringify(error));}}// 跳转到指定位置private async seekTo(position: number) {if (!this.avPlayer) return;try {await this.avPlayer.seek(position);this.currentTime = position;} catch (error) {console.error('跳转失败: ', JSON.stringify(error));}}// 释放资源private async releasePlayer() {if (this.avPlayer) {await this.avPlayer.release();this.avPlayer = null;}}build() {Column({ space: 10 }) {// 视频显示区域VideoComponent({ avPlayer: this.avPlayer }).width('100%').height(300).backgroundColor('#000000')// 播放控制区域Row({ space: 5 }) {Button(this.isPlaying ? '暂停' : '播放').onClick(() => this.togglePlay()).width(80)Text(`${formatTime(this.currentTime)}/${formatTime(this.duration)}`).fontSize(14).textAlign(TextAlign.Center)}.margin(10)// 进度条组件Slider({ value: this.currentTime, min: 0, max: this.duration }).onChange((value: number) => this.seekTo(value)).width('90%')}.width('100%').height('100%').onDisappear(() => this.releasePlayer())}
}// 时间格式化工具函数
function formatTime(milliseconds: number): string {const seconds = Math.floor(milliseconds / 1000);const minutes = Math.floor(seconds / 60);const remainingSeconds = seconds % 60;return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
}
2.2 支持的格式与协议
HarmonyOS AVPlayer支持多种主流媒体格式和协议:
类型 | 支持格式 | 说明 |
---|---|---|
网络协议 | HTTP/HTTPS, HLS, HTTP-FLV | 支持直播和点播 |
音频格式 | AAC, MP3, VORBIS, PCM, AMR | 包含多种容器格式 |
视频格式 | H.264, H.265, MP4, MKV, TS | 支持4K分辨率 |
3. 音视频录制实现
3.1 AVRecorder音频录制
AVRecorder提供高质量的音频录制功能,支持多种音频格式和参数配置。
import media from '@ohos.multimedia.media';
import fileIo from '@ohos.file.fs';
import common from '@ohos.app.ability.common';@Entry
@Component
struct AudioRecorderDemo {private avRecorder: media.AVRecorder | null = null;@State isRecording: boolean = false;@State recordTime: number = 0;private outputPath: string = '';private timer: number | null = null;// 初始化录制器async aboutToAppear() {await this.initRecorder();}private async initRecorder() {try {const context = getContext(this) as common.Context;// 创建输出目录this.outputPath = context.filesDir + '/recordings/';await fileIo.mkdir(this.outputPath, 0o755);// 创建AVRecorder实例this.avRecorder = await media.createAVRecorder();// 配置录制参数const config: media.AVRecorderConfig = {audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,outputFormat: media.OutputFormat.FORMAT_AAC_ADTS,audioEncoder: media.AudioEncoder.AUDIO_ENCODER_AAC,audioSampleRate: 44100,audioChannels: 2,audioBitrate: 128000};await this.avRecorder.prepare(config);} catch (error) {console.error('录制器初始化失败: ', JSON.stringify(error));}}// 开始录制private async startRecording() {if (!this.avRecorder) return;try {// 生成唯一文件名const fileName = `recording_${Date.now()}.aac`;const fullPath = this.outputPath + fileName;await this.avRecorder.start(fullPath);this.isRecording = true;// 开始计时this.recordTime = 0;this.timer = setInterval(() => {this.recordTime += 1;}, 1000);} catch (error) {console.error('开始录制失败: ', JSON.stringify(error));}}// 停止录制private async stopRecording() {if (!this.avRecorder) return;try {await this.avRecorder.stop();this.isRecording = false;// 停止计时if (this.timer) {clearInterval(this.timer);this.timer = null;}console.log('录制完成,文件保存于: ' + this.outputPath);} catch (error) {console.error('停止录制失败: ', JSON.stringify(error));}}build() {Column({ space: 10 }) {Text('音频录制演示').fontSize(20).margin(10)Text(`录制时间: ${this.recordTime}秒`).fontSize(16).margin(5)Button(this.isRecording ? '停止录制' : '开始录制').onClick(() => {if (this.isRecording) {this.stopRecording();} else {this.startRecording();}}).width(200).margin(10)}.width('100%').height('100%')}
}
3.2 屏幕录制(AVScreenCapture)
对于需要录制屏幕的场景,可以使用AVScreenCapture模块:
import { BusinessError } from '@ohos.base';class ScreenRecorder {private capture: any = null;private isRecording: boolean = false;// 初始化屏幕录制async initialize() {try {// 创建屏幕录制实例this.capture = await media.createAVScreenCapture();// 配置录制参数const config: media.AVScreenCaptureConfig = {captureMode: media.CaptureMode.CAPTURE_HOME_SCREEN,dataType: media.DataType.ORIGINAL_STREAM,audioInfo: {micCapInfo: {audioSampleRate: 48000,audioChannels: 2,audioSource: media.AudioSource.MIC}},videoInfo: {videoCapInfo: {videoFrameWidth: 1280,videoFrameHeight: 720,videoSource: media.VideoSource.SURFACE_RGBA}}};await this.capture.init(config);await this.capture.setMicrophoneEnabled(true);} catch (error) {console.error('屏幕录制初始化失败: ', (error as BusinessError).message);}}// 开始屏幕录制async startRecording(outputPath: string) {if (!this.capture) return;try {await this.capture.start(outputPath);this.isRecording = true;} catch (error) {console.error('开始屏幕录制失败: ', (error as BusinessError).message);}}// 停止屏幕录制async stopRecording() {if (!this.capture) return;try {await this.capture.stop();this.isRecording = false;} catch (error) {console.error('停止屏幕录制失败: ', (error as BusinessError).message);}}
}
4. 权限管理
多媒体功能需要相应的权限声明和使用时动态申请。
4.1 权限声明
在module.json5
文件中声明所需权限:
{"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "$string:microphone_permission_reason","usedScene": {"abilities": ["EntryAbility"],"when": "inuse"}},{"name": "ohos.permission.CAPTURE_SCREEN","reason": "$string:screen_capture_permission_reason","usedScene": {"abilities": ["EntryAbility"],"when": "always"}}]}
}
4.2 动态权限申请
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundleManager from '@ohos.bundle.bundleManager';
import { BusinessError } from '@ohos.base';async function checkAndRequestPermission(permission: string, context: common.Context): Promise<boolean> {try {const atManager = abilityAccessCtrl.createAtManager();const bundleInfo = await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);const tokenId = bundleInfo.appInfo.accessTokenId;// 检查权限状态const grantStatus = await atManager.checkAccessToken(tokenId, permission);if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {return true;}// 申请权限const requestResult = await atManager.requestPermissionsFromUser(context, [permission]);return requestResult.authResults[0] === 0;} catch (error) {console.error('权限检查失败: ', (error as BusinessError).message);return false;}
}
5. 性能优化与最佳实践
5.1 内存管理
- 及时释放不再使用的播放器/录制器实例
- 使用合适的视频分辨率和码率以减少内存占用
- 实现资源预加载和缓存机制
5.2 能耗优化
- 在后台时暂停不必要的媒体播放
- 使用合适的编码参数平衡质量和能耗
- 实现自适应码率调整以适应网络条件
5.3 错误处理
class MediaErrorHandler {static handleAVPlayerError(error: BusinessError): void {switch (error.code) {case 5400103:console.error('媒体资源格式不支持');break;case 5400104:console.error('网络连接失败');break;case 5400105:console.error('解码失败');break;default:console.error('未知错误: ', error.message);}}static handleRecorderError(error: BusinessError): void {// 录制错误处理逻辑}
}
6. 实战案例:简易视频播放器
以下是一个完整的视频播放器实现示例:
import media from '@ohos.multimedia.media';
import common from '@ohos.app.ability.common';@Entry
@Component
struct SimpleVideoPlayer {private avPlayer: media.AVPlayer | null = null;@State isPlaying: boolean = false;@State currentTime: number = 0;@State duration: number = 0;@State showControls: boolean = true;private controlsTimeout: number | null = null;async aboutToAppear() {await this.initializePlayer();}private async initializePlayer() {try {this.avPlayer = await media.createAVPlayer();// 配置播放器await this.avPlayer.setSource({uri: 'https://example.com/sample.mp4',mediaType: media.MediaType.VIDEO});await this.avPlayer.prepare();this.duration = await this.avPlayer.getDuration();// 设置事件监听this.setupEventListeners();} catch (error) {console.error('播放器初始化失败: ', JSON.stringify(error));}}private setupEventListeners() {if (!this.avPlayer) return;// 时间更新监听this.avPlayer.on('timeUpdate', (time: number) => {this.currentTime = time;});// 播放完成监听this.avPlayer.on('end', () => {this.isPlaying = false;this.currentTime = 0;});// 错误监听this.avPlayer.on('error', (error: BusinessError) => {console.error('播放错误: ', error.message);this.isPlaying = false;});}private togglePlayPause() {if (!this.avPlayer) return;if (this.isPlaying) {this.avPlayer.pause();} else {this.avPlayer.play();}this.isPlaying = !this.isPlaying;}private async seekToPosition(position: number) {if (!this.avPlayer) return;const validPosition = Math.max(0, Math.min(position, this.duration));await this.avPlayer.seek(validPosition);this.currentTime = validPosition;}build() {Column() {// 视频显示区域Video({ avPlayer: this.avPlayer }).width('100%').height(300).onClick(() => {this.showControls = !this.showControls;this.resetControlsTimer();})// 控制界面if (this.showControls) {Column() {// 进度条Slider({value: this.currentTime,min: 0,max: this.duration,onChange: (value: number) => this.seekToPosition(value)}).width('90%')// 控制按钮Row({ space: 20 }) {Button(this.isPlaying ? '暂停' : '播放').onClick(() => this.togglePlayPause())Text(`${formatTime(this.currentTime)} / ${formatTime(this.duration)}`).fontSize(14)}.margin(10)}.backgroundColor('#CC000000').padding(10)}}.width('100%').height('100%')}private resetControlsTimer() {if (this.controlsTimeout) {clearTimeout(this.controlsTimeout);}this.controlsTimeout = setTimeout(() => {this.showControls = false;}, 3000);}
}
7. 总结
HarmonyOS 5的多媒体框架提供了强大而灵活的API集合,支持从简单的音频播放到复杂的屏幕录制等各种场景。通过合理使用AVPlayer、AVRecorder和AVScreenCapture等组件,并结合适当的权限管理和错误处理策略,开发者可以构建出高性能、用户体验良好的多媒体应用。
关键要点总结:
- 使用统一的媒体服务接口简化开发流程
- 合理配置编码参数以平衡质量和性能
- 实现完善的错误处理和用户反馈机制
- 注重权限管理和隐私保护
- 优化内存使用和能耗表现