1919 lines
72 KiB
C++
1919 lines
72 KiB
C++
/*
|
||
* Copyright (c) 2020.Huawei Technologies Co., Ltd. All rights reserved.
|
||
* 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.
|
||
*/
|
||
|
||
#include "DvppCommon.h"
|
||
#include <iostream>
|
||
#include <memory>
|
||
|
||
#include "Log.h"
|
||
#include "CommonDataType.h"
|
||
|
||
static auto g_resizeConfigDeleter = [](acldvppResizeConfig *const p) { acldvppDestroyResizeConfig(p); };
|
||
static auto g_picDescDeleter = [](acldvppPicDesc *const picDesc) { acldvppDestroyPicDesc(picDesc); };
|
||
static auto g_roiConfigDeleter = [](acldvppRoiConfig *const p) { acldvppDestroyRoiConfig(p); };
|
||
static auto g_jpegeConfigDeleter = [](acldvppJpegeConfig *const p) { acldvppDestroyJpegeConfig(p); };
|
||
|
||
DvppCommon::DvppCommon(aclrtStream dvppStream)
|
||
{
|
||
dvppStream_ = dvppStream;
|
||
}
|
||
|
||
DvppCommon::DvppCommon(const VdecConfig &vdecConfig)
|
||
{
|
||
vdecConfig_ = vdecConfig;
|
||
}
|
||
|
||
/*
|
||
* @description: Create a channel for processing image data,
|
||
* the channel description is created by acldvppCreateChannelDesc
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::Init(void)
|
||
{
|
||
dvppChannelDesc_ = acldvppCreateChannelDesc();
|
||
if (dvppChannelDesc_ == nullptr)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
//若不调用该接口,则系统默认3种模式的通道都创建(通道数的限制,请参见总体说明。),
|
||
//可能会占用资源,推荐用户根据实际功能指定通道模式。
|
||
acldvppSetChannelDescMode(dvppChannelDesc_, DVPP_CHNMODE_VPC);
|
||
|
||
APP_ERROR ret = acldvppCreateChannel(dvppChannelDesc_);
|
||
if (ret != 0)
|
||
{
|
||
LogFatal << "Failed to create dvpp channel: " << GetAppErrCodeInfo(ret) << ".";
|
||
acldvppDestroyChannelDesc(dvppChannelDesc_);
|
||
dvppChannelDesc_ = nullptr;
|
||
return ret;
|
||
}
|
||
|
||
//获取通道号,通道号会自己增加
|
||
// uint64_t channelid = acldvppGetChannelDescChannelId(dvppChannelDesc_);
|
||
// printf("channelid:%d\n", channelid);
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Create a channel for processing video data,
|
||
* the channel description is created by aclvdecCreateChannelDesc
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::InitVdec()
|
||
{
|
||
isVdec_ = true;
|
||
|
||
// create vdec channelDesc
|
||
vdecChannelDesc_ = aclvdecCreateChannelDesc();
|
||
if (vdecChannelDesc_ == nullptr)
|
||
{
|
||
LogError << "Failed to create vdec channel description.";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
// channelId: 0-15
|
||
aclError ret = aclvdecSetChannelDescChannelId(vdecChannelDesc_, vdecConfig_.channelId);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to set vdec channel id, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
ret = aclvdecSetChannelDescThreadId(vdecChannelDesc_, vdecConfig_.threadId);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to set thread id, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
// callback func
|
||
ret = aclvdecSetChannelDescCallback(vdecChannelDesc_, vdecConfig_.callback);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to set vdec callback function, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
ret = aclvdecSetChannelDescEnType(vdecChannelDesc_, vdecConfig_.inFormat);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to set encoded type of input video, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
ret = aclvdecSetChannelDescOutPicFormat(vdecChannelDesc_, vdecConfig_.outFormat);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to set vdec output format, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
//设置是否实时出帧(即发送一帧解码一帧,无需依赖后续帧的传入)。
|
||
//只支持简单参考关系的H264/H265标准码流(无长期参考帧,无B帧)。
|
||
ret = aclvdecSetChannelDescOutMode(vdecChannelDesc_, vdecConfig_.outMode);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to set vdec output format, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
// create vdec channel
|
||
ret = aclvdecCreateChannel(vdecChannelDesc_);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Failed to create vdec channel, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
LogInfo << "Vdec init resource successfully.";
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: If isVdec_ is true, destroy the channel and the channel description used by video.
|
||
* Otherwise destroy the channel and the channel description used by image.
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::DeInit(void)
|
||
{
|
||
if (isVdec_)
|
||
{
|
||
return DestroyResource();
|
||
}
|
||
|
||
APP_ERROR ret = aclrtSynchronizeStream(dvppStream_); // APP_ERROR ret
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogFatal << "Failed to synchronize stream, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
//如果在调用acldvppDestroyChannel接口销毁通道前,
|
||
//已调用acldvppDestroyChannelDesc接口销毁了通道描述信息,那么在调用acldvppDestroyChannel接口销毁通道时会报错。
|
||
ret = acldvppDestroyChannel(dvppChannelDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogFatal << "Failed to destory dvpp channel, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
//销毁通道描述信息
|
||
ret = acldvppDestroyChannelDesc(dvppChannelDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogFatal << "Failed to destroy dvpp channel description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
//释放内存
|
||
ReleaseDvppBuffer();
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Destroy the channel and the channel description used by video.
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::DestroyResource()
|
||
{
|
||
APP_ERROR ret = APP_ERR_OK;
|
||
isVdec_ = true;
|
||
//如果在调用aclvdecDestroyChannel接口销毁通道前,
|
||
//已调用aclvdecDestroyChannelDesc接口销毁了通道描述信息,那么在调用aclvdecDestroyChannel接口销毁通道时会报错。
|
||
if (vdecChannelDesc_ != nullptr)
|
||
{
|
||
ret = aclvdecDestroyChannel(vdecChannelDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to destory dvpp channel, ret = " << ret;
|
||
}
|
||
aclvdecDestroyChannelDesc(vdecChannelDesc_);
|
||
vdecChannelDesc_ = nullptr;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* @description: Release the memory that is allocated in the interfaces which are started with "Combine"
|
||
*/
|
||
void DvppCommon::ReleaseDvppBuffer() const
|
||
{
|
||
if (cropImage_ != nullptr)
|
||
{
|
||
RELEASE_DVPP_DATA(cropImage_->data);
|
||
}
|
||
if (resizedImage_ != nullptr)
|
||
{
|
||
RELEASE_DVPP_DATA(resizedImage_->data);
|
||
}
|
||
if (decodedImage_ != nullptr)
|
||
{
|
||
RELEASE_DVPP_DATA(decodedImage_->data);
|
||
}
|
||
if (inputImage_ != nullptr)
|
||
{
|
||
RELEASE_DVPP_DATA(inputImage_->data);
|
||
}
|
||
if (encodedImage_ != nullptr)
|
||
{
|
||
RELEASE_DVPP_DATA(encodedImage_->data);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* @description: Get the size of buffer used to save image for VPC according to width, height and format
|
||
* @param width specifies the width of the output image
|
||
* @param height specifies the height of the output image
|
||
* @param format specifies the format of the output image
|
||
* @param: vpcSize is used to save the result size
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetVpcDataSize(uint32_t width, uint32_t height, acldvppPixelFormat format, uint32_t &vpcSize)
|
||
{
|
||
// Check the invalid format of VPC function and calculate the output buffer size
|
||
if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420)
|
||
{
|
||
LogError << "Format[" << format << "] for VPC is not supported, just support NV12 or NV21.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
uint32_t widthStride = DVPP_ALIGN_UP(width, VPC_WIDTH_ALIGN);
|
||
uint32_t heightStride = DVPP_ALIGN_UP(height, VPC_HEIGHT_ALIGN);
|
||
vpcSize = widthStride * heightStride * YUV_BGR_SIZE_CONVERT_3 / YUV_BGR_SIZE_CONVERT_2;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the aligned width and height of the input image according to the image format
|
||
* @param: width specifies the width before alignment
|
||
* @param: height specifies the height before alignment
|
||
* @param: format specifies the image format
|
||
* @param: widthStride is used to save the width after alignment
|
||
* @param: heightStride is used to save the height after alignment
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetVpcInputStrideSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
|
||
uint32_t &widthStride, uint32_t &heightStride)
|
||
{
|
||
uint32_t inputWidthStride;
|
||
// Check the invalidty of input format and calculate the input width stride
|
||
if (format >= PIXEL_FORMAT_YUV_400 && format <= PIXEL_FORMAT_YVU_SEMIPLANAR_444)
|
||
{
|
||
// If format is YUV SP, keep widthStride not change.
|
||
inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH);
|
||
}
|
||
else if (format >= PIXEL_FORMAT_YUYV_PACKED_422 && format <= PIXEL_FORMAT_VYUY_PACKED_422)
|
||
{
|
||
// If format is YUV422 packed, image size = H x W * 2;
|
||
inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH) * YUV422_WIDTH_NU;
|
||
}
|
||
else if (format >= PIXEL_FORMAT_YUV_PACKED_444 && format <= PIXEL_FORMAT_BGR_888)
|
||
{
|
||
// If format is YUV444 packed or RGB, image size = H x W * 3;
|
||
inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH) * YUV444_RGB_WIDTH_NU;
|
||
}
|
||
else if (format >= PIXEL_FORMAT_ARGB_8888 && format <= PIXEL_FORMAT_BGRA_8888)
|
||
{
|
||
// If format is XRGB8888, image size = H x W * 4
|
||
inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH) * XRGB_WIDTH_NU;
|
||
}
|
||
else
|
||
{
|
||
LogError << "Input format[" << format << "] for VPC is invalid, please check it.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
uint32_t inputHeightStride = DVPP_ALIGN_UP(height, VPC_STRIDE_HEIGHT);
|
||
// Check the input validity width stride.
|
||
if (inputWidthStride > MAX_RESIZE_WIDTH || inputWidthStride < MIN_RESIZE_WIDTH)
|
||
{
|
||
LogError << "Input width stride " << inputWidthStride << " is invalid, not in [" << MIN_RESIZE_WIDTH
|
||
<< ", " << MAX_RESIZE_WIDTH << "].";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
// Check the input validity height stride.
|
||
if (inputHeightStride > MAX_RESIZE_HEIGHT || inputHeightStride < MIN_RESIZE_HEIGHT)
|
||
{
|
||
LogError << "Input height stride " << inputHeightStride << " is invalid, not in [" << MIN_RESIZE_HEIGHT
|
||
<< ", " << MAX_RESIZE_HEIGHT << "].";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
widthStride = inputWidthStride;
|
||
heightStride = inputHeightStride;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the aligned width and height of the output image according to the image format
|
||
* @param: width specifies the width before alignment
|
||
* @param: height specifies the height before alignment
|
||
* @param: format specifies the image format
|
||
* @param: widthStride is used to save the width after alignment
|
||
* @param: heightStride is used to save the height after alignment
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetVpcOutputStrideSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
|
||
uint32_t &widthStride, uint32_t &heightStride)
|
||
{
|
||
// Check the invalidty of output format and calculate the output width and height
|
||
if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420)
|
||
{
|
||
LogError << "Output format[" << format << "] for VPC is not supported, just support NV12 or NV21.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
|
||
widthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH);
|
||
heightStride = DVPP_ALIGN_UP(height, VPC_STRIDE_HEIGHT);
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Set picture description information and execute resize function
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @param: processType specifies whether to perform proportional scaling, default is non-proportional resize
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::VpcResize(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize,
|
||
VpcProcessType processType)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "VpcResize cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
|
||
acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
|
||
resizeInputDesc_.reset(inputDesc, g_picDescDeleter);
|
||
resizeOutputDesc_.reset(outputDesc, g_picDescDeleter);
|
||
|
||
// Set dvpp picture descriptin info of input image
|
||
APP_ERROR ret = SetDvppPicDescData(input, *resizeInputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set dvpp input picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Set dvpp picture descriptin info of output image
|
||
ret = SetDvppPicDescData(output, *resizeOutputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set dvpp output picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
//默认缩放,非等比例
|
||
if (processType == VPC_PT_DEFAULT)
|
||
{
|
||
return ResizeProcess(*resizeInputDesc_, *resizeOutputDesc_, withSynchronize);
|
||
}
|
||
|
||
// Get crop area according to the processType
|
||
// When the processType is VPC_PT_FILL, the image will be cropped if the image size is different from the target resolution
|
||
CropRoiConfig cropRoi = {0};
|
||
GetCropRoi(input, output, processType, cropRoi);
|
||
|
||
// The width and height of the original image will be resized by the same ratio
|
||
// The cropped image will be pasted on the upper left corner or the middle location or the whole location according to the processType
|
||
CropRoiConfig pasteRoi = {0};
|
||
GetPasteRoi(input, output, processType, pasteRoi);
|
||
|
||
//记住paste区域
|
||
paste_up_ = pasteRoi.up;
|
||
paste_left_ = pasteRoi.left;
|
||
paste_right_ = pasteRoi.right;
|
||
paste_down_ = pasteRoi.down;
|
||
|
||
return ResizeWithPadding(*resizeInputDesc_, *resizeOutputDesc_, cropRoi, pasteRoi, withSynchronize);
|
||
}
|
||
|
||
//抠图和缩放
|
||
APP_ERROR DvppCommon::VpcCropAndPaste(const DvppCropInputInfo &input, const DvppDataInfo &output, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "VpcResize cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
|
||
acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
|
||
resizeInputDesc_.reset(inputDesc, g_picDescDeleter); //自定义析构器
|
||
resizeOutputDesc_.reset(outputDesc, g_picDescDeleter);
|
||
|
||
// Set dvpp picture descriptin info of input image
|
||
APP_ERROR ret = SetDvppPicDescData(input.dataInfo, *resizeInputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set dvpp input picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Set dvpp picture descriptin info of output image
|
||
ret = SetDvppPicDescData(output, *resizeOutputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set dvpp output picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
//抠图区域
|
||
CropRoiConfig cropRoi = input.roi;
|
||
|
||
//贴图区域,贴在左上角,等比例 (注:获取贴图区域pasteRoi时,应该用抠图区域的宽高作等比例计算)
|
||
CropRoiConfig pasteRoi = {0};
|
||
DvppDataInfo cropAreaInfo;
|
||
cropAreaInfo.width = cropRoi.right - cropRoi.left + ODD_NUM_1;
|
||
cropAreaInfo.height = cropRoi.down - cropRoi.up + ODD_NUM_1;
|
||
GetPasteRoi(cropAreaInfo, output, VPC_PT_PADDING, pasteRoi);
|
||
|
||
//记住paste区域
|
||
paste_up_ = pasteRoi.up;
|
||
paste_left_ = pasteRoi.left;
|
||
paste_right_ = pasteRoi.right;
|
||
paste_down_ = pasteRoi.down;
|
||
|
||
return ResizeWithPadding(*resizeInputDesc_, *resizeOutputDesc_, cropRoi, pasteRoi, withSynchronize);
|
||
}
|
||
|
||
/*
|
||
* @description: Set image description information
|
||
* @param: dataInfo specifies the image information
|
||
* @param: picsDesc specifies the picture description information to be set
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::SetDvppPicDescData(const DvppDataInfo &dataInfo, acldvppPicDesc &picDesc) const
|
||
{
|
||
APP_ERROR ret = acldvppSetPicDescData(&picDesc, dataInfo.data);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set data for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescSize(&picDesc, dataInfo.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set size for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescFormat(&picDesc, dataInfo.format);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set format for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescWidth(&picDesc, dataInfo.width);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set width for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescHeight(&picDesc, dataInfo.height);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set height for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescWidthStride(&picDesc, dataInfo.widthStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set aligned width for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescHeightStride(&picDesc, dataInfo.heightStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set aligned height for dvpp picture description, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Check whether the image format and zoom ratio meet the requirements
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::CheckResizeParams(const DvppDataInfo &input, const DvppDataInfo &output) const
|
||
{
|
||
if (output.format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && output.format != PIXEL_FORMAT_YVU_SEMIPLANAR_420)
|
||
{
|
||
LogError << "Output format[" << output.format << "] for VPC is not supported, just support NV12 or NV21.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
//针对缩放功能,贴图/抠图的宽高缩放比例范围:[1/32, 16]。
|
||
if (((float)output.height / input.height) < MIN_RESIZE_SCALE ||
|
||
((float)output.height / input.height) > MAX_RESIZE_SCALE)
|
||
{
|
||
LogError << "Resize scale should be in range [1/32, 16], which is " << (output.height / input.height) << ".";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
if (((float)output.width / input.width) < MIN_RESIZE_SCALE ||
|
||
((float)output.width / input.width) > MAX_RESIZE_SCALE)
|
||
{
|
||
LogError << "Resize scale should be in range [1/32, 16], which is " << (output.width / input.width) << ".";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Scale the input image to the size specified by the output image and
|
||
* saves the result to the output image (non-proportionate scaling)
|
||
* @param: inputDesc specifies the description information of the input image
|
||
* @param: outputDesc specifies the description information of the output image
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::ResizeProcess(acldvppPicDesc &inputDesc, acldvppPicDesc &outputDesc, bool withSynchronize)
|
||
{
|
||
acldvppResizeConfig *resizeConfig = acldvppCreateResizeConfig();
|
||
if (resizeConfig == nullptr)
|
||
{
|
||
LogError << "Failed to create dvpp resize config.";
|
||
return APP_ERR_COMM_INVALID_POINTER;
|
||
}
|
||
|
||
resizeConfig_.reset(resizeConfig, g_resizeConfigDeleter);
|
||
APP_ERROR ret = acldvppVpcResizeAsync(dvppChannelDesc_, &inputDesc, &outputDesc, resizeConfig_.get(), dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to resize asynchronously, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
if (withSynchronize)
|
||
{
|
||
ret = aclrtSynchronizeStream(dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to synchronize stream, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Crop the image from the input image based on the specified area and
|
||
* paste the cropped image to the specified position of the target image
|
||
* as the output image
|
||
* @param: inputDesc specifies the description information of the input image
|
||
* @param: outputDesc specifies the description information of the output image
|
||
* @param: cropRoi specifies the cropped area
|
||
* @param: pasteRoi specifies the pasting area
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: If the width and height of the crop area are different from those of the
|
||
* paste area, the image is scaled again
|
||
*/
|
||
APP_ERROR DvppCommon::ResizeWithPadding(acldvppPicDesc &inputDesc, acldvppPicDesc &outputDesc, CropRoiConfig &cropRoi,
|
||
CropRoiConfig &pasteRoi, bool withSynchronize)
|
||
{
|
||
acldvppRoiConfig *cropRoiCfg = acldvppCreateRoiConfig(cropRoi.left, cropRoi.right, cropRoi.up, cropRoi.down);
|
||
if (cropRoiCfg == nullptr)
|
||
{
|
||
LogError << "Failed to create dvpp roi config for corp area.";
|
||
return APP_ERR_COMM_FAILURE;
|
||
}
|
||
cropAreaConfig_.reset(cropRoiCfg, g_roiConfigDeleter);
|
||
|
||
acldvppRoiConfig *pastRoiCfg = acldvppCreateRoiConfig(pasteRoi.left, pasteRoi.right, pasteRoi.up, pasteRoi.down);
|
||
if (pastRoiCfg == nullptr)
|
||
{
|
||
LogError << "Failed to create dvpp roi config for paster area.";
|
||
return APP_ERR_COMM_FAILURE;
|
||
}
|
||
pasteAreaConfig_.reset(pastRoiCfg, g_roiConfigDeleter);
|
||
|
||
APP_ERROR ret = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, &inputDesc, &outputDesc, cropAreaConfig_.get(),
|
||
pasteAreaConfig_.get(), dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// release resource.
|
||
LogError << "Failed to crop and paste asynchronously, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
if (withSynchronize)
|
||
{
|
||
ret = aclrtSynchronizeStream(dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed tp synchronize stream, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get crop area
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @param: processType specifies whether to perform proportional scaling
|
||
* @param: cropRoi is used to save the info of the crop roi area
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
void DvppCommon::GetCropRoi(const DvppDataInfo &input, const DvppDataInfo &output, VpcProcessType processType,
|
||
CropRoiConfig &cropRoi) const
|
||
{
|
||
// When processType is not VPC_PT_FILL, crop area is the whole input image
|
||
if (processType != VPC_PT_FILL)
|
||
{
|
||
cropRoi.right = CONVERT_TO_ODD(input.width - ODD_NUM_1);
|
||
cropRoi.down = CONVERT_TO_ODD(input.height - ODD_NUM_1);
|
||
return;
|
||
}
|
||
|
||
bool widthRatioSmaller = true;
|
||
// The scaling ratio is based on the smaller ratio to ensure the smallest edge to fill the targe edge
|
||
float resizeRatio = static_cast<float>(input.width) / output.width;
|
||
if (resizeRatio > (static_cast<float>(input.height) / output.height))
|
||
{
|
||
resizeRatio = static_cast<float>(input.height) / output.height;
|
||
widthRatioSmaller = false;
|
||
}
|
||
|
||
const int halfValue = 2;
|
||
// The left and up must be even, right and down must be odd which is required by acl
|
||
if (widthRatioSmaller)
|
||
{
|
||
cropRoi.left = 0;
|
||
cropRoi.right = CONVERT_TO_ODD(input.width - ODD_NUM_1);
|
||
cropRoi.up = CONVERT_TO_EVEN(static_cast<uint32_t>((input.height - output.height * resizeRatio) / halfValue));
|
||
cropRoi.down = CONVERT_TO_ODD(input.height - cropRoi.up - ODD_NUM_1);
|
||
return;
|
||
}
|
||
|
||
cropRoi.up = 0;
|
||
cropRoi.down = CONVERT_TO_ODD(input.height - ODD_NUM_1);
|
||
cropRoi.left = CONVERT_TO_EVEN(static_cast<uint32_t>((input.width - output.width * resizeRatio) / halfValue));
|
||
cropRoi.right = CONVERT_TO_ODD(input.width - cropRoi.left - ODD_NUM_1);
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* @description: Get paste area
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @param: processType specifies whether to perform proportional scaling
|
||
* @param: pasteRio is used to save the info of the paste area
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
void DvppCommon::GetPasteRoi(const DvppDataInfo &input, const DvppDataInfo &output, VpcProcessType processType,
|
||
CropRoiConfig &pasteRoi) const
|
||
{
|
||
if (processType == VPC_PT_FILL)
|
||
{
|
||
pasteRoi.right = CONVERT_TO_ODD(output.width - ODD_NUM_1);
|
||
pasteRoi.down = CONVERT_TO_ODD(output.height - ODD_NUM_1);
|
||
return;
|
||
}
|
||
|
||
bool widthRatioLarger = true;
|
||
// The scaling ratio is based on the larger ratio to ensure the largest edge to fill the targe edge
|
||
float resizeRatio = static_cast<float>(input.width) / output.width;
|
||
if (resizeRatio < (static_cast<float>(input.height) / output.height))
|
||
{
|
||
resizeRatio = static_cast<float>(input.height) / output.height;
|
||
widthRatioLarger = false;
|
||
}
|
||
|
||
// Left and up is 0 when the roi paste on the upper left corner
|
||
if (processType == VPC_PT_PADDING)
|
||
{
|
||
pasteRoi.right = (input.width / resizeRatio) - ODD_NUM_1;
|
||
pasteRoi.down = (input.height / resizeRatio) - ODD_NUM_1;
|
||
pasteRoi.right = CONVERT_TO_ODD(pasteRoi.right);
|
||
pasteRoi.down = CONVERT_TO_ODD(pasteRoi.down);
|
||
return;
|
||
}
|
||
|
||
const int halfValue = 2;
|
||
// Left and up is 0 when the roi paste on the middler location
|
||
if (widthRatioLarger)
|
||
{
|
||
pasteRoi.left = 0;
|
||
pasteRoi.right = output.width - ODD_NUM_1;
|
||
pasteRoi.up = (output.height - (input.height / resizeRatio)) / halfValue;
|
||
pasteRoi.down = output.height - pasteRoi.up - ODD_NUM_1;
|
||
}
|
||
else
|
||
{
|
||
pasteRoi.up = 0;
|
||
pasteRoi.down = output.height - ODD_NUM_1;
|
||
pasteRoi.left = (output.width - (input.width / resizeRatio)) / halfValue;
|
||
pasteRoi.right = output.width - pasteRoi.left - ODD_NUM_1;
|
||
}
|
||
|
||
// The left must be even and align to 16, up must be even, right and down must be odd which is required by acl
|
||
pasteRoi.left = DVPP_ALIGN_UP(CONVERT_TO_EVEN(pasteRoi.left), VPC_WIDTH_ALIGN);
|
||
pasteRoi.right = CONVERT_TO_ODD(pasteRoi.right);
|
||
pasteRoi.up = CONVERT_TO_EVEN(pasteRoi.up);
|
||
pasteRoi.down = CONVERT_TO_ODD(pasteRoi.down);
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* @description: Resize the image specified by input and save the result to member variable resizedImage_
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @param: processType specifies whether to perform proportional scaling, default is non-proportional resize
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::CombineResizeProcess(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize,
|
||
VpcProcessType processType)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineResizeProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
//检查缩放比例是否合适
|
||
APP_ERROR ret = CheckResizeParams(input, output);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
//在外部设置对齐后宽高
|
||
// Get widthStride and heightStride for input and output image according to the format
|
||
// ret = GetVpcInputStrideSize(input.width, input.height, input.format, input.widthStride,
|
||
// input.heightStride);
|
||
// if (ret != APP_ERR_OK)
|
||
// {
|
||
// return ret;
|
||
// }
|
||
|
||
resizedImage_ = std::make_shared<DvppDataInfo>();
|
||
resizedImage_->width = output.width;
|
||
resizedImage_->height = output.height;
|
||
resizedImage_->format = output.format;
|
||
ret = GetVpcOutputStrideSize(output.width, output.height, output.format, resizedImage_->widthStride,
|
||
resizedImage_->heightStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Get output buffer size for resize output
|
||
ret = GetVpcDataSize(output.width, output.height, output.format, resizedImage_->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Malloc buffer for output of resize module
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)(&(resizedImage_->data)), resizedImage_->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc " << resizedImage_->dataSize << " bytes on dvpp for resize, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
aclrtMemset(resizedImage_->data, resizedImage_->dataSize, YUV_GREYER_VALUE, resizedImage_->dataSize);
|
||
resizedImage_->frameId = input.frameId;
|
||
|
||
ret = VpcResize(input, *resizedImage_, withSynchronize, processType);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when resize failed, otherwise release it after use
|
||
RELEASE_DVPP_DATA(resizedImage_->data);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
//等比例缩放,不使用成员变量
|
||
APP_ERROR DvppCommon::CombineResizeProcess2(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize,
|
||
VpcProcessType processType)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineResizeProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
//检查缩放比例
|
||
APP_ERROR ret = CheckResizeParams(input, output);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
ret = GetVpcOutputStrideSize(output.width, output.height, output.format, output.widthStride,
|
||
output.heightStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
// Get output buffer size for resize output
|
||
ret = GetVpcDataSize(output.width, output.height, output.format, output.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Malloc buffer for output of resize module
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)(&(output.data)), output.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc " << output.dataSize << " bytes on dvpp for resize, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
aclrtMemset(output.data, output.dataSize, YUV_GREYER_VALUE, output.dataSize);
|
||
|
||
ret = VpcResize(input, output, withSynchronize, processType);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when resize failed, otherwise release it after use
|
||
RELEASE_DVPP_DATA(output.data);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
//抠图+缩放
|
||
APP_ERROR DvppCommon::CombineCropProcess2(DvppCropInputInfo &input, DvppDataInfo &output, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineCropProcess2 cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
//检查抠图区域
|
||
APP_ERROR ret = CheckCropParams(input);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
//检查缩放比例
|
||
DvppDataInfo box_step1;
|
||
box_step1.width = input.roi.right - input.roi.left + ODD_NUM_1;
|
||
box_step1.height = input.roi.down - input.roi.up + ODD_NUM_1;
|
||
ret = CheckResizeParams(box_step1, output);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
//得到输出对齐宽高
|
||
ret = GetVpcOutputStrideSize(output.width, output.height, output.format, output.widthStride,
|
||
output.heightStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
// Get output buffer size for resize output
|
||
ret = GetVpcDataSize(output.width, output.height, output.format, output.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Malloc buffer for output of resize module
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)(&(output.data)), output.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc " << output.dataSize << " bytes on dvpp for resize, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
aclrtMemset(output.data, output.dataSize, YUV_GREYER_VALUE, output.dataSize);
|
||
|
||
//抠图和缩放
|
||
ret = VpcCropAndPaste(input, output, withSynchronize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when resize failed, otherwise release it after use
|
||
RELEASE_DVPP_DATA(output.data);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* @description: Set picture description information and execute crop function
|
||
* @param: cropInput specifies the input image information and cropping area
|
||
* @param: output specifies the output image information
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::VpcCrop(const DvppCropInputInfo &cropInput, const DvppDataInfo &output, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "VpcCrop cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
|
||
acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
|
||
cropInputDesc_.reset(inputDesc, g_picDescDeleter);
|
||
cropOutputDesc_.reset(outputDesc, g_picDescDeleter);
|
||
|
||
// Set dvpp picture descriptin info of input image
|
||
APP_ERROR ret = SetDvppPicDescData(cropInput.dataInfo, *cropInputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Set dvpp picture descriptin info of output image
|
||
ret = SetDvppPicDescData(output, *cropOutputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
return CropProcess(*cropInputDesc_, *cropOutputDesc_, cropInput.roi, withSynchronize);
|
||
}
|
||
|
||
/*
|
||
* @description: Check whether the size of the cropped data and the cropped area meet the requirements
|
||
* @param: input specifies the image information and the information about the area to be cropped
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::CheckCropParams(const DvppCropInputInfo &input) const
|
||
{
|
||
APP_ERROR ret;
|
||
|
||
//不检查数据大小是否合适
|
||
// uint32_t payloadSize;
|
||
// ret = GetVpcDataSize(input.dataInfo.widthStride, input.dataInfo.heightStride, PIXEL_FORMAT_YUV_SEMIPLANAR_420,
|
||
// payloadSize);
|
||
// if (ret != APP_ERR_OK)
|
||
// {
|
||
// return ret;
|
||
// }
|
||
// if (payloadSize != input.dataInfo.dataSize)
|
||
// {
|
||
// LogError << "Input data size: " << payloadSize << " to crop does not match input yuv image size: "
|
||
// << input.dataInfo.dataSize << ".";
|
||
// return APP_ERR_COMM_INVALID_PARAM;
|
||
// }
|
||
|
||
if ((!CHECK_EVEN(input.roi.left)) || (!CHECK_EVEN(input.roi.up)) || (!CHECK_ODD(input.roi.right)) ||
|
||
(!CHECK_ODD(input.roi.down)))
|
||
{
|
||
LogError << "Crop area left and top(" << input.roi.left << ", " << input.roi.up
|
||
<< ") must be even, right bottom(" << input.roi.right << "," << input.roi.down << ") must be odd.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
|
||
// Calculate crop width and height according to the input location
|
||
uint32_t cropWidth = input.roi.right - input.roi.left + ODD_NUM_1;
|
||
uint32_t cropHeight = input.roi.down - input.roi.up + ODD_NUM_1;
|
||
if ((cropWidth < MIN_CROP_WIDTH) || (cropHeight < MIN_CROP_HEIGHT))
|
||
{
|
||
LogError << "Crop area width:" << cropWidth << " need to be larger than 10 and height:" << cropHeight
|
||
<< " need to be larger than 6.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
|
||
if ((input.roi.left + cropWidth > input.dataInfo.width) || (input.roi.up + cropHeight > input.dataInfo.height))
|
||
{
|
||
LogError << "Target rectangle start location(" << input.roi.left << "," << input.roi.up << ") with size("
|
||
<< cropWidth << "," << cropHeight << ") is out of the input image(" << input.dataInfo.width << ","
|
||
<< input.dataInfo.height << ") to be cropped.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: It is used to crop an input image based on a specified region and
|
||
* store the cropped image to the output memory as an output image
|
||
* @param: inputDesc specifies the description information of the input image
|
||
* @param: outputDesc specifies the description information of the output image
|
||
* @param: CropRoiConfig specifies the cropped area
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: if the region of the output image is inconsistent with the crop area, the image is scaled again
|
||
*/
|
||
APP_ERROR DvppCommon::CropProcess(acldvppPicDesc &inputDesc, acldvppPicDesc &outputDesc,
|
||
const CropRoiConfig &cropArea, bool withSynchronize)
|
||
{
|
||
uint32_t leftOffset = CONVERT_TO_EVEN(cropArea.left);
|
||
uint32_t rightOffset = CONVERT_TO_ODD(cropArea.right);
|
||
uint32_t upOffset = CONVERT_TO_EVEN(cropArea.up);
|
||
uint32_t downOffset = CONVERT_TO_ODD(cropArea.down);
|
||
|
||
auto cropRioCfg = acldvppCreateRoiConfig(leftOffset, rightOffset, upOffset, downOffset);
|
||
if (cropRioCfg == nullptr)
|
||
{
|
||
LogError << "DvppCommon: create dvpp vpc resize failed.";
|
||
return APP_ERR_DVPP_RESIZE_FAIL;
|
||
}
|
||
cropRoiConfig_.reset(cropRioCfg, g_roiConfigDeleter);
|
||
|
||
APP_ERROR ret = acldvppVpcCropAsync(dvppChannelDesc_, &inputDesc, &outputDesc, cropRoiConfig_.get(), dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// release resource.
|
||
LogError << "Failed to crop, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
if (withSynchronize)
|
||
{
|
||
ret = aclrtSynchronizeStream(dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to synchronize stream, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Crop the image specified by the input parameter and saves the result to member variable cropImage_
|
||
* @param: input specifies the input image information and cropping area
|
||
* @param: output specifies the output image information
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::CombineCropProcess(DvppCropInputInfo &input, DvppDataInfo &output, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineCropProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
// Get widthStride and heightStride for input and output image according to the format
|
||
//外部设置输入的对齐宽高
|
||
// APP_ERROR ret = GetVpcInputStrideSize(input.dataInfo.width, input.dataInfo.height, input.dataInfo.format,
|
||
// input.dataInfo.widthStride, input.dataInfo.heightStride);
|
||
// if (ret != APP_ERR_OK)
|
||
// {
|
||
// return ret;
|
||
// }
|
||
|
||
APP_ERROR ret = CheckCropParams(input);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
cropImage_ = std::make_shared<DvppDataInfo>();
|
||
cropImage_->width = output.width;
|
||
cropImage_->height = output.height;
|
||
cropImage_->format = output.format;
|
||
ret = GetVpcOutputStrideSize(output.width, output.height, output.format, cropImage_->widthStride,
|
||
cropImage_->heightStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Get output buffer size for resize output
|
||
ret = GetVpcDataSize(output.width, output.height, output.format, cropImage_->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
// Malloc buffer for output of resize module
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)(&(cropImage_->data)), cropImage_->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc " << cropImage_->dataSize << " bytes on dvpp for resize, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
cropImage_->frameId = input.dataInfo.frameId;
|
||
ret = VpcCrop(input, *cropImage_, withSynchronize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when resize failed, otherwise release it after use
|
||
RELEASE_DVPP_DATA(cropImage_->data);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* @description: Set the description of the output image and decode
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::JpegDecode(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "JpegDecode cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
|
||
decodeOutputDesc_.reset(outputDesc, g_picDescDeleter);
|
||
|
||
APP_ERROR ret = acldvppSetPicDescData(decodeOutputDesc_.get(), output.data);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set desc data, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescFormat(decodeOutputDesc_.get(), output.format);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set desc format, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
ret = acldvppSetPicDescSize(decodeOutputDesc_.get(), output.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set desc size, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
ret = acldvppJpegDecodeAsync(dvppChannelDesc_, input.data, input.dataSize, decodeOutputDesc_.get(), dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to decode jpeg, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
if (withSynchronize)
|
||
{
|
||
ret = aclrtSynchronizeStream(dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to synchronize stream, ret = " << ret << ".";
|
||
return APP_ERR_DVPP_JPEG_DECODE_FAIL;
|
||
}
|
||
}
|
||
|
||
ret = acldvppGetPicDescRetCode(decodeOutputDesc_.get());
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get image info, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
output.width = acldvppGetPicDescWidth(decodeOutputDesc_.get());
|
||
output.height = acldvppGetPicDescHeight(decodeOutputDesc_.get());
|
||
output.widthStride = acldvppGetPicDescWidthStride(decodeOutputDesc_.get());
|
||
output.heightStride = acldvppGetPicDescHeightStride(decodeOutputDesc_.get());
|
||
output.dataSize = acldvppGetPicDescSize(decodeOutputDesc_.get());
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the aligned width and height of the image after decoding
|
||
* @param: width specifies the width before alignment
|
||
* @param: height specifies the height before alignment
|
||
* @param: widthStride is used to save the width after alignment
|
||
* @param: heightStride is used to save the height after alignment
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function is used for obtaining jpeg decode stride in Ascend 310
|
||
*/
|
||
void DvppCommon::GetJpegDecodeStrideSize(uint32_t width, uint32_t height, uint32_t &widthStride, uint32_t &heightStride)
|
||
{
|
||
widthStride = DVPP_ALIGN_UP(width, JPEGD_STRIDE_WIDTH);
|
||
heightStride = DVPP_ALIGN_UP(height, JPEGD_STRIDE_HEIGHT);
|
||
}
|
||
|
||
/*
|
||
* @description: Get picture width and height and number of channels from image data
|
||
* @param: data specifies the memory to store the image data
|
||
* @param: dataSize specifies the size of the image data
|
||
* @param: width is used to save the image width
|
||
* @param: height is used to save the image height
|
||
* @param: components is used to save the number of channels
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetJpegImageInfo(const void *data, uint32_t dataSize, uint32_t &width, uint32_t &height,
|
||
int32_t &components)
|
||
{
|
||
uint32_t widthTmp;
|
||
uint32_t heightTmp;
|
||
int32_t componentsTmp;
|
||
APP_ERROR ret = acldvppJpegGetImageInfo(data, dataSize, &widthTmp, &heightTmp, &componentsTmp);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get image info of jpeg, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
if (widthTmp > MAX_JPEGD_WIDTH || widthTmp < MIN_JPEGD_WIDTH)
|
||
{
|
||
LogError << "Input width is invalid, not in [" << MIN_JPEGD_WIDTH << ", " << MAX_JPEGD_WIDTH << "].";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
if (heightTmp > MAX_JPEGD_HEIGHT || heightTmp < MIN_JPEGD_HEIGHT)
|
||
{
|
||
LogError << "Input height is invalid, not in [" << MIN_JPEGD_HEIGHT << ", " << MAX_JPEGD_HEIGHT << "].";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
width = widthTmp;
|
||
height = heightTmp;
|
||
components = componentsTmp;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the size of the buffer for storing decoded images based on the image data, size, and format
|
||
* @param: data specifies the memory to store the image data
|
||
* @param: dataSize specifies the size of the image data
|
||
* @param: format specifies the image format
|
||
* @param: decSize is used to store the result size
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetJpegDecodeDataSize(const void *data, uint32_t dataSize, acldvppPixelFormat format,
|
||
uint32_t &decSize)
|
||
{
|
||
uint32_t outputSize;
|
||
APP_ERROR ret = acldvppJpegPredictDecSize(data, dataSize, format, &outputSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to predict decode size of jpeg image, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
decSize = outputSize;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Decode the image specified by imageInfo and save the result to member variable decodedImage_
|
||
* @param: imageInfo specifies image information
|
||
* @param: format specifies the image format
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::CombineJpegdProcess(const RawData &imageInfo, acldvppPixelFormat format, bool withSynchronize, bool bReleaseInput/*=false*/)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineJpegdProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
int32_t components;
|
||
inputImage_ = std::make_shared<DvppDataInfo>();
|
||
inputImage_->format = format;
|
||
APP_ERROR ret = GetJpegImageInfo(imageInfo.data.get(), imageInfo.lenOfByte, inputImage_->width, inputImage_->height,
|
||
components);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get input image info, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Get the buffer size of decode output according to the input data and output format
|
||
uint32_t outBuffSize;
|
||
ret = GetJpegDecodeDataSize(imageInfo.data.get(), imageInfo.lenOfByte, format, outBuffSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get size of decode output buffer, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// In TransferImageH2D function, device buffer will be alloced to store the input image
|
||
// Need to pay attention to release of the buffer
|
||
ret = TransferImageH2D(imageInfo, inputImage_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
decodedImage_ = std::make_shared<DvppDataInfo>();
|
||
decodedImage_->format = format;
|
||
decodedImage_->dataSize = outBuffSize;
|
||
// Malloc dvpp buffer to store the output data after decoding
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)&decodedImage_->data, decodedImage_->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc memory on dvpp, ret = " << ret << ".";
|
||
RELEASE_DVPP_DATA(inputImage_->data);
|
||
return ret;
|
||
}
|
||
|
||
ret = JpegDecode(*inputImage_, *decodedImage_, withSynchronize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when decode failed, otherwise release it after use
|
||
RELEASE_DVPP_DATA(inputImage_->data);
|
||
//inputImage_->data = nullptr;
|
||
RELEASE_DVPP_DATA(decodedImage_->data);
|
||
//decodedImage_->data = nullptr;
|
||
return ret;
|
||
}
|
||
|
||
//释放图片解码时内部申请的dvpp输入内存。当参数bReleaseInput没传或传false时由调用者释放(兼顾历史调用点)
|
||
if(bReleaseInput)
|
||
{
|
||
RELEASE_DVPP_DATA(inputImage_->data);
|
||
}
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Transfer data from host to device
|
||
* @param: imageInfo specifies the image data on the host
|
||
* @param: jpegInput is used to save the buffer and its size which is allocate on the device
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::TransferImageH2D(const RawData &imageInfo, const std::shared_ptr<DvppDataInfo> &jpegInput) const
|
||
{
|
||
// Check image buffer size validity
|
||
if (imageInfo.lenOfByte <= 0)
|
||
{
|
||
LogError << "The input buffer size on host should not be empty.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
|
||
uint8_t *inDevBuff = nullptr;
|
||
APP_ERROR ret = acldvppMalloc((void **)&inDevBuff, imageInfo.lenOfByte);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc " << imageInfo.lenOfByte << " bytes on dvpp, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Copy the image data from host to device
|
||
ret = aclrtMemcpyAsync(inDevBuff, imageInfo.lenOfByte, imageInfo.data.get(), imageInfo.lenOfByte,
|
||
ACL_MEMCPY_HOST_TO_DEVICE, dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to copy " << imageInfo.lenOfByte << " bytes from host to device, ret = " << ret << ".";
|
||
RELEASE_DVPP_DATA(inDevBuff);
|
||
return ret;
|
||
}
|
||
// Attention: We must call the aclrtSynchronizeStream to ensure the task of memory replication has been completed
|
||
// after calling aclrtMemcpyAsync
|
||
ret = aclrtSynchronizeStream(dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to synchronize stream, ret = " << ret << ".";
|
||
RELEASE_DVPP_DATA(inDevBuff);
|
||
return ret;
|
||
}
|
||
jpegInput->data = inDevBuff;
|
||
jpegInput->dataSize = imageInfo.lenOfByte;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Create and set the description of a video stream
|
||
* @param: data specifies the information about the video stream
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::CreateStreamDesc(std::shared_ptr<DvppDataInfo> data)
|
||
{
|
||
// Malloc input device memory which need to be released in vdec callback function
|
||
void *modelInBuff = nullptr;
|
||
APP_ERROR ret = acldvppMalloc(&modelInBuff, data->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc dvpp data with " << data->dataSize << " bytes, ret = " << ret << ".";
|
||
return APP_ERR_ACL_BAD_ALLOC;
|
||
}
|
||
// copy input to device memory
|
||
ret = aclrtMemcpy(modelInBuff, data->dataSize, static_cast<uint8_t *>(data->data), data->dataSize,
|
||
ACL_MEMCPY_HOST_TO_DEVICE);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to copy memory with " << data->dataSize << " bytes from host to device, ret = "
|
||
<< ret << ".";
|
||
acldvppFree(modelInBuff);
|
||
modelInBuff = nullptr;
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
// Create input stream desc which need to be destoryed in vdec callback function
|
||
streamInputDesc_ = acldvppCreateStreamDesc();
|
||
if (streamInputDesc_ == nullptr)
|
||
{
|
||
LogError << "Failed to create input stream description.";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
ret = acldvppSetStreamDescData(streamInputDesc_, modelInBuff);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set data for stream desdescription, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
// set size for dvpp stream desc
|
||
ret = acldvppSetStreamDescSize(streamInputDesc_, data->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set data size for stream desdescription, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
ret = acldvppSetStreamDescTimestamp(streamInputDesc_, data->timestamp);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set data Timestamp for stream desdescription, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Decode the video based on the video stream specified by data and user-defined data,
|
||
* and outputs the image of each frame
|
||
* @param: data specifies the information about the video stream
|
||
* @param: userdata is specified for user-defined data
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with InitVdec
|
||
*/
|
||
APP_ERROR DvppCommon::CombineVdecProcess(std::shared_ptr<DvppDataInfo> data, void *userData)
|
||
{
|
||
// Return special error code when the DvppCommon object is not initialized with InitVdec
|
||
if (!isVdec_)
|
||
{
|
||
LogError << "CombineVdecProcess cannot be called by the DvppCommon object which is not initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
// create stream desc
|
||
APP_ERROR ret = CreateStreamDesc(data);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
uint32_t dataSize;
|
||
ret = GetVideoDecodeDataSize(vdecConfig_.inputWidth, vdecConfig_.inputHeight, vdecConfig_.outFormat, dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
void *picOutBufferDev = nullptr;
|
||
// picOutBufferDev need to be destoryed in vdec callback function
|
||
ret = acldvppMalloc(&picOutBufferDev, dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc memory with " << dataSize << " bytes, ret = " << ret << ".";
|
||
return APP_ERR_ACL_BAD_ALLOC;
|
||
}
|
||
|
||
// picOutputDesc_ will be destoryed in vdec callback function
|
||
picOutputDesc_ = acldvppCreatePicDesc();
|
||
if (picOutputDesc_ == NULL)
|
||
{
|
||
return APP_ERR_ACL_BAD_ALLOC;
|
||
}
|
||
|
||
DvppDataInfo dataInfo;
|
||
dataInfo.width = vdecConfig_.inputWidth;
|
||
dataInfo.height = vdecConfig_.inputHeight;
|
||
dataInfo.format = vdecConfig_.outFormat;
|
||
ret = GetVideoDecodeStrideSize(dataInfo.width, dataInfo.height, dataInfo.format, dataInfo.widthStride, dataInfo.heightStride);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to GetVideoDecodeStrideSize, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
dataInfo.dataSize = dataSize;
|
||
dataInfo.data = static_cast<uint8_t *>(picOutBufferDev);
|
||
|
||
ret = SetDvppPicDescData(dataInfo, *picOutputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
// send frame,发送到通道中
|
||
ret = aclvdecSendFrame(vdecChannelDesc_, streamInputDesc_, picOutputDesc_, nullptr, userData);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to send frame, ret = " << ret << ".";
|
||
return APP_ERR_ACL_FAILURE;
|
||
}
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Send eos frame when video stream ends
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::VdecSendEosFrame() const
|
||
{
|
||
// create input stream desc
|
||
acldvppStreamDesc *eosStreamDesc = acldvppCreateStreamDesc();
|
||
if (eosStreamDesc == nullptr)
|
||
{
|
||
LogError << "Fail to create dvpp stream desc for eos.";
|
||
return ACL_ERROR_FAILURE;
|
||
}
|
||
|
||
// set eos for eos stream desc
|
||
APP_ERROR ret = acldvppSetStreamDescEos(eosStreamDesc, true);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Fail to set eos for stream desc, ret = " << ret << ".";
|
||
acldvppDestroyStreamDesc(eosStreamDesc);
|
||
return ret;
|
||
}
|
||
|
||
// send eos and synchronize
|
||
ret = aclvdecSendFrame(vdecChannelDesc_, eosStreamDesc, nullptr, nullptr, nullptr);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Fail to send eos, ret = " << ret << ".";
|
||
acldvppDestroyStreamDesc(eosStreamDesc);
|
||
return ret;
|
||
}
|
||
|
||
// destroy input stream desc
|
||
ret = acldvppDestroyStreamDesc(eosStreamDesc);
|
||
if (ret != ACL_ERROR_NONE)
|
||
{
|
||
LogError << "Fail to destory dvpp stream desc for eos, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the aligned width and height of the output image after video decoding
|
||
* @param: width specifies the width before alignment
|
||
* @param: height specifies the height before alignment
|
||
* @param: format specifies the format of the output image
|
||
* @param: widthStride is used to save the width after alignment
|
||
* @param: heightStride is used to save the height after alignment
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetVideoDecodeStrideSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
|
||
uint32_t &widthStride, uint32_t &heightStride)
|
||
{
|
||
// Check the invalidty of output format and calculate the output width and height
|
||
if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420)
|
||
{
|
||
LogError << "Input format[" << format << "] for VPC is not supported, just support NV12 or NV21.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
widthStride = (width < VDEC_SPECIAL_WIDTH) ? VDEC_SPECIAL_STRIDE : DVPP_ALIGN_UP(width, VDEC_STRIDE_WIDTH);
|
||
heightStride = DVPP_ALIGN_UP(height, VDEC_STRIDE_HEIGHT);
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the buffer size for storing results after video decoding
|
||
* @param width specifies the width of the output image after video decoding
|
||
* @param height specifies the height of the output image after video decoding
|
||
* @param format specifies the format of the output image
|
||
* @param: vpcSize is used to save the result size
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetVideoDecodeDataSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
|
||
uint32_t &vdecSize)
|
||
{
|
||
// Check the invalid format of vdec output and calculate the output buffer size
|
||
if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420)
|
||
{
|
||
LogError << "Format[" << format << "] for VPC is not supported, just support NV12 or NV21.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
uint32_t widthStride = DVPP_ALIGN_UP(width, VDEC_STRIDE_WIDTH);
|
||
uint32_t heightStride = DVPP_ALIGN_UP(height, VDEC_STRIDE_HEIGHT);
|
||
vdecSize = widthStride * heightStride * YUV_BGR_SIZE_CONVERT_3 / YUV_BGR_SIZE_CONVERT_2;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Encode a YUV image into a JPG image
|
||
* @param: input specifies the input image information
|
||
* @param: output specifies the output image information
|
||
* @param: jpegeConfig specifies the encoding configuration data
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::JpegEncode(DvppDataInfo &input, DvppDataInfo &output, acldvppJpegeConfig *jpegeConfig,
|
||
bool withSynchronize) const
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "JpegEncode cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
APP_ERROR ret = SetDvppPicDescData(input, *encodeInputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
ret = acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_.get(), output.data, &output.dataSize, jpegeConfig,
|
||
dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to encode image, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
if (withSynchronize)
|
||
{
|
||
ret = aclrtSynchronizeStream(dvppStream_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to aclrtSynchronizeStream, ret = " << ret << ".";
|
||
return APP_ERR_DVPP_JPEG_ENCODE_FAIL;
|
||
}
|
||
}
|
||
//LogInfo << "Encode successfully.";
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Get the aligned width, height, and data size of the input image
|
||
* @param: inputImage specifies the input image information
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::GetJpegEncodeStrideSize(std::shared_ptr<DvppDataInfo> &inputImage)
|
||
{
|
||
uint32_t inputWidth = inputImage->width;
|
||
uint32_t inputHeight = inputImage->height;
|
||
acldvppPixelFormat format = inputImage->format;
|
||
uint32_t widthStride;
|
||
uint32_t heightStride;
|
||
uint32_t encodedBufferSize;
|
||
// Align up the input width and height and calculate buffer size of encoded input file
|
||
if (format == PIXEL_FORMAT_YUV_SEMIPLANAR_420 || format == PIXEL_FORMAT_YVU_SEMIPLANAR_420)
|
||
{
|
||
widthStride = DVPP_ALIGN_UP(inputWidth, JPEGE_STRIDE_WIDTH);
|
||
heightStride = DVPP_ALIGN_UP(inputHeight, JPEGE_STRIDE_HEIGHT);
|
||
encodedBufferSize = widthStride * heightStride * YUV_BYTES_NU / YUV_BYTES_DE;
|
||
}
|
||
else if (format == PIXEL_FORMAT_YUYV_PACKED_422 || format == PIXEL_FORMAT_UYVY_PACKED_422 ||
|
||
format == PIXEL_FORMAT_YVYU_PACKED_422 || format == PIXEL_FORMAT_VYUY_PACKED_422)
|
||
{
|
||
widthStride = DVPP_ALIGN_UP(inputWidth * YUV422_WIDTH_NU, JPEGE_STRIDE_WIDTH);
|
||
heightStride = DVPP_ALIGN_UP(inputHeight, JPEGE_STRIDE_HEIGHT);
|
||
encodedBufferSize = widthStride * heightStride;
|
||
}
|
||
else
|
||
{
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
if (encodedBufferSize == 0)
|
||
{
|
||
LogError << "Input host buffer size is empty.";
|
||
return APP_ERR_COMM_INVALID_PARAM;
|
||
}
|
||
inputImage->widthStride = widthStride;
|
||
inputImage->heightStride = heightStride;
|
||
inputImage->dataSize = encodedBufferSize;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Estimate the size of the output memory required by image encoding according to
|
||
* the input image description and image encoding configuration data
|
||
* @param: input specifies specifies the input image information
|
||
* @param: jpegeConfig specifies the encoding configuration data
|
||
* @param: encSize is used to save the result size
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::GetJpegEncodeDataSize(DvppDataInfo &input, acldvppJpegeConfig *jpegeConfig, uint32_t &encSize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "GetJpegEncodeDataSize cannot be called by the DvppCommon object which is initialized with "
|
||
<< "InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
|
||
encodeInputDesc_.reset(inputDesc, g_picDescDeleter);
|
||
|
||
APP_ERROR ret = SetDvppPicDescData(input, *encodeInputDesc_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
|
||
uint32_t outputSize;
|
||
ret = acldvppJpegPredictEncSize(encodeInputDesc_.get(), jpegeConfig, &outputSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to predict encode size of jpeg image, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
encSize = outputSize;
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Set the encoding configuration data
|
||
* @param: level specifies the encode quality range
|
||
* @param: jpegeConfig specifies the encoding configuration data
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
*/
|
||
APP_ERROR DvppCommon::SetEncodeLevel(uint32_t level, acldvppJpegeConfig &jpegeConfig)
|
||
{
|
||
// Set the encoding quality
|
||
// The coding quality range [0, 100]
|
||
// The level 0 coding quality is similar to the level 100
|
||
// The smaller the value in [1, 100], the worse the quality of the output picture
|
||
auto ret = (APP_ERROR)acldvppSetJpegeConfigLevel(&jpegeConfig, level);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/*
|
||
* @description: Encode the image specified by imageInfo and save the result to member variable encodedImage_
|
||
* @param: imageInfo specifies image information
|
||
* @param: width specifies the width of the input image
|
||
* @param: height specifies the height of the input image
|
||
* @param: format specifies the format of the input image
|
||
* @param: withSynchronize specifies whether to execute synchronously
|
||
* @return: APP_ERR_OK if success, other values if failure
|
||
* @attention: This function can be called only when the DvppCommon object is initialized with Init
|
||
*/
|
||
APP_ERROR DvppCommon::CombineJpegeProcess(const RawData &imageInfo, uint32_t width, uint32_t height,
|
||
acldvppPixelFormat format, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineJpegeProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
inputImage_ = std::make_shared<DvppDataInfo>();
|
||
inputImage_->format = format;
|
||
inputImage_->width = width;
|
||
inputImage_->height = height;
|
||
// In TransferImageH2D function, device buffer will be alloced to store the input image
|
||
// Need to pay attention to release of the buffer
|
||
APP_ERROR ret = TransferImageH2D(imageInfo, inputImage_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
return ret;
|
||
}
|
||
// Get stride size of encoded image
|
||
ret = GetJpegEncodeStrideSize(inputImage_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get encode stride size of input image file, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
auto jpegeConfig = acldvppCreateJpegeConfig();
|
||
jpegeConfig_.reset(jpegeConfig, g_jpegeConfigDeleter);
|
||
|
||
uint32_t encodeLevel = 100;
|
||
ret = SetEncodeLevel(encodeLevel, *jpegeConfig_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set encode level, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Get the buffer size of encode output according to the input data and jpeg encode config
|
||
uint32_t encodeOutBufferSize;
|
||
ret = GetJpegEncodeDataSize(*inputImage_, jpegeConfig_.get(), encodeOutBufferSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get size of encode output buffer, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
encodedImage_ = std::make_shared<DvppDataInfo>();
|
||
encodedImage_->dataSize = encodeOutBufferSize;
|
||
// Malloc dvpp buffer to store the output data after decoding
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)&encodedImage_->data, encodedImage_->dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc memory on dvpp, ret = " << ret << ".";
|
||
acldvppFree(inputImage_->data);
|
||
return ret;
|
||
}
|
||
|
||
// Encode input image
|
||
ret = JpegEncode(*inputImage_, *encodedImage_, jpegeConfig_.get(), withSynchronize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when decode failed, otherwise release it after use
|
||
acldvppFree(inputImage_->data);
|
||
acldvppFree(encodedImage_->data);
|
||
return ret;
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
//jpg编码,不使用成员变量
|
||
APP_ERROR DvppCommon::CombineJpegeProcess2(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize)
|
||
{
|
||
// Return special error code when the DvppCommon object is initialized with InitVdec
|
||
if (isVdec_)
|
||
{
|
||
LogError << "CombineJpegeProcess2 cannot be called by the DvppCommon object which is initialized with InitVdec.";
|
||
return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
|
||
}
|
||
|
||
auto jpegeConfig = acldvppCreateJpegeConfig();
|
||
jpegeConfig_.reset(jpegeConfig, g_jpegeConfigDeleter);
|
||
|
||
uint32_t encodeLevel = 25; //编码质量设为25,防止图片太大,sftp上传太慢
|
||
APP_ERROR ret = SetEncodeLevel(encodeLevel, *jpegeConfig_);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to set encode level, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Get the buffer size of encode output according to the input data and jpeg encode config
|
||
uint32_t encodeOutBufferSize;
|
||
ret = GetJpegEncodeDataSize(input, jpegeConfig_.get(), encodeOutBufferSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to get size of encode output buffer, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
//创建输出内存
|
||
output.dataSize = encodeOutBufferSize;
|
||
|
||
// Malloc dvpp buffer to store the output data after decoding
|
||
// Need to pay attention to release of the buffer
|
||
ret = acldvppMalloc((void **)(&output.data), output.dataSize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
LogError << "Failed to malloc memory on dvpp, ret = " << ret << ".";
|
||
return ret;
|
||
}
|
||
|
||
// Encode input image
|
||
ret = JpegEncode(input, output, jpegeConfig_.get(), withSynchronize);
|
||
if (ret != APP_ERR_OK)
|
||
{
|
||
// Release the output buffer when resize failed, otherwise release it after use
|
||
RELEASE_DVPP_DATA(output.data);
|
||
return ret;
|
||
}
|
||
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
std::shared_ptr<DvppDataInfo> DvppCommon::GetInputImage() const
|
||
{
|
||
return inputImage_;
|
||
}
|
||
|
||
std::shared_ptr<DvppDataInfo> DvppCommon::GetDecodedImage() const
|
||
{
|
||
return decodedImage_;
|
||
}
|
||
|
||
std::shared_ptr<DvppDataInfo> DvppCommon::GetResizedImage() const
|
||
{
|
||
return resizedImage_;
|
||
}
|
||
|
||
std::shared_ptr<DvppDataInfo> DvppCommon::GetEncodedImage() const
|
||
{
|
||
return encodedImage_;
|
||
}
|
||
|
||
std::shared_ptr<DvppDataInfo> DvppCommon::GetCropedImage() const
|
||
{
|
||
return cropImage_;
|
||
}
|
||
|
||
DvppCommon::~DvppCommon() {}
|