当前位置: 首页 > news >正文

鸿蒙选择本地视频文件,并获取首帧预览图

选择本地视频文件,并获取首帧预览图

参考文档

由于文件权限获取不太方便,现在使用的是 picker 的方式获取本地视频文件。文件位于我的手机/下载目录下。

操作分为几步:

  1. 获取文件地址;
  2. 获取视频信息;
  3. 首帧截图;
  4. 显示截图;

获取文件地址

try {let context = CCAppContext.context.getHostContext()!let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['视频|.mp4', '视频|.avi']let documentPicker = new picker.DocumentViewPicker(context);documentPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {console.info('DocumentViewPicker.select successfully, documentSelectResult uri: ' + JSON.stringify(documentSelectResult));if (documentSelectResult.length > 0) {let uri = documentSelectResult[0] // 这个是获取到的文件地址}).catch((err: BusinessError) => {console.error(`DocumentViewPicker.select failed with err, code is: ${err.code}, message is: ${err.message}`);});
} catch (error) {let err: BusinessError = error as BusinessError;console.error(`DocumentViewPicker failed with err, code is: ${err.code}, message is: ${err.message}`);
}

获取视频信息 & 获取首帧截图 & 显示图片

try {// 打开视频文件获取文件描述符let fd = await fileIo.open(videoPath, fileIo.OpenMode.READ_ONLY)const extractor = await media.createAVMetadataExtractor()extractor.fdSrc = { fd: fd.fd }let metaData = await extractor.fetchMetadata()this.imageWidth = parseInt(metaData.videoWidth || '1') // 视频宽度this.imageHeight = parseInt(metaData.videoHeight || '1') // 视频高度let orientation = metaData.videoOrientation // 视频旋转,截图有可能有旋转角度const avImageGenerator = await media.createAVImageGenerator()avImageGenerator.fdSrc = { fd: fd.fd }// 配置缩略图参数const param: media.PixelMapParams = {width: this.imageWidth,height: this.imageHeight,}this.pixelMap = await avImageGenerator.fetchFrameByTime(0, // 0表示首帧(单位微秒)media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC,param)await avImageGenerator.release() // 释放资源fileIo.close(fd) // 关闭文件
} catch (error) {console.error(`Get thumbnail failed: ${error.code}, ${error.message}`)
}

完整代码

import { fileIo, fileUri, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@ohos.base'
import { media } from '@kit.MediaKit';@Entry
struct test {@State pixelMap: PixelMap | undefined = undefined@State imageWidth: number = 1@State imageHeight: number = 1@State orientation: number = 0chooseFile() {try {let context = getContext()let documentSelectOptions = new picker.DocumentSelectOptions();documentSelectOptions.fileSuffixFilters = ['视频|.mp4', '视频|.avi']let documentPicker = new picker.DocumentViewPicker(context);documentPicker.select(documentSelectOptions).then((documentSelectResult: Array<string>) => {console.info('DocumentViewPicker.select successfully, documentSelectResult uri: ' + JSON.stringify(documentSelectResult));if (documentSelectResult.length > 0) {let uri = documentSelectResult[0]this.getFirstFrame(uri)}}).catch((err: BusinessError) => {console.error(`DocumentViewPicker.select failed with err, code is: ${err.code}, message is: ${err.message}`);});} catch (error) {let err: BusinessError = error as BusinessError;console.error(`DocumentViewPicker failed with err, code is: ${err.code}, message is: ${err.message}`);}}async getFirstFrame(videoPath: string) {try {// 打开视频文件获取文件描述符let fd = await fileIo.open(videoPath, fileIo.OpenMode.READ_ONLY);const extractor = await media.createAVMetadataExtractor()extractor.fdSrc = { fd: fd.fd };let metaData = await extractor.fetchMetadata()this.imageWidth = parseInt(metaData.videoWidth || '1')this.imageHeight = parseInt(metaData.videoHeight || '1')this.orientation = parseInt(metaData.videoOrientation || '0')const avImageGenerator = await media.createAVImageGenerator();avImageGenerator.fdSrc = { fd: fd.fd };// 配置缩略图参数const param: media.PixelMapParams = {width: this.imageWidth,height: this.imageHeight};this.pixelMap = await avImageGenerator.fetchFrameByTime(0, // 0表示首帧(单位微秒)media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC,param);await avImageGenerator.release(); // 释放资源fileIo.close(fd); // 关闭文件} catch (error) {console.error(`Get thumbnail failed: ${error.code}, ${error.message}`);}}build() {Column() {Text('截图').fontSize('22fp').fontColor(Color.Black).onClick(() => {this.chooseFile()})Image(this.pixelMap).objectFit(ImageFit.Cover).width('30%').aspectRatio(1).orientation(this.orientation)}.justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).width('100%').height('100%')}
}
http://www.lryc.cn/news/587246.html

相关文章:

  • 【算法】贪心算法:柠檬水找零C++
  • 密码学系列文(1)--密码学基础概念详解
  • 密码学系列文(2)--流密码
  • ansible自动化部署考试系统前后端分离项目
  • 在 C# 中调用 Python 脚本:实现跨语言功能集成
  • MySQL逻辑删除与唯一索引冲突解决
  • C++高频知识点(九)
  • 39.Sentinel微服务流量控制组件
  • 【一起来学AI大模型】部署优化推理加速:vLLM
  • word中多行合一功能实现
  • comfyUI-ControlNet-姿势控制深度控制
  • Java 8 LocalDate 日期操作全攻略
  • CS课程项目设计1:交互友好的井字棋游戏
  • 【多线程】 线程池设多大才合理?CPU 密集型和 I/O 密集型的终极公式
  • 深度学习图像分类数据集—七种树叶识别分类
  • AI生成单词消消乐游戏. HTML代码
  • LeetCode 2401.最长优雅子数组
  • Ampace厦门新能安科技Verify 测评演绎数字推理及四色测评考点分析、SHL真题题库
  • 【sql学习之拉链表】
  • 系规备考论文:论IT服务知识管理
  • MyBatis框架进阶指南:深入理解CRUD与参数映射
  • CVE-2022-0609
  • Oracle SQL - 使用行转列PIVOT减少表重复扫描(实例)
  • 常用的docker命令备份
  • Docker从环境配置到应用上云的极简路径
  • 《Google 软件工程》:如何写好文档?
  • Qt窗口:QToolBar、QStatusBar、QDockWidget、QDialog
  • QT 多线程 管理串口
  • Vue框架之计算属性与侦听器详解
  • 深入理解 LangChain:AI 应用开发的全新范式