首页
看点啥
插画图片
首页 看点啥 [鸿蒙从零到一] 鸿蒙媒体能力实战:图片、音频与视频处理

[鸿蒙从零到一] 鸿蒙媒体能力实战:图片、音频与视频处理

2026-08-19 0

[鸿蒙从零到一] 鸿蒙媒体能力实战:图片、音频与视频处理并不只看表面做法,关键还要理解相关条件、限制和后续影响。

前言

在移动应用开发中,媒体能力是核心功能之一。HarmonyOS 提供了完整的媒体框架,覆盖图片选择、音频播放、视频录制等场景。下文会从实战角度出发,带你掌握 HarmonyOS 的媒体能力。

[鸿蒙从零到一] 鸿蒙媒体能力实战:图片、音频与视频处理

一、图片选择与处理

1.1 使用 Picker 选择图片

HarmonyOS 提供了统一的 Picker API,支持从相册选择图片:

import {picker } from '@kit.CoreFileKit';import {BusinessError } from '@kit.BasicServicesKit';async function pickImage(): Promise { try { const photoSelectOptions = new picker.PhotoSelectOptions();photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;photoSelectOptions.maxSelectNumber = 1;const photoViewPicker = new picker.PhotoViewPicker();const result = await photoViewPicker.select(photoSelectOptions);if (result && result.photoUris.length > 0) { return result.photoUris[0];}return '';} catch (err) { console.error('选择图片失败:', JSON.stringify(err));return '';}}

1.2 图片解码与显示

获取图片 URI 后,使用 Image 组件显示:

import {image } from '@kit.ImageKit';@Entry@Componentstruct ImageDemo { @State imageUri: string = '';build() { Column() { Button('选择图片').onClick(async () => { this.imageUri = await pickImage();})if (this.imageUri) { Image(this.imageUri).width('100%').height(300).objectFit(ImageFit.Contain)}}.padding(20)}}

1.3 图片压缩与保存

处理大图时需要压缩:

import {image } from '@kit.ImageKit';import {fileIo } from '@kit.CoreFileKit';async function compressImage(sourceUri: string, targetPath: string): Promise { try { const imageSource = image.createImageSource(sourceUri);const imageInfo = await imageSource.getImageInfo();console.info(`原始尺寸: ${ imageInfo.size.width}x${ imageInfo.size.height}`);const decodingOptions: image.DecodingOptions = { desiredSize: {width: 800, height: 800 },desiredPixelFormat: image.PixelMapFormat.RGBA_8888};const pixelMap = await imageSource.createPixelMap(decodingOptions);const imagePacker = image.createImagePacker();const packOpts: image.PackingOption = { format: 'image/jpeg',quality: 80};const buffer = await imagePacker.packing(pixelMap, packOpts);const file = fileIo.openSync(targetPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY);fileIo.writeSync(file.fd, buffer);fileIo.closeSync(file);console.info('图片压缩完成');} catch (err) { console.error('压缩失败:', JSON.stringify(err));}}

二、音频播放与录制

2.1 音频播放

使用 AVPlayer 播放音频:

import {media } from '@kit.MediaKit';@Componentexport struct AudioPlayer { private avPlayer?: media.AVPlayer;@State isPlaying: boolean = false;@State currentTime: number = 0;@State duration: number = 0;async initPlayer(audioUri: string) { try { this.avPlayer = await media.createAVPlayer();this.avPlayer.on('stateChange', (state: string) => { console.info(`播放器状态: ${ state}`);});this.avPlayer.on('timeUpdate', (time: number) => { this.currentTime = time;});this.avPlayer.on('durationUpdate', (duration: number) => { this.duration = duration;});this.avPlayer.url = audioUri;} catch (err) { console.error('初始化播放器失败:', JSON.stringify(err));}}async play() { await this.avPlayer?.play();this.isPlaying = true;}async pause() { await this.avPlayer?.pause();this.isPlaying = false;}build() { Column() { Text(`${ this.formatTime(this.currentTime)} / ${ this.formatTime(this.duration)}`)Row() { Button(this.isPlaying ? '暂停' : '播放').onClick(() => { if (this.isPlaying) { this.pause();} else { this.play();}})}}}formatTime(ms: number): string { const seconds = Math.floor(ms / 1000);const min = Math.floor(seconds / 60);const sec = seconds % 60;return `${ min}:${ sec.toString().padStart(2, '0')}`;}aboutToDisappear() { this.avPlayer?.release();}}

2.2 音频录制

使用 AVRecorder 录制音频:

import {media } from '@kit.MediaKit';import {fileIo } from '@kit.CoreFileKit';@Componentexport struct AudioRecorder { private avRecorder?: media.AVRecorder;@State isRecording: boolean = false;private outputPath: string = '';async initRecorder() { try { this.avRecorder = await media.createAVRecorder();this.avRecorder.on('stateChange', (state: string) => { console.info(`录制器状态: ${ state}`);});const context = getContext(this);this.outputPath = `${ context.cacheDir}/audio_${ Date.now()}.m4a`;const config: media.AVRecorderConfig = { audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,profile: { audioBitrate: 128000,audioChannels: 2,audioCodec: media.CodecMimeType.AUDIO_AAC,audioSampleRate: 48000,fileFormat: media.ContainerFormatType.CFT_MPEG_4A},url: `fd://${ fileIo.openSync(this.outputPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY).fd}`};await this.avRecorder.prepare(config);} catch (err) { console.error('初始化录制器失败:', JSON.stringify(err));}}async startRecord() { await this.avRecorder?.start();this.isRecording = true;}async stopRecord() { await this.avRecorder?.stop();this.isRecording = false;console.info('录音已保存:', this.outputPath);}build() { Column() { Button(this.isRecording ? '停止录音' : '开始录音').onClick(() => { if (this.isRecording) { this.stopRecord();} else { this.startRecord();}})}}aboutToDisappear() { this.avRecorder?.release();}}

三、视频播放与录制

3.1 视频播放

使用 AVPlayerXComponent 播放视频:

import {media } from '@kit.MediaKit';@Entry@Componentstruct VideoPlayer { private avPlayer?: media.AVPlayer;private surfaceId: string = '';@State isPlaying: boolean = false;async initPlayer(videoUri: string) { try { this.avPlayer = await media.createAVPlayer();this.avPlayer.on('stateChange', (state: string) => { console.info(`播放器状态: ${ state}`);});this.avPlayer.url = videoUri;this.avPlayer.surfaceId = this.surfaceId;} catch (err) { console.error('初始化播放器失败:', JSON.stringify(err));}}build() { Column() { XComponent({ id: 'video_surface',type: XComponentType.SURFACE,controller: new XComponentController()}).onLoad((context?: object) => { this.surfaceId = (context as {surfaceId: string }).surfaceId;this.initPlayer('file://...');}).width('100%').height(300)Button(this.isPlaying ? '暂停' : '播放').onClick(async () => { if (this.isPlaying) { await this.avPlayer?.pause();} else { await this.avPlayer?.play();}this.isPlaying = !this.isPlaying;})}}}

3.2 视频录制

使用相机 API 录制视频:

import {camera } from '@kit.CameraKit';@Componentexport struct VideoRecorder { private cameraManager?: camera.CameraManager;private videoOutput?: camera.VideoOutput;@State isRecording: boolean = false;async initCamera() { try { this.cameraManager = camera.getCameraManager(getContext(this));const cameras = this.cameraManager.getSupportedCameras();if (cameras.length === 0) { console.error('没有可用相机');return;}const cameraInput = this.cameraManager.createCameraInput(cameras[0]);await cameraInput.open();const profile: camera.VideoProfile = { format: camera.CameraFormat.CAMERA_FORMAT_YUV_420_SP,size: {width: 1920, height: 1080 },frameRateRange: {min: 30, max: 30 }};this.videoOutput = this.cameraManager.createVideoOutput(profile, 'fd://...');const session = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO);session.beginConfig();session.addInput(cameraInput);session.addOutput(this.videoOutput);await session.commitConfig();await session.start();console.info('相机初始化完成');} catch (err) { console.error('初始化相机失败:', JSON.stringify(err));}}async startRecord() { await this.videoOutput?.start();this.isRecording = true;}async stopRecord() { await this.videoOutput?.stop();this.isRecording = false;}build() { Column() { Button(this.isRecording ? '停止录制' : '开始录制').onClick(() => { if (this.isRecording) { this.stopRecord();} else { this.startRecord();}})}}}

四、权限申请

媒体功能需要申请相应权限:

4.1 module.json5 配置

{"module": {"requestPermissions": [{"name": "ohos.permission.READ_IMAGEVIDEO","reason": "$string:permission_read_media","usedScene": { "when": "inuse" }},{"name": "ohos.permission.WRITE_IMAGEVIDEO","reason": "$string:permission_write_media","usedScene": { "when": "inuse" }},{"name": "ohos.permission.MICROPHONE","reason": "$string:permission_microphone","usedScene": { "when": "inuse" }},{"name": "ohos.permission.CAMERA","reason": "$string:permission_camera","usedScene": { "when": "inuse" }}]}}

4.2 运行时申请

import {abilityAccessCtrl, Permissions } from '@kit.AbilityKit';async function requestPermissions(): Promise { const permissions: Permissions[] = ['ohos.permission.READ_IMAGEVIDEO','ohos.permission.MICROPHONE','ohos.permission.CAMERA'];const context = getContext(this);const atManager = abilityAccessCtrl.createAtManager();try { const result = await atManager.requestPermissionsFromUser(context, permissions);return result.authResults.every(r => r === 0);} catch (err) { console.error('权限申请失败:', JSON.stringify(err));return false;}}

五、实战案例:完整的媒体播放器

import {media } from '@kit.MediaKit';import {picker } from '@kit.CoreFileKit';@Entry@Componentstruct MediaPlayerDemo { private avPlayer?: media.AVPlayer;@State mediaUri: string = '';@State isPlaying: boolean = false;@State currentTime: number = 0;@State duration: number = 0;async selectMedia() { try { const options = new picker.PhotoSelectOptions();options.MIMEType = picker.PhotoViewMIMETypes.VIDEO_TYPE;options.maxSelectNumber = 1;const photoPicker = new picker.PhotoViewPicker();const result = await photoPicker.select(options);if (result.photoUris.length > 0) { this.mediaUri = result.photoUris[0];await this.initPlayer();}} catch (err) { console.error('选择媒体失败:', JSON.stringify(err));}}async initPlayer() { this.avPlayer = await media.createAVPlayer();this.avPlayer.on('timeUpdate', (time: number) => { this.currentTime = time;});this.avPlayer.on('durationUpdate', (duration: number) => { this.duration = duration;});this.avPlayer.url = this.mediaUri;}build() { Column() { Text('HarmonyOS 媒体播放器').fontSize(24).fontWeight(FontWeight.Bold)Button('选择视频').onClick(() => this.selectMedia()).margin({top: 20 })if (this.mediaUri) { Text(`播放中: ${ this.mediaUri.split('/').pop()}`).margin({top: 10 })Row() { Button(this.isPlaying ? '暂停' : '播放').onClick(async () => { if (this.isPlaying) { await this.avPlayer?.pause();} else { await this.avPlayer?.play();}this.isPlaying = !this.isPlaying;})Button('停止').onClick(async () => { await this.avPlayer?.stop();this.isPlaying = false;})}.margin({top: 20 })}}.width('100%').height('100%').padding(20)}aboutToDisappear() { this.avPlayer?.release();}}

六、性能优化建议

6.1 图片加载优化

使用缩略图预览大图 异步解码避免主线程阻塞 实现图片缓存机制

6.2 音视频播放优化

预加载下一个媒体文件 实现播放进度保存与恢复 监听系统中断事件(来电等)

6.3 内存管理

及时释放 PixelMap 和 AVPlayer 使用弱引用避免内存泄漏 监控内存占用并主动回收

总结

本文系统介绍了 HarmonyOS 的媒体能力,涵盖:

图片处理 — Picker 选择、解码显示、压缩保存 音频能力 — AVPlayer 播放、AVRecorder 录制 视频能力 — 视频播放、相机录制 权限管理 — 静态声明与动态申请 实战案例 — 完整媒体播放器实现 性能优化 — 内存管理与加载优化

掌握这些能力后,你就可以开发功能完整的媒体类应用了。

喜欢(0)

上一篇

企业内网终端标准化运维实战:功能落地拆解与避坑干货

企业内网终端标准化运维实战:功能落地拆解与避坑干货

下一篇

YARN提交任务的两种方式

YARN提交任务的两种方式
猜你喜欢