1 /*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
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 "avmetadata_mock.h"
17 #include <fcntl.h>
18 #include "gtest/gtest.h"
19 #include "media_errors.h"
20
21 using namespace OHOS;
22 using namespace OHOS::Media;
23 using namespace AVMetadataTestParam;
24 namespace OHOS {
25 namespace Media {
AVMetadataMock()26 AVMetadataMock::AVMetadataMock()
27 {
28 }
29
~AVMetadataMock()30 AVMetadataMock::~AVMetadataMock()
31 {
32 }
33
CreateAVMetadataHelper()34 bool AVMetadataMock::CreateAVMetadataHelper()
35 {
36 UNITTEST_INFO_LOG("%s", __FUNCTION__);
37 avMetadataHelper_ = AVMetadataHelperFactory::CreateAVMetadataHelper();
38 if (avMetadataHelper_ == nullptr) {
39 return false;
40 }
41 return true;
42 }
43
SetSource(const std::string & uri,int32_t usage)44 int32_t AVMetadataMock::SetSource(const std::string &uri, int32_t usage)
45 {
46 UNITTEST_INFO_LOG("%s %s", __FUNCTION__, uri.c_str());
47 return avMetadataHelper_->SetSource(uri, usage);
48 }
49
SetSource(const std::string & path,int64_t offset,int64_t size,int32_t usage)50 int32_t AVMetadataMock::SetSource(const std::string &path, int64_t offset, int64_t size, int32_t usage)
51 {
52 UNITTEST_INFO_LOG("%s %s", __FUNCTION__, path.c_str());
53 std::string rawFile = path.substr(strlen("file://"));
54 int32_t fd = open(rawFile.c_str(), O_RDONLY);
55 if (fd <= 0) {
56 std::cout << "Open file failed" << std::endl;
57 return -1;
58 }
59
60 struct stat64 st;
61 if (fstat64(fd, &st) != 0) {
62 std::cout << "Get file state failed" << std::endl;
63 (void)close(fd);
64 return -1;
65 }
66 int64_t length = static_cast<int64_t>(st.st_size);
67 if (size > 0) {
68 length = size;
69 }
70 int32_t ret = avMetadataHelper_->SetSource(fd, offset, length, usage);
71 if (ret != 0) {
72 (void)close(fd);
73 return -1;
74 }
75
76 (void)close(fd);
77 return ret;
78 }
79
PrintMetadata()80 void AVMetadataMock::PrintMetadata()
81 {
82 UNITTEST_INFO_LOG("%s", __FUNCTION__);
83 auto resultMetas = avMetadataHelper_->ResolveMetadata();
84 for (const auto &[key, value]: resultMetas) {
85 std::string prettyValue = value;
86 if (key == AV_KEY_DURATION) {
87 int64_t resultDuration = 0;
88 AVMetadataTestBase::GetInstance().StrToInt64(value, resultDuration);
89 prettyValue = AVMetadataTestBase::GetInstance().GetPrettyDuration(resultDuration);
90 }
91 if (AVMETA_KEY_TO_STRING_MAP.count(key) != 0) {
92 UNITTEST_INFO_LOG("key %s: value %s", AVMETA_KEY_TO_STRING_MAP.at(key).data(), prettyValue.c_str());
93 } else {
94 UNITTEST_INFO_LOG("key %d: value %s", key, prettyValue.c_str());
95 }
96 }
97 }
98
ResolveMetadata()99 std::unordered_map<int32_t, std::string> AVMetadataMock::ResolveMetadata()
100 {
101 UNITTEST_INFO_LOG("%s", __FUNCTION__);
102 return avMetadataHelper_->ResolveMetadata();
103 }
104
ResolveMetadata(int32_t key)105 std::string AVMetadataMock::ResolveMetadata(int32_t key)
106 {
107 UNITTEST_INFO_LOG("%s(%d)", __FUNCTION__, key);
108 return avMetadataHelper_->ResolveMetadata(key);
109 }
110
FetchFrameAtTime(int64_t timeUs,int32_t option,PixelMapParams param)111 std::shared_ptr<PixelMap> AVMetadataMock::FetchFrameAtTime(int64_t timeUs, int32_t option, PixelMapParams param)
112 {
113 UNITTEST_INFO_LOG("%s", __FUNCTION__);
114 return avMetadataHelper_->FetchFrameAtTime(timeUs, option, param);
115 }
116
FetchArtPicture()117 std::shared_ptr<AVSharedMemory> AVMetadataMock::FetchArtPicture()
118 {
119 UNITTEST_INFO_LOG("%s", __FUNCTION__);
120 return avMetadataHelper_->FetchArtPicture();
121 }
122
Release()123 void AVMetadataMock::Release()
124 {
125 UNITTEST_INFO_LOG("%s", __FUNCTION__);
126 return avMetadataHelper_->Release();
127 }
128
129 // only valid for little-endian order.
RGB565ToRGB888(const unsigned short * rgb565Buf,int rgb565Size,unsigned char * rgb888Buf,int rgb888Size)130 int32_t AVMetadataMock::RGB565ToRGB888(const unsigned short *rgb565Buf, int rgb565Size,
131 unsigned char *rgb888Buf, int rgb888Size)
132 {
133 if (rgb565Buf == nullptr || rgb565Size <= 0 || rgb888Buf == nullptr || rgb888Size <= 0) {
134 return -1;
135 }
136
137 if (rgb888Size < rgb565Size * RGB888_PIXEL_BYTES) {
138 return -1;
139 }
140
141 for (int i = 0; i < rgb565Size; i++) {
142 rgb888Buf[i * RGB888_PIXEL_BYTES + R_INDEX] = (rgb565Buf[i] & RGB565_MASK_RED);
143 rgb888Buf[i * RGB888_PIXEL_BYTES + G_INDEX] = (rgb565Buf[i] & RGB565_MASK_GREEN) >> SHIFT_5_BIT;
144 rgb888Buf[i * RGB888_PIXEL_BYTES + B_INDEX] = (rgb565Buf[i] & RGB565_MASK_BLUE) >> SHIFT_11_BIT;
145 rgb888Buf[i * RGB888_PIXEL_BYTES + R_INDEX] <<= SHIFT_3_BIT;
146 rgb888Buf[i * RGB888_PIXEL_BYTES + G_INDEX] <<= SHIFT_2_BIT;
147 rgb888Buf[i * RGB888_PIXEL_BYTES + B_INDEX] <<= SHIFT_3_BIT;
148 }
149
150 return 0;
151 }
152
FrameToFile(std::shared_ptr<PixelMap> frame,const char * fileName,int64_t timeUs,int32_t queryOption)153 void AVMetadataMock::FrameToFile(std::shared_ptr<PixelMap> frame,
154 const char *fileName, int64_t timeUs, int32_t queryOption)
155 {
156 const uint8_t *data = frame->GetPixels();
157 EXPECT_NE(data, nullptr);
158 int32_t bufferSize = frame->GetByteCount();
159 const uint8_t MAX_FILE_PATH_LENGTH = 255;
160 char filePath[MAX_FILE_PATH_LENGTH];
161 if (access("/data/test/ThumbnailBak", 0) != F_OK) {
162 mkdir("/data/test/ThumbnailBak", 0777); // 0777 is the file permission.
163 }
164 auto ret = sprintf_s(filePath, MAX_FILE_PATH_LENGTH,
165 "/data/test/ThumbnailBak/%s_time_%" PRIi64 "_option_%d_width_%d_height_%d_color_%d.pixel",
166 fileName, timeUs, queryOption, frame->GetWidth(), frame->GetHeight(), frame->GetPixelFormat());
167 if (ret <= 0) {
168 std::cout << "generate file path failed" << std::endl;
169 return;
170 }
171 FILE *desFile = fopen(filePath, "wb");
172 ASSERT_NE(desFile, nullptr);
173 int64_t dstBufferSize = fwrite(data, bufferSize, 1, desFile);
174 EXPECT_EQ(dstBufferSize, 1);
175 (void)fclose(desFile);
176 }
177
SurfaceToFile(std::shared_ptr<AVSharedMemory> frame,const char * fileName)178 void AVMetadataMock::SurfaceToFile(std::shared_ptr<AVSharedMemory> frame,
179 const char *fileName)
180 {
181 const uint8_t *data = frame->GetBase();
182 EXPECT_NE(data, nullptr);
183 int32_t bufferSize = frame->GetSize();
184 uint32_t flag = frame->GetFlags();
185 const uint8_t MAX_FILE_PATH_LENGTH = 255;
186 char filePath[MAX_FILE_PATH_LENGTH];
187 if (access("/data/test/SurfaceBak", 0) != F_OK) {
188 mkdir("/data/test/SurfaceBak", 0777); // permission 0777
189 }
190 auto ret = sprintf_s(filePath, MAX_FILE_PATH_LENGTH, "/data/test/SurfaceBak/%s.pixel", fileName);
191 if (ret <= 0) {
192 std::cout << "generate file path failed, flag:" << flag << std::endl;
193 return;
194 }
195 FILE *desFile = fopen(filePath, "wb");
196 ASSERT_NE(desFile, nullptr);
197 int64_t dstBufferSize = fwrite(data, bufferSize, 1, desFile);
198 EXPECT_EQ(dstBufferSize, 1);
199 (void)fclose(desFile);
200 }
201
FrameToJpeg(std::shared_ptr<PixelMap> frame,const char * fileName,int64_t timeUs,int32_t queryOption)202 void AVMetadataMock::FrameToJpeg(std::shared_ptr<PixelMap> frame,
203 const char *fileName, int64_t timeUs, int32_t queryOption)
204 {
205 const uint8_t MAX_FILE_PATH_LENGTH = 255;
206 char filePath[MAX_FILE_PATH_LENGTH];
207 if (access("/data/test/ThumbnailBak", 0) != F_OK) {
208 mkdir("/data/test/ThumbnailBak", 0777); // permission 0777
209 }
210 auto ret = sprintf_s(filePath, MAX_FILE_PATH_LENGTH,
211 "/data/test/ThumbnailBak/%s_time_%" PRIi64 "_option_%d_width_%d_height_%d_color_%d.jpg",
212 fileName, timeUs, queryOption, frame->GetWidth(), frame->GetHeight(), frame->GetPixelFormat());
213 if (ret <= 0) {
214 std::cout << "generate file path failed" << std::endl;
215 return;
216 }
217 if (frame->GetPixelFormat() == PixelFormat::RGB_565) {
218 uint32_t rgb888Size = (frame->GetByteCount() / RGB565_PIXEL_BYTES) * RGB888_PIXEL_BYTES;
219 if (rgb888Size <= 0) {
220 std::cout << "invalid rgb888Size" << std::endl;
221 return;
222 }
223 uint8_t *rgb888 = new (std::nothrow) uint8_t[rgb888Size];
224 if (rgb888 == nullptr) {
225 std::cout << "alloc mem failed" << std::endl;
226 return;
227 }
228 const uint16_t *rgb565Data = reinterpret_cast<const uint16_t *>(frame->GetPixels());
229 ret = RGB565ToRGB888(rgb565Data, frame->GetByteCount() / RGB565_PIXEL_BYTES, rgb888, rgb888Size);
230 if (ret != 0) {
231 std::cout << "convert rgb565 to rgb888 failed" << std::endl;
232 delete [] rgb888;
233 return;
234 }
235 delete [] rgb888;
236 } else if (frame->GetPixelFormat() == PixelFormat::RGB_888) {
237 return;
238 } else {
239 std::cout << "invalid pixel format" << std::endl;
240 return;
241 }
242 if (ret != 0) {
243 std::cout << "pack image failed" << std::endl;
244 }
245 std::cout << "save to " << filePath << std::endl;
246 }
247
AVMetadataTestBase()248 AVMetadataTestBase::AVMetadataTestBase()
249 {
250 }
251
~AVMetadataTestBase()252 AVMetadataTestBase::~AVMetadataTestBase()
253 {
254 }
255
StrToInt64(const std::string & str,int64_t & value)256 bool AVMetadataTestBase::StrToInt64(const std::string &str, int64_t &value)
257 {
258 if (str.empty() || (!isdigit(str.front()) && (str.front() != '-'))) {
259 return false;
260 }
261
262 char *end = nullptr;
263 errno = 0;
264 auto addr = str.c_str();
265 auto result = strtoll(addr, &end, 10); /* 10 means decimal */
266 if (result == 0) {
267 return false;
268 }
269 if ((end == addr) || (end[0] != '\0') || (errno == ERANGE)) {
270 UNITTEST_INFO_LOG("call StrToInt func false, input str is: %s!", str.c_str());
271 return false;
272 }
273
274 value = result;
275 return true;
276 }
277
CompareMetadata(int32_t key,const std::string & result,const std::string & expected)278 bool AVMetadataTestBase::CompareMetadata(int32_t key, const std::string &result, const std::string &expected)
279 {
280 std::string keyStr = (AVMETA_KEY_TO_STRING_MAP.count(key) == 0) ?
281 std::string(AVMETA_KEY_TO_STRING_MAP.at(key)) : std::to_string(key);
282
283 do {
284 if (key == AV_KEY_DURATION) {
285 int64_t resultDuration = 0;
286 int64_t expectedDuration = 0;
287 if (result.compare(expected) == 0) {
288 return true;
289 }
290 if (!StrToInt64(result, resultDuration) || !StrToInt64(expected, expectedDuration)) {
291 break;
292 }
293 if (std::abs(resultDuration - expectedDuration) > 1000) { // max allowed time margin is 1000ms
294 break;
295 }
296 } else {
297 if (result.compare(expected) != 0) {
298 break;
299 }
300 }
301 return true;
302 } while (0);
303
304 UNITTEST_INFO_LOG(">>>>>>>>>>>>>>>>>>>>>>>>>>[resolve failed] key = %s, result = %s, expected = %s",
305 keyStr.c_str(), result.c_str(), expected.c_str());
306 return false;
307 }
308
CompareMetadata(const std::unordered_map<int32_t,std::string> & result,const std::unordered_map<int32_t,std::string> & expected)309 bool AVMetadataTestBase::CompareMetadata(const std::unordered_map<int32_t, std::string> &result,
310 const std::unordered_map<int32_t, std::string> &expected)
311 {
312 std::string resultValue;
313 bool success = true;
314
315 for (const auto &[key, expectedValue] : expected) {
316 if (result.count(key) == 0) {
317 resultValue = "";
318 } else {
319 resultValue = result.at(key);
320 }
321
322 success = success && CompareMetadata(key, resultValue, expectedValue);
323 }
324
325 return success;
326 }
327
GetPrettyDuration(int64_t duration)328 std::string AVMetadataTestBase::GetPrettyDuration(int64_t duration) // ms
329 {
330 static const int32_t msPerSec = 1000;
331 static const int32_t msPerMin = 60 * msPerSec;
332 static const int32_t msPerHour = 60 * msPerMin;
333
334 int64_t hour = duration / msPerHour;
335 int64_t min = (duration % msPerHour) / msPerMin;
336 int64_t sec = (duration % msPerMin) / msPerSec;
337 int64_t milliSec = duration % msPerSec;
338
339 std::ostringstream oss;
340 oss << std::setfill('0')
341 << std::setw(2) << hour << ":" // Set the width of the output field to 2 for hour.
342 << std::setw(2) << min << ":" // Set the width of the output field to 2 for min.
343 << std::setw(2) << sec << "." // Set the width of the output field to 2 for sec.
344 << std::setw(3) << milliSec; // Set the width of the output field to 3 for milliSec.
345
346 return oss.str();
347 }
348 } // namespace Media
349 } // namespace OHOS