---
title: VENC视频编码
description: "VENC（Video Encoder）将YUV420SP格式的图片编码成H.264/H.265格式的视频码流。关于VENC功能的详细介绍请参见VENC功能及约束说明(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0504.html)。"
url: https://www.hiascend.com/document/detail/zh/canncommercial/latest/programug/acldevg/aclpythondevg_0065.html
sourcePath: /source/zh/canncommercial/900/programug/acldevg/aclpythondevg_0065.html
indexId: 24d0bb366df75b8125dd393655632b4608ac01ed556fb2dff4f90bd0c9de513c71
---
# VENC视频编码

VENC（Video Encoder）将YUV420SP格式的图片编码成H.264/H.265格式的视频码流。关于VENC功能的详细介绍请参见VENC功能及约束说明(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0504.html)。

本节介绍VENC视频编码的接口调用流程，同时配合示例代码辅助理解该接口调用流程。


Atlas 训练系列产品 上，当前版本不支持该功能。

Atlas A2 训练系列产品 / Atlas A2 推理系列产品 上，不支持该功能。


#### 接口调用流程

开发应用时，如果涉及视频编码，则应用程序中必须包含编码的代码逻辑，关于编码的接口调用流程，请先参见接口调用流程了解整体流程，再查看本节中的流程说明。

图1 接口调用流程

当前系统支持H.264/H.265格式的视频码流，关键接口的说明如下：1. 调用  acl.himpi.sys_init(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0414.html)
接口进行媒体数据处理系统初始化。
2. 调用  acl.himpi.venc_create_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0506.html)
函数创建通道。
  成功创建通道之后，您可以根据实际需求设置编码的高级参数，例如场景模式、码流控制器的高级参数等，请参见acl.himpi.venc_set_jpeg_param(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0519.html)~acl.himpi.venc_compact_jpeg_tables(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0529.html)章节中的接口说明。

3. 调用  acl.himpi.venc_get_fd(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0517.html)
将通道ID转换为一个文件句柄。
4. 调用  acl.himpi.sys_create_epoll(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0420.html)
函数创建DVPP epoll实例。
5. 调用  acl.himpi.sys_ctl_epoll(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0421.html)
函数将编码通道的文件句柄添加到epoll实例中，由epoll实例处理。
  select或者poll方式，不需要执行该步骤。

6. 调用  acl.himpi.venc_start_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0508.html)
函数通知通道准备开始编码。
7. 调用  acl.himpi.dvpp_malloc(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0416.html)
接口申请存放Device上输入数据的内存。
  Atlas 200I/500 A2 推理产品 上，同时支持使用acl.rt.malloc(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/runtimeapi/aclpythondevg_01_0110.html)接口申请内存。

  对于 Atlas 200I/500 A2 推理产品 ，调用acl.himpi.dvpp_malloc(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0416.html)接口申请的内存为媒体数据处理的专用内存，但专用内存的地址空间有限，若关注内存规划或内存资源有限时，建议调用acl.rt.malloc(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/runtimeapi/aclpythondevg_01_0110.html)接口申请内存。

8. 启动一个用户态线程，调用  acl.himpi.sys_wait_epoll(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0422.html)
函数等待编码完成。
9. 之后用户就可以调用  acl.himpi.venc_send_frame(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0513.html)
函数发送待编码的码流。
10. 一旦编码完成，  acl.himpi.sys_wait_epoll(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0422.html)
函数或select函数或poll函数就会返回，用户就可以调用  acl.himpi.venc_query_status(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0510.html)
接口查询编码状态，再调用  acl.himpi.venc_get_stream(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0511.html)
函数获取编码结果。
11. 用户需要注意的是，编码结果数据使用完成之后，需要及时调用  acl.himpi.venc_release_stream(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0512.html)
函数释放Buffer。否则会因编码Buffer用完导致后续编码无法进行。
12. 调用  acl.himpi.dvpp_free(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0417.html)
接口释放输入内存。
  Atlas 200I/500 A2 推理产品 上，若使用acl.rt.malloc(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/runtimeapi/aclpythondevg_01_0110.html)接口申请内存，则需使用acl.rt.free(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/runtimeapi/aclpythondevg_01_0115.html)接口释放内存。

13. 当用户不需发送图像到目标通道继续编码时，需要调用  acl.himpi.venc_stop_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0509.html)
函数通知该通道不再接收新的输入图片。
14. 调用  acl.himpi.sys_ctl_epoll(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0421.html)
函数从epoll实例中删除编码通道的文件句柄。
15. 当用户完成所有编码之后，需要调用  acl.himpi.venc_destroy_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0507.html)
释放编码通道以及内部内存资源。
16. 调用  acl.himpi.sys_close_epoll(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0423.html)
函数销毁DVPP epoll实例。
17. 调用  acl.himpi.sys_exit(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0415.html)
接口进行媒体数据处理系统去初始化。


#### 优化视频编码质量

在实现VENC视频编码功能时，可在创建通道时设置基本参数、或调用对应的set接口设置高级参数，优化视频编码质量，以下调整手段可以叠加使用，效果是叠加的，例如：

- H.264视频数据获取场景，分辨率720P，gop = 60，帧率30fps，码率1M需要提升编码质量，可以使用如下优化手段组合：CBR模式、HI_VENC_SCENE_0、stats_time等于2、profile等于2、关闭宏块级码控。
- H.265电影场景，分辨率1080P，gop=30，帧率25fps，码率2M需要提升编码质量，可以使用如下优化手段组合：CBR模式、HI_VENC_SCENE_1、stats_time等于1、关闭宏块级码控。

当前支持以下方式优化视频编码质量：

- 设置基本参数，优化视频编码质量
不同分辨率的视频，其编码质量与视频的帧率、GOP（Group of pictures）、码率有关，在调用acl.himpi.venc_create_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0506.html)接口创建通道时，可设置编码的等级、设置H.264/H.265协议编码场景下CBR/VBR/AVBR/CVBR/QVBR模式的帧率、GOP、码率等参数，来调整视频编码质量：

  - 编码等级，通过    hi_venc_chn_attr(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0615.html)
["venc_attr"]字典内的“profile”属性来确定。
  - 帧率，通过    hi_venc_chn_attr(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0615.html)
["rc_attr"]字典内的“src_frame_rate”输入帧率参数、“dst_frame_rate”输出帧率属性来确定。
  - GOP，通过    hi_venc_chn_attr(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0615.html)
["rc_attr"]字典内的“gop”属性来确定。
  - 码率，通过    hi_venc_chn_attr(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg_01_0615.html)
["rc_attr"]字典内的“bit_rate”、“max_bit_rate”或“target_bit_rate”属性来确定。

**表1 典型场景下帧率、GOP、码率的取值**

| 画质/分辨率 | 帧率 | GOP | 码率（mbps） |
| --- | --- | --- | --- |
| 4K 3840\*2160/4096\*2160 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H264/H265码流，码率取值8~12。 秀场/主播/短视频场景 H265码流，码率取值6~12。 H264码流，不涉及。 游戏视频场景 H264/H265码流，码率取值10~16。 |
| 2K 2560\*1440 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H264/H265码流，码率取值6~10。 秀场/主播/短视频场景 H265码流，码率取值4.8~8。 H264码流，不涉及。 游戏视频场景 H264/H265码流，码率取值6~10。 |
| 1080P（蓝光） 1920\*1080 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H265码流，码率取值1~4。 H264码流，码率取值2~6。 秀场/主播/短视频场景 H265码流，码率取值1.4~3.6。 H264码流，码率取值2~4.8。 游戏视频场景 H264/H265码流，码率取值3~6。 |
| 720P（高清） 1280\*720 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H265码流，码率取值0.8~2。 H264码流，码率取值1~3。 秀场/主播/短视频场景 H265码流，码率取值1~2。 H264码流，码率取值1~3。 游戏视频场景 H264/H265码流，码率取值2~4。 |
| 480P/D1\_N（标清） 854\*480/720\*480 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H265码流，码率取值0.3~0.7。 H264码流，码率取值0.6~1.4。 秀场/主播/短视频场景 H265码流，码率取值0.25~0.6。 H264码流，码率取值0.3~0.7。 游戏视频场景 不涉及。 |
| 576P/D1（标清） 720\*576 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H265码流，码率取值0.3~0.7。 H264码流，码率取值0.6~1.4。 秀场/主播/短视频场景 H265码流，码率取值0.25~0.6。 H264码流，码率取值0.3~0.7。 游戏视频场景 不涉及。 |
| 270P（流畅） 480\*270 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 不涉及。 秀场/主播/短视频场景 H265码流，码率取值0.2。 H264码流，码率取值0.3。 游戏视频场景 不涉及。 |
| CIF P/N 352\*288/320\*240 | 25或30 | 建议GOP为帧率的整数倍，例如帧率为25时，GOP建议25或50。 | 视频数据获取场景 H264/H265码流，码率取值0.25。 秀场/主播/短视频场景 不涉及。 游戏视频场景 不涉及。 |


- 设置高级参数，调整视频编码细节
  您可以调用接口设置码控模式、宏块级码率控制参数、编码场景模式等，来调整视频编码的细节，进一步改善编码质量。

**表2 高级配置项列表**

| 配置项 | 接口 | 参数名 | 说明 |
| --- | --- | --- | --- |
| 码控模式 | acl.himpi.venc\_create\_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0506.html) | hi\_venc\_chn\_attr(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0615.html)["rc\_attr"]字典内的“rc\_mode”属性 | 追求码率平稳或追求PSNR大且码率符合目标值，配置为CBR。 追求节省码率，对主观编码质量有一定要求，配置为VBR。 追求节省码率，对主观编码质量有一定要求，且场景中有较多静止画面，配置为AVBR。 追求PSNR且对码率上浮没有严格要求，配置为QVBR。 追求节省码率，对主观编码质量有一定要求，且可以根据带宽、存储空间要求进行更多调整，配置为CVBR。 |
| 码率控制模型统计时间 | acl.himpi.venc\_create\_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0506.html) | hi\_venc\_chn\_attr(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0615.html)["rc\_attr"]字典内各模式属性值字典内的“stats\_time”属性 | 关注长期码率稳定，短期波动不在意的可以设置大一些，例：DVR存盘。设大可以提高重编码判决的门槛，重编码次数会减少，但是码率波动会加大。 |
| 宏块级码率控制参数 | acl.himpi.venc\_set\_rc\_param(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0525.html) | hi\_venc\_rc\_param(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0679.html)字典内的“threshold\_i”、“threshold\_p”、“threshold\_b”、“direction”、“row\_qp\_delta”属性。 | 如果图像内容复杂、细节较多或用户关注PSNR等客观指标时，需关闭宏块级码率控制。 |
| 第一帧的起始QP值 | acl.himpi.venc\_create\_chn(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0506.html) | hi\_venc\_rc\_param(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0679.html)字典内的“first\_frame\_start\_qp”属性 | 典型场景下，用户配置的码率小于表1中给的参考值，且编码后的视频第一帧明显模糊，则建议配置“first\_frame\_start\_qp”属性，参数值取[min\_i\_qp, max\_i\_qp]的中间值，例如,[min\_i\_qp, max\_i\_qp]为[30, 40]，则“first\_frame\_start\_qp”配置为“35”，同时将“max\_reencode\_times”配置为“0”，会获得较好的编码质量。 |
| 编码场景模式 | acl.himpi.venc\_set\_scene\_mode(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0523.html) | hi\_venc\_scene\_mode(https://www.hiascend.comdocument/detail/zh/canncommercial/900/API/dvpp/aclpythondevg\_01\_0678.html)类 | 安防场景配置为HI\_VENC\_SCENE\_0；自动驾驶、直播、游戏、动画、电影配置为HI\_VENC\_SCENE\_1。 |


#### 示例代码

调用接口后，需增加异常处理的分支，并记录报错日志、提示日志，此处不一一列举。以下是关键步骤的代码示例，不可以直接拷贝运行，仅供参考。

```
# 1.获取软件栈的运行模式，不同运行模式影响后续的接口调用流程（例如是否进行数据传输等）。
run_mode, ret = acl.rt.get_run_mode()

# 2.初始化。
ret = acl.init()

# 3.运行时资源申请。
# 4.初始化媒体数据处理系统。
ret = acl.himpi.sys_init()

# 5.设置VENC模块参数。
param = {'mod_type':HI_VENC_MOD_H265}
param, ret = acl.himpi.venc_get_mod_param(param)
param['jpeg_mod_param']['one_stream_buf'] = 1
ret = acl.himpi.venc_set_mod_param(param)

# 6.创建通道。
channel_id = 0
venc_attr = {'type': HI_VENC_MOD_H265, 'profile': 0,
             'max_pic_width': 128, 'pic_width': 128,
             'max_pic_height': 128, 'pic_height': 128,
             'buf_size': 1024 * 1024 * 2, 'is_by_frame': 1}
rc_attr = {'rc_mode':HI_VENC_RC_MODE_H265_VBR,
           'h265_vbr':{'gop': 30, 'stats_time': 1,
                       'src_frame_rate': 30, 'dst_frame_rate': 30,
                       'max_bit_rate': 4000}}
gop_attr = {'gop_mode':0, 'normal_p':{'ip_qp_delta':3}}
attr = {'venc_attr':venc_attr, 'rc_attr':rc_attr, 'gop_attr':gop_attr}
ret = acl.himpi.venc_create_chn(channel_id, attr)

# 7.通知编码器开始接收输入数据。
recv_param = {'recv_pic_num':-1}
ret = acl.himpi.venc_start_chn(channel_id, recv_param)

# 8.发送输入数据。
# 8.1 申请输入内存。
input_size = 128 * 128 * 3 // 2
input_addr, ret = acl.himpi.dvpp_malloc(0, input_size);

# 如果运行模式为ACL_HOST，则需要申请Host内存，将输入数据读入Host内存，再通过acl.rt.memcpy接口将Host的数据传输到Device，数据传输完成后，需及时释放Host内存；否则直接将输入数据读入Device内存。
# 直接将输入数据读入Device内存。
if run_mode == ACL_HOST:
    # 将输入图片读入内存中。
    jpege_file = np.fromfile(jpege_file_path, dtype=np.byte)
    jpege_file_size = jpege_file.itemsize * jpege_file.size
    
    bytes_data = jpege_file.tobytes()
    jpege_file_ptr = acl.util.bytes_to_ptr(bytes_data)
    # 数据传输。
    ret = acl.rt.memcpy(input_addr, input_size, jpege_file_ptr, jpege_file_size, ACL_MEMCPY_HOST_TO_DEVICE)
else:
    # 将输入图片读入内存中。
    jpege_file = np.fromfile(jpege_file_path, dtype=np.byte)
    jpege_file_size = jpege_file.itemsize * jpege_file.size
    
    bytes_data = jpege_file.tobytes()
    jpege_file_ptr = acl.util.bytes_to_ptr(bytes_data)
    # 数据传输。
    ret = acl.rt.memcpy(input_addr, input_size, jpege_file_ptr, jpege_file_size, ACL_MEMCPY_DEVICE_TO_DEVICE)

# 8.2 发送输入数据，开始编码。
v_frame = {'width': 128,
           'height': 128,
           'field': HI_VIDEO_FIELD_FRAME,
           'pixel_format': HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420,
           'video_format': HI_VIDEO_FORMAT_LINEAR,
           'compress_mode': HI_COMPRESS_MODE_NONE,
           'dynamic_range': HI_DYNAMIC_RANGE_SDR8,
           'color_gamut': HI_COLOR_GAMUT_BT709,
           'header_stride': [0, 0, 0],
           'width_stride': [128, 0, 0],
           'height_stride': [0, 0, 0],
           'header_phys_addr': [0, 0, 0],
           'phys_addr': [0, 0, 0],
           'header_virt_addr': [0, 0, 0],
           'virt_addr': [input_addr, 0, 0],
           'time_ref': 0,'pts': cur_time}
frame = {'v_frame':v_frame, 'pool_id':0, 'mod_id':HI_ID_VENC}
ret = acl.himpi.venc_send_frame(channel_id, frame, 0)

# 9.获取编码结果。
# 9.1 通过EPOLL处理编码完成事件。
fd = acl.himpi.venc_get_fd(channel_id)
epoll_fd, ret = acl.himpi.sys_create_epoll(10)

event = {'data': fd, 'events': HI_DVPP_EPOLL_IN}
ret = acl.himpi.sys_ctl_epoll(epoll_fd, HI_DVPP_EPOLL_CTL_ADD, fd, event)

# 编码完成前，会超时阻塞在这里，一旦完成，才会往下执行。
events, eventCount, ret = acl.himpi.sys_wait_epoll(epoll_fd, 3, 1000);

# 9.2 获取编码结果。
status, ret = acl.himpi.venc_query_status(channel_id)
stream = {'pack_cnt': status['cur_packs']}
stream, ret = acl.himpi.venc_get_stream(self.channel_id, stream, 1000)
# 9.3 如果运行模式为ACL_HOST，且Host上需要使用编码输出的码流，则需要申请Host内存，通过acl.rt.memcpy接口将Device的输出码流传输到Host。
# 获取编码输出码流数据。
if run_mode == ACL_HOST:
    # 申请Host内存。
    output_buffer, ret= acl.rt.malloc_host(output_size)
    # 数据传输。
    ret = acl.rt.memcpy(output_buffer, output_size, stream['pack'][0]['addr'], output_size, ACL_MEMCPY_DEVICE_TO_HOST)
    # ......
    # 数据使用完成后，及时释放不使用的内存。
    ret = acl.rt.free_host(output_buffer)
else:
    # 可以直接使用编码输出码流数据，在stream['pack'][0]['addr']指向的内存中。
    # ......

# 10.释放输入内存和输出码流。
ret = acl.himpi.dvpp_free(input_addr)
ret = acl.himpi.venc_release_stream(channel_id, stream)

# 11.通知编码器停止接收输入数据。
ret = acl.himpi.venc_stop_chn(channel_id)
ret = acl.himpi.sys_ctl_epoll(epoll_fd, HI_DVPP_EPOLL_CTL_DEL, fd, event)
ret = acl.himpi.sys_close_epoll(epoll_fd)

# 12.销毁通道。
ret = acl.himpi.venc_destroy_chn(channel_id)

# 13. 媒体数据处理系统去初始化。
ret = acl.himpi.sys_exit()

# 14. 释放运行时资源。
# 15.去初始化。
ret = acl.finalize()
```
