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 "image_processing_loader.h"
17 
18 #include <dlfcn.h>
19 
20 #include "vpe_log.h"
21 
22 namespace {
23 const std::string VPE_IMPL_LIBRARY_PATH = "libimage_processing_capi_impl.so";
24 }
25 
Get()26 ImageProcessingNdkLoader& ImageProcessingNdkLoader::Get()
27 {
28     static ImageProcessingNdkLoader loader{};
29     return loader;
30 }
31 
LoadLibrary()32 bool ImageProcessingNdkLoader::LoadLibrary()
33 {
34     std::lock_guard<std::mutex> lock(lock_);
35     if (refCount_ > 0) {
36         refCount_++;
37         return true;
38     }
39 
40     if (!LoadLibraryLocked()) {
41         return false;
42     }
43     refCount_++;
44     return true;
45 }
46 
UnloadLibrary()47 void ImageProcessingNdkLoader::UnloadLibrary()
48 {
49     std::lock_guard<std::mutex> lock(lock_);
50     if (refCount_ == 0) {
51         VPE_LOGW("Unload too many times!");
52         return;
53     }
54 
55     refCount_--;
56     if (refCount_ > 0) {
57         return;
58     }
59     UnloadLibraryLocked();
60 }
61 
IsValid() const62 bool ImageProcessingNdkLoader::IsValid() const
63 {
64     return isValid_.load();
65 }
66 
InitializeEnvironment()67 ImageProcessing_ErrorCode ImageProcessingNdkLoader::InitializeEnvironment()
68 {
69     return CallNdk([](IImageProcessingNdk* intfNdk) { return intfNdk->InitializeEnvironment(); });
70 }
71 
DeinitializeEnvironment()72 ImageProcessing_ErrorCode ImageProcessingNdkLoader::DeinitializeEnvironment()
73 {
74     return CallNdk([](IImageProcessingNdk* intfNdk) { return intfNdk->DeinitializeEnvironment(); });
75 }
76 
IsColorSpaceConversionSupported(const ImageProcessing_ColorSpaceInfo * sourceImageInfo,const ImageProcessing_ColorSpaceInfo * destinationImageInfo)77 bool ImageProcessingNdkLoader::IsColorSpaceConversionSupported(
78     const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
79     const ImageProcessing_ColorSpaceInfo* destinationImageInfo)
80 {
81     return CallSupportNdk([sourceImageInfo, destinationImageInfo](IImageProcessingNdk* intfNdk) {
82         return intfNdk->IsColorSpaceConversionSupported(sourceImageInfo, destinationImageInfo);
83     });
84 }
85 
IsCompositionSupported(const ImageProcessing_ColorSpaceInfo * sourceImageInfo,const ImageProcessing_ColorSpaceInfo * sourceGainmapInfo,const ImageProcessing_ColorSpaceInfo * destinationImageInfo)86 bool ImageProcessingNdkLoader::IsCompositionSupported(
87     const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
88     const ImageProcessing_ColorSpaceInfo* sourceGainmapInfo,
89     const ImageProcessing_ColorSpaceInfo* destinationImageInfo)
90 {
91     return CallSupportNdk([sourceImageInfo, sourceGainmapInfo, destinationImageInfo](IImageProcessingNdk* intfNdk) {
92         return intfNdk->IsCompositionSupported(sourceImageInfo, sourceGainmapInfo, destinationImageInfo);
93     });
94 }
95 
IsDecompositionSupported(const ImageProcessing_ColorSpaceInfo * sourceImageInfo,const ImageProcessing_ColorSpaceInfo * destinationImageInfo,const ImageProcessing_ColorSpaceInfo * destinationGainmapInfo)96 bool ImageProcessingNdkLoader::IsDecompositionSupported(
97     const ImageProcessing_ColorSpaceInfo* sourceImageInfo,
98     const ImageProcessing_ColorSpaceInfo* destinationImageInfo,
99     const ImageProcessing_ColorSpaceInfo* destinationGainmapInfo)
100 {
101     return CallSupportNdk(
102         [sourceImageInfo, destinationImageInfo, destinationGainmapInfo](IImageProcessingNdk* intfNdk) {
103             return intfNdk->IsDecompositionSupported(sourceImageInfo, destinationImageInfo, destinationGainmapInfo);
104         });
105 }
106 
IsMetadataGenerationSupported(const ImageProcessing_ColorSpaceInfo * sourceImageInfo)107 bool ImageProcessingNdkLoader::IsMetadataGenerationSupported(const ImageProcessing_ColorSpaceInfo* sourceImageInfo)
108 {
109     return CallSupportNdk([sourceImageInfo](IImageProcessingNdk* intfNdk) {
110         return intfNdk->IsMetadataGenerationSupported(sourceImageInfo);
111     });
112 }
113 
Create(OH_ImageProcessing ** imageProcessor,int32_t type)114 ImageProcessing_ErrorCode ImageProcessingNdkLoader::Create(OH_ImageProcessing** imageProcessor, int32_t type)
115 {
116     return CallNdk([imageProcessor, type](IImageProcessingNdk* intfNdk) {
117         return intfNdk->Create(imageProcessor, type);
118     });
119 }
120 
Destroy(OH_ImageProcessing * imageProcessor)121 ImageProcessing_ErrorCode ImageProcessingNdkLoader::Destroy(OH_ImageProcessing* imageProcessor)
122 {
123     return CallNdk([imageProcessor](IImageProcessingNdk* intfNdk) { return intfNdk->Destroy(imageProcessor); });
124 }
125 
SetParameter(OH_ImageProcessing * imageProcessor,const OH_AVFormat * parameter)126 ImageProcessing_ErrorCode ImageProcessingNdkLoader::SetParameter(OH_ImageProcessing* imageProcessor,
127     const OH_AVFormat* parameter)
128 {
129     return CallNdk([imageProcessor, parameter](IImageProcessingNdk* intfNdk) {
130         return intfNdk->SetParameter(imageProcessor, parameter);
131     });
132 }
133 
GetParameter(OH_ImageProcessing * imageProcessor,OH_AVFormat * parameter)134 ImageProcessing_ErrorCode ImageProcessingNdkLoader::GetParameter(OH_ImageProcessing* imageProcessor,
135     OH_AVFormat* parameter)
136 {
137     return CallNdk([imageProcessor, parameter](IImageProcessingNdk* intfNdk) {
138         return intfNdk->GetParameter(imageProcessor, parameter);
139     });
140 }
141 
ConvertColorSpace(OH_ImageProcessing * imageProcessor,OH_PixelmapNative * sourceImage,OH_PixelmapNative * destinationImage)142 ImageProcessing_ErrorCode ImageProcessingNdkLoader::ConvertColorSpace(OH_ImageProcessing* imageProcessor,
143     OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage)
144 {
145     return CallNdk([imageProcessor, sourceImage, destinationImage](IImageProcessingNdk* intfNdk) {
146         return intfNdk->ConvertColorSpace(imageProcessor, sourceImage, destinationImage);
147     });
148 }
149 
Compose(OH_ImageProcessing * imageProcessor,OH_PixelmapNative * sourceImage,OH_PixelmapNative * sourceGainmap,OH_PixelmapNative * destinationImage)150 ImageProcessing_ErrorCode ImageProcessingNdkLoader::Compose(OH_ImageProcessing* imageProcessor,
151     OH_PixelmapNative* sourceImage, OH_PixelmapNative* sourceGainmap, OH_PixelmapNative* destinationImage)
152 {
153     return CallNdk([imageProcessor, sourceImage, sourceGainmap, destinationImage](IImageProcessingNdk* intfNdk) {
154         return intfNdk->Compose(imageProcessor, sourceImage, sourceGainmap, destinationImage);
155     });
156 }
157 
Decompose(OH_ImageProcessing * imageProcessor,OH_PixelmapNative * sourceImage,OH_PixelmapNative * destinationImage,OH_PixelmapNative * destinationGainmap)158 ImageProcessing_ErrorCode ImageProcessingNdkLoader::Decompose(OH_ImageProcessing* imageProcessor,
159     OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage, OH_PixelmapNative* destinationGainmap)
160 {
161     return CallNdk([imageProcessor, sourceImage, destinationImage, destinationGainmap](IImageProcessingNdk* intfNdk) {
162         return intfNdk->Decompose(imageProcessor, sourceImage, destinationImage, destinationGainmap);
163     });
164 }
165 
GenerateMetadata(OH_ImageProcessing * imageProcessor,OH_PixelmapNative * sourceImage)166 ImageProcessing_ErrorCode ImageProcessingNdkLoader::GenerateMetadata(OH_ImageProcessing* imageProcessor,
167     OH_PixelmapNative* sourceImage)
168 {
169     return CallNdk([imageProcessor, sourceImage](IImageProcessingNdk* intfNdk) {
170         return intfNdk->GenerateMetadata(imageProcessor, sourceImage);
171     });
172 }
173 
EnhanceDetail(OH_ImageProcessing * imageProcessor,OH_PixelmapNative * sourceImage,OH_PixelmapNative * destinationImage)174 ImageProcessing_ErrorCode ImageProcessingNdkLoader::EnhanceDetail(OH_ImageProcessing* imageProcessor,
175     OH_PixelmapNative* sourceImage, OH_PixelmapNative* destinationImage)
176 {
177     return CallNdk([imageProcessor, sourceImage, destinationImage](IImageProcessingNdk* intfNdk) {
178         return intfNdk->EnhanceDetail(imageProcessor, sourceImage, destinationImage);
179     });
180 }
181 
LoadLibraryLocked()182 bool ImageProcessingNdkLoader::LoadLibraryLocked()
183 {
184     VPE_LOGI("Load library...");
185     const std::string& path = VPE_IMPL_LIBRARY_PATH;
186     if (!OpenLibraryLocked(path)) {
187         return false;
188     }
189 
190     if (!LoadInterfaceLocked(imageProcessing_, destroyImageProcessingFunc_,
191         "CreateImageProcessingNdk", "DestroyImageProcessingNdk", path)) {
192         UnloadLibraryLocked();
193         return false;
194     }
195 
196     isValid_ = true;
197     VPE_LOGI("Load library successfully.");
198     return true;
199 }
200 
UnloadLibraryLocked()201 void ImageProcessingNdkLoader::UnloadLibraryLocked()
202 {
203     isValid_ = false;
204     if (destroyImageProcessingFunc_ != nullptr) {
205         destroyImageProcessingFunc_(imageProcessing_);
206         imageProcessing_ = nullptr;
207         destroyImageProcessingFunc_ = nullptr;
208     }
209 
210     if (libHandle_ != nullptr)  {
211         dlclose(libHandle_);
212         libHandle_ = nullptr;
213     }
214 
215     VPE_LOGI("Unload library.");
216 }
217 
OpenLibraryLocked(const std::string & path)218 bool ImageProcessingNdkLoader::OpenLibraryLocked(const std::string& path)
219 {
220     libHandle_ = dlopen(path.c_str(), RTLD_NOW);
221     if (libHandle_ == nullptr) {
222         VPE_LOGW("Can't open library %{public}s - %{public}s", path.c_str(), dlerror());
223         return false;
224     }
225     return true;
226 }
227 
LoadInterfaceLocked(IImageProcessingNdk * & interface,destroyNdkFunc & destroyFunc,const std::string & createFuncName,const std::string & destroyFuncName,const std::string & path)228 bool ImageProcessingNdkLoader::LoadInterfaceLocked(IImageProcessingNdk*& interface, destroyNdkFunc& destroyFunc,
229     const std::string& createFuncName, const std::string& destroyFuncName, const std::string& path)
230 {
231     createNdkFunc createFunc = reinterpret_cast<createNdkFunc>(dlsym(libHandle_, createFuncName.c_str()));
232     if (createFunc == nullptr) {
233         VPE_LOGE("Failed to locate %{public}s in %{public}s - %{public}s",
234             createFuncName.c_str(), path.c_str(), path.c_str());
235         UnloadLibraryLocked();
236         return false;
237     }
238     destroyFunc = reinterpret_cast<destroyNdkFunc>(dlsym(libHandle_, destroyFuncName.c_str()));
239     if (destroyFunc == nullptr) {
240         VPE_LOGE("Failed to locate %{public}s in %{public}s - %{public}s",
241             destroyFuncName.c_str(), path.c_str(), path.c_str());
242         UnloadLibraryLocked();
243         return false;
244     }
245     interface = createFunc();
246     if (interface == nullptr) {
247         VPE_LOGW("Failed to create interface!");
248         UnloadLibraryLocked();
249         return false;
250     }
251     return true;
252 }
253 
CallSupportNdk(std::function<bool (IImageProcessingNdk *)> && operation)254 bool ImageProcessingNdkLoader::CallSupportNdk(std::function<bool(IImageProcessingNdk*)>&& operation)
255 {
256     std::lock_guard<std::mutex> lock(lock_);
257     if (imageProcessing_ == nullptr) {
258         return false;
259     }
260     return operation(imageProcessing_);
261 }
262 
CallNdk(std::function<ImageProcessing_ErrorCode (IImageProcessingNdk *)> && operation)263 ImageProcessing_ErrorCode ImageProcessingNdkLoader::CallNdk(
264     std::function<ImageProcessing_ErrorCode(IImageProcessingNdk*)>&& operation)
265 {
266     std::lock_guard<std::mutex> lock(lock_);
267     if (imageProcessing_ == nullptr) {
268         return IMAGE_PROCESSING_ERROR_UNKNOWN;
269     }
270     return operation(imageProcessing_);
271 }
272