1 /**
2 * Copyright 2022-2023 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "minddata/dataset/kernels/image/dvpp/utils/AclLiteUtils.h"
17
18 #include <dirent.h>
19 #include <sys/stat.h>
20
21 #include <fstream>
22 #include <iostream>
23 #include <map>
24 #include <regex>
25 #include <vector>
26
27 #include "acl/ops/acl_dvpp.h"
28 #include "transform/symbol/acl_rt_symbol.h"
29 #include "transform/symbol/symbol_utils.h"
30
31 namespace {
32 const char COMMENT_CHAR = '#';
33 const char EQUALS_CHAR = '=';
34 const char BLANK_SPACE_CHAR = ' ';
35 const char TABLE_CHAR = '\t';
36
37 const std::string kImagePathSeparator = ",";
38 const int kStatSuccess = 0;
39 const std::string kFileSperator = "/";
40 const std::string kPathSeparator = "/";
41 // output image prefix
42 const std::string kOutputFilePrefix = "out_";
43
44 const std::string kRegexIpAddr =
45 "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[0-9])\\."
46 "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
47 "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
48 "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)"
49 ":([1-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|"
50 "6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$";
51
52 // regex for verify video file name
53 const std::string kRegexVideoFile = "^.+\\.(mp4|h264|h265)$";
54
55 // regex for verify RTSP rtsp://ip:port/channelname
56 const std::string kRegexRtsp = "^rtsp://.*";
57 } // namespace
58
IsDigitStr(const std::string & str)59 bool IsDigitStr(const std::string &str) { return std::all_of(str.begin(), str.end(), isdigit); }
60
IsPathExist(const std::string & path)61 bool IsPathExist(const std::string &path) {
62 std::ifstream file(path, std::ios::in);
63 if (!file) {
64 return false;
65 }
66 file.close();
67 return true;
68 }
69
IsVideoFile(const std::string & path)70 bool IsVideoFile(const std::string &path) {
71 std::regex regexVideoFile(kRegexVideoFile.c_str());
72 return regex_match(path, regexVideoFile);
73 }
74
IsRtspAddr(const std::string & str)75 bool IsRtspAddr(const std::string &str) {
76 std::regex regexRtspAddress(kRegexRtsp.c_str());
77
78 return regex_match(str, regexRtspAddress);
79 }
80
IsIpAddrWithPort(const std::string & addrStr)81 bool IsIpAddrWithPort(const std::string &addrStr) {
82 std::regex regexIpAddr(kRegexIpAddr.c_str());
83
84 return regex_match(addrStr, regexIpAddr);
85 }
86
ParseIpAddr(std::string & ip,std::string & port,const std::string & addr)87 void ParseIpAddr(std::string &ip, std::string &port, const std::string &addr) {
88 std::string::size_type pos = addr.find(':');
89
90 (void)ip.assign(addr.substr(0, pos));
91 (void)port.assign(addr.substr(pos + 1));
92 }
93
IsDirectory(const std::string & path)94 bool IsDirectory(const std::string &path) {
95 // get path stat
96 struct stat buf {};
97 if (stat(path.c_str(), &buf) != kStatSuccess) {
98 return false;
99 }
100
101 // check
102 return S_ISDIR(buf.st_mode);
103 }
104
SplitPath(const std::string & path,std::vector<std::string> & pathVec)105 void SplitPath(const std::string &path, std::vector<std::string> &pathVec) {
106 char *imageFile = strtok(const_cast<char *>(path.c_str()), kImagePathSeparator.c_str());
107 while (imageFile) {
108 (void)pathVec.emplace_back(imageFile);
109 imageFile = strtok(nullptr, kImagePathSeparator.c_str());
110 }
111 }
112
GetPathFiles(const std::string & path,std::vector<std::string> & fileVec)113 void GetPathFiles(const std::string &path, std::vector<std::string> &fileVec) {
114 if (IsDirectory(path)) {
115 DIR *dir = opendir(path.c_str());
116 struct dirent *direntPtr;
117 while ((direntPtr = readdir(dir)) != nullptr) {
118 // skip . and ..
119 if (direntPtr->d_name[0] == '.') {
120 continue;
121 }
122
123 // file path
124 std::string fullPath = path + kPathSeparator + direntPtr->d_name;
125 // directory need recursion
126 if (IsDirectory(fullPath)) {
127 GetPathFiles(fullPath, fileVec);
128 } else {
129 // put file
130 (void)fileVec.emplace_back(fullPath);
131 }
132 }
133 closedir(dir);
134 } else {
135 (void)fileVec.emplace_back(path);
136 }
137 }
138
GetAllFiles(const std::string & pathList,std::vector<std::string> & fileVec)139 void GetAllFiles(const std::string &pathList, std::vector<std::string> &fileVec) {
140 // split file path
141 std::vector<std::string> pathVec;
142 SplitPath(pathList, pathVec);
143
144 for (const std::string &everyPath : pathVec) {
145 // check path exist or not
146 if (!IsPathExist(pathList)) {
147 ACLLITE_LOG_ERROR("Failed to deal path=%s. Reason: not exist or can not access.", everyPath.c_str());
148 continue;
149 }
150 // get files in path and sub-path
151 GetPathFiles(everyPath, fileVec);
152 }
153 }
154
MallocMemory(uint32_t dataSize,MemoryType memType)155 void *MallocMemory(uint32_t dataSize, MemoryType memType) {
156 void *buffer = nullptr;
157 aclError aclRet = ACL_SUCCESS;
158
159 switch (memType) {
160 case MemoryType::MEMORY_NORMAL:
161 buffer = new uint8_t[dataSize];
162 break;
163 case MemoryType::MEMORY_HOST:
164 aclRet = CALL_ASCEND_API(aclrtMallocHost, &buffer, dataSize);
165 break;
166 case MemoryType::MEMORY_DEVICE:
167 aclRet = CALL_ASCEND_API(aclrtMalloc, &buffer, dataSize, ACL_MEM_MALLOC_HUGE_FIRST);
168 break;
169 case MemoryType::MEMORY_DVPP:
170 aclRet = acldvppMalloc(&buffer, dataSize);
171 break;
172 default:
173 ACLLITE_LOG_ERROR("Invalid memory type %d", memType);
174 aclRet = ACL_ERROR_INVALID_PARAM;
175 break;
176 }
177
178 if ((aclRet != ACL_SUCCESS) || (buffer == nullptr)) {
179 ACLLITE_LOG_ERROR("Malloc memory failed, type: %d, errorno:%d", memType, aclRet);
180 return nullptr;
181 }
182
183 return buffer;
184 }
185
FreeMemory(void * mem,MemoryType memType)186 void FreeMemory(void *mem, MemoryType memType) {
187 if (mem == nullptr) {
188 ACLLITE_LOG_ERROR("Invalid mem");
189 return;
190 }
191 aclError ret = ACL_SUCCESS;
192 switch (memType) {
193 case MemoryType::MEMORY_NORMAL:
194 delete[](reinterpret_cast<uint8_t *>(mem));
195 break;
196 case MemoryType::MEMORY_HOST:
197 ret = CALL_ASCEND_API(aclrtFreeHost, mem);
198 if (ret != ACL_SUCCESS) {
199 ACLLITE_LOG_ERROR("aclrtFreeHost failed, errorno: %d", ret);
200 }
201 break;
202 case MemoryType::MEMORY_DEVICE:
203 ret = CALL_ASCEND_API(aclrtFree, mem);
204 if (ret != ACL_SUCCESS) {
205 ACLLITE_LOG_ERROR("aclrtFree failed, errorno: %d", ret);
206 }
207 break;
208 case MemoryType::MEMORY_DVPP:
209 ret = acldvppFree(mem);
210 if (ret != ACL_SUCCESS) {
211 ACLLITE_LOG_ERROR("acldvppFree failed, errorno: %d", ret);
212 }
213 break;
214 default:
215 ACLLITE_LOG_ERROR("Invalid memory type %d", memType);
216 break;
217 }
218 }
219
GetCopyPolicy(aclrtRunMode srcDev,CopyDirection direct,MemoryType memType)220 aclrtMemcpyKind GetCopyPolicy(aclrtRunMode srcDev, CopyDirection direct, MemoryType memType) {
221 aclrtMemcpyKind policy = ACL_MEMCPY_HOST_TO_HOST;
222
223 if (direct == CopyDirection::TO_DEVICE) {
224 if (srcDev == ACL_HOST) {
225 policy = ACL_MEMCPY_HOST_TO_DEVICE;
226 } else {
227 policy = ACL_MEMCPY_DEVICE_TO_DEVICE;
228 }
229 } else { // TO_HOST
230 if (srcDev == ACL_DEVICE) {
231 policy = ACL_MEMCPY_DEVICE_TO_HOST;
232 }
233 }
234
235 return policy;
236 }
237
CopyDataToDevice(const void * data,uint32_t size,aclrtRunMode curRunMode,MemoryType memType)238 void *CopyDataToDevice(const void *data, uint32_t size, aclrtRunMode curRunMode, MemoryType memType) {
239 if ((data == nullptr) || (size == 0) || ((curRunMode != ACL_HOST) && (curRunMode != ACL_DEVICE)) ||
240 (memType >= MemoryType::MEMORY_INVALID_TYPE) || (memType == MemoryType::MEMORY_HOST)) {
241 ACLLITE_LOG_ERROR(
242 "Copy data args invalid, data %p, "
243 "size %d, src dev %d, memory type %d",
244 data, size, curRunMode, memType);
245 return nullptr;
246 }
247
248 aclrtMemcpyKind policy = GetCopyPolicy(curRunMode, CopyDirection::TO_DEVICE, memType);
249
250 return CopyData(data, size, policy, memType);
251 }
252
CopyDataToDeviceEx(void * dest,uint32_t destSize,const void * src,uint32_t srcSize,aclrtRunMode runMode)253 AclLiteError CopyDataToDeviceEx(void *dest, uint32_t destSize, const void *src, uint32_t srcSize,
254 aclrtRunMode runMode) {
255 aclrtMemcpyKind policy = ACL_MEMCPY_HOST_TO_DEVICE;
256 if (runMode == ACL_DEVICE) {
257 policy = ACL_MEMCPY_DEVICE_TO_DEVICE;
258 }
259
260 aclError aclRet = CALL_ASCEND_API(aclrtMemcpy, dest, destSize, src, srcSize, policy);
261 if (aclRet != ACL_SUCCESS) {
262 ACLLITE_LOG_ERROR("Copy data to device failed, aclRet is %d", aclRet);
263 return ACLLITE_ERROR;
264 }
265
266 return ACLLITE_OK;
267 }
268
CopyDataToHost(const void * data,uint32_t size,aclrtRunMode curRunMode,MemoryType memType)269 void *CopyDataToHost(const void *data, uint32_t size, aclrtRunMode curRunMode, MemoryType memType) {
270 if ((data == nullptr) || (size == 0) || ((curRunMode != ACL_HOST) && (curRunMode != ACL_DEVICE)) ||
271 ((memType != MemoryType::MEMORY_HOST) && (memType != MemoryType::MEMORY_NORMAL))) {
272 ACLLITE_LOG_ERROR(
273 "Copy data args invalid, data %p, "
274 "size %d, src dev %d, memory type %d",
275 data, size, curRunMode, memType);
276 return nullptr;
277 }
278
279 aclrtMemcpyKind policy = GetCopyPolicy(curRunMode, CopyDirection::TO_HOST, memType);
280
281 return CopyData(data, size, policy, memType);
282 }
283
CopyDataToHostEx(void * dest,uint32_t destSize,const void * src,uint32_t srcSize,aclrtRunMode runMode)284 AclLiteError CopyDataToHostEx(void *dest, uint32_t destSize, const void *src, uint32_t srcSize, aclrtRunMode runMode) {
285 aclrtMemcpyKind policy = ACL_MEMCPY_DEVICE_TO_HOST;
286 if (runMode == ACL_DEVICE) {
287 policy = ACL_MEMCPY_DEVICE_TO_DEVICE;
288 }
289
290 aclError aclRet = CALL_ASCEND_API(aclrtMemcpy, dest, destSize, src, srcSize, policy);
291 if (aclRet != ACL_SUCCESS) {
292 ACLLITE_LOG_ERROR("Copy data to device failed, aclRet is %d", aclRet);
293 return ACLLITE_ERROR;
294 }
295
296 return ACLLITE_OK;
297 }
298
CopyData(const void * data,uint32_t size,aclrtMemcpyKind policy,MemoryType memType)299 void *CopyData(const void *data, uint32_t size, aclrtMemcpyKind policy, MemoryType memType) {
300 void *buffer = MallocMemory(size, memType);
301 if (buffer == nullptr) {
302 return nullptr;
303 }
304
305 aclError aclRet = CALL_ASCEND_API(aclrtMemcpy, buffer, size, data, size, policy);
306 if (aclRet != ACL_SUCCESS) {
307 ACLLITE_LOG_ERROR("Copy data to device failed, aclRet is %d", aclRet);
308 FreeMemory(buffer, memType);
309 return nullptr;
310 }
311
312 return buffer;
313 }
314
CopyImageToLocal(ImageData & destImage,ImageData & srcImage,aclrtRunMode curRunMode)315 AclLiteError CopyImageToLocal(ImageData &destImage, ImageData &srcImage, aclrtRunMode curRunMode) {
316 void *data = CopyDataToHost(srcImage.data.get(), srcImage.size, curRunMode, MemoryType::MEMORY_NORMAL);
317 if (data == nullptr) {
318 return ACLLITE_ERROR_COPY_DATA;
319 }
320
321 destImage.format = srcImage.format;
322 destImage.width = srcImage.width;
323 destImage.height = srcImage.height;
324 destImage.size = srcImage.size;
325 destImage.alignWidth = srcImage.alignWidth;
326 destImage.alignHeight = srcImage.alignHeight;
327 destImage.data = SHARED_PTR_U8_BUF(data);
328
329 return ACLLITE_OK;
330 }
331
CopyImageToDevice(ImageData & destImage,ImageData & srcImage,aclrtRunMode curRunMode,MemoryType memType)332 AclLiteError CopyImageToDevice(ImageData &destImage, ImageData &srcImage, aclrtRunMode curRunMode, MemoryType memType) {
333 void *data = CopyDataToDevice(srcImage.data.get(), srcImage.size, curRunMode, memType);
334 if (data == nullptr) {
335 return ACLLITE_ERROR_COPY_DATA;
336 }
337
338 destImage.format = srcImage.format;
339 destImage.width = srcImage.width;
340 destImage.height = srcImage.height;
341 destImage.size = srcImage.size;
342 destImage.alignWidth = srcImage.alignWidth;
343 destImage.alignHeight = srcImage.alignHeight;
344
345 if (memType == MemoryType::MEMORY_DEVICE) {
346 destImage.data = SHARED_PTR_DEV_BUF(data);
347 } else {
348 destImage.data = SHARED_PTR_DVPP_BUF(data);
349 }
350
351 return ACLLITE_OK;
352 }
353
ReadBinFile(const std::string & fileName,void * & data,uint32_t & size)354 AclLiteError ReadBinFile(const std::string &fileName, void *&data, uint32_t &size) {
355 struct stat sBuf {};
356 int fileStatus = stat(fileName.data(), &sBuf);
357 if (fileStatus == -1) {
358 ACLLITE_LOG_ERROR("failed to get file");
359 return ACLLITE_ERROR_ACCESS_FILE;
360 }
361 if (S_ISREG(sBuf.st_mode) == 0) {
362 ACLLITE_LOG_ERROR("%s is not a file, please enter a file", fileName.c_str());
363 return ACLLITE_ERROR_INVALID_FILE;
364 }
365 std::ifstream binFile(fileName, std::ifstream::in | std::ifstream::binary);
366 if (!binFile.is_open()) {
367 ACLLITE_LOG_ERROR("open file %s failed", fileName.c_str());
368 return ACLLITE_ERROR_OPEN_FILE;
369 }
370
371 (void)binFile.seekg(0, std::ifstream::end);
372 uint32_t binFileBufferLen = binFile.tellg();
373 if (binFileBufferLen == 0) {
374 ACLLITE_LOG_ERROR("binfile is empty, filename is %s", fileName.c_str());
375 binFile.close();
376 return ACLLITE_ERROR_INVALID_FILE;
377 }
378
379 (void)binFile.seekg(0, std::ifstream::beg);
380
381 auto *binFileBufferData = new (std::nothrow) uint8_t[binFileBufferLen];
382 if (binFileBufferData == nullptr) {
383 ACLLITE_LOG_ERROR("malloc binFileBufferData failed");
384 binFile.close();
385 return ACLLITE_ERROR_MALLOC;
386 }
387 (void)binFile.read(reinterpret_cast<char *>(binFileBufferData), binFileBufferLen);
388 binFile.close();
389
390 data = binFileBufferData;
391 size = binFileBufferLen;
392
393 return ACLLITE_OK;
394 }
395
ReadJpeg(ImageData & image,const std::string & fileName)396 AclLiteError ReadJpeg(ImageData &image, const std::string &fileName) {
397 uint32_t size = 0;
398 void *buf = nullptr;
399
400 auto lite_ret = ReadBinFile(fileName, buf, size);
401 if (lite_ret != ACLLITE_OK) {
402 delete[](reinterpret_cast<uint8_t *>(buf));
403 return lite_ret;
404 }
405
406 int32_t ch = 0;
407 auto ret = acldvppJpegGetImageInfo(buf, size, &(image.width), &(image.height), &ch);
408 if (ret != ACL_SUCCESS) {
409 ACLLITE_LOG_ERROR("acldvppJpegGetImageInfo failed, errorno: %d", ret);
410 delete[](reinterpret_cast<uint8_t *>(buf));
411 return ACLLITE_ERROR;
412 }
413 if (image.width == 0 || image.height == 0) {
414 ACLLITE_LOG_ERROR("unsupported format, only Baseline JPEG");
415 delete[](reinterpret_cast<uint8_t *>(buf));
416 return ACLLITE_ERROR;
417 }
418 image.data.reset(reinterpret_cast<uint8_t *>(buf), [](const uint8_t *p) { delete[](p); });
419 image.size = size;
420
421 return ACLLITE_OK;
422 }
423
SaveBinFile(const std::string & filename,const void * data,uint32_t size)424 void SaveBinFile(const std::string &filename, const void *data, uint32_t size) {
425 FILE *outFileFp = fopen(filename.c_str(), "wb+");
426 if (outFileFp == nullptr) {
427 ACLLITE_LOG_ERROR("Save file %s failed for open error", filename.c_str());
428 return;
429 }
430 (void)fwrite(data, 1, size, outFileFp);
431
432 (void)fflush(outFileFp);
433 (void)fclose(outFileFp);
434 }
435
IsSpace(char c)436 bool IsSpace(char c) { return (c == BLANK_SPACE_CHAR || c == TABLE_CHAR); }
437
Trim(std::string & str)438 void Trim(std::string &str) {
439 if (str.empty()) {
440 return;
441 }
442 int32_t i;
443 int32_t start_pos;
444 int32_t end_pos;
445 for (i = 0; i < str.size(); ++i) {
446 if (!IsSpace(str[i])) {
447 break;
448 }
449 }
450 if (i == str.size()) { // is all blank space
451 str = "";
452 return;
453 }
454
455 start_pos = i;
456
457 for (i = str.size() - 1; i >= 0; --i) {
458 if (!IsSpace(str[i])) {
459 break;
460 }
461 }
462 end_pos = i;
463
464 str = str.substr(start_pos, end_pos - start_pos + 1);
465 }
466
AnalyseLine(const std::string & line,std::string & key,std::string & value)467 bool AnalyseLine(const std::string &line, std::string &key, std::string &value) {
468 if (line.empty()) {
469 return false;
470 }
471
472 int start_pos = 0;
473 auto end_pos = line.size() - 1;
474 std::string::size_type pos = line.find(COMMENT_CHAR);
475 if (pos != std::string::npos) {
476 if (pos == 0) { // the first charactor is #
477 return false;
478 }
479 end_pos = pos - 1;
480 }
481 std::string new_line = line.substr(start_pos, start_pos + 1 - end_pos); // delete comment
482 pos = new_line.find(EQUALS_CHAR);
483 if (pos == std::string::npos) { // has no =
484 return false;
485 }
486
487 key = new_line.substr(0, pos);
488 value = new_line.substr(pos + 1, end_pos + 1 - (pos + 1));
489
490 Trim(key);
491 if (key.empty()) {
492 return false;
493 }
494 Trim(value);
495 return true;
496 }
497
ReadConfig(std::map<std::string,std::string> & config,const char * configFile)498 bool ReadConfig(std::map<std::string, std::string> &config, const char *configFile) {
499 config.clear();
500 std::ifstream infile(configFile, std::ifstream::in);
501 if (!infile) {
502 return false;
503 }
504 std::string line;
505 std::string key;
506 std::string value;
507 while (getline(infile, line)) {
508 if (AnalyseLine(line, key, value)) {
509 config[key] = value;
510 }
511 }
512
513 infile.close();
514 return true;
515 }
516
PrintConfig(const std::map<std::string,std::string> & config)517 void PrintConfig(const std::map<std::string, std::string> &config) {
518 auto mIter = config.begin();
519 for (; mIter != config.end(); ++mIter) {
520 std::cout << mIter->first << "=" << mIter->second << std::endl;
521 }
522 }
523