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 "video_processing_native_base.h"
17
18 #include "common/native_mfmagic.h"
19 #include "native_window.h"
20
21 #include "video_environment_native.h"
22 #include "video_processing_callback_impl.h"
23 #include "vpe_log.h"
24
25 using namespace OHOS;
26 using namespace OHOS::Media::VideoProcessingEngine;
27
VideoProcessingNativeBase(OH_VideoProcessing * context)28 VideoProcessingNativeBase::VideoProcessingNativeBase(OH_VideoProcessing* context) : context_(context)
29 {
30 }
31
Initialize()32 VideoProcessing_ErrorCode VideoProcessingNativeBase::Initialize()
33 {
34 CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
35 "Already init!");
36 std::lock_guard<std::mutex> lock(lock_);
37 CHECK_AND_RETURN_RET_LOG(!isInitialized_.load(), VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
38 "Already init!");
39 auto result = InitializeInner();
40 isInitialized_ = true;
41 return result;
42 }
43
Deinitialize()44 VideoProcessing_ErrorCode VideoProcessingNativeBase::Deinitialize()
45 {
46 CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
47 "Already deinit!");
48 std::lock_guard<std::mutex> lock(lock_);
49 CHECK_AND_RETURN_RET_LOG(isInitialized_.load(), VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
50 "Already deinit!");
51 isInitialized_ = false;
52 auto result = DeinitializeInner();
53 return result;
54 }
55
RegisterCallback(const VideoProcessing_Callback * callback,void * userData)56 VideoProcessing_ErrorCode VideoProcessingNativeBase::RegisterCallback(const VideoProcessing_Callback* callback,
57 void* userData)
58 {
59 CHECK_AND_RETURN_RET_LOG(callback != nullptr, VIDEO_PROCESSING_ERROR_INVALID_PARAMETER, "Callback is null!");
60 CHECK_AND_RETURN_RET_LOG(callback->GetInnerCallback() != nullptr && callback->GetInnerCallback()->IsValid(),
61 VIDEO_PROCESSING_ERROR_INVALID_VALUE, "Callback is empty!");
62
63 return ExecuteWhenIdle([this, &callback, &userData]() {
64 std::lock_guard<std::mutex> lock(callbackLock_);
65 VideoProcessing_ErrorCode errorCode = PrepareRegistrationLocked();
66 if (errorCode != VIDEO_PROCESSING_SUCCESS) {
67 return errorCode;
68 }
69 auto [it, result] = callbacks_.insert({ callback->GetInnerCallback(), userData });
70 CHECK_AND_RETURN_RET_LOG(result, VIDEO_PROCESSING_ERROR_PROCESS_FAILED, "Add callback failed!");
71 hasCallback_ = true;
72 if (callback->GetInnerCallback()->HasOnNewOutputBuffer()) {
73 hasOnRenderOutputBuffer_ = true;
74 }
75 return VIDEO_PROCESSING_SUCCESS;
76 }, "Registration during running is not allowed!");
77 }
78
SetSurface(const OHNativeWindow * window)79 VideoProcessing_ErrorCode VideoProcessingNativeBase::SetSurface(const OHNativeWindow* window)
80 {
81 CHECK_AND_RETURN_RET_LOG(window != nullptr && window->surface != nullptr, VIDEO_PROCESSING_ERROR_INVALID_PARAMETER,
82 "window is null or surface buffer is null!");
83
84 std::lock_guard<std::mutex> lock(lock_);
85 auto result = SetSurface(window->surface, *window);
86 hasOutputSurface_ = (result == VIDEO_PROCESSING_SUCCESS);
87 return result;
88 }
89
GetSurface(OHNativeWindow ** window)90 VideoProcessing_ErrorCode VideoProcessingNativeBase::GetSurface(OHNativeWindow** window)
91 {
92 CHECK_AND_RETURN_RET_LOG(window != nullptr, VIDEO_PROCESSING_ERROR_INVALID_PARAMETER, "window is null!");
93 return ExecuteWhenIdle([this, &window]() {
94 if (hasInputSurface_.load()) {
95 VPE_LOGE("Input surface is already created!");
96 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
97 }
98
99 sptr<Surface> surface = GetSurface();
100 CHECK_AND_RETURN_RET_LOG(surface != nullptr, VIDEO_PROCESSING_ERROR_CREATE_FAILED, "get surface failed!");
101 *window = CreateNativeWindowFromSurface(&surface);
102 CHECK_AND_RETURN_RET_LOG(*window != nullptr, VIDEO_PROCESSING_ERROR_CREATE_FAILED, "create window failed!");
103 hasInputSurface_ = true;
104 return VIDEO_PROCESSING_SUCCESS;
105 }, "Surface getting during running is not allowed!");
106 }
107
SetParameter(const OH_AVFormat * parameter)108 VideoProcessing_ErrorCode VideoProcessingNativeBase::SetParameter(const OH_AVFormat* parameter)
109 {
110 CHECK_AND_RETURN_RET_LOG(parameter != nullptr, VIDEO_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
111 return SetParameter(parameter->format_);
112 }
113
GetParameter(OH_AVFormat * parameter)114 VideoProcessing_ErrorCode VideoProcessingNativeBase::GetParameter(OH_AVFormat* parameter)
115 {
116 CHECK_AND_RETURN_RET_LOG(parameter != nullptr, VIDEO_PROCESSING_ERROR_INVALID_PARAMETER, "parameter is null!");
117 return GetParameter(parameter->format_);
118 }
119
Start()120 VideoProcessing_ErrorCode VideoProcessingNativeBase::Start()
121 {
122 return ExecuteWhenIdle([this]() {
123 CHECK_AND_RETURN_RET_LOG(hasInputSurface_.load() && hasOutputSurface_.load() && hasCallback_.load(),
124 VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
125 "Input/Output surface is not ready or the callback is not registered!");
126
127 TraverseCallbacksLocked([](std::shared_ptr<VideoProcessingCallbackNative>& cb, void*) { cb->LockModifiers(); });
128 isRunning_ = true;
129 return OnStart();
130 }, "Already start!");
131 }
132
Stop()133 VideoProcessing_ErrorCode VideoProcessingNativeBase::Stop()
134 {
135 return ExecuteWhenRunning([this]() {
136 TraverseCallbacksLocked(
137 [](std::shared_ptr<VideoProcessingCallbackNative>& cb, void*) { cb->UnlockModifiers(); });
138 isRunning_ = false;
139 return OnStop();
140 }, "Already stop!");
141 }
142
RenderOutputBuffer(uint32_t index)143 VideoProcessing_ErrorCode VideoProcessingNativeBase::RenderOutputBuffer(uint32_t index)
144 {
145 CHECK_AND_RETURN_RET_LOG(hasOnRenderOutputBuffer_.load(), VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED,
146 "The operation is not permitted without binding OnRenderOutputBuffer!");
147 if (isOnNewOutputBuffer_.load()) {
148 return OnRenderOutputBuffer(index);
149 }
150 return ExecuteWhenRunning([this, &index]() {
151 return OnRenderOutputBuffer(index);
152 }, "RenderOutputBuffer must be called during running!");
153 }
154
InitializeInner()155 VideoProcessing_ErrorCode VideoProcessingNativeBase::InitializeInner()
156 {
157 return VideoEnvironmentNative::Get().InitializeByDefault();
158 }
159
DeinitializeInner()160 VideoProcessing_ErrorCode VideoProcessingNativeBase::DeinitializeInner()
161 {
162 return VideoEnvironmentNative::Get().DeinitializeByDefault();
163 }
164
RegisterCallback()165 VideoProcessing_ErrorCode VideoProcessingNativeBase::RegisterCallback()
166 {
167 return VIDEO_PROCESSING_SUCCESS;
168 }
169
SetSurface(const sptr<Surface> & surface,const OHNativeWindow & window)170 VideoProcessing_ErrorCode VideoProcessingNativeBase::SetSurface(const sptr<Surface>& surface,
171 [[maybe_unused]] const OHNativeWindow& window)
172 {
173 return SetSurface(surface);
174 }
175
SetSurface(const sptr<Surface> & surface)176 VideoProcessing_ErrorCode VideoProcessingNativeBase::SetSurface([[maybe_unused]] const sptr<Surface>& surface)
177 {
178 return VIDEO_PROCESSING_SUCCESS;
179 }
180
GetSurface()181 sptr<Surface> VideoProcessingNativeBase::GetSurface()
182 {
183 return nullptr;
184 }
185
SetParameter(const OHOS::Media::Format & parameter)186 VideoProcessing_ErrorCode VideoProcessingNativeBase::SetParameter([[maybe_unused]] const OHOS::Media::Format& parameter)
187 {
188 return VIDEO_PROCESSING_SUCCESS;
189 }
190
GetParameter(OHOS::Media::Format & parameter)191 VideoProcessing_ErrorCode VideoProcessingNativeBase::GetParameter([[maybe_unused]] OHOS::Media::Format& parameter)
192 {
193 return VIDEO_PROCESSING_SUCCESS;
194 }
195
OnStart()196 VideoProcessing_ErrorCode VideoProcessingNativeBase::OnStart()
197 {
198 return VIDEO_PROCESSING_SUCCESS;
199 }
200
OnStop()201 VideoProcessing_ErrorCode VideoProcessingNativeBase::OnStop()
202 {
203 return VIDEO_PROCESSING_SUCCESS;
204 }
205
OnRenderOutputBuffer(uint32_t index)206 VideoProcessing_ErrorCode VideoProcessingNativeBase::OnRenderOutputBuffer([[maybe_unused]] uint32_t index)
207 {
208 return VIDEO_PROCESSING_SUCCESS;
209 }
210
OnError(VideoProcessing_ErrorCode errorCode)211 void VideoProcessingNativeBase::OnError(VideoProcessing_ErrorCode errorCode)
212 {
213 OnCallback([this, &errorCode](std::shared_ptr<VideoProcessingCallbackNative>& callback, void* userData) {
214 callback->OnError(context_, errorCode, userData);
215 }, "OnError");
216 }
217
OnState(VideoProcessing_State state)218 void VideoProcessingNativeBase::OnState(VideoProcessing_State state)
219 {
220 OnCallback([this, &state](std::shared_ptr<VideoProcessingCallbackNative>& callback, void* userData) {
221 callback->OnState(context_, state, userData);
222 }, "OnState");
223 }
224
OnNewOutputBuffer(uint32_t index)225 void VideoProcessingNativeBase::OnNewOutputBuffer(uint32_t index)
226 {
227 if (!isInitialized_.load()) {
228 VPE_LOGI("Skip index:%{public}u buffer because VPE has been deinitialized.", index);
229 return;
230 }
231 OnCallback([this, &index](std::shared_ptr<VideoProcessingCallbackNative>& callback, void* userData) {
232 if (callback->HasOnNewOutputBuffer()) {
233 isOnNewOutputBuffer_ = true;
234 callback->OnNewOutputBuffer(context_, index, userData);
235 isOnNewOutputBuffer_ = false;
236 } else {
237 OnRenderOutputBuffer(index);
238 }
239 }, "OnNewOutputBuffer");
240 }
241
ExecuteWhenIdle(std::function<VideoProcessing_ErrorCode (void)> && task,const std::string & errLog)242 VideoProcessing_ErrorCode VideoProcessingNativeBase::ExecuteWhenIdle(
243 std::function<VideoProcessing_ErrorCode(void)>&& task, const std::string& errLog)
244 {
245 if (isRunning_.load()) {
246 VPE_LOGW("%{public}s", errLog.c_str());
247 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
248 }
249
250 std::lock_guard<std::mutex> lock(lock_);
251 if (isRunning_.load()) {
252 VPE_LOGW("%{public}s", errLog.c_str());
253 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
254 }
255 return task();
256 }
257
ExecuteWhenRunning(std::function<VideoProcessing_ErrorCode (void)> && task,const std::string & errLog)258 VideoProcessing_ErrorCode VideoProcessingNativeBase::ExecuteWhenRunning(
259 std::function<VideoProcessing_ErrorCode(void)>&& task, const std::string& errLog)
260 {
261 if (!isRunning_.load()) {
262 VPE_LOGW("%{public}s", errLog.c_str());
263 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
264 }
265
266 std::lock_guard<std::mutex> lock(lock_);
267 if (!isRunning_.load()) {
268 VPE_LOGW("%{public}s", errLog.c_str());
269 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
270 }
271 return task();
272 }
273
OnCallback(std::function<void (std::shared_ptr<VideoProcessingCallbackNative> &,void *)> && task,const std::string & name)274 void VideoProcessingNativeBase::OnCallback(
275 std::function<void(std::shared_ptr<VideoProcessingCallbackNative>&, void*)>&& task,
276 const std::string& name)
277 {
278 std::lock_guard<std::mutex> lock(callbackLock_);
279 TraverseCallbacksLocked(std::move(task));
280 }
281
TraverseCallbacksLocked(std::function<void (std::shared_ptr<VideoProcessingCallbackNative> &,void *)> && task)282 void VideoProcessingNativeBase::TraverseCallbacksLocked(
283 std::function<void(std::shared_ptr<VideoProcessingCallbackNative>&, void*)>&& task)
284 {
285 TraverseCallbacksExLocked([&task](std::shared_ptr<VideoProcessingCallbackNative>& cb, void* userData) {
286 task(cb, userData);
287 return false;
288 });
289 }
290
TraverseCallbacksExLocked(std::function<bool (std::shared_ptr<VideoProcessingCallbackNative> &,void *)> && task)291 void VideoProcessingNativeBase::TraverseCallbacksExLocked(
292 std::function<bool(std::shared_ptr<VideoProcessingCallbackNative>&, void*)>&& task)
293 {
294 for (auto& callback : callbacks_) {
295 std::shared_ptr<VideoProcessingCallbackNative> cb = callback.callback;
296 if (cb == nullptr) [[unlikely]] {
297 VPE_LOGW("callback is null!");
298 continue;
299 }
300 if (task(cb, callback.userData)) {
301 break;
302 }
303 }
304 }
305
PrepareRegistrationLocked()306 VideoProcessing_ErrorCode VideoProcessingNativeBase::PrepareRegistrationLocked()
307 {
308 if (isInnerCallbackReady_) {
309 return VIDEO_PROCESSING_SUCCESS;
310 }
311 VideoProcessing_ErrorCode errorCode = RegisterCallback();
312 if (errorCode == VIDEO_PROCESSING_SUCCESS) {
313 VPE_LOGD("Inner RegisterCallback success.");
314 isInnerCallbackReady_ = true;
315 }
316 return errorCode;
317 }
318