• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Rgb888ToJpeg(const std::string_view & filename,const uint8_t * rgbData,int width,int height)153 int32_t AVMetadataMock::Rgb888ToJpeg(const std::string_view &filename,
154     const uint8_t *rgbData, int width, int height)
155 {
156     if (rgbData == nullptr) {
157         std::cout << "rgbData is nullptr" << std::endl;
158         return -1;
159     }
160 
161     jpeg.err = jpeg_std_error(&jerr);
162     jpeg_create_compress(&jpeg);
163     jpeg.image_width = width;
164     jpeg.image_height = height;
165     jpeg.input_components = RGB888_PIXEL_BYTES;
166     jpeg.in_color_space = JCS_RGB;
167     jpeg_set_defaults(&jpeg);
168 
169     static const int QUALITY = 100;
170     jpeg_set_quality(&jpeg, QUALITY, TRUE);
171 
172     FILE *pFile = fopen(filename.data(), "wb");
173     if (!pFile) {
174         jpeg_destroy_compress(&jpeg);
175         return 0;
176     }
177 
178     jpeg_stdio_dest(&jpeg, pFile);
179     jpeg_start_compress(&jpeg, TRUE);
180     JSAMPROW row_pointer[1];
181     for (uint32_t i = 0; i < jpeg.image_height; i++) {
182         row_pointer[0] = const_cast<uint8_t *>(rgbData + i * jpeg.image_width * RGB888_PIXEL_BYTES);
183         jpeg_write_scanlines(&jpeg, row_pointer, 1);
184     }
185     jpeg_finish_compress(&jpeg);
186     (void)fclose(pFile);
187     pFile = NULL;
188 
189     jpeg_destroy_compress(&jpeg);
190     return 0;
191 }
192 
FrameToFile(std::shared_ptr<PixelMap> frame,const char * fileName,int64_t timeUs,int32_t queryOption)193 void AVMetadataMock::FrameToFile(std::shared_ptr<PixelMap> frame,
194     const char *fileName, int64_t timeUs, int32_t queryOption)
195 {
196     const uint8_t *data = frame->GetPixels();
197     EXPECT_NE(data, nullptr);
198     int32_t bufferSize = frame->GetByteCount();
199     const uint8_t MAX_FILE_PATH_LENGTH = 255;
200     char filePath[MAX_FILE_PATH_LENGTH];
201     if (access("/data/test/ThumbnailBak", 0) != F_OK) {
202         mkdir("/data/test/ThumbnailBak", 0777);  // 0777 is the file permission.
203     }
204     auto ret = sprintf_s(filePath, MAX_FILE_PATH_LENGTH,
205         "/data/test/ThumbnailBak/%s_time_%" PRIi64 "_option_%d_width_%d_height_%d_color_%d.pixel",
206         fileName, timeUs, queryOption, frame->GetWidth(), frame->GetHeight(), frame->GetPixelFormat());
207     if (ret <= 0) {
208         std::cout << "generate file path failed" << std::endl;
209         return;
210     }
211     FILE *desFile = fopen(filePath, "wb");
212     ASSERT_NE(desFile, nullptr);
213     int64_t dstBufferSize = fwrite(data, bufferSize, 1, desFile);
214     EXPECT_EQ(dstBufferSize, 1);
215     (void)fclose(desFile);
216 }
217 
SurfaceToFile(std::shared_ptr<AVSharedMemory> frame,const char * fileName)218 void AVMetadataMock::SurfaceToFile(std::shared_ptr<AVSharedMemory> frame,
219     const char *fileName)
220 {
221     const uint8_t *data = frame->GetBase();
222     EXPECT_NE(data, nullptr);
223     int32_t bufferSize = frame->GetSize();
224     uint32_t flag = frame->GetFlags();
225     const uint8_t MAX_FILE_PATH_LENGTH = 255;
226     char filePath[MAX_FILE_PATH_LENGTH];
227     if (access("/data/test/SurfaceBak", 0) != F_OK) {
228         mkdir("/data/test/SurfaceBak", 0777); // permission 0777
229     }
230     auto ret = sprintf_s(filePath, MAX_FILE_PATH_LENGTH, "/data/test/SurfaceBak/%s.pixel", fileName);
231     if (ret <= 0) {
232         std::cout << "generate file path failed, flag:" << flag << std::endl;
233         return;
234     }
235     FILE *desFile = fopen(filePath, "wb");
236     ASSERT_NE(desFile, nullptr);
237     int64_t dstBufferSize = fwrite(data, bufferSize, 1, desFile);
238     EXPECT_EQ(dstBufferSize, 1);
239     (void)fclose(desFile);
240 }
241 
FrameToJpeg(std::shared_ptr<PixelMap> frame,const char * fileName,int64_t timeUs,int32_t queryOption)242 void AVMetadataMock::FrameToJpeg(std::shared_ptr<PixelMap> frame,
243     const char *fileName, int64_t timeUs, int32_t queryOption)
244 {
245     const uint8_t MAX_FILE_PATH_LENGTH = 255;
246     char filePath[MAX_FILE_PATH_LENGTH];
247     if (access("/data/test/ThumbnailBak", 0) != F_OK) {
248         mkdir("/data/test/ThumbnailBak", 0777); // permission 0777
249     }
250     auto ret = sprintf_s(filePath, MAX_FILE_PATH_LENGTH,
251         "/data/test/ThumbnailBak/%s_time_%" PRIi64 "_option_%d_width_%d_height_%d_color_%d.jpg",
252         fileName, timeUs, queryOption, frame->GetWidth(), frame->GetHeight(), frame->GetPixelFormat());
253     if (ret <= 0) {
254         std::cout << "generate file path failed" << std::endl;
255         return;
256     }
257     if (frame->GetPixelFormat() == PixelFormat::RGB_565) {
258         uint32_t rgb888Size = (frame->GetByteCount() / RGB565_PIXEL_BYTES) * RGB888_PIXEL_BYTES;
259         if (rgb888Size <= 0) {
260             std::cout << "invalid rgb888Size" << std::endl;
261             return;
262         }
263         uint8_t *rgb888 = new (std::nothrow) uint8_t[rgb888Size];
264         if (rgb888 == nullptr) {
265             std::cout << "alloc mem failed" << std::endl;
266             return;
267         }
268         const uint16_t *rgb565Data = reinterpret_cast<const uint16_t *>(frame->GetPixels());
269         ret = RGB565ToRGB888(rgb565Data, frame->GetByteCount() / RGB565_PIXEL_BYTES, rgb888, rgb888Size);
270         if (ret != 0) {
271             std::cout << "convert rgb565 to rgb888 failed" << std::endl;
272             delete [] rgb888;
273             return;
274         }
275         ret = Rgb888ToJpeg(filePath, rgb888, frame->GetWidth(), frame->GetHeight());
276         delete [] rgb888;
277     } else if (frame->GetPixelFormat() == PixelFormat::RGB_888) {
278         ret = Rgb888ToJpeg(filePath, frame->GetPixels(), frame->GetWidth(), frame->GetHeight());
279     } else {
280         std::cout << "invalid pixel format" << std::endl;
281         return;
282     }
283     if (ret != 0) {
284         std::cout << "pack image failed" << std::endl;
285     }
286     std::cout << "save to " << filePath << std::endl;
287 }
288 
AVMetadataTestBase()289 AVMetadataTestBase::AVMetadataTestBase()
290 {
291 }
292 
~AVMetadataTestBase()293 AVMetadataTestBase::~AVMetadataTestBase()
294 {
295 }
296 
StrToInt64(const std::string & str,int64_t & value)297 bool AVMetadataTestBase::StrToInt64(const std::string &str, int64_t &value)
298 {
299     if (str.empty() || (!isdigit(str.front()) && (str.front() != '-'))) {
300         return false;
301     }
302 
303     char *end = nullptr;
304     errno = 0;
305     auto addr = str.c_str();
306     auto result = strtoll(addr, &end, 10); /* 10 means decimal */
307     if (result == 0) {
308         return false;
309     }
310     if ((end == addr) || (end[0] != '\0') || (errno == ERANGE)) {
311         UNITTEST_INFO_LOG("call StrToInt func false,  input str is: %s!", str.c_str());
312         return false;
313     }
314 
315     value = result;
316     return true;
317 }
318 
CompareMetadata(int32_t key,const std::string & result,const std::string & expected)319 bool AVMetadataTestBase::CompareMetadata(int32_t key, const std::string &result, const std::string &expected)
320 {
321     std::string keyStr = (AVMETA_KEY_TO_STRING_MAP.count(key) == 0) ?
322         std::string(AVMETA_KEY_TO_STRING_MAP.at(key)) : std::to_string(key);
323 
324     do {
325         if (key == AV_KEY_DURATION) {
326             int64_t resultDuration = 0;
327             int64_t expectedDuration = 0;
328             if (result.compare(expected) == 0) {
329                 return true;
330             }
331             if (!StrToInt64(result, resultDuration) || !StrToInt64(expected, expectedDuration)) {
332                 break;
333             }
334             if (std::abs(resultDuration - expectedDuration) > 1000) { // max allowed time margin is 1000ms
335                 break;
336             }
337         } else {
338             if (result.compare(expected) != 0) {
339                 break;
340             }
341         }
342         return true;
343     } while (0);
344 
345     UNITTEST_INFO_LOG(">>>>>>>>>>>>>>>>>>>>>>>>>>[resolve failed] key = %s, result = %s, expected = %s",
346         keyStr.c_str(), result.c_str(), expected.c_str());
347     return false;
348 }
349 
CompareMetadata(const std::unordered_map<int32_t,std::string> & result,const std::unordered_map<int32_t,std::string> & expected)350 bool AVMetadataTestBase::CompareMetadata(const std::unordered_map<int32_t, std::string> &result,
351     const std::unordered_map<int32_t, std::string> &expected)
352 {
353     std::string resultValue;
354     bool success = true;
355 
356     for (const auto &[key, expectedValue] : expected) {
357         if (result.count(key) == 0) {
358             resultValue = "";
359         } else {
360             resultValue = result.at(key);
361         }
362 
363         success = success && CompareMetadata(key, resultValue, expectedValue);
364     }
365 
366     return success;
367 }
368 
GetPrettyDuration(int64_t duration)369 std::string AVMetadataTestBase::GetPrettyDuration(int64_t duration) // ms
370 {
371     static const int32_t msPerSec = 1000;
372     static const int32_t msPerMin = 60 * msPerSec;
373     static const int32_t msPerHour = 60 * msPerMin;
374 
375     int64_t hour = duration / msPerHour;
376     int64_t min = (duration % msPerHour) / msPerMin;
377     int64_t sec = (duration % msPerMin) / msPerSec;
378     int64_t milliSec = duration % msPerSec;
379 
380     std::ostringstream oss;
381     oss << std::setfill('0')
382         << std::setw(2) << hour << ":" // Set the width of the output field to 2 for hour.
383         << std::setw(2) << min << ":"  // Set the width of the output field to 2 for min.
384         << std::setw(2) << sec << "."  // Set the width of the output field to 2 for sec.
385         << std::setw(3) << milliSec;   // Set the width of the output field to 3 for milliSec.
386 
387     return oss.str();
388 }
389 } // namespace Media
390 } // namespace OHOS