鸿蒙-AVPlayer
compileVersion 5.0.2(14)
音频播放
import media from '@ohos.multimedia.media';
import common from '@ohos.app.ability.common';
import { BusinessError } from '@ohos.base';@Entry
@Component
struct AudioPlayer {private avPlayer: media.AVPlayer | null = null;@State isPlaying: boolean = false;@State playProgress: number = 0;private timerId: number | null = null; // 存储定时器IDprivate readonly audioPath: string = 'qingtian.mp3';//页面初始化aboutToAppear() {this.initAudioPlayer();}//页面销毁aboutToDisappear(): void {this.releasePlayer();}// 修改为异步函数private async initAudioPlayer() {console.log('initAudioPlayer=====');const context = getContext(this) as common.UIAbilityContext;const resourceManager = context.resourceManager;try {// 添加await处理Promiseconst fdObj = await resourceManager.getRawFd(this.audioPath);const avFileDescriptor: media.AVFileDescriptor = {fd: fdObj.fd,offset: fdObj.offset, // 已正确处理offset属性length: fdObj.length};media.createAVPlayer((err: BusinessError, player: media.AVPlayer) => {if (err) {console.error('创建播放器失败: ' + JSON.stringify(err));return;}console.info('创建播放器success');this.avPlayer = player;this.setupPlayerEvents();this.avPlayer.fdSrc = avFileDescriptor;});} catch (error) {console.error('文件加载失败: ' + JSON.stringify(error));}}private setupPlayerEvents() {if (!this.avPlayer) {return;}// 修改为字符串状态匹配this.avPlayer.on('stateChange', (state: string) => {console.log('stateChange:' + state);switch (state) {case 'initialized': // 原media.AVPlayerState.PREPAREDthis.avPlayer?.prepare();break;case 'prepared': // 原media.AVPlayerState.PREPAREDconsole.log('准备完成');break;case 'playing': // 原media.AVPlayerState.PLAYINGthis.isPlaying = true;this.startProgressTracking();break;case 'paused': // 原media.AVPlayerState.PAUSEDthis.isPlaying = false;this.stopProgressUpdate();break;case 'completed': // 原media.AVPlayerState.COMPLETEDthis.isPlaying = false;this.playProgress = 100;this.stopProgressUpdate();break;}});this.avPlayer.on('error', (err: BusinessError) => {console.error('播放错误: ' + JSON.stringify(err));this.releasePlayer();this.initAudioPlayer();});}// 开始播放进度跟踪private startProgressTracking() {console.log('startProgressTracking=====');this.timerId = setInterval(() => {if (this.avPlayer && this.avPlayer.duration > 0) {console.log('setInterval currentTime=' + this.avPlayer.currentTime + ' duration=' + this.avPlayer.duration);this.playProgress = (this.avPlayer.currentTime / this.avPlayer.duration) * 100;}}, 1000);console.log('this.timerId=' + this.timerId);}// 停止进度更新private stopProgressUpdate() {console.log('stopProgressUpdate=====');if (this.timerId !== null) {clearInterval(this.timerId);this.timerId = null;}}// 释放播放器资源private releasePlayer() {console.log('releasePlayer=====');if (this.avPlayer) {this.avPlayer.release();this.avPlayer = null;}}// 播放/暂停控制private togglePlayback() {if (!this.avPlayer) {return;}if (this.isPlaying) {this.avPlayer.pause();} else {if (this.avPlayer.currentTime >= this.avPlayer.duration) {this.avPlayer.seek(0);}this.avPlayer.play();}}build() {Column() {// 播放控制区域Row({ space: 20 }) {Button(this.isPlaying ? '暂停' : '播放').onClick(() => this.togglePlayback()).width(100).height(40)Progress({ value: this.playProgress, total: 100 }).width('60%').height(10).color('#409EFF')}.padding(20).width('100%')// 音频信息显示Text('当前播放:' + this.audioPath.split('/').pop()).fontSize(16).margin({ top: 20 })}.width('100%').height('100%').padding(20).backgroundColor('#F5F5F5')}
}
media.AVFileDescriptor
fd:文件描述符
- 含义:操作系统分配的唯一标识符,代表已打开的文件句柄(file descriptor)。
- 作用:
-
- 系统通过该标识符定位具体的媒体文件(如存储在rawfile目录下的音频文件或HAP包内嵌资源)
- 用于跨进程文件访问时传递文件引用(如播放器服务与UI界面的数据交互)
- 示例:通过
resourceManager.getRawFd('music.mp3')获取打包资源文件的描述符
offset:文件偏移量
- 含义:从文件起始位置到目标数据的字节偏移量(单位:字节)。
- 技术细节:
-
- 当媒体文件被压缩或打包时(如HAP资源文件),需跳过文件头等非音频数据部分
- 支持精确指定播放起始点(如从视频第10秒开始播放,需计算对应的字节偏移)
- 示例:若资源文件在HAP包中的物理偏移为1024字节,则offset需设为1024
length:数据长度
- 含义:需要读取的媒体数据总长度(单位:字节)。
- 关键作用:
-
- 限制播放器读取范围,避免处理无关数据(如仅播放某段音频或视频片段)
- 防止越界读取导致的崩溃(如文件实际大小小于声明长度时触发错误码5400102)
- 示例:从HAP包中读取一个30秒的MP3片段时,需通过
fs.statSync获取精确文件长度
参数关系与开发规范
| 参数 | 典型取值范围 | 异常处理建议 |
| fd | ≥0(0表示无效句柄) | 检查fs.open()返回值是否有效 |
| offset | 0 ≤ offset ≤ 文件大小-1 | 配合fs.stat验证偏移有效性 |
| length | 1 ≤ length ≤ 剩余字节数 | 动态计算:length = 文件大小 - offset |
示例
播放HAP内嵌资源
typescriptconst fdObj = await resourceManager.getRawFd('music.mp3');
const avFileDescriptor = {fd: fdObj.fd,offset: fdObj.offset, // 自动处理HAP打包偏移length: fdObj.length // 精确获取资源实际长度
};
avPlayer.fdSrc = avFileDescriptor; // 直接绑定播放源[3](@ref)
分段播放大型文件
typescript// 播放视频第60-120秒的内容
const startOffset = 60 * bitrate; // 根据码率计算字节偏移
const playLength = 60 * bitrate;
avPlayer.fdSrc = { fd, offset: startOffset, length: playLength };
开发注意事项:
- 若
offset + length超过实际文件大小,将触发BusinessError 5400102(参数非法) - 使用
fs.close(fd)在aboutToDisappear生命周期关闭文件描述符,避免资源泄漏 - 在
on('error')回调中处理文件访问异常(如权限不足或文件损坏)
相关文章:
鸿蒙-AVPlayer
compileVersion 5.0.2(14) 音频播放 import media from ohos.multimedia.media; import common from ohos.app.ability.common; import { BusinessError } from ohos.base;Entry Component struct AudioPlayer {private avPlayer: media.AVPlayer | nu…...
解决单元测试 mock final类报错
文章目录 前言解决单元测试 mock final类报错1. 报错原因2. 解决方案3. 示例demo4. 扩展 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差࿰…...
Kafka消费者相关
Kafka生产者相关-CSDN博客 消费者消费数据基本流程 package com.hrui;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache…...
Vue nextTick原理回顾
nextTick就是将异步函数放在下一次实践循环的微任务队列中执行 实现原理比较简单,极简版本: function myNextTick(cb){let p;pPromise.resolve().then(cb)return cb?p:Promise.resolve() }复杂版本,考虑异步函数入队、执行锁、兼容处理 l…...
JavaWeb登录认证
在Web系统中,如果没有登录功能和登录认证,是可以直接访问到Web系统的后台的。 这是不安全的,所以我们今天的主题就是登录认证。最终要实现的效果是: 如果用户名密码错误,不允许登录系统。如果用户名和密码都正确&…...
半导体制造工艺(二)光刻工艺—掩模版
在上文中我们已经简单概述了光刻工艺的大致流程。接下来将会介绍在光刻工艺中所需用到的必备材料以及设备。例如掩模版、光刻胶、匀胶机、光刻机等等。由于需要保持讲述工艺的完整性以及流畅,每一个都需要涉及,所以每次仅是侧重点不同。此篇主要讲述的是…...
计算机视觉算法实战——高精度分割(主页有源码)
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 1. 高精度分割领域简介✨✨ 图像分割是计算机视觉中的核心任务之一,其目标是将图像划分为多个语义区域,并为…...
DeepSeek-R1-Zero:基于基础模型的强化学习
注:此文章内容均节选自充电了么创始人,CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》(人工智能科学与技术丛书)【陈敬雷编著】【清华大学出版社】 文章目录 DeepSeek大模型技术系列四DeepSeek大模型技术系列四》DeepSeek-…...
判断一个文件中以三个#号开头有多少行的shell脚本怎么写
在Linux中,你可以使用grep命令结合正则表达式来统计一个文件中以三个#号开头的行数。以下是一个简单的命令: grep -c ^### filename这里的grep是搜索工具,-c选项表示统计匹配的行数,###是正则表达式,表示行…...
PHP如何与HTML结合使用?
PHP与HTML结合使用的主要方式是通过在HTML文件中嵌入PHP代码,从而实现动态内容的生成和网页的交互性。以下是详细的方法和最佳实践: 1. 嵌入PHP代码到HTML中 PHP代码可以直接嵌入到HTML文件中,通过<?php ?>标签来包裹PHP代码。服务…...
计算机网络之传输层(传输层的功能)
一、数据分段与重组 传输层从会话层接收数据,并将其分割成较小的数据段,以适应网络层的最大传输单元(MTU)限制。在目的端,传输层负责将这些数据段重新组合成原始数据,确保数据的完整性和正确性。 二、端口…...
矩阵碰一碰发视频源码搭建之,支持OEM
引言 阵碰一碰发视频" 技术凭借其便捷的交互方式和高效的传播能力,已成为品牌推广和内容创作的重要工具。为进一步提升视频传播效果,本文将深入探讨如何在矩阵碰一碰系统中集成 AI 文案生成功能,实现 "一碰即传 智能文案" 的…...
DeepSeek 2月27日技术突破:三大核心功能解析与行业影响
DeepSeek 2月27日技术突破:三大核心功能解析与行业影响 一、最新发布功能全景图 1. DualPipe:双向流水线并行革命 DualPipe是一项极具创新性的双向管道并行算法,旨在解决大规模模型训练过程中计算与通信效率低下的关键问题。在传统的模型训…...
【实战 ES】实战 Elasticsearch:快速上手与深度实践-1.2.2倒排索引原理与分词器(Analyzer)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 1.2.2倒排索引原理与分词器(Analyzer)1. 倒排索引:搜索引擎的基石1.1 正排索引 vs 倒排索引示例数据对比: 1.2 倒排索引核心结…...
Vue.js响应式基础
响应式基础 API 参考 本页和后面很多页面中都分别包含了选项式 API 和组合式 API 的示例代码。现在你选择的是 组合式 API。你可以使用左侧侧边栏顶部的“API 风格偏好”开关在 API 风格之间切换。 声明响应式状态 ref() 在组合式 API 中,推荐使用 ref() 函数来声明…...
DeepSeek-OpenSourceWeek-第四天-Optimized Parallelism Strategies
DeepSeek 在 #OpenSourceWeek(开源周) 的第四天推出了两项新工具,旨在让深度学习更快、更高效:**DualPipe** 和 **EPLB**。 DualPipe 定义:DualPipe 是一种用于 V3/R1 训练中计算与通信重叠的双向pipline并行算法。 作用:它通过实现前向和后向计算-通信阶段的完全重叠,减…...
深入浅出:插入排序算法完全解析
1. 什么是插入排序? 插入排序(Insertion Sort)是一种简单的排序算法,其基本思想与我们整理扑克牌的方式非常相似。我们将扑克牌从第二张开始依次与前面已排序的牌进行比较,将其插入到合适的位置,直到所有牌…...
【Keras图像处理入门:图像加载与预处理全解析】
本文将全面讲解如何使用Keras进行图像加载、预处理和数据增强,为深度学习模型准备高质量的图像数据。 一、单张图像处理基础 1. 图像加载与尺寸调整 from keras.preprocessing import image# 加载图像并调整尺寸 img image.load_img(example.jpg, target_size(1…...
企业级AI办公落地实践:基于钉钉/飞书的标准产品解决方案
一、平台化AI的崛起:开箱即用的智能革命 2024年企业AI应用调研数据显示: 73%的中型企业选择平台标准产品而非自研头部SaaS平台AI功能渗透率达89%典型ROI周期从18个月缩短至3-6个月 核心优势对比: 维度自研方案平台标准产品部署周期6-12个…...
对于邮箱地址而言,短中划线(Hyphen, -)和长中划线(Em dash, —)有区别吗
对于邮箱地址而言,**短中划线(Hyphen, -)和长中划线(Em dash, —)**有明确的区别: 短中划线(Hyphen, -): 在邮箱地址中,短中划线是可以使用的,通常…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
