VTrain/base/DvppCommon/DvppCommon.cpp

1919 lines
72 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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() {}