• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "hcodec.h"
17 #include "utils/hdf_base.h"
18 #include "hcodec_list.h"
19 #include "hcodec_log.h"
20 
21 namespace OHOS::MediaAVCodec {
22 using namespace std;
23 using namespace OHOS::HDI::Codec::V1_0;
24 
25 /**************************** BaseState Start ****************************/
OnMsgReceived(const MsgInfo & info)26 void HCodec::BaseState::OnMsgReceived(const MsgInfo &info)
27 {
28     switch (info.type) {
29         case MsgWhat::CODEC_EVENT: {
30             OnCodecEvent(info);
31             return;
32         }
33         case MsgWhat::OMX_EMPTY_BUFFER_DONE: {
34             uint32_t bufferId;
35             (void)info.param->GetValue(BUFFER_ID, bufferId);
36             codec_->OnOMXEmptyBufferDone(bufferId, inputMode_);
37             return;
38         }
39         case MsgWhat::OMX_FILL_BUFFER_DONE: {
40             OmxCodecBuffer omxBuffer;
41             (void)info.param->GetValue("omxBuffer", omxBuffer);
42             codec_->OnOMXFillBufferDone(omxBuffer, outputMode_);
43             return;
44         }
45         case MsgWhat::GET_INPUT_FORMAT:
46         case MsgWhat::GET_OUTPUT_FORMAT: {
47             OnGetFormat(info);
48             return;
49         }
50         case MsgWhat::STOP:
51         case MsgWhat::RELEASE: {
52             OnShutDown(info);
53             return;
54         }
55         default: {
56             const char* msgWhat = HCodec::ToString(static_cast<MsgWhat>(info.type));
57             if (info.id == ASYNC_MSG_ID) {
58                 SLOGI("ignore msg %{public}s in current state", msgWhat);
59             } else { // Make sure that all sync message are replied
60                 SLOGE("%{public}s cannot be called at this state", msgWhat);
61                 ReplyErrorCode(info.id, AVCS_ERR_INVALID_STATE);
62             }
63             return;
64         }
65     }
66 }
67 
ReplyErrorCode(MsgId id,int32_t err)68 void HCodec::BaseState::ReplyErrorCode(MsgId id, int32_t err)
69 {
70     if (id == ASYNC_MSG_ID) {
71         return;
72     }
73     ParamSP reply = ParamBundle::Create();
74     reply->SetValue("err", err);
75     codec_->PostReply(id, reply);
76 }
77 
OnCodecEvent(const MsgInfo & info)78 void HCodec::BaseState::OnCodecEvent(const MsgInfo &info)
79 {
80     CodecEventType event;
81     uint32_t data1;
82     uint32_t data2;
83     (void)info.param->GetValue("event", event);
84     (void)info.param->GetValue("data1", data1);
85     (void)info.param->GetValue("data2", data2);
86     if (event == CODEC_EVENT_CMD_COMPLETE &&
87         data1 == static_cast<uint32_t>(CODEC_COMMAND_FLUSH) &&
88         data2 == static_cast<uint32_t>(OMX_ALL)) {
89         SLOGD("ignore flush all complete event");
90     } else {
91         OnCodecEvent(event, data1, data2);
92     }
93 }
94 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)95 void HCodec::BaseState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
96 {
97     if (event == CODEC_EVENT_ERROR) {
98         SLOGE("omx report error event, data1 = %{public}u, data2 = %{public}u", data1, data2);
99         codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_SERVICE_DIED);
100     } else {
101         SLOGW("ignore event %{public}d, data1 = %{public}u, data2 = %{public}u", event, data1, data2);
102     }
103 }
104 
OnGetFormat(const MsgInfo & info)105 void HCodec::BaseState::OnGetFormat(const MsgInfo &info)
106 {
107     shared_ptr<Format> fmt = (info.type == MsgWhat::GET_INPUT_FORMAT) ?
108         codec_->inputFormat_ : codec_->outputFormat_;
109     ParamSP reply = ParamBundle::Create();
110     if (fmt) {
111         reply->SetValue<int32_t>("err", AVCS_ERR_OK);
112         reply->SetValue("format", *fmt);
113         codec_->PostReply(info.id, reply);
114     } else {
115         ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
116     }
117 }
118 
OnCheckIfStuck(const MsgInfo & info)119 void HCodec::BaseState::OnCheckIfStuck(const MsgInfo &info)
120 {
121     int32_t generation;
122     (void)info.param->GetValue("generation", generation);
123     if (generation == codec_->stateGeneration_) {
124         SLOGE("stucked");
125         codec_->PrintAllBufferInfo();
126         codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
127     }
128 }
129 
OnForceShutDown(const MsgInfo & info)130 void HCodec::BaseState::OnForceShutDown(const MsgInfo &info)
131 {
132     int32_t generation;
133     (void)info.param->GetValue("generation", generation);
134     codec_->ForceShutdown(generation);
135 }
136 /**************************** BaseState End ******************************/
137 
138 
139 /**************************** UninitializedState start ****************************/
OnStateEntered()140 void HCodec::UninitializedState::OnStateEntered()
141 {
142     codec_->ReleaseComponent();
143 }
144 
OnMsgReceived(const MsgInfo & info)145 void HCodec::UninitializedState::OnMsgReceived(const MsgInfo &info)
146 {
147     switch (info.type) {
148         case MsgWhat::INIT: {
149             string name;
150             (void)info.param->GetValue("name", name);
151             int32_t err = OnAllocateComponent(name);
152             ReplyErrorCode(info.id, err);
153             if (err == AVCS_ERR_OK) {
154                 codec_->ChangeStateTo(codec_->initializedState_);
155             }
156             break;
157         }
158         default: {
159             BaseState::OnMsgReceived(info);
160         }
161     }
162 }
163 
OnAllocateComponent(const std::string & name)164 int32_t HCodec::UninitializedState::OnAllocateComponent(const std::string &name)
165 {
166     codec_->compMgr_ = GetManager();
167     if (codec_->compMgr_ == nullptr) {
168         SLOGE("GetCodecComponentManager failed");
169         return AVCS_ERR_UNKNOWN;
170     }
171     codec_->compCb_ = new HdiCallback(codec_);
172     int32_t ret = codec_->compMgr_->CreateComponent(codec_->compNode_, codec_->componentId_, name,
173                                                     0, codec_->compCb_);
174     if (ret != HDF_SUCCESS || codec_->compNode_ == nullptr) {
175         codec_->compCb_ = nullptr;
176         codec_->compMgr_ = nullptr;
177         SLOGE("CreateComponent failed, ret=%{public}d", ret);
178         return AVCS_ERR_UNKNOWN;
179     }
180     codec_->componentName_ = name;
181     SLOGI("create omx node succ");
182     return AVCS_ERR_OK;
183 }
184 
OnShutDown(const MsgInfo & info)185 void HCodec::UninitializedState::OnShutDown(const MsgInfo &info)
186 {
187     ReplyErrorCode(info.id, AVCS_ERR_OK);
188 }
189 
190 /**************************** UninitializedState End ******************************/
191 
192 /**************************** InitializedState Start **********************************/
OnStateEntered()193 void HCodec::InitializedState::OnStateEntered()
194 {
195     codec_->inputPortEos_ = false;
196     codec_->outputPortEos_ = false;
197     codec_->inputFormat_.reset();
198     codec_->outputFormat_.reset();
199     codec_->sharedBufferFormat_.reset();
200 
201     ProcessShutDownFromRunning();
202     codec_->notifyCallerAfterShutdownComplete_ = false;
203     codec_->ProcessDeferredMessages();
204 }
205 
ProcessShutDownFromRunning()206 void HCodec::InitializedState::ProcessShutDownFromRunning()
207 {
208     if (!codec_->isShutDownFromRunning_) {
209         return;
210     }
211     SLOGI("we are doing shutdown from running/portchange/flush -> stopping -> initialized");
212     bool keepComponentAllocated = codec_->keepComponentAllocated_;
213     if (keepComponentAllocated) {
214         if (codec_->configFormat_ == nullptr) {
215             SLOGW("stored configuration is null");
216         } else {
217             Format copyOfCurConfig(*codec_->configFormat_);
218             codec_->OnConfigure(copyOfCurConfig);
219         }
220     } else {
221         codec_->ChangeStateTo(codec_->uninitializedState_);
222     }
223     if (codec_->notifyCallerAfterShutdownComplete_) {
224         SLOGI("reply to %{public}s msg", keepComponentAllocated ? "stop" : "release");
225         MsgInfo msg { keepComponentAllocated ? MsgWhat::STOP : MsgWhat::RELEASE, 0, nullptr };
226         if (codec_->GetFirstSyncMsgToReply(msg)) {
227             ReplyErrorCode(msg.id, AVCS_ERR_OK);
228         }
229         codec_->notifyCallerAfterShutdownComplete_ = false;
230     }
231     codec_->isShutDownFromRunning_ = false;
232     codec_->keepComponentAllocated_ = false;
233 }
234 
OnMsgReceived(const MsgInfo & info)235 void HCodec::InitializedState::OnMsgReceived(const MsgInfo &info)
236 {
237     switch (info.type) {
238         case MsgWhat::SET_CALLBACK: {
239             OnSetCallBack(info);
240             return;
241         }
242         case MsgWhat::CONFIGURE: {
243             OnConfigure(info);
244             return;
245         }
246         case MsgWhat::CREATE_INPUT_SURFACE: {
247             sptr<Surface> surface = codec_->OnCreateInputSurface();
248             ParamSP reply = ParamBundle::Create();
249             reply->SetValue<int32_t>("err", surface != nullptr ? AVCS_ERR_OK : AVCS_ERR_UNKNOWN);
250             reply->SetValue("surface", surface);
251             codec_->PostReply(info.id, reply);
252             return;
253         }
254         case MsgWhat::SET_INPUT_SURFACE: {
255             OnSetSurface(info, true);
256             return;
257         }
258         case MsgWhat::SET_OUTPUT_SURFACE: {
259             OnSetSurface(info, false);
260             return;
261         }
262         case MsgWhat::START: {
263             OnStart(info);
264             return;
265         }
266         default: {
267             BaseState::OnMsgReceived(info);
268         }
269     }
270 }
271 
OnSetCallBack(const MsgInfo & info)272 void HCodec::InitializedState::OnSetCallBack(const MsgInfo &info)
273 {
274     int32_t err;
275     shared_ptr<AVCodecCallback> cb;
276     (void)info.param->GetValue("callback", cb);
277     if (cb == nullptr) {
278         err = AVCS_ERR_INVALID_VAL;
279         SLOGE("invalid param");
280     } else {
281         codec_->callback_ = cb;
282         err = AVCS_ERR_OK;
283     }
284     ReplyErrorCode(info.id, err);
285 }
286 
OnConfigure(const MsgInfo & info)287 void HCodec::InitializedState::OnConfigure(const MsgInfo &info)
288 {
289     Format fmt;
290     (void)info.param->GetValue("format", fmt);
291     ReplyErrorCode(info.id, codec_->OnConfigure(fmt));
292 }
293 
OnSetSurface(const MsgInfo & info,bool isInput)294 void HCodec::InitializedState::OnSetSurface(const MsgInfo &info, bool isInput)
295 {
296     sptr<Surface> surface;
297     (void)info.param->GetValue("surface", surface);
298     int32_t err = isInput ? codec_->OnSetInputSurface(surface) : codec_->OnSetOutputSurface(surface);
299     ReplyErrorCode(info.id, err);
300 }
301 
OnStart(const MsgInfo & info)302 void HCodec::InitializedState::OnStart(const MsgInfo &info)
303 {
304     if (!codec_->ReadyToStart()) {
305         SLOGE("callback not set or format is not configured, can't start");
306         ReplyErrorCode(info.id, AVCS_ERR_INVALID_OPERATION);
307         return;
308     }
309     SLOGI("begin to set omx to idle");
310     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
311     if (ret == HDF_SUCCESS) {
312         codec_->ReplyToSyncMsgLater(info);
313         codec_->ChangeStateTo(codec_->startingState_);
314     } else {
315         SLOGE("set omx to idle failed, ret=%{public}d", ret);
316         ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
317     }
318 }
319 
OnShutDown(const MsgInfo & info)320 void HCodec::InitializedState::OnShutDown(const MsgInfo &info)
321 {
322     if (info.type == MsgWhat::STOP) {
323         SLOGI("receive STOP");
324     } else {
325         SLOGI("receive RELEASE");
326         codec_->ChangeStateTo(codec_->uninitializedState_);
327     }
328     codec_->notifyCallerAfterShutdownComplete_ = false;
329     ReplyErrorCode(info.id, AVCS_ERR_OK);
330 }
331 /**************************** InitializedState End ******************************/
332 
333 
334 /**************************** StartingState Start ******************************/
OnStateEntered()335 void HCodec::StartingState::OnStateEntered()
336 {
337     hasError_ = false;
338 
339     ParamSP msg = ParamBundle::Create();
340     msg->SetValue("generation", codec_->stateGeneration_);
341     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
342 
343     int32_t ret = AllocateBuffers();
344     if (ret != AVCS_ERR_OK) {
345         SLOGE("AllocateBuffers failed, back to init state");
346         hasError_ = true;
347         ReplyStartMsg(ret);
348         codec_->ChangeStateTo(codec_->initializedState_);
349     }
350 }
351 
AllocateBuffers()352 int32_t HCodec::StartingState::AllocateBuffers()
353 {
354     int32_t ret = codec_->AllocateBuffersOnPort(OMX_DirInput);
355     if (ret != AVCS_ERR_OK) {
356         return ret;
357     }
358     ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
359     if (ret != AVCS_ERR_OK) {
360         return ret;
361     }
362     return AVCS_ERR_OK;
363 }
364 
OnMsgReceived(const MsgInfo & info)365 void HCodec::StartingState::OnMsgReceived(const MsgInfo &info)
366 {
367     switch (info.type) {
368         case MsgWhat::GET_BUFFER_FROM_SURFACE:
369         case MsgWhat::SET_PARAMETERS:
370         case MsgWhat::GET_INPUT_FORMAT:
371         case MsgWhat::GET_OUTPUT_FORMAT: {
372             codec_->DeferMessage(info);
373             return;
374         }
375         case MsgWhat::START:
376         case MsgWhat::FLUSH: {
377             ReplyErrorCode(info.id, AVCS_ERR_OK);
378             return;
379         }
380         case MsgWhat::CHECK_IF_STUCK: {
381             int32_t generation;
382             if (info.param->GetValue("generation", generation) &&
383                 generation == codec_->stateGeneration_) {
384                 SLOGE("stucked, force state transition");
385                 hasError_ = true;
386                 ReplyStartMsg(AVCS_ERR_UNKNOWN);
387                 codec_->ChangeStateTo(codec_->initializedState_);
388             }
389             return;
390         }
391         default: {
392             BaseState::OnMsgReceived(info);
393         }
394     }
395 }
396 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)397 void HCodec::StartingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
398 {
399     if (event != CODEC_EVENT_CMD_COMPLETE) {
400         return BaseState::OnCodecEvent(event, data1, data2);
401     }
402     if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
403         SLOGW("ignore event: data1=%{public}u, data2=%{public}u", data1, data2);
404         return;
405     }
406     if (data2 == (uint32_t)CODEC_STATE_IDLE) {
407         SLOGI("omx now idle, begin to set omx to executing");
408         int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
409         if (ret != HDF_SUCCESS) {
410             SLOGE("set omx to executing failed, ret=%{public}d", ret);
411             hasError_ = true;
412             ReplyStartMsg(AVCS_ERR_UNKNOWN);
413             codec_->ChangeStateTo(codec_->initializedState_);
414         }
415     } else if (data2 == (uint32_t)CODEC_STATE_EXECUTING) {
416         SLOGI("omx now executing");
417         ReplyStartMsg(AVCS_ERR_OK);
418         codec_->SubmitAllBuffersOwnedByUs();
419         codec_->etbCnt_ = 0;
420         codec_->fbdCnt_ = 0;
421         codec_->ChangeStateTo(codec_->runningState_);
422     }
423 }
424 
OnShutDown(const MsgInfo & info)425 void HCodec::StartingState::OnShutDown(const MsgInfo &info)
426 {
427     codec_->DeferMessage(info);
428 }
429 
ReplyStartMsg(int32_t errCode)430 void HCodec::StartingState::ReplyStartMsg(int32_t errCode)
431 {
432     MsgInfo msg {MsgWhat::START, 0, nullptr};
433     if (codec_->GetFirstSyncMsgToReply(msg)) {
434         SLOGI("start %{public}s", (errCode == 0) ? "succ" : "failed");
435         ReplyErrorCode(msg.id, errCode);
436     } else {
437         SLOGE("there should be a start msg to reply");
438     }
439 }
440 
OnStateExited()441 void HCodec::StartingState::OnStateExited()
442 {
443     if (hasError_) {
444         SLOGW("error occured, roll omx back to loaded and free allocated buffers");
445         if (codec_->RollOmxBackToLoaded()) {
446             codec_->ClearBufferPool(OMX_DirInput);
447             codec_->ClearBufferPool(OMX_DirOutput);
448         }
449     }
450     BaseState::OnStateExited();
451 }
452 
453 /**************************** StartingState End ******************************/
454 
455 /**************************** RunningState Start ********************************/
OnStateEntered()456 void HCodec::RunningState::OnStateEntered()
457 {
458     codec_->ProcessDeferredMessages();
459 }
460 
OnMsgReceived(const MsgInfo & info)461 void HCodec::RunningState::OnMsgReceived(const MsgInfo &info)
462 {
463     switch (info.type) {
464         case MsgWhat::START:
465             ReplyErrorCode(info.id, codec_->SubmitAllBuffersOwnedByUs());
466             break;
467         case MsgWhat::SET_PARAMETERS:
468             OnSetParameters(info);
469             break;
470         case MsgWhat::REQUEST_IDR_FRAME:
471             ReplyErrorCode(info.id, codec_->RequestIDRFrame());
472             break;
473         case MsgWhat::FLUSH:
474             OnFlush(info);
475             break;
476         case MsgWhat::GET_BUFFER_FROM_SURFACE:
477             codec_->OnGetBufferFromSurface();
478             break;
479         case MsgWhat::QUEUE_INPUT_BUFFER:
480             codec_->OnQueueInputBuffer(info, inputMode_);
481             break;
482         case MsgWhat::NOTIFY_EOS:
483             codec_->OnSignalEndOfInputStream(info);
484             break;
485         case MsgWhat::RENDER_OUTPUT_BUFFER:
486             codec_->OnRenderOutputBuffer(info, outputMode_);
487             break;
488         case MsgWhat::RELEASE_OUTPUT_BUFFER:
489             codec_->OnReleaseOutputBuffer(info, outputMode_);
490             break;
491         default:
492             BaseState::OnMsgReceived(info);
493             break;
494     }
495 }
496 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)497 void HCodec::RunningState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
498 {
499     switch (event) {
500         case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
501             if (data1 != OMX_DirOutput) {
502                 SLOGI("ignore input port changed");
503                 return;
504             }
505             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
506                 SLOGI("output port settings changed");
507                 if (codec_->UpdateOutPortFormat() == AVCS_ERR_OK) {
508                     codec_->callback_->OnOutputFormatChanged(*(codec_->outputFormat_.get()));
509                 }
510                 SLOGI("begin to ask omx to disable out port");
511                 int32_t ret = codec_->compNode_->SendCommand(
512                     CODEC_COMMAND_PORT_DISABLE, OMX_DirOutput, {});
513                 if (ret == HDF_SUCCESS) {
514                     codec_->EraseOutBuffersOwnedByUsOrSurface();
515                     codec_->ChangeStateTo(codec_->outputPortChangedState_);
516                 } else {
517                     SLOGE("ask omx to disable out port failed");
518                     codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
519                 }
520             } else {
521                 SLOGW("unknown data2 for CODEC_EVENT_PORT_SETTINGS_CHANGED");
522             }
523             return;
524         }
525         default: {
526             BaseState::OnCodecEvent(event, data1, data2);
527         }
528     }
529 }
530 
OnShutDown(const MsgInfo & info)531 void HCodec::RunningState::OnShutDown(const MsgInfo &info)
532 {
533     codec_->isShutDownFromRunning_ = true;
534     codec_->notifyCallerAfterShutdownComplete_ = true;
535     codec_->keepComponentAllocated_ = (info.type == MsgWhat::STOP);
536     codec_->isBufferCirculating_ = false;
537 
538     SLOGI("receive %{public}s msg, begin to set omx to idle", info.type == MsgWhat::RELEASE ? "release" : "stop");
539     auto costUs = chrono::duration_cast<chrono::microseconds>(
540         chrono::steady_clock::now() - codec_->firstFbdTime_).count();
541     SLOGI("etb cnt %{public}" PRIu64 ", fbd cnt %{public}" PRIu64 ", fbd fps %{public}.2f",
542         codec_->etbCnt_, codec_->fbdCnt_,
543         static_cast<double>(codec_->fbdCnt_) / costUs * codec_->TIME_RATIO_S_TO_US);
544     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
545     if (ret == HDF_SUCCESS) {
546         codec_->ReplyToSyncMsgLater(info);
547         codec_->ChangeStateTo(codec_->stoppingState_);
548     } else {
549         SLOGE("set omx to idle failed, ret=%{public}d", ret);
550         ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
551     }
552 }
553 
OnFlush(const MsgInfo & info)554 void HCodec::RunningState::OnFlush(const MsgInfo &info)
555 {
556     codec_->isBufferCirculating_ = false;
557     SLOGI("begin to ask omx to flush");
558     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_FLUSH, OMX_ALL, {});
559     if (ret == HDF_SUCCESS) {
560         codec_->ReplyToSyncMsgLater(info);
561         codec_->ChangeStateTo(codec_->flushingState_);
562     } else {
563         SLOGI("ask omx to flush failed, ret=%{public}d", ret);
564         ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
565     }
566 }
567 
OnSetParameters(const MsgInfo & info)568 void HCodec::RunningState::OnSetParameters(const MsgInfo &info)
569 {
570     Format params;
571     (void)info.param->GetValue("params", params);
572     ReplyErrorCode(info.id, codec_->OnSetParameters(params));
573 }
574 /**************************** RunningState End ********************************/
575 
576 
577 /**************************** OutputPortChangedState Start ********************************/
OnStateEntered()578 void HCodec::OutputPortChangedState::OnStateEntered()
579 {
580     ParamSP msg = ParamBundle::Create();
581     msg->SetValue("generation", codec_->stateGeneration_);
582     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
583 }
584 
OnMsgReceived(const MsgInfo & info)585 void HCodec::OutputPortChangedState::OnMsgReceived(const MsgInfo &info)
586 {
587     switch (info.type) {
588         case MsgWhat::FLUSH: {
589             OnFlush(info);
590             return;
591         }
592         case MsgWhat::START:
593         case MsgWhat::SET_PARAMETERS:
594         case MsgWhat::GET_INPUT_FORMAT:
595         case MsgWhat::GET_OUTPUT_FORMAT: {
596             codec_->DeferMessage(info);
597             return;
598         }
599         case MsgWhat::QUEUE_INPUT_BUFFER: {
600             codec_->OnQueueInputBuffer(info, inputMode_);
601             return;
602         }
603         case MsgWhat::NOTIFY_EOS: {
604             codec_->OnSignalEndOfInputStream(info);
605             return;
606         }
607         case MsgWhat::RENDER_OUTPUT_BUFFER: {
608             codec_->OnRenderOutputBuffer(info, outputMode_);
609             return;
610         }
611         case MsgWhat::RELEASE_OUTPUT_BUFFER: {
612             codec_->OnReleaseOutputBuffer(info, outputMode_);
613             return;
614         }
615         case MsgWhat::FORCE_SHUTDOWN: {
616             OnForceShutDown(info);
617             return;
618         }
619         case MsgWhat::CHECK_IF_STUCK: {
620             OnCheckIfStuck(info);
621             return;
622         }
623         default: {
624             BaseState::OnMsgReceived(info);
625         }
626     }
627 }
628 
OnShutDown(const MsgInfo & info)629 void HCodec::OutputPortChangedState::OnShutDown(const MsgInfo &info)
630 {
631     if (codec_->hasFatalError_) {
632         ParamSP stopMsg = ParamBundle::Create();
633         stopMsg->SetValue("generation", codec_->stateGeneration_);
634         codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
635     }
636     codec_->DeferMessage(info);
637 }
638 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)639 void HCodec::OutputPortChangedState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
640 {
641     switch (event) {
642         case CODEC_EVENT_CMD_COMPLETE: {
643             if (data1 == CODEC_COMMAND_PORT_DISABLE) {
644                 if (data2 != OMX_DirOutput) {
645                     SLOGW("ignore input port disable complete");
646                     return;
647                 }
648                 SLOGI("output port is disabled");
649                 HandleOutputPortDisabled();
650             } else if (data1 == CODEC_COMMAND_PORT_ENABLE) {
651                 if (data2 != OMX_DirOutput) {
652                     SLOGW("ignore input port enable complete");
653                     return;
654                 }
655                 SLOGI("output port is enabled");
656                 HandleOutputPortEnabled();
657             }
658             return;
659         }
660         default: {
661             BaseState::OnCodecEvent(event, data1, data2);
662         }
663     }
664 }
665 
HandleOutputPortDisabled()666 void HCodec::OutputPortChangedState::HandleOutputPortDisabled()
667 {
668     int32_t ret = AVCS_ERR_OK;
669     if (!codec_->outputBufferPool_.empty()) {
670         SLOGE("output port is disabled but not empty: %{public}zu", codec_->outputBufferPool_.size());
671         ret = AVCS_ERR_UNKNOWN;
672     }
673 
674     if (ret == AVCS_ERR_OK) {
675         SLOGI("begin to ask omx to enable out port");
676         int32_t err = codec_->compNode_->SendCommand(CODEC_COMMAND_PORT_ENABLE, OMX_DirOutput, {});
677         if (err == HDF_SUCCESS) {
678             ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
679         } else {
680             SLOGE("ask omx to enable out port failed, ret=%{public}d", ret);
681             ret = AVCS_ERR_UNKNOWN;
682         }
683     }
684     if (ret != AVCS_ERR_OK) {
685         codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_INVALID_VAL);
686     }
687 }
688 
HandleOutputPortEnabled()689 void HCodec::OutputPortChangedState::HandleOutputPortEnabled()
690 {
691     if (codec_->isBufferCirculating_) {
692         codec_->SubmitOutputBuffersToOmxNode();
693     }
694     codec_->ChangeStateTo(codec_->runningState_);
695 }
696 
OnFlush(const MsgInfo & info)697 void HCodec::OutputPortChangedState::OnFlush(const MsgInfo &info)
698 {
699     if (codec_->hasFatalError_) {
700         ParamSP stopMsg = ParamBundle::Create();
701         stopMsg->SetValue("generation", codec_->stateGeneration_);
702         codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
703     }
704     codec_->DeferMessage(info);
705 }
706 /**************************** OutputPortChangedState End ********************************/
707 
708 
709 /**************************** FlushingState Start ********************************/
OnStateEntered()710 void HCodec::FlushingState::OnStateEntered()
711 {
712     flushCompleteFlag_[OMX_DirInput] = false;
713     flushCompleteFlag_[OMX_DirOutput] = false;
714     codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
715     codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
716     SLOGI("all buffer owned by user are now owned by us");
717 
718     ParamSP msg = ParamBundle::Create();
719     msg->SetValue("generation", codec_->stateGeneration_);
720     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
721 }
722 
OnMsgReceived(const MsgInfo & info)723 void HCodec::FlushingState::OnMsgReceived(const MsgInfo &info)
724 {
725     switch (info.type) {
726         case MsgWhat::GET_BUFFER_FROM_SURFACE: {
727             codec_->DeferMessage(info);
728             return;
729         }
730         case MsgWhat::FLUSH: {
731             ReplyErrorCode(info.id, AVCS_ERR_OK);
732             return;
733         }
734         case MsgWhat::FORCE_SHUTDOWN: {
735             OnForceShutDown(info);
736             return;
737         }
738         case MsgWhat::CHECK_IF_STUCK: {
739             OnCheckIfStuck(info);
740             return;
741         }
742         default: {
743             BaseState::OnMsgReceived(info);
744         }
745     }
746 }
747 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)748 void HCodec::FlushingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
749 {
750     switch (event) {
751         case CODEC_EVENT_CMD_COMPLETE: {
752             auto ret = UpdateFlushStatusOnPorts(data1, data2);
753             if (ret == AVCS_ERR_OK && IsFlushCompleteOnAllPorts()) {
754                 ChangeStateIfWeOwnAllBuffers();
755             }
756             return;
757         }
758         case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
759             ParamSP portSettingChangedMsg = ParamBundle::Create();
760             portSettingChangedMsg->SetValue("generation", codec_->stateGeneration_);
761             portSettingChangedMsg->SetValue("event", event);
762             portSettingChangedMsg->SetValue("data1", data1);
763             portSettingChangedMsg->SetValue("data2", data2);
764             codec_->DeferMessage(MsgInfo {MsgWhat::CODEC_EVENT, 0, portSettingChangedMsg});
765             SLOGI("deferring CODEC_EVENT_PORT_SETTINGS_CHANGED");
766             return;
767         }
768         default: {
769             BaseState::OnCodecEvent(event, data1, data2);
770         }
771     }
772 }
773 
UpdateFlushStatusOnPorts(uint32_t data1,uint32_t data2)774 int32_t HCodec::FlushingState::UpdateFlushStatusOnPorts(uint32_t data1, uint32_t data2)
775 {
776     if (data2 == OMX_DirInput || data2 == OMX_DirOutput) {
777         if (flushCompleteFlag_[data2]) {
778             SLOGE("flush already completed for port (%{public}u)", data2);
779             return AVCS_ERR_OK;
780         }
781         flushCompleteFlag_[data2] = true;
782     } else if (data2 == OMX_ALL) {
783         if (!IsFlushCompleteOnAllPorts()) {
784             SLOGW("received flush complete event for OMX_ALL, portFlushStatue=(%{public}d/%{public}d)",
785                 flushCompleteFlag_[OMX_DirInput], flushCompleteFlag_[OMX_DirOutput]);
786             return AVCS_ERR_INVALID_VAL;
787         }
788     } else {
789         SLOGW("unexpected data2(%{public}d) for CODEC_COMMAND_FLUSH complete", data2);
790     }
791     return AVCS_ERR_OK;
792 }
793 
IsFlushCompleteOnAllPorts()794 bool HCodec::FlushingState::IsFlushCompleteOnAllPorts()
795 {
796     return flushCompleteFlag_[OMX_DirInput] && flushCompleteFlag_[OMX_DirOutput];
797 }
798 
ChangeStateIfWeOwnAllBuffers()799 void HCodec::FlushingState::ChangeStateIfWeOwnAllBuffers()
800 {
801     if (!IsFlushCompleteOnAllPorts() || !codec_->IsAllBufferOwnedByUsOrSurface()) {
802         return;
803     }
804     MsgInfo msg {MsgWhat::FLUSH, 0, nullptr};
805     if (codec_->GetFirstSyncMsgToReply(msg)) {
806         ReplyErrorCode(msg.id, AVCS_ERR_OK);
807     }
808     codec_->inputPortEos_ = false;
809     codec_->outputPortEos_ = false;
810     codec_->ChangeStateTo(codec_->runningState_);
811 }
812 
OnShutDown(const MsgInfo & info)813 void HCodec::FlushingState::OnShutDown(const MsgInfo &info)
814 {
815     codec_->DeferMessage(info);
816     if (codec_->hasFatalError_) {
817         ParamSP stopMsg = ParamBundle::Create();
818         stopMsg->SetValue("generation", codec_->stateGeneration_);
819         codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
820     }
821 }
822 /**************************** FlushingState End ********************************/
823 
824 
825 /**************************** StoppingState Start ********************************/
OnStateEntered()826 void HCodec::StoppingState::OnStateEntered()
827 {
828     omxNodeInIdleState_ = false;
829     omxNodeIsChangingToLoadedState_ = false;
830     codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
831     codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
832     SLOGI("all buffer owned by user are now owned by us");
833 
834     ParamSP msg = ParamBundle::Create();
835     msg->SetValue("generation", codec_->stateGeneration_);
836     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
837 }
838 
OnMsgReceived(const MsgInfo & info)839 void HCodec::StoppingState::OnMsgReceived(const MsgInfo &info)
840 {
841     switch (info.type) {
842         case MsgWhat::CHECK_IF_STUCK: {
843             int32_t generation;
844             (void)info.param->GetValue("generation", generation);
845             if (generation == codec_->stateGeneration_) {
846                 SLOGE("stucked, force state transition");
847                 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_OMX);
848                 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_OMX);
849                 SLOGI("all buffer owned by omx are now owned by us");
850                 ChangeOmxNodeToLoadedState(true);
851                 codec_->ChangeStateTo(codec_->initializedState_);
852             }
853             return;
854         }
855         default: {
856             BaseState::OnMsgReceived(info);
857         }
858     }
859 }
860 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)861 void HCodec::StoppingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
862 {
863     switch (event) {
864         case CODEC_EVENT_CMD_COMPLETE: {
865             if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
866                 SLOGW("unexpected CODEC_EVENT_CMD_COMPLETE: %{public}u %{public}u", data1, data2);
867                 return;
868             }
869             if (data2 == (uint32_t)CODEC_STATE_IDLE) {
870                 SLOGI("omx now idle");
871                 omxNodeInIdleState_ = true;
872                 ChangeStateIfWeOwnAllBuffers();
873             } else if (data2 == (uint32_t)CODEC_STATE_LOADED) {
874                 SLOGI("omx now loaded");
875                 codec_->ChangeStateTo(codec_->initializedState_);
876             }
877             return;
878         }
879         default: {
880             BaseState::OnCodecEvent(event, data1, data2);
881         }
882     }
883 }
884 
ChangeStateIfWeOwnAllBuffers()885 void HCodec::StoppingState::ChangeStateIfWeOwnAllBuffers()
886 {
887     if (omxNodeInIdleState_ && codec_->IsAllBufferOwnedByUsOrSurface()) {
888         ChangeOmxNodeToLoadedState(false);
889     } else {
890         SLOGD("cannot change state yet");
891     }
892 }
893 
ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)894 void HCodec::StoppingState::ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)
895 {
896     if (!omxNodeIsChangingToLoadedState_) {
897         SLOGI("begin to set omx to loaded");
898         int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
899         if (ret == HDF_SUCCESS) {
900             omxNodeIsChangingToLoadedState_ = true;
901         } else {
902             SLOGE("set omx to loaded failed, ret=%{public}d", ret);
903         }
904     }
905     if (forceToFreeBuffer || omxNodeIsChangingToLoadedState_) {
906         codec_->ClearBufferPool(OMX_DirInput);
907         codec_->ClearBufferPool(OMX_DirOutput);
908         return;
909     }
910     codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
911 }
912 
OnShutDown(const MsgInfo & info)913 void HCodec::StoppingState::OnShutDown(const MsgInfo &info)
914 {
915     codec_->DeferMessage(info);
916 }
917 
918 /**************************** StoppingState End ********************************/
919 }