1 /*
2 * Copyright (C) 2023 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 "thumbnail_manager_ani.h"
17
18 #include <memory>
19 #include <mutex>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22
23 #include "ashmem.h"
24 #include "image_source.h"
25 #include "image_type.h"
26 #include "media_file_uri.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_tracer.h"
29 #include "media_log.h"
30 #include "pixel_map.h"
31 #include "post_proc.h"
32 #include "securec.h"
33 #include "string_ex.h"
34 #include "thumbnail_const.h"
35 #include "unique_fd.h"
36 #include "userfilemgr_uri.h"
37 #include "userfile_manager_types.h"
38 #include "uv.h"
39 #include "userfile_client.h"
40
41 #ifdef IMAGE_PURGEABLE_PIXELMAP
42 #include "purgeable_pixelmap_builder.h"
43 #endif
44
45 using namespace std;
46
47 namespace OHOS {
48 namespace Media {
49
OpenThumbnail(const string & path,ThumbnailType type)50 static int OpenThumbnail(const string &path, ThumbnailType type)
51 {
52 if (path.empty()) {
53 return E_ERR;
54 }
55
56 string sandboxPath = GetSandboxPath(path, type);
57 if (sandboxPath.empty()) {
58 return E_ERR;
59 }
60
61 char realPath[PATH_MAX] = {0};
62 if (realpath(sandboxPath.c_str(), realPath) == nullptr) {
63 MEDIA_ERR_LOG("Failed to canonicalize path: %s", sandboxPath.c_str());
64 return E_ERR;
65 }
66
67 int fd = open(realPath, O_RDONLY);
68 if (fd < 0) {
69 MEDIA_ERR_LOG("Failed to open %s", realPath);
70 return E_ERR;
71 }
72 return fd;
73 }
74
GetPixelMapFromServer(const string & uriStr,const Size & size,const string & path)75 static int32_t GetPixelMapFromServer(const string &uriStr, const Size &size, const string &path)
76 {
77 string openUriStr = uriStr + "?" + MEDIA_OPERN_KEYWORD + "=" + MEDIA_DATA_DB_THUMBNAIL + "&" +
78 MEDIA_DATA_DB_WIDTH + "=" + to_string(size.width) + "&" + MEDIA_DATA_DB_HEIGHT + "=" +
79 to_string(size.height);
80 if (IsAsciiString(path)) {
81 openUriStr += "&" + THUMBNAIL_PATH + "=" + path;
82 }
83 Uri openUri(openUriStr);
84 return UserFileClient::OpenFile(openUri, "R");
85 }
86
CreateThumbnailByAshmem(UniqueFd & uniqueFd,const Size & size)87 static PixelMapPtr CreateThumbnailByAshmem(UniqueFd &uniqueFd, const Size &size)
88 {
89 MediaLibraryTracer tracer;
90 tracer.Start("CreateThumbnailByAshmem");
91
92 Media::InitializationOptions option = {
93 .size = size,
94 };
95 PixelMapPtr pixel = Media::PixelMap::Create(option);
96 if (pixel == nullptr) {
97 MEDIA_ERR_LOG("Can not create pixel");
98 return nullptr;
99 }
100
101 UniqueFd dupFd = UniqueFd(dup(uniqueFd.Get()));
102 MMapFdPtr mmapFd(dupFd.Get(), false);
103 if (!mmapFd.IsValid()) {
104 MEDIA_ERR_LOG("Can not mmap by fd");
105 return nullptr;
106 }
107 auto memSize = static_cast<int32_t>(mmapFd.GetFdSize());
108
109 void* fdPtr = new int32_t();
110 *static_cast<int32_t*>(fdPtr) = dupFd.Release();
111 pixel->SetPixelsAddr(mmapFd.GetFdPtr(), fdPtr, memSize, Media::AllocatorType::SHARE_MEM_ALLOC, nullptr);
112 return pixel;
113 }
114
IfSizeEqualsRatio(const Size & imageSize,const Size & targetSize)115 static bool IfSizeEqualsRatio(const Size &imageSize, const Size &targetSize)
116 {
117 if (imageSize.height <= 0 || targetSize.height <= 0) {
118 return false;
119 }
120
121 float imageSizeScale = static_cast<float>(imageSize.width) / static_cast<float>(imageSize.height);
122 float targetSizeScale = static_cast<float>(targetSize.width) / static_cast<float>(targetSize.height);
123 if (imageSizeScale - targetSizeScale > FLOAT_EPSILON || targetSizeScale - imageSizeScale > FLOAT_EPSILON) {
124 return false;
125 } else {
126 return true;
127 }
128 }
129
DecodeThumbnail(const UniqueFd & uniqueFd,const Size & size)130 static PixelMapPtr DecodeThumbnail(const UniqueFd &uniqueFd, const Size &size)
131 {
132 MediaLibraryTracer tracer;
133 tracer.Start("ImageSource::CreateImageSource");
134 SourceOptions opts;
135 uint32_t err = 0;
136 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(uniqueFd.Get(), opts, err);
137 if (imageSource == nullptr) {
138 MEDIA_ERR_LOG("CreateImageSource err %{public}d", err);
139 return nullptr;
140 }
141
142 ImageInfo imageInfo;
143 err = imageSource->GetImageInfo(0, imageInfo);
144 if (err != E_OK) {
145 MEDIA_ERR_LOG("GetImageInfo err %{public}d", err);
146 return nullptr;
147 }
148
149 bool isEqualsRatio = IfSizeEqualsRatio(imageInfo.size, size);
150 DecodeOptions decodeOpts;
151 decodeOpts.desiredSize = isEqualsRatio ? size : imageInfo.size;
152 unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
153 if (pixelMap == nullptr) {
154 MEDIA_ERR_LOG("CreatePixelMap err %{public}d", err);
155 return nullptr;
156 }
157
158 PostProc postProc;
159 if (size.width != DEFAULT_ORIGINAL && !isEqualsRatio && !postProc.CenterScale(size, *pixelMap)) {
160 MEDIA_ERR_LOG("CenterScale failed, size: %{public}d * %{public}d, imageInfo size: %{public}d * %{public}d",
161 size.width, size.height, imageInfo.size.width, imageInfo.size.height);
162 return nullptr;
163 }
164
165 // Make the ashmem of pixelmap to be purgeable after the operation on ashmem.
166 // And then make the pixelmap subject to PurgeableManager's control.
167 #ifdef IMAGE_PURGEABLE_PIXELMAP
168 PurgeableBuilder::MakePixelMapToBePurgeable(pixelMap, imageSource, decodeOpts, size);
169 #endif
170 return pixelMap;
171 }
172
QueryThumbnail(const string & uriStr,const Size & size,const string & path)173 unique_ptr<PixelMap> ThumbnailManagerAni::QueryThumbnail(const string &uriStr, const Size &size, const string &path)
174 {
175 MediaLibraryTracer tracer;
176 tracer.Start("QueryThumbnail uri:" + uriStr);
177 tracer.Start("DataShare::OpenFile");
178 ThumbnailType thumbType = GetThumbType(size.width, size.height);
179 if (MediaFileUri::GetMediaTypeFromUri(uriStr) == MediaType::MEDIA_TYPE_AUDIO &&
180 (thumbType == ThumbnailType::MTH || thumbType == ThumbnailType::YEAR)) {
181 thumbType = ThumbnailType::THUMB;
182 }
183 UniqueFd uniqueFd(OpenThumbnail(path, thumbType));
184 if (uniqueFd.Get() == E_ERR) {
185 uniqueFd = UniqueFd(GetPixelMapFromServer(uriStr, size, path));
186 if (uniqueFd.Get() < 0) {
187 MEDIA_ERR_LOG("queryThumb is null, errCode is %{public}d", uniqueFd.Get());
188 return nullptr;
189 }
190 return DecodeThumbnail(uniqueFd, size);
191 }
192 tracer.Finish();
193 if (thumbType == ThumbnailType::MTH || thumbType == ThumbnailType::YEAR) {
194 return CreateThumbnailByAshmem(uniqueFd, size);
195 } else {
196 return DecodeThumbnail(uniqueFd, size);
197 }
198 }
199
200 }
201 }
202