调用示例
实现VPC功能
概念说明
关于抠图、缩放、叠加、上偏移、下偏移、左偏移、右偏移等概念,请参见VPC功能。
示例1:仅原图缩放
关键参数设置如下:
- 抠图区域宽高跟输入图片的真实宽高相同,抠图区域各偏移值的设置如下:
- 左偏移leftOffset=0
- 上偏移upOffset=0
- 右偏移rightOffset - 左偏移leftOffset+1=输入图片真实宽
- 下偏移downOffset - 上偏移upOffset+1=输入图片真实高
- 贴图区域宽高是缩放后图片的宽高,可指定贴图区域的位置,例如:若指定贴图区域的位置在输出图片的左上角,则贴图区域各偏移值的设置如下:
- 左偏移leftOffset=0
- 上偏移upOffset=0
- 右偏移rightOffset - 左偏移leftOffset+1=缩放后图片的宽
- 下偏移downOffset - 上偏移upOffset+1=缩放后图片的高
- 如果是8K的原图缩放,则inputFormat和outputFormat只支持依次设置为INPUT_YUV420_SEMI_PLANNER_UV、OUTPUT_YUV420SP_UV或设置为INPUT_YUV420_SEMI_PLANNER_VU、OUTPUT_YUV420SP_VU;如果是非8K的原图缩放,inputFormat和outputFormat的设置可参考表10-10。
示例代码:
本示例是将yuv420sp格式的图片从1080p缩放到720p。
void NewVpcTest1() { uint32_t inWidthStride = 1920; uint32_t inHeightStride = 1080; uint32_t outWidthStride = 1280; uint32_t outHeightStride = 720; uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; // 1080P yuv420sp Image uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // 720P yuv420sp bImage uint8_t* inBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(inBufferSize)); // Construct an input picture. if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc input buffer"); return; } uint8_t* outBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(outBufferSize)); // Construct an output picture. if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } FILE* fp = fopen("dvpp_vpc_1920x1080_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); DFreeInOutBuffer(inBuffer, outBuffer); return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp = nullptr; // Construct the input picture configuration. std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the drawing area, [0,0] in the upper left corner of the area, // and [1919,1079] in the lower right corner. inputConfigure->cropArea.leftOffset = 0; inputConfigure->cropArea.rightOffset = inWidthStride - 1; inputConfigure->cropArea.upOffset = 0; inputConfigure->cropArea.downOffset = inHeightStride - 1; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area, coordinate [0,0] in the upper left corner of the map area, // and [1279,719] in the lower right corner. outputConfigure->outputArea.leftOffset = 0; outputConfigure->outputArea.rightOffset = outWidthStride - 1; outputConfigure->outputArea.upOffset = 0; outputConfigure->outputArea.downOffset = outHeightStride - 1; imageConfigure->roiConfigure = roiConfigure.get(); IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); DFreeInOutBuffer(inBuffer, outBuffer); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest1::call vpc dvppctl process success!"); } FILE* outImageFp = fopen("NewVpcTest1Out.yuv", "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "open NewVpcTest1Out.yuv faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } fwrite(outBuffer, 1, outBufferSize, outImageFp); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); fclose(outImageFp); outImageFp = nullptr; return; }
示例2:抠一张图+缩放
关键参数设置如下:
- 抠图区域宽高是缩放前图片的宽高,可指定抠图区域的位置,例如:若指定抠图区域的位置在输入图片的中间,则抠图区域各偏移值的设置如下:
- 左偏移leftOffset=100
- 右偏移rightOffset=499
- 上偏移upOffset=100
- 下偏移downOffset=399
- 右偏移rightOffset - 左偏移leftOffset+1=抠图区域图片的宽
- 下偏移downOffset - 上偏移upOffset+1=抠图区域图片的高
- 贴图区域宽高是缩放后图片的宽高,可指定贴图区域的位置,例如:若指定贴图区域的位置在输出图片的中间,则贴图区域各偏移值的设置如下:
- 左偏移leftOffset=256
- 右偏移rightOffset=399
- 上偏移upOffset=200
- 下偏移downOffset=399
- 右偏移rightOffset - 左偏移leftOffset+1=缩放后图片的宽
- 下偏移downOffset - 上偏移upOffset+1=缩放后图片的高
示例代码:
本示例是从yuv420sp格式、1080p的图片中抠出一张图,经过缩放后,将缩放后的图片贴到720p的输出图片(由用户申请的空输出内存产生的空白图片)中。如果需要将已有图片作为输出图片,用户需在申请输出内存后,将已有图片读入输出内存,代码示例请参考示例5:叠加。
void NewVpcTest2() { uint32_t inWidthStride = 1920; uint32_t inHeightStride = 1080; uint32_t outWidthStride = 1280; uint32_t outHeightStride = 720; uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; // 1080P yuv420sp Image uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // 720P yuv420sp Image uint8_t* inBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(inBufferSize)); // Construct an input picture. if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc input buffer"); return; } uint8_t* outBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(outBufferSize)); // Construct an output picture. if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } (void)memset_s(outBuffer, outBufferSize, 0x80, outBufferSize); FILE* fp = fopen("dvpp_vpc_1920x1080_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); DFreeInOutBuffer(inBuffer, outBuffer); return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp = nullptr; // Construct the input picture configuration std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the drawing area, [100,100] in the upper left corner of the area, and [499,499] in the lower right corner. inputConfigure->cropArea.leftOffset = 100; inputConfigure->cropArea.rightOffset = 499; inputConfigure->cropArea.upOffset = 100; inputConfigure->cropArea.downOffset = 499; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area, [256,200] in the upper left corner of the map area, and [399,399] in the lower right corner. outputConfigure->outputArea.leftOffset = 256; // The offset value must be 16-pixel-aligned. outputConfigure->outputArea.rightOffset = 399; outputConfigure->outputArea.upOffset = 200; outputConfigure->outputArea.downOffset = 399; imageConfigure->roiConfigure = roiConfigure.get(); IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); DFreeInOutBuffer(inBuffer, outBuffer); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest2::call vpc dvppctl process success!"); } FILE* outImageFp = fopen("NewVpcTest2Out.yuv", "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "open NewVpcTest2Out.yuv failed"); DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } fwrite(outBuffer, 1, outBufferSize, outImageFp); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); fclose(outImageFp); outImageFp = nullptr; return; }
示例3:抠多张图+缩放+拼接
关键参数设置:抠图区域上偏移、下偏移、左偏移、右偏移以及贴图区域上偏移、下偏移、左偏移、右偏移的配置,请参见示例2:抠一张图+缩放中的说明。
示例代码:本示例是从yuv420sp格式、1080p的图片中抠出多张图,经过缩放后,将缩放后的多张图片拼接到720p的输出图片(由用户申请的空输出内存产生的空白图片)中,贴图区域拼接的位置由上偏移、下偏移、左偏移、右偏移的值决定。如果需要将已有图片作为输出图片,用户需在申请输出内存后,将已有图片读入输出内存,代码示例请参考示例5:叠加。
void NewVpcTest3() { uint32_t inWidthStride = 1920; uint32_t inHeightStride = 1080; uint32_t outWidthStride = 1280; uint32_t outHeightStride = 720; uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; // 1080P yuv420sp Image uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // 720P yuv420sp Image uint8_t* inBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(inBufferSize)); // Construct an input picture. if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc input buffer"); return; } FILE* fp = fopen("dvpp_vpc_1920x1080_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp == nullptr; // Construct the input picture configuration. std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> lastRoi; std::vector<std::shared_ptr<VpcUserRoiConfigure>> roiVector; for (uint32_t i = 0; i < 5; i++) { std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiVector.push_back(roiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the drawing area. inputConfigure->cropArea.leftOffset = 100 + i * 16; inputConfigure->cropArea.rightOffset = 499 + i * 16; inputConfigure->cropArea.upOffset = 100 + i * 16; inputConfigure->cropArea.downOffset = 499 + i * 16; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; uint8_t* outBuffer = static_cast<uint8_t*>(HIAI_DVPP_DMalloc(outBufferSize)); // Construct an input picture if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } (void)memset_s(outBuffer, outBufferSize, 0x80, outBufferSize); outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area. outputConfigure->outputArea.leftOffset = 256 + i * 16; // The offset value must be 16-pixel-aligned. outputConfigure->outputArea.rightOffset = 399 + i * 16; outputConfigure->outputArea.upOffset = 256 + i * 16; outputConfigure->outputArea.downOffset = 399 + i * 16; if (i == 0) { imageConfigure->roiConfigure = roiConfigure.get(); lastRoi = roiConfigure; } else { lastRoi->next = roiConfigure.get(); lastRoi = roiConfigure; } } IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest3::call vpc dvppctl process success!"); } FILE* outImageFp = nullptr; uint32_t imageCount = 0; char fileName[50] = {0}; while (imageConfigure->roiConfigure != nullptr) { int32_t safeFuncRet = sprintf_s(fileName, sizeof(fileName), "NewVpcTest3_%dOut.yuv", imageCount); if (safeFuncRet == -1) { HIAI_ENGINE_LOG(HIAI_ERROR, "sprintf_s fail, ret = %d", safeFuncRet); DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } outImageFp = fopen(fileName, "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "open %s faild!", fileName); DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; } fwrite(imageConfigure->roiConfigure->outputConfigure.addr, 1, imageConfigure->roiConfigure->outputConfigure.bufferSize, outImageFp); fclose(outImageFp); outImageFp = nullptr; imageConfigure->roiConfigure = imageConfigure->roiConfigure->next; imageCount++; } ret = DestroyDvppApi(pidvppapi); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; FreeMultipleRio(imageConfigure->roiConfigure); return; }
示例4,8K缩放功能
对于8K缩放功能,支持缩放、支持YUV420SP NV12与YUV420SP NV21之间的格式转换、不支持抠图。
示例代码:本示例是将yuv420sp格式的图片从8129*8192缩放至4000*4000。
void NewVpcTest4() { uint32_t inWidthStride = 8192; // No need for 128 byte alignment uint32_t inHeightStride = 8192; // No need for 16 byte alignment uint32_t outWidthStride = 4000; // No need for 128 byte alignment uint32_t outHeightStride = 4000; // No need for 16 byte alignment uint32_t inBufferSize = inWidthStride * inHeightStride * 3 / 2; uint32_t outBufferSize = outWidthStride * outHeightStride * 3 / 2; // Construct dummy data uint8_t* inBuffer = (uint8_t*)HIAI_DVPP_DMalloc(inBufferSize); // Construct input image if (inBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc roiOutput buffer"); return; } uint8_t* outBuffer = (uint8_t*)HIAI_DVPP_DMalloc(outBufferSize); // Construct output image if (outBuffer == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc roiOutput buffer"); HIAI_DVPP_DFree(inBuffer); inBuffer = nullptr; return; } FILE* fp = fopen("dvpp_vpc_8192x8192_nv12.yuv", "rb+"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed"); DFreeInOutBuffer(inBuffer, outBuffer); return; } fread(inBuffer, 1, inBufferSize, fp); fclose(fp); fp = nullptr; std::shared_ptr<VpcUserImageConfigure> imageConfigure(new VpcUserImageConfigure); imageConfigure->bareDataAddr = inBuffer; imageConfigure->bareDataBufferSize = inBufferSize; imageConfigure->isCompressData = false; imageConfigure->widthStride = inWidthStride; imageConfigure->heightStride = inHeightStride; imageConfigure->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; imageConfigure->outputFormat = OUTPUT_YUV420SP_UV; imageConfigure->yuvSumEnable = false; imageConfigure->cmdListBufferAddr = nullptr; imageConfigure->cmdListBufferSize = 0; std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; VpcUserRoiInputConfigure* inputConfigure = &roiConfigure->inputConfigure; // Set the roi area inputConfigure->cropArea.leftOffset = 0; inputConfigure->cropArea.rightOffset = inWidthStride - 1; inputConfigure->cropArea.upOffset = 0; inputConfigure->cropArea.downOffset = inHeightStride - 1; VpcUserRoiOutputConfigure* outputConfigure = &roiConfigure->outputConfigure; outputConfigure->addr = outBuffer; outputConfigure->bufferSize = outBufferSize; outputConfigure->widthStride = outWidthStride; outputConfigure->heightStride = outHeightStride; // Set the map area outputConfigure->outputArea.leftOffset = 0; outputConfigure->outputArea.rightOffset = outWidthStride - 1; outputConfigure->outputArea.upOffset = 0; outputConfigure->outputArea.downOffset = outHeightStride - 1; imageConfigure->roiConfigure = roiConfigure.get(); IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateDvppApi(pidvppapi); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); DFreeInOutBuffer(inBuffer, outBuffer); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = static_cast<void*>(imageConfigure.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(pidvppapi, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "call vpc dvppctl process faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } else { HIAI_ENGINE_LOG(HIAI_OK, "NewVpcTest4::call vpc dvppctl process success!"); } FILE* outImageFp = fopen("NewVpcTest4Out.yuv", "wb+"); if (outImageFp == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "open NewVpcTest4Out.yuv faild!"); ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; } fwrite(outBuffer, 1, outBufferSize, outImageFp); fclose(outImageFp); outImageFp = nullptr; ret = DestroyDvppApi(pidvppapi); DFreeInOutBuffer(inBuffer, outBuffer); return; }
示例5:叠加
FILE* fpOut = fopen("vpcOut.yuv", "rb+"); if (fpOut == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "fopen file failed."); fclose(fpOut); return; } fread(outBuffer, 1, outBufferSize, fpOut); fclose(fpOut);
实现JPEGE功能
- 使用DvppGetOutParameter接口获取内存大小,由用户指定输出内存,由用户自行释放内存,调用示例如下 。
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; } // 此处获得的jpgSize为估算值,实际数据长度可能要小于这个值 // 最终jpgSize大小,以调用DvppCtl接口以后,此字段才为真正的编码后的jpgSize大小 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) { // 注意:释放内存时需要使用tmpAddr,因为outData.jpgData在JPEGE处理后会有地址偏移 HIAI_DVPP_DFree(tmpAddr); tmpAddr = nullptr; } }
- 不由用户指定输出内存时,DVPP内部申请内存,需由用户调用cbFree()回调函数释放内存,调用示例如下。
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 }
实现JPEGD功能
- 使用DvppGetOutParameter接口获取内存大小,由用户指定输出内存,由用户自行释放内存,调用示例如下 。
void TEST_JPEGD_CUSTOM_MEMORY() { struct JpegdIn jpegdInData; struct JpegdOut jpegdOutData; if (g_rank) { jpegdInData.isYUV420Need = false; } FILE *fpIn = fopen(g_inFileName, "rb"); if (fpIn == nullptr) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "can not open file %s.", g_inFileName); return; } do { // for resource fpIn fseek(fpIn, 0, SEEK_END); // the buf len should 8 byte larger, the driver asked uint32_t fileLen = ftell(fpIn); jpegdInData.jpegDataSize = fileLen + 8; fseek(fpIn, 0, SEEK_SET); void* addrOrig = HIAI_DVPP_DMalloc(jpegdInData.jpegDataSize); if (addrOrig == nullptr) { HIAI_ENGINE_LOG(HIAI_JPEGD_CTL_ERROR, "can not alloc input buffer"); fclose(fpIn); fpIn = nullptr; break; } jpegdInData.jpegData = reinterpret_cast<unsigned char*>(addrOrig); do { // for resource inBuf fread(jpegdInData.jpegData, 1, fileLen, fpIn); fclose(fpIn); fpIn = nullptr; int32_t ret = DvppGetOutParameter((void*)(&jpegdInData), (void*)(&jpegdOutData), GET_JPEGD_OUT_PARAMETER); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_JPEGD_CTL_ERROR, "call DvppGetOutParameter process failed"); break; } HIAI_ENGINE_LOG("jpegd out size is %d", jpegdOutData.yuvDataSize); jpegdOutData.yuvData = (unsigned char*)HIAI_DVPP_DMalloc(jpegdOutData.yuvDataSize); if (jpegdOutData.yuvData == nullptr) { HIAI_ENGINE_LOG(HIAI_JPEGD_CTL_ERROR, "can not alloc output buffer"); break; } HIAI_ENGINE_LOG("jpegdOutData.yuvData is %p", jpegdOutData.yuvData); dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = (void *)&jpegdInData; dvppApiCtlMsg.in_size = sizeof(jpegdInData); dvppApiCtlMsg.out = (void *)&jpegdOutData; dvppApiCtlMsg.out_size = sizeof(jpegdOutData); IDVPPAPI *pidvppapi = nullptr; CreateDvppApi(pidvppapi); if (pidvppapi != nullptr) { for (int i = 0;i < g_loop; i++) { if (0 != DvppCtl(pidvppapi, DVPP_CTL_JPEGD_PROC, &dvppApiCtlMsg)) { HIAI_ENGINE_LOG(HIAI_JPEGD_CTL_ERROR, "call dvppctl process failed"); break; } } DestroyDvppApi(pidvppapi); } else { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "can not create dvpp api"); break; } WriteTestJpegdResultToFile(&jpegdOutData); } while (0); // for resource inBuf if (addrOrig != nullptr) { HIAI_DVPP_DFree(addrOrig); addrOrig = nullptr; } if (jpegdOutData.yuvData != nullptr) { HIAI_DVPP_DFree(jpegdOutData.yuvData); jpegdOutData.yuvData = nullptr; } } while (0); // for resource fpIn }
- 不由用户指定输出内存时,DVPP内部申请内存,需由用户调用cbFree()回调函数释放内存,调用示例如下。
void JpegdProcess() { struct jpegd_raw_data_info jpegdInData; struct jpegd_yuv_data_info jpegdOutData; if (g_rank) { jpegdInData.IsYUV420Need = false; } FILE *fpIn = fopen(g_inFileName, "rb"); if (fpIn == nullptr) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "can not open file %s.", g_inFileName); return; } do { // for resource fpIn fseek(fpIn, 0, SEEK_END); // the buf len should 8 byte larger, the driver asked uint32_t fileLen = ftell(fpIn); jpegdInData.jpeg_data_size = fileLen + 8; fseek(fpIn, 0, SEEK_SET); void* addrOrig = HIAI_DVPP_DMalloc(jpegdInData.jpeg_data_size); if (addrOrig == nullptr) { HIAI_ENGINE_LOG(HIAI_JPEGD_CTL_ERROR, "can not alloc input buffer"); break; } jpegdInData.jpeg_data = reinterpret_cast<unsigned char*>(addrOrig); do { // for resource inBuf fread(jpegdInData.jpeg_data, 1, fileLen, fpIn); dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = (void*)&jpegdInData; dvppApiCtlMsg.in_size = sizeof(jpegdInData); dvppApiCtlMsg.out = (void*)&jpegdOutData; dvppApiCtlMsg.out_size = sizeof(jpegdOutData); IDVPPAPI *pidvppapi = nullptr; CreateDvppApi(pidvppapi); if (pidvppapi != nullptr) { for (int i = 0;i < g_loop; i++) { // same picture loop test if (DvppCtl(pidvppapi, DVPP_CTL_JPEGD_PROC, &dvppApiCtlMsg) != 0) { HIAI_ENGINE_LOG(HIAI_JPEGD_CTL_ERROR, "call dvppctl process failed"); break; } if (i < g_loop - 1) { jpegdOutData.cbFree(); jpegdOutData.yuv_data = nullptr; } } DestroyDvppApi(pidvppapi); } else { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "can not create dvpp api"); break; } WriteJpegdProcessResultToFile(&jpegdOutData); jpegdOutData.cbFree(); jpegdOutData.yuv_data = nullptr; } while (0); // for resource inBuf if (addrOrig != nullptr) { HIAI_DVPP_DFree(addrOrig); addrOrig = nullptr; } } while (0); // for resource fpIn fclose(fpIn); fpIn = nullptr; }
实现PNGD功能
使用DvppGetOutParameter接口获取内存大小,由用户指定输出内存,由用户自行释放内存,调用示例如下 。
void TEST_PNGD_CUSTOM_MEMORY() { FILE* fpIn = fopen(g_inFileName, "rb"); if (nullptr == fpIn) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "can not open file %s.", g_inFileName); return; } fseek(fpIn, 0, SEEK_END); uint32_t fileLen = ftell(fpIn); fseek(fpIn, 0, SEEK_SET); void* inbuf = HIAI_DVPP_DMalloc(fileLen); if (inbuf == nullptr) { HIAI_ENGINE_LOG(HIAI_PNGD_CTL_ERROR, "can not alloc input buffer"); fclose(fpIn); fpIn = nullptr; return; } // prepare msg struct PngInputInfoAPI inputPngData; // input data inputPngData.inputData = inbuf; // input png data inputPngData.inputSize = fileLen; // the size of png data HIAI_ENGINE_LOG("inputPngData.address: %p", inputPngData.address); HIAI_ENGINE_LOG("inputPngData.size: %u", inputPngData.size); HIAI_ENGINE_LOG("inputPngData.inputData: %p", inputPngData.inputData); HIAI_ENGINE_LOG("inputPngData.inputSize: %u", inputPngData.inputSize); fread(inputPngData.inputData, 1, fileLen, fpIn); fclose(fpIn); fpIn = nullptr; if (g_transform == 1) { // Whether format conversion inputPngData.transformFlag = 1; // RGBA -> RGB } else { inputPngData.transformFlag = 0; } struct PngOutputInfoAPI outputPngData; // output data int32_t ret = DvppGetOutParameter((void*)(&inputPngData), (void*)(&outputPngData), GET_PNGD_OUT_PARAMETER); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_PNGD_CTL_ERROR, "call DvppGetOutParameter process failed"); HIAI_DVPP_DFree(inbuf); inbuf = nullptr; return; } HIAI_ENGINE_LOG("pngd out size is %d", outputPngData.size); outputPngData.address = HIAI_DVPP_DMalloc(outputPngData.size); if (outputPngData.address == nullptr) { HIAI_ENGINE_LOG(HIAI_PNGD_CTL_ERROR, "can not alloc output buffer"); HIAI_DVPP_DFree(inbuf); inbuf = nullptr; return; } dvppapi_ctl_msg dvppApiCtlMsg; // call the interface msg dvppApiCtlMsg.in = (void*)(&inputPngData); dvppApiCtlMsg.in_size = sizeof(struct PngInputInfoAPI); dvppApiCtlMsg.out = (void*)(&outputPngData); dvppApiCtlMsg.out_size = sizeof(struct PngOutputInfoAPI); // use interface IDVPPAPI *pidvppapi = nullptr; CreateDvppApi(pidvppapi); // create dvppapi if (pidvppapi != nullptr) { // use DvppCtl interface to handle DVPP_CTL_PNGD_PROC for (int i = 0; i < g_loop; i++) { if (-1 == DvppCtl(pidvppapi, DVPP_CTL_PNGD_PROC, &dvppApiCtlMsg)) { HIAI_ENGINE_LOG(HIAI_PNGD_CTL_ERROR, "call dvppctl process failed"); HIAI_DVPP_DFree(inbuf); inbuf = nullptr; HIAI_DVPP_DFree(outputPngData.address); outputPngData.address = nullptr; DestroyDvppApi(pidvppapi); // destory dvppapi return; } } } else { HIAI_ENGINE_LOG(HIAI_PNGD_CTL_ERROR, "can not get dvpp api"); } DestroyDvppApi(pidvppapi); HIAI_ENGINE_LOG("output result"); char* pAddr = (char*)outputPngData.outputData; FILE* fpOut = fopen(g_outFileName, "wb"); if (fpOut == nullptr) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "can not open file %s.", g_outFileName); HIAI_DVPP_DFree(inbuf); inbuf = nullptr; HIAI_DVPP_DFree(outputPngData.address); outputPngData.address = nullptr; return; } int size = outputPngData.width * 4; if (outputPngData.format == PNGD_RGB_FORMAT_NUM) { size = outputPngData.width * 3; } else if (outputPngData.format == PNGD_RGBA_FORMAT_NUM) { size = outputPngData.width * 4; } // copy valid image data from every line. for (int i = 0; i < outputPngData.high; i++) { fwrite(pAddr + (int)(i * outputPngData.widthAlign), size, 1, fpOut); } fclose(fpOut); fpOut = nullptr; HIAI_DVPP_DFree(inbuf); inbuf = nullptr; HIAI_DVPP_DFree(outputPngData.address); outputPngData.address = nullptr; return; }
实现VDEC功能
对于一个视频码流,调用一次CreateVdecApi接口创建实例后,必须使用同一个实例调用VdecCtl接口进行视频解码,最后再调用一次DestroyVdecApi接口释放实例。
在视频解码时,如果需要从一个视频码流切换到另一个视频码流,则需要先调用DestroyVdecApi接口释放前一个码流的实例,再调用CreateVdecApi接口创建新的实例,用于处理新的视频码流。
此调用示例是读取文件名为“test_file”的h264码流文件,调用VDEC功能,将解码结果存放到“output_dir”目录。
// 自定义子类 class HIAI_DATA_SP_SON: public HIAI_DATA_SP { public: ~ HIAI_DATA_SP_SON () { //destruct here; } // 用户自定义新增一些成员函数,以用户需求为准,下述新增成员函数仅为示例 uint8_t GetTotalFrameNum() { return info_.totalFrameNum; } private: // 用户自定义一些成员变量,以用户需求为准,下述新增成员变量结构体info_仅为示例 struct INFO { uint8_t totalFrameNum; uint8_t frameRate; }info_; }; IDVPPAPI * pidvppapi_vpc = NULL; IDVPPAPI * pidvppapi_vdec = NULL; //回调函数举例,调用方需根据自己的需求来重新定义回调函数 void FrameReturn(FRAME* frame, void* hiaiData) { static int32_t imageCount = 0; imageCount++; HIAI_ENGINE_LOG("call save frame number:[%d], width:[%d], height:[%d]", imageCount, frame->width, frame->height); // The image directly output by vdec is an image of hfbc compression format, which cannot be directly displayed. // It is necessary to call vpc to convert hfbc to an image of uncompressed format to display. HIAI_ENGINE_LOG("start call vpc interface to translate hfbc."); IDVPPAPI* dvppHandle = nullptr; int32_t ret = CreateDvppApi(dvppHandle); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "creat dvpp api fail."); return; } // Construct vpc input configuration. std::shared_ptr<VpcUserImageConfigure> userImage(new VpcUserImageConfigure); // bareDataAddr should be null which the image is hfbc. userImage->bareDataAddr = nullptr; userImage->bareDataBufferSize = 0; userImage->widthStride = frame->width; userImage->heightStride = frame->height; // Configuration input format string imageFormat(frame->image_format); if (frame->bitdepth == 8) { if (imageFormat == "nv12") { userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV; } else { userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_VU; } } else { if (imageFormat == "nv12") { userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_UV_10BIT; } else { userImage->inputFormat = INPUT_YUV420_SEMI_PLANNER_VU_10BIT; } } userImage->outputFormat = OUTPUT_YUV420SP_UV; userImage->isCompressData = true; // Configure hfbc input address VpcCompressDataConfigure* compressDataConfigure = &userImage->compressDataConfigure; uint64_t baseAddr = (uint64_t)frame->buffer; compressDataConfigure->lumaHeadAddr = baseAddr + frame->offset_head_y; compressDataConfigure->chromaHeadAddr = baseAddr + frame->offset_head_c; compressDataConfigure->lumaPayloadAddr = baseAddr + frame->offset_payload_y; compressDataConfigure->chromaPayloadAddr = baseAddr + frame->offset_payload_c; compressDataConfigure->lumaHeadStride = frame->stride_head; compressDataConfigure->chromaHeadStride = frame->stride_head; compressDataConfigure->lumaPayloadStride = frame->stride_payload; compressDataConfigure->chromaPayloadStride = frame->stride_payload; userImage->yuvSumEnable = false; userImage->cmdListBufferAddr = nullptr; userImage->cmdListBufferSize = 0; // Configure the roi area and output area std::shared_ptr<VpcUserRoiConfigure> roiConfigure(new VpcUserRoiConfigure); roiConfigure->next = nullptr; userImage->roiConfigure = roiConfigure.get(); VpcUserRoiInputConfigure* roiInput = &roiConfigure->inputConfigure; roiInput->cropArea.leftOffset = 0; roiInput->cropArea.rightOffset = frame->width - 1; roiInput->cropArea.upOffset = 0; roiInput->cropArea.downOffset = frame->height - 1; VpcUserRoiOutputConfigure* roiOutput = &roiConfigure->outputConfigure; roiOutput->outputArea.leftOffset = 0; roiOutput->outputArea.rightOffset = frame->width - 1; roiOutput->outputArea.upOffset = 0; roiOutput->outputArea.downOffset = frame->height - 1; roiOutput->bufferSize = ALIGN_UP(frame->width, 16) * ALIGN_UP(frame->height, 2) * 3 / 2; roiOutput->addr = (uint8_t*)HIAI_DVPP_DMalloc(roiOutput->bufferSize); if (roiOutput->addr == nullptr) { HIAI_ENGINE_LOG(HIAI_VPC_CTL_ERROR, "can not alloc roiOutput buffer"); DestroyDvppApi(dvppHandle); return; } roiOutput->widthStride = ALIGN_UP(frame->width, 16); roiOutput->heightStride = ALIGN_UP(frame->height, 2); dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = (void*)(userImage.get()); dvppApiCtlMsg.in_size = sizeof(VpcUserImageConfigure); ret = DvppCtl(dvppHandle, DVPP_CTL_VPC_PROC, &dvppApiCtlMsg); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_ERROR, "call dvppctl fail"); HIAI_DVPP_DFree(roiOutput->addr); roiOutput->addr = nullptr; DestroyDvppApi(dvppHandle); return; } ret = FrameReturnSaveVpcResult(frame, roiOutput->addr, imageCount); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_ERROR, "save vpc result fail"); } HIAI_DVPP_DFree(roiOutput->addr); roiOutput->addr = nullptr; DestroyDvppApi(dvppHandle); return; } /* *错误上报回调函数,用户若不需要错误信息,可不定义此函数 */ void ErrReport(VDECERR* vdecErr) { if (vdecErr != nullptr) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "vdec error code is %d, channelId = %u\n", vdecErr->errType, vdecErr->channelId); } } //测试函数主入口 void TEST_VDEC() { char outputDir[20] = {0}; int32_t safeFuncRet = memset_s(outputDir, sizeof(outputDir), 0, 20); if (safeFuncRet != EOK) { HIAI_ENGINE_LOG(HIAI_ERROR, "memset_s fail"); return; } safeFuncRet = strncpy_s(outputDir, sizeof(outputDir), "output_dir", strlen("output_dir")); if (safeFuncRet != EOK) { HIAI_ENGINE_LOG(HIAI_ERROR, "strncpy_s fail"); return; } if (access(outputDir, F_OK) == -1) { if (mkdir(outputDir, 0700) < 0) { // directory authority: 0700 HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "create dir failed."); return; } } else if (access(outputDir, R_OK | W_OK | X_OK) == -1) { HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "output directory authority is not correct, use 700 instead."); return; } IDVPPAPI *pidvppapi = nullptr; int32_t ret = CreateVdecApi(pidvppapi, 0); if (ret != 0) { HIAI_ENGINE_LOG(HIAI_CREATE_DVPP_ERROR, "create dvpp api fail."); return; } if (pidvppapi != nullptr) { FILE* fp = fopen(g_inFileName, "rb"); if (fp == nullptr) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "open file: %s failed.", g_inFileName); DestroyVdecApi(pidvppapi, 0); return; } fseek(fp, 0L, SEEK_END); int file_size = ftell(fp); fseek(fp, 0L, SEEK_SET); int rest_len = file_size; int len = file_size; vdec_in_msg vdec_msg; vdec_msg.call_back = FrameReturn; vdec_msg.err_report = ErrReport; // can be unassigned, if user does not need error info vdec_msg.hiai_data = nullptr; int32_t safeFuncRet = 0; if (g_format == 0) { safeFuncRet = memcpy_s(vdec_msg.video_format, sizeof(vdec_msg.video_format), "h264", 4); if (safeFuncRet != EOK) { HIAI_ENGINE_LOG(HIAI_ERROR, "memcpy_s fail"); DestroyVdecApi(pidvppapi, 0); fclose(fp); fp = nullptr; return; } } else { safeFuncRet = memcpy_s(vdec_msg.video_format, sizeof(vdec_msg.video_format), "h265", 4); if (safeFuncRet != EOK) { HIAI_ENGINE_LOG(HIAI_ERROR, "memcpy_s fail"); DestroyVdecApi(pidvppapi, 0); fclose(fp); fp = nullptr; return; } } vdec_msg.in_buffer = (char*)malloc(len); if (vdec_msg.in_buffer == nullptr) { HIAI_ENGINE_LOG(HIAI_ERROR, "malloc fail"); fclose(fp); fp = nullptr; DestroyVdecApi(pidvppapi, 0); return; } dvppapi_ctl_msg dvppApiCtlMsg; dvppApiCtlMsg.in = (void*)(&vdec_msg); dvppApiCtlMsg.in_size = sizeof(vdec_in_msg); while (rest_len > 0) { int read_len = fread(vdec_msg.in_buffer, 1, len, fp); HIAI_ENGINE_LOG("rest_len is %d,read len is %d.", rest_len, read_len); vdec_msg.in_buffer_size = read_len; fclose(fp); fp = nullptr; if (VdecCtl(pidvppapi, DVPP_CTL_VDEC_PROC, &dvppApiCtlMsg, 0) != 0) { HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "call dvppctl process faild!"); free(vdec_msg.in_buffer); vdec_msg.in_buffer = nullptr; DestroyVdecApi(pidvppapi, 0); return; } HIAI_ENGINE_LOG(HIAI_OK, "call vdec process success!"); rest_len = rest_len - len; } free(vdec_msg.in_buffer); vdec_msg.in_buffer = nullptr; } else { HIAI_ENGINE_LOG(HIAI_VDEC_CTL_ERROR, "pidvppapi is null!"); } DestroyVdecApi(pidvppapi, 0); return; }
实现VENC功能
若需要将多张图片编码成一个视频,则调用一次CreateVenc接口创建实例后,必须使用同一个实例调用RunVenc接口进行视频编码,最后再调用一次DestroyVenc接口释放实例。
本调用示例是调用VENC接口将yuv图片编码成h265或者h264格式的码流。
std::string vencOutFileName("venc.bin"); std::shared_ptr<FILE> vencOutFile(nullptr); void VencCallBackDumpFile(struct VencOutMsg* vencOutMsg, void* userData) { if (vencOutFile.get() == nullptr) { HIAI_ENGINE_LOG(HIAI_VENC_CTL_ERROR, "get venc out file fail!"); return; } fwrite(vencOutMsg->outputData, 1, vencOutMsg->outputDataSize, vencOutFile.get()); fflush(vencOutFile.get()); } /* * venc new interface to achieve venc basic functions. */ void TEST_VENC() { std::shared_ptr<FILE> fpIn(fopen(g_inFileName, "rb"), fclose); vencOutFile.reset(fopen(vencOutFileName.c_str(), "wb"), fclose); if (fpIn.get() == nullptr || vencOutFile.get() == nullptr) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "open open venc in/out file failed."); return; } fseek(fpIn.get(), 0, SEEK_END); uint32_t fileLen = ftell(fpIn.get()); fseek(fpIn.get(), 0, SEEK_SET); struct VencConfig vencConfig; vencConfig.width = g_width; vencConfig.height = g_high; vencConfig.codingType = g_format; vencConfig.yuvStoreType = g_yuvStoreType; vencConfig.keyFrameInterval = 16; vencConfig.vencOutMsgCallBack = VencCallBackDumpFile; vencConfig.userData = nullptr; int32_t vencHandle = CreateVenc(&vencConfig); if (vencHandle == -1) { HIAI_ENGINE_LOG(HIAI_VENC_CTL_ERROR, "CreateVenc fail!"); return; } // input 16 frames once uint32_t inDataLenMaxOnce = g_width * g_high * 3 / 2; std::shared_ptr<char> inBuffer(static_cast<char*>(malloc(inDataLenMaxOnce)), free); if (inBuffer.get() == nullptr) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "alloc input buffer failed"); DestroyVenc(vencHandle); return; } uint32_t inDataUnhandledLen = fileLen; auto start = std::chrono::system_clock::now(); uint32_t frameCount = 0; while (inDataUnhandledLen > 0) { uint32_t inDataLen = inDataUnhandledLen; if (inDataUnhandledLen > inDataLenMaxOnce) { inDataLen = inDataLenMaxOnce; } inDataUnhandledLen -= inDataLen; uint32_t readLen = fread(inBuffer.get(), 1, inDataLen, fpIn.get()); if (readLen != inDataLen) { HIAI_ENGINE_LOG(HIAI_OPEN_FILE_ERROR, "error in read input file"); DestroyVenc(vencHandle); return; } struct VencInMsg vencInMsg; vencInMsg.inputData = inBuffer.get(); vencInMsg.inputDataSize = inDataLen; vencInMsg.keyFrameInterval = 16; vencInMsg.forceIFrame = 0; vencInMsg.eos = 0; if (RunVenc(vencHandle, &vencInMsg) == -1) { HIAI_ENGINE_LOG(HIAI_VENC_CTL_ERROR, "call video encode fail"); break; } ++frameCount; } auto end = std::chrono::system_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start); size_t timeCount = static_cast<size_t>(duration.count()); HIAI_ENGINE_LOG("Total frame count: %u", frameCount); HIAI_ENGINE_LOG("Time cost: %lu us", timeCount); HIAI_ENGINE_LOG("FPS: %lf", frameCount * 1.0 / (timeCount / 1000000.0)); DestroyVenc(vencHandle); return; }