#include #include #include "acl/acl.h" #include "acl/ops/acl_dvpp.h" #include "acl/dvpp/hi_dvpp.h" #include #include using namespace std; int32_t save_jpege_pic(hi_venc_stream &stream, string out_file_name) { FILE* fd = nullptr; fd = fopen(out_file_name.c_str(), "wb"); if (fd == nullptr) { printf("open output file err\n"); return HI_FAILURE; } uint32_t dataLen = stream.pack[0].len - stream.pack[0].offset; char* pcData = new char[dataLen]; auto aclRet = aclrtMemcpy(pcData, dataLen, stream.pack[0].addr + stream.pack[0].offset, dataLen, ACL_MEMCPY_DEVICE_TO_HOST); if (aclRet != ACL_SUCCESS) { printf("aclrtMemcpy fail %d pcData:%lx,dataLen:%u,addr:%lx,offset:%d ", aclRet, (uint64_t)pcData, dataLen, (uint64_t)stream.pack[0].addr, stream.pack[0].offset); delete[] pcData; pcData = nullptr; return HI_FAILURE; } fwrite(pcData, dataLen, 1, fd); fflush(fd); delete[] pcData; pcData = nullptr; fclose(fd); return HI_SUCCESS; } int vpc_jpege_save(hi_vpc_pic_info vpc_jpege_pic, string out_file_name){ hi_venc_jpeg_param stParamJpeg{}; void* outputBuf; hi_venc_stream stream{}; hi_video_frame_info inputFrame{}; hi_u32 outputBufSize = 0; hi_venc_chn_attr vencChnAttr; vencChnAttr.venc_attr.type = HI_PT_JPEG; vencChnAttr.venc_attr.profile = 0; vencChnAttr.venc_attr.max_pic_width = vpc_jpege_pic.picture_width; vencChnAttr.venc_attr.max_pic_height = vpc_jpege_pic.picture_height; vencChnAttr.venc_attr.pic_width = vpc_jpege_pic.picture_width; vencChnAttr.venc_attr.pic_height = vpc_jpege_pic.picture_height; vencChnAttr.venc_attr.buf_size = ALIGN_UP(vpc_jpege_pic.picture_width * vpc_jpege_pic.picture_width, 64); // aligned to 64 bytes vencChnAttr.venc_attr.is_by_frame = HI_TRUE; // get stream mode is field mode or frame mode vencChnAttr.venc_attr.jpeg_attr.dcf_en = HI_FALSE; vencChnAttr.venc_attr.jpeg_attr.recv_mode = HI_VENC_PIC_RECV_SINGLE; vencChnAttr.venc_attr.jpeg_attr.mpf_cfg.large_thumbnail_num = 0; // create venc chn hi_venc_chn g_chn_id = 4; int32_t s32Ret = hi_mpi_venc_create_chn(g_chn_id, &vencChnAttr); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_create_chn [%d] faild with %#x!\n", g_chn_id, s32Ret); return s32Ret; } // start venc chn hi_venc_start_param recvParam; recvParam.recv_pic_num = -1; // unspecified frame count s32Ret = hi_mpi_venc_start_chn(g_chn_id, &recvParam); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_start_chn faild with%#x in chnl %d!\n", s32Ret, g_chn_id); goto DESTROY_CHN; } // set encode parameter s32Ret = hi_mpi_venc_get_jpeg_param(g_chn_id, &stParamJpeg); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_get_jpeg_param err 0x%x\n", s32Ret); goto DESTROY_CHN; } stParamJpeg.qfactor = 100; // assign qfactor as 100 for (hi_u32 i = 0; i < HI_VENC_JPEG_QT_COEF_NUM; i++) { stParamJpeg.y_qt[i] = 0xFF; stParamJpeg.cb_qt[i] = 0xFF; stParamJpeg.cr_qt[i] = 0xFF; } s32Ret = hi_mpi_venc_set_jpeg_param(g_chn_id, &stParamJpeg); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_set_jpeg_param err 0x%x\n", s32Ret); goto DESTROY_CHN; } // get predicted stream size inputFrame.pool_id = 0; inputFrame.v_frame.width = vpc_jpege_pic.picture_width; inputFrame.v_frame.height = vpc_jpege_pic.picture_height; inputFrame.v_frame.dynamic_range = HI_DYNAMIC_RANGE_SDR8; // Dynamic Range inputFrame.v_frame.compress_mode = HI_COMPRESS_MODE_NONE; // Compression Mode inputFrame.v_frame.pixel_format = vpc_jpege_pic.picture_format; inputFrame.v_frame.video_format = HI_VIDEO_FORMAT_LINEAR; // Video format inputFrame.v_frame.field = HI_VIDEO_FIELD_FRAME; // Frame Or Field Mode inputFrame.v_frame.color_gamut = HI_COLOR_GAMUT_BT709; // Gamut range inputFrame.v_frame.header_stride[0] = 0; // Image compression head span inputFrame.v_frame.header_stride[1] = 0; inputFrame.v_frame.width_stride[0] = vpc_jpege_pic.picture_width_stride; inputFrame.v_frame.width_stride[1] = vpc_jpege_pic.picture_width_stride; inputFrame.v_frame.header_virt_addr[0] = vpc_jpege_pic.picture_address; // Compression header virtual address inputFrame.v_frame.header_virt_addr[1] = inputFrame.v_frame.header_virt_addr[0]; // virtual address inputFrame.v_frame.virt_addr[0] = inputFrame.v_frame.header_virt_addr[0]; inputFrame.v_frame.virt_addr[1] = (hi_void*)((uintptr_t)inputFrame.v_frame.virt_addr[0] + vpc_jpege_pic.picture_width_stride * vpc_jpege_pic.picture_height_stride); s32Ret = hi_mpi_venc_get_jpege_predicted_size(&inputFrame, &stParamJpeg, &outputBufSize); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_get_jpege_predicted_size err 0x%x\n", s32Ret); goto FAIL0; } // malloc output buffer s32Ret = hi_mpi_dvpp_malloc(0, &outputBuf, outputBufSize); if (s32Ret != HI_SUCCESS) { printf("malloc venc out buffer err 0x%x\n", s32Ret); goto FAIL0; } // send frame s32Ret = hi_mpi_venc_send_frame(g_chn_id, &inputFrame, 10000); // time out 10000us if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_send_jpege_frame err 0x%x\n", s32Ret); goto FAIL1; } stream.pack_cnt = 1; stream.pack = (hi_venc_pack*)malloc(sizeof(hi_venc_pack)); if (stream.pack == nullptr) { printf("malloc failed!\n"); goto FAIL1; } // get stream s32Ret = hi_mpi_venc_get_stream(g_chn_id, &stream, -1); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_get_stream failed with %#x!\n", s32Ret); goto FAIL2; } // save file s32Ret = save_jpege_pic(stream, out_file_name); if (s32Ret != HI_SUCCESS) { printf("save jpege pic failed with %#x!\n", s32Ret); goto FAIL2; } // release stream s32Ret = hi_mpi_venc_release_stream(g_chn_id, &stream); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_release_stream failed with %#x!\n", s32Ret); goto FAIL2; } s32Ret = hi_mpi_venc_stop_chn(g_chn_id); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_stop_chn vencChn[%d] failed with %#x!\n", g_chn_id, s32Ret); goto FAIL2; } s32Ret = hi_mpi_venc_destroy_chn(g_chn_id); if (s32Ret != HI_SUCCESS) { printf("hi_mpi_venc_destroy_chn [%d] failed with %#x!\n", g_chn_id, s32Ret); goto FAIL2; } // free memory hi_mpi_dvpp_free(outputBuf); outputBuf = nullptr; hi_mpi_dvpp_free(vpc_jpege_pic.picture_address); vpc_jpege_pic.picture_address = nullptr; free(stream.pack); stream.pack = nullptr; printf("jpegd_vpc_jpege sample finished\n"); return HI_SUCCESS; FAIL2: free(stream.pack); stream.pack = nullptr; FAIL1: hi_mpi_dvpp_free(outputBuf); outputBuf = nullptr; FAIL0: hi_mpi_dvpp_free(vpc_jpege_pic.picture_address); vpc_jpege_pic.picture_address = nullptr; DESTROY_CHN: hi_mpi_venc_destroy_chn(g_chn_id); return HI_FAILURE; } int vpc_crop(acldvppPicDesc *input){ aclError aclRet; // 1.AscendCL初始化 aclRet = aclInit(nullptr); if(aclRet != ACL_ERROR_NONE){ printf("aclInit failed ! \n"); return aclRet; } // 2.运行管理资源申请(依次申请Device、Context) aclrtContext g_context; aclRet = aclrtSetDevice(0); aclRet = aclrtCreateContext(&g_context, 0); // 3.初始化媒体数据处理系统 int32_t ret = hi_mpi_sys_init(); if (ret != HI_SUCCESS) { printf("hi_mpi_sys_init failed, ret = %#x!\n", ret); return ret; } // 4.创建通道 hi_vpc_chn chnId; hi_vpc_chn_attr stChnAttr {}; stChnAttr.attr = 0; ret = hi_mpi_vpc_sys_create_chn(&chnId, &stChnAttr); if (ret != HI_SUCCESS) { printf("Call hi_mpi_vpc_sys_create_chn failed, ret = %#x\n", ret); hi_mpi_sys_exit(); return ret; } int cropInBufferSize = 1920 * 1080 * 3 / 2; char cropInHostBuffer[1920 * 1080 * 3 / 2]; for(int i=0; i< 1920 * 1080 * 3 / 2; i++){ cropInHostBuffer[i] = i % 255; } void *cropInDevBuffer_ = nullptr; ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize); ret = aclrtMemcpy(cropInDevBuffer_, cropInBufferSize, cropInHostBuffer, cropInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE); // ret = aclrtMemset(cropInDevBuffer_, cropInBufferSize, 0, cropInBufferSize); acldvppPicDesc *cropInputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(cropInputDesc_, cropInDevBuffer_); acldvppSetPicDescFormat(cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropInputDesc_, 1920); acldvppSetPicDescHeight(cropInputDesc_, 1080); acldvppSetPicDescWidthStride(cropInputDesc_, 1920); acldvppSetPicDescHeightStride(cropInputDesc_, 1080); acldvppSetPicDescSize(cropInputDesc_, cropInBufferSize); // 5.执行抠图 // 5.1 构造存放输入图片信息的结构体 hi_vpc_pic_info inputPic; inputPic.picture_width = acldvppGetPicDescWidth(cropInputDesc_); inputPic.picture_height = acldvppGetPicDescHeight(cropInputDesc_); inputPic.picture_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; inputPic.picture_width_stride = acldvppGetPicDescWidthStride(cropInputDesc_); inputPic.picture_height_stride = acldvppGetPicDescHeightStride(cropInputDesc_); inputPic.picture_buffer_size = inputPic.picture_width_stride * inputPic.picture_height_stride * 3 / 2; // 5.2 准备输入图片数据 inputPic.picture_address = acldvppGetPicDescData(cropInputDesc_); vpc_jpege_save(inputPic, "input.jpg"); // 5.3 构造存放输出图片信息的结构体 // 该参数表示抠图数量 uint32_t multiCount = 1; // cropRegionInfos数组的大小与抠图数量保持一致 vector vec_regions; hi_vpc_crop_region_info cropRegionInfo[1]; for (uint32_t i = 0; i < multiCount; i++) { // hi_vpc_crop_region_info cropRegionInfo; hi_vpc_pic_info outputPic; outputPic.picture_width = 960; outputPic.picture_height = 540; outputPic.picture_format = HI_PIXEL_FORMAT_YUV_SEMIPLANAR_420; outputPic.picture_width_stride = 960; outputPic.picture_height_stride = 540; outputPic.picture_buffer_size = outputPic.picture_width_stride * outputPic.picture_height_stride * 3 / 2; ret = hi_mpi_dvpp_malloc(0, &outputPic.picture_address, outputPic.picture_buffer_size); // 初始化内存 aclRet = aclrtMemset(outputPic.picture_address, outputPic.picture_buffer_size, 0, outputPic.picture_buffer_size); // 表示从输入图片中抠出以左上角为原点、分辨率960*540的子图 cropRegionInfo[0].dest_pic_info = outputPic; cropRegionInfo[0].crop_region.left_offset = 0; cropRegionInfo[0].crop_region.top_offset = 0; cropRegionInfo[0].crop_region.crop_width = 960; cropRegionInfo[0].crop_region.crop_height = 540; // vec_regions.push_back(cropRegionInfo); } // 5.4 调用抠图接口 uint32_t taskID = 0; ret = hi_mpi_vpc_crop(chnId, &inputPic, cropRegionInfo, 1, &taskID, -1); // 5.5 等待任务处理结束,任务处理结束后,输出图片数据在outputPic.picture_address指向的内存中 uint32_t taskIDResult = taskID; ret = hi_mpi_vpc_get_process_result(chnId, taskIDResult, -1); // 5.6 如果运行模式为ACL_HOST,且Host上需要展示VPC输出的图片数据,则需要申请Host内存,通过aclrtMemcpy接口将Device的输出图片数据传输到Host;如果Host上不需要展示VPC输出的图片数据,则VPC的输出图片数据可以直接作为模型推理的输入 vpc_jpege_save(cropRegionInfo[0].dest_pic_info, "output.jpg"); // 5.7 释放输入、输出内存 ret = hi_mpi_dvpp_free(inputPic.picture_address); inputPic.picture_address = nullptr; for (uint32_t i = 0; i < vec_regions.size(); i++) { hi_mpi_dvpp_free(vec_regions[i].dest_pic_info.picture_address); vec_regions[i].dest_pic_info.picture_address = nullptr; } // 6.销毁通道 ret = hi_mpi_vpc_destroy_chn(chnId); // 7. 媒体数据处理系统去初始化 ret = hi_mpi_sys_exit(); // 8. 释放运行管理资源(依次释放Context、Device) aclRet = aclrtDestroyContext(g_context); aclRet = aclrtResetDevice(0); return 0; } int32_t dvpp_jpege_save(char* pcData , uint32_t dataLen, string out_file_name) { FILE* fd = nullptr; fd = fopen(out_file_name.c_str(), "wb"); if (fd == nullptr) { printf("open output file err\n"); return HI_FAILURE; } fwrite(pcData, dataLen, 1, fd); fflush(fd); fclose(fd); return HI_SUCCESS; } void dvpp_jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name){ aclError aclRet; // 2.运行管理资源申请(依次申请Device、Context、Stream) aclrtContext context_; aclrtStream stream_; aclrtSetDevice(0); aclrtCreateContext(&context_, 0); aclrtCreateStream(&stream_); // 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 acldvppChannelDesc *dvppChannelDesc_ = acldvppCreateChannelDesc(); // 4.创建图片数据处理的通道 aclRet = acldvppCreateChannel(dvppChannelDesc_); // 7. 创建图片编码配置数据,设置编码质量 // 编码质量范围[0, 100],其中level 0编码质量与level 100差不多,而在[1, 100]内数值越小输出图片质量越差。 acldvppJpegeConfig *jpegeConfig_ = acldvppCreateJpegeConfig(); acldvppSetJpegeConfigLevel(jpegeConfig_, 100); // 8. 申请输出内存,申请Device内存encodeOutBufferDev_,存放编码后的输出数据 uint32_t outBufferSize= 0; aclRet = acldvppJpegPredictEncSize(encodeInputDesc_, jpegeConfig_, &outBufferSize); void *encodeOutBufferDev_ = nullptr; aclRet = acldvppMalloc(&encodeOutBufferDev_, outBufferSize); // 9. 执行异步编码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 aclRet = acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_, &outBufferSize, jpegeConfig_, stream_); aclRet = aclrtSynchronizeStream(stream_); // 该模式下,由于处理结果在Device侧,因此需要调用内存复制接口传输结果数据后,再释放Device侧内存 // 申请Host内存outputHostBuffer void* outputHostBuffer = malloc(outBufferSize); // 通过aclrtMemcpy接口将Device的处理结果数据传输到Host aclRet = aclrtMemcpy(outputHostBuffer, outBufferSize, encodeOutBufferDev_, outBufferSize, ACL_MEMCPY_DEVICE_TO_HOST); // 释放掉输入输出的device内存 (void)acldvppFree(encodeOutBufferDev_); // 数据使用完成后,释放内存 dvpp_jpege_save((char*)outputHostBuffer, outBufferSize, out_file_name); free(outputHostBuffer); acldvppDestroyChannel(dvppChannelDesc_); (void)acldvppDestroyChannelDesc(dvppChannelDesc_); dvppChannelDesc_ = nullptr; // 11. 释放运行管理资源(依次释放Stream、Context、Device) aclrtDestroyStream(stream_); aclrtDestroyContext(context_); aclrtResetDevice(0); } void dvpp_crop(acldvppPicDesc *input_pic_desc){ aclError aclRet; // 1.AscendCL初始化 aclRet = aclInit(nullptr); if(aclRet != ACL_ERROR_NONE){ printf("aclInit failed ! \n"); } int ret = ACL_ERROR_NONE; // 2.运行管理资源申请(依次申请Device、Context、Stream) aclrtContext context_; aclrtStream stream_; ret = aclrtSetDevice(0); ret = aclrtCreateContext(&context_, 0); ret = aclrtCreateStream(&stream_); // 3. 创建缩放配置数据,并指定抠图区域的位置 // resizeConfig_是acldvppResizeConfig类型 acldvppResizeConfig *resizeConfig_ = acldvppCreateResizeConfig(); aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0); if(aclRet != ACL_ERROR_NONE){ printf("acldvppSetResizeConfigInterpolation failed ! \n"); } int cropInBufferSize = 1920 * 1080 * 3 / 2; char cropInHostBuffer[1920 * 1080 * 3 / 2]; for(int i=0; i< 1920 * 1080 * 3 / 2; i++){ cropInHostBuffer[i] = i % 255; } void *cropInDevBuffer_ = nullptr; ret = acldvppMalloc(&cropInDevBuffer_, cropInBufferSize); ret = aclrtMemcpy(cropInDevBuffer_, cropInBufferSize, cropInHostBuffer, cropInBufferSize, ACL_MEMCPY_HOST_TO_DEVICE); acldvppPicDesc *cropInputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(cropInputDesc_, cropInDevBuffer_); acldvppSetPicDescFormat(cropInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropInputDesc_, 1920); acldvppSetPicDescHeight(cropInputDesc_, 1080); acldvppSetPicDescWidthStride(cropInputDesc_, 1920); acldvppSetPicDescHeightStride(cropInputDesc_, 1080); acldvppSetPicDescSize(cropInputDesc_, cropInBufferSize); dvpp_jpeg_encode(cropInputDesc_, "input.jpg"); // cropArea_是acldvppRoiConfig类型 acldvppRoiConfig *cropArea_ = acldvppCreateRoiConfig(550, 749, 480, 679); // 4. 创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 acldvppChannelDesc *dvppChannelDesc_ = acldvppCreateChannelDesc(); // 5. 创建图片数据处理的通道。 ret = acldvppCreateChannel(dvppChannelDesc_); uint32_t OutputWidth_ = 749 - 550; uint32_t OutputHeight_ = 679 - 480; // 7. 申请Device输出内存cropOutBufferDev_,内存大小cropOutBufferSize_根据计算公式得出 // outputPicWidth、outputPicHeight分别表示图片的对齐后宽、对齐后高,此处以YUV420SP格式的图片为例 uint32_t cropOutBufferSize_ = OutputWidth_ * OutputHeight_ * 3 / 2; void *cropOutBufferDev_ = nullptr; ret = acldvppMalloc(&cropOutBufferDev_, cropOutBufferSize_); // 9. 创建输出图片的描述信息,并设置各属性值,cropOutputDesc_是acldvppPicDesc类型 // 如果抠图的输出图片作为模型推理的输入,则输出图片的宽高要与模型要求的宽高保持一致 acldvppPicDesc *cropOutputDesc_ = acldvppCreatePicDesc(); acldvppSetPicDescData(cropOutputDesc_, cropOutBufferDev_); acldvppSetPicDescFormat(cropOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(cropOutputDesc_, OutputWidth_); acldvppSetPicDescHeight(cropOutputDesc_, OutputHeight_); acldvppSetPicDescWidthStride(cropOutputDesc_, OutputWidth_); acldvppSetPicDescHeightStride(cropOutputDesc_, OutputHeight_); acldvppSetPicDescSize(cropOutputDesc_, cropOutBufferSize_); // 10. 执行异步抠图缩放,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成 ret = acldvppVpcCropResizeAsync(dvppChannelDesc_, cropInputDesc_, cropOutputDesc_, cropArea_, resizeConfig_, stream_); ret = aclrtSynchronizeStream(stream_); if(ret != ACL_ERROR_NONE){ printf("Call aclrtSynchronizeStream failed, ret = %d\n", ret); } // vpc_jpege_save(cropOutputDesc_, "output.jpg"); dvpp_jpeg_encode(cropOutputDesc_, "output.jpg"); // 11. 抠图贴图结束后,释放资源,包括输入/输出图片的描述信息、输入/输出内存、通道描述信息、通道等 acldvppDestroyRoiConfig(cropArea_); acldvppDestroyResizeConfig(resizeConfig_); acldvppDestroyPicDesc(cropOutputDesc_); // 此时运行在device侧,处理结果也在Device侧,可以根据需要操作抠图结果后,释放Device侧内存 (void)acldvppFree(cropOutBufferDev_); acldvppDestroyChannel(dvppChannelDesc_); (void)acldvppDestroyChannelDesc(dvppChannelDesc_); dvppChannelDesc_ = nullptr; // 12. 释放运行管理资源(依次释放Stream、Context、Device) aclrtDestroyStream(stream_); aclrtDestroyContext(context_); aclrtResetDevice(0); } int main(){ dvpp_crop(nullptr); }