注册网站授权书怎么写,linux vps网站搬家命令,公司注册资金多少合适,太原小店区最新消息今天Media Kit 特点
一般场合的音视频处理#xff0c;可以直接使用系统集成的Video组件#xff0c;不过外观和功能自定义程度低Media kit#xff1a;轻量媒体引擎#xff0c;系统资源占用低支持音视频播放/录制#xff0c;pipeline灵活拼装#xff0c;插件化扩展source/demu…Media Kit 特点
一般场合的音视频处理可以直接使用系统集成的Video组件不过外观和功能自定义程度低Media kit轻量媒体引擎系统资源占用低支持音视频播放/录制pipeline灵活拼装插件化扩展source/demuxer/codec原生支持HDR vivid的采集与播放支持音频池SoundPool低时延播放短促音效场景如相机快门音效、信息通知
Media Kit 常用类
AVPlayer播放AVRecorder录制SoundPool短促提示音
音频播放
流程创建AVPlayer设置播放资源设置播放参数音量/倍速/焦点模式播放控制播放/暂停/跳转/停止通过AVPlayer的state属性主动获取当前状态或用on(‘stateChange’)监听状态变化如要实现后台播放或熄屏播放需要使用AVSession媒体会话和申请长时任务避免播放被系统强制中断
创建实例createAVPlayer()AVPlayer初始化idle状态设置业务需要的监听事件搭配全流程场景使用设置资源设置属性urlAVPlayer进入initialized状态准备播放调用prepare()AVPlayer进入prepared状态此时可以获取duration设置音量音频播控播放play()暂停pause()跳转seek()停止stop() 等 SoundPool - 音频池
SoundPool当前支持播放1MB以下的音频资源超过1MB将被截断。过程创建SoundPool实例加载音频设置参数循环模式/播放优先级等播放控制播放/停止释放。 createSoundPool方法创建SoundPool实例 load方法进行音频资源加载。可以传入uri或fd加载资源此处使用传入uri的方式为例 on(‘loadComplete’)方法用于监听“资源加载完成” on(‘playFinished’)方法用于监听“播放完成” on(‘error’)方法设置错误类型监听 配置播放参数PlayParameters并调用play方法播放音频。多次调用play播放同一个soundID只会播放一次 调用setLoop方法设置循环次数 创建实例
import audio from ohos.multimedia.audio;
import media from ohos.multimedia.media;
import fs from ohos.file.fs
import { BusinessError } from kit.BasicServicesKit;Entry
Component
struct SoundPoolPage {soundPool?: media.SoundPool;streamId: number 0;soundId: number 0;audioRendererInfo: audio.AudioRendererInfo {usage: audio.StreamUsage.STREAM_USAGE_MUSIC,rendererFlags: 1}PlayParameters: media.PlayParameters {loop: 3, // 循环4次rate: audio.AudioRendererRate.RENDER_RATE_NORMAL, // 正常倍速leftVolume: 0.5, // range 0.0-1.0rightVolume: 0.5, // range 0.0-1.0priority: 0, // 最低优先级}uri: string ;aboutToAppear(): void {this.create()}build() {Column() {Button(SoundPool播放).onClick(() {// this.PlaySoundPool()this.soundPool!.play(this.soundId).then(() {}).catch((error: BusinessError) {console.error(play error error.message)})})}.justifyContent(FlexAlign.Center).width(100%).height(100%)}async create() {//创建soundPool实例this.soundPool await media.createSoundPool(5, this.audioRendererInfo);//注册监听this.loadCallback();this.finishPlayCallback();this.setErrorCallback();// 加载音频资源await fs.open(getContext(this).filesDir /02.mp3, fs.OpenMode.READ_ONLY).then((file: fs.File) {console.info(file fd: file.fd);this.uri fd:// (file.fd).toString()}); // /02.mp3 作为样例使用时需要传入文件对应路径。this.soundId await this.soundPool!.load(this.uri);}async loadCallback() {// 加载完成回调this.soundPool!.on(loadComplete, (soundId_: number) {console.info(loadComplete, soundId: soundId_);})}//设置播放完成监听async finishPlayCallback() {// 播放完成回调this.soundPool!.on(playFinished, () {console.info(recive play finished message);// 可进行下次播放})}//设置错误类型监听setErrorCallback() {this.soundPool!.on(error, (error) {console.info(error happened,message is : error.message);})}async PlaySoundPool() {// // 设置循环播放次数// this.soundPool!.setLoop(this.streamId, 2); // 播放3次// // 设置对应流的优先级// this.soundPool!.setPriority(this.streamId, 1);// // 设置音量// this.soundPool!.setVolume(this.streamId, 0.5, 0.5);// 开始播放,这边play也可带播放播放的参数PlayParametersthis.streamId await this.soundPool!.play(this.soundId);}async release() {// 终止指定流的播放this.soundPool!.stop(this.streamId);// 卸载音频资源await this.soundPool!.unload(this.soundId);//关闭监听this.setOffCallback();// 释放SoundPoolawait this.soundPool!.release();}//关闭监听setOffCallback() {this.soundPool!.off(loadComplete);this.soundPool!.off(playFinished);this.soundPool!.off(error);}
}AVRecorder - 音频录制
可通过AVRecorder的state属性获取当前状态或使用on(‘stateChange’)方法监听状态变化。开发过程中应该严格遵循状态机要求例如只能在started状态下调用pause()只能在paused状态下调用resume()。
创建AVRecorder实例实例创建完成进入idle状态。设置业务需要的监听事件监听状态变化及错误上报。配置音频录制参数调用prepare()接口此时进入prepared状态。开始录制调用start()接口此时进入started状态。暂停录制调用pause()接口此时进入paused状态。恢复录制调用resume()接口此时再次进入started状态。停止录制调用stop()接口此时进入stopped状态。
import media from ohos.multimedia.media;
import { BusinessError } from ohos.base;
import fs from ohos.file.fs;
import AVPlayerDemo from ../utils/AVPlayerDemo;
import { abilityAccessCtrl, Permissions } from kit.AbilityKit;Entry
Component
struct AVRecorderAudioPage {readonly fileName 03.mp3player new AudioRecorderDemo(getContext(this), this.fileName)aboutToAppear() {const permission: Permissions[] [ohos.permission.MICROPHONE]abilityAccessCtrl.createAtManager().requestPermissionsFromUser(getContext(this), permission).then((result) {if (result.authResults.indexOf(-1) -1) {}})}build() {Row() {Column() {Button(开始录制).margin({ bottom: 20 }).onClick(() {this.player.startRecordingProcess();})Button(暂停录制).margin({ bottom: 20 }).onClick(() {this.player.pauseRecordingProcess();})Button(恢复录制).margin({ bottom: 20 }).onClick(() {this.player.resumeRecordingProcess();})Button(停止录制).margin({ bottom: 20 }).onClick(() {this.player.stopRecordingProcess();})Button(播放录音).margin({ bottom: 20 }).onClick(() {const playerDemo new AVPlayerDemo(this.fileName)playerDemo.avPlayerUrlDemo()})}.width(100%)}.height(100%)}aboutToDisappear(): void {this.player.stopRecordingProcess();}
}class AudioRecorderDemo {private context: Contextprivate fileName: stringprivate file?: fs.Fileprivate avRecorder: media.AVRecorder | undefined undefined;private avProfile: media.AVRecorderProfile {audioBitrate: 100000, // 音频比特率audioChannels: 2, // 音频声道数audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式当前只支持aacaudioSampleRate: 48000, // 音频采样率fileFormat: media.ContainerFormatType.CFT_MPEG_4A, // 封装格式当前只支持m4a-};private avConfig: media.AVRecorderConfig {audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, // 音频输入源这里设置为麦克风profile: this.avProfile,url: fd://35, // 参考应用文件访问与管理开发示例新建并读写一个文件};constructor(context: Context, fileName: string) {this.context contextthis.fileName fileName}// 注册audioRecorder回调函数setAudioRecorderCallback() {if (this.avRecorder ! undefined) {// 状态机变化回调函数this.avRecorder.on(stateChange, (state: media.AVRecorderState, reason: media.StateChangeReason) {console.log(AudioRecorder current state is ${state});})// 错误上报回调函数this.avRecorder.on(error, (err: BusinessError) {console.error(AudioRecorder failed, code is ${err.code}, message is ${err.message});})}}// 开始录制对应的流程async startRecordingProcess() {if (this.avRecorder ! undefined) {await this.avRecorder.release();this.avRecorder undefined;}// 1.创建录制实例this.avRecorder await media.createAVRecorder();this.setAudioRecorderCallback();// 2.获取录制文件fd赋予avConfig里的url参考FilePicker文档this.file fs.openSync(this.context.filesDir / this.fileName, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)this.avConfig.url fd:// this.file.fd// 3.配置录制参数完成准备工作await this.avRecorder.prepare(this.avConfig);// 4.开始录制await this.avRecorder.start();}// 暂停录制对应的流程async pauseRecordingProcess() {if (this.avRecorder ! undefined this.avRecorder.state started) { // 仅在started状态下调用pause为合理状态切换await this.avRecorder.pause();}}// 恢复录制对应的流程async resumeRecordingProcess() {if (this.avRecorder ! undefined this.avRecorder.state paused) { // 仅在paused状态下调用resume为合理状态切换await this.avRecorder.resume();}}// 停止录制对应的流程async stopRecordingProcess() {if (this.avRecorder ! undefined) {// 1. 停止录制if (this.avRecorder.state started|| this.avRecorder.state paused) { // 仅在started或者paused状态下调用stop为合理状态切换await this.avRecorder.stop();}// 2.重置await this.avRecorder.reset();// 3.释放录制实例await this.avRecorder.release();this.avRecorder undefined;// 4.关闭录制文件fdfs.close(this.file)}}
}获取音视频元数据
以获取一个音频资源的元信息为例讲解AVMetadataExtractor。视频资源元信息获取类似由于视频没有专辑封面所以无法获取。
开发步骤
使用createAVMetadataExtractor()创建实例。设置资源用户可以根据需要选择设置属性fdSrc表示文件描述符, 或者设置属性dataSrc表示dataSource描述符。获取元信息调用fetchMetadata()可以获取到一个AVMetadata对象通过访问该对象的各个属性可以获取到元信息。可选获取专辑封面调用fetchAlbumCover()可以获取到专辑封面。释放资源调用release()销毁实例释放资源。
import media from ohos.multimedia.media
import image from ohos.multimedia.image
import type common from ohos.app.ability.common;
import fs from ohos.file.fs;const TAG MetadataDemoEntry
Component
struct AVMetadataExtractorPage {// pixelMap对象声明用于图片显示State pixelMap: image.PixelMap | undefined undefined;State title?: string undefinedState artist?: string undefinedState album?: string undefinedState genre?: string undefinedState mimeType?: string undefinedbuild() {Row() {Column() {// Row() {Button(FdSrcByCallback).margin({ bottom: 10 }).onClick(() {// 设置fdSrc, 获取音频元信息和专辑封面异步接口以Callback形式调用this.testFetchMetadataFromFdSrcByCallback()})Button(FdSrcByPromise).margin({ bottom: 10 }).onClick(() {// 设置fdSrc, 获取音频元信息和专辑封面异步接口以Promise形式调用this.testFetchMetadataFromFdSrcByPromise()})Button(DataSrc).margin({ bottom: 10 }).onClick(() {// 设置dataSrc, 获取音频元信息和专辑封面this.testFetchMetadataFromDataSrc()})// }Text(标题 this.title)Text(歌手 this.artist)Text(专辑 this.album)Text(曲风 this.genre)Text(mimeType this.mimeType)Image(this.pixelMap).width(300).height(300).margin({top: 20})}.width(100%)}.height(100%)}// 在以下demo中使用资源管理接口获取打包在HAP内的媒体资源文件通过设置fdSrc属性获取音频元信息并打印// 获取音频专辑封面并通过Image控件显示在屏幕上。该demo以Callback形式进行异步接口调用async testFetchMetadataFromFdSrcByCallback() {// 创建AVMetadataExtractor对象let avMetadataExtractor: media.AVMetadataExtractor await media.createAVMetadataExtractor()// 设置fdSrcavMetadataExtractor.fdSrc await getContext(this).resourceManager.getRawFd(01.mp3);// 获取元信息callback模式avMetadataExtractor.fetchMetadata((error, metadata) {if (error) {console.error(TAG, fetchMetadata callback failed, err ${JSON.stringify(error)})return}console.info(TAG, fetchMetadata callback success, genre: ${metadata.genre})this.showMetadata(metadata)})//获取专辑封面callback模式avMetadataExtractor.fetchAlbumCover((err, pixelMap) {if (err) {console.error(TAG, fetchAlbumCover callback failed, err ${JSON.stringify(err)})return}this.pixelMap pixelMap// 释放资源callback模式avMetadataExtractor.release((error) {if (error) {console.error(TAG, release failed, err ${JSON.stringify(error)})return}console.info(TAG, release success.)})})}// 在以下demo中使用资源管理接口获取打包在HAP内的媒体资源文件通过设置fdSrc属性获取音频元信息并打印// 获取音频专辑封面并通过Image控件显示在屏幕上。该demo以Promise形式进行异步接口调用async testFetchMetadataFromFdSrcByPromise() {// 创建AVMetadataExtractor对象let avMetadataExtractor: media.AVMetadataExtractor await media.createAVMetadataExtractor()// 设置fdSrcavMetadataExtractor.fdSrc await getContext(this).resourceManager.getRawFd(01.mp3);// 获取元信息promise模式let metadata await avMetadataExtractor.fetchMetadata()console.info(TAG, get meta data, hasAudio: ${metadata.hasAudio})this.showMetadata(metadata)// 获取专辑封面promise模式this.pixelMap await avMetadataExtractor.fetchAlbumCover()// 释放资源promise模式avMetadataExtractor.release()console.info(TAG, release success.)}// 在以下demo中使用fs文件系统打开沙箱地址获取媒体文件地址设置dataSrc属性获取音频元信息并打印// 获取音频专辑封面并通过Image控件显示在屏幕上。async testFetchMetadataFromDataSrc() {let context getContext(this) as common.UIAbilityContext// 通过UIAbilityContext获取沙箱地址filesDir以Stage模型为例let filePath: string context.filesDir /01.mp3;let fd: number fs.openSync(filePath, 0o0).fd;let fileSize: number fs.statSync(filePath).size;// 设置dataSrc描述符通过callback从文件中获取资源写入buffer中let dataSrc: media.AVDataSrcDescriptor {fileSize: fileSize,callback: (buffer, len, pos) {if (buffer undefined || len undefined || pos undefined) {console.error(TAG, dataSrc callback param invalid)return -1}class Option {offset: number | undefined 0;length: number | undefined len;position: number | undefined pos;}let options new Option();let num fs.readSync(fd, buffer, options)console.info(TAG, readAt end, num: num)if (num 0 fileSize pos) {return num;}return -1;}}// 创建AVMetadataExtractor对象let avMetadataExtractor await media.createAVMetadataExtractor()// 设置dataSrcavMetadataExtractor.dataSrc dataSrc;// 获取元信息promise模式let metadata await avMetadataExtractor.fetchMetadata()console.info(TAG, get meta data, mimeType: ${metadata.mimeType})this.showMetadata(metadata)// 获取专辑封面promise模式this.pixelMap await avMetadataExtractor.fetchAlbumCover()// 释放资源promise模式avMetadataExtractor.release()console.info(TAG, release data source success.)}showMetadata(metadata: media.AVMetadata) {this.title metadata.titlethis.artist metadata.artistthis.album metadata.albumthis.genre metadata.genrethis.mimeType metadata.mimeType}
}视频播放/录制
开发步骤
调用createAVPlayer()创建AVPlayer实例初始化进入idle状态。设置业务需要的监听事件搭配全流程场景使用。设置资源设置属性urlAVPlayer进入initialized状态。设置窗口获取并设置属性SurfaceID用于设置显示画面。应用需要从XComponent组件获取surfaceID获取方式请参考XComponent。准备播放调用prepare()AVPlayer进入prepared状态此时可以获取duration设置缩放模式、音量等。视频播控播放play()暂停pause()跳转seek()停止stop() 等操作。可选更换资源调用reset()重置资源AVPlayer重新进入idle状态允许更换资源url。退出播放调用release()销毁实例AVPlayer进入released状态退出播放。
import media from ohos.multimedia.media;
import fs from ohos.file.fs;
import common from ohos.app.ability.common;
import { BusinessError } from ohos.base;export default class AVPlayerDemo {fileName: stringsurfaceID?: stringprivate count: number 0;private isSeek: boolean true; // 用于区分模式是否支持seek操作private fileSize: number -1;private fd: number 0;avPlayer?: media.AVPlayerconstructor(fileName: string, surfaceID?: string) {this.fileName fileNamethis.surfaceID surfaceID}stop() {this.avPlayer?.stop()this.avPlayer?.release()}// 注册avplayer回调函数setAVPlayerCallback(avPlayer: media.AVPlayer) {// seek操作结果回调函数avPlayer.on(seekDone, (seekDoneTime: number) {console.info(AVPlayer seek succeeded, seek time is ${seekDoneTime});})// error回调监听函数,当avPlayer在操作过程中出现错误时调用 reset接口触发重置流程avPlayer.on(error, (err: BusinessError) {console.error(Invoke avPlayer failed, code is ${err.code}, message is ${err.message});avPlayer.reset(); // 调用reset重置资源触发idle状态})// 状态机变化回调函数avPlayer.on(stateChange, async (state: string, reason: media.StateChangeReason) {switch (state) {case idle: // 成功调用reset接口后触发该状态机上报console.info(AVPlayer state idle called.);avPlayer.release(); // 调用release接口销毁实例对象break;case initialized: // avplayer 设置播放源后触发该状态上报console.info(AVPlayer state initialized called.);if (this.surfaceID) {avPlayer.surfaceId this.surfaceID}avPlayer.prepare();break;case prepared: // prepare调用成功后上报该状态机console.info(AVPlayer state prepared called.);avPlayer.play(); // 调用播放接口开始播放break;case playing: // play成功调用后触发该状态机上报console.info(AVPlayer state playing called.);if (this.isSeek) { //如果是seek播放 拖到到指定时长的位置播放console.info(AVPlayer start to seek.);avPlayer.seek(avPlayer.duration / 2 - 1500); //seek到音频中间} else {// 当播放模式不支持seek操作时继续播放到结尾console.info(AVPlayer wait to play end.);}break;case paused: // pause成功调用后触发该状态机上报console.info(AVPlayer state paused called.);avPlayer.play(); // 再次播放接口开始播放break;case completed: // 播放结束后触发该状态机上报console.info(AVPlayer state completed called.);avPlayer.stop(); //调用播放结束接口break;case stopped: // stop接口成功调用后触发该状态机上报console.info(AVPlayer state stopped called.);avPlayer.reset(); // 调用reset接口初始化avplayer状态break;case released:console.info(AVPlayer state released called.);break;default:console.info(AVPlayer state unknown called.);break;}})}// 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过url属性进行播放示例async avPlayerUrlDemo() {this.stop()// 创建avPlayer实例对象this.avPlayer await media.createAVPlayer();// 创建状态机变化回调函数this.setAVPlayerCallback(this.avPlayer);let fdPath fd://;// 通过UIAbilityContext获取沙箱地址filesDir以Stage模型为例let context getContext(this) as common.UIAbilityContext;let pathDir context.filesDir;let path pathDir / this.fileName;// 打开相应的资源文件地址获取fd并为url赋值触发initialized状态机上报let file await fs.open(path);fdPath fdPath file.fd;this.isSeek false; // 支持seek操作this.avPlayer.url fdPath;}// 以下demo为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放示例async avPlayerFdSrcDemo() {this.stop()// 创建avPlayer实例对象this.avPlayer await media.createAVPlayer();// 创建状态机变化回调函数this.setAVPlayerCallback(this.avPlayer!);// 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址// 返回类型为{fd,offset,length},fd为HAP包fd地址offset为媒体资源偏移量length为播放长度let context getContext(this) as common.UIAbilityContext;let fileDescriptor await context.resourceManager.getRawFd(this.fileName);let avFileDescriptor: media.AVFileDescriptor { fd: fileDescriptor.fd, offset: fileDescriptor.offset, length: fileDescriptor.length };this.isSeek false; // 支持seek操作// 为fdSrc赋值触发initialized状态机上报this.avPlayer.fdSrc avFileDescriptor;}// 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放(seek模式)示例async avPlayerDataSrcSeekDemo() { //拖动进度条播放跳转到指定的时间位置seekthis.stop()// 创建avPlayer实例对象this.avPlayer await media.createAVPlayer();// 创建状态机变化回调函数this.setAVPlayerCallback(this.avPlayer); //在这里设定了 seek位置// dataSrc播放模式的的播放源地址当播放为Seek模式时fileSize为播放文件的具体大小下面会对fileSize赋值let src: media.AVDataSrcDescriptor {fileSize: -1,callback: (buf: ArrayBuffer, length: number, pos: number | undefined) {let num 0;if (buf undefined || length undefined || pos undefined) {return -1;}num fs.readSync(this.fd, buf, { offset: pos, length: length });if (num 0 (this.fileSize pos)) {return num;}return -1;}}let context getContext(this) as common.UIAbilityContext;// 通过UIAbilityContext获取沙箱地址filesDir以Stage模型为例let pathDir context.filesDir;let path pathDir / this.fileName;await fs.open(path).then((file: fs.File) {this.fd file.fd;})// 获取播放文件的大小this.fileSize fs.statSync(path).size;src.fileSize this.fileSize;this.isSeek true; // 支持seek操作this.avPlayer.dataSrc src;}// 以下demo为使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放(No seek模式)示例async avPlayerDataSrcNoSeekDemo() {this.stop()// 创建avPlayer实例对象this.avPlayer await media.createAVPlayer();// 创建状态机变化回调函数this.setAVPlayerCallback(this.avPlayer);let context getContext(this) as common.UIAbilityContext;let src: media.AVDataSrcDescriptor {fileSize: -1,callback: (buf: ArrayBuffer, length: number) {let num 0;if (buf undefined || length undefined) {return -1;}num fs.readSync(this.fd, buf);if (num 0) {return num;}return -1;}}// 通过UIAbilityContext获取沙箱地址filesDir以Stage模型为例let pathDir context.filesDir;let path pathDir / this.fileName;await fs.open(path).then((file: fs.File) {this.fd file.fd;})this.isSeek false;this.avPlayer.dataSrc src;}// 以下demo为通过url设置网络地址来实现播放直播码流的demoasync avPlayerLiveDemo() {this.stop()// 创建avPlayer实例对象this.avPlayer await media.createAVPlayer();// 创建状态机变化回调函数this.setAVPlayerCallback(this.avPlayer);this.isSeek false; // 不支持seek操作if (this.surfaceID) {this.avPlayer.url http://www.w3school.com.cn/example/html5/mov_bbb.mp4} else {this.avPlayer.url https://sdk-release.qnsdk.com/1599039859854_9242359.mp3;}}
}