使用AVTranscoder可以实现视频转码功能,从API 20开始支持视频转码的C/C++开发,转码功能可在手机、平板、2in1设备上作为系统提供的基础能力使用。可以通过调用canIUse接口来判断当前设备是否支持AVTranscoder,当canIUse("SystemCapability.Multimedia.Media.AVTranscoder")的返回值为true时,表示可以使用转码能力。
本开发指导将以“开始转码-暂停转码-恢复转码-转码完成”的一次流程为示例,向开发者讲解AVTranscoder视频转码相关功能。
详细的API说明请参考AVTranscoder。
如需对转码后的文件进行转发、上传、转存等处理,应用须收到complete事件后调用系统接口await avTranscoder.release(),以保证视频文件完整性。
创建AVTranscoder实例。
import { media } from '@kit.MediaKit';
private avTranscoder: media.AVTranscoder | undefined = undefined;
// 创建转码实例。
this.avTranscoder = await media.createAVTranscoder(); 设置业务需要的监听事件,监听状态变化及错误上报。
| 事件类型 | 说明 |
|---|---|
| complete | 必要事件,监听AVTranscoder的转码完成。 |
| error | 必要事件,监听AVTranscoder的错误信息。 |
| progressUpdate | 监听AVTranscoder的进度。 |
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo } from '@kit.CoreFileKit';
import { media } from '@kit.MediaKit';
private currentProgress: number = 0;
private avTranscoder: media.AVTranscoder | undefined = undefined;
async test() {
// 创建转码实例。
this.avTranscoder = await media.createAVTranscoder();
if (this.avTranscoder != undefined) {
// 转码完成回调函数。
this.avTranscoder.on('complete', async () => {
console.info(`AVTranscoder is completed`);
await this.releaseTranscoderingProcess();
});
// 错误上报回调函数。
this.avTranscoder.on('error', (err: BusinessError) => {
console.error(`AVTranscoder failed, code is ${err.code}, message is ${err.message}`);
});
// 进度上报回调函数。
this.avTranscoder.on('progressUpdate', (progress: number) => {
console.info(`AVTranscoder progressUpdate = ${progress}`);
this.currentProgress = progress;
})
}
}
// 获取当前进度。
getCurrentProgress(): number {
console.info(`getCurrentProgress = ${this.currentProgress}`);
return this.currentProgress;
}
// 释放转码流程。
async releaseTranscoderingProcess() {
if (canIUse('SystemCapability.Multimedia.Media.AVTranscoder')) {
if (this.avTranscoder != undefined) {
// 1.释放转码实例。
await this.avTranscoder.release();
let lastFdDst = this.avTranscoder.fdDst;
let lastFdSrc = this.avTranscoder.fdSrc;
this.avTranscoder = undefined;
// 2.关闭转码目标文件fd。
if (lastFdDst != undefined) {
fs.closeSync(lastFdDst);
}
// 3.关闭转码源文件fd。
if (lastFdSrc != undefined) {
fs.closeSync(lastFdSrc.fd);
}
}
}
}
设置源视频文件fd:设置属性fdSrc。
下面代码示例中的fdSrc仅作示意使用,开发者需根据实际情况,确认资源有效性并设置:
如果使用本地资源转码,必须确认资源文件可用,并使用应用沙箱路径访问对应资源,参考获取应用文件路径。应用沙箱的介绍及如何向应用沙箱推送文件,请参考文件管理。
应通过Context属性获取应用文件路径,建议使用getUIContext获取UIContext实例,并使用getHostContext调用绑定实例的getContext,请参考getHostContext。
如果使用ResourceManager.getRawFd()打开HAP资源文件描述符,使用方法可参考ResourceManager中的getRawFd。
// 导入来自于ets/transcoder/AVTranscoderManager.ets文件。
import {AVTranscoderDemo} from '../transcoder/AVTranscoderManager'
@Entry
@Component
struct Index {
// 获取当前组件所在Ability的Context,以通过Context获取应用文件路径。
private context:Context | undefined = this.getUIContext()?.getHostContext();
// 获取转码功能管理类。
@State avTranscoder: AVTranscoderDemo | undefined = this.context ? new AVTranscoderDemo(this.context) : undefined;
build() {
RelativeContainer() {
Column() {
Button($r('app.string.StartTranscoder')) // 来自于resources/base/element/string.json文件中的name:StartTranscoder的值。
.onClick(async () => {
console.info(`Button put`);
await this.avTranscoder?.avTranscoderDemo();
})
.id('AVTranscoderButton')
// 获取转码进度。
Progress({ value: 0, total: 100, type: ProgressType.Linear }).value(this.avTranscoder?.getCurrentProgress())
.height(50)
.width('80%')
}
.alignRules({
center: { anchor: '__container__', align: VerticalAlign.Center },
middle: { anchor: '__container__', align: HorizontalAlign.Center }
})
}
.height('100%')
.width('100%')
}
} import { media } from '@kit.MediaKit';
private avTranscoder: media.AVTranscoder | undefined = undefined;
private context: Context | undefined;
constructor(context: Context | undefined) {
if (context != undefined) {
this.context = context; // this.getUIContext().getHostContext();。
}
}
async test() {
// 创建转码实例。
this.avTranscoder = await media.createAVTranscoder();
// 获取输入文件fd,H264_AAC.mp4为rawfile目录下的预置资源,需要开发者根据实际情况进行替换。
if (this.context != undefined) {
let fileDescriptor = await this.context.resourceManager.getRawFd('H264_AAC.mp4');
// 设置转码的源文件属性fdSrc。
this.avTranscoder.fdSrc = fileDescriptor;
}
} 设置目标视频文件fd:设置属性fdDst。
import { fileIo } from '@kit.CoreFileKit';
import { media } from '@kit.MediaKit';
private avTranscoder: media.AVTranscoder | undefined = undefined;
private context: Context | undefined;
constructor(context: Context | undefined) {
if (context != undefined) {
this.context = context; // this.getUIContext().getHostContext();。
}
}
async test() {
// 创建转码实例。
this.avTranscoder = await media.createAVTranscoder();
if (this.context != undefined) {
// 设置输出目标文件的沙箱路径。
let outputFilePath = this.context.filesDir + "/output.mp4";
// 文件不存在时创建并打开文件,文件存在时打开文件。
let file = fileIo.openSync(outputFilePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
// 设置转码的目标文件属性fdDst。
this.avTranscoder.fdDst = file.fd; // 参考应用文件访问与管理中的开发示例获取创建的视频文件fd填入此处。
}
} 配置视频转码参数,调用prepare()接口。
import { media } from '@kit.MediaKit';
private avTranscoder: media.AVTranscoder | undefined = undefined;
private avConfig: media.AVTranscoderConfig = {
audioBitrate: 100000, // 音频比特率。
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式。
fileFormat: media.ContainerFormatType.CFT_MPEG_4, // 封装格式。
videoBitrate: 2000000, // 视频比特率。
videoCodec: media.CodecMimeType.VIDEO_AVC, // 视频编码格式。
};
async test() {
// 创建转码实例。
this.avTranscoder = await media.createAVTranscoder();
// 配置转码参数完成准备工作。
await this.avTranscoder.prepare(this.avConfig);
} 可在avConfig中设置目标视频的分辨率。
let avConfig: media.AVTranscoderConfig = {
audioBitrate: 100000, // 音频比特率。
audioCodec: media.CodecMimeType.AUDIO_AAC, // 音频编码格式。
fileFormat: media.ContainerFormatType.CFT_MPEG_4, // 封装格式。
videoBitrate: 2000000, // 视频比特率。
videoCodec: media.CodecMimeType.VIDEO_AVC, // 视频编码格式。
videoFrameWidth: 640, // 目标视频分辨率的宽为640。
videoFrameHeight: 480, // 目标视频分辨率的高为480。
}; 开始转码,调用start()接口。
async startTranscoderingProcess() {
if (canIUse('SystemCapability.Multimedia.Media.AVTranscoder')) {
if (this.avTranscoder != undefined) {
await this.avTranscoder.release();
this.avTranscoder = undefined;
}
// 开始转码前需要创建转码实例、设置回调、设置fd并完成prepare。
// 具体创建步骤参考开发步骤1-5。
// 开始转码。
await this.avTranscoder.start();
}
} 暂停转码,调用pause()接口。
// 暂停转码对应的流程。
async pauseTranscoderingProcess() {
if (canIUse('SystemCapability.Multimedia.Media.AVTranscoder')) {
if (this.avTranscoder != undefined) { // 仅在调用start返回后调用pause为合理调用。
await this.avTranscoder.pause();
}
}
} 恢复转码,调用resume()接口。
// 恢复转码。
async resumeTranscoderingProcess() {
if (canIUse('SystemCapability.Multimedia.Media.AVTranscoder')) {
if (this.avTranscoder != undefined) { // 仅在调用pause返回后调用resume为合理调用。
await this.avTranscoder.resume();
}
}
} 销毁实例,调用release()接口,退出转码。
// 销毁实例。
async releaseTranscoderingProcess() {
if (canIUse('SystemCapability.Multimedia.Media.AVTranscoder')) {
if (this.avTranscoder != undefined) {
// 1.销毁实例。
await this.avTranscoder.release();
this.avTranscoder = undefined;
// 2.关闭转码目标文件fd。
fileIo.closeSync(this.avTranscoder!.fdDst);
}
}
} 完整的【开始转码-暂停转码-恢复转码-转码完成】流程
async avTranscoderDemo() {
await this.startTranscoderingProcess(); // 开始转码。
await this.pauseTranscoderingProcess(); // 暂停转码。
await this.resumeTranscoderingProcess(); // 恢复转码。
} 参考以下示例,完成“开始转码-暂停转码-恢复转码-转码完成”的完整流程。
AVTranscoderArkTS
entry/src/main/ets/
└── pages
│ └── Index.ets (转码界面)
│
└── transcoder
└── AVTranscoderManager.ets (转码功能)
entry/src/main/resources/
├── base
│ ├── element
│ │ ├── color.json
│ │ ├── float.json
│ │ └── string.json
│ └── media
│
└── rawfile
└── H264_AAC.mp4 (视频资源)