• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2022 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 #define HST_LOG_TAG "AsyncMode"
17 
18 #include "async_mode.h"
19 #include "common/plugin_utils.h"
20 #include "utils/dump_buffer.h"
21 #include "osal/utils/util.h"
22 #if !defined(OHOS_LITE) && defined(VIDEO_SUPPORT)
23 #include "plugin/common/surface_memory.h"
24 #endif
25 
26 namespace {
27 constexpr uint32_t DEFAULT_TRY_DECODE_TIME = 5;
28 constexpr uint32_t DEFAULT_TRY_RENDER_TIME = 5;
29 }
30 
31 namespace OHOS {
32 namespace Media {
33 namespace Pipeline {
AsyncMode(std::string name)34 AsyncMode::AsyncMode(std::string name) : CodecMode(std::move(name))
35 {
36     MEDIA_LOG_I(PUBLIC_LOG_S " ThreadMode: ASYNC", codecName_.c_str());
37 }
38 
~AsyncMode()39 AsyncMode::~AsyncMode()
40 {
41     MEDIA_LOG_D("Async mode dtor called");
42 }
43 
Release()44 ErrorCode AsyncMode::Release()
45 {
46     MEDIA_LOG_I("AsyncMode Release start.");
47     stopped_ = true;
48 
49     // 先停止线程 然后释放bufferQ 如果顺序反过来 可能导致线程访问已经释放的锁
50     if (handleFrameTask_) {
51         handleFrameTask_->Stop();
52         handleFrameTask_.reset();
53     }
54     if (pushTask_ != nullptr) {
55         pushTask_->Stop();
56         pushTask_.reset();
57     }
58     if (inBufQue_) {
59         inBufQue_->SetActive(false);
60         inBufQue_.reset();
61     }
62     {
63         OSAL::ScopedLock l(renderMutex_);
64         while (!outBufQue_.empty()) {
65             outBufQue_.pop();
66         }
67     }
68     MEDIA_LOG_I("AsyncMode Release end.");
69     return ErrorCode::SUCCESS;
70 }
71 
Configure()72 ErrorCode AsyncMode::Configure()
73 {
74     stopped_ = false;
75     FALSE_LOG_MSG_W(QueueAllBufferInPoolToPluginLocked() == ErrorCode::SUCCESS,
76                     "Can not configure all output buffers to plugin before start.");
77     FAIL_RETURN(CodecMode::Configure());
78     if (handleFrameTask_) {
79         handleFrameTask_->Start();
80     }
81     if (pushTask_) {
82         pushTask_->Start();
83     }
84     return ErrorCode::SUCCESS;
85 }
86 
PushData(const std::string & inPort,const AVBufferPtr & buffer,int64_t offset)87 ErrorCode AsyncMode::PushData(const std::string &inPort, const AVBufferPtr& buffer, int64_t offset)
88 {
89     DUMP_BUFFER2LOG("AsyncMode in", buffer, offset);
90     inBufQue_->Push(buffer);
91     return ErrorCode::SUCCESS;
92 }
93 
Stop()94 ErrorCode AsyncMode::Stop()
95 {
96     MEDIA_LOG_I("AsyncMode stop start.");
97     stopped_ = true;
98     pushTask_->Stop();
99     inBufQue_->SetActive(false);
100     {
101         OSAL::ScopedLock l(renderMutex_);
102         while (!outBufQue_.empty()) {
103             outBufQue_.pop();
104         }
105     }
106     if (handleFrameTask_) {
107         handleFrameTask_->Stop();
108     }
109     outBufPool_.reset();
110     MEDIA_LOG_I("AsyncMode stop end.");
111     return ErrorCode::SUCCESS;
112 }
113 
FlushStart()114 void AsyncMode::FlushStart()
115 {
116     MEDIA_LOG_D("AsyncMode FlushStart entered.");
117     stopped_ = true; // thread will pause, should not enter endless loop
118     if (inBufQue_) {
119         inBufQue_->SetActive(false);
120     }
121     if (handleFrameTask_) {
122         handleFrameTask_->Pause();
123     }
124     if (pushTask_) {
125         pushTask_->Pause();
126     }
127     MEDIA_LOG_D("AsyncMode FlushStart exit.");
128 }
129 
FlushEnd()130 void AsyncMode::FlushEnd()
131 {
132     MEDIA_LOG_I("AsyncMode FlushEnd entered");
133     stopped_ = false;
134     if (inBufQue_) {
135         inBufQue_->SetActive(true);
136     }
137     if (handleFrameTask_) {
138         handleFrameTask_->Start();
139     }
140     if (pushTask_) {
141         pushTask_->Start();
142     }
143     if (plugin_) {
144         QueueAllBufferInPoolToPluginLocked();
145     }
146 }
147 
HandleFrame()148 ErrorCode AsyncMode::HandleFrame()
149 {
150     MEDIA_LOG_DD("AsyncMode handle frame called");
151     auto oneBuffer = inBufQue_->Pop(200); // timeout 200 ms
152     if (oneBuffer == nullptr) {
153         MEDIA_LOG_DD("decoder find nullptr in esBufferQ");
154         return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
155     }
156     Plugin::Status status = Plugin::Status::OK;
157     do {
158         DUMP_BUFFER2LOG("AsyncMode QueueInput to Plugin", oneBuffer, -1);
159         status = plugin_->QueueInputBuffer(oneBuffer, 0);
160         if (status == Plugin::Status::OK || status == Plugin::Status::END_OF_STREAM
161             || status != Plugin::Status::ERROR_AGAIN || stopped_) {
162             break;
163         }
164         MEDIA_LOG_DD("Send data to plugin error: " PUBLIC_LOG_D32, status);
165         OSAL::SleepFor(DEFAULT_TRY_DECODE_TIME);
166     } while (true);
167     MEDIA_LOG_DD("Async handle frame finished");
168     return TranslatePluginStatus(status);
169 }
170 
FinishFrame()171 ErrorCode AsyncMode::FinishFrame()
172 {
173     MEDIA_LOG_DD("FinishFrame begin");
174     bool isRendered = false;
175     {
176         OSAL::ScopedLock l(renderMutex_);
177         std::shared_ptr<AVBuffer> frameBuffer = nullptr;
178         if (!outBufQue_.empty()) {
179             frameBuffer = outBufQue_.front();
180         }
181         if (frameBuffer != nullptr) {
182             auto oPort = outPorts_[0];
183             if (oPort->GetWorkMode() == WorkMode::PUSH) {
184                 DUMP_BUFFER2LOG("AsyncMode PushData to Sink", frameBuffer, -1);
185                 oPort->PushData(frameBuffer, -1);
186                 isRendered = true;
187                 outBufQue_.pop();
188             } else {
189                 MEDIA_LOG_W("decoder out port works in pull mode");
190                 return ErrorCode::ERROR_INVALID_OPERATION;
191             }
192             frameBuffer.reset();
193         }
194     }
195     auto newOutBuffer = outBufPool_->AllocateBufferNonBlocking();
196     if (CheckBufferValidity(newOutBuffer) == ErrorCode::SUCCESS) {
197         newOutBuffer->Reset();
198         plugin_->QueueOutputBuffer(newOutBuffer, 0);
199     }
200     if (!isRendered) {
201         OSAL::SleepFor(DEFAULT_TRY_RENDER_TIME);
202     }
203     MEDIA_LOG_DD("AsyncMode finish frame success");
204     return ErrorCode::SUCCESS;
205 }
206 
OnOutputBufferDone(const std::shared_ptr<Plugin::Buffer> & buffer)207 void AsyncMode::OnOutputBufferDone(const std::shared_ptr<Plugin::Buffer>& buffer)
208 {
209     OSAL::ScopedLock l(renderMutex_);
210     outBufQue_.push(buffer);
211 }
212 
Prepare()213 ErrorCode AsyncMode::Prepare()
214 {
215     MEDIA_LOG_I("AsyncMode prepare called.");
216     if (!inBufQue_) {
217         inBufQue_ = std::make_shared<BlockingQueue<AVBufferPtr>>("asyncFilterInBufQue", GetInBufferPoolSize());
218     } else {
219         inBufQue_->SetActive(true);
220     }
221     if (!handleFrameTask_) {
222         handleFrameTask_ = std::make_shared<OSAL::Task>(codecName_ + "AsyncHandleFrame");
223         handleFrameTask_->RegisterHandler([this] { (void)HandleFrame(); });
224     }
225     if (!pushTask_) {
226         pushTask_ = std::make_shared<OSAL::Task>(codecName_ + "AsyncPush");
227         pushTask_->RegisterHandler([this] { (void)FinishFrame(); });
228     }
229     return ErrorCode::SUCCESS;
230 }
231 
QueueAllBufferInPoolToPluginLocked()232 ErrorCode AsyncMode::QueueAllBufferInPoolToPluginLocked()
233 {
234     ErrorCode err = ErrorCode::SUCCESS;
235     while (!outBufPool_->Empty()) {
236         auto buf = outBufPool_->AllocateBuffer();
237         if (CheckBufferValidity(buf) != ErrorCode::SUCCESS) {
238             MEDIA_LOG_W("cannot allocate buffer in buffer pool");
239             continue;
240         }
241         err = TranslatePluginStatus(plugin_->QueueOutputBuffer(buf, -1));
242         if (err != ErrorCode::SUCCESS) {
243             MEDIA_LOG_W("Queue output buffer error, plugin doesn't support queue all out buffers.");
244             break;
245         }
246     }
247     return err;
248 }
249 
CheckBufferValidity(std::shared_ptr<AVBuffer> & buffer)250 ErrorCode AsyncMode::CheckBufferValidity(std::shared_ptr<AVBuffer>& buffer)
251 {
252     if (buffer == nullptr) {
253         return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
254     }
255     auto memory = buffer->GetMemory();
256     if (memory == nullptr) {
257         return ErrorCode::ERROR_INVALID_PARAMETER_VALUE;
258     }
259 #if !defined(OHOS_LITE) && defined(VIDEO_SUPPORT)
260     if (memory->GetMemoryType() == Plugin::MemoryType::SURFACE_BUFFER) {
261         std::shared_ptr<Plugin::SurfaceMemory> surfaceMemory =
262             Plugin::ReinterpretPointerCast<Plugin::SurfaceMemory>(memory);
263 
264         // trigger surface memory to request surface buffer again when it is surface buffer
265         FALSE_RETURN_V_MSG_E(surfaceMemory->GetSurfaceBuffer() != nullptr, ErrorCode::ERROR_NO_MEMORY,
266                              "get surface buffer fail");
267     }
268 #endif
269     return ErrorCode::SUCCESS;
270 }
271 } // namespace Pipeline
272 } // namespace Media
273 } // namespace OHOS