示例代码
基本原理
- VENC视频编码前,需调用acl.himpi.venc_start_chn接口通知编码器启动接收编码输入数据帧,再调用acl.himpi.venc_send_frame接口发送编码输入数据帧,acl.himpi.venc_send_frame接口是异步接口,调用该接口仅表示任务下发成功,还需要调acl.himpi.venc_get_stream接口获取编码码流。编码结束后,需调用acl.himpi.venc_stop_chn接口通知编码器停止接收输入数据。
- 输入、输出相关的约束要求,请参见VENC功能及约束说明。
示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝运行,仅供参考。
# 1.获取软件栈的运行模式,不同运行模式影响后续的接口调用流程(例如是否进行数据传输等)。
run_mode, ret = acl.rt.get_run_mode()
# 2.pyACL 初始化。
ret = acl.init()
# 3.运行管理资源申请(依次申请Device、Context)。
ret = acl.rt.set_device(0)
context, ret = acl.rt.create_context(0)
# 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_filee_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 = 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
event['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。
# 9.3 获取编码输出码流数据。
if run_mode == ACL_HOST:
# 申请Host内存。
output_buffer, ret= acl.rt.malloc_host(output_ize)
# 数据传输。
ret = acl.rt.memcpy(output_buffer, output_ize, stream['pack'][0]['addr'], output_ize, 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. 释放运行管理资源(依次释放Context、Device)。
ret = acl.rt.destroy_context(context)
ret = acl.rt.reset_device(0)
# 15.pyACL去初始化。
ret = acl.finalize()
父主题: VENC视频编码