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