HarmonyOS鸿蒙Next中“仿抖音快手”App开发技术分享(九)截取某帧获得视频缩略图

HarmonyOS鸿蒙Next中“仿抖音快手”App开发技术分享(九)截取某帧获得视频缩略图

上一节我们利用系统相机实现了录像功能,那么为了直观地浏览视频列表,就要给每个视频配上封面,这个封面图的来源之一便是视频里的某帧画面。接下来就介绍如何从视频文件中根据时间点提取帧图像,具体的提取过程分为以下四个步骤。

1、导入系统提供的媒体库

因为提取帧图像用到了来自媒体库的元数据提取器和图像生成器,所以要在ETS代码开头添加下面的导包语句,声明引入media媒体库。

import { media } from '@kit.MediaKit';

还要在代码开头添加元数据提取器和图像生成器的变量声明代码,以便在创建过程中赋值,变量声明代码如下所示:

let avMetadataExtractor: media.AVMetadataExtractor; // 音视频元数据提取器
let avImageGenerator: media.AVImageGenerator; // 音视频图像生成器

2、创建元数据提取器和图像生成器

由于元数据提取器和图像生成器的创建结果为异步返回,所以可在aboutToAppear方法中提前创建它们的实例。其中元数据提取器通过media库的createAVMetadataExtractor方法返回,图像生成器通过media库的createAVImageGenerator方法返回,详细地创建代码示例如下:

aboutToAppear() {
  // 创建音视频的元数据提取器
  media.createAVMetadataExtractor((error: BusinessError, extractor: media.AVMetadataExtractor) => {
    if (extractor != null) {
      avMetadataExtractor = extractor;
    } else {
      console.error(`Failed to create AVMetadataExtractor, error message:${error.message}`);
    }
  });

  // 创建音视频的图像生成器
  media.createAVImageGenerator((error: BusinessError, generator: media.AVImageGenerator) => {
    if (generator != null) {
      avImageGenerator = generator;
    } else {
      console.error(`Failed to creat AVImageGenerator, error message:${error.message}`);
    }
  });
}

3、从音视频文件中提取元数据

这里之所以要从视频文件提取元数据,是因为一个可以检查指定文件是否属于音视频格式,另一个能够获取视频文件的画面宽高。在调用元数据提取器的fetchMetadata方法之前,得先给提取器的fdSrc字段赋值,传入音视频文件的文件句柄和文件大小等信息。下面是从视频文件提取元数据的代码例子:

// 前面省略通过fileIo文件库获取文件句柄的代码,文件句柄放在file.fd
let avFileDescriptor: media.AVFileDescriptor =
  { fd: file.fd, offset: 0, length: stat.size };
avMetadataExtractor.fdSrc = avFileDescriptor

// 从fdSrc指定的音视频文件中提取元数据
avMetadataExtractor.fetchMetadata((error: BusinessError, metadata: media.AVMetadata) => {
  if (error) {
    console.error(`Failed to fetch Metadata, err = ${JSON.stringify(error)}`);
    return;
  }
  // 这里暂时省略获取视频帧的代码
});

4、根据时间点从视频文件获取帧图像

调用图像生成器的fetchFrameByTime方法,即可根据时间点从视频文件获取帧图像,注意在此之前得先给生成器的fdSrc字段赋值,传入视频文件的文件句柄和文件大小等信息。

fetchFrameByTime方法的前三个参数包含了待截取的图像帧规格,其中第一个参数为该帧所处的时间点,单位微秒;第二个参数指定了要返回哪种关键帧;第三个参数指定了图像按什么尺寸返回。那么最后截取的图像帧也是异步返回,且返回的图像数据为image.PixelMap类型,使用Image组件即可显示该缩略图。

下面是从视频文件获取图像帧的代码例子:

avImageGenerator.fdSrc = avFileDescriptor

let timeUs = 1000*1000 // 缩略图所处的时间点,单位微秒

// AV_IMAGE_QUERY_NEXT_SYNC表示取时间点之后的关键帧,AV_IMAGE_QUERY_PREVIOUS_SYNC表示取时间点之前的关键帧
let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC

let param: media.PixelMapParams = {
  width : 300, // 缩略图的宽度
  height : 300 // 缩略图的高度
}

// 从视频文件的指定时间点获取帧图像
avImageGenerator.fetchFrameByTime(timeUs, queryOption, param, (error: BusinessError, pixelMap) => {
  if (error) {
    console.error(`Failed to fetch FrameByTime, err = ${JSON.stringify(error)}`)
    return
  }
  this.pixelMap = pixelMap; // Image组件绑定this.pixelMap即可显示图像
});

下一篇文章会介绍如何给视频缩略图添加高亮边框。


更多关于HarmonyOS鸿蒙Next中“仿抖音快手”App开发技术分享(九)截取某帧获得视频缩略图的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

有用

更多关于HarmonyOS鸿蒙Next中“仿抖音快手”App开发技术分享(九)截取某帧获得视频缩略图的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,可以通过AVImageGenerator组件实现视频帧截取。使用步骤如下:

  1. 创建AVImageGenerator实例并设置视频源路径
  2. 调用fetchImageByTime()方法指定截取时间点(毫秒)
  3. 通过PixelMap对象获取图像数据
  4. 转换为Image组件可用的格式显示

关键代码示例:

let generator = new AVImageGenerator(videoPath);
generator.fetchImageByTime(timeMs).then((pixelMap) => {
  // 使用pixelMap创建缩略图
})

该方法支持异步操作,不会阻塞UI线程。

在HarmonyOS Next中获取视频缩略图的技术实现非常清晰。补充几点关键细节:

  1. 关于时间点参数timeUs:
  • 1秒=1000毫秒=1000000微秒
  • 建议取视频中间时间点(如总时长/2)作为封面更合理
  • 可通过avMetadataExtractor获取视频总时长
  1. PixelMapParams参数优化:
  • 建议保持原始宽高比,避免变形
  • 可先获取视频原始分辨率(通过metadata),再按比例缩放
  1. 性能优化建议:
  • 可缓存生成的缩略图,避免重复生成
  • 大量视频处理时可考虑使用Worker线程
  1. 错误处理:
  • 需要检查fdSrc是否设置成功
  • 注意资源释放,特别是fileIo的文件句柄
  1. 扩展应用:
  • 同样的方法也可用于音频文件封面提取
  • 可结合媒体库的缩略图功能实现更高效方案

整体实现方案完整,关键点都覆盖到了,是标准的HarmonyOS媒体处理流程。

回到顶部