示例代码
基本原理
- JPEGE编码前,需调用hi_mpi_venc_start_chn接口通知编码器启动接收编码输入数据帧,再调用hi_mpi_venc_send_frame接口发送编码输入数据帧,hi_mpi_venc_send_frame接口是异步接口,调用该接口仅表示任务下发成功,还需要调hi_mpi_venc_get_stream接口获取编码码流。编码结束后,需调用hi_mpi_venc_stop_chn接口通知编码器停止接收输入数据。
- 输入、输出相关的约束要求,请参见JPEGE功能及约束说明。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
// 1.AscendCL初始化
aclRet = aclInit(nullptr);
// 2.运行管理资源申请(依次申请Device、Context)
aclrtContext g_context;
aclRet = aclrtSetDevice(0);
aclRet = aclrtCreateContext(&g_context, 0);
// 获取软件栈的运行模式,不同运行模式影响后续的接口调用流程(例如是否进行数据传输等)
aclrtRunMode runMode;
aclError aclRet = aclrtGetRunMode(&runMode);
// 3.初始化媒体数据处理系统
int32_t ret = hi_mpi_sys_init();
// 4.创建通道
hi_venc_chn chn = 0;
hi_venc_chn_attr attr{};
attr.venc_attr.type = HI_PT_JPEG;
attr.venc_attr.profile = 0;
attr.venc_attr.max_pic_width = 128;
attr.venc_attr.max_pic_height = 128;
attr.venc_attr.pic_width = 128;
attr.venc_attr.pic_height = 128;
attr.venc_attr.buf_size = 2 * 1024 * 1024;
attr.venc_attr.is_by_frame = HI_TRUE;
attr.venc_attr.jpeg_attr.dcf_en = HI_FALSE;
attr.venc_attr.jpeg_attr.recv_mode = HI_VENC_PIC_RECV_SINGLE;
attr.venc_attr.jpeg_attr.mpf_cfg.large_thumbnail_num = 0;
ret = hi_mpi_venc_create_chn(chn, &attr);
// 5.通知编码器开始接收输入数据
hi_venc_start_param recv_param{};
recv_param.recv_pic_num = -1;
ret = hi_mpi_venc_start_chn(chn, &recv_param);
// 6.发送输入数据
// 6.1 申请输入内存
uint8_t* inputAddr = nullptr;
int32_t inputSize = 128 * 128 * 3 / 2;
ret = hi_mpi_dvpp_malloc(0, &inputAddr, inputSize);
// 如果运行模式为ACL_HOST,则需要申请Host内存,将输入图片数据读入Host内存,再通过aclrtMemcpy接口将Host的图片数据传输到Device,数据传输完成后,需及时释放Host内存;否则直接将输入图片数据读入Device内存
if (runMode == ACL_HOST) {
void* hostInputAddr = nullptr;
// 申请Host内存
aclRet = aclrtMallocHost(&hostInputAddr, inputSize);
// 将输入数据读入内存中,该自定义函数JpegeReadYuvFile由用户实现
JpegeReadYuvFile(streamName, hostInputAddr, inputSize);
// 数据传输
aclRet = aclrtMemcpy(inputAddr, inputSize, hostInputAddr, inputSize, ACL_MEMCPY_HOST_TO_DEVICE);
// 完成数据传输后,需及时释放不使用的内存
aclrtFreeHost(hostInputAddr );
hostInputAddr = nullptr;
} else {
// 将输入数据读入内存中,该自定义函数JpegeReadYuvFile由用户实现
JpegeReadYuvFile(streamName, inputAddr, inputSize);
}
// 6.2 发送输入数据,开始编码
hi_video_frame_info frame{};
frame.mod_id = HI_ID_VENC;
frame.v_frame.width = 128;
frame.v_frame.height = 128;
frame.v_frame.field = HI_VIDEO_FIELD_FRAME;
frame.v_frame.pixel_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
frame.v_frame.video_format = HI_VIDEO_FORMAT_LINEAR;
frame.v_frame.compress_mode = HI_COMPRESS_MODE_NONE;
frame.v_frame.dynamic_range = HI_DYNAMIC_RANGE_SDR8;
frame.v_frame.color_gamut = HI_COLOR_GAMUT_BT709;
frame.v_frame.width_stride[0] = 128;
frame.v_frame.width_stride[1] = 128;
frame.v_frame.width_stride[2] = 128;
frame.v_frame.virt_addr[0] = inputAddr;
frame.v_frame.virt_addr[1] = (hi_void *)((uintptr_t)frame.v_frame.virt_addr[0] + 128 * 128);
frame.v_frame.frame_flag = 0;
frame.v_frame.time_ref = 0;
frame.v_frame.pts = 0;
ret = hi_mpi_venc_send_frame(chn, &frame, 0);
// 7.获取编码结果
// 7.1 创建EPOLL实例
int32_t epollFd = 0;
int32_t fd = hi_mpi_venc_get_fd(chn);
ret = hi_mpi_sys_create_epoll(10, &epollFd);
hi_dvpp_epoll_event event;
event.events = HI_DVPP_EPOLL_IN;
event.data = (void*)(unsigned long)(fd);
ret = hi_mpi_sys_ctl_epoll(epollFd, HI_DVPP_EPOLL_CTL_ADD, fd, &event);
int32_t eventCount = 0;
// 编码完成前,会超时阻塞在这里,一旦完成,才会往下执行
ret = hi_mpi_sys_wait_epoll(epollFd, events, 3, 1000, &eventCount);
// 7.2 获取编码结果
hi_venc_chn_status stat;
ret = hi_mpi_venc_query_status(chn, &stat);
hi_venc_stream stream;
stream.pack_cnt = stat.cur_packs;
stream.pack = new hi_venc_pack[stream.pack_cnt];
ret = hi_mpi_venc_get_stream(chn, &stream, 1000);
// 7.3 如果运行模式为ACL_HOST,且Host上需要使用编码输出的码流,则需要申请Host内存,通过aclrtMemcpy接口将Device的输出码流传输到Host;否则直接使用编码输出码流数据
if (g_runMode == ACL_HOST) {
void* hostOutputAddr = nullptr;
aclRet = aclrtMallocHost(&hostOutputAddr, outputSize);
aclRet = aclrtMemcpy(hostOutputAddr, outputSize, stream.pack[0].addr, outputSize, ACL_MEMCPY_DEVICE_TO_HOST);
// ......
// 数据使用完成后,需及时释放不使用的内存
aclrtFreeHost(hostOutputAddr);
hostOutputAddr = nullptr;
} else {
// 可以直接使用编码输出码流数据,在stream.pack[0].addr指向的内存中
// ......
}
// 8.释放输入内存和输出码流
ret = hi_mpi_dvpp_free(inputAddr);
ret = hi_mpi_venc_release_stream(chn, &stream);
delete[] stream.pack;
// 9.通知编码器停止接收输入数据
ret = hi_mpi_venc_stop_chn(chn);
ret = hi_mpi_sys_ctl_epoll(epollFd, HI_DVPP_EPOLL_CTL_DEL, fd, NULL);
ret = hi_mpi_sys_close_epoll(epollFd);
// 10.销毁通道
ret = hi_mpi_venc_destroy_chn(chn);
// 11.媒体数据处理系统去初始化
ret = hi_mpi_sys_exit();
// 12.释放运行管理资源(依次释放Context、Device)
aclRet = aclrtDestroyContext(g_context);
aclRet = aclrtResetDevice(0);
// 13.AscendCL去初始化
aclRet = aclFinalize();
// ....
父主题: JPEGE图片编码