main.cpp 11.3 KB
/**
* Copyright 2020 Huawei Technologies Co., Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at

* http://www.apache.org/licenses/LICENSE-2.0

* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.

* File main.cpp
* Description: dvpp sample main func
*/

#include <iostream>
#include <cstdlib>
#include <dirent.h>
#include "main.h"
using namespace std;

/* Run managed resource applications, including Device, Context, and Stream */
Result Initparam(int argc, char *argv[])
{
    DIR *dir;
    if ((dir = opendir("./output")) == NULL)
        system("mkdir ./output");
    // if (argc != 9) {
    //     ERROR_LOG("./crop infile w h outfile outl outt outw outh");
    //     return FAILED;
    // }
    int inw, inh, outl, outt, outw, outh;
    inw = 1920;//atoi(argv[2]);
    inh = 1080;//atoi(argv[3]);
    outl = 0;//atoi(argv[5]);
    outt = 0;//atoi(argv[6]);
    outw = 300;//atoi(argv[7]);
    outh = 300;//atoi(argv[8]);
    inPicDesc={argv[1],inw,inh};
    outPicDesc={"output.jpg", outl, outt, outw, outh};
    return SUCCESS;
}

uint32_t AlignmentHelper(uint32_t origSize, uint32_t alignment)
{
    if (alignment == 0) {
        return 0;
    }
    uint32_t alignmentH = alignment - 1;
    return (origSize + alignmentH) / alignment * alignment;
}

uint32_t SaveDvppOutputData(const char *fileName, const void *devPtr, uint32_t dataSize)
{
    FILE * outFileFp = fopen(fileName, "wb+");
    if (runMode == ACL_HOST) {
        void * hostPtr = nullptr;
        aclrtMallocHost(&hostPtr, dataSize);
        aclrtMemcpy(hostPtr, dataSize, devPtr, dataSize, ACL_MEMCPY_DEVICE_TO_HOST);
        fwrite(hostPtr, sizeof(char), dataSize, outFileFp);
        (void)aclrtFreeHost(hostPtr);
    } else {
        fwrite(devPtr, sizeof(char), dataSize, outFileFp);
    }
    fflush(outFileFp);
    fclose(outFileFp);
    return SUCCESS;
}

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 -1;
    }

    fwrite(pcData, dataLen, 1, fd);
    fflush(fd);

    fclose(fd);
    return ACL_ERROR_NONE;
}

void dvpp_jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name){

    aclError aclRet;

    // 2.运行管理资源申请(依次申请Device、Context、Stream)
    aclrtContext context_;
    aclrtStream stream_;
    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_);
}

char* ReadBinFile(std::string fileName, uint32_t &fileSize)
{
    std::ifstream binFile(fileName, std::ifstream::binary);
    if (binFile.is_open() == false) {
        ERROR_LOG("open file %s failed", fileName.c_str());
        return nullptr;
    }

    binFile.seekg(0, binFile.end);
    uint32_t binFileBufferLen = binFile.tellg();
    if (binFileBufferLen == 0) {
        ERROR_LOG("binfile is empty, filename is %s", fileName.c_str());
        binFile.close();
        return nullptr;
    }

    binFile.seekg(0, binFile.beg);

    char* binFileBufferData = new(std::nothrow) char[binFileBufferLen];
    if (binFileBufferData == nullptr) {
        ERROR_LOG("malloc binFileBufferData failed");
        binFile.close();
        return nullptr;
    }
    binFile.read(binFileBufferData, binFileBufferLen);
    binFile.close();
    fileSize = binFileBufferLen;
    
    return binFileBufferData;
}

void DestroyResource()
{
    aclError ret;
    if (context_ != nullptr) {
        if (stream_ != nullptr) {
            ret = aclrtDestroyStream(stream_);
            if (ret != ACL_SUCCESS) {
                ERROR_LOG("destroy stream failed");
            }
            stream_ = nullptr;
        }
        INFO_LOG("end to destroy stream");

        ret = aclrtDestroyContext(context_);
        if (ret != ACL_SUCCESS) {
            ERROR_LOG("destroy context failed");
        }
        context_ = nullptr;
    }

    INFO_LOG("end to reset device is %d", deviceId_);

    ret = aclFinalize();
    if (ret != ACL_SUCCESS) {
        ERROR_LOG("finalize acl failed");
    }
    INFO_LOG("end to finalize acl");
}


int main(int argc, char *argv[])
{
    /* 1.ACL initialization  */
    aclInit(nullptr);

    /* 2.Run the management resource application, including Device, Context, Stream */
    aclrtCreateContext(&context_, deviceId_);
    aclrtCreateStream(&stream_);
    aclrtGetRunMode(&runMode);

    /* 3.Initialization parameters: width and height of the original image, crop width and height. 
     * Initialize folder: Output folder */
    Initparam(argc, argv);
    const int orimodelInputWidth = outPicDesc.width; // cur model shape is 224 * 224
    const int orimodelInputHeight = outPicDesc.height;
    const int modelInputLeft = outPicDesc.left; // cur model shape is 224 * 224
    const int modelInputTop = outPicDesc.top;

    /* 4. Channel description information when creating image data processing channels, 
     * dvppChannelDesc_ is acldvppChannelDesc type */
    dvppChannelDesc_ = acldvppCreateChannelDesc();

    /* 5. Create the image data processing channel. */
    acldvppCreateChannel(dvppChannelDesc_);

    // GetPicDevBuffer4JpegD
    int modelInputWidth = (orimodelInputWidth + 15) / 16 * 16;
    int modelInputHeight = (orimodelInputHeight + 1) / 2 * 2;
    // uint32_t inputBuffSize = 0;
    // char* inputBuff = ReadBinFile(inPicDesc.picName, inputBuffSize);

    int inputBuffSize = 1920 * 1080 * 3 / 2;
    char inputBuff[1920 * 1080 * 3 / 2];
    for(int i=0; i< inputBuffSize; i++){
        inputBuff[i] = i % 255;
    }

    void *inBufferDev = nullptr;
    inBufferSize = inputBuffSize;
    acldvppMalloc(&inBufferDev, inBufferSize);
    if (runMode == ACL_HOST) {
        aclrtMemcpy(inBufferDev, inBufferSize, inputBuff, inputBuffSize, ACL_MEMCPY_HOST_TO_DEVICE);
    } else {
        aclrtMemcpy(inBufferDev, inBufferSize, inputBuff, inputBuffSize, ACL_MEMCPY_DEVICE_TO_DEVICE);
    }
    // delete[] inputBuff;
    
    uint32_t oddNum = 1;
    uint32_t cropSizeWidth = modelInputWidth;
    uint32_t cropSizeHeight = modelInputHeight;
    uint32_t cropLeftOffset = modelInputLeft;  // must even
    uint32_t cropRightOffset = cropLeftOffset + cropSizeWidth - oddNum;  // must odd
    uint32_t cropTopOffset = modelInputTop;  // must even
    uint32_t cropBottomOffset = cropTopOffset + cropSizeHeight - oddNum;  // must odd
    acldvppRoiConfig  *cropArea_ = acldvppCreateRoiConfig(cropLeftOffset, cropRightOffset,
        cropTopOffset, cropBottomOffset);

    /* processdecode */
    inputWidth = inPicDesc.width;
    inputHeight = inPicDesc.height;
    uint32_t widthAlignment = 16;
    uint32_t heightAlignment = 2;
    uint32_t sizeAlignment = 3;
    uint32_t sizeNum = 2;
    uint32_t decodeOutWidthStride = AlignmentHelper(inputWidth, widthAlignment);
    uint32_t decodeOutHeightStride = AlignmentHelper(inputHeight, heightAlignment);
    uint32_t decodeOutBufferSize = decodeOutWidthStride * decodeOutHeightStride * sizeAlignment / sizeNum;
    acldvppPicDesc *vpcInputDesc_ = acldvppCreatePicDesc();
    void *vpcOutBufferDev_ = nullptr;
    acldvppSetPicDescData(vpcInputDesc_, reinterpret_cast<char *>(inBufferDev));
    acldvppSetPicDescFormat(vpcInputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(vpcInputDesc_, inputWidth);
    acldvppSetPicDescHeight(vpcInputDesc_, inputHeight);
    acldvppSetPicDescWidthStride(vpcInputDesc_, decodeOutWidthStride);
    acldvppSetPicDescHeightStride(vpcInputDesc_, decodeOutHeightStride);
    acldvppSetPicDescSize(vpcInputDesc_, decodeOutBufferSize);

    uint32_t vpcOutBufferSize_ = modelInputWidth * modelInputHeight * sizeAlignment / sizeNum;
    acldvppMalloc(&vpcOutBufferDev_, vpcOutBufferSize_);
    acldvppPicDesc *vpcOutputDesc_ = acldvppCreatePicDesc();
    acldvppSetPicDescData(vpcOutputDesc_, vpcOutBufferDev_);
    acldvppSetPicDescFormat(vpcOutputDesc_, PIXEL_FORMAT_YUV_SEMIPLANAR_420);
    acldvppSetPicDescWidth(vpcOutputDesc_, modelInputWidth);
    acldvppSetPicDescHeight(vpcOutputDesc_, modelInputHeight);
    acldvppSetPicDescWidthStride(vpcOutputDesc_, modelInputWidth);
    acldvppSetPicDescHeightStride(vpcOutputDesc_, modelInputHeight);
    acldvppSetPicDescSize(vpcOutputDesc_, vpcOutBufferSize_);

    int ret = acldvppVpcCropAsync(dvppChannelDesc_, vpcInputDesc_, vpcOutputDesc_, cropArea_, stream_);

    ret = aclrtSynchronizeStream(stream_);

    dvpp_jpeg_encode(vpcOutputDesc_, "output.jpg");

    /* DestroycropResource */
    (void)acldvppDestroyRoiConfig(cropArea_);
    cropArea_ = nullptr;
    (void)acldvppDestroyPicDesc(vpcInputDesc_);
    vpcInputDesc_ = nullptr;
    (void)acldvppDestroyPicDesc(vpcOutputDesc_);
    vpcOutputDesc_ = nullptr;

    SaveDvppOutputData(outPicDesc.picName.c_str(), vpcOutBufferDev_, vpcOutBufferSize_);
    if (vpcOutBufferDev_ != nullptr) {
        (void)acldvppFree(vpcOutBufferDev_);
	    vpcOutBufferDev_ = nullptr;
    }
    DestroyResource();
    return SUCCESS;
}