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

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

参考文档

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

操作分为几步:

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

获取文件地址

typescript 复制代码
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}`);
}

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

typescript 复制代码
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}`)
}

完整代码

typescript 复制代码
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 = 0

  chooseFile() {
    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%')
  }
}
相关推荐
kiros_wang12 小时前
@Observed/@ObjectLink深层监听:嵌套对象更新失效根源与修复
华为·harmonyos
智塑未来18 小时前
鸿蒙6.1隐私安全升级——加密分享限时查看+水印+应用锁+防诈一键开启
安全·华为·harmonyos
OH_TPC19 小时前
HarmonyOS APP开发---“股动力“实时行情App,需要用到这个库
华为·音视频·harmonyos·鸿蒙
小雨青年21 小时前
【HarmonyOS 7 沉浸光感深度实战】10 通用组件封装与现有项目接入
华为·harmonyos
YM52e1 天前
蒙特卡洛模拟器:鸿蒙 Canvas 上的大数定律与中心极限定理实证
华为·harmonyos
Dovis(誓平步青云)1 天前
DevEco Studio 6.1.1 Windows 安装实录:从下载校验到首次启动
android·开发语言·数据库·人工智能·windows·harmonyos
2501_919749031 天前
华为鸿蒙免费排班APP—小羊排班
华为·harmonyos·鸿蒙
大雷神1 天前
相册照片不用上传:HarmonyOS Core Vision 端侧识别动物与植物
harmonyos
OH_TPC1 天前
HarmonyOS APP开发---"刷刷"短视频App,需要用到这个库
harmonyos
超爱西西鸭1 天前
思维导图编辑体验:触摸交互与节点操作(ArkTS)
学习·华为·harmonyos