Updated on 2022-03-13 GMT+08:00

Implementing the JPEGE Function

  • The memory size can be obtained by calling DvppGetOutParameter. The output memory can be specified and freed by the user. The calling example is as follows:
    void TEST_JPEGE_CUSTOM_MEMORY()
    {
        sJpegeIn  inData;
        sJpegeOut outData;
    
        inData.width         = g_width;
        inData.height        = g_high;
        inData.heightAligned = g_high; // no need to align
        inData.format        = (eEncodeFormat)g_format;
        inData.level         = 100;
    
        inData.stride  = ALIGN_UP(inData.width * 2, 16);
        inData.bufSize = inData.stride * inData.heightAligned;
        if (JPGENC_FORMAT_YUV420 == (inData.format & JPGENC_FORMAT_BIT)) {
            inData.stride  = ALIGN_UP(inData.width, 16);
            inData.bufSize = inData.stride * inData.heightAligned * 3 / 2;
        }
    
        void* addrOrig = HIAI_DVPP_DMalloc(inData.bufSize);
        if (addrOrig == nullptr) {
            HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "can not alloc input buffer");
            return;
        }
        inData.buf = reinterpret_cast<unsigned char*>(addrOrig);
    
        unsigned char* tmpAddr = nullptr;
    
        do {
            // load img file
            FILE* fpIn = fopen(g_inFileName, "rb");
            if (nullptr == fpIn) {
                HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "can not open input file");
                break;
            }
            // only copy valid image data, other part is pending
            if (JPGENC_FORMAT_YUV420 == (inData.format & JPGENC_FORMAT_BIT)) {
                // for yuv420semi-planar format, like nv12 / nv21
                HIAI_ENGINE_LOG("input yuv 420 data");
                // for y data
                for (uint32_t j = 0; j < inData.height; j++) {
                    fread(inData.buf + j * inData.stride, 1, inData.width, fpIn);
                }
                // for uv data
                for (uint32_t j = inData.heightAligned; j < inData.heightAligned + inData.height / 2; j++) {
                    fread(inData.buf + j * inData.stride, 1, inData.width, fpIn);
                }
            } else {
                // for yuv422packed format, like uyvy / vyuy / yuyv / yvyu
                HIAI_ENGINE_LOG("input yuv 422 data");
                for (uint32_t j = 0; j < inData.height; j++) {
                    fread(inData.buf + j * inData.stride, 1, inData.width * 2, fpIn);
                }
            }
            fclose(fpIn);
            fpIn = nullptr;
    
            int32_t ret = DvppGetOutParameter((void*)(&inData), (void*)(&outData), GET_JPEGE_OUT_PARAMETER);
            if (ret != 0) {
                HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "call DvppGetOutParameter process failed");
                break;
            }
            // The obtained jpgSize is an estimated value. The actual data length may be less than the estimated value.
            // After the DvppCtl API is called, the jpgSize value is the actual value after encoding.
            HIAI_ENGINE_LOG("outdata size is %d", outData.jpgSize);
            tmpAddr = (unsigned char*)HIAI_DVPP_DMalloc(outData.jpgSize);
            if (tmpAddr == nullptr) {
                HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "can not alloc output buffer");
                break;
            }
            uint32_t size = outData.jpgSize;
    
            // call jpege process
            dvppapi_ctl_msg dvppApiCtlMsg;
            dvppApiCtlMsg.in = (void *)&inData;
            dvppApiCtlMsg.in_size = sizeof(inData);
            dvppApiCtlMsg.out = (void *)&outData;
            dvppApiCtlMsg.out_size = sizeof(outData);
    
            if(!IsHandleJpegeCtlSucc(dvppApiCtlMsg, tmpAddr, size, &outData)) {
                break;
            }
        } while (0); // for resource inData.buf
        if (addrOrig != nullptr) {
            HIAI_DVPP_DFree(addrOrig);
            addrOrig = nullptr;
        }
        if (tmpAddr != nullptr) {// Note: tmpAddr is used to free the buffer, because address offset occurs after outData.jpgData is processed by the JPEGE.
            HIAI_DVPP_DFree(tmpAddr);
            tmpAddr = nullptr;
        }
    }
    
  • If the output buffer is not specified by the user, DVPP allocates the buffer internally. The cbFree() callback function should be called to free the buffer. The calling example is as follows:
    void JpegeProcess()
    {
        sJpegeIn  inData;
        sJpegeOut outData;
    
        inData.width         = g_width;
        inData.height        = g_high;
        inData.heightAligned = g_high; // no need to align
        inData.format        = (eEncodeFormat)g_format;
        inData.level         = 100;
    
        if (JPGENC_FORMAT_YUV420 == (inData.format & JPGENC_FORMAT_BIT)) {
            inData.stride  = ALIGN_UP(inData.width, 16);
            inData.bufSize = inData.stride * inData.heightAligned * 3 / 2;
        } else {
            inData.stride  = ALIGN_UP(inData.width * 2, 16);
            inData.bufSize = inData.stride * inData.heightAligned;
        }
    
        void* addrOrig = HIAI_DVPP_DMalloc(inData.bufSize);
    
        if (addrOrig == nullptr) {
            HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "can not alloc input buffer");
            return;
        }
        inData.buf = reinterpret_cast<unsigned char*>(addrOrig);
    
        do {
            // load img file
            FILE* fpIn = fopen(g_inFileName, "rb");
            if (fpIn == nullptr) {
                HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "can not open input file");
                break;
            }
            // only copy valid image data, other part is pending
            if (JPGENC_FORMAT_YUV420 == (inData.format & JPGENC_FORMAT_BIT)) {
                // for yuv420semi-planar format, like nv12 / nv21
                HIAI_ENGINE_LOG("input yuv 420 data");
                // for y data
                for (uint32_t j = 0; j < inData.height; j++) {
                    fread(inData.buf + j * inData.stride, 1, inData.width, fpIn);
                }
                // for uv data
                for (uint32_t j = inData.heightAligned; j < inData.heightAligned + inData.height / 2; j++) {
                    fread(inData.buf + j * inData.stride, 1, inData.width, fpIn);
                }
            } else {
                // for yuv422packed format, like uyvy / vyuy / yuyv / yvyu
                HIAI_ENGINE_LOG("input yuv 422 data");
                for (uint32_t j = 0; j < inData.height; j++) {
                    fread(inData.buf + j * inData.stride, 1, inData.width * 2, fpIn );
                }
    
            }
            fclose(fpIn);
            fpIn = nullptr;
    
            // call jpege process
            dvppapi_ctl_msg dvppApiCtlMsg;
            dvppApiCtlMsg.in = (void*)&inData;
            dvppApiCtlMsg.in_size = sizeof(inData);
            dvppApiCtlMsg.out = (void*)&outData;
            dvppApiCtlMsg.out_size = sizeof(outData);
    
            IDVPPAPI *pidvppapi = nullptr;
            CreateDvppApi(pidvppapi);
            if (pidvppapi == nullptr) {
                HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "can not open dvppapi engine");
                break;
            }
    
            JpegeProcessBranch(pidvppapi, dvppApiCtlMsg, outData);
    
            DestroyDvppApi(pidvppapi);
    
        } while (0); // for resource inData.buf
        if (addrOrig != nullptr) {
            HIAI_DVPP_DFree(addrOrig);
            addrOrig = nullptr;
        }
    }
    
    /*
     * only handle jpege process.
     */
    void JpegeProcessBranch(IDVPPAPI*& pidvppapi, dvppapi_ctl_msg& dvppApiCtlMsg, sJpegeOut& outData)
    {
        do {
            for (int i = 0;i < g_loop; i++) { // same picture loop test
                if (DvppCtl(pidvppapi, DVPP_CTL_JPEGE_PROC, &dvppApiCtlMsg)) {
                    HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "call jpeg encoder fail");
                    break;
                }
                if (i < g_loop - 1) {
                    outData.cbFree();
                    outData.jpgData = nullptr;
                }
            }
            stringstream outFile;
            outFile << g_outFileName << "_t" << std::this_thread::get_id() << ".jpg";
    
            FILE* fpOut = fopen(outFile.str().c_str(), "wb");
            if (fpOut != nullptr) {
                fwrite(outData.jpgData, 1, outData.jpgSize, fpOut);
                fflush(fpOut);
                fclose(fpOut);
                fpOut = nullptr;
            } else {
                HIAI_ENGINE_LOG(HIAI_JPEGE_CTL_ERROR, "call not save result file %s ", outFile.str().c_str());
            }
    
            outData.cbFree();
            outData.jpgData = nullptr;
            HIAI_ENGINE_LOG(HIAI_OK, "jpeg encode process completed");
        } while (0); // for resource pddvppapi
    }