• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "detail_enhancer_image_fwk.h"
17 
18 #include <dlfcn.h>
19 
20 #include "detail_enhancer_common.h"
21 #include "extension_manager.h"
22 #include "native_buffer.h"
23 #include "surface_buffer.h"
24 #include "video_processing_client.h"
25 #include "securec.h"
26 #include "vpe_log.h"
27 #include "vpe_sa_constants.h"
28 #include "vpe_trace.h"
29 
30 namespace {
31 enum RectLevelItem {
32     RECT_LEVEL_INVALID = -1,
33     RECT_MIN_WIDTH,
34     RECT_MAX_WIDTH,
35     RECT_MIN_HEIGHT,
36     RECT_MAX_HEIGHT,
37     RECT_LEVEL_NUM,
38 };
39 
40 constexpr float EPSILON = 1e-6; // extremely small value
41 const int MAX_URL_LENGTH = 100;
42 const int SUPPORTED_MIN_WIDTH = 32;
43 const int SUPPORTED_MIN_HEIGHT = 32;
44 const int SUPPORTED_MAX_WIDTH = 20000; // 20000 max support width
45 const int SUPPORTED_MAX_HEIGHT = 20000; // 20000 max support height
46 const int TIMEOUT_THRESHOLD = 10; // 10 millisecond
47 const std::unordered_set<int32_t> SUPPORTED_FORMATS = {
48     OHOS::GRAPHIC_PIXEL_FMT_BGRA_8888, // BGRA
49     OHOS::GRAPHIC_PIXEL_FMT_RGBA_8888, // RGBA
50     OHOS::GRAPHIC_PIXEL_FMT_YCBCR_420_SP, // NV12
51     OHOS::GRAPHIC_PIXEL_FMT_YCRCB_420_SP, // NV21
52     OHOS::GRAPHIC_PIXEL_FMT_YCBCR_420_P, // YU12
53     OHOS::GRAPHIC_PIXEL_FMT_YCRCB_420_P, // YV12
54     OHOS::GRAPHIC_PIXEL_FMT_RGBA_1010102, // RGBA_1010102
55 };
56 const std::vector<std::array<int, RECT_LEVEL_NUM>> SUPER_LEVEL_TARGET_RECT = {
57     {1, 1104, 1, 848},
58     {1, 1104, 1, 1488},
59     {1, 1488, 1, 1104},
60     {1, 1872, 1, 1360},
61 };
62 
IsValidSurfaceBuffer(const OHOS::sptr<OHOS::SurfaceBuffer> & buffer)63 inline bool IsValidSurfaceBuffer(const OHOS::sptr<OHOS::SurfaceBuffer>& buffer)
64 {
65     CHECK_AND_RETURN_RET_LOG(buffer != nullptr, false, "buffer is nullptr!!");
66     return SUPPORTED_FORMATS.find(buffer->GetFormat()) != SUPPORTED_FORMATS.end() &&
67         buffer->GetWidth() > SUPPORTED_MIN_WIDTH && buffer->GetHeight() > SUPPORTED_MIN_HEIGHT &&
68         buffer->GetWidth() <= SUPPORTED_MAX_WIDTH && buffer->GetHeight() <= SUPPORTED_MAX_HEIGHT;
69 }
70 
71 std::atomic<int32_t> g_instanceId = -1;
72 std::timed_mutex g_externLock{};
73 }
74 
75 namespace OHOS {
76 namespace Media {
77 namespace VideoProcessingEngine {
DetailEnhancerImageFwk(int type)78 DetailEnhancerImageFwk::DetailEnhancerImageFwk(int type)
79 {
80     type_ = (type >= IMAGE && type <= VIDEO) ? type : IMAGE;
81     Extension::ExtensionManager::GetInstance().IncreaseInstance();
82 }
83 
~DetailEnhancerImageFwk()84 DetailEnhancerImageFwk::~DetailEnhancerImageFwk()
85 {
86     Clear();
87     Extension::ExtensionManager::GetInstance().DecreaseInstance();
88 }
89 
Create(int type)90 std::shared_ptr<DetailEnhancerImage> DetailEnhancerImage::Create(int type)
91 {
92     CHECK_AND_RETURN_RET_LOG(type <= VIDEO && type >= IMAGE, nullptr, "type is invalid!!");
93     std::shared_ptr<DetailEnhancerImage> impl = std::make_shared<DetailEnhancerImageFwk>(type);
94     CHECK_AND_RETURN_RET_LOG(impl != nullptr, nullptr, "failed to init DetailEnhancerImage");
95     return impl;
96 }
97 
GetAlgorithm(int level)98 std::shared_ptr<DetailEnhancerBase> DetailEnhancerImageFwk::GetAlgorithm(int level)
99 {
100     if (level < DETAIL_ENH_LEVEL_NONE || level > DETAIL_ENH_LEVEL_VIDEO) {
101         VPE_LOGE("Invalid level:%{public}d", level);
102         return nullptr;
103     }
104     std::lock_guard<std::mutex> lock(lock_);
105     auto createdImpl = algorithms_.find(level);
106     if (createdImpl != algorithms_.end()) [[likely]] {
107         return createdImpl->second;
108     }
109     auto algo = CreateAlgorithm(level);
110     if (algo.get() == nullptr) {
111         return nullptr;
112     }
113     VPE_LOGD("level:%d enable:%d", level, enableProtection_);
114     auto ret = algo->EnableProtection(enableProtection_);
115     CHECK_AND_RETURN_RET_LOG(ret == VPE_ALGO_ERR_OK, nullptr,
116         "Failed to EnableProtection(%{public}d) for level:%{pubcli}d ret:%{pubcli}d", enableProtection_, level, ret);
117     algorithms_[level] = algo;
118     return algorithms_[level];
119 }
120 
CreateAlgorithm(int level)121 std::shared_ptr<DetailEnhancerBase> DetailEnhancerImageFwk::CreateAlgorithm(int level)
122 {
123     auto& manager = Extension::ExtensionManager::GetInstance();
124     VPE_SYNC_TRACE;
125     std::shared_ptr<DetailEnhancerBase> algoImpl = manager.CreateDetailEnhancer(level);
126     VPE_LOGE("level:%{public}d", level);
127     if (algoImpl == nullptr) {
128         VPE_LOGE("Extension create failed, get a empty impl, level: %{public}d", level);
129         return nullptr;
130     }
131     if (algoImpl->Init() != VPE_ALGO_ERR_OK) {
132         VPE_LOGE("Init failed, extension level: %{public}d", level);
133         return nullptr;
134     }
135     return algoImpl;
136 }
137 
SetParameter(const DetailEnhancerParameters & parameter)138 VPEAlgoErrCode DetailEnhancerImageFwk::SetParameter(const DetailEnhancerParameters& parameter)
139 {
140     CHECK_AND_RETURN_RET_LOG(parameter.level >= DETAIL_ENH_LEVEL_NONE && parameter.level <= DETAIL_ENH_LEVEL_HIGH &&
141         parameter.uri.length() < MAX_URL_LENGTH, VPE_ALGO_ERR_INVALID_VAL, "Invalid parameter");
142     std::lock_guard<std::mutex> lock(lock_);
143     parameter_ = parameter;
144     parameterUpdated = true;
145     hasParameter_ = true;
146     VPE_LOGI("DetailEnhancerImageFwk SetParameter Succeed");
147     return VPE_ALGO_ERR_OK;
148 }
149 
GetParameter(DetailEnhancerParameters & parameter) const150 VPEAlgoErrCode DetailEnhancerImageFwk::GetParameter(DetailEnhancerParameters& parameter) const
151 {
152     std::lock_guard<std::mutex> lock(lock_);
153     parameter = parameter_;
154     VPE_LOGI("DetailEnhancerImageFwk SetParameter Succeed");
155     return VPE_ALGO_ERR_OK;
156 }
157 
IsValidProcessedObject(const sptr<SurfaceBuffer> & input,const sptr<SurfaceBuffer> & output)158 bool DetailEnhancerImageFwk::IsValidProcessedObject(const sptr<SurfaceBuffer>& input,
159     const sptr<SurfaceBuffer>& output)
160 {
161     CHECK_AND_RETURN_RET_LOG((input != nullptr) && (output != nullptr),
162         false, "Input or output is nullptr");
163     CHECK_AND_RETURN_RET_LOG(input->GetFormat() == output->GetFormat(), false,
164         "The input format and output format need to be consistent");
165     CHECK_AND_RETURN_RET_LOG(IsValidSurfaceBuffer(input) && IsValidSurfaceBuffer(output), false, "Invalid buffer");
166     return true;
167 }
168 
EvaluateTargetLevel(const sptr<SurfaceBuffer> & input,const sptr<SurfaceBuffer> & output,float widthRatio,float heightRatio) const169 int DetailEnhancerImageFwk::EvaluateTargetLevel(const sptr<SurfaceBuffer>& input,
170     const sptr<SurfaceBuffer>& output, float widthRatio, float heightRatio) const
171 {
172     CHECK_AND_RETURN_RET_LOG((input != nullptr) && (output != nullptr), false, "Input or output is nullptr");
173     if (parameter_.level == DETAIL_ENH_LEVEL_HIGH) {
174         int inputW = input->GetWidth();
175         int inputH = input->GetHeight();
176         if (widthRatio < 1.0 && heightRatio < 1.0 && // 1.0 means zoom out
177             // 0.5 means rounding, 2 means two pixels
178             std::abs(static_cast<int>(widthRatio * inputW + 0.5) - static_cast<int>(heightRatio * inputW + 0.5)) <= 2 &&
179             // 0.5 means rounding, 2 means two pixels
180             std::abs(static_cast<int>(widthRatio * inputH + 0.5) - static_cast<int>(heightRatio * inputH + 0.5)) <= 2) {
181             VPE_LOGI("Prioritize using extream vision algo when scaling down scenes");
182             return DETAIL_ENH_LEVEL_HIGH;
183         }
184         return DETAIL_ENH_LEVEL_HIGH_AISR;
185     }
186     return parameter_.level;
187 }
188 
ProcessVideo(const sptr<SurfaceBuffer> & input,const sptr<SurfaceBuffer> & output)189 VPEAlgoErrCode DetailEnhancerImageFwk::ProcessVideo(const sptr<SurfaceBuffer>& input,
190     const sptr<SurfaceBuffer>& output)
191 {
192     auto algoImpl = GetAlgorithm(DETAIL_ENH_LEVEL_VIDEO);
193     if (algoImpl == nullptr) {
194         VPE_LOGE("Get Algorithm impl for video failed!");
195         return VPE_ALGO_ERR_UNKNOWN;
196     }
197     if (parameterUpdated.load() && (algoImpl->SetParameter(parameter_) !=  VPE_ALGO_ERR_OK)) {
198         VPE_LOGE("set parameter failed!");
199         return VPE_ALGO_ERR_UNKNOWN;
200     } else {
201         parameterUpdated = false;
202     }
203     UpdateLastAlgorithm(algoImpl);
204     if (ProcessAlgorithm(algoImpl, input, output) != VPE_ALGO_ERR_OK) {
205         VPE_LOGE("process video failed");
206         return VPE_ALGO_ERR_UNKNOWN;
207     }
208     return VPE_ALGO_ERR_OK;
209 }
210 
Process(const sptr<SurfaceBuffer> & input,const sptr<SurfaceBuffer> & output)211 VPEAlgoErrCode DetailEnhancerImageFwk::Process(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output)
212 {
213     auto err = DoProcess(input, output);
214     if (err != VPE_ALGO_ERR_OK) {
215         std::lock_guard<std::mutex> lock(restoreLock_);
216         if (!needRestore_) {
217             return err;
218         }
219         VPE_LOGD("Clear status to restore algorithms.");
220         Clear();
221         needRestore_ = false;
222         VPE_LOGD("Try to process again.");
223         err = DoProcess(input, output);
224         VPE_LOGD("process return %{public}d", err);
225     }
226     return err;
227 }
228 
DoProcess(const sptr<SurfaceBuffer> & input,const sptr<SurfaceBuffer> & output)229 VPEAlgoErrCode DetailEnhancerImageFwk::DoProcess(const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output)
230 {
231     CHECK_AND_RETURN_RET_LOG(IsValidProcessedObject(input, output), VPE_ALGO_ERR_INVALID_VAL, "Invalid input!");
232     VPE_SYNC_TRACE;
233     if (type_ == VIDEO) {
234         return ProcessVideo(input, output);
235     }
236     float widthRatio = static_cast<float>(output->GetWidth()) / static_cast<float>(input->GetWidth());
237     float heightRatio = static_cast<float>(output->GetHeight()) / static_cast<float>(input->GetHeight());
238     int targetLevel = EvaluateTargetLevel(input, output, widthRatio, heightRatio);
239     if (targetLevel < DETAIL_ENH_LEVEL_HIGH_AISR &&
240         std::fabs(widthRatio - 1.0f) < EPSILON && std::fabs(heightRatio - 1.0f) < EPSILON) {
241         VPE_LOGI("The current scaling ratio is 1.0, and the algorithm is not AISR, so copy it directly.");
242         return (memcpy_s(output->GetVirAddr(), output->GetSize(), input->GetVirAddr(), input->GetSize()) == EOK) ?
243             VPE_ALGO_ERR_OK : VPE_ALGO_ERR_UNKNOWN;
244     }
245     bool processSuccessfully = false;
246     for (int level = targetLevel; level >= DETAIL_ENH_LEVEL_NONE; level--) {
247         auto algoImpl = GetAlgorithm(level);
248         if (algoImpl == nullptr) {
249             VPE_LOGE("Get Algorithm impl for %{public}d failed!", level);
250             continue;
251         }
252         parameter_.level = static_cast<DetailEnhancerLevel>((level == DETAIL_ENH_LEVEL_HIGH_AISR) ?
253             DETAIL_ENH_LEVEL_HIGH : level); // map level
254         if (algoImpl->SetParameter(parameter_) !=  VPE_ALGO_ERR_OK) {
255             VPE_LOGE("set parameter failed!");
256             return VPE_ALGO_ERR_UNKNOWN;
257         }
258         UpdateLastAlgorithm(algoImpl);
259         if (ProcessAlgorithm(algoImpl, input, output) == VPE_ALGO_ERR_OK) {
260             processSuccessfully = true;
261             break;
262         } else if (level == DETAIL_ENH_LEVEL_HIGH_AISR) {
263             VPE_LOGD("AISR processed failed, try to process by EVE");
264         } else if (level > DETAIL_ENH_LEVEL_NONE) {
265             VPE_LOGW("Failed to process with level %{public}d", level);
266         } else {
267             VPE_LOGE("Failed to process with detail enhancer");
268             return VPE_ALGO_ERR_UNKNOWN;
269         }
270     }
271     return processSuccessfully ? VPE_ALGO_ERR_OK : VPE_ALGO_ERR_INVALID_VAL;
272 }
273 
EnableProtection(bool enable)274 VPEAlgoErrCode DetailEnhancerImageFwk::EnableProtection(bool enable)
275 {
276     std::lock_guard<std::mutex> lock(lock_);
277     VPEAlgoErrCode ret = VPE_ALGO_ERR_OK;
278     for (auto& [level, algo] : algorithms_) {
279         if (algo == nullptr) {
280             VPE_LOGW("Algorithm for level:%{pubcli}d is null!", level);
281             continue;
282         }
283         VPE_LOGD("level:%d enable:%d", level, enable);
284         ret = algo->EnableProtection(enable);
285         if (ret != VPE_ALGO_ERR_OK) {
286             VPE_LOGW("Failed to EnableProtection(%{public}d) for level:%{pubcli}d ret:%{pubcli}d", enable, level, ret);
287         }
288     }
289     enableProtection_ = enable;
290     return ret;
291 }
292 
ResetProtectionStatus()293 VPEAlgoErrCode DetailEnhancerImageFwk::ResetProtectionStatus()
294 {
295     std::lock_guard<std::mutex> lock(lock_);
296     if (lastAlgorithm_ == nullptr) {
297         return VPE_ALGO_ERR_OK;
298     }
299     return lastAlgorithm_->ResetProtectionStatus();
300 }
301 
UpdateLastAlgorithm(const std::shared_ptr<DetailEnhancerBase> & algorithm)302 void DetailEnhancerImageFwk::UpdateLastAlgorithm(const std::shared_ptr<DetailEnhancerBase>& algorithm)
303 {
304     std::lock_guard<std::mutex> lock(lock_);
305     lastAlgorithm_ = algorithm;
306 }
307 
Clear()308 void DetailEnhancerImageFwk::Clear()
309 {
310     std::lock_guard<std::mutex> lock(lock_);
311     lastAlgorithm_ = nullptr;
312     algorithms_.clear();
313     if (hasParameter_) {
314         parameterUpdated = true;
315     }
316 }
317 
ProcessAlgorithm(const std::shared_ptr<DetailEnhancerBase> & algo,const sptr<SurfaceBuffer> & input,const sptr<SurfaceBuffer> & output)318 VPEAlgoErrCode DetailEnhancerImageFwk::ProcessAlgorithm(const std::shared_ptr<DetailEnhancerBase>& algo,
319     const sptr<SurfaceBuffer>& input, const sptr<SurfaceBuffer>& output)
320 {
321     CHECK_AND_RETURN_RET_LOG(algo != nullptr, VPE_ALGO_ERR_INVALID_VAL, "Invalid input: algorithm is null!");
322     auto err = algo->Process(input, output);
323     if (static_cast<VPEAlgoErrExCode>(err) == VPE_ALGO_ERR_INVALID_CLIENT_ID) {
324         VPE_LOGD("needRestore_ = true");
325         std::lock_guard<std::mutex> lock(restoreLock_);
326         needRestore_ = true;
327     }
328     return err;
329 }
330 
DetailEnhancerCreate(int32_t * instance)331 int32_t DetailEnhancerCreate(int32_t* instance)
332 {
333     CHECK_AND_RETURN_RET_LOG(g_externLock.try_lock_for(std::chrono::milliseconds(TIMEOUT_THRESHOLD)),
334         VPE_ALGO_ERR_INVALID_VAL, "get lock timeout");
335     if (instance == nullptr) {
336         VPE_LOGE("invalid instance");
337         g_externLock.unlock();
338         return VPE_ALGO_ERR_INVALID_VAL;
339     }
340     if (g_instanceId != -1) {
341         // if there is an instance, return it
342         *instance = g_instanceId;
343         g_externLock.unlock();
344         return VPE_ALGO_ERR_OK;
345     }
346     auto detailEnh = DetailEnhancerImage::Create();
347     if (detailEnh == nullptr) {
348         VPE_LOGE("cannot create instance");
349         g_externLock.unlock();
350         return VPE_ALGO_ERR_INVALID_VAL;
351     }
352     Extension::ExtensionManager::InstanceVariableType instanceVar { detailEnh };
353     int32_t newId = Extension::ExtensionManager::GetInstance().NewInstanceId(instanceVar);
354     if (newId == -1) {
355         VPE_LOGE("cannot create more instance");
356         g_externLock.unlock();
357         return VPE_ALGO_ERR_NO_MEMORY;
358     }
359     *instance = newId;
360     g_instanceId = newId;
361     g_externLock.unlock();
362     return VPE_ALGO_ERR_OK;
363 }
364 
CreateSurfaceBufFromNativeWindow(OHNativeWindowBuffer * image)365 sptr<SurfaceBuffer> CreateSurfaceBufFromNativeWindow(OHNativeWindowBuffer* image)
366 {
367     OH_NativeBuffer* imageNativeBuffer = nullptr;
368     CHECK_AND_RETURN_RET_LOG(OH_NativeBuffer_FromNativeWindowBuffer(image, &imageNativeBuffer) == GSERROR_OK,
369         nullptr, "invalid input or output image");
370     sptr<SurfaceBuffer> imageSurfaceBuffer(SurfaceBuffer::NativeBufferToSurfaceBuffer(imageNativeBuffer));
371     return imageSurfaceBuffer;
372 }
373 
DetailEnhancerProcessImage(int32_t instance,OHNativeWindowBuffer * inputImage,OHNativeWindowBuffer * outputImage,int32_t level)374 int32_t DetailEnhancerProcessImage(int32_t instance, OHNativeWindowBuffer* inputImage,
375     OHNativeWindowBuffer* outputImage, int32_t level)
376 {
377     CHECK_AND_RETURN_RET_LOG(g_externLock.try_lock_for(std::chrono::milliseconds(TIMEOUT_THRESHOLD)),
378         VPE_ALGO_ERR_INVALID_VAL, "get lock timeout");
379     if (inputImage == nullptr || outputImage == nullptr) {
380         VPE_LOGE("invalid parameters");
381         g_externLock.unlock();
382         return VPE_ALGO_ERR_INVALID_VAL;
383     }
384     auto someInstance = Extension::ExtensionManager::GetInstance().GetInstance(instance);
385     if (someInstance == std::nullopt) {
386         VPE_LOGE("invalid instance");
387         g_externLock.unlock();
388         return VPE_ALGO_ERR_INVALID_VAL;
389     }
390     VPEAlgoErrCode ret = VPE_ALGO_ERR_INVALID_VAL;
391     auto visitFunc = [inputImage, outputImage, &ret, &level](auto&& var) {
392         using VarType = std::decay_t<decltype(var)>;
393         if constexpr (std::is_same_v<VarType, std::shared_ptr<DetailEnhancerImage>>) {
394             sptr<SurfaceBuffer> inputImageSurfaceBuffer = CreateSurfaceBufFromNativeWindow(inputImage);
395             sptr<SurfaceBuffer> outputImageSurfaceBuffer = CreateSurfaceBufFromNativeWindow(outputImage);
396             DetailEnhancerParameters param {
397                 .uri = "",
398                 .level = static_cast<DetailEnhancerLevel>(level),
399             };
400             var->SetParameter(param);
401             ret = var->Process(inputImageSurfaceBuffer, outputImageSurfaceBuffer);
402         } else {
403             VPE_LOGE("instance may be miss used");
404         }
405     };
406     std::visit(visitFunc, *someInstance);
407     g_externLock.unlock();
408     return ret;
409 }
410 
DetailEnhancerDestroy(int32_t * instance)411 int32_t DetailEnhancerDestroy(int32_t* instance)
412 {
413     CHECK_AND_RETURN_RET_LOG(instance != nullptr, VPE_ALGO_ERR_INVALID_VAL, "instance is null");
414     int ret = Extension::ExtensionManager::GetInstance().RemoveInstanceReference(*instance);
415     if (ret == VPE_ALGO_ERR_OK) {
416         g_instanceId = -1;
417     }
418     return ret;
419 }
420 } // namespace VideoProcessingEngine
421 } // namespace Media
422 } // namespace OHOS
423