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 "hardware/imagecodec/image_codec.h"
17 #include "hardware/imagecodec/image_codec_list.h"
18 #include "hardware/imagecodec/image_codec_log.h"
19 
20 namespace OHOS::ImagePlugin {
21 using namespace std;
22 using namespace HdiCodecNamespace;
23 
24 /**************************** BaseState Start ****************************/
OnMsgReceived(const MsgInfo & info)25 void ImageCodec::BaseState::OnMsgReceived(const MsgInfo &info)
26 {
27     switch (info.type) {
28         case MsgWhat::CODEC_EVENT: {
29             OnCodecEvent(info);
30             return;
31         }
32         case MsgWhat::OMX_EMPTY_BUFFER_DONE: {
33             if (info.param == nullptr) {
34                 return;
35             }
36             uint32_t bufferId;
37             if (!info.param->GetValue(BUFFER_ID, bufferId)) {
38                 SLOGE("OnMsgReceived param has no BUFFER_ID");
39             }
40             codec_->OnOMXEmptyBufferDone(bufferId, inputMode_);
41             return;
42         }
43         case MsgWhat::OMX_FILL_BUFFER_DONE: {
44             if (info.param == nullptr) {
45                 return;
46             }
47             OmxCodecBuffer omxBuffer;
48             if (!info.param->GetValue("omxBuffer", omxBuffer)) {
49                 SLOGE("OnMsgReceived param has no omxBuffer");
50             }
51             codec_->OnOMXFillBufferDone(omxBuffer, outputMode_);
52             return;
53         }
54         case MsgWhat::GET_INPUT_FORMAT:
55         case MsgWhat::GET_OUTPUT_FORMAT: {
56             OnGetFormat(info);
57             return;
58         }
59         case MsgWhat::RELEASE: {
60             OnShutDown(info);
61             return;
62         }
63         default: {
64             const char* msgWhat = ImageCodec::ToString(static_cast<MsgWhat>(info.type));
65             if (info.id == ASYNC_MSG_ID) {
66                 SLOGI("ignore msg %{public}s in current state", msgWhat);
67             } else { // Make sure that all sync message are replied
68                 SLOGE("%{public}s cannot be called at this state", msgWhat);
69                 ReplyErrorCode(info.id, IC_ERR_INVALID_STATE);
70             }
71             return;
72         }
73     }
74 }
75 
ReplyErrorCode(MsgId id,int32_t err)76 void ImageCodec::BaseState::ReplyErrorCode(MsgId id, int32_t err)
77 {
78     if (id == ASYNC_MSG_ID) {
79         return;
80     }
81     ParamSP reply = make_shared<ParamBundle>();
82     reply->SetValue("err", err);
83     codec_->PostReply(id, reply);
84 }
85 
OnCodecEvent(const MsgInfo & info)86 void ImageCodec::BaseState::OnCodecEvent(const MsgInfo &info)
87 {
88     if (info.param == nullptr) {
89         return;
90     }
91     CodecEventType event{};
92     uint32_t data1;
93     uint32_t data2;
94     (void)info.param->GetValue("event", event);
95     (void)info.param->GetValue("data1", data1);
96     (void)info.param->GetValue("data2", data2);
97     if (event == CODEC_EVENT_CMD_COMPLETE &&
98         data1 == static_cast<uint32_t>(CODEC_COMMAND_FLUSH) &&
99         data2 == static_cast<uint32_t>(OMX_ALL)) {
100         SLOGD("ignore flush all complete event");
101     } else {
102         OnCodecEvent(event, data1, data2);
103     }
104 }
105 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)106 void ImageCodec::BaseState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
107 {
108     if (event == CODEC_EVENT_ERROR) {
109         SLOGE("omx report error event, data1 = %{public}u, data2 = %{public}u", data1, data2);
110         codec_->SignalError(IC_ERR_SERVICE_DIED);
111     } else {
112         SLOGW("ignore event %{public}d, data1 = %{public}u, data2 = %{public}u", event, data1, data2);
113     }
114 }
115 
OnGetFormat(const MsgInfo & info)116 void ImageCodec::BaseState::OnGetFormat(const MsgInfo &info)
117 {
118     shared_ptr<Format> fmt = (info.type == MsgWhat::GET_INPUT_FORMAT) ?
119         codec_->inputFormat_ : codec_->outputFormat_;
120     ParamSP reply = make_shared<ParamBundle>();
121     if (fmt) {
122         reply->SetValue<int32_t>("err", IC_ERR_OK);
123         reply->SetValue("format", *fmt);
124         codec_->PostReply(info.id, reply);
125     } else {
126         ReplyErrorCode(info.id, IC_ERR_UNKNOWN);
127     }
128 }
129 
OnCheckIfStuck(const MsgInfo & info)130 void ImageCodec::BaseState::OnCheckIfStuck(const MsgInfo &info)
131 {
132     int32_t generation;
133     (void)info.param->GetValue("generation", generation);
134     if (generation == codec_->stateGeneration_) {
135         SLOGE("stucked");
136         codec_->PrintAllBufferInfo();
137         codec_->SignalError(IC_ERR_UNKNOWN);
138     }
139 }
140 
OnForceShutDown(const MsgInfo & info)141 void ImageCodec::BaseState::OnForceShutDown(const MsgInfo &info)
142 {
143     int32_t generation;
144     (void)info.param->GetValue("generation", generation);
145     codec_->ForceShutdown(generation);
146 }
147 /**************************** BaseState End ******************************/
148 
149 /**************************** UninitializedState start ****************************/
OnStateEntered()150 void ImageCodec::UninitializedState::OnStateEntered()
151 {
152     codec_->ReleaseComponent();
153 }
154 
OnMsgReceived(const MsgInfo & info)155 void ImageCodec::UninitializedState::OnMsgReceived(const MsgInfo &info)
156 {
157     switch (info.type) {
158         case MsgWhat::INIT: {
159             string name;
160             (void)info.param->GetValue("name", name);
161             int32_t err = OnAllocateComponent(name);
162             ReplyErrorCode(info.id, err);
163             if (err == IC_ERR_OK) {
164                 codec_->ChangeStateTo(codec_->initializedState_);
165             }
166             break;
167         }
168         default: {
169             BaseState::OnMsgReceived(info);
170         }
171     }
172 }
173 
OnAllocateComponent(const std::string & name)174 int32_t ImageCodec::UninitializedState::OnAllocateComponent(const std::string &name)
175 {
176     codec_->compMgr_ = GetManager();
177     if (codec_->compMgr_ == nullptr) {
178         SLOGE("GetCodecComponentManager failed");
179         return IC_ERR_UNKNOWN;
180     }
181     codec_->compCb_ = new HdiCallback(codec_);
182     int32_t ret = codec_->compMgr_->CreateComponent(codec_->compNode_, codec_->componentId_, name,
183                                                     0, codec_->compCb_);
184     if (ret != HDF_SUCCESS || codec_->compNode_ == nullptr) {
185         codec_->compCb_ = nullptr;
186         codec_->compMgr_ = nullptr;
187         SLOGE("CreateComponent failed, ret=%{public}d", ret);
188         return IC_ERR_UNKNOWN;
189     }
190     codec_->componentName_ = name;
191     codec_->compUniqueStr_ = "[" + to_string(codec_->componentId_) + "][" + name + "]";
192     SLOGI("create omx node succ");
193     return IC_ERR_OK;
194 }
195 
OnShutDown(const MsgInfo & info)196 void ImageCodec::UninitializedState::OnShutDown(const MsgInfo &info)
197 {
198     ReplyErrorCode(info.id, IC_ERR_OK);
199 }
200 
201 /**************************** UninitializedState End ******************************/
202 
203 /**************************** InitializedState Start **********************************/
OnStateEntered()204 void ImageCodec::InitializedState::OnStateEntered()
205 {
206     codec_->inputPortEos_ = false;
207     codec_->outputPortEos_ = false;
208     codec_->outputFormat_.reset();
209 
210     ProcessShutDownFromRunning();
211     codec_->notifyCallerAfterShutdownComplete_ = false;
212     codec_->ProcessDeferredMessages();
213 }
214 
ProcessShutDownFromRunning()215 void ImageCodec::InitializedState::ProcessShutDownFromRunning()
216 {
217     if (!codec_->isShutDownFromRunning_) {
218         return;
219     }
220     SLOGI("we are doing shutdown from running/portchange/flush -> stopping -> initialized");
221     codec_->ChangeStateTo(codec_->uninitializedState_);
222     if (codec_->notifyCallerAfterShutdownComplete_) {
223         SLOGI("reply to release msg");
224         MsgInfo msg { MsgWhat::RELEASE, 0, nullptr };
225         if (codec_->GetFirstSyncMsgToReply(msg)) {
226             ReplyErrorCode(msg.id, IC_ERR_OK);
227         }
228         codec_->notifyCallerAfterShutdownComplete_ = false;
229     }
230     codec_->isShutDownFromRunning_ = false;
231 }
232 
OnMsgReceived(const MsgInfo & info)233 void ImageCodec::InitializedState::OnMsgReceived(const MsgInfo &info)
234 {
235     switch (info.type) {
236         case MsgWhat::SET_CALLBACK: {
237             OnSetCallBack(info);
238             return;
239         }
240         case MsgWhat::CONFIGURE: {
241             OnConfigure(info);
242             return;
243         }
244         case MsgWhat::GET_OUTPUT_BUFFER_USAGE: {
245             OnGetOutputBufferUsage(info);
246             break;
247         }
248         case MsgWhat::SET_OUTPUT_BUFFER: {
249             OnSetOutputBuffer(info);
250             break;
251         }
252         case MsgWhat::GET_PACKED_INPUT_FLAG: {
253             OnGetPackedInputFlag(info);
254             break;
255         }
256         case MsgWhat::START: {
257             OnStart(info);
258             return;
259         }
260         default: {
261             BaseState::OnMsgReceived(info);
262         }
263     }
264 }
265 
OnSetCallBack(const MsgInfo & info)266 void ImageCodec::InitializedState::OnSetCallBack(const MsgInfo &info)
267 {
268     int32_t err;
269     shared_ptr<ImageCodecCallback> cb;
270     (void)info.param->GetValue("callback", cb);
271     if (cb == nullptr) {
272         err = IC_ERR_INVALID_VAL;
273         SLOGE("invalid param");
274     } else {
275         codec_->callback_ = cb;
276         err = IC_ERR_OK;
277     }
278     ReplyErrorCode(info.id, err);
279 }
280 
OnConfigure(const MsgInfo & info)281 void ImageCodec::InitializedState::OnConfigure(const MsgInfo &info)
282 {
283     Format fmt;
284     (void)info.param->GetValue("format", fmt);
285     ReplyErrorCode(info.id, codec_->OnConfigure(fmt));
286 }
287 
OnGetOutputBufferUsage(const MsgInfo & info)288 void ImageCodec::InitializedState::OnGetOutputBufferUsage(const MsgInfo &info)
289 {
290     ParamSP reply = make_shared<ParamBundle>();
291     reply->SetValue<int32_t>("err", IC_ERR_OK);
292     reply->SetValue("usage", codec_->OnGetOutputBufferUsage());
293     codec_->PostReply(info.id, reply);
294 }
295 
OnSetOutputBuffer(const MsgInfo & info)296 void ImageCodec::InitializedState::OnSetOutputBuffer(const MsgInfo &info)
297 {
298     sptr<SurfaceBuffer> output;
299     (void)info.param->GetValue("output", output);
300     ReplyErrorCode(info.id, codec_->OnSetOutputBuffer(output));
301 }
302 
OnGetPackedInputFlag(const MsgInfo & info)303 void ImageCodec::InitializedState::OnGetPackedInputFlag(const MsgInfo &info)
304 {
305     ParamSP reply = make_shared<ParamBundle>();
306     reply->SetValue<int32_t>("err", IC_ERR_OK);
307     reply->SetValue("packedInputFlag", codec_->OnGetPackedInputFlag());
308     codec_->PostReply(info.id, reply);
309 }
310 
OnStart(const MsgInfo & info)311 void ImageCodec::InitializedState::OnStart(const MsgInfo &info)
312 {
313     if (!codec_->ReadyToStart()) {
314         ReplyErrorCode(info.id, IC_ERR_INVALID_OPERATION);
315         return;
316     }
317     SLOGI("begin to set omx to idle");
318     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
319     if (ret == HDF_SUCCESS) {
320         codec_->ReplyToSyncMsgLater(info);
321         codec_->ChangeStateTo(codec_->startingState_);
322     } else {
323         SLOGE("set omx to idle failed, ret=%{public}d", ret);
324         ReplyErrorCode(info.id, IC_ERR_UNKNOWN);
325     }
326 }
327 
OnShutDown(const MsgInfo & info)328 void ImageCodec::InitializedState::OnShutDown(const MsgInfo &info)
329 {
330     SLOGI("receive RELEASE");
331     codec_->ChangeStateTo(codec_->uninitializedState_);
332     codec_->notifyCallerAfterShutdownComplete_ = false;
333     ReplyErrorCode(info.id, IC_ERR_OK);
334 }
335 /**************************** InitializedState End ******************************/
336 
337 /**************************** StartingState Start ******************************/
OnStateEntered()338 void ImageCodec::StartingState::OnStateEntered()
339 {
340     hasError_ = false;
341 
342     ParamSP msg = make_shared<ParamBundle>();
343     msg->SetValue("generation", codec_->stateGeneration_);
344     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
345 
346     int32_t ret = AllocateBuffers();
347     if (ret != IC_ERR_OK) {
348         SLOGE("AllocateBuffers failed, back to init state");
349         hasError_ = true;
350         ReplyStartMsg(ret);
351         codec_->ChangeStateTo(codec_->initializedState_);
352     }
353 }
354 
AllocateBuffers()355 int32_t ImageCodec::StartingState::AllocateBuffers()
356 {
357     int32_t ret = codec_->AllocateBuffersOnPort(OMX_DirInput, false);
358     if (ret != IC_ERR_OK) {
359         return ret;
360     }
361     ret = codec_->AllocateBuffersOnPort(OMX_DirOutput, false);
362     if (ret != IC_ERR_OK) {
363         return ret;
364     }
365     return IC_ERR_OK;
366 }
367 
OnMsgReceived(const MsgInfo & info)368 void ImageCodec::StartingState::OnMsgReceived(const MsgInfo &info)
369 {
370     switch (info.type) {
371         case MsgWhat::GET_INPUT_FORMAT:
372         case MsgWhat::GET_OUTPUT_FORMAT: {
373             codec_->DeferMessage(info);
374             return;
375         }
376         case MsgWhat::START: {
377             ReplyErrorCode(info.id, IC_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(IC_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 ImageCodec::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 != static_cast<uint32_t>(CODEC_COMMAND_STATE_SET)) {
403         SLOGW("ignore event: data1=%{public}u, data2=%{public}u", data1, data2);
404         return;
405     }
406     if (data2 == static_cast<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(IC_ERR_UNKNOWN);
413             codec_->ChangeStateTo(codec_->initializedState_);
414         }
415     } else if (data2 == static_cast<uint32_t>(CODEC_STATE_EXECUTING)) {
416         SLOGI("omx now executing");
417         ReplyStartMsg(IC_ERR_OK);
418         codec_->SubmitAllBuffersOwnedByUs();
419         codec_->ChangeStateTo(codec_->runningState_);
420     }
421 }
422 
OnShutDown(const MsgInfo & info)423 void ImageCodec::StartingState::OnShutDown(const MsgInfo &info)
424 {
425     codec_->DeferMessage(info);
426 }
427 
ReplyStartMsg(int32_t errCode)428 void ImageCodec::StartingState::ReplyStartMsg(int32_t errCode)
429 {
430     MsgInfo msg {MsgWhat::START, 0, nullptr};
431     if (codec_->GetFirstSyncMsgToReply(msg)) {
432         SLOGI("start %{public}s", (errCode == 0) ? "succ" : "failed");
433         ReplyErrorCode(msg.id, errCode);
434     } else {
435         SLOGE("there should be a start msg to reply");
436     }
437 }
438 
OnStateExited()439 void ImageCodec::StartingState::OnStateExited()
440 {
441     if (hasError_) {
442         SLOGW("error occured, roll omx back to loaded and free allocated buffers");
443         if (codec_->RollOmxBackToLoaded()) {
444             codec_->ClearBufferPool(OMX_DirInput);
445             codec_->ClearBufferPool(OMX_DirOutput);
446         }
447     }
448     BaseState::OnStateExited();
449 }
450 
451 /**************************** StartingState End ******************************/
452 
453 /**************************** RunningState Start ********************************/
OnStateEntered()454 void ImageCodec::RunningState::OnStateEntered()
455 {
456     codec_->ProcessDeferredMessages();
457 }
458 
OnMsgReceived(const MsgInfo & info)459 void ImageCodec::RunningState::OnMsgReceived(const MsgInfo &info)
460 {
461     switch (info.type) {
462         case MsgWhat::START:
463             ReplyErrorCode(info.id, codec_->SubmitAllBuffersOwnedByUs());
464             break;
465         case MsgWhat::QUEUE_INPUT_BUFFER:
466             codec_->OnQueueInputBuffer(info, inputMode_);
467             break;
468         case MsgWhat::RELEASE_OUTPUT_BUFFER:
469             codec_->OnReleaseOutputBuffer(info, outputMode_);
470             break;
471         default:
472             BaseState::OnMsgReceived(info);
473             break;
474     }
475 }
476 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)477 void ImageCodec::RunningState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
478 {
479     switch (event) {
480         case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
481             if (data1 != OMX_DirOutput) {
482                 SLOGI("ignore input port changed");
483                 return;
484             }
485             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
486                 SLOGI("output port settings changed, begin to ask omx to disable out port");
487                 codec_->UpdateOutPortFormat();
488                 int32_t ret = codec_->compNode_->SendCommand(
489                     CODEC_COMMAND_PORT_DISABLE, OMX_DirOutput, {});
490                 if (ret == HDF_SUCCESS) {
491                     codec_->EraseOutBuffersOwnedByUs();
492                     codec_->ChangeStateTo(codec_->outputPortChangedState_);
493                 } else {
494                     SLOGE("ask omx to disable out port failed");
495                     codec_->SignalError(IC_ERR_UNKNOWN);
496                 }
497             } else if (data2 == OMX_IndexColorAspects) {
498                 codec_->UpdateColorAspects();
499             } else {
500                 SLOGI("unknown data2 0x%{public}x for CODEC_EVENT_PORT_SETTINGS_CHANGED", data2);
501             }
502             return;
503         }
504         default: {
505             BaseState::OnCodecEvent(event, data1, data2);
506         }
507     }
508 }
509 
OnShutDown(const MsgInfo & info)510 void ImageCodec::RunningState::OnShutDown(const MsgInfo &info)
511 {
512     codec_->isShutDownFromRunning_ = true;
513     codec_->notifyCallerAfterShutdownComplete_ = true;
514     codec_->isBufferCirculating_ = false;
515 
516     SLOGI("receive release msg, begin to set omx to idle");
517     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
518     if (ret == HDF_SUCCESS) {
519         codec_->ReplyToSyncMsgLater(info);
520         codec_->ChangeStateTo(codec_->stoppingState_);
521     } else {
522         SLOGE("set omx to idle failed, ret=%{public}d", ret);
523         ReplyErrorCode(info.id, IC_ERR_UNKNOWN);
524     }
525 }
526 /**************************** RunningState End ********************************/
527 
528 
529 /**************************** OutputPortChangedState Start ********************************/
OnStateEntered()530 void ImageCodec::OutputPortChangedState::OnStateEntered()
531 {
532     ParamSP msg = make_shared<ParamBundle>();
533     msg->SetValue("generation", codec_->stateGeneration_);
534     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
535 }
536 
OnMsgReceived(const MsgInfo & info)537 void ImageCodec::OutputPortChangedState::OnMsgReceived(const MsgInfo &info)
538 {
539     switch (info.type) {
540         case MsgWhat::START:
541         case MsgWhat::GET_INPUT_FORMAT:
542         case MsgWhat::GET_OUTPUT_FORMAT: {
543             codec_->DeferMessage(info);
544             return;
545         }
546         case MsgWhat::QUEUE_INPUT_BUFFER: {
547             codec_->OnQueueInputBuffer(info, inputMode_);
548             return;
549         }
550         case MsgWhat::RELEASE_OUTPUT_BUFFER: {
551             codec_->OnReleaseOutputBuffer(info, outputMode_);
552             return;
553         }
554         case MsgWhat::FORCE_SHUTDOWN: {
555             OnForceShutDown(info);
556             return;
557         }
558         case MsgWhat::CHECK_IF_STUCK: {
559             OnCheckIfStuck(info);
560             return;
561         }
562         default: {
563             BaseState::OnMsgReceived(info);
564         }
565     }
566 }
567 
OnShutDown(const MsgInfo & info)568 void ImageCodec::OutputPortChangedState::OnShutDown(const MsgInfo &info)
569 {
570     if (codec_->hasFatalError_) {
571         ParamSP stopMsg = make_shared<ParamBundle>();
572         stopMsg->SetValue("generation", codec_->stateGeneration_);
573         codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
574     }
575     codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER, true);
576     codec_->DeferMessage(info);
577 }
578 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)579 void ImageCodec::OutputPortChangedState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
580 {
581     switch (event) {
582         case CODEC_EVENT_CMD_COMPLETE: {
583             if (data1 == CODEC_COMMAND_PORT_DISABLE) {
584                 if (data2 != OMX_DirOutput) {
585                     SLOGW("ignore input port disable complete");
586                     return;
587                 }
588                 SLOGI("output port is disabled");
589                 HandleOutputPortDisabled();
590             } else if (data1 == CODEC_COMMAND_PORT_ENABLE) {
591                 if (data2 != OMX_DirOutput) {
592                     SLOGW("ignore input port enable complete");
593                     return;
594                 }
595                 SLOGI("output port is enabled");
596                 HandleOutputPortEnabled();
597             }
598             return;
599         }
600         default: {
601             BaseState::OnCodecEvent(event, data1, data2);
602         }
603     }
604 }
605 
HandleOutputPortDisabled()606 void ImageCodec::OutputPortChangedState::HandleOutputPortDisabled()
607 {
608     int32_t ret = IC_ERR_OK;
609     if (!codec_->outputBufferPool_.empty()) {
610         SLOGE("output port is disabled but not empty: %{public}zu", codec_->outputBufferPool_.size());
611         ret = IC_ERR_UNKNOWN;
612     }
613     if (ret == IC_ERR_OK) {
614         ret = codec_->ReConfigureOutputBufferCnt();
615     }
616     if (ret == IC_ERR_OK) {
617         SLOGI("begin to ask omx to enable out port");
618         int32_t err = codec_->compNode_->SendCommand(CODEC_COMMAND_PORT_ENABLE, OMX_DirOutput, {});
619         if (err == HDF_SUCCESS) {
620             ret = codec_->AllocateBuffersOnPort(OMX_DirOutput, true);
621         } else {
622             SLOGE("ask omx to enable out port failed, ret=%{public}d", ret);
623             ret = IC_ERR_UNKNOWN;
624         }
625     }
626     if (ret != IC_ERR_OK) {
627         codec_->SignalError(IC_ERR_INVALID_VAL);
628     }
629 }
630 
HandleOutputPortEnabled()631 void ImageCodec::OutputPortChangedState::HandleOutputPortEnabled()
632 {
633     if (codec_->isBufferCirculating_) {
634         codec_->SubmitOutputBuffersToOmxNode();
635     }
636     codec_->callback_->OnOutputFormatChanged(*(codec_->outputFormat_.get()));
637     codec_->ChangeStateTo(codec_->runningState_);
638 }
639 /**************************** OutputPortChangedState End ********************************/
640 
641 /**************************** StoppingState Start ********************************/
OnStateEntered()642 void ImageCodec::StoppingState::OnStateEntered()
643 {
644     omxNodeInIdleState_ = false;
645     omxNodeIsChangingToLoadedState_ = false;
646     codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
647     codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
648     SLOGI("all buffer owned by user are now owned by us");
649 
650     ParamSP msg = make_shared<ParamBundle>();
651     msg->SetValue("generation", codec_->stateGeneration_);
652     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
653 }
654 
OnMsgReceived(const MsgInfo & info)655 void ImageCodec::StoppingState::OnMsgReceived(const MsgInfo &info)
656 {
657     switch (info.type) {
658         case MsgWhat::CHECK_IF_STUCK: {
659             int32_t generation;
660             (void)info.param->GetValue("generation", generation);
661             if (generation == codec_->stateGeneration_) {
662                 SLOGE("stucked, force state transition");
663                 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_OMX);
664                 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_OMX);
665                 SLOGI("all buffer owned by omx are now owned by us");
666                 ChangeOmxNodeToLoadedState(true);
667                 codec_->ChangeStateTo(codec_->initializedState_);
668             }
669             return;
670         }
671         default: {
672             BaseState::OnMsgReceived(info);
673         }
674     }
675 }
676 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)677 void ImageCodec::StoppingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
678 {
679     switch (event) {
680         case CODEC_EVENT_CMD_COMPLETE: {
681             if (data1 != static_cast<uint32_t>(CODEC_COMMAND_STATE_SET)) {
682                 SLOGW("unexpected CODEC_EVENT_CMD_COMPLETE: %{public}u %{public}u", data1, data2);
683                 return;
684             }
685             if (data2 == static_cast<uint32_t>(CODEC_STATE_IDLE)) {
686                 SLOGI("omx now idle");
687                 omxNodeInIdleState_ = true;
688                 ChangeStateIfWeOwnAllBuffers();
689             } else if (data2 == static_cast<uint32_t>(CODEC_STATE_LOADED)) {
690                 SLOGI("omx now loaded");
691                 codec_->ChangeStateTo(codec_->initializedState_);
692             }
693             return;
694         }
695         default: {
696             BaseState::OnCodecEvent(event, data1, data2);
697         }
698     }
699 }
700 
ChangeStateIfWeOwnAllBuffers()701 void ImageCodec::StoppingState::ChangeStateIfWeOwnAllBuffers()
702 {
703     if (omxNodeInIdleState_ && codec_->IsAllBufferOwnedByUs()) {
704         ChangeOmxNodeToLoadedState(false);
705     } else {
706         SLOGD("cannot change state yet");
707     }
708 }
709 
ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)710 void ImageCodec::StoppingState::ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)
711 {
712     if (!omxNodeIsChangingToLoadedState_) {
713         SLOGI("begin to set omx to loaded");
714         int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
715         if (ret == HDF_SUCCESS) {
716             omxNodeIsChangingToLoadedState_ = true;
717         } else {
718             SLOGE("set omx to loaded failed, ret=%{public}d", ret);
719         }
720     }
721     if (forceToFreeBuffer || omxNodeIsChangingToLoadedState_) {
722         codec_->ClearBufferPool(OMX_DirInput);
723         codec_->ClearBufferPool(OMX_DirOutput);
724         return;
725     }
726     codec_->SignalError(IC_ERR_UNKNOWN);
727 }
728 
OnShutDown(const MsgInfo & info)729 void ImageCodec::StoppingState::OnShutDown(const MsgInfo &info)
730 {
731     codec_->DeferMessage(info);
732 }
733 /**************************** StoppingState End ********************************/
734 
735 } // namespace OHOS::ImagePlugin