JpegUtil.cpp 4.22 KB
#include <cstdio>
#include <cstdlib>
#include <memory>
#include "JpegUtil.h"
#include "../common/logger.hpp"

using namespace std;

#define ACL_CHECK_AND_ABORT(ret, message)    \
            if(ret != 0) {LOG_ERROR("{}", message); std::abort();}

int JpegUtil::jpeg_init(int32_t devId){
    deviceId_ = devId;

    ACL_CHECK_AND_ABORT(aclrtCreateContext(&context_, deviceId_), "aclrtCreateContext failed!");

    // channel  准备
    dvppChannelDesc_ = acldvppCreateChannelDesc();
    if (dvppChannelDesc_ == nullptr)
    {
        LOG_ERROR("acldvppCreateChannelDesc failed!");
        std::abort();
    }
    
    ACL_CHECK_AND_ABORT(acldvppCreateChannel(dvppChannelDesc_), "acldvppCreateChannel failed!");

    // 创建图片编码配置数据,设置编码质量
    // 编码质量范围[0, 100],其中level 0编码质量与level 100差不多,而在[1, 100]内数值越小输出图片质量越差。
    jpegeConfig_ = acldvppCreateJpegeConfig();
    if (jpegeConfig_ == nullptr)
    {
        LOG_ERROR("acldvppCreateJpegeConfig failed!");
        std::abort();
    }
    ACL_CHECK_AND_ABORT(acldvppSetJpegeConfigLevel(jpegeConfig_, 100), "acldvppSetJpegeConfigLevel failed!");
}

void JpegUtil::jpeg_release(){

    ACL_CHECK_AND_ABORT(aclrtSetCurrentContext(context_), "aclrtSetCurrentContext failed!");

    ACL_CHECK_AND_ABORT(acldvppDestroyChannel(dvppChannelDesc_), "acldvppDestroyChannel failed!");
    ACL_CHECK_AND_ABORT(acldvppDestroyChannelDesc(dvppChannelDesc_), "acldvppDestroyChannelDesc failed!");

    dvppChannelDesc_ = nullptr;

    acldvppDestroyJpegeConfig(jpegeConfig_);

    if (context_ != nullptr) {
        ACL_CHECK_AND_ABORT(aclrtDestroyContext(context_), "aclrtDestroyContext failed!");
        context_ = nullptr;
    }
}

int32_t JpegUtil::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) {
        LOG_ERROR("open output file error");
        return 1;
    }

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

    fclose(fd);
    return 0;
}

bool JpegUtil::jpeg_encode(acldvppPicDesc *encodeInputDesc_, string out_file_name) {

    ACL_CHECK_AND_ABORT(aclrtSetCurrentContext(context_), "aclrtSetCurrentContext failed!");

    // 8. 申请输出内存,申请Device内存encodeOutBufferDev_,存放编码后的输出数据
    uint32_t outBufferSize= 0;
    ACL_CHECK_AND_ABORT(acldvppJpegPredictEncSize(encodeInputDesc_, jpegeConfig_, &outBufferSize), "acldvppJpegPredictEncSize failed!");
    int ret ;

    void *encodeOutBufferDev_ = nullptr;
    ACL_CHECK_AND_ABORT(acldvppMalloc(&encodeOutBufferDev_, outBufferSize), "acldvppJpegPredictEncSize failed!");

    bool bRet = false;
    aclrtStream stream_{nullptr};
    aclrtCreateStream(&stream_);
    do {
        // 9. 执行异步编码,再调用aclrtSynchronizeStream接口阻塞程序运行,直到指定Stream中的所有任务都完成
        ACL_CHECK_AND_ABORT(acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_, encodeOutBufferDev_, &outBufferSize, jpegeConfig_, stream_), "acldvppJpegEncodeAsync failed!");
        ACL_CHECK_AND_ABORT(aclrtSynchronizeStream(stream_), "aclrtSynchronizeStream failed!");

        // 申请Host内存outputHostBuffer 
        void* outputHostBuffer = malloc(outBufferSize);
        if(outputHostBuffer == nullptr) {
            LOG_ERROR("malloc failed!");
            break;
        }

        // 通过aclrtMemcpy接口将Device的处理结果数据传输到Host
        ACL_CHECK_AND_ABORT(aclrtMemcpy(outputHostBuffer, outBufferSize, encodeOutBufferDev_, outBufferSize, ACL_MEMCPY_DEVICE_TO_HOST), "aclrtMemcpy failed!");

        // 数据使用完成后,释放内存
        ret = jpege_save((char*)outputHostBuffer, outBufferSize, out_file_name);
        free(outputHostBuffer);
        outputHostBuffer = nullptr;
        if(ret != 0) {
            LOG_ERROR("jpege_save failed!");
            break;
        }

        bRet = true;
    } while (0);

    if (stream_ != nullptr) {
        ACL_CHECK_AND_ABORT(aclrtDestroyStream(stream_), "aclrtDestroyStream failed!");
        stream_ = nullptr;
    }
    
    // 释放掉输入输出的device内存
    (void)acldvppFree(encodeOutBufferDev_);
    encodeOutBufferDev_ = nullptr;
    return bRet;
}