• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2021.Huawei Technologies Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <memory>
17 
18 #include "mindspore/core/utils/log_adapter.h"
19 #include "DvppCommon.h"
20 #include "CommonDataType.h"
21 
__anon51d3ca3b0102(acldvppResizeConfig *p) 22 static auto g_resizeConfigDeleter = [](acldvppResizeConfig *p) { acldvppDestroyResizeConfig(p); };
__anon51d3ca3b0202(acldvppPicDesc *picDesc) 23 static auto g_picDescDeleter = [](acldvppPicDesc *picDesc) { acldvppDestroyPicDesc(picDesc); };
__anon51d3ca3b0302(acldvppRoiConfig *p) 24 static auto g_roiConfigDeleter = [](acldvppRoiConfig *p) { acldvppDestroyRoiConfig(p); };
__anon51d3ca3b0402(acldvppJpegeConfig *p) 25 static auto g_jpegeConfigDeleter = [](acldvppJpegeConfig *p) { acldvppDestroyJpegeConfig(p); };
26 
DvppCommon(aclrtContext dvppContext,aclrtStream dvppStream)27 DvppCommon::DvppCommon(aclrtContext dvppContext, aclrtStream dvppStream)
28     : dvppContext_(dvppContext), dvppStream_(dvppStream) {}
29 
DvppCommon(const VdecConfig & vdecConfig)30 DvppCommon::DvppCommon(const VdecConfig &vdecConfig) : vdecConfig_(vdecConfig) {}
31 
32 /*
33  * @description: Create a channel for processing image data,
34  *               the channel description is created by acldvppCreateChannelDesc
35  * @return: APP_ERR_OK if success, other values if failure
36  */
Init(void)37 APP_ERROR DvppCommon::Init(void) {
38   dvppChannelDesc_ = acldvppCreateChannelDesc();
39   if (dvppChannelDesc_ == nullptr) {
40     return APP_ERR_COMM_INVALID_POINTER;
41   }
42 
43   APP_ERROR ret = acldvppCreateChannel(dvppChannelDesc_);
44   if (ret != APP_ERR_OK) {
45     MS_LOG(ERROR) << "Failed to create dvpp channel: " << GetAppErrCodeInfo(ret) << ".";
46     acldvppDestroyChannelDesc(dvppChannelDesc_);
47     dvppChannelDesc_ = nullptr;
48     return ret;
49   }
50 
51   return APP_ERR_OK;
52 }
53 
54 /*
55  * @description: Create a channel for processing video data,
56  *               the channel description is created by aclvdecCreateChannelDesc
57  * @return: APP_ERR_OK if success, other values if failure
58  */
InitVdec()59 APP_ERROR DvppCommon::InitVdec() {
60   isVdec_ = true;
61   // create vdec channelDesc
62   vdecChannelDesc_ = aclvdecCreateChannelDesc();
63   if (vdecChannelDesc_ == nullptr) {
64     MS_LOG(ERROR) << "Failed to create vdec channel description.";
65     return APP_ERR_ACL_FAILURE;
66   }
67 
68   // channelId: 0-15
69   aclError ret = aclvdecSetChannelDescChannelId(vdecChannelDesc_, vdecConfig_.channelId);
70   if (ret != ACL_ERROR_NONE) {
71     MS_LOG(ERROR) << "Failed to set vdec channel id, ret = " << ret << ".";
72     return APP_ERR_ACL_FAILURE;
73   }
74 
75   ret = aclvdecSetChannelDescThreadId(vdecChannelDesc_, vdecConfig_.threadId);
76   if (ret != ACL_ERROR_NONE) {
77     MS_LOG(ERROR) << "Failed to set thread id, ret = " << ret << ".";
78     return APP_ERR_ACL_FAILURE;
79   }
80 
81   // callback func
82   ret = aclvdecSetChannelDescCallback(vdecChannelDesc_, vdecConfig_.callback);
83   if (ret != ACL_ERROR_NONE) {
84     MS_LOG(ERROR) << "Failed to set vdec callback function, ret = " << ret << ".";
85     return APP_ERR_ACL_FAILURE;
86   }
87 
88   ret = aclvdecSetChannelDescEnType(vdecChannelDesc_, vdecConfig_.inFormat);
89   if (ret != ACL_ERROR_NONE) {
90     MS_LOG(ERROR) << "Failed to set encoded type of input video, ret = " << ret << ".";
91     return APP_ERR_ACL_FAILURE;
92   }
93 
94   ret = aclvdecSetChannelDescOutPicFormat(vdecChannelDesc_, vdecConfig_.outFormat);
95   if (ret != ACL_ERROR_NONE) {
96     MS_LOG(ERROR) << "Failed to set vdec output format, ret = " << ret << ".";
97     return APP_ERR_ACL_FAILURE;
98   }
99 
100   // create vdec channel
101   ret = aclvdecCreateChannel(vdecChannelDesc_);
102   if (ret != ACL_ERROR_NONE) {
103     MS_LOG(ERROR) << "Failed to create vdec channel, ret = " << ret << ".";
104     return APP_ERR_ACL_FAILURE;
105   }
106 
107   MS_LOG(INFO) << "Vdec init resource successfully.";
108   return APP_ERR_OK;
109 }
110 
111 /*
112  * @description: If isVdec_ is true, destroy the channel and the channel description used by video.
113  *               Otherwise destroy the channel and the channel description used by image.
114  * @return: APP_ERR_OK if success, other values if failure
115  */
DeInit(void)116 APP_ERROR DvppCommon::DeInit(void) {
117   if (isVdec_) {
118     return DestroyResource();
119   }
120 
121   // Obtain the dvppContext_ allocated by AscendResource which contains the dvppStream_, they mush bind each other
122   APP_ERROR ret = aclrtSetCurrentContext(dvppContext_);
123   if (ret != APP_ERR_OK) {
124     MS_LOG(ERROR) << "Failed to get ACL context, ret = " << ret;
125     return ret;
126   }
127 
128   ret = aclrtSynchronizeStream(dvppStream_);  // APP_ERROR ret
129   if (ret != APP_ERR_OK) {
130     MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
131     return ret;
132   }
133 
134   ret = acldvppDestroyChannel(dvppChannelDesc_);
135   if (ret != APP_ERR_OK) {
136     MS_LOG(ERROR) << "Failed to destroy dvpp channel, ret = " << ret << ".";
137     return ret;
138   }
139 
140   ret = acldvppDestroyChannelDesc(dvppChannelDesc_);
141   if (ret != APP_ERR_OK) {
142     MS_LOG(ERROR) << "Failed to destroy dvpp channel description, ret = " << ret << ".";
143     return ret;
144   }
145   return APP_ERR_OK;
146 }
147 
148 /*
149  * @description: Destroy the channel and the channel description used by video.
150  * @return: APP_ERR_OK if success, other values if failure
151  */
DestroyResource()152 APP_ERROR DvppCommon::DestroyResource() {
153   APP_ERROR ret = APP_ERR_OK;
154   isVdec_ = true;
155   if (vdecChannelDesc_ != nullptr) {
156     ret = aclvdecDestroyChannel(vdecChannelDesc_);
157     if (ret != APP_ERR_OK) {
158       MS_LOG(ERROR) << "Failed to destroy dvpp channel, ret = " << ret;
159     }
160     aclvdecDestroyChannelDesc(vdecChannelDesc_);
161     vdecChannelDesc_ = nullptr;
162   }
163   return ret;
164 }
165 
166 /*
167  * @description: Release the memory that is allocated in the interfaces which are started with "Combine"
168  */
ReleaseDvppBuffer()169 void DvppCommon::ReleaseDvppBuffer() {
170   if (cropImage_ != nullptr) {
171     RELEASE_DVPP_DATA(cropImage_->data);
172   }
173   if (resizedImage_ != nullptr) {
174     RELEASE_DVPP_DATA(resizedImage_->data);
175   }
176   if (decodedImage_ != nullptr) {
177     RELEASE_DVPP_DATA(decodedImage_->data);
178   }
179   if (inputImage_ != nullptr) {
180     RELEASE_DVPP_DATA(inputImage_->data);
181   }
182   if (encodedImage_ != nullptr) {
183     RELEASE_DVPP_DATA(encodedImage_->data);
184   }
185 }
186 
187 /*
188  * @description: Get the size of buffer used to save image for VPC according to width, height and format
189  * @param  width specifies the width of the output image
190  * @param  height specifies the height of the output image
191  * @param  format specifies the format of the output image
192  * @param: vpcSize is used to save the result size
193  * @return: APP_ERR_OK if success, other values if failure
194  */
GetVpcDataSize(uint32_t width,uint32_t height,acldvppPixelFormat format,uint32_t & vpcSize)195 APP_ERROR DvppCommon::GetVpcDataSize(uint32_t width, uint32_t height, acldvppPixelFormat format, uint32_t &vpcSize) {
196   // Check the invalid format of VPC function and calculate the output buffer size
197   if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420 &&
198       format != PIXEL_FORMAT_RGB_888) {
199     MS_LOG(ERROR) << "Format[" << format << "] for VPC is not supported, just support NV12 or NV21 or RGB888.";
200     return APP_ERR_COMM_INVALID_PARAM;
201   }
202   uint32_t widthStride = DVPP_ALIGN_UP(width, VPC_WIDTH_ALIGN);
203   if (format == PIXEL_FORMAT_RGB_888) {
204     widthStride *= 3;
205   }
206 
207   uint32_t heightStride = DVPP_ALIGN_UP(height, VPC_HEIGHT_ALIGN);
208   vpcSize = widthStride * heightStride * YUV_BGR_SIZE_CONVERT_3 / YUV_BGR_SIZE_CONVERT_2;
209   return APP_ERR_OK;
210 }
211 
212 /*
213  * @description: Get the aligned width and height of the input image according to the image format
214  * @param: width specifies the width before alignment
215  * @param: height specifies the height before alignment
216  * @param: format specifies the image format
217  * @param: widthStride is used to save the width after alignment
218  * @param: heightStride is used to save the height after alignment
219  * @return: APP_ERR_OK if success, other values if failure
220  */
GetVpcInputStrideSize(uint32_t width,uint32_t height,acldvppPixelFormat format,uint32_t & widthStride,uint32_t & heightStride)221 APP_ERROR DvppCommon::GetVpcInputStrideSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
222                                             uint32_t &widthStride, uint32_t &heightStride) {
223   uint32_t inputWidthStride;
224   // Check the invalidty of input format and calculate the input width stride
225   if (format >= PIXEL_FORMAT_YUV_400 && format <= PIXEL_FORMAT_YVU_SEMIPLANAR_444) {
226     // If format is YUV SP, keep widthStride not change.
227     inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH);
228   } else if (format >= PIXEL_FORMAT_YUYV_PACKED_422 && format <= PIXEL_FORMAT_VYUY_PACKED_422) {
229     // If format is YUV422 packed, image size = H x W * 2;
230     inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH) * YUV422_WIDTH_NU;
231   } else if (format >= PIXEL_FORMAT_YUV_PACKED_444 && format <= PIXEL_FORMAT_BGR_888) {
232     // If format is YUV444 packed or RGB, image size = H x W * 3;
233     inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH) * YUV444_RGB_WIDTH_NU;
234   } else if (format >= PIXEL_FORMAT_ARGB_8888 && format <= PIXEL_FORMAT_BGRA_8888) {
235     // If format is XRGB8888, image size = H x W * 4
236     inputWidthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH) * XRGB_WIDTH_NU;
237   } else {
238     MS_LOG(ERROR) << "Input format[" << format << "] for VPC is invalid, please check it.";
239     return APP_ERR_COMM_INVALID_PARAM;
240   }
241   uint32_t inputHeightStride = DVPP_ALIGN_UP(height, VPC_STRIDE_HEIGHT);
242   // Check the input validity width stride.
243   if (inputWidthStride > MAX_RESIZE_WIDTH || inputWidthStride < MIN_RESIZE_WIDTH) {
244     MS_LOG(ERROR) << "Input width stride " << inputWidthStride << " is invalid, not in [" << MIN_RESIZE_WIDTH << ", "
245                   << MAX_RESIZE_WIDTH << "].";
246     return APP_ERR_COMM_INVALID_PARAM;
247   }
248   // Check the input validity height stride.
249   if (inputHeightStride > MAX_RESIZE_HEIGHT || inputHeightStride < MIN_RESIZE_HEIGHT) {
250     MS_LOG(ERROR) << "Input height stride " << inputHeightStride << " is invalid, not in [" << MIN_RESIZE_HEIGHT << ", "
251                   << MAX_RESIZE_HEIGHT << "].";
252     return APP_ERR_COMM_INVALID_PARAM;
253   }
254   widthStride = inputWidthStride;
255   heightStride = inputHeightStride;
256   return APP_ERR_OK;
257 }
258 
259 /*
260  * @description: Get the aligned width and height of the output image according to the image format
261  * @param: width specifies the width before alignment
262  * @param: height specifies the height before alignment
263  * @param: format specifies the image format
264  * @param: widthStride is used to save the width after alignment
265  * @param: heightStride is used to save the height after alignment
266  * @return: APP_ERR_OK if success, other values if failure
267  */
GetVpcOutputStrideSize(uint32_t width,uint32_t height,acldvppPixelFormat format,uint32_t & widthStride,uint32_t & heightStride)268 APP_ERROR DvppCommon::GetVpcOutputStrideSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
269                                              uint32_t &widthStride, uint32_t &heightStride) {
270   // Check the invalidty of output format and calculate the output width and height
271   if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420 &&
272       format != PIXEL_FORMAT_RGB_888) {
273     MS_LOG(ERROR) << "Output format[" << format << "] for VPC is not supported, just support NV12 or NV21 or RGB888.";
274     return APP_ERR_COMM_INVALID_PARAM;
275   }
276 
277   widthStride = DVPP_ALIGN_UP(width, VPC_STRIDE_WIDTH);
278   if (format == PIXEL_FORMAT_RGB_888) {
279     widthStride *= 3;
280   }
281 
282   heightStride = DVPP_ALIGN_UP(height, VPC_STRIDE_HEIGHT);
283   return APP_ERR_OK;
284 }
285 
286 /*
287  * @description: Set picture description information and execute resize function
288  * @param: input specifies the input image information
289  * @param: output specifies the output image information
290  * @param: withSynchronize specifies whether to execute synchronously
291  * @param: processType specifies whether to perform proportional scaling, default is non-proportional resize
292  * @return: APP_ERR_OK if success, other values if failure
293  * @attention: This function can be called only when the DvppCommon object is initialized with Init
294  */
VpcResize(DvppDataInfo & input,DvppDataInfo & output,bool withSynchronize,VpcProcessType processType)295 APP_ERROR DvppCommon::VpcResize(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize,
296                                 VpcProcessType processType) {
297   // Return special error code when the DvppCommon object is initialized with InitVdec
298   if (isVdec_) {
299     MS_LOG(ERROR) << "VpcResize cannot be called by the DvppCommon object which is initialized with InitVdec.";
300     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
301   }
302 
303   acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
304   acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
305   resizeInputDesc_.reset(inputDesc, g_picDescDeleter);
306   resizeOutputDesc_.reset(outputDesc, g_picDescDeleter);
307 
308   // Set dvpp picture descriptin info of input image
309   APP_ERROR ret = SetDvppPicDescData(input, *resizeInputDesc_);
310   if (ret != APP_ERR_OK) {
311     MS_LOG(ERROR) << "Failed to set dvpp input picture description, ret = " << ret << ".";
312     return ret;
313   }
314 
315   // Set dvpp picture descriptin info of output image
316   ret = SetDvppPicDescData(output, *resizeOutputDesc_);
317   if (ret != APP_ERR_OK) {
318     MS_LOG(ERROR) << "Failed to set dvpp output picture description, ret = " << ret << ".";
319     return ret;
320   }
321   if (processType == VPC_PT_DEFAULT) {
322     return ResizeProcess(*resizeInputDesc_, *resizeOutputDesc_, withSynchronize);
323   }
324 
325   // Get crop area according to the processType
326   // When the processType is VPC_PT_FILL, the image will be cropped if the image size is different from the target
327   // resolution
328   CropRoiConfig cropRoi = {0};
329   GetCropRoi(input, output, processType, cropRoi);
330 
331   // The width and height of the original image will be resized by the same ratio
332   // The cropped image will be pasted on the upper left corner or the middle location or the whole location according to
333   // the processType
334   CropRoiConfig pasteRoi = {0};
335   GetPasteRoi(input, output, processType, pasteRoi);
336 
337   return ResizeWithPadding(*resizeInputDesc_, *resizeOutputDesc_, cropRoi, pasteRoi, withSynchronize);
338 }
339 
340 /*
341  * @description: Set image description information
342  * @param: dataInfo specifies the image information
343  * @param: picsDesc specifies the picture description information to be set
344  * @return: APP_ERR_OK if success, other values if failure
345  */
SetDvppPicDescData(const DvppDataInfo & dataInfo,acldvppPicDesc & picDesc)346 APP_ERROR DvppCommon::SetDvppPicDescData(const DvppDataInfo &dataInfo, acldvppPicDesc &picDesc) {
347   APP_ERROR ret = acldvppSetPicDescData(&picDesc, dataInfo.data);
348   if (ret != APP_ERR_OK) {
349     MS_LOG(ERROR) << "Failed to set data for dvpp picture description, ret = " << ret << ".";
350     return ret;
351   }
352   ret = acldvppSetPicDescSize(&picDesc, dataInfo.dataSize);
353   if (ret != APP_ERR_OK) {
354     MS_LOG(ERROR) << "Failed to set size for dvpp picture description, ret = " << ret << ".";
355     return ret;
356   }
357   ret = acldvppSetPicDescFormat(&picDesc, dataInfo.format);
358   if (ret != APP_ERR_OK) {
359     MS_LOG(ERROR) << "Failed to set format for dvpp picture description, ret = " << ret << ".";
360     return ret;
361   }
362   ret = acldvppSetPicDescWidth(&picDesc, dataInfo.width);
363   if (ret != APP_ERR_OK) {
364     MS_LOG(ERROR) << "Failed to set width for dvpp picture description, ret = " << ret << ".";
365     return ret;
366   }
367   ret = acldvppSetPicDescHeight(&picDesc, dataInfo.height);
368   if (ret != APP_ERR_OK) {
369     MS_LOG(ERROR) << "Failed to set height for dvpp picture description, ret = " << ret << ".";
370     return ret;
371   }
372   if (!isVdec_) {
373     ret = acldvppSetPicDescWidthStride(&picDesc, dataInfo.widthStride);
374     if (ret != APP_ERR_OK) {
375       MS_LOG(ERROR) << "Failed to set aligned width for dvpp picture description, ret = " << ret << ".";
376       return ret;
377     }
378     ret = acldvppSetPicDescHeightStride(&picDesc, dataInfo.heightStride);
379     if (ret != APP_ERR_OK) {
380       MS_LOG(ERROR) << "Failed to set aligned height for dvpp picture description, ret = " << ret << ".";
381       return ret;
382     }
383   }
384 
385   return APP_ERR_OK;
386 }
387 
388 /*
389  * @description: Check whether the image format and zoom ratio meet the requirements
390  * @param: input specifies the input image information
391  * @param: output specifies the output image information
392  * @return: APP_ERR_OK if success, other values if failure
393  */
CheckResizeParams(const DvppDataInfo & input,const DvppDataInfo & output)394 APP_ERROR DvppCommon::CheckResizeParams(const DvppDataInfo &input, const DvppDataInfo &output) {
395   if (output.format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && output.format != PIXEL_FORMAT_YVU_SEMIPLANAR_420 &&
396       output.format != PIXEL_FORMAT_RGB_888) {
397     MS_LOG(ERROR) << "Output format[" << output.format << "] for VPC is not supported, only NV12 or NV21 or RGB888.";
398     return APP_ERR_COMM_INVALID_PARAM;
399   }
400   if (((float)output.height / input.height) < MIN_RESIZE_SCALE ||
401       ((float)output.height / input.height) > MAX_RESIZE_SCALE) {
402     MS_LOG(ERROR) << "Resize scale should be in range [1/16, 16], which is " << (output.height / input.height) << ".";
403     return APP_ERR_COMM_INVALID_PARAM;
404   }
405   if (((float)output.width / input.width) < MIN_RESIZE_SCALE ||
406       ((float)output.width / input.width) > MAX_RESIZE_SCALE) {
407     MS_LOG(ERROR) << "Resize scale should be in range [1/16, 16], which is " << (output.width / input.width) << ".";
408     return APP_ERR_COMM_INVALID_PARAM;
409   }
410   return APP_ERR_OK;
411 }
412 
413 /*
414  * @description: Scale the input image to the size specified by the output image and
415  *               saves the result to the output image (non-proportionate scaling)
416  * @param: inputDesc specifies the description information of the input image
417  * @param: outputDesc specifies the description information of the output image
418  * @param: withSynchronize specifies whether to execute synchronously
419  * @return: APP_ERR_OK if success, other values if failure
420  */
ResizeProcess(acldvppPicDesc & inputDesc,acldvppPicDesc & outputDesc,bool withSynchronize)421 APP_ERROR DvppCommon::ResizeProcess(acldvppPicDesc &inputDesc, acldvppPicDesc &outputDesc, bool withSynchronize) {
422   acldvppResizeConfig *resizeConfig = acldvppCreateResizeConfig();
423   if (resizeConfig == nullptr) {
424     MS_LOG(ERROR) << "Failed to create dvpp resize config.";
425     return APP_ERR_COMM_INVALID_POINTER;
426   }
427 
428   resizeConfig_.reset(resizeConfig, g_resizeConfigDeleter);
429   APP_ERROR ret = acldvppVpcResizeAsync(dvppChannelDesc_, &inputDesc, &outputDesc, resizeConfig_.get(), dvppStream_);
430   if (ret != APP_ERR_OK) {
431     MS_LOG(ERROR) << "Failed to resize asynchronously, ret = " << ret << ".";
432     return ret;
433   }
434 
435   if (withSynchronize) {
436     ret = aclrtSynchronizeStream(dvppStream_);
437     if (ret != APP_ERR_OK) {
438       MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
439       return ret;
440     }
441   }
442 
443   return APP_ERR_OK;
444 }
445 
446 /*
447  * @description: Crop the image from the input image based on the specified area and
448  *               paste the cropped image to the specified position of the target image
449  *               as the output image
450  * @param: inputDesc specifies the description information of the input image
451  * @param: outputDesc specifies the description information of the output image
452  * @param: cropRoi specifies the cropped area
453  * @param: pasteRoi specifies the pasting area
454  * @param: withSynchronize specifies whether to execute synchronously
455  * @return: APP_ERR_OK if success, other values if failure
456  * @attention: If the width and height of the crop area are different from those of the
457  *             paste area, the image is scaled again
458  */
ResizeWithPadding(acldvppPicDesc & inputDesc,acldvppPicDesc & outputDesc,CropRoiConfig & cropRoi,CropRoiConfig & pasteRoi,bool withSynchronize)459 APP_ERROR DvppCommon::ResizeWithPadding(acldvppPicDesc &inputDesc, acldvppPicDesc &outputDesc, CropRoiConfig &cropRoi,
460                                         CropRoiConfig &pasteRoi, bool withSynchronize) {
461   acldvppRoiConfig *cropRoiCfg = acldvppCreateRoiConfig(cropRoi.left, cropRoi.right, cropRoi.up, cropRoi.down);
462   if (cropRoiCfg == nullptr) {
463     MS_LOG(ERROR) << "Failed to create dvpp roi config for corp area.";
464     return APP_ERR_COMM_FAILURE;
465   }
466   cropAreaConfig_.reset(cropRoiCfg, g_roiConfigDeleter);
467 
468   acldvppRoiConfig *pastRoiCfg = acldvppCreateRoiConfig(pasteRoi.left, pasteRoi.right, pasteRoi.up, pasteRoi.down);
469   if (pastRoiCfg == nullptr) {
470     MS_LOG(ERROR) << "Failed to create dvpp roi config for paster area.";
471     return APP_ERR_COMM_FAILURE;
472   }
473   pasteAreaConfig_.reset(pastRoiCfg, g_roiConfigDeleter);
474 
475   APP_ERROR ret = acldvppVpcCropAndPasteAsync(dvppChannelDesc_, &inputDesc, &outputDesc, cropAreaConfig_.get(),
476                                               pasteAreaConfig_.get(), dvppStream_);
477   if (ret != APP_ERR_OK) {
478     // release resource.
479     MS_LOG(ERROR) << "Failed to crop and paste asynchronously, ret = " << ret << ".";
480     return ret;
481   }
482   if (withSynchronize) {
483     ret = aclrtSynchronizeStream(dvppStream_);
484     if (ret != APP_ERR_OK) {
485       MS_LOG(ERROR) << "Failed tp synchronize stream, ret = " << ret << ".";
486       return ret;
487     }
488   }
489   return APP_ERR_OK;
490 }
491 
492 /*
493  * @description: Get crop area
494  * @param: input specifies the input image information
495  * @param: output specifies the output image information
496  * @param: processType specifies whether to perform proportional scaling
497  * @param: cropRoi is used to save the info of the crop roi area
498  * @return: APP_ERR_OK if success, other values if failure
499  */
GetCropRoi(const DvppDataInfo & input,const DvppDataInfo & output,VpcProcessType processType,CropRoiConfig & cropRoi)500 void DvppCommon::GetCropRoi(const DvppDataInfo &input, const DvppDataInfo &output, VpcProcessType processType,
501                             CropRoiConfig &cropRoi) {
502   // When processType is not VPC_PT_FILL, crop area is the whole input image
503   if (processType != VPC_PT_FILL) {
504     cropRoi.right = CONVERT_TO_ODD(input.width - ODD_NUM_1);
505     cropRoi.down = CONVERT_TO_ODD(input.height - ODD_NUM_1);
506     return;
507   }
508 
509   bool widthRatioSmaller = true;
510   // The scaling ratio is based on the smaller ratio to ensure the smallest edge to fill the targe edge
511   float resizeRatio = static_cast<float>(input.width) / output.width;
512   if (resizeRatio > (static_cast<float>(input.height) / output.height)) {
513     resizeRatio = static_cast<float>(input.height) / output.height;
514     widthRatioSmaller = false;
515   }
516 
517   const int halfValue = 2;
518   // The left and up must be even, right and down must be odd which is required by acl
519   if (widthRatioSmaller) {
520     cropRoi.left = 0;
521     cropRoi.right = CONVERT_TO_ODD(input.width - ODD_NUM_1);
522     cropRoi.up = CONVERT_TO_EVEN(static_cast<uint32_t>((input.height - output.height * resizeRatio) / halfValue));
523     cropRoi.down = CONVERT_TO_ODD(input.height - cropRoi.up - ODD_NUM_1);
524     return;
525   }
526 
527   cropRoi.up = 0;
528   cropRoi.down = CONVERT_TO_ODD(input.height - ODD_NUM_1);
529   cropRoi.left = CONVERT_TO_EVEN(static_cast<uint32_t>((input.width - output.width * resizeRatio) / halfValue));
530   cropRoi.right = CONVERT_TO_ODD(input.width - cropRoi.left - ODD_NUM_1);
531   return;
532 }
533 
534 /*
535  * @description: Get paste area
536  * @param: input specifies the input image information
537  * @param: output specifies the output image information
538  * @param: processType specifies whether to perform proportional scaling
539  * @param: pasteRio is used to save the info of the paste area
540  * @return: APP_ERR_OK if success, other values if failure
541  */
GetPasteRoi(const DvppDataInfo & input,const DvppDataInfo & output,VpcProcessType processType,CropRoiConfig & pasteRoi)542 void DvppCommon::GetPasteRoi(const DvppDataInfo &input, const DvppDataInfo &output, VpcProcessType processType,
543                              CropRoiConfig &pasteRoi) {
544   if (processType == VPC_PT_FILL) {
545     pasteRoi.right = CONVERT_TO_ODD(output.width - ODD_NUM_1);
546     pasteRoi.down = CONVERT_TO_ODD(output.height - ODD_NUM_1);
547     return;
548   }
549 
550   bool widthRatioLarger = true;
551   // The scaling ratio is based on the larger ratio to ensure the largest edge to fill the targe edge
552   float resizeRatio = static_cast<float>(input.width) / output.width;
553   if (resizeRatio < (static_cast<float>(input.height) / output.height)) {
554     resizeRatio = static_cast<float>(input.height) / output.height;
555     widthRatioLarger = false;
556   }
557 
558   // Left and up is 0 when the roi paste on the upper left corner
559   if (processType == VPC_PT_PADDING) {
560     pasteRoi.right = (input.width / resizeRatio) - ODD_NUM_1;
561     pasteRoi.down = (input.height / resizeRatio) - ODD_NUM_1;
562     pasteRoi.right = CONVERT_TO_ODD(pasteRoi.right);
563     pasteRoi.down = CONVERT_TO_ODD(pasteRoi.down);
564     return;
565   }
566 
567   const int halfValue = 2;
568   // Left and up is 0 when the roi paste on the middler location
569   if (widthRatioLarger) {
570     pasteRoi.left = 0;
571     pasteRoi.right = output.width - ODD_NUM_1;
572     pasteRoi.up = (output.height - (input.height / resizeRatio)) / halfValue;
573     pasteRoi.down = output.height - pasteRoi.up - ODD_NUM_1;
574   } else {
575     pasteRoi.up = 0;
576     pasteRoi.down = output.height - ODD_NUM_1;
577     pasteRoi.left = (output.width - (input.width / resizeRatio)) / halfValue;
578     pasteRoi.right = output.width - pasteRoi.left - ODD_NUM_1;
579   }
580 
581   // The left must be even and align to 16, up must be even, right and down must be odd which is required by acl
582   pasteRoi.left = DVPP_ALIGN_UP(CONVERT_TO_EVEN(pasteRoi.left), VPC_WIDTH_ALIGN);
583   pasteRoi.right = CONVERT_TO_ODD(pasteRoi.right);
584   pasteRoi.up = CONVERT_TO_EVEN(pasteRoi.up);
585   pasteRoi.down = CONVERT_TO_ODD(pasteRoi.down);
586   return;
587 }
588 
589 /*
590  * @description: Resize the image specified by input and save the result to member variable resizedImage_
591  * @param: input specifies the input image information
592  * @param: output specifies the output image information
593  * @param: withSynchronize specifies whether to execute synchronously
594  * @param: processType specifies whether to perform proportional scaling, default is non-proportional resize
595  * @return: APP_ERR_OK if success, other values if failure
596  * @attention: This function can be called only when the DvppCommon object is initialized with Init
597  */
CombineResizeProcess(DvppDataInfo & input,DvppDataInfo & output,bool withSynchronize,VpcProcessType processType)598 APP_ERROR DvppCommon::CombineResizeProcess(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize,
599                                            VpcProcessType processType) {
600   // Return special error code when the DvppCommon object is initialized with InitVdec
601   if (isVdec_) {
602     MS_LOG(ERROR)
603       << "CombineResizeProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
604     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
605   }
606 
607   APP_ERROR ret = CheckResizeParams(input, output);
608   if (ret != APP_ERR_OK) {
609     return ret;
610   }
611   // Get widthStride and heightStride for input and output image according to the format
612   ret =
613     GetVpcInputStrideSize(input.widthStride, input.heightStride, input.format, input.widthStride, input.heightStride);
614   if (ret != APP_ERR_OK) {
615     return ret;
616   }
617 
618   resizedImage_ = std::make_shared<DvppDataInfo>();
619   resizedImage_->width = output.width;
620   resizedImage_->height = output.height;
621   resizedImage_->format = output.format;
622   ret = GetVpcOutputStrideSize(output.width, output.height, output.format, resizedImage_->widthStride,
623                                resizedImage_->heightStride);
624   if (ret != APP_ERR_OK) {
625     return ret;
626   }
627   // Get output buffer size for resize output
628   ret = GetVpcDataSize(output.width, output.height, output.format, resizedImage_->dataSize);
629   if (ret != APP_ERR_OK) {
630     return ret;
631   }
632   // Malloc buffer for output of resize module
633   // Need to pay attention to release of the buffer
634   ret = acldvppMalloc((void **)(&(resizedImage_->data)), resizedImage_->dataSize);
635   if (ret != APP_ERR_OK) {
636     MS_LOG(ERROR) << "Failed to malloc " << resizedImage_->dataSize << " bytes on dvpp for resize, ret = " << ret
637                   << ".";
638     return ret;
639   }
640 
641   aclrtMemset(resizedImage_->data, resizedImage_->dataSize, YUV_GREYER_VALUE, resizedImage_->dataSize);
642   resizedImage_->frameId = input.frameId;
643   ret = VpcResize(input, *resizedImage_, withSynchronize, processType);
644   if (ret != APP_ERR_OK) {
645     // Release the output buffer when resize failed, otherwise release it after use
646     RELEASE_DVPP_DATA(resizedImage_->data);
647   }
648   return ret;
649 }
650 
651 /*
652  * @description: Set picture description information and execute crop function
653  * @param: cropInput specifies the input image information and cropping area
654  * @param: output specifies the output image information
655  * @param: withSynchronize specifies whether to execute synchronously
656  * @return: APP_ERR_OK if success, other values if failure
657  * @attention: This function can be called only when the DvppCommon object is initialized with Init
658  */
VpcCrop(const DvppCropInputInfo & cropInput,const DvppDataInfo & output,bool withSynchronize)659 APP_ERROR DvppCommon::VpcCrop(const DvppCropInputInfo &cropInput, const DvppDataInfo &output, bool withSynchronize) {
660   // Return special error code when the DvppCommon object is initialized with InitVdec
661   if (isVdec_) {
662     MS_LOG(ERROR) << "VpcCrop cannot be called by the DvppCommon object which is initialized with InitVdec.";
663     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
664   }
665 
666   acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
667   acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
668   cropInputDesc_.reset(inputDesc, g_picDescDeleter);
669   cropOutputDesc_.reset(outputDesc, g_picDescDeleter);
670 
671   // Set dvpp picture descriptin info of input image
672   APP_ERROR ret = SetDvppPicDescData(cropInput.dataInfo, *cropInputDesc_);
673   if (ret != APP_ERR_OK) {
674     return ret;
675   }
676   // Set dvpp picture descriptin info of output image
677   ret = SetDvppPicDescData(output, *cropOutputDesc_);
678   if (ret != APP_ERR_OK) {
679     return ret;
680   }
681   return CropProcess(*cropInputDesc_, *cropOutputDesc_, cropInput.roi, withSynchronize);
682 }
683 
684 /*
685  * @description: Check whether the size of the cropped data and the cropped area meet the requirements
686  * @param: input specifies the image information and the information about the area to be cropped
687  * @return: APP_ERR_OK if success, other values if failure
688  */
CheckCropParams(const DvppCropInputInfo & input)689 APP_ERROR DvppCommon::CheckCropParams(const DvppCropInputInfo &input) {
690   APP_ERROR ret;
691   uint32_t payloadSize;
692   ret = GetVpcDataSize(input.dataInfo.widthStride, input.dataInfo.heightStride, PIXEL_FORMAT_YUV_SEMIPLANAR_420,
693                        payloadSize);
694   if (ret != APP_ERR_OK) {
695     return ret;
696   }
697   if (payloadSize != input.dataInfo.dataSize) {
698     MS_LOG(ERROR) << "Input data size: " << payloadSize
699                   << " to crop does not match input yuv image size: " << input.dataInfo.dataSize << ".";
700     return APP_ERR_COMM_INVALID_PARAM;
701   }
702 
703   if ((!CHECK_EVEN(input.roi.left)) || (!CHECK_EVEN(input.roi.up)) || (!CHECK_ODD(input.roi.right)) ||
704       (!CHECK_ODD(input.roi.down))) {
705     MS_LOG(ERROR) << "Crop area left and top(" << input.roi.left << ", " << input.roi.up
706                   << ") must be even, right bottom(" << input.roi.right << "," << input.roi.down << ") must be odd.";
707     return APP_ERR_COMM_INVALID_PARAM;
708   }
709 
710   // Calculate crop width and height according to the input location
711   uint32_t cropWidth = input.roi.right - input.roi.left + ODD_NUM_1;
712   uint32_t cropHeight = input.roi.down - input.roi.up + ODD_NUM_1;
713   if ((cropWidth < MIN_CROP_WIDTH) || (cropHeight < MIN_CROP_HEIGHT)) {
714     MS_LOG(ERROR) << "Crop area width:" << cropWidth << " need to be larger than 10 and height:" << cropHeight
715                   << " need to be larger than 6.";
716     return APP_ERR_COMM_INVALID_PARAM;
717   }
718 
719   if ((input.roi.left + cropWidth > input.dataInfo.width) || (input.roi.up + cropHeight > input.dataInfo.height)) {
720     MS_LOG(ERROR) << "Target rectangle start location(" << input.roi.left << "," << input.roi.up << ") with size("
721                   << cropWidth << "," << cropHeight << ") is out of the input image(" << input.dataInfo.width << ","
722                   << input.dataInfo.height << ") to be cropped.";
723     return APP_ERR_COMM_INVALID_PARAM;
724   }
725 
726   return APP_ERR_OK;
727 }
728 
729 /*
730  * @description: It is used to crop an input image based on a specified region and
731  *               store the cropped image to the output memory as an output image
732  * @param: inputDesc specifies the description information of the input image
733  * @param: outputDesc specifies the description information of the output image
734  * @param: CropRoiConfig specifies the cropped area
735  * @param: withSynchronize specifies whether to execute synchronously
736  * @return: APP_ERR_OK if success, other values if failure
737  * @attention: if the region of the output image is inconsistent with the crop area, the image is scaled again
738  */
CropProcess(acldvppPicDesc & inputDesc,acldvppPicDesc & outputDesc,const CropRoiConfig & cropArea,bool withSynchronize)739 APP_ERROR DvppCommon::CropProcess(acldvppPicDesc &inputDesc, acldvppPicDesc &outputDesc, const CropRoiConfig &cropArea,
740                                   bool withSynchronize) {
741   uint32_t leftOffset = CONVERT_TO_EVEN(cropArea.left);
742   uint32_t rightOffset = CONVERT_TO_ODD(cropArea.right);
743   uint32_t upOffset = CONVERT_TO_EVEN(cropArea.up);
744   uint32_t downOffset = CONVERT_TO_ODD(cropArea.down);
745 
746   auto cropRioCfg = acldvppCreateRoiConfig(leftOffset, rightOffset, upOffset, downOffset);
747   if (cropRioCfg == nullptr) {
748     MS_LOG(ERROR) << "DvppCommon: create dvpp vpc resize failed.";
749     return APP_ERR_DVPP_RESIZE_FAIL;
750   }
751   cropRoiConfig_.reset(cropRioCfg, g_roiConfigDeleter);
752 
753   APP_ERROR ret = acldvppVpcCropAsync(dvppChannelDesc_, &inputDesc, &outputDesc, cropRoiConfig_.get(), dvppStream_);
754   if (ret != APP_ERR_OK) {
755     // release resource.
756     MS_LOG(ERROR) << "Failed to crop, ret = " << ret << ".";
757     return ret;
758   }
759   if (withSynchronize) {
760     ret = aclrtSynchronizeStream(dvppStream_);
761     if (ret != APP_ERR_OK) {
762       MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
763       return ret;
764     }
765   }
766   return APP_ERR_OK;
767 }
768 
769 /*
770  * @description: Crop the image specified by the input parameter and saves the result to member variable cropImage_
771  * @param: input specifies the input image information and cropping area
772  * @param: output specifies the output image information
773  * @param: withSynchronize specifies whether to execute synchronously
774  * @return: APP_ERR_OK if success, other values if failure
775  * @attention: This function can be called only when the DvppCommon object is initialized with Init
776  */
CombineCropProcess(DvppCropInputInfo & input,DvppDataInfo & output,bool withSynchronize)777 APP_ERROR DvppCommon::CombineCropProcess(DvppCropInputInfo &input, DvppDataInfo &output, bool withSynchronize) {
778   // Return special error code when the DvppCommon object is initialized with InitVdec
779   if (isVdec_) {
780     MS_LOG(ERROR) << "CombineCropProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
781     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
782   }
783 
784   // Get widthStride and heightStride for input and output image according to the format
785   APP_ERROR ret = GetVpcInputStrideSize(input.dataInfo.width, input.dataInfo.height, input.dataInfo.format,
786                                         input.dataInfo.widthStride, input.dataInfo.heightStride);
787   if (ret != APP_ERR_OK) {
788     return ret;
789   }
790   ret = CheckCropParams(input);
791   if (ret != APP_ERR_OK) {
792     return ret;
793   }
794   // cropImage_所持有的成员变量 uint8_t *data通过acldvppMalloc()接口申请,位于Device上
795   cropImage_ = std::make_shared<DvppDataInfo>();
796   cropImage_->width = output.width;
797   cropImage_->height = output.height;
798   cropImage_->format = output.format;
799   ret = GetVpcOutputStrideSize(output.width, output.height, output.format, cropImage_->widthStride,
800                                cropImage_->heightStride);
801   if (ret != APP_ERR_OK) {
802     return ret;
803   }
804   // Get output buffer size for resize output
805   ret = GetVpcDataSize(output.width, output.height, output.format, cropImage_->dataSize);
806   if (ret != APP_ERR_OK) {
807     return ret;
808   }
809 
810   // Malloc buffer for output of resize module
811   // Need to pay attention to release of the buffer
812   ret = acldvppMalloc((void **)(&(cropImage_->data)), cropImage_->dataSize);
813   if (ret != APP_ERR_OK) {
814     MS_LOG(ERROR) << "Failed to malloc " << cropImage_->dataSize << " bytes on dvpp for resize, ret = " << ret << ".";
815     return ret;
816   }
817   cropImage_->frameId = input.dataInfo.frameId;
818   ret = VpcCrop(input, *cropImage_, withSynchronize);
819   if (ret != APP_ERR_OK) {
820     // Release the output buffer when resize failed, otherwise release it after use
821     RELEASE_DVPP_DATA(cropImage_->data);
822   }
823   return ret;
824 }
825 
826 /*
827  * @description: Set the description of the output image and decode
828  * @param: input specifies the input image information
829  * @param: output specifies the output image information
830  * @param: withSynchronize specifies whether to execute synchronously
831  * @return: APP_ERR_OK if success, other values if failure
832  * @attention: This function can be called only when the DvppCommon object is initialized with Init
833  */
JpegDecode(DvppDataInfo & input,DvppDataInfo & output,bool withSynchronize)834 APP_ERROR DvppCommon::JpegDecode(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize) {
835   // Return special error code when the DvppCommon object is initialized with InitVdec
836   if (isVdec_) {
837     MS_LOG(ERROR) << "JpegDecode cannot be called by the DvppCommon object which is initialized with InitVdec.";
838     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
839   }
840 
841   acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
842   decodeOutputDesc_.reset(outputDesc, g_picDescDeleter);
843 
844   APP_ERROR ret = SetDvppPicDescData(output, *decodeOutputDesc_);
845   if (ret != APP_ERR_OK) {
846     return ret;
847   }
848 
849   ret = acldvppJpegDecodeAsync(dvppChannelDesc_, input.data, input.dataSize, decodeOutputDesc_.get(), dvppStream_);
850   if (ret != APP_ERR_OK) {
851     MS_LOG(ERROR) << "Failed to decode jpeg, ret = " << ret << ".";
852     return ret;
853   }
854   if (withSynchronize) {
855     ret = aclrtSynchronizeStream(dvppStream_);
856     if (ret != APP_ERR_OK) {
857       MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
858       return APP_ERR_DVPP_JPEG_DECODE_FAIL;
859     }
860   }
861   return APP_ERR_OK;
862 }
863 
864 /*
865  * @description: Set the description of the output image and decode
866  * @param: input specifies the input image information
867  * @param: output specifies the output image information
868  * @param: withSynchronize specifies whether to execute synchronously
869  * @return: APP_ERR_OK if success, other values if failure
870  * @attention: This function can be called only when the DvppCommon object is initialized with Init
871  */
PngDecode(DvppDataInfo & input,DvppDataInfo & output,bool withSynchronize)872 APP_ERROR DvppCommon::PngDecode(DvppDataInfo &input, DvppDataInfo &output, bool withSynchronize) {
873   // Return special error code when the DvppCommon object is initialized with InitVdec
874   if (isVdec_) {
875     MS_LOG(ERROR) << "PngDecode cannot be called by the DvppCommon object which is initialized with InitVdec.";
876     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
877   }
878 
879   acldvppPicDesc *outputDesc = acldvppCreatePicDesc();
880   decodeOutputDesc_.reset(outputDesc, g_picDescDeleter);
881 
882   APP_ERROR ret = SetDvppPicDescData(output, *decodeOutputDesc_);
883   if (ret != APP_ERR_OK) {
884     return ret;
885   }
886 
887   ret = acldvppPngDecodeAsync(dvppChannelDesc_, input.data, input.dataSize, decodeOutputDesc_.get(), dvppStream_);
888   if (ret != APP_ERR_OK) {
889     MS_LOG(ERROR) << "Failed to decode png, ret = " << ret << ".";
890     return ret;
891   }
892   if (withSynchronize) {
893     ret = aclrtSynchronizeStream(dvppStream_);
894     if (ret != APP_ERR_OK) {
895       MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
896       return APP_ERR_DVPP_JPEG_DECODE_FAIL;
897     }
898   }
899   return APP_ERR_OK;
900 }
901 
902 /*
903  * @description: Get the aligned width and height of the image after decoding
904  * @param: width specifies the width before alignment
905  * @param: height specifies the height before alignment
906  * @param: widthStride is used to save the width after alignment
907  * @param: heightStride is used to save the height after alignment
908  * @return: APP_ERR_OK if success, other values if failure
909  */
GetJpegDecodeStrideSize(uint32_t width,uint32_t height,uint32_t & widthStride,uint32_t & heightStride)910 void DvppCommon::GetJpegDecodeStrideSize(uint32_t width, uint32_t height, uint32_t &widthStride,
911                                          uint32_t &heightStride) {
912   widthStride = DVPP_ALIGN_UP(width, JPEGD_STRIDE_WIDTH);
913   heightStride = DVPP_ALIGN_UP(height, JPEGD_STRIDE_HEIGHT);
914 }
915 
GetPngDecodeStrideSize(uint32_t width,uint32_t height,uint32_t & widthStride,uint32_t & heightStride,acldvppPixelFormat format)916 void DvppCommon::GetPngDecodeStrideSize(uint32_t width, uint32_t height, uint32_t &widthStride, uint32_t &heightStride,
917                                         acldvppPixelFormat format) {
918   if (format == PIXEL_FORMAT_RGB_888) {
919     widthStride = DVPP_ALIGN_UP(width * 3, JPEGD_STRIDE_WIDTH);
920     heightStride = DVPP_ALIGN_UP(height, JPEGD_STRIDE_HEIGHT);
921   } else {
922     widthStride = DVPP_ALIGN_UP(width * 4, JPEGD_STRIDE_WIDTH);
923     heightStride = DVPP_ALIGN_UP(height, JPEGD_STRIDE_HEIGHT);
924   }
925 }
926 
927 /*
928  * @description: Get picture width and height and number of channels from image data
929  * @param: data specifies the memory to store the image data
930  * @param: dataSize specifies the size of the image data
931  * @param: width is used to save the image width
932  * @param: height is used to save the image height
933  * @param: components is used to save the number of channels
934  * @return: APP_ERR_OK if success, other values if failure
935  */
GetJpegImageInfo(const void * data,uint32_t dataSize,uint32_t & width,uint32_t & height,int32_t & components)936 APP_ERROR DvppCommon::GetJpegImageInfo(const void *data, uint32_t dataSize, uint32_t &width, uint32_t &height,
937                                        int32_t &components) {
938   uint32_t widthTmp;
939   uint32_t heightTmp;
940   int32_t componentsTmp;
941   APP_ERROR ret = acldvppJpegGetImageInfo(data, dataSize, &widthTmp, &heightTmp, &componentsTmp);
942   if (ret != APP_ERR_OK) {
943     MS_LOG(ERROR) << "Failed to get image info of jpeg, ret = " << ret << ".";
944     return ret;
945   }
946   if (widthTmp > MAX_JPEGD_WIDTH || widthTmp < MIN_JPEGD_WIDTH) {
947     MS_LOG(ERROR) << "Input width is invalid, not in [" << MIN_JPEGD_WIDTH << ", " << MAX_JPEGD_WIDTH << "].";
948     return APP_ERR_COMM_INVALID_PARAM;
949   }
950   if (heightTmp > MAX_JPEGD_HEIGHT || heightTmp < MIN_JPEGD_HEIGHT) {
951     MS_LOG(ERROR) << "Input height is invalid, not in [" << MIN_JPEGD_HEIGHT << ", " << MAX_JPEGD_HEIGHT << "].";
952     return APP_ERR_COMM_INVALID_PARAM;
953   }
954   width = widthTmp;
955   height = heightTmp;
956   components = componentsTmp;
957   return APP_ERR_OK;
958 }
959 
960 /*
961  * @description: Get picture width and height and number of channels from PNG image data
962  * @param: data specifies the memory to store the image data
963  * @param: dataSize specifies the size of the image data
964  * @param: width is used to save the image width
965  * @param: height is used to save the image height
966  * @param: components is used to save the number of channels
967  * @return: APP_ERR_OK if success, other values if failure
968  */
GetPngImageInfo(const void * data,uint32_t dataSize,uint32_t & width,uint32_t & height,int32_t & components)969 APP_ERROR DvppCommon::GetPngImageInfo(const void *data, uint32_t dataSize, uint32_t &width, uint32_t &height,
970                                       int32_t &components) {
971   uint32_t widthTmp;
972   uint32_t heightTmp;
973   int32_t componentsTmp;
974   APP_ERROR ret = acldvppPngGetImageInfo(data, dataSize, &widthTmp, &heightTmp, &componentsTmp);
975   if (ret != APP_ERR_OK) {
976     MS_LOG(ERROR) << "Failed to get image info of PNG, ret = " << ret << ".";
977     return ret;
978   }
979   if (widthTmp > MAX_PNGD_WIDTH || widthTmp < MIN_PNGD_WIDTH) {
980     MS_LOG(ERROR) << "Input width is invalid, not in [" << MIN_PNGD_WIDTH << ", " << MAX_PNGD_WIDTH << "].";
981     return APP_ERR_COMM_INVALID_PARAM;
982   }
983   if (heightTmp > MAX_PNGD_HEIGHT || heightTmp < MIN_PNGD_HEIGHT) {
984     MS_LOG(ERROR) << "Input height is invalid, not in [" << MIN_PNGD_HEIGHT << ", " << MAX_PNGD_HEIGHT << "].";
985     return APP_ERR_COMM_INVALID_PARAM;
986   }
987   width = widthTmp;
988   height = heightTmp;
989   components = componentsTmp;
990   return APP_ERR_OK;
991 }
992 
993 /*
994  * @description: Get the size of the buffer for storing decoded images based on the image data, size, and format
995  * @param: data specifies the memory to store the image data
996  * @param: dataSize specifies the size of the image data
997  * @param: format specifies the image format
998  * @param: decSize is used to store the result size
999  * @return: APP_ERR_OK if success, other values if failure
1000  */
GetJpegDecodeDataSize(const void * data,uint32_t dataSize,acldvppPixelFormat format,uint32_t & decSize)1001 APP_ERROR DvppCommon::GetJpegDecodeDataSize(const void *data, uint32_t dataSize, acldvppPixelFormat format,
1002                                             uint32_t &decSize) {
1003   uint32_t outputSize;
1004   APP_ERROR ret = acldvppJpegPredictDecSize(data, dataSize, format, &outputSize);
1005   if (ret != APP_ERR_OK) {
1006     MS_LOG(ERROR) << "Failed to predict decode size of jpeg image, ret = " << ret << ".";
1007     return ret;
1008   }
1009   decSize = outputSize;
1010   return APP_ERR_OK;
1011 }
1012 
1013 /*
1014  * @description: Get the size of the buffer for storing decoded images based on the PNG image data, size, and format
1015  * @param: data specifies the memory to store the image data
1016  * @param: dataSize specifies the size of the image data
1017  * @param: format specifies the image format
1018  * @param: decSize is used to store the result size
1019  * @return: APP_ERR_OK if success, other values if failure
1020  */
GetPngDecodeDataSize(const void * data,uint32_t dataSize,acldvppPixelFormat format,uint32_t & decSize)1021 APP_ERROR DvppCommon::GetPngDecodeDataSize(const void *data, uint32_t dataSize, acldvppPixelFormat format,
1022                                            uint32_t &decSize) {
1023   uint32_t outputSize;
1024   APP_ERROR ret = acldvppPngPredictDecSize(data, dataSize, format, &outputSize);
1025   if (ret != APP_ERR_OK) {
1026     MS_LOG(ERROR) << "Failed to predict decode size of png image, ret = " << ret << ".";
1027     return ret;
1028   }
1029   decSize = outputSize;
1030   return APP_ERR_OK;
1031 }
1032 
1033 /*
1034  * @description: Decode the image specified by imageInfo and save the result to member variable decodedImage_
1035  * @param: imageInfo specifies image information
1036  * @param: format specifies the image format
1037  * @param: withSynchronize specifies whether to execute synchronously
1038  * @return: APP_ERR_OK if success, other values if failure
1039  * @attention: This function can be called only when the DvppCommon object is initialized with Init
1040  */
CombineJpegdProcess(const RawData & imageInfo,acldvppPixelFormat format,bool withSynchronize)1041 APP_ERROR DvppCommon::CombineJpegdProcess(const RawData &imageInfo, acldvppPixelFormat format, bool withSynchronize) {
1042   // Return special error code when the DvppCommon object is initialized with InitVdec
1043   if (isVdec_) {
1044     MS_LOG(ERROR)
1045       << "CombineJpegdProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
1046     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1047   }
1048 
1049   int32_t components;
1050   // Member variable of inputImage_, uint8_t *data will be on device
1051   inputImage_ = std::make_shared<DvppDataInfo>();
1052   inputImage_->format = format;
1053   APP_ERROR ret =
1054     GetJpegImageInfo(imageInfo.data, imageInfo.lenOfByte, inputImage_->width, inputImage_->height, components);
1055   if (ret != APP_ERR_OK) {
1056     MS_LOG(ERROR) << "Failed to get input image info, ret = " << ret << ".";
1057     return ret;
1058   }
1059 
1060   // Get the buffer size(On device) of decode output according to the input data and output format
1061   uint32_t outBuffSize;
1062   // ret = GetJpegDecodeDataSize(imageInfo.data.get(), imageInfo.lenOfByte, format, outBuffSize);
1063   ret = GetJpegDecodeDataSize(imageInfo.data, imageInfo.lenOfByte, format, outBuffSize);
1064   if (ret != APP_ERR_OK) {
1065     MS_LOG(ERROR) << "Failed to get size of decode output buffer, ret = " << ret << ".";
1066     return ret;
1067   }
1068 
1069   // In TransferImageH2D function, device buffer will be allocated to store the input image before decode
1070   // Need to pay attention to release of the buffer
1071   ret = TransferImageH2D(imageInfo, inputImage_);
1072   if (ret != APP_ERR_OK) {
1073     return ret;
1074   }
1075 
1076   decodedImage_ = std::make_shared<DvppDataInfo>();
1077   decodedImage_->format = format;
1078   decodedImage_->width = inputImage_->width;
1079   decodedImage_->height = inputImage_->height;
1080   GetJpegDecodeStrideSize(inputImage_->width, inputImage_->height, decodedImage_->widthStride,
1081                           decodedImage_->heightStride);
1082   decodedImage_->dataSize = outBuffSize;
1083   // Malloc dvpp buffer to store the output data after decoding
1084   // Need to pay attention to release of the buffer
1085   ret = acldvppMalloc((void **)&decodedImage_->data, decodedImage_->dataSize);
1086   if (ret != APP_ERR_OK) {
1087     MS_LOG(ERROR) << "Failed to malloc memory on dvpp, ret = " << ret << ".";
1088     RELEASE_DVPP_DATA(inputImage_->data);
1089     return ret;
1090   }
1091 
1092   ret = JpegDecode(*inputImage_, *decodedImage_, withSynchronize);
1093   if (ret != APP_ERR_OK) {
1094     // Release the output buffer when decode failed, otherwise release it after use
1095     RELEASE_DVPP_DATA(inputImage_->data);
1096     inputImage_->data = nullptr;
1097     RELEASE_DVPP_DATA(decodedImage_->data);
1098     decodedImage_->data = nullptr;
1099     return ret;
1100   }
1101 
1102   return APP_ERR_OK;
1103 }
1104 
SinkCombineJpegdProcess(std::shared_ptr<DvppDataInfo> & input,std::shared_ptr<DvppDataInfo> & output,bool withSynchronize)1105 APP_ERROR DvppCommon::SinkCombineJpegdProcess(std::shared_ptr<DvppDataInfo> &input,
1106                                               std::shared_ptr<DvppDataInfo> &output, bool withSynchronize) {
1107   // Both input and output are locate on device, so we must release them if fail in decode
1108   APP_ERROR ret = JpegDecode(*input, *output, withSynchronize);
1109   if (ret != APP_ERR_OK) {
1110     // Release the output buffer when decode failed, otherwise release it after use
1111     RELEASE_DVPP_DATA(inputImage_->data);
1112     inputImage_->data = nullptr;
1113     RELEASE_DVPP_DATA(decodedImage_->data);
1114     decodedImage_->data = nullptr;
1115     return ret;
1116   }
1117   return APP_ERR_OK;
1118 }
1119 
SinkCombinePngdProcess(std::shared_ptr<DvppDataInfo> & input,std::shared_ptr<DvppDataInfo> & output,bool withSynchronize)1120 APP_ERROR DvppCommon::SinkCombinePngdProcess(std::shared_ptr<DvppDataInfo> &input,
1121                                              std::shared_ptr<DvppDataInfo> &output, bool withSynchronize) {
1122   // Both input and output are locate on device, so we must release them if fail in decode
1123   APP_ERROR ret = PngDecode(*input, *output, withSynchronize);
1124   if (ret != APP_ERR_OK) {
1125     // Release the output buffer when decode failed, otherwise release it after use
1126     RELEASE_DVPP_DATA(inputImage_->data);
1127     inputImage_->data = nullptr;
1128     RELEASE_DVPP_DATA(decodedImage_->data);
1129     decodedImage_->data = nullptr;
1130     return ret;
1131   }
1132   return APP_ERR_OK;
1133 }
1134 
1135 /*
1136  * @description: Decode the image specified by imageInfo and save the result to member variable decodedImage_
1137  * This function is for PNG format image
1138  * @param: imageInfo specifies image information
1139  * @param: format specifies the image format
1140  * @param: withSynchronize specifies whether to execute synchronously
1141  * @return: APP_ERR_OK if success, other values if failure
1142  * @attention: This function can be called only when the DvppCommon object is initialized with Init
1143  */
CombinePngdProcess(const RawData & imageInfo,acldvppPixelFormat format,bool withSynchronize)1144 APP_ERROR DvppCommon::CombinePngdProcess(const RawData &imageInfo, acldvppPixelFormat format, bool withSynchronize) {
1145   // Return special error code when the DvppCommon object is initialized with InitVdec
1146   if (isVdec_) {
1147     MS_LOG(ERROR) << "CombinePngdProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
1148     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1149   }
1150 
1151   int32_t components;
1152   inputImage_ = std::make_shared<DvppDataInfo>();
1153   inputImage_->format = format;
1154   APP_ERROR ret =
1155     GetPngImageInfo(imageInfo.data, imageInfo.lenOfByte, inputImage_->width, inputImage_->height, components);
1156   if (ret != APP_ERR_OK) {
1157     MS_LOG(ERROR) << "Failed to get input image info, ret = " << ret << ".";
1158     return ret;
1159   }
1160 
1161   // Get the buffer size of decode output according to the input data and output format
1162   uint32_t outBuffSize;
1163   // ret = GetJpegDecodeDataSize(imageInfo.data.get(), imageInfo.lenOfByte, format, outBuffSize);
1164   ret = GetPngDecodeDataSize(imageInfo.data, imageInfo.lenOfByte, format, outBuffSize);
1165   if (ret != APP_ERR_OK) {
1166     MS_LOG(ERROR) << "Failed to get size of decode output buffer, ret = " << ret << ".";
1167     return ret;
1168   }
1169 
1170   // In TransferImageH2D function, device buffer will be allocated to store the input image
1171   // Need to pay attention to release of the buffer
1172   ret = TransferImageH2D(imageInfo, inputImage_);
1173   if (ret != APP_ERR_OK) {
1174     return ret;
1175   }
1176 
1177   decodedImage_ = std::make_shared<DvppDataInfo>();
1178   decodedImage_->format = format;
1179   decodedImage_->width = inputImage_->width;
1180   decodedImage_->height = inputImage_->height;
1181   GetPngDecodeStrideSize(inputImage_->width, inputImage_->height, decodedImage_->widthStride,
1182                          decodedImage_->heightStride, format);
1183   decodedImage_->dataSize = outBuffSize;
1184   // Malloc dvpp buffer to store the output data after decoding
1185   // Need to pay attention to release of the buffer
1186   ret = acldvppMalloc((void **)&decodedImage_->data, decodedImage_->dataSize);
1187   if (ret != APP_ERR_OK) {
1188     MS_LOG(ERROR) << "Failed to malloc memory on dvpp, ret = " << ret << ".";
1189     RELEASE_DVPP_DATA(inputImage_->data);
1190     return ret;
1191   }
1192   ret = PngDecode(*inputImage_, *decodedImage_, withSynchronize);
1193   if (ret != APP_ERR_OK) {
1194     // Release the output buffer when decode failed, otherwise release it after use
1195     RELEASE_DVPP_DATA(inputImage_->data);
1196     inputImage_->data = nullptr;
1197     RELEASE_DVPP_DATA(decodedImage_->data);
1198     decodedImage_->data = nullptr;
1199     return ret;
1200   }
1201 
1202   return APP_ERR_OK;
1203 }
1204 
1205 /*
1206  * @description: Transfer data from host to device
1207  * @param: imageInfo specifies the image data on the host
1208  * @return: APP_ERR_OK if success, other values if failure
1209  */
TransferYuvDataH2D(const DvppDataInfo & imageinfo)1210 APP_ERROR DvppCommon::TransferYuvDataH2D(const DvppDataInfo &imageinfo) {
1211   if (imageinfo.dataSize <= 0) {
1212     MS_LOG(ERROR) << "The input buffer size on host should not be empty.";
1213     return APP_ERR_COMM_INVALID_PARAM;
1214   }
1215   uint8_t *device_ptr = nullptr;
1216   APP_ERROR ret = acldvppMalloc((void **)&device_ptr, imageinfo.dataSize);
1217   if (ret != APP_ERR_OK) {
1218     MS_LOG(ERROR) << "Failed to malloc " << imageinfo.dataSize << " bytes on dvpp, ret = " << ret << ".";
1219     return ret;
1220   }
1221   ret = aclrtMemcpyAsync(device_ptr, imageinfo.dataSize, imageinfo.data, imageinfo.dataSize, ACL_MEMCPY_HOST_TO_DEVICE,
1222                          dvppStream_);
1223   if (ret != APP_ERR_OK) {
1224     MS_LOG(ERROR) << "Failed to copy " << imageinfo.dataSize << " bytes from host to device, ret = " << ret << ".";
1225     RELEASE_DVPP_DATA(device_ptr);
1226     return ret;
1227   }
1228   ret = aclrtSynchronizeStream(dvppStream_);
1229   if (ret != APP_ERR_OK) {
1230     MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
1231     RELEASE_DVPP_DATA(device_ptr);
1232     return ret;
1233   }
1234   /* Important!!! decodedImage_ speifies the image in decoded format(RGB OR YUV)
1235    * Not essentially to be the image after decode.(Specifies the data not in RAW encode format)
1236    * It can also be the image after resize(Very important)
1237    */
1238   decodedImage_ = std::make_shared<DvppDataInfo>();
1239   decodedImage_->data = device_ptr;
1240   decodedImage_->dataSize = imageinfo.dataSize;
1241   decodedImage_->height = imageinfo.height;
1242   decodedImage_->heightStride = imageinfo.heightStride;
1243   decodedImage_->width = imageinfo.width;
1244   decodedImage_->widthStride = imageinfo.widthStride;
1245   return APP_ERR_OK;
1246 }
1247 
1248 /*
1249  * @description: Transfer data from host to device
1250  * @param: imageInfo specifies the image data on the host
1251  * @param: jpegInput is used to save the buffer and its size which is allocate on the device
1252  * @return: APP_ERR_OK if success, other values if failure
1253  */
TransferImageH2D(const RawData & imageInfo,const std::shared_ptr<DvppDataInfo> & jpegInput)1254 APP_ERROR DvppCommon::TransferImageH2D(const RawData &imageInfo, const std::shared_ptr<DvppDataInfo> &jpegInput) {
1255   // Check image buffer size validity
1256   if (imageInfo.lenOfByte <= 0) {
1257     MS_LOG(ERROR) << "The input buffer size on host should not be empty.";
1258     return APP_ERR_COMM_INVALID_PARAM;
1259   }
1260 
1261   uint8_t *inDevBuff = nullptr;  // This pointer will be on device
1262   APP_ERROR ret = acldvppMalloc((void **)&inDevBuff, imageInfo.lenOfByte);
1263   if (ret != APP_ERR_OK) {
1264     MS_LOG(ERROR) << "Failed to malloc " << imageInfo.lenOfByte << " bytes on dvpp, ret = " << ret << ".";
1265     return ret;
1266   }
1267 
1268   // Copy the image data from host to device
1269   ret = aclrtMemcpyAsync(inDevBuff, imageInfo.lenOfByte, imageInfo.data, imageInfo.lenOfByte, ACL_MEMCPY_HOST_TO_DEVICE,
1270                          dvppStream_);
1271   if (ret != APP_ERR_OK) {
1272     MS_LOG(ERROR) << "Failed to copy " << imageInfo.lenOfByte << " bytes from host to device, ret = " << ret << ".";
1273     RELEASE_DVPP_DATA(inDevBuff);
1274     return ret;
1275   }
1276   // Attention: We must call the aclrtSynchronizeStream to ensure the task of memory replication has been completed
1277   // after calling aclrtMemcpyAsync
1278   ret = aclrtSynchronizeStream(dvppStream_);
1279   if (ret != APP_ERR_OK) {
1280     MS_LOG(ERROR) << "Failed to synchronize stream, ret = " << ret << ".";
1281     RELEASE_DVPP_DATA(inDevBuff);
1282     return ret;
1283   }
1284   jpegInput->data = inDevBuff;
1285   jpegInput->dataSize = imageInfo.lenOfByte;
1286   return APP_ERR_OK;
1287 }
1288 
1289 /*
1290  * Sink RawData(On host) into DvppDataInfo(On device)
1291  */
SinkImageH2D(const RawData & imageInfo,acldvppPixelFormat format)1292 APP_ERROR DvppCommon::SinkImageH2D(const RawData &imageInfo, acldvppPixelFormat format) {
1293   if (isVdec_) {
1294     MS_LOG(ERROR)
1295       << "CombineJpegdProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
1296     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1297   }
1298 
1299   APP_ERROR ret = aclrtSetCurrentContext(dvppContext_);
1300   if (ret != APP_ERR_OK) {
1301     MS_LOG(ERROR) << "Failed to get ACL context, ret = " << ret;
1302     return ret;
1303   }
1304 
1305   int32_t components;
1306   // Member variable of inputImage_, uint8_t *data will be on device
1307   inputImage_ = std::make_shared<DvppDataInfo>();
1308   inputImage_->format = format;
1309   ret = GetJpegImageInfo(imageInfo.data, imageInfo.lenOfByte, inputImage_->width, inputImage_->height, components);
1310 
1311   if (ret != APP_ERR_OK) {
1312     MS_LOG(ERROR) << "Failed to get input image info, ret = " << ret << ".";
1313     return ret;
1314   }
1315 
1316   // Get the buffer size(On device) of decode output according to the input data and output format
1317   uint32_t outBufferSize;
1318 
1319   ret = GetJpegDecodeDataSize(imageInfo.data, imageInfo.lenOfByte, format, outBufferSize);
1320   if (ret != APP_ERR_OK) {
1321     MS_LOG(ERROR) << "Failed to get size of decode output buffer, ret = " << ret << ".";
1322     return ret;
1323   }
1324   // In TransferImageH2D function, device buffer will be allocated to store the input image before decode
1325   // Need to pay attention to release of the buffer
1326   ret = TransferImageH2D(imageInfo, inputImage_);
1327   if (ret != APP_ERR_OK) {
1328     return ret;
1329   }
1330   // This part is to define the data after decode (MALLOC ON DEVICE!!)
1331   decodedImage_ = std::make_shared<DvppDataInfo>();
1332   decodedImage_->format = format;
1333   decodedImage_->width = inputImage_->width;
1334   decodedImage_->height = inputImage_->height;
1335   GetJpegDecodeStrideSize(inputImage_->width, inputImage_->height, decodedImage_->widthStride,
1336                           decodedImage_->heightStride);
1337   // Obtain all the attributes of inputImage_
1338   GetJpegDecodeStrideSize(inputImage_->width, inputImage_->height, inputImage_->widthStride, inputImage_->heightStride);
1339   decodedImage_->dataSize = outBufferSize;
1340   // Malloc dvpp buffer to store the output data after decoding
1341   // Need to pay attention to release of the buffer
1342   ret = acldvppMalloc((void **)&decodedImage_->data, decodedImage_->dataSize);
1343   if (ret != APP_ERR_OK) {
1344     MS_LOG(ERROR) << "Failed to malloc memory on dvpp, ret = " << ret << ".";
1345     RELEASE_DVPP_DATA(inputImage_->data);
1346     return ret;
1347   }
1348   return APP_ERR_OK;
1349 }
1350 
SinkImageH2D(const RawData & imageInfo)1351 APP_ERROR DvppCommon::SinkImageH2D(const RawData &imageInfo) {
1352   if (isVdec_) {
1353     MS_LOG(ERROR) << "CombinePngdProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
1354     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1355   }
1356 
1357   APP_ERROR ret = aclrtSetCurrentContext(dvppContext_);
1358   if (ret != APP_ERR_OK) {
1359     MS_LOG(ERROR) << "Failed to get ACL context, ret = " << ret;
1360     return ret;
1361   }
1362 
1363   int32_t components;
1364   inputImage_ = std::make_shared<DvppDataInfo>();
1365   acldvppPixelFormat format = PIXEL_FORMAT_RGB_888;
1366   inputImage_->format = format;
1367 
1368   ret = GetPngImageInfo(imageInfo.data, imageInfo.lenOfByte, inputImage_->width, inputImage_->height, components);
1369   if (ret != APP_ERR_OK) {
1370     MS_LOG(ERROR) << "Failed to get input image info, ret = " << ret << ".";
1371     return ret;
1372   }
1373 
1374   // Get the buffer size of decode output according to the input data and output format
1375   uint32_t outBuffSize;
1376 
1377   ret = GetPngDecodeDataSize(imageInfo.data, imageInfo.lenOfByte, format, outBuffSize);
1378   if (ret != APP_ERR_OK) {
1379     MS_LOG(ERROR) << "Failed to get size of decode output buffer, ret = " << ret << ".";
1380     return ret;
1381   }
1382 
1383   // In TransferImageH2D function, device buffer will be allocated to store the input image
1384   // Need to pay attention to release of the buffer
1385   ret = TransferImageH2D(imageInfo, inputImage_);
1386   if (ret != APP_ERR_OK) {
1387     return ret;
1388   }
1389 
1390   decodedImage_ = std::make_shared<DvppDataInfo>();
1391   decodedImage_->format = format;
1392   decodedImage_->width = inputImage_->width;
1393   decodedImage_->height = inputImage_->height;
1394   GetPngDecodeStrideSize(inputImage_->width, inputImage_->height, decodedImage_->widthStride,
1395                          decodedImage_->heightStride, format);
1396   decodedImage_->dataSize = outBuffSize;
1397   // Malloc dvpp buffer to store the output data after decoding
1398   // Need to pay attention to release of the buffer
1399   ret = acldvppMalloc((void **)&decodedImage_->data, decodedImage_->dataSize);
1400   if (ret != APP_ERR_OK) {
1401     MS_LOG(ERROR) << "Failed to malloc memory on dvpp, ret = " << ret << ".";
1402     RELEASE_DVPP_DATA(inputImage_->data);
1403     return ret;
1404   }
1405   return APP_ERR_OK;
1406 }
1407 
1408 /*
1409  * @description: Create and set the description of a video stream
1410  * @param: data specifies the information about the video stream
1411  * @return: APP_ERR_OK if success, other values if failure
1412  */
CreateStreamDesc(std::shared_ptr<DvppDataInfo> data)1413 APP_ERROR DvppCommon::CreateStreamDesc(std::shared_ptr<DvppDataInfo> data) {
1414   // Malloc input device memory which need to be released in vdec callback function
1415   void *modelInBuff = nullptr;
1416   APP_ERROR ret = acldvppMalloc(&modelInBuff, data->dataSize);
1417   if (ret != APP_ERR_OK) {
1418     MS_LOG(ERROR) << "Failed to malloc dvpp data with " << data->dataSize << " bytes, ret = " << ret << ".";
1419     return APP_ERR_ACL_BAD_ALLOC;
1420   }
1421   // copy input to device memory
1422   ret = aclrtMemcpy(modelInBuff, data->dataSize, static_cast<uint8_t *>(data->data), data->dataSize,
1423                     ACL_MEMCPY_HOST_TO_DEVICE);
1424   if (ret != APP_ERR_OK) {
1425     MS_LOG(ERROR) << "Failed to copy memory with " << data->dataSize << " bytes from host to device, ret = " << ret
1426                   << ".";
1427     acldvppFree(modelInBuff);
1428     modelInBuff = nullptr;
1429     return APP_ERR_ACL_FAILURE;
1430   }
1431   // Create input stream desc which need to be destroyed in vdec callback function
1432   streamInputDesc_ = acldvppCreateStreamDesc();
1433   if (streamInputDesc_ == nullptr) {
1434     MS_LOG(ERROR) << "Failed to create input stream description.";
1435     return APP_ERR_ACL_FAILURE;
1436   }
1437   ret = acldvppSetStreamDescData(streamInputDesc_, modelInBuff);
1438   if (ret != APP_ERR_OK) {
1439     MS_LOG(ERROR) << "Failed to set data for stream desdescription, ret = " << ret << ".";
1440     return ret;
1441   }
1442   // set size for dvpp stream desc
1443   ret = acldvppSetStreamDescSize(streamInputDesc_, data->dataSize);
1444   if (ret != APP_ERR_OK) {
1445     MS_LOG(ERROR) << "Failed to set data size for stream desdescription,  ret = " << ret << ".";
1446     return ret;
1447   }
1448   return APP_ERR_OK;
1449 }
1450 
1451 /*
1452  * @description: Decode the video based on the video stream specified by data and user-defined data,
1453  *               and outputs the image of each frame
1454  * @param: data specifies the information about the video stream
1455  * @param: userdata is specified for user-defined data
1456  * @return: APP_ERR_OK if success, other values if failure
1457  * @attention: This function can be called only when the DvppCommon object is initialized with InitVdec
1458  */
CombineVdecProcess(std::shared_ptr<DvppDataInfo> data,void * userData)1459 APP_ERROR DvppCommon::CombineVdecProcess(std::shared_ptr<DvppDataInfo> data, void *userData) {
1460   // Return special error code when the DvppCommon object is not initialized with InitVdec
1461   if (!isVdec_) {
1462     MS_LOG(ERROR)
1463       << "CombineVdecProcess cannot be called by the DvppCommon object which is not initialized with InitVdec.";
1464     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1465   }
1466   // create stream desc
1467   APP_ERROR ret = CreateStreamDesc(data);
1468   if (ret != APP_ERR_OK) {
1469     return ret;
1470   }
1471 
1472   uint32_t dataSize;
1473   ret = GetVideoDecodeDataSize(vdecConfig_.inputWidth, vdecConfig_.inputHeight, vdecConfig_.outFormat, dataSize);
1474   if (ret != APP_ERR_OK) {
1475     return ret;
1476   }
1477 
1478   void *picOutBufferDev = nullptr;
1479   // picOutBufferDev need to be destroyed in vdec callback function
1480   ret = acldvppMalloc(&picOutBufferDev, dataSize);
1481   if (ret != APP_ERR_OK) {
1482     MS_LOG(ERROR) << "Failed to malloc memory with " << dataSize << " bytes, ret = " << ret << ".";
1483     return APP_ERR_ACL_BAD_ALLOC;
1484   }
1485 
1486   // picOutputDesc_ will be destroyed in vdec callback function
1487   picOutputDesc_ = acldvppCreatePicDesc();
1488   if (picOutputDesc_ == NULL) {
1489     return APP_ERR_ACL_BAD_ALLOC;
1490   }
1491 
1492   DvppDataInfo dataInfo;
1493   dataInfo.width = vdecConfig_.inputWidth;
1494   dataInfo.height = vdecConfig_.inputHeight;
1495   dataInfo.format = vdecConfig_.outFormat;
1496   dataInfo.dataSize = dataSize;
1497   dataInfo.data = static_cast<uint8_t *>(picOutBufferDev);
1498   ret = SetDvppPicDescData(dataInfo, *picOutputDesc_);
1499   if (ret != APP_ERR_OK) {
1500     return ret;
1501   }
1502 
1503   // send frame
1504   ret = aclvdecSendFrame(vdecChannelDesc_, streamInputDesc_, picOutputDesc_, nullptr, userData);
1505   if (ret != APP_ERR_OK) {
1506     MS_LOG(ERROR) << "Failed to send frame, ret = " << ret << ".";
1507     return APP_ERR_ACL_FAILURE;
1508   }
1509 
1510   return APP_ERR_OK;
1511 }
1512 
1513 /*
1514  * @description: Send eos frame when video stream ends
1515  * @return: APP_ERR_OK if success, other values if failure
1516  */
VdecSendEosFrame() const1517 APP_ERROR DvppCommon::VdecSendEosFrame() const {
1518   // create input stream desc
1519   acldvppStreamDesc *eosStreamDesc = acldvppCreateStreamDesc();
1520   if (eosStreamDesc == nullptr) {
1521     MS_LOG(ERROR) << "Fail to create dvpp stream desc for eos.";
1522     return ACL_ERROR_FAILURE;
1523   }
1524 
1525   // set eos for eos stream desc
1526   APP_ERROR ret = acldvppSetStreamDescEos(eosStreamDesc, true);
1527   if (ret != ACL_ERROR_NONE) {
1528     MS_LOG(ERROR) << "Fail to set eos for stream desc, ret = " << ret << ".";
1529     acldvppDestroyStreamDesc(eosStreamDesc);
1530     return ret;
1531   }
1532 
1533   // send eos and synchronize
1534   ret = aclvdecSendFrame(vdecChannelDesc_, eosStreamDesc, nullptr, nullptr, nullptr);
1535   if (ret != ACL_ERROR_NONE) {
1536     MS_LOG(ERROR) << "Fail to send eos, ret = " << ret << ".";
1537     acldvppDestroyStreamDesc(eosStreamDesc);
1538     return ret;
1539   }
1540 
1541   // destroy input stream desc
1542   ret = acldvppDestroyStreamDesc(eosStreamDesc);
1543   if (ret != ACL_ERROR_NONE) {
1544     MS_LOG(ERROR) << "Fail to destroy dvpp stream desc for eos, ret = " << ret << ".";
1545     return ret;
1546   }
1547   return ret;
1548 }
1549 
1550 /*
1551  * @description: Get the aligned width and height of the output image after video decoding
1552  * @param: width specifies the width before alignment
1553  * @param: height specifies the height before alignment
1554  * @param: format specifies the format of the output image
1555  * @param: widthStride is used to save the width after alignment
1556  * @param: heightStride is used to save the height after alignment
1557  * @return: APP_ERR_OK if success, other values if failure
1558  */
GetVideoDecodeStrideSize(uint32_t width,uint32_t height,acldvppPixelFormat format,uint32_t & widthStride,uint32_t & heightStride)1559 APP_ERROR DvppCommon::GetVideoDecodeStrideSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
1560                                                uint32_t &widthStride, uint32_t &heightStride) {
1561   // Check the invalidty of output format and calculate the output width and height
1562   if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
1563     MS_LOG(ERROR) << "Input format[" << format << "] for VPC is not supported, just support NV12 or NV21.";
1564     return APP_ERR_COMM_INVALID_PARAM;
1565   }
1566   widthStride = DVPP_ALIGN_UP(width, VDEC_STRIDE_WIDTH);
1567   heightStride = DVPP_ALIGN_UP(height, VDEC_STRIDE_HEIGHT);
1568   return APP_ERR_OK;
1569 }
1570 
1571 /*
1572  * @description: Get the buffer size for storing results after video decoding
1573  * @param  width specifies the width of the output image after video decoding
1574  * @param  height specifies the height of the output image after video decoding
1575  * @param  format specifies the format of the output image
1576  * @param: vpcSize is used to save the result size
1577  * @return: APP_ERR_OK if success, other values if failure
1578  */
GetVideoDecodeDataSize(uint32_t width,uint32_t height,acldvppPixelFormat format,uint32_t & vdecSize)1579 APP_ERROR DvppCommon::GetVideoDecodeDataSize(uint32_t width, uint32_t height, acldvppPixelFormat format,
1580                                              uint32_t &vdecSize) {
1581   // Check the invalid format of vdec output and calculate the output buffer size
1582   if (format != PIXEL_FORMAT_YUV_SEMIPLANAR_420 && format != PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
1583     MS_LOG(ERROR) << "Format[" << format << "] for VPC is not supported, just support NV12 or NV21.";
1584     return APP_ERR_COMM_INVALID_PARAM;
1585   }
1586   uint32_t widthStride = DVPP_ALIGN_UP(width, VDEC_STRIDE_WIDTH);
1587   uint32_t heightStride = DVPP_ALIGN_UP(height, VDEC_STRIDE_HEIGHT);
1588   vdecSize = widthStride * heightStride * YUV_BGR_SIZE_CONVERT_3 / YUV_BGR_SIZE_CONVERT_2;
1589   return APP_ERR_OK;
1590 }
1591 
1592 /*
1593  * @description: Encode a YUV image into a JPG image
1594  * @param: input specifies the input image information
1595  * @param: output specifies the output image information
1596  * @param: jpegeConfig specifies the encoding configuration data
1597  * @param: withSynchronize specifies whether to execute synchronously
1598  * @return: APP_ERR_OK if success, other values if failure
1599  * @attention: This function can be called only when the DvppCommon object is initialized with Init
1600  */
JpegEncode(DvppDataInfo & input,DvppDataInfo & output,acldvppJpegeConfig * jpegeConfig,bool withSynchronize)1601 APP_ERROR DvppCommon::JpegEncode(DvppDataInfo &input, DvppDataInfo &output, acldvppJpegeConfig *jpegeConfig,
1602                                  bool withSynchronize) {
1603   // Return special error code when the DvppCommon object is initialized with InitVdec
1604   if (isVdec_) {
1605     MS_LOG(ERROR) << "JpegEncode cannot be called by the DvppCommon object which is initialized with InitVdec.";
1606     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1607   }
1608 
1609   APP_ERROR ret = SetDvppPicDescData(input, *encodeInputDesc_);
1610   if (ret != APP_ERR_OK) {
1611     return ret;
1612   }
1613 
1614   ret = acldvppJpegEncodeAsync(dvppChannelDesc_, encodeInputDesc_.get(), output.data, &output.dataSize, jpegeConfig,
1615                                dvppStream_);
1616   if (ret != APP_ERR_OK) {
1617     MS_LOG(ERROR) << "Failed to encode image, ret = " << ret << ".";
1618     return ret;
1619   }
1620   if (withSynchronize) {
1621     ret = aclrtSynchronizeStream(dvppStream_);
1622     if (ret != APP_ERR_OK) {
1623       MS_LOG(ERROR) << "Failed to aclrtSynchronizeStream, ret = " << ret << ".";
1624       return APP_ERR_DVPP_JPEG_ENCODE_FAIL;
1625     }
1626   }
1627   MS_LOG(INFO) << "Encode successfully.";
1628   return APP_ERR_OK;
1629 }
1630 
1631 /*
1632  * @description: Get the aligned width, height, and data size of the input image
1633  * @param: inputImage specifies the input image information
1634  * @return: APP_ERR_OK if success, other values if failure
1635  */
GetJpegEncodeStrideSize(std::shared_ptr<DvppDataInfo> & inputImage)1636 APP_ERROR DvppCommon::GetJpegEncodeStrideSize(std::shared_ptr<DvppDataInfo> &inputImage) {
1637   uint32_t inputWidth = inputImage->width;
1638   uint32_t inputHeight = inputImage->height;
1639   acldvppPixelFormat format = inputImage->format;
1640   uint32_t widthStride;
1641   uint32_t heightStride;
1642   uint32_t encodedBufferSize;
1643   // Align up the input width and height and calculate buffer size of encoded input file
1644   if (format == PIXEL_FORMAT_YUV_SEMIPLANAR_420 || format == PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
1645     widthStride = DVPP_ALIGN_UP(inputWidth, JPEGE_STRIDE_WIDTH);
1646     heightStride = DVPP_ALIGN_UP(inputHeight, JPEGE_STRIDE_HEIGHT);
1647     encodedBufferSize = widthStride * heightStride * YUV_BYTES_NU / YUV_BYTES_DE;
1648   } else if (format == PIXEL_FORMAT_YUYV_PACKED_422 || format == PIXEL_FORMAT_UYVY_PACKED_422 ||
1649              format == PIXEL_FORMAT_YVYU_PACKED_422 || format == PIXEL_FORMAT_VYUY_PACKED_422) {
1650     widthStride = DVPP_ALIGN_UP(inputWidth * YUV422_WIDTH_NU, JPEGE_STRIDE_WIDTH);
1651     heightStride = DVPP_ALIGN_UP(inputHeight, JPEGE_STRIDE_HEIGHT);
1652     encodedBufferSize = widthStride * heightStride;
1653   } else {
1654     return APP_ERR_COMM_INVALID_PARAM;
1655   }
1656   if (encodedBufferSize == 0) {
1657     MS_LOG(ERROR) << "Input host buffer size is empty.";
1658     return APP_ERR_COMM_INVALID_PARAM;
1659   }
1660   inputImage->widthStride = widthStride;
1661   inputImage->heightStride = heightStride;
1662   inputImage->dataSize = encodedBufferSize;
1663   return APP_ERR_OK;
1664 }
1665 
1666 /*
1667  * @description: Estimate the size of the output memory required by image encoding according to
1668  *               the input image description and image encoding configuration data
1669  * @param: input specifies specifies the input image information
1670  * @param: jpegeConfig specifies the encoding configuration data
1671  * @param: encSize is used to save the result size
1672  * @return: APP_ERR_OK if success, other values if failure
1673  * @attention: This function can be called only when the DvppCommon object is initialized with Init
1674  */
GetJpegEncodeDataSize(DvppDataInfo & input,acldvppJpegeConfig * jpegeConfig,uint32_t & encSize)1675 APP_ERROR DvppCommon::GetJpegEncodeDataSize(DvppDataInfo &input, acldvppJpegeConfig *jpegeConfig, uint32_t &encSize) {
1676   // Return special error code when the DvppCommon object is initialized with InitVdec
1677   if (isVdec_) {
1678     MS_LOG(ERROR)
1679       << "GetJpegEncodeDataSize cannot be called by the DvppCommon object which is initialized with InitVdec.";
1680     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1681   }
1682 
1683   acldvppPicDesc *inputDesc = acldvppCreatePicDesc();
1684   encodeInputDesc_.reset(inputDesc, g_picDescDeleter);
1685 
1686   APP_ERROR ret = SetDvppPicDescData(input, *encodeInputDesc_);
1687   if (ret != APP_ERR_OK) {
1688     return ret;
1689   }
1690 
1691   uint32_t outputSize;
1692   ret = acldvppJpegPredictEncSize(encodeInputDesc_.get(), jpegeConfig, &outputSize);
1693   if (ret != APP_ERR_OK) {
1694     MS_LOG(ERROR) << "Failed to predict encode size of jpeg image, ret = " << ret << ".";
1695     return ret;
1696   }
1697   encSize = outputSize;
1698   return APP_ERR_OK;
1699 }
1700 
1701 /*
1702  * @description: Set the encoding configuration data
1703  * @param: level specifies the encode quality range
1704  * @param: jpegeConfig specifies the encoding configuration data
1705  * @return: APP_ERR_OK if success, other values if failure
1706  */
SetEncodeLevel(uint32_t level,acldvppJpegeConfig & jpegeConfig)1707 APP_ERROR DvppCommon::SetEncodeLevel(uint32_t level, acldvppJpegeConfig &jpegeConfig) {
1708   // Set the encoding quality
1709   // The coding quality range [0, 100]
1710   // The level 0 coding quality is similar to the level 100
1711   // The smaller the value in [1, 100], the worse the quality of the output picture
1712   auto ret = (APP_ERROR)acldvppSetJpegeConfigLevel(&jpegeConfig, level);
1713   if (ret != APP_ERR_OK) {
1714     return ret;
1715   }
1716   return APP_ERR_OK;
1717 }
1718 
1719 /*
1720  * @description: Encode the image specified by imageInfo and save the result to member variable encodedImage_
1721  * @param: imageInfo specifies image information
1722  * @param: width specifies the width of the input image
1723  * @param: height specifies the height of the input image
1724  * @param: format specifies the format of the input image
1725  * @param: withSynchronize specifies whether to execute synchronously
1726  * @return: APP_ERR_OK if success, other values if failure
1727  * @attention: This function can be called only when the DvppCommon object is initialized with Init
1728  */
CombineJpegeProcess(const RawData & imageInfo,uint32_t width,uint32_t height,acldvppPixelFormat format,bool withSynchronize)1729 APP_ERROR DvppCommon::CombineJpegeProcess(const RawData &imageInfo, uint32_t width, uint32_t height,
1730                                           acldvppPixelFormat format, bool withSynchronize) {
1731   // Return special error code when the DvppCommon object is initialized with InitVdec
1732   if (isVdec_) {
1733     MS_LOG(ERROR)
1734       << "CombineJpegeProcess cannot be called by the DvppCommon object which is initialized with InitVdec.";
1735     return APP_ERR_DVPP_OBJ_FUNC_MISMATCH;
1736   }
1737   inputImage_ = std::make_shared<DvppDataInfo>();
1738   inputImage_->format = format;
1739   inputImage_->width = width;
1740   inputImage_->height = height;
1741   // In TransferImageH2D function, device buffer will be allocated to store the input image
1742   // Need to pay attention to release of the buffer
1743   APP_ERROR ret = TransferImageH2D(imageInfo, inputImage_);
1744   if (ret != APP_ERR_OK) {
1745     return ret;
1746   }
1747   // Get stride size of encoded image
1748   ret = GetJpegEncodeStrideSize(inputImage_);
1749   if (ret != APP_ERR_OK) {
1750     MS_LOG(ERROR) << "Failed to get encode stride size of input image file, ret = " << ret << ".";
1751     return ret;
1752   }
1753 
1754   auto jpegeConfig = acldvppCreateJpegeConfig();
1755   jpegeConfig_.reset(jpegeConfig, g_jpegeConfigDeleter);
1756 
1757   uint32_t encodeLevel = 100;
1758   ret = SetEncodeLevel(encodeLevel, *jpegeConfig_);
1759   if (ret != APP_ERR_OK) {
1760     MS_LOG(ERROR) << "Failed to set encode level, ret = " << ret << ".";
1761     return ret;
1762   }
1763 
1764   // Get the buffer size of encode output according to the input data and jpeg encode config
1765   uint32_t encodeOutBufferSize;
1766   ret = GetJpegEncodeDataSize(*inputImage_, jpegeConfig_.get(), encodeOutBufferSize);
1767   if (ret != APP_ERR_OK) {
1768     MS_LOG(ERROR) << "Failed to get size of encode output buffer, ret = " << ret << ".";
1769     return ret;
1770   }
1771 
1772   encodedImage_ = std::make_shared<DvppDataInfo>();
1773   encodedImage_->dataSize = encodeOutBufferSize;
1774   // Malloc dvpp buffer to store the output data after decoding
1775   // Need to pay attention to release of the buffer
1776   ret = acldvppMalloc((void **)&encodedImage_->data, encodedImage_->dataSize);
1777   if (ret != APP_ERR_OK) {
1778     MS_LOG(ERROR) << "Failed to malloc memory on dvpp, ret = " << ret << ".";
1779     acldvppFree(inputImage_->data);
1780     return ret;
1781   }
1782 
1783   // Encode input image
1784   ret = JpegEncode(*inputImage_, *encodedImage_, jpegeConfig_.get(), withSynchronize);
1785   if (ret != APP_ERR_OK) {
1786     // Release the output buffer when decode failed, otherwise release it after use
1787     acldvppFree(inputImage_->data);
1788     acldvppFree(encodedImage_->data);
1789     return ret;
1790   }
1791   return APP_ERR_OK;
1792 }
1793 
GetInputImage()1794 std::shared_ptr<DvppDataInfo> DvppCommon::GetInputImage() { return inputImage_; }
1795 
GetDecodedImage()1796 std::shared_ptr<DvppDataInfo> DvppCommon::GetDecodedImage() { return decodedImage_; }
1797 
GetResizedImage()1798 std::shared_ptr<DvppDataInfo> DvppCommon::GetResizedImage() { return resizedImage_; }
1799 
GetEncodedImage()1800 std::shared_ptr<DvppDataInfo> DvppCommon::GetEncodedImage() { return encodedImage_; }
1801 
GetCropedImage()1802 std::shared_ptr<DvppDataInfo> DvppCommon::GetCropedImage() { return cropImage_; }
1803 
~DvppCommon()1804 DvppCommon::~DvppCommon() {}
1805