VDEC(Video Decoder)负责将H264/H265格式的视频码流解码为YUV/RGB格式的图片。关于VDEC功能的详细介绍及约束请参见VDEC功能及约束说明。
本节介绍VDEC视频编码的接口调用流程,同时配合示例代码辅助理解该接口调用流程。
Atlas 200/300/500 推理产品上,当前版本不支持该功能。
Atlas 训练系列产品上,当前版本不支持该功能。
开发应用时,如果涉及视频解码,则应用程序中必须包含解码的代码逻辑,关于视频解码的接口调用流程,请先参见pyACL接口调用流程了解整体流程,再查看本节中的流程说明。
当前系统支持解码H264/H265的视频码流,关键接口的说明如下:
解码结束后,需调用acl.himpi.vdec_stop_recv_stream接口通知解码器停止接收码流。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝运行,仅供参考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# 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.创建通道。 channel_id = 0 buf_attr = [1920, 1080, 0, 8, HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420, HI_COMPRESS_MODE_NONE] tmv_buf_size = acl.himpi.vdec_get_tmv_buf_size(HI_PT_H264, 1920, 1080) attr = {'type': HI_PT_H264, 'mode': HI_VDEC_SEND_MODE_FRAME, 'pic_width': 1920, 'pic_height': 1080, 'stream_buf_size': 1920 * 1080 * 3 // 2, 'frame_buf_size': 0, 'frame_buf_cnt': 16, 'video_attr': {'ref_frame_num': 12, 'temporal_mvp_en': HI_TRUE, 'tmv_buf_size': tmv_buf_size}} ret = acl.himpi.vdec_create_chn(channel_id, attr) # 6.设置通道属性。 video_param_dict, ret = acl.himpi.vdec_get_chn_param(channel_id) video_param_dict["video_param"]["dec_mode "] = HI_VIDEO_DEC_MODE_IPB video_param_dict["video_param"]["compress_mode "] = HI_COMPRESS_MODE_HFBC video_param_dict["video_param"]["video_format "] = HI_VIDEO_FORMAT_TILE_64x16 video_param_dict["video_param"]["out_order"] = HI_VIDEO_OUT_ORDER_DISPLAY video_param_dict["display_frame_num"] = 3 ret = acl.himpi.vdec_set_chn_param(i, video_param_dict) # 7.解码器启动接收码流。 ret = acl.himpi.vdec_start_recv_stream(channel_id) # 8.发送码流。 # 8.1 申请输入内存。 # input_size表示输入图片占用的内存大小,此处以1024 Byte为例,用户需根据实际情况计算内存大小。 input_size = 1024; 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: # 申请Host内存。 input_buffer, ret= acl.rt.malloc_host(input_size) # 将输入图片读入内存中。 vdec_file = np.fromfile(vdec_file_path, dtype=np.byte) vdec_file_size = vdec_file.itemsize * vdec_file.size bytes_data = vdec_file.tobytes() vdec_file_ptr = acl.util.bytes_to_ptr(bytes_data) # 数据传输。 ret = acl.rt.memcpy(input_addr, input_size, vdec_file_ptr, vdec_file_size, ACL_MEMCPY_HOST_TO_DEVICE) else: # 将输入图片读入内存中。 vdec_file = np.fromfile(vdec_file_path, dtype=np.byte) vdec_file_size = vdec_file.itemsize * vdec_file.size bytes_data = vdec_file.tobytes() vdec_file_ptr = acl.util.bytes_to_ptr(bytes_data) # 数据传输。 ret = acl.rt.memcpy(input_addr, input_size, vdec_file_ptr, vdec_file_size, ACL_MEMCPY_DEVICE_TO_DEVICE) # 8.2 申请输出内存。 output_size = 1920 * 1080 * 3 // 2 output_addr, ret = acl.himpi.dvpp_malloc(0, output_size); # 8.3 构造存放一帧输入码流信息的字典。 stream = {'end_of_frame': HI_TRUE, 'end_of_stream': HI_FALSE, 'need_display': HI_TRUE, 'pts': 0, 'len': input_size, 'addr': input_addr} # 8.4 构造存放一帧输出结果信息的字典。 out_pic_info = {"width": 1920, "height": 1080, "width_stride": 1920, "height_stride": 1080, "pixel_format": HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420, 'vir_addr': output_addr, "buffer_size": output_size} # 8.4 发送一帧码流。 ret = acl.himpi.vdec_send_stream(channel_id, stream, out_pic_info, 0) # 9.接收解码结果。 # 9.1 获取解码结果。 frame_info, supplement, stream, ret = acl.himpi.vdec_get_frame(channel_id, 0) if ret == 0: dec_result = frame_info['v_frame']['frame_flag'] if dec_result == 0: # 0: Decode success print("Chn %u GetFrame Success, Decode Success \n"%channel_id) elif dec_result == 1: # 1:Decode fail print("Chn %u GetFrame Success, Decode Fail \n"%channel_id) elif dec_result == 2: # 2:This result is returned for the second field of print("Chn %u GetFrame Success, No Picture \n"%channel_id) elif dec_result == 3: # 3: Reference frame number set error print("Chn %u GetFrame Success, RefFrame Num Error \n"%channel_id) elif dec_result == 4: # 4: Reference frame size set error print("Chn %u GetFrame Success, RefFrame Size Error \n"% channel_id) # 9.2 如果运行模式为ACL_HOST,且Host上需要展示VDEC输出的图片数据,则需要申请Host内存,通过acl.rt.memcpy接口将Device的输出图片数据传输到Host。 # 9.2 获取解码结果数据。 if run_mode == ACL_HOST: # 申请Host内存。 output_buffer, ret= acl.rt.malloc_host(out_pic_info['buffer_size']) # 数据传输。 ret = acl.rt.memcpy(output_buffer, out_pic_info['buffer_size'], frame_info['v_frame']['virt_addr'][0], out_pic_info['buffer_size'], ACL_MEMCPY_DEVICE_TO_HOST) # ...... # 数据使用完成后,及时释放不使用的内存。 ret = acl.rt.free_host(output_buffer) else: # 可以直接使用JPEGD的输出图片数据,在outputPic.picture_address指向的内存中。 # ...... # 9.3 释放输入、输出内存。 ret = acl.himpi.dvpp_free(frame_info['v_frame']['virt_addr'][0]) ret = acl.himpi.dvpp_free(stream['addr']) # 9.4 释放资源。 ret = acl.himpi.vdec_release_frame(channel_id, frame_info) # 10.解码器停止接收码流。 ret = acl.himpi.vdec_stop_recv_stream(channel_id) # 7.销毁通道。 ret = acl.himpi.vdec_destroy_chn(channel_id) # 8. 媒体数据处理系统去初始化。 ret = acl.himpi.sys_exit() # 9. 释放运行管理资源(依次释放Context、Device)。 ret = acl.rt.destroy_context(context) ret = acl.rt.reset_device(0) # 10.pyACL去初始化。 ret = acl.finalize() |