本文将全面介绍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();
}
// 初始化AVPlayer
private 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等组件,并结合适当的权限管理和错误处理策略,开发者可以构建出高性能、用户体验良好的多媒体应用。
关键要点总结:
- 使用统一的媒体服务接口简化开发流程
- 合理配置编码参数以平衡质量和性能
- 实现完善的错误处理和用户反馈机制
- 注重权限管理和隐私保护
- 优化内存使用和能耗表现