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