示例代码
基本原理
- PNGD图片解码时,调用hi_mpi_pngd_send_stream接口发送解码码流。hi_mpi_pngd_send_stream接口是异步接口,调用该接口仅表示任务下发成功,还需要调hi_mpi_pngd_get_image_data接口获取解码结果数据。
- 输入、输出相关的约束要求,请参见功能及约束说明。
示例代码
您可以从样例介绍中获取完整样例代码。
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
// 1.获取软件栈的运行模式,不同运行模式影响后续的接口调用流程(例如是否进行数据传输等)
aclrtRunMode runMode;
aclError aclRet = aclrtGetRunMode(&runMode);
// 2.AscendCL初始化
aclRet = aclInit(nullptr);
// 3.运行管理资源申请(依次申请Device、Context)
aclrtContext g_context;
aclRet = aclrtSetDevice(0);
aclRet = aclrtCreateContext(&g_context, 0);
// 4.初始化媒体数据处理系统
int32_t ret = hi_mpi_sys_init();
// 5.创建通道
hi_pngd_chn chnId;
hi_pngd_chn_attr chnAttr; // hi_pngd_chn_attr都是保留参数,无需设置
ret = hi_mpi_pngd_create_chn(chnId, &chnAttr);
// 6.发送码流
// 6.1 申请输入内存
uint8_t* inputAddr = nullptr;
// inputsize表示输入图片占用的内存大小,此处以1024 byte为例,用户需根据实际情况计算内存大小
int32_t inputSize = 1024;
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);
// 将输入图片读入内存中,该自定义函数ReadStreamFile由用户实现
ReadStreamFile(fileName, hostInputAddr, inputSize);
// 数据传输
aclRet = aclrtMemcpy(inputAddr, inputSize, hostInputAddr, inputSize, ACL_MEMCPY_HOST_TO_DEVICE);
} else {
// 将输入图片读入内存中,该自定义函数ReadStreamFile由用户实现
ReadStreamFile(fileName, inputAddr, inputSize);
}
// 6.2 构造存放输入图片信息的结构体
hi_img_stream stStream{};
hi_img_info stImgInfo{};
stStream.pts = 0;
if (g_runMode == ACL_HOST) {
stStream.addr = (uint8_t *)hostInputAddr;
} else {
stStream.addr = (uint8_t *)inputAddr;
}
stStream.len = inputSize;
stStream.type = HI_PT_PNG;
ret = hi_mpi_png_get_image_info(&stStream, &stImgInfo);
if (g_runMode == ACL_HOST) {
// 如果不使用Host上的数据,需及时释放
aclrtFreeHost(hostInputAddr);
hostInputAddr = nullptr;
}
stStream.addr = (uint8_t *)inputAddr;
// 6.3 构造存放输出图片信息的结构体,并申请输出内存
hi_pic_info outPicInfo{};
void *outBuffer = nullptr;
outPicInfo.picture_width = stImgInfo.width;
outPicInfo.picture_height = stImgInfo.height;
outPicInfo.picture_width_stride = stImgInfo.width_stride;
outPicInfo.picture_height_stride = stImgInfo.height_stride;
outPicInfo.picture_buffer_size = stImgInfo.img_buf_size;
outPicInfo.picture_format = HI_PIXEL_FORMAT_UNKNOWN;
ret = hi_mpi_dvpp_malloc(0, &outBuffer, outPicInfo.buffer_size);
outPicInfo.picture_address = (uint64_t)outBuffer;
// 6.4 发送需解码的输入图片
ret = hi_mpi_pngd_send_stream(chnId, &stream, &outPicInfo, 0);
// 7.接收解码结果
// 7.1 获取解码结果
hi_pic_info picInfo;
hi_img_stream stream;
ret = hi_mpi_pngd_get_image_data(chnId, &picInfo, &stream, 0);
if (ret == HI_SUCCESS) { // Decode success
printf("[%s][%d] Chn %u GetFrame Success, Decode Success \n",__FUNCTION__, __LINE__, chnId);
} else if (ret == HI_ERR_PNGD_BUF_EMPTY){ // Decoding
printf("[%s][%d] Chn %u Decoding, try again \n",__FUNCTION__, __LINE__, chnId);
} else { // Decode fail
printf("[%s][%d] Chn %u GetFrame Success, Decode Fail \n",__FUNCTION__, __LINE__, chnId);
}
// 7.2 如果运行模式为ACL_HOST,且Host上需要展示PNGD输出的图片数据,则需要申请Host内存,通过aclrtMemcpy接口将Device的输出图片数据传输到Host
if (g_runMode == ACL_HOST) {
void* hostOutputAddr = nullptr;
aclRet = aclrtMallocHost(&hostOutputAddr, outputSize);
aclRet = aclrtMemcpy(hostOutputAddr, outputSize, frame.v_frame.virt_addr[0], outputSize, ACL_MEMCPY_DEVICE_TO_HOST);
// ......
// 数据使用完成后,及时释放不使用的内存
aclrtFreeHost(hostOutputAddr);
hostOutputAddr = nullptr;
} else {
// 可以直接使用PNGD的输出图片数据,在outputPic.picture_address指向的内存中
// ......
}
// 7.3 释放输入、输出内存
ret = hi_mpi_dvpp_free(frame.v_frame.virt_addr[0]);
ret = hi_mpi_dvpp_free(stream.addr);
// 8.销毁通道
ret = hi_mpi_pngd_destroy_chn(chnId);
// 9. 媒体数据处理系统去初始化
ret = hi_mpi_sys_exit();
// 10. 释放运行管理资源(依次释放Context、Device)
aclRet = aclrtDestroyContext(g_context);
aclRet = aclrtResetDevice(0);
// 11.AscendCL去初始化
aclRet = aclFinalize();
// ....
父主题: PNGD图片解码