• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "video_processing_server.h"
17 
18 #include <fstream>
19 #include <iostream>
20 #include <sstream>
21 
22 #include <iservice_registry.h>
23 #include <system_ability_definition.h>
24 
25 #include "algorithm_errors.h"
26 #include "surface_buffer.h"
27 #include "vpe_model_path.h"
28 #include "vpe_sa_constants.h"
29 
30 using namespace OHOS::Media::VideoProcessingEngine;
31 using namespace OHOS;
32 using namespace std::placeholders;
33 
34 using VpeAlgo = IVideoProcessingAlgorithm;
35 
36 namespace {
37 const int VPE_INFO_FILE_MAX_LENGTH = 20485760;
38 const std::string UNLOAD_HANLDER = "unload_vpe_sa_handler";
39 const std::string UNLOAD_TASK_ID = "unload_vpe_sa";
40 constexpr int32_t DELAY_TIME = 180000;
41 REGISTER_SYSTEM_ABILITY_BY_ID(VideoProcessingServer, VIDEO_PROCESSING_SERVER_SA_ID, false);
42 }
43 
VideoProcessingServer(int32_t saId,bool runOnCreate)44 VideoProcessingServer::VideoProcessingServer(int32_t saId, bool runOnCreate) : SystemAbility(saId, runOnCreate)
45 {
46     VPE_LOGD("VideoProcessingServer construct!");
47 }
48 
~VideoProcessingServer()49 VideoProcessingServer::~VideoProcessingServer()
50 {
51     VPE_LOGD("VideoProcessingServer destruction!");
52 }
53 
LoadInfo(int32_t key,SurfaceBufferInfo & bufferInfo)54 ErrCode VideoProcessingServer::LoadInfo(int32_t key, SurfaceBufferInfo& bufferInfo)
55 {
56     if (key < 0 || key >= VPE_MODEL_KEY_NUM) {
57         VPE_LOGE("Input key %{public}d is invalid!", key);
58         UnloadVideoProcessingSA();
59         return ERR_INVALID_DATA;
60     }
61     std::string path = VPE_MODEL_PATHS[key];
62     VPE_LOGD("LoadInfoForVpe %{public}s", path.c_str());
63     bufferInfo.surfacebuffer = SurfaceBuffer::Create();
64     if (bufferInfo.surfacebuffer == nullptr) {
65         VPE_LOGE("Create surface buffer failed");
66         UnloadVideoProcessingSA();
67         return ERR_NULL_OBJECT;
68     }
69     std::unique_ptr<std::ifstream> fileStream = std::make_unique<std::ifstream>(path, std::ios::binary);
70     if (!fileStream->is_open()) {
71         VPE_LOGE("file is not open %{public}s", path.c_str());
72         UnloadVideoProcessingSA();
73         return ERR_NULL_OBJECT;
74     }
75     fileStream->seekg(0, std::ios::end);
76     int fileLength = fileStream->tellg();
77     fileStream->seekg(0, std::ios::beg);
78     if (fileLength < 0 || fileLength > VPE_INFO_FILE_MAX_LENGTH) {
79         VPE_LOGE("fileLength %{public}d is too short or too long!", fileLength);
80         UnloadVideoProcessingSA();
81         return ERR_INVALID_DATA;
82     }
83 
84     BufferRequestConfig inputCfg;
85     inputCfg.width = fileLength;
86     inputCfg.height = 1;
87     VPE_LOGD("FileLength: %{public}d", fileLength);
88     inputCfg.strideAlignment = fileLength;
89     inputCfg.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA;
90     inputCfg.format = GRAPHIC_PIXEL_FMT_YCBCR_420_SP;
91     inputCfg.timeout = 0;
92     GSError err = bufferInfo.surfacebuffer->Alloc(inputCfg);
93     if (err != GSERROR_OK) {
94         VPE_LOGE("Alloc surface buffer failed");
95         UnloadVideoProcessingSA();
96         return ERR_INVALID_DATA;
97     }
98     fileStream->read(reinterpret_cast<char*>(bufferInfo.surfacebuffer->GetVirAddr()), fileLength);
99     fileStream->close();
100     UnloadVideoProcessingSA();
101     return ERR_NONE;
102 }
103 
104 // For optimized SA
Create(const std::string & feature,const std::string & clientName,int32_t & clientID)105 ErrCode VideoProcessingServer::Create(const std::string& feature, const std::string& clientName, int32_t& clientID)
106 {
107     VPE_LOGD(">>> feature:%{public}s client:%{public}s", feature.c_str(), clientName.c_str());
108     uint32_t id;
109     std::lock_guard<std::mutex> lock(lock_);
110     auto ret = CreateLocked(feature, clientName, id);
111     if (ret == VPE_ALGO_ERR_OK) {
112         clientID = static_cast<int>(id);
113         VPE_LOGD("<<< feature:%{public}s client:%{public}s isWorking_:%{public}d {new ID:%{public}u}",
114             feature.c_str(), clientName.c_str(), isWorking_.load(), id);
115     }
116     DelayUnloadTaskLocked();
117     return ret;
118 }
119 
Destroy(int32_t clientID)120 ErrCode VideoProcessingServer::Destroy(int32_t clientID)
121 {
122     std::lock_guard<std::mutex> lock(lock_);
123     auto ret = DestroyLocked(static_cast<uint32_t>(clientID));
124     DelayUnloadTaskLocked();
125     return ret;
126 }
127 
SetParameter(int32_t clientID,int32_t tag,const std::vector<uint8_t> & parameter)128 ErrCode VideoProcessingServer::SetParameter(int32_t clientID, int32_t tag, const std::vector<uint8_t>& parameter)
129 {
130     return Execute(clientID, std::bind(&VpeAlgo::SetParameter, _1, _2, tag, parameter), VPE_LOG_INFO);
131 }
132 
GetParameter(int32_t clientID,int32_t tag,std::vector<uint8_t> & parameter)133 ErrCode VideoProcessingServer::GetParameter(int32_t clientID, int32_t tag, std::vector<uint8_t>& parameter)
134 {
135     return Execute(clientID, std::bind(&VpeAlgo::GetParameter, _1, _2, tag, parameter), VPE_LOG_INFO);
136 }
137 
UpdateMetadata(int32_t clientID,SurfaceBufferInfo & image)138 ErrCode VideoProcessingServer::UpdateMetadata(int32_t clientID, SurfaceBufferInfo& image)
139 {
140     CHECK_AND_RETURN_RET_LOG(image.surfacebuffer != nullptr, VPE_ALGO_ERR_INVALID_PARAM,
141         "Invalid input: image is null!");
142     return Execute(clientID, std::bind(&VpeAlgo::UpdateMetadata, _1, _2, image), VPE_LOG_INFO);
143 }
144 
Process(int32_t clientID,const SurfaceBufferInfo & input,SurfaceBufferInfo & output)145 ErrCode VideoProcessingServer::Process(int32_t clientID, const SurfaceBufferInfo& input, SurfaceBufferInfo& output)
146 {
147     CHECK_AND_RETURN_RET_LOG(input.surfacebuffer != nullptr && output.surfacebuffer != nullptr,
148         VPE_ALGO_ERR_INVALID_PARAM, "Invalid input: input or output is null!");
149     return Execute(clientID, std::bind(&VpeAlgo::Process, _1, _2, input, output), VPE_LOG_INFO);
150 }
151 
ComposeImage(int32_t clientID,const SurfaceBufferInfo & inputSdrImage,const SurfaceBufferInfo & inputGainmap,SurfaceBufferInfo & outputHdrImage,bool legacy)152 ErrCode VideoProcessingServer::ComposeImage(int32_t clientID, const SurfaceBufferInfo& inputSdrImage,
153     const SurfaceBufferInfo& inputGainmap, SurfaceBufferInfo& outputHdrImage, bool legacy)
154 {
155     CHECK_AND_RETURN_RET_LOG(inputSdrImage.surfacebuffer != nullptr && inputGainmap.surfacebuffer != nullptr &&
156         outputHdrImage.surfacebuffer != nullptr, VPE_ALGO_ERR_INVALID_PARAM, "Invalid input: input or output is null!");
157     return Execute(clientID,
158         std::bind(&VpeAlgo::ComposeImage, _1, _2, inputSdrImage, inputGainmap, outputHdrImage, legacy), VPE_LOG_INFO);
159 }
160 
DecomposeImage(int32_t clientID,const SurfaceBufferInfo & inputImage,SurfaceBufferInfo & outputSdrImage,SurfaceBufferInfo & outputGainmap)161 ErrCode VideoProcessingServer::DecomposeImage(int32_t clientID, const SurfaceBufferInfo& inputImage,
162     SurfaceBufferInfo& outputSdrImage, SurfaceBufferInfo& outputGainmap)
163 {
164     CHECK_AND_RETURN_RET_LOG(inputImage.surfacebuffer != nullptr && outputSdrImage.surfacebuffer != nullptr &&
165         outputGainmap.surfacebuffer != nullptr, VPE_ALGO_ERR_INVALID_PARAM, "Invalid input: input or output is null!");
166     return Execute(clientID,
167         std::bind(&VpeAlgo::DecomposeImage, _1, _2, inputImage, outputSdrImage, outputGainmap), VPE_LOG_INFO);
168 }
169 
UnloadVideoProcessingSA()170 void VideoProcessingServer::UnloadVideoProcessingSA()
171 {
172     if (CreateUnloadHandler()) {
173         VPE_LOGI("CreateUnloadHandler success!");
174         DelayUnloadTask();
175     } else {
176         return;
177     }
178     VPE_LOGD("Start/Update Delay Time Unload VPE SA!");
179     return;
180 }
181 
OnStart(const SystemAbilityOnDemandReason & startReason)182 void VideoProcessingServer::OnStart(const SystemAbilityOnDemandReason& startReason)
183 {
184     VPE_LOGD("Start VPE SA because %{public}s.", startReason.GetName().c_str());
185     if (CreateUnloadHandler()) {
186         VPE_LOGI("CreateUnloadHandler success!");
187         DelayUnloadTask();
188     }
189     CHECK_AND_RETURN_LOG(Publish(this), "Failed to publish SA!");
190 }
191 
OnStop(const SystemAbilityOnDemandReason & stopReason)192 void VideoProcessingServer::OnStop(const SystemAbilityOnDemandReason& stopReason)
193 {
194     VPE_LOGD("Stop VPE SA because %{public}s.", stopReason.GetName().c_str());
195     DestroyUnloadHandler();
196     ClearAlgorithms();
197 }
198 
CreateLocked(const std::string & feature,const std::string & clientName,uint32_t & id)199 ErrCode VideoProcessingServer::CreateLocked(const std::string& feature, const std::string& clientName, uint32_t& id)
200 {
201     AlgoPtr algo = nullptr;
202     bool isNew = false;
203     auto it = algorithms_.find(feature);
204     if (it == algorithms_.end() || it->second == nullptr) {
205         algo = factory_.Create(feature);
206         CHECK_AND_RETURN_RET_LOG(algo != nullptr, VPE_ALGO_ERR_NO_MEMORY,
207             "Failed to create '%{public}s' for '%{public}s'!", feature.c_str(), clientName.c_str());
208         CHECK_AND_RETURN_RET_LOG(algo->Initialize() == VPE_ALGO_ERR_OK, ERR_INVALID_STATE,
209             "Failed to initialize '%{public}s' for '%{public}s'!", feature.c_str(), clientName.c_str());
210         isNew = true;
211     } else {
212         algo = it->second;
213     }
214     CHECK_AND_RETURN_RET_LOG(algo->Add(clientName, id) == VPE_ALGO_ERR_OK, ERR_INVALID_DATA,
215         "Failed to add client to '%{public}s' for '%{public}s'!", feature.c_str(), clientName.c_str());
216     clients_[id] = feature;
217     if (isNew) {
218         algorithms_[feature] = algo;
219     }
220     isWorking_ = true;
221     return VPE_ALGO_ERR_OK;
222 }
223 
DestroyLocked(uint32_t id)224 ErrCode VideoProcessingServer::DestroyLocked(uint32_t id)
225 {
226     auto it = clients_.find(id);
227     if (it == clients_.end()) [[unlikely]] {
228         VPE_LOGE("Invalid input: no client for ID=%{public}d", id);
229         return VPE_ALGO_ERR_INVALID_CLIENT_ID;
230     }
231     std::string feature = it->second;
232     clients_.erase(it);
233     isWorking_ = !clients_.empty();
234     VPE_LOGD("isWorking_:%{public}d", isWorking_.load());
235     auto itAlgo = algorithms_.find(feature);
236     if (itAlgo == algorithms_.end()) [[unlikely]] {
237         VPE_LOGE("Invalid input: no '%{public}s' for ID=%{public}d", feature.c_str(), id);
238         return VPE_ALGO_ERR_INVALID_VAL;
239     }
240     if (itAlgo->second == nullptr) [[unlikely]] {
241         VPE_LOGE("Invalid input: null '%{public}s' for ID=%{public}d", feature.c_str(), id);
242         algorithms_.erase(itAlgo);
243         return VPE_ALGO_ERR_INVALID_VAL;
244     }
245     auto algo = itAlgo->second;
246     auto ret = algo->Del(id);
247     CHECK_AND_LOG(ret == VPE_ALGO_ERR_OK, "Failed to del(ID=%{public}d) of '%{public}s'", id, feature.c_str());
248     if (!algo->HasClient()) {
249         ret = algo->Deinitialize();
250         CHECK_AND_LOG(ret == VPE_ALGO_ERR_OK, "Failed to deinitialize of '%{public}s' for ID=%{public}d",
251             feature.c_str(), id);
252         algorithms_.erase(itAlgo);
253     }
254     return ret;
255 }
256 
CreateUnloadHandler()257 bool VideoProcessingServer::CreateUnloadHandler()
258 {
259     std::lock_guard<std::mutex> lock(lock_);
260     return CreateUnloadHandlerLocked();
261 }
262 
CreateUnloadHandlerLocked()263 bool VideoProcessingServer::CreateUnloadHandlerLocked()
264 {
265     if (unloadHandler_ != nullptr) {
266         return true;
267     }
268     unloadHandler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::Create(UNLOAD_HANLDER));
269     return unloadHandler_ != nullptr;
270 }
271 
DestroyUnloadHandler()272 void VideoProcessingServer::DestroyUnloadHandler()
273 {
274     std::lock_guard<std::mutex> lock(lock_);
275     if (unloadHandler_ != nullptr) {
276         unloadHandler_->RemoveAllEvents();
277         unloadHandler_->RemoveTask(UNLOAD_TASK_ID);
278         unloadHandler_ = nullptr;
279     }
280 }
281 
DelayUnloadTask()282 void VideoProcessingServer::DelayUnloadTask()
283 {
284     std::lock_guard<std::mutex> lock(lock_);
285     DelayUnloadTaskLocked();
286 }
287 
DelayUnloadTaskLocked()288 void VideoProcessingServer::DelayUnloadTaskLocked()
289 {
290     VPE_LOGD("delay unload task begin, isWorking_:%{public}d", isWorking_.load());
291     CHECK_AND_RETURN_LOG(CreateUnloadHandlerLocked(), "unloadHandler_ is NOT created!");
292     unloadHandler_->RemoveTask(UNLOAD_TASK_ID);
293     VPE_LOGD("delay unload task post task(wait %{public}dms)", DELAY_TIME);
294     auto task = [this]() {
295         VPE_LOGD("do unload task, isWorking_:%{public}d", isWorking_.load());
296         auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
297         CHECK_AND_RETURN_LOG(samgr != nullptr, "Failed to GetSystemAbilityManager!");
298         CHECK_AND_RETURN_LOG(samgr->UnloadSystemAbility(VIDEO_PROCESSING_SERVER_SA_ID) == ERR_OK,
299             "Failed to unload VPE SA!");
300         VPE_LOGI("kill VPE service success!");
301     };
302     unloadHandler_->PostTask(task, UNLOAD_TASK_ID, DELAY_TIME);
303 }
304 
ClearAlgorithms()305 void VideoProcessingServer::ClearAlgorithms()
306 {
307     std::lock_guard<std::mutex> lock(lock_);
308     for (auto& [feature, algo] : algorithms_) {
309         if (algo == nullptr) [[unlikely]] {
310             VPE_LOGE("algorithm is null of '%{public}s'!", feature.c_str());
311             continue;
312         }
313         if (algo->Deinitialize() != VPE_ALGO_ERR_OK) [[unlikely]] {
314             VPE_LOGE("Failed to deinitialize of '%{public}s'!", feature.c_str());
315             continue;
316         }
317     }
318     algorithms_.clear();
319     clients_.clear();
320     isWorking_ = false;
321     VPE_LOGD("isWorking_:%{public}d", isWorking_.load());
322 }
323 
Execute(int clientID,std::function<int (AlgoPtr &,uint32_t)> && operation,const LogInfo & logInfo)324 ErrCode VideoProcessingServer::Execute(int clientID, std::function<int(AlgoPtr&, uint32_t)>&& operation,
325     const LogInfo& logInfo)
326 {
327     uint32_t id = static_cast<uint32_t>(clientID);
328     AlgoPtr algorithm;
329     {
330         std::lock_guard<std::mutex> lock(lock_);
331         auto it = clients_.find(id);
332         if (it == clients_.end()) [[unlikely]] {
333             VPE_ORG_LOGE(logInfo, "Invalid input: no client for ID=%{public}d!", id);
334             DelayUnloadTaskLocked();
335             return VPE_ALGO_ERR_INVALID_CLIENT_ID;
336         }
337         auto itAlgo = algorithms_.find(it->second);
338         if (itAlgo == algorithms_.end() || itAlgo->second == nullptr) [[unlikely]] {
339             VPE_ORG_LOGE(logInfo, "Invalid input: no '%{public}s' for ID=%{public}d!", it->second.c_str(), id);
340             DelayUnloadTaskLocked();
341             return VPE_ALGO_ERR_INVALID_VAL;
342         }
343         algorithm = itAlgo->second;
344     }
345     auto err = operation(algorithm, id);
346     DelayUnloadTask();
347     return err;
348 }
349