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.h"
17
18 #include <chrono>
19 #include <cinttypes>
20
21 #include "common/native_mfmagic.h"
22 #include "native_window.h"
23
24 #include "vpe_log.h"
25 #include "video_processing_callback_impl.h"
26
27 using namespace OHOS;
28 using namespace OHOS::Media::VideoProcessingEngine;
29
30 namespace {
31 constexpr uint32_t BUFFER_QUEUE_SIZE = 5;
32 constexpr int LIMITTED_TIME = 100;
33 const std::unordered_map<AlgoErrorCode, VideoProcessing_ErrorCode> ERROR_MAP = {
34 { ALGO_SUCCESS, VIDEO_PROCESSING_SUCCESS },
35 { ALGO_ERROR_INVALID_PARAMETER, VIDEO_PROCESSING_ERROR_INVALID_PARAMETER },
36 { ALGO_ERROR_UNKNOWN, VIDEO_PROCESSING_ERROR_UNKNOWN },
37 { ALGO_ERROR_INITIALIZE_FAILED, VIDEO_PROCESSING_ERROR_INITIALIZE_FAILED },
38 { ALGO_ERROR_CREATE_FAILED, VIDEO_PROCESSING_ERROR_CREATE_FAILED },
39 { ALGO_ERROR_PROCESS_FAILED, VIDEO_PROCESSING_ERROR_PROCESS_FAILED },
40 { ALGO_ERROR_UNSUPPORTED_PROCESSING, VIDEO_PROCESSING_ERROR_UNSUPPORTED_PROCESSING },
41 { ALGO_ERROR_OPERATION_NOT_PERMITTED, VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED },
42 { ALGO_ERROR_NO_MEMORY, VIDEO_PROCESSING_ERROR_NO_MEMORY },
43 { ALGO_ERROR_INVALID_INSTANCE, VIDEO_PROCESSING_ERROR_INVALID_INSTANCE },
44 { ALGO_ERROR_INVALID_VALUE, VIDEO_PROCESSING_ERROR_INVALID_VALUE },
45 };
46 }
47
Initialize()48 VideoProcessing_ErrorCode VideoProcessingNative::Initialize()
49 {
50 std::lock_guard<std::mutex> lock(lock_);
51 if (isInitialized_) {
52 VPE_LOGE("Already initialize!");
53 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
54 }
55 worker_ = std::thread([this]() {
56 while (!isExit_.load()) {
57 {
58 std::unique_lock<std::mutex> lock(bufferLock_);
59 if (!WaitCV([this] {
60 return isExit_.load() || (!producerBufferQueue_.empty() && !consumerBufferQueue_.empty());
61 }, lock)) {
62 CheckStopping();
63 continue;
64 }
65
66 if (isExit_.load()) {
67 VPE_LOGI("Video processing destroy.");
68 break;
69 }
70 if (producerBufferQueue_.empty() || consumerBufferQueue_.empty()) {
71 VPE_LOGD("Video processing spurious wakeup.");
72 continue;
73 }
74 }
75 ProcessBuffers();
76 CheckStopping();
77 };
78 });
79 auto errorCode = InitializeInner();
80 isInitialized_ = true;
81 return errorCode;
82 }
83
Deinitialize()84 VideoProcessing_ErrorCode VideoProcessingNative::Deinitialize()
85 {
86 VideoProcessing_ErrorCode errorCode;
87 {
88 std::lock_guard<std::mutex> lock(lock_);
89 if (!isInitialized_) {
90 VPE_LOGE("Already deinitialize!");
91 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
92 }
93 isInitialized_ = false;
94 errorCode = DeinitializeInner();
95 if (state_.load() == VPEState::RUNNING) {
96 state_ = VPEState::STOPPING;
97 }
98 isExit_ = true;
99 }
100 cv_.notify_one();
101 if (worker_.joinable()) {
102 worker_.join();
103 }
104 CheckStopping();
105 return errorCode;
106 }
107
RegisterCallback(const VideoProcessing_Callback * callback,void * userData)108 VideoProcessing_ErrorCode VideoProcessingNative::RegisterCallback(const VideoProcessing_Callback* callback,
109 void* userData)
110 {
111 if (callback == nullptr || callback->GetObj() == nullptr || !callback->GetObj()->IsValid()) {
112 VPE_LOGE("callback is null or invalid!");
113 return VIDEO_PROCESSING_ERROR_INVALID_PARAMETER;
114 }
115
116 return ExecuteWhenIdle([this, callback, userData]() {
117 callback_ = callback->GetObj();
118 userData_ = userData;
119 return VIDEO_PROCESSING_SUCCESS;
120 }, "Registration of callbacks during running is not allowed!");
121 }
122
SetSurface(const OHNativeWindow * window)123 VideoProcessing_ErrorCode VideoProcessingNative::SetSurface(const OHNativeWindow* window)
124 {
125 if (window == nullptr || window->surface == nullptr || window->surface->IsConsumer() ||
126 !IsProducerSurfaceValid(*window)) {
127 VPE_LOGE("window is null or invalid!");
128 return VIDEO_PROCESSING_ERROR_INVALID_PARAMETER;
129 }
130
131 std::lock_guard<std::mutex> lock(lock_);
132 auto surface = window->surface;
133 GSError errorCode = surface->RegisterReleaseListener([this]([[maybe_unused]] sptr<SurfaceBuffer> &buffer) {
134 return OnProducerBufferReleased();
135 });
136 if (errorCode != GSERROR_OK) {
137 VPE_LOGE("window is null or invalid!");
138 return VIDEO_PROCESSING_ERROR_PROCESS_FAILED;
139 }
140 surface->SetQueueSize(BUFFER_QUEUE_SIZE);
141
142 producer_ = surface;
143 return SetProducerSurface(*window, requestCfg_);
144 }
145
GetSurface(OHNativeWindow ** window)146 VideoProcessing_ErrorCode VideoProcessingNative::GetSurface(OHNativeWindow** window)
147 {
148 if (window == nullptr) {
149 VPE_LOGE("window is null!");
150 return VIDEO_PROCESSING_ERROR_INVALID_PARAMETER;
151 }
152 return ExecuteWhenIdle([this, window]() {
153 if (consumer_ != nullptr) {
154 VPE_LOGE("consumer surface is already created!");
155 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
156 }
157
158 consumer_ = CreateConsumerSurface(*window);
159 if (consumer_ == nullptr) {
160 VPE_LOGE("Failed to create consumer surface!");
161 return VIDEO_PROCESSING_ERROR_CREATE_FAILED;
162 }
163 return VIDEO_PROCESSING_SUCCESS;
164 }, "Getting a surface during running is not allowed!");
165 }
166
SetParameter(const OH_AVFormat * parameter)167 VideoProcessing_ErrorCode VideoProcessingNative::SetParameter(const OH_AVFormat* parameter)
168 {
169 if (parameter == nullptr) {
170 VPE_LOGE("parameter is null!");
171 return VIDEO_PROCESSING_ERROR_INVALID_PARAMETER;
172 }
173 return SetParameter(parameter->format_);
174 }
175
GetParameter(OH_AVFormat * parameter)176 VideoProcessing_ErrorCode VideoProcessingNative::GetParameter(OH_AVFormat* parameter)
177 {
178 if (parameter == nullptr) {
179 VPE_LOGE("parameter is null!");
180 return VIDEO_PROCESSING_ERROR_INVALID_PARAMETER;
181 }
182 return GetParameter(parameter->format_);
183 }
184
Start()185 VideoProcessing_ErrorCode VideoProcessingNative::Start()
186 {
187 auto errorCode = ExecuteWhenIdle([this]() {
188 if (consumer_ == nullptr || producer_ == nullptr || callback_ == nullptr) {
189 VPE_LOGE("The consumer, producer surfaces and callback are not ready!");
190 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
191 }
192 callback_->LockModifiers();
193 state_ = VPEState::RUNNING;
194 return VIDEO_PROCESSING_SUCCESS;
195 }, "Already start!");
196 if (errorCode == VIDEO_PROCESSING_SUCCESS) {
197 OnState(VIDEO_PROCESSING_STATE_RUNNING);
198 }
199 return errorCode;
200 }
201
Stop()202 VideoProcessing_ErrorCode VideoProcessingNative::Stop()
203 {
204 auto errorCode = ExecuteWhenRunning([this]() {
205 callback_->UnlockModifiers();
206
207 std::lock_guard<std::mutex> lock(bufferLock_);
208 if (consumerBufferQueue_.empty()) {
209 state_ = VPEState::IDLE;
210 } else {
211 state_ = VPEState::STOPPING;
212 }
213 return VIDEO_PROCESSING_SUCCESS;
214 }, "Already stop!");
215
216 if (state_.load() == VPEState::IDLE) {
217 OnState(VIDEO_PROCESSING_STATE_STOPPED);
218 } else {
219 cv_.notify_one();
220 }
221 return errorCode;
222 }
223
RenderOutputBuffer(uint32_t index)224 VideoProcessing_ErrorCode VideoProcessingNative::RenderOutputBuffer(uint32_t index)
225 {
226 if (isOnNewOutputBuffer_.load()) {
227 return RenderOutputBufferInner(index);
228 }
229 return ExecuteWhenNotIdle(
230 [this, index]() { return RenderOutputBufferInner(index); },
231 "RenderOutputBuffer must be called during running!");
232 }
233
AlgoErrorToNdk(AlgoErrorCode errorCode)234 VideoProcessing_ErrorCode VideoProcessingNative::AlgoErrorToNdk(AlgoErrorCode errorCode)
235 {
236 auto it = ERROR_MAP.find(errorCode);
237 if (it == ERROR_MAP.end()) {
238 VPE_LOGE("Invalid error code:%{public}d", errorCode);
239 return VIDEO_PROCESSING_ERROR_UNKNOWN;
240 }
241 return it->second;
242 }
243
InitializeInner()244 VideoProcessing_ErrorCode VideoProcessingNative::InitializeInner()
245 {
246 return VIDEO_PROCESSING_SUCCESS;
247 }
248
DeinitializeInner()249 VideoProcessing_ErrorCode VideoProcessingNative::DeinitializeInner()
250 {
251 return VIDEO_PROCESSING_SUCCESS;
252 }
253
254 VideoProcessing_ErrorCode VideoProcessingNative::SetParameter([[maybe_unused]] const OHOS::Media::Format& parameter)
255 {
256 return VIDEO_PROCESSING_SUCCESS;
257 }
258
259 VideoProcessing_ErrorCode VideoProcessingNative::GetParameter([[maybe_unused]] OHOS::Media::Format& parameter)
260 {
261 return VIDEO_PROCESSING_SUCCESS;
262 }
263
264 bool VideoProcessingNative::IsProducerSurfaceValid([[maybe_unused]] const OHNativeWindow& window)
265 {
266 return true;
267 }
268
269 VideoProcessing_ErrorCode VideoProcessingNative::SetProducerSurface([[maybe_unused]] const OHNativeWindow& window,
270 [[maybe_unused]] BufferRequestConfig& requestCfg)
271 {
272 return VIDEO_PROCESSING_SUCCESS;
273 }
274
275 VideoProcessing_ErrorCode VideoProcessingNative::Process([[maybe_unused]] const sptr<SurfaceBuffer>& sourceImage,
276 [[maybe_unused]] sptr<SurfaceBuffer>& destinationImage)
277 {
278 return VIDEO_PROCESSING_SUCCESS;
279 }
280
281 void VideoProcessingNative::UpdateRequestCfg([[maybe_unused]] const sptr<SurfaceBuffer>& consumerBuffer,
282 [[maybe_unused]] BufferRequestConfig& requestCfg)
283 {
284 }
285
OnError(VideoProcessing_ErrorCode errorCode)286 void VideoProcessingNative::OnError(VideoProcessing_ErrorCode errorCode)
287 {
288 OnCallback([this, errorCode](std::shared_ptr<VideoProcessingCallbackNative>& callback, void* userData) {
289 callback->OnError(context_, errorCode, userData);
290 });
291 }
292
OnState(VideoProcessing_State state)293 void VideoProcessingNative::OnState(VideoProcessing_State state)
294 {
295 OnCallback([this, state](std::shared_ptr<VideoProcessingCallbackNative>& callback, void* userData) {
296 callback->OnState(context_, state, userData);
297 });
298 }
299
OnNewOutputBuffer(uint32_t index)300 void VideoProcessingNative::OnNewOutputBuffer(uint32_t index)
301 {
302 OnCallback([this, index](std::shared_ptr<VideoProcessingCallbackNative>& callback, void* userData) {
303 if (state_.load() == VPEState::IDLE) {
304 return;
305 }
306 if (callback->HasOnNewOutputBuffer()) {
307 isOnNewOutputBuffer_ = true;
308 callback->OnNewOutputBuffer(context_, index, userData);
309 isOnNewOutputBuffer_ = false;
310 } else {
311 RenderOutputBufferInner(index);
312 }
313 });
314 }
315
OnConsumerBufferAvailable()316 GSError VideoProcessingNative::OnConsumerBufferAvailable()
317 {
318 {
319 std::lock_guard<std::mutex> lock(lock_);
320 if (state_.load() != VPEState::RUNNING) {
321 return GSERROR_INVALID_OPERATING;
322 }
323
324 SurfaceBufferInfo bufferInfo{};
325 int releaseFence = -1;
326 OHOS::Rect damage;
327 GSError errorCode = consumer_->AcquireBuffer(bufferInfo.buffer, releaseFence, bufferInfo.timestamp, damage);
328 if (errorCode != GSERROR_OK || bufferInfo.buffer == nullptr) {
329 VPE_LOGE("Failed to acquire buffer!");
330 return errorCode;
331 }
332
333 std::lock_guard<std::mutex> buflock(bufferLock_);
334 if (!isBufferQueueReady_) {
335 isBufferQueueReady_ = true;
336 requestCfg_.usage |= bufferInfo.buffer->GetUsage();
337 requestCfg_.timeout = 0;
338 requestCfg_.strideAlignment = 32; // 32 内存对齐
339 UpdateRequestCfg(bufferInfo.buffer, requestCfg_);
340 PrepareBuffers();
341 }
342 consumerBufferQueue_.push(bufferInfo);
343 }
344 cv_.notify_one();
345 return GSERROR_OK;
346 }
347
OnProducerBufferReleased()348 GSError VideoProcessingNative::OnProducerBufferReleased()
349 {
350 {
351 std::lock_guard<std::mutex> lock(lock_);
352 if (producer_ == nullptr) {
353 VPE_LOGW("Producer surface is null!");
354 return GSERROR_OK;
355 }
356
357 std::lock_guard<std::mutex> buflock(bufferLock_);
358 GSError errorCode = GSERROR_OK;
359 if (!RequestBuffer(errorCode)) {
360 VPE_LOGE("Failed to request buffer!");
361 return errorCode;
362 }
363 }
364 if (state_.load() != VPEState::IDLE) {
365 cv_.notify_one();
366 }
367 return GSERROR_OK;
368 }
369
RenderOutputBufferInner(uint32_t index)370 VideoProcessing_ErrorCode VideoProcessingNative::RenderOutputBufferInner(uint32_t index)
371 {
372 std::unique_lock<std::mutex> lock(bufferLock_);
373 for (uint32_t i = 0; i < RenderBufferQueue_.size(); i++) {
374 SurfaceBufferInfo bufferInfo = RenderBufferQueue_.front();
375 RenderBufferQueue_.pop();
376 if (bufferInfo.buffer->GetSeqNum() == index) {
377 BufferFlushConfig flushcfg {
378 { 0, 0, bufferInfo.buffer->GetWidth(), bufferInfo.buffer->GetHeight() },
379 bufferInfo.timestamp
380 };
381 producer_->FlushBuffer(bufferInfo.buffer, -1, flushcfg);
382 return VIDEO_PROCESSING_SUCCESS;
383 }
384 }
385 VPE_LOGE("Invalid input: index=%{public}u!", index);
386 return VIDEO_PROCESSING_ERROR_INVALID_PARAMETER;
387 }
388
CreateConsumerSurface(OHNativeWindow * & window)389 sptr<Surface> VideoProcessingNative::CreateConsumerSurface(OHNativeWindow*& window)
390 {
391 sptr<Surface> consumer = Surface::CreateSurfaceAsConsumer("VideoProcessingSurface");
392 if (consumer == nullptr) {
393 VPE_LOGE("Failed to create consumer surface!");
394 return nullptr;
395 }
396 sptr<IBufferConsumerListener> listener = new(std::nothrow) ConsumerListener(shared_from_this());
397 if (listener == nullptr) {
398 VPE_LOGE("Failed to create consumer surface listener!");
399 return nullptr;
400 }
401 if (consumer->RegisterConsumerListener(listener) != GSERROR_OK) {
402 VPE_LOGE("Failed to register consumer surface listener!");
403 return nullptr;
404 }
405
406 sptr<IBufferProducer> producer = consumer->GetProducer();
407 sptr<Surface> surface = Surface::CreateSurfaceAsProducer(producer);
408 if (surface == nullptr) {
409 VPE_LOGE("Failed to create producer surface!");
410 return nullptr;
411 }
412 consumer->SetQueueSize(BUFFER_QUEUE_SIZE);
413
414 window = CreateNativeWindowFromSurface(&surface);
415 if (window == nullptr) {
416 VPE_LOGE("Failed to create the window!");
417 return nullptr;
418 }
419 return consumer;
420 }
421
RequestBuffer(GSError & errorCode)422 bool VideoProcessingNative::RequestBuffer(GSError& errorCode)
423 {
424 SurfaceBufferInfo bufferInfo{};
425 int releaseFence = -1;
426 errorCode = producer_->RequestBuffer(bufferInfo.buffer, releaseFence, requestCfg_);
427 if (errorCode != GSERROR_OK || bufferInfo.buffer == nullptr) {
428 return false;
429 }
430 producerBufferQueue_.push(bufferInfo);
431 return true;
432 }
433
PrepareBuffers()434 void VideoProcessingNative::PrepareBuffers()
435 {
436 for (uint32_t i = 0; i < producer_->GetQueueSize(); i++) {
437 GSError errorCode;
438 RequestBuffer(errorCode);
439 }
440 }
441
ProcessBuffers()442 void VideoProcessingNative::ProcessBuffers()
443 {
444 sptr<Surface> consumer;
445 {
446 std::lock_guard<std::mutex> lock(lock_);
447 if (consumer_ == nullptr) {
448 return;
449 }
450 consumer = consumer_;
451 }
452 while (state_.load() != VPEState::IDLE) {
453 SurfaceBufferInfo srcBufferInfo;
454 SurfaceBufferInfo dstBufferInfo;
455 {
456 std::lock_guard<std::mutex> bufferLock(bufferLock_);
457 if (producerBufferQueue_.empty() || consumerBufferQueue_.empty()) {
458 break;
459 }
460 srcBufferInfo = consumerBufferQueue_.front();
461 dstBufferInfo = producerBufferQueue_.front();
462 consumerBufferQueue_.pop();
463 producerBufferQueue_.pop();
464 }
465 dstBufferInfo.timestamp = srcBufferInfo.timestamp;
466 auto errorCode = Process(srcBufferInfo.buffer, dstBufferInfo.buffer);
467 if (errorCode != VIDEO_PROCESSING_SUCCESS) {
468 OnError(errorCode);
469 }
470 consumer->ReleaseBuffer(srcBufferInfo.buffer, -1);
471 {
472 std::lock_guard<std::mutex> bufferLock(bufferLock_);
473 RenderBufferQueue_.push(dstBufferInfo);
474 }
475 // If this function is not registered, the output buffer is sent out as soon as the buffer is filled with
476 // processed data without reporting.
477 OnNewOutputBuffer(dstBufferInfo.buffer->GetSeqNum());
478 }
479 }
480
WaitCV(std::function<bool (void)> && checker,std::unique_lock<std::mutex> & lock)481 bool VideoProcessingNative::WaitCV(std::function<bool(void)>&& checker, std::unique_lock<std::mutex>& lock)
482 {
483 if (state_.load() == VPEState::STOPPING) {
484 if (!cv_.wait_for(lock, std::chrono::milliseconds(LIMITTED_TIME), checker)) {
485 VPE_LOGI("Video processing timeout.");
486 return false;
487 }
488 } else {
489 cv_.wait(lock, checker);
490 }
491 return true;
492 }
493
CheckStopping()494 void VideoProcessingNative::CheckStopping()
495 {
496 bool isStopped = false;
497 {
498 std::lock_guard<std::mutex> lock(lock_);
499 if (state_.load() == VPEState::STOPPING) {
500 state_ = VPEState::IDLE;
501 isStopped = true;
502 }
503 }
504 if (isStopped) {
505 OnState(VIDEO_PROCESSING_STATE_STOPPED);
506 }
507 }
508
ExecuteWhenIdle(std::function<VideoProcessing_ErrorCode (void)> && operation,const std::string & errorMessage)509 VideoProcessing_ErrorCode VideoProcessingNative::ExecuteWhenIdle(
510 std::function<VideoProcessing_ErrorCode(void)>&& operation, const std::string& errorMessage)
511 {
512 return ExecuteWithCheck([this] { return state_.load() != VPEState::IDLE; }, std::move(operation), errorMessage);
513 }
514
ExecuteWhenNotIdle(std::function<VideoProcessing_ErrorCode (void)> && operation,const std::string & errorMessage)515 VideoProcessing_ErrorCode VideoProcessingNative::ExecuteWhenNotIdle(
516 std::function<VideoProcessing_ErrorCode(void)>&& operation, const std::string& errorMessage)
517 {
518 return ExecuteWithCheck([this] { return state_.load() == VPEState::IDLE; }, std::move(operation), errorMessage);
519 }
520
ExecuteWhenRunning(std::function<VideoProcessing_ErrorCode (void)> && operation,const std::string & errorMessage)521 VideoProcessing_ErrorCode VideoProcessingNative::ExecuteWhenRunning(
522 std::function<VideoProcessing_ErrorCode(void)>&& operation, const std::string& errorMessage)
523 {
524 return ExecuteWithCheck([this] { return state_.load() != VPEState::RUNNING; }, std::move(operation), errorMessage);
525 }
526
ExecuteWithCheck(std::function<bool (void)> && checker,std::function<VideoProcessing_ErrorCode (void)> && operation,const std::string & errorMessage)527 VideoProcessing_ErrorCode VideoProcessingNative::ExecuteWithCheck(std::function<bool(void)>&& checker,
528 std::function<VideoProcessing_ErrorCode(void)>&& operation, const std::string& errorMessage)
529 {
530 std::lock_guard<std::mutex> lock(lock_);
531 if (checker()) {
532 VPE_LOGW("%{public}s", errorMessage.c_str());
533 return VIDEO_PROCESSING_ERROR_OPERATION_NOT_PERMITTED;
534 }
535 return operation();
536 }
537
OnCallback(std::function<void (std::shared_ptr<VideoProcessingCallbackNative> &,void *)> && task)538 void VideoProcessingNative::OnCallback(
539 std::function<void(std::shared_ptr<VideoProcessingCallbackNative>&, void*)>&& task)
540 {
541 std::lock_guard<std::mutex> lock(lock_);
542 if (callback_ == nullptr) {
543 return;
544 }
545 task(callback_, userData_);
546 }
547
OnBufferAvailable()548 void VideoProcessingNative::ConsumerListener::OnBufferAvailable()
549 {
550 if (owner_ == nullptr) {
551 VPE_LOGE("Video processing is null!");
552 return;
553 }
554 owner_->OnConsumerBufferAvailable();
555 }
556