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