仓颉语言接入 ohos.multimedia.media 媒体服务:AVImageGenerator 视频缩略图获取实战指南
仓颉语言接入 ohos.multimedia.media 媒体服务:AVImageGenerator 视频缩略图获取实战指南
导读
ohos.multimedia.media(媒体服务)是 OpenHarmony 媒体子系统的核心仓颉 API 模块,为开发者提供一套简单且易于理解的接口,方便应用接入系统媒体资源。本指南聚焦其中与视频缩略图获取强相关的能力——AVImageGenerator 视频缩略图生成器,系统讲解从创建实例、描述媒体文件、按时间点抓帧到释放资源的完整调用链,并结合 CangjieCorpus 仓库中的错误码文档与关联 Kit 源码,帮助读者在仓颉模板工程中快速落地"从任意时间点截取视频帧"的实战方案。
一、模块概览:媒体子系统与 AVImageGenerator 的定位
媒体子系统包含音视频相关媒体业务,ohos.multimedia.media 模块为开发者提供接入系统媒体资源的能力。在仓颉侧,该模块当前以 Beta 特性 形式提供(见 Media Kit 模块说明),其中与本文主题直接相关的常用功能是:
- 获取视频缩略图(
AVImageGenerator)
AVImageGenerator 是一个典型的同步抓帧器:开发者向它描述一段媒体文件(文件句柄 + 偏移量 + 长度),指定目标时间点与取帧策略,即可获得对应的 PixelMap 缩略图。这一能力在视频列表封面、视频剪辑预览、短视频应用等场景中非常实用。
二、开发前置准备
2.1 导入模块
在仓颉代码中通过 Kit 导入方式引入媒体能力:
import kit.MediaKit.*
Kit 封装了同一 Kit 下各接口模块,开发者通过导入 MediaKit 即可使用 AVImageGenerator、AVFileDescriptor、PixelMapParams、AVImageQueryOptions 等接口(关于 Kit 导入机制的说明可参考 开发说明)。
2.2 权限列表
调用本模块接口需要申请权限:
ohos.permission.MICROPHONE
需要在应用配置文件(如 module.json5)中声明该权限,并遵守应用运行时权限申请流程。
2.3 示例工程使用说明
文档中的 API 示例代码遵循以下约定(详见仓颉示例代码说明):
- 若示例代码首行有
// index.cj注释,表示该示例可在仓颉模板工程的index.cj文件中直接编译运行; - 若示例需获取 Context 应用上下文,需在仓颉模板工程中的
main_ability.cj文件中进行配置; - 获取当前应用沙箱所在路径可通过 UIAbilityContext.filesDir 获取。
三、核心调用链总览
视频缩略图获取的完整生命周期包含四个步骤:
- 创建实例:调用
createAVImageGenerator()构建AVImageGenerator; - 描述数据源:构造
AVFileDescriptor并赋给generator.fdSrc; - 按时间抓帧:调用
fetchFrameByTime()获取PixelMap缩略图; - 释放资源:调用
release()释放底层资源。
下面逐一展开。
四、创建实例:func createAVImageGenerator()
public func createAVImageGenerator(): AVImageGenerator
- 功能:创建
AVImageGenerator实例。 - 系统能力:
SystemCapability.Multimedia.Media.AVImageGenerator - 起始版本:22
返回值
| 类型 | 说明 |
|---|---|
| AVImageGenerator | 返回 AVImageGenerator 实例。 |
异常
BusinessException:对应错误码如下表,详见 Media 错误码。
| 错误码 ID | 错误信息 |
|---|---|
| 5400101 | No memory. |
示例(可在 index.cj 中编译运行)
// index.cj
import kit.MediaKit.*
import kit.PerformanceAnalysisKit.*
import ohos.business_exception.BusinessException
try {
let generator = createAVImageGenerator()
} catch (e: BusinessException) {
Hilog.error(0, "AppLogCj", e.message)
}
五、描述媒体数据源:class AVFileDescriptor
AVFileDescriptor 是音视频文件资源描述类型,对应一种特殊资源的播放方式:当应用中的音频/视频资源被连续存储在同一个文件中时,需要根据偏移量和长度进行播放(或抓帧)。
public class AVFileDescriptor {
public var fd: Int32
public var offset: Int64
public var length: Int64
public init(
fd: Int32,
offset!: Int64 = 0,
length!: Int64 = -1
)
}
- 系统能力:
SystemCapability.Multimedia.Media.Core - 起始版本:22
5.1 var fd(资源句柄)
public var fd: Int32
- 功能:资源句柄。
- 类型:
Int32 - 读写能力:可读写
该句柄有两种典型获取方式:
- 通过 getRawFd 获取 HAP 内置 rawfile 资源的文件描述符(返回 RawFileDescriptor,其包含
fd、offset、length三个字段); - 通过 open 打开应用沙箱内的文件获得句柄(默认以
OpenMode.READ_ONLY只读方式打开)。
5.2 var offset(资源偏移量)
public var offset: Int64
- 功能:资源偏移量,默认值为
0。 - 类型:
Int64 - 读写能力:可读写
需要基于预置资源的信息输入,非法值会造成音视频资源解析错误。
5.3 var length(资源长度)
public var length: Int64
- 功能:资源长度,默认值为文件中从偏移量开始的剩余字节。
- 类型:
Int64 - 读写能力:可读写
需要基于预置资源的信息输入,非法值会造成音视频资源解析错误。
5.4 init(Int32, Int64, Int64)
public init(
fd: Int32,
offset!: Int64 = 0,
length!: Int64 = -1
)
参数说明
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| fd | Int32 | 是 | - | 资源句柄,通过 getRawFd 获取,也可以通过 open 获取。 |
| offset | Int64 | 否 | 0 | 命名参数。 资源偏移量,需要基于预置资源的信息输入,非法值会造成音视频资源解析错误。 |
| length | Int64 | 否 | -1 | 命名参数。 资源长度,默认值为文件中从偏移量开始的剩余字节,需要基于预置资源的信息输入,非法值会造成音视频资源解析错误。 |
六、抓帧核心类:class AVImageGenerator
public class AVImageGenerator {}
- 功能:视频缩略图获取类,用于从视频资源中获取缩略图。在调用
AVImageGenerator的方法前,需要先通过 createAVImageGenerator() 构建一个AVImageGenerator实例。 - 系统能力:
SystemCapability.Multimedia.Media.AVImageGenerator - 起始版本:22
6.1 prop fdSrc(媒体文件描述)
public mut prop fdSrc: AVFileDescriptor
- 功能:媒体文件描述,通过该属性设置数据源。
- 类型:AVFileDescriptor
- 读写能力:可读写
- 系统能力:
SystemCapability.Multimedia.Media.AVMetadataExtractor
使用示例:假设一个连续存储的媒体文件,地址偏移为 0、字节长度为 100,则其文件描述为:
AVFileDescriptor { fd = 资源句柄; offset = 0; length = 100; }
说明(重要)
将资源句柄(fd)传递给
AVImageGenerator实例之后,不允许通过该资源句柄再执行其他读写操作,包括但不限于将同一个资源句柄传递给多个AVPlayer/AVMetadataExtractor/AVImageGenerator/AVTranscoder。同一时间通过同一个资源句柄读写文件时存在竞争关系,将导致视频缩略图数据获取异常。
异常
BusinessException:错误码如下表。
| 错误码 ID | 错误信息 |
|---|---|
| 5400101 | No memory. |
| 5400102 | Operation not allowed. |
6.2 func fetchFrameByTime(Int64, AVImageQueryOptions, PixelMapParams)
public func fetchFrameByTime(timeUs: Int64, options: AVImageQueryOptions, param: PixelMapParams): PixelMap
- 功能:获取视频缩略图。
- 系统能力:
SystemCapability.Multimedia.Media.AVImageGenerator - 起始版本:22
参数说明
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| timeUs | Int64 | 是 | - | 需要获取的缩略图在视频中的时间点,单位为微秒(μs)。 |
| options | AVImageQueryOptions | 是 | - | 需要获取的缩略图时间点与视频帧的对应关系。 |
| param | PixelMapParams | 是 | - | 需要获取的缩略图的格式参数。 |
返回值
| 类型 | 说明 |
|---|---|
| PixelMap | 视频缩略图。 |
返回的 PixelMap 是图像像素类,可用于读取或写入图像数据以及获取图像信息,例如进一步交给 Image Kit 进行编码保存(注意其序列化大小存在上限,见 Image Kit 文档说明)。
异常
BusinessException:错误码如下表。
| 错误码 ID | 错误信息 |
|---|---|
| 5400101 | No memory. |
| 5400102 | Operation not allowed. |
| 5400106 | Unsupported format. |
完整示例(可在 index.cj 中编译运行)
// index.cj
import kit.MediaKit.*
import kit.LocalizationKit.*
import ohos.business_exception.BusinessException
import kit.PerformanceAnalysisKit.Hilog
try {
let timeUs = 0
let queryOption = AVImageQueryOptions.AvImageQueryNextSync
let param = PixelMapParams(width: 300, height: 300)
let generator = createAVImageGenerator()
let abilityContext = Global.abilityContext // 此处需手动配置模板,获取Context上下文。上下文获取方式请参见使用说明。
let rawFd = abilityContext.resourceManager.getRawFd("trailer.mp4") // 请替换您的资源路径,获取文件路径参考本文使用说明
generator.fdSrc = AVFileDescriptor(rawFd.fd, offset: rawFd.offset, length: rawFd.length)
let pic = generator.fetchFrameByTime(timeUs, queryOption, param)
generator.release()
} catch (e: BusinessException) {
Hilog.info(0, "test", "${e.message}")
}
6.3 func release()
public func release(): Unit
- 功能:释放资源。
- 系统能力:
SystemCapability.Multimedia.Media.AVImageGenerator - 起始版本:22
异常
BusinessException:错误码如下表。
| 错误码 ID | 错误信息 |
|---|---|
| 5400101 | No memory. |
示例(可在 index.cj 中编译运行)
// index.cj
import kit.MediaKit.*
import kit.LocalizationKit.*
import kit.PerformanceAnalysisKit.*
import ohos.business_exception.BusinessException
try {
let timeUs = 0
let queryOption = AVImageQueryOptions.AvImageQueryNextSync
let param = PixelMapParams(width: 300, height: 300)
let generator = createAVImageGenerator()
let abilityContext = Global.abilityContext // 此处需手动配置模板,获取Context上下文。上下文获取方式请参见使用说明。
let rawFd = abilityContext.resourceManager.getRawFd("trailer.mp4")
generator.fdSrc = AVFileDescriptor(rawFd.fd, offset:rawFd.offset, length:rawFd.length)
let pic = generator.fetchFrameByTime(timeUs, queryOption, param)
generator.release()
} catch (e: BusinessException) {
Hilog.error(0, "AppLogCj", e.message)
}
release() 是实例生命周期的收尾动作,与 createAVImageGenerator() 成对使用;尤其在反复创建实例、频繁抓帧的场景下,及时释放可避免句柄与内存资源占用。
七、输出格式参数:class PixelMapParams
PixelMapParams 用于描述获取视频缩略图时输出缩略图的格式参数。
public class PixelMapParams {
public var width: Int32
public var height: Int32
public init(width!: Int32 = -1, height!: Int32 = -1)
}
- 系统能力:
SystemCapability.Multimedia.Media.AVImageGenerator - 起始版本:22
7.1 var width / var height
public var width: Int32
public var height: Int32
- 功能:
width:输出的缩略图宽度,应保证大于 0 且不大于原始视频宽度,否则返回的缩略图不会进行缩放;height:输出的缩略图高度,应保证大于 0 且不大于原始视频高度,否则返回的缩略图不会进行缩放。
- 类型:
Int32 - 读写能力:可读写
7.2 init(Int32, Int32)
public init(width!: Int32 = -1, height!: Int32 = -1)
参数说明
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| width | Int32 | 否 | -1 | 命名参数。 输出的缩略图宽度。应保证大于 0 且不大于原始视频宽度,否则返回的缩略图不会进行缩放。 |
| height | Int32 | 否 | -1 | 命名参数。 输出的缩略图高度。应保证大于 0 且不大于原始视频高度,否则返回的缩略图不会进行缩放。 |
八、取帧策略枚举:enum AVImageQueryOptions
在获取视频缩略图时,传入的时间点与实际取得的视频帧所在时间点不一定相等,因此需要指定传入时间点与实际取得的视频帧的时间关系。AVImageQueryOptions 即用于描述这一对应关系。
public enum AVImageQueryOptions <: Equatable<AVImageQueryOptions> & ToString {
| AvImageQueryNextSync
| AvImageQueryPreviousSync
| AvImageQueryClosestSync
| AvImageQueryClosest
| ...
}
- 系统能力:
SystemCapability.Multimedia.Media.AVImageGenerator - 起始版本:22
父类型
Equatable<AVImageQueryOptions>ToString
8.1 枚举取值语义
| 取值 | 功能 |
|---|---|
| AvImageQueryClosest | 表示选取离传入时间点最近的帧,该帧不一定是关键帧。 |
| AvImageQueryClosestSync | 表示选取离传入时间点最近的关键帧。 |
| AvImageQueryNextSync | 表示选取传入时间点或之后的关键帧。 |
| AvImageQueryPreviousSync | 表示选取传入时间点或之前的关键帧。 |
实际应用中,若追求"又快又稳"的封面图,通常选用 AvImageQueryNextSync 或 AvImageQueryClosestSync(只取关键帧,解码开销小、成功率高);若对时间点精度要求高、需要逐帧呈现画面内容,则可选用 AvImageQueryClosest。
8.2 运算符与字符串化
枚举通过实现 Equatable<AVImageQueryOptions> 与 ToString 提供了三个成员方法:
public operator func ==(other: AVImageQueryOptions): Bool
public operator func !=(other: AVImageQueryOptions): Bool
public func toString(): String
==(other):比较两个AVImageQueryOptions是否相等,相等返回true,否则返回false;!=(other):比较两个AVImageQueryOptions是否不等,不等返回true,否则返回false;toString():返回AVImageQueryOptions的字符串表示,便于日志输出与调试。
九、异常与错误码速查
ohos.multimedia.media 相关接口抛出的 BusinessException 对应 Media 特有错误码,完整定义见 Media 错误码。其中与 AVImageGenerator 直接相关的错误码如下:
9.1 5400101 内存分配失败(No memory.)
- 可能原因:① 实例数量超过 16 个;②
new或malloc流程失败导致空指针。 - 处理步骤:销毁当前实例并重新创建;如果重新创建失败,则停止相关操作。
9.2 5400102 当前状态机不支持此操作(Operation not allowed.)
- 可能原因:当前状态机不支持该操作。
- 处理步骤:确认当前状态是否支持当前操作,把实例切换到正确的状态后再执行正确操作。
9.3 5400106 不支持的规格(Unsupported format.)
- 可能原因:不支持的文件或格式。
- 处理步骤:当前使用的格式规格不支持,需切换为支持的规格。
除上述特有错误码外,通用错误码请参考通用错误码说明文档。
十、数据源获取路径深入:rawfile 与沙箱文件
前文示例通过 abilityContext.resourceManager.getRawFd("trailer.mp4") 获取内置资源的句柄,这是最常用的数据源获取方式。围绕这一环节,仓库中相关 Kit 提供了两类路径:
方式一:rawfile 内置资源
- getRawFd(String):获取
resources/rawfile目录下 rawfile 文件所在 HAP 的文件描述符,返回 RawFileDescriptor(含fd、offset、length三字段,恰好与AVFileDescriptor一一对应,可直接透传); - 注意:
getRawFd获取的 fd 使用完毕后需调用closeRawFd关闭,避免资源泄露。
方式二:应用沙箱文件
- 先通过 UIAbilityContext.filesDir 取得应用沙箱目录路径,再通过 open(path, mode) 打开文件获取
File对象及对应句柄,之后填充AVFileDescriptor的fd、offset、length字段。
十一、实战要点汇总
- 生命周期完整:
createAVImageGenerator()→ 设置fdSrc→fetchFrameByTime()→release(),四步缺一不可; - 时间单位:
fetchFrameByTime的timeUs单位为微秒,如取视频开头帧传入0即可; - 输出尺寸:
PixelMapParams的宽高需大于 0 且不超过原始视频宽高,否则不缩放;示例中width: 300, height: 300即为典型的封面缩略图尺寸; - fd 独占性:句柄传给
AVImageGenerator后不得再用于其他读写或传给其他媒体组件,否则可能因竞争导致缩略图数据异常; - 异常兜底:所有调用均建议使用
try/catch捕获BusinessException,并按错误码(5400101/5400102/5400106)执行销毁重建或规格切换策略; - 工程落地:示例代码需放入仓颉模板工程的
index.cj,涉及Global.abilityContext的需在main_ability.cj中配置Context上下文,具体可参考仓颉示例代码说明。
通过以上步骤,开发者即可在仓颉应用中稳定获取视频任意时间点的缩略图,为视频列表封面、预览封面等功能提供统一的实现范式。