/** * @file dvpp_process.cpp * * Copyright (C) 2020. Huawei Technologies Co., Ltd. All rights reserved. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include "crop_process.h" #include #include #include #include #include #include "utils.h" #include "acl/acl_base.h" #include "acl/acl_rt.h" #include "acl/acl_op.h" #include "acl/acl_mdl.h" #include "acl/ops/acl_dvpp.h" #include "acl/ops/acl_cblas.h" #include "../decoder/interface/DeviceMemory.hpp" using namespace std; namespace { uint32_t AlignSize(uint32_t origSize, uint32_t alignment) { if (alignment == 0) { return 0; } uint32_t alignmentH = alignment - 1; return (origSize + alignmentH) / alignment * alignment; } } DvppCropProcess::DvppCropProcess() : dvppChannelDesc_(nullptr), inputBatchPicDesc_(nullptr), outputBatchPicDesc_(nullptr), inputBatchSize_(0), outputBatchSize_(0) { } DvppCropProcess::~DvppCropProcess() { DestroyBatchCropResource(); } Result DvppCropProcess::InitProcess() { // create vpc channel description dvppChannelDesc_ = acldvppCreateChannelDesc(); if (dvppChannelDesc_ == nullptr) { ERROR_LOG("acldvppCreateChannelDesc failed"); return FAILED; } // create vpc channel aclError aclRet = acldvppCreateChannel(dvppChannelDesc_); if (aclRet != ACL_SUCCESS) { ERROR_LOG("acldvppCreateChannel failed, errorCode = %d", static_cast(aclRet)); return FAILED; } // create dvpp resize config resizeConfig_ = acldvppCreateResizeConfig(); if (resizeConfig_ == nullptr) { ERROR_LOG("acldvppCreateResizeConfig failed"); return FAILED; } INFO_LOG("dvpp init resource success"); return SUCCESS; } Result DvppCropProcess::InitBatchCropInputDesc(DeviceMemory *devMem) { inputBatchPicDesc_ = acldvppCreateBatchPicDesc(inputBatchSize_); if (inputBatchPicDesc_ == nullptr) { ERROR_LOG("InitBatchCropInputDesc inBatchPicDesc failed"); return FAILED; } acldvppBatchPicDesc *inputBatchPicDesc_ = acldvppCreateBatchPicDesc(1); acldvppPicDesc *vpcInputDesc_ = acldvppGetPicDesc(inputBatchPicDesc_, 0); acldvppSetPicDescData(vpcInputDesc_, devMem->getMem()); acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420); acldvppSetPicDescWidth(vpcInputDesc_, devMem->getWidth()); acldvppSetPicDescHeight(vpcInputDesc_, devMem->getHeight()); acldvppSetPicDescWidthStride(vpcInputDesc_, devMem->getWidthStride()); acldvppSetPicDescHeightStride(vpcInputDesc_, devMem->getHeightStride()); acldvppSetPicDescSize(vpcInputDesc_, devMem->getSize()); // if (inputBatchSize_ > batchInput_.size()) { // inputBatchSize_ = batchInput_.size(); // } // uint32_t inputWidth = devMem->getWidth(); // for (uint32_t i = 0; i < inputBatchSize_; i++) { // vecInPtr_.push_back(inputBufferDev); // acldvppPicDesc *vpcInputDesc = acldvppGetPicDesc(inputBatchPicDesc_, i); // (void)acldvppSetPicDescData(vpcInputDesc, devMem->getMem()); // (void)acldvppSetPicDescFormat(vpcInputDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420); // (void)acldvppSetPicDescWidth(vpcInputDesc, batchInput_[i].inputWidth); // (void)acldvppSetPicDescHeight(vpcInputDesc, batchInput_[i].inputHeight); // (void)acldvppSetPicDescWidthStride(vpcInputDesc, inputWidthStride_); // (void)acldvppSetPicDescHeightStride(vpcInputDesc, inputHeightStride_); // (void)acldvppSetPicDescSize(vpcInputDesc, inputBufferSize); // INFO_LOG("set inputDesc success."); // } return SUCCESS; } Result DvppCropProcess::InitBatchCropOutputDesc(vector objs) { const uint32_t widthAlignment = 16; const uint32_t heightAlignment = 16; const uint32_t sizeAlignment = 3; const uint32_t sizeNum = 2; outputBatchPicDesc_ = acldvppCreateBatchPicDesc(outputBatchSize_); if (outputBatchPicDesc_ == nullptr) { ERROR_LOG("acldvppCreatePicDesc outBatchPicDesc failed"); return FAILED; } acldvppPicDesc *vpcOutputDesc = nullptr; for (uint32_t i = 0; i < outputBatchSize_; i++) { video_object_info obj = objs[i]; int outputWidth_ = obj.right - obj.left; int outputHeight_ = obj.bottom - obj.top; int modelInputLeft = obj.left; int modelInputTop = obj.top; uint32_t outputWidthStride = AlignSize(outputWidth_, widthAlignment); uint32_t outputHeightStride = AlignSize(outputHeight_, heightAlignment); uint32_t outputBufferSize = outputWidthStride * outputHeightStride * sizeAlignment / sizeNum; void *vpcBatchOutputBufferDev = nullptr; auto ret = acldvppMalloc(&vpcBatchOutputBufferDev, outputBufferSize); if (ret != ACL_SUCCESS) { ERROR_LOG("acldvppMalloc failed, size = %u, errorCode = %d.", outputBufferSize, static_cast(ret)); return FAILED; } vecOutPtr_.push_back(vpcBatchOutputBufferDev); vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); (void)acldvppSetPicDescData(vpcOutputDesc, vpcBatchOutputBufferDev); (void)acldvppSetPicDescFormat(vpcOutputDesc, PIXEL_FORMAT_YUV_SEMIPLANAR_420); (void)acldvppSetPicDescWidth(vpcOutputDesc, outputWidth_); (void)acldvppSetPicDescHeight(vpcOutputDesc, outputHeight_); (void)acldvppSetPicDescWidthStride(vpcOutputDesc, outputWidthStride); (void)acldvppSetPicDescHeightStride(vpcOutputDesc, outputHeightStride); (void)acldvppSetPicDescSize(vpcOutputDesc, outputBufferSize); } return SUCCESS; } static Result 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 FAILED; } fwrite(pcData, dataLen, 1, fd); fflush(fd); fclose(fd); return SUCCESS; } static void dvpp_jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name){ // 2.运行管理资源申请(依次申请Device、Context、Stream) aclrtContext context_; aclrtStream stream_; aclrtSetDevice(0); aclrtCreateContext(&context_, 0); aclrtCreateStream(&stream_); // 3.创建图片数据处理通道时的通道描述信息,dvppChannelDesc_是acldvppChannelDesc类型 acldvppChannelDesc *dvppChannelDesc_ = acldvppCreateChannelDesc(); // 4.创建图片数据处理的通道 aclError 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; int ret = acldvppJpegPredictEncSize(encodeInputDesc_, jpegeConfig_, &outBufferSize); void *encodeOutBufferDev_ = nullptr; ret = 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); } Result DvppCropProcess::ProcessBatchCrop(DeviceMemory *devMem, vector objs) { inputBatchSize_ = 1; outputBatchSize_ = objs.size(); INFO_LOG("ProcessBatchCrop start."); const uint32_t oddNum = 1; std::unique_ptr cropArea(new(std::nothrow) acldvppRoiConfig *[outputBatchSize_ * sizeof(acldvppRoiConfig *)]); for (uint32_t i = 0; i < outputBatchSize_; i++) { video_object_info obj = objs[i]; cropArea[i] = acldvppCreateRoiConfig(obj.left, obj.right, obj.top, obj.bottom); if (cropArea[i] == nullptr) { ERROR_LOG("acldvppCreateRoiConfig cropArea_ failed"); return FAILED; } } Result ret = InitBatchCropInputDesc(devMem); if (ret != SUCCESS) { ERROR_LOG("InitBatchCropInputDesc failed"); return FAILED; } ret = InitBatchCropOutputDesc(objs); if (ret != SUCCESS) { ERROR_LOG("InitBatchCropOutputDesc failed"); return FAILED; } // calculate total number of crop image uint32_t totalNum = 0; std::unique_ptr roiNums(new (std::nothrow) uint32_t[inputBatchSize_]); if (roiNums != nullptr){ for (int i = 0; i < inputBatchSize_; i++) { // crop number of images from one source image is outputBatchSize_ / inputBatchSize_ roiNums[i] = outputBatchSize_ / inputBatchSize_; totalNum += roiNums[i]; } } // crop number of images from last source image is // outputBatchSize_ / inputBatchSize_ + outputBatchSize_ % inputBatchSize_ if (outputBatchSize_ % inputBatchSize_ != 0) { roiNums[inputBatchSize_ - 1] = (outputBatchSize_ - totalNum) + roiNums[inputBatchSize_ - 1]; } aclError aclRet = acldvppSetResizeConfigInterpolation(resizeConfig_, 0); aclRet = acldvppVpcBatchCropResizeAsync(dvppChannelDesc_, inputBatchPicDesc_, roiNums.get(), inputBatchSize_, outputBatchPicDesc_, cropArea.get(), resizeConfig_, stream_); if (aclRet != ACL_SUCCESS) { ERROR_LOG("acldvppVpcBatchCropAsync failed, errorCode = %d", static_cast(aclRet)); return FAILED; } aclRet = aclrtSynchronizeStream(stream_); if (aclRet != ACL_SUCCESS) { ERROR_LOG("crop aclrtSynchronizeStream failed, errorCode = %d", static_cast(aclRet)); return FAILED; } for (uint32_t i = 0; i < outputBatchSize_; i++) { acldvppPicDesc *vpcOutputDesc = acldvppGetPicDesc(outputBatchPicDesc_, i); string file_name = "output"; file_name = file_name + to_string(i) + ".jpg"; dvpp_jpeg_encode(vpcOutputDesc, file_name); } for (uint32_t i = 0; i < outputBatchSize_; i++) { if (cropArea[i] != nullptr) { (void)acldvppDestroyRoiConfig(cropArea[i]); cropArea[i] = nullptr; } } INFO_LOG("ProcessBatchCrop success."); return SUCCESS; } void DvppCropProcess::DestroyBatchCropResource() { INFO_LOG("DestroyBatchCropResource start."); if (inputBatchPicDesc_ != nullptr) { (void)acldvppDestroyBatchPicDesc(inputBatchPicDesc_); inputBatchPicDesc_ = nullptr; } for (auto ptr : vecOutPtr_) { if (ptr != nullptr) { (void)acldvppFree(ptr); } } vecOutPtr_.clear(); if (outputBatchPicDesc_ != nullptr) { (void)acldvppDestroyBatchPicDesc(outputBatchPicDesc_); outputBatchPicDesc_ = nullptr; } if (dvppChannelDesc_ != nullptr) { aclError aclRet = acldvppDestroyChannel(dvppChannelDesc_); if (aclRet != ACL_SUCCESS) { ERROR_LOG("acldvppDestroyChannel failed, errorCode = %d", static_cast(aclRet)); } (void)acldvppDestroyChannelDesc(dvppChannelDesc_); dvppChannelDesc_ = nullptr; } if (resizeConfig_ != nullptr) { (void)acldvppDestroyResizeConfig(resizeConfig_); resizeConfig_ = nullptr; } INFO_LOG("DestroyBatchCropResource end."); return; } Result DvppCropProcess::init(int deviceId) { deviceId_ = deviceId; aclError ret; // ret = aclInit(NULL); // if (ret != ACL_SUCCESS) { // ERROR_LOG("acl init failed, errorCode = %d", static_cast(ret)); // return FAILED; // } // INFO_LOG("acl init success"); // set device ret = aclrtSetDevice(deviceId_); if (ret != ACL_SUCCESS) { ERROR_LOG("acl set device %d failed, errorCode = %d", deviceId_, static_cast(ret)); return FAILED; } INFO_LOG("set device %d success", deviceId_); // create context (set current) ret = aclrtCreateContext(&context_, deviceId_); if (ret != ACL_SUCCESS) { ERROR_LOG("acl create context failed, deviceId = %d, errorCode = %d", deviceId_, static_cast(ret)); return FAILED; } INFO_LOG("create context success"); // create stream ret = aclrtCreateStream(&stream_); if (ret != ACL_SUCCESS) { ERROR_LOG("acl create stream failed, deviceId = %d, errorCode = %d", deviceId_, static_cast(ret)); return FAILED; } INFO_LOG("create stream success"); InitProcess(); return SUCCESS; } void DvppCropProcess::DestroyResource() { aclError ret; if (stream_ != nullptr) { ret = aclrtDestroyStream(stream_); if (ret != ACL_SUCCESS) { ERROR_LOG("destroy stream failed, errorCode = %d", static_cast(ret)); } stream_ = nullptr; } INFO_LOG("end to destroy stream"); if (context_ != nullptr) { ret = aclrtDestroyContext(context_); if (ret != ACL_SUCCESS) { ERROR_LOG("destroy context failed, errorCode = %d", static_cast(ret)); } context_ = nullptr; } INFO_LOG("end to destroy context"); ret = aclrtResetDevice(deviceId_); if (ret != ACL_SUCCESS) { ERROR_LOG("reset device %d failed, errorCode = %d", deviceId_, static_cast(ret)); } INFO_LOG("end to reset device %d", deviceId_); ret = aclFinalize(); if (ret != ACL_SUCCESS) { ERROR_LOG("finalize acl failed, errorCode = %d", static_cast(ret)); } INFO_LOG("end to finalize acl"); }