• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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