鸿蒙-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, -): 在邮箱地址中,短中划线是可以使用的,通常…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!
本文介绍了一种名为AnomalyAny的创新框架,该方法利用Stable Diffusion的强大生成能力,仅需单个正常样本和文本描述,即可生成逼真且多样化的异常样本,有效解决了视觉异常检测中异常样本稀缺的难题,为工业质检、医疗影像…...
