• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_) + "]";
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("go 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_CAPABILITY: {
253             OnGetPackedInputCapability(info);
254             break;
255         }
256         case MsgWhat::SET_PACKED_INPUT_FLAG: {
257             OnSetPackedInputFlag(info);
258             break;
259         }
260         case MsgWhat::START: {
261             OnStart(info);
262             return;
263         }
264         default: {
265             BaseState::OnMsgReceived(info);
266         }
267     }
268 }
269 
OnSetCallBack(const MsgInfo & info)270 void ImageCodec::InitializedState::OnSetCallBack(const MsgInfo &info)
271 {
272     int32_t err;
273     shared_ptr<ImageCodecCallback> cb;
274     (void)info.param->GetValue("callback", cb);
275     if (cb == nullptr) {
276         err = IC_ERR_INVALID_VAL;
277         SLOGE("invalid param");
278     } else {
279         codec_->callback_ = cb;
280         err = IC_ERR_OK;
281     }
282     ReplyErrorCode(info.id, err);
283 }
284 
OnConfigure(const MsgInfo & info)285 void ImageCodec::InitializedState::OnConfigure(const MsgInfo &info)
286 {
287     Format fmt;
288     (void)info.param->GetValue("format", fmt);
289     ReplyErrorCode(info.id, codec_->OnConfigure(fmt));
290 }
291 
OnGetOutputBufferUsage(const MsgInfo & info)292 void ImageCodec::InitializedState::OnGetOutputBufferUsage(const MsgInfo &info)
293 {
294     ParamSP reply = make_shared<ParamBundle>();
295     reply->SetValue<int32_t>("err", IC_ERR_OK);
296     reply->SetValue("usage", codec_->OnGetOutputBufferUsage());
297     codec_->PostReply(info.id, reply);
298 }
299 
OnSetOutputBuffer(const MsgInfo & info)300 void ImageCodec::InitializedState::OnSetOutputBuffer(const MsgInfo &info)
301 {
302     sptr<SurfaceBuffer> output;
303     (void)info.param->GetValue("output", output);
304     ReplyErrorCode(info.id, codec_->OnSetOutputBuffer(output));
305 }
306 
OnSetPackedInputFlag(const MsgInfo & info)307 void ImageCodec::InitializedState::OnSetPackedInputFlag(const MsgInfo &info)
308 {
309     bool flag = false;
310     (void)info.param->GetValue("packedInputFlag", flag);
311     ReplyErrorCode(info.id, codec_->OnSetPackedInputFlag(flag));
312 }
313 
OnGetPackedInputCapability(const MsgInfo & info)314 void ImageCodec::InitializedState::OnGetPackedInputCapability(const MsgInfo &info)
315 {
316     ParamSP reply = make_shared<ParamBundle>();
317     reply->SetValue<int32_t>("err", IC_ERR_OK);
318     reply->SetValue("isPackedInputSupported", codec_->OnGetPackedInputCapability());
319     codec_->PostReply(info.id, reply);
320 }
321 
OnStart(const MsgInfo & info)322 void ImageCodec::InitializedState::OnStart(const MsgInfo &info)
323 {
324     if (!codec_->ReadyToStart()) {
325         ReplyErrorCode(info.id, IC_ERR_INVALID_OPERATION);
326         return;
327     }
328     SLOGI("set omx to idle");
329     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
330     if (ret == HDF_SUCCESS) {
331         codec_->ReplyToSyncMsgLater(info);
332         codec_->ChangeStateTo(codec_->startingState_);
333     } else {
334         SLOGE("set omx to idle failed, ret=%{public}d", ret);
335         ReplyErrorCode(info.id, IC_ERR_UNKNOWN);
336     }
337 }
338 
OnShutDown(const MsgInfo & info)339 void ImageCodec::InitializedState::OnShutDown(const MsgInfo &info)
340 {
341     SLOGI("receive RELEASE");
342     codec_->ChangeStateTo(codec_->uninitializedState_);
343     codec_->notifyCallerAfterShutdownComplete_ = false;
344     ReplyErrorCode(info.id, IC_ERR_OK);
345 }
346 /**************************** InitializedState End ******************************/
347 
348 /**************************** StartingState Start ******************************/
OnStateEntered()349 void ImageCodec::StartingState::OnStateEntered()
350 {
351     hasError_ = false;
352 
353     ParamSP msg = make_shared<ParamBundle>();
354     msg->SetValue("generation", codec_->stateGeneration_);
355     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
356 
357     int32_t ret = AllocateBuffers();
358     if (ret != IC_ERR_OK) {
359         SLOGE("AllocateBuffers failed, back to init state");
360         hasError_ = true;
361         ReplyStartMsg(ret);
362         codec_->ChangeStateTo(codec_->initializedState_);
363     }
364 }
365 
AllocateBuffers()366 int32_t ImageCodec::StartingState::AllocateBuffers()
367 {
368     int32_t ret = codec_->AllocateBuffersOnPort(OMX_DirInput, false);
369     if (ret != IC_ERR_OK) {
370         return ret;
371     }
372     ret = codec_->AllocateBuffersOnPort(OMX_DirOutput, false);
373     if (ret != IC_ERR_OK) {
374         return ret;
375     }
376     return IC_ERR_OK;
377 }
378 
OnMsgReceived(const MsgInfo & info)379 void ImageCodec::StartingState::OnMsgReceived(const MsgInfo &info)
380 {
381     switch (info.type) {
382         case MsgWhat::GET_INPUT_FORMAT:
383         case MsgWhat::GET_OUTPUT_FORMAT: {
384             codec_->DeferMessage(info);
385             return;
386         }
387         case MsgWhat::START: {
388             ReplyErrorCode(info.id, IC_ERR_OK);
389             return;
390         }
391         case MsgWhat::CHECK_IF_STUCK: {
392             int32_t generation;
393             if (info.param->GetValue("generation", generation) &&
394                 generation == codec_->stateGeneration_) {
395                 SLOGE("stucked, force state transition");
396                 hasError_ = true;
397                 ReplyStartMsg(IC_ERR_UNKNOWN);
398                 codec_->ChangeStateTo(codec_->initializedState_);
399             }
400             return;
401         }
402         default: {
403             BaseState::OnMsgReceived(info);
404         }
405     }
406 }
407 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)408 void ImageCodec::StartingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
409 {
410     if (event != CODEC_EVENT_CMD_COMPLETE) {
411         return BaseState::OnCodecEvent(event, data1, data2);
412     }
413     if (data1 != static_cast<uint32_t>(CODEC_COMMAND_STATE_SET)) {
414         SLOGW("ignore event: data1=%{public}u, data2=%{public}u", data1, data2);
415         return;
416     }
417     if (data2 == static_cast<uint32_t>(CODEC_STATE_IDLE)) {
418         SLOGI("omx now idle, set to executing");
419         int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
420         if (ret != HDF_SUCCESS) {
421             SLOGE("set omx to executing failed, ret=%{public}d", ret);
422             hasError_ = true;
423             ReplyStartMsg(IC_ERR_UNKNOWN);
424             codec_->ChangeStateTo(codec_->initializedState_);
425         }
426     } else if (data2 == static_cast<uint32_t>(CODEC_STATE_EXECUTING)) {
427         SLOGI("omx now executing");
428         ReplyStartMsg(IC_ERR_OK);
429         codec_->SubmitAllBuffersOwnedByUs();
430         codec_->ChangeStateTo(codec_->runningState_);
431     }
432 }
433 
OnShutDown(const MsgInfo & info)434 void ImageCodec::StartingState::OnShutDown(const MsgInfo &info)
435 {
436     codec_->DeferMessage(info);
437 }
438 
ReplyStartMsg(int32_t errCode)439 void ImageCodec::StartingState::ReplyStartMsg(int32_t errCode)
440 {
441     MsgInfo msg {MsgWhat::START, 0, nullptr};
442     if (codec_->GetFirstSyncMsgToReply(msg)) {
443         SLOGI("start %{public}s", (errCode == 0) ? "succ" : "failed");
444         ReplyErrorCode(msg.id, errCode);
445     } else {
446         SLOGE("there should be a start msg to reply");
447     }
448 }
449 
OnStateExited()450 void ImageCodec::StartingState::OnStateExited()
451 {
452     if (hasError_) {
453         SLOGW("error occured, roll omx back to loaded and free allocated buffers");
454         if (codec_->RollOmxBackToLoaded()) {
455             codec_->ClearBufferPool(OMX_DirInput);
456             codec_->ClearBufferPool(OMX_DirOutput);
457         }
458     }
459     BaseState::OnStateExited();
460 }
461 
462 /**************************** StartingState End ******************************/
463 
464 /**************************** RunningState Start ********************************/
OnStateEntered()465 void ImageCodec::RunningState::OnStateEntered()
466 {
467     codec_->ProcessDeferredMessages();
468 }
469 
OnMsgReceived(const MsgInfo & info)470 void ImageCodec::RunningState::OnMsgReceived(const MsgInfo &info)
471 {
472     switch (info.type) {
473         case MsgWhat::START:
474             ReplyErrorCode(info.id, codec_->SubmitAllBuffersOwnedByUs());
475             break;
476         case MsgWhat::QUEUE_INPUT_BUFFER:
477             codec_->OnQueueInputBuffer(info, inputMode_);
478             break;
479         case MsgWhat::RELEASE_OUTPUT_BUFFER:
480             codec_->OnReleaseOutputBuffer(info, outputMode_);
481             break;
482         default:
483             BaseState::OnMsgReceived(info);
484             break;
485     }
486 }
487 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)488 void ImageCodec::RunningState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
489 {
490     switch (event) {
491         case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
492             if (data1 != OMX_DirOutput) {
493                 SLOGI("ignore input port changed");
494                 return;
495             }
496             if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
497                 SLOGI("output port changed, need to disable");
498                 codec_->UpdateOutPortFormat();
499                 int32_t ret = codec_->compNode_->SendCommand(
500                     CODEC_COMMAND_PORT_DISABLE, OMX_DirOutput, {});
501                 if (ret == HDF_SUCCESS) {
502                     codec_->EraseOutBuffersOwnedByUs();
503                     codec_->ChangeStateTo(codec_->outputPortChangedState_);
504                 } else {
505                     SLOGE("ask omx to disable out port failed");
506                     codec_->SignalError(IC_ERR_UNKNOWN);
507                 }
508             } else if (data2 == OMX_IndexColorAspects) {
509                 codec_->UpdateColorAspects();
510             } else {
511                 SLOGI("unknown data2 0x%{public}x for CODEC_EVENT_PORT_SETTINGS_CHANGED", data2);
512             }
513             return;
514         }
515         default: {
516             BaseState::OnCodecEvent(event, data1, data2);
517         }
518     }
519 }
520 
OnShutDown(const MsgInfo & info)521 void ImageCodec::RunningState::OnShutDown(const MsgInfo &info)
522 {
523     codec_->isShutDownFromRunning_ = true;
524     codec_->notifyCallerAfterShutdownComplete_ = true;
525     codec_->isBufferCirculating_ = false;
526 
527     SLOGI("receive release msg, set omx to idle");
528     int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
529     if (ret == HDF_SUCCESS) {
530         codec_->ReplyToSyncMsgLater(info);
531         codec_->ChangeStateTo(codec_->stoppingState_);
532     } else {
533         SLOGE("set omx to idle failed, ret=%{public}d", ret);
534         ReplyErrorCode(info.id, IC_ERR_UNKNOWN);
535     }
536 }
537 /**************************** RunningState End ********************************/
538 
539 
540 /**************************** OutputPortChangedState Start ********************************/
OnStateEntered()541 void ImageCodec::OutputPortChangedState::OnStateEntered()
542 {
543     ParamSP msg = make_shared<ParamBundle>();
544     msg->SetValue("generation", codec_->stateGeneration_);
545     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
546 }
547 
OnMsgReceived(const MsgInfo & info)548 void ImageCodec::OutputPortChangedState::OnMsgReceived(const MsgInfo &info)
549 {
550     switch (info.type) {
551         case MsgWhat::START:
552         case MsgWhat::GET_INPUT_FORMAT:
553         case MsgWhat::GET_OUTPUT_FORMAT: {
554             codec_->DeferMessage(info);
555             return;
556         }
557         case MsgWhat::QUEUE_INPUT_BUFFER: {
558             codec_->OnQueueInputBuffer(info, inputMode_);
559             return;
560         }
561         case MsgWhat::RELEASE_OUTPUT_BUFFER: {
562             codec_->OnReleaseOutputBuffer(info, outputMode_);
563             return;
564         }
565         case MsgWhat::FORCE_SHUTDOWN: {
566             OnForceShutDown(info);
567             return;
568         }
569         case MsgWhat::CHECK_IF_STUCK: {
570             OnCheckIfStuck(info);
571             return;
572         }
573         default: {
574             BaseState::OnMsgReceived(info);
575         }
576     }
577 }
578 
OnShutDown(const MsgInfo & info)579 void ImageCodec::OutputPortChangedState::OnShutDown(const MsgInfo &info)
580 {
581     if (codec_->hasFatalError_) {
582         ParamSP stopMsg = make_shared<ParamBundle>();
583         stopMsg->SetValue("generation", codec_->stateGeneration_);
584         codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
585     }
586     codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER, true);
587     codec_->DeferMessage(info);
588 }
589 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)590 void ImageCodec::OutputPortChangedState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
591 {
592     switch (event) {
593         case CODEC_EVENT_CMD_COMPLETE: {
594             if (data1 == CODEC_COMMAND_PORT_DISABLE) {
595                 if (data2 != OMX_DirOutput) {
596                     SLOGW("ignore input port disable complete");
597                     return;
598                 }
599                 SLOGI("disable out port");
600                 HandleOutputPortDisabled();
601             } else if (data1 == CODEC_COMMAND_PORT_ENABLE) {
602                 if (data2 != OMX_DirOutput) {
603                     SLOGW("ignore input port enable complete");
604                     return;
605                 }
606                 SLOGI("enable out port");
607                 HandleOutputPortEnabled();
608             }
609             return;
610         }
611         default: {
612             BaseState::OnCodecEvent(event, data1, data2);
613         }
614     }
615 }
616 
HandleOutputPortDisabled()617 void ImageCodec::OutputPortChangedState::HandleOutputPortDisabled()
618 {
619     int32_t ret = IC_ERR_OK;
620     if (!codec_->outputBufferPool_.empty()) {
621         SLOGE("output port is disabled but not empty: %{public}zu", codec_->outputBufferPool_.size());
622         ret = IC_ERR_UNKNOWN;
623     }
624     if (ret == IC_ERR_OK) {
625         ret = codec_->ReConfigureOutputBufferCnt();
626     }
627     if (ret == IC_ERR_OK) {
628         SLOGI("ask omx to enable out port");
629         int32_t err = codec_->compNode_->SendCommand(CODEC_COMMAND_PORT_ENABLE, OMX_DirOutput, {});
630         if (err == HDF_SUCCESS) {
631             ret = codec_->AllocateBuffersOnPort(OMX_DirOutput, true);
632         } else {
633             SLOGE("ask omx to enable out port failed, ret=%{public}d", ret);
634             ret = IC_ERR_UNKNOWN;
635         }
636     }
637     if (ret != IC_ERR_OK) {
638         codec_->SignalError(IC_ERR_INVALID_VAL);
639     }
640 }
641 
HandleOutputPortEnabled()642 void ImageCodec::OutputPortChangedState::HandleOutputPortEnabled()
643 {
644     if (codec_->isBufferCirculating_) {
645         codec_->SubmitOutputBuffersToOmxNode();
646     }
647     codec_->callback_->OnOutputFormatChanged(*(codec_->outputFormat_.get()));
648     codec_->ChangeStateTo(codec_->runningState_);
649 }
650 /**************************** OutputPortChangedState End ********************************/
651 
652 /**************************** StoppingState Start ********************************/
OnStateEntered()653 void ImageCodec::StoppingState::OnStateEntered()
654 {
655     omxNodeInIdleState_ = false;
656     omxNodeIsChangingToLoadedState_ = false;
657     codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
658     codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
659     SLOGI("user buffer now owned by us");
660 
661     ParamSP msg = make_shared<ParamBundle>();
662     msg->SetValue("generation", codec_->stateGeneration_);
663     codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
664 }
665 
OnMsgReceived(const MsgInfo & info)666 void ImageCodec::StoppingState::OnMsgReceived(const MsgInfo &info)
667 {
668     switch (info.type) {
669         case MsgWhat::CHECK_IF_STUCK: {
670             int32_t generation;
671             (void)info.param->GetValue("generation", generation);
672             if (generation == codec_->stateGeneration_) {
673                 SLOGE("stucked, force state transition");
674                 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_OMX);
675                 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_OMX);
676                 SLOGI("omx buffer now owned by us");
677                 ChangeOmxNodeToLoadedState(true);
678                 codec_->ChangeStateTo(codec_->initializedState_);
679             }
680             return;
681         }
682         default: {
683             BaseState::OnMsgReceived(info);
684         }
685     }
686 }
687 
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)688 void ImageCodec::StoppingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
689 {
690     switch (event) {
691         case CODEC_EVENT_CMD_COMPLETE: {
692             if (data1 != static_cast<uint32_t>(CODEC_COMMAND_STATE_SET)) {
693                 SLOGW("unexpected CODEC_EVENT_CMD_COMPLETE: %{public}u %{public}u", data1, data2);
694                 return;
695             }
696             if (data2 == static_cast<uint32_t>(CODEC_STATE_IDLE)) {
697                 SLOGI("omx now idle");
698                 omxNodeInIdleState_ = true;
699                 ChangeStateIfWeOwnAllBuffers();
700             } else if (data2 == static_cast<uint32_t>(CODEC_STATE_LOADED)) {
701                 SLOGI("omx now loaded");
702                 codec_->ChangeStateTo(codec_->initializedState_);
703             }
704             return;
705         }
706         default: {
707             BaseState::OnCodecEvent(event, data1, data2);
708         }
709     }
710 }
711 
ChangeStateIfWeOwnAllBuffers()712 void ImageCodec::StoppingState::ChangeStateIfWeOwnAllBuffers()
713 {
714     if (omxNodeInIdleState_ && codec_->IsAllBufferOwnedByUs()) {
715         ChangeOmxNodeToLoadedState(false);
716     } else {
717         SLOGD("cannot change state yet");
718     }
719 }
720 
ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)721 void ImageCodec::StoppingState::ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)
722 {
723     if (!omxNodeIsChangingToLoadedState_) {
724         SLOGI("set omx to loaded");
725         int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
726         if (ret == HDF_SUCCESS) {
727             omxNodeIsChangingToLoadedState_ = true;
728         } else {
729             SLOGE("set omx to loaded failed, ret=%{public}d", ret);
730         }
731     }
732     if (forceToFreeBuffer || omxNodeIsChangingToLoadedState_) {
733         codec_->ClearBufferPool(OMX_DirInput);
734         codec_->ClearBufferPool(OMX_DirOutput);
735         return;
736     }
737     codec_->SignalError(IC_ERR_UNKNOWN);
738 }
739 
OnShutDown(const MsgInfo & info)740 void ImageCodec::StoppingState::OnShutDown(const MsgInfo &info)
741 {
742     codec_->DeferMessage(info);
743 }
744 /**************************** StoppingState End ********************************/
745 
746 } // namespace OHOS::ImagePlugin