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