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