h26x_ascend编码器
1 简介
Ffmepg-Ascend 中内置了h264_ascend和h265_ascend编码器,利用昇腾NPU设备分别处理h264视频流和h265视频流的编码。
2 头文件
#include "libavcodec/ascend_enc.h"
3 特性支持
| 特性 | 参数名 | 类型 | 说明 | h264_ascend | h265_ascend |
|---|---|---|---|---|---|
| 指定运行设备 | device_id | int | 取值范围取决于芯片个数,默认为 0。 `npu-smi info` 命令可以查看芯片个数 | ✅ | ✅ |
| 指定运行通道号 | channel_id | int | 取值范围取决于芯片实际情况,超出时会报错(对于昇腾Atlas 300I pro、 Atlas 300V pro,该参数的取值范围:[0, 256),JPEGD功能和VDEC功能共用通道,且通道总数最多256。对于Atlas 500 A2推理产品,该参数的取值范围:[0, 128),JPEGD功能和VDEC功能共用通道,且通道总数最多128)。 若是指定的通道已被占用, 则自动寻找并申请新的通道。 | ✅ | ✅ |
| 指定视频编码的画质级别 | profile | int | 0: baseline, 1: main, 2: high, 默认为 1。 H265 编码器只支持 main | ✅ | ✅ |
| 指定视频编码器的速率控制模式 | rc_mode | int | 0: CBR, 1: VBR, 默认为 0 | ✅ | ✅ |
| 指定关键帧间隔 | gop | int | [1, 65536], 默认为 30 | ✅ | ✅ |
| 指定帧率 | frame_rate | int | [1, 240], 默认为25 | ✅ | ✅ |
| 限制码流的最大比特率 | max_bit_rate | int | [2, 614400], 默认为 20000 | ✅ | ✅ |
| 指定视频场景 | movement_scene | int | 0:静态场景(监控视频等), 1:动态场景(直播,游戏等), 默认为 1 | ✅ | ✅ |
| 强制编码下一帧为I帧 | \ | \ | 该特性需要修改AVFrame中的opaque参数,详情见4.2 | ✅ | ✅ |
4 编码器使用
开发态使用编码器代码样例请参考:FFmpeg-n4.4.1/doc/examples/encode_video.c
4.1 常规特性使用
如用户对执行设备,执行通道以及其他常规特性有自定义诉求,可以利用“ascend_enc.h”文件中的ASCENDEncContext_t结构体实现,如下代码所示:
ASCENDEncContext_t* privData = (ASCENDEncContext_t*)av_malloc(sizeof(ASCENDEncContext_t));
privData->device_id = 1; // 用户可自定义修改
privData->channel_id = 1; // 用户可自定义修改
privData->profile = 0; // 用户可自定义修改
privData->rc_mode = 0; // 用户可自定义修改
privData->gop = 25; // 用户可自定义修改
privData->frame_rate = 25; // 用户可自定义修改
privData->movement_scene = 0; // 用户可自定义修改
AVCodec *encoder; // 假设已经完成对encoder的初始化
AVCodecContext* encoder_ctx = avcodec_alloc_context3(encoder);
decoder_ctx->priv_data = privData; // 将自定义数据传入编码器上下文
/* 执行编码以及相关资源释放 */
···
4.2 强制编码下一帧为I帧
该特性通过AVFrame结构体中的opaque指针传递给编码器,如下代码所示:
// 通过AscendEncPrivateData_t来承载是否编码下一帧为I的语义。AscendEncPrivateData_t结构体定义在“liavcodec/avcodec.h”文件中。
AscendEncPrivateData_t privData = (AscendEncPrivateData_t*)av_malloc(sizeof(AscendEncPrivateData_t));
privData->next_is_I_frame = true; // 该参数为true时,代表下一帧将会强制编码为I帧
privData->is_instant = true; // 该参数为true时,立即编出I帧,不受帧率控制约束;该参数为false时,则在帧率控制的下一帧编出I帧。
// 当前底层支持场景为目标帧率与原帧率一致,故该参数目前无论设置为true或者false,都是每调用一次接口即可编出一个I帧,调用频繁会影响码流帧率和码率的稳定。
AVCodecContext* enc_ctx; // 假设已完成编码器上下文的初始化
AVFrame *frame; // 假设已完成AVFrame的初始化
frame->opaque = privData; // 将是否将下一帧编码为I帧的信息赋值给frame
avcodec_send_frame(enc_ctx, frame); // 调用编码器进行编码
/* 获取编码结果 */
···
frame->opaque = NULL; // 当编码I帧结束,需要对该参数进行复位,否则后续视频帧都会编码为I帧
/* 释放资源 */
···