1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "hcodec.h"
17 #include "hdf_base.h"
18 #include "hitrace_meter.h"
19 #include "hcodec_list.h"
20 #include "hcodec_log.h"
21 #include "hcodec_utils.h"
22
23 namespace OHOS::MediaAVCodec {
24 using namespace std;
25 using namespace CodecHDI;
26
27 /**************************** BaseState Start ****************************/
OnMsgReceived(const MsgInfo & info)28 void HCodec::BaseState::OnMsgReceived(const MsgInfo &info)
29 {
30 switch (info.type) {
31 case MsgWhat::GET_HIDUMPER_INFO: {
32 ParamSP reply = make_shared<ParamBundle>();
33 reply->SetValue("hidumper-info", codec_->OnGetHidumperInfo());
34 reply->SetValue<int32_t>("err", AVCS_ERR_OK);
35 codec_->PostReply(info.id, reply);
36 return;
37 }
38 case MsgWhat::CODEC_EVENT: {
39 OnCodecEvent(info);
40 return;
41 }
42 case MsgWhat::OMX_EMPTY_BUFFER_DONE: {
43 uint32_t bufferId = 0;
44 (void)info.param->GetValue(BUFFER_ID, bufferId);
45 codec_->OnOMXEmptyBufferDone(bufferId, inputMode_);
46 return;
47 }
48 case MsgWhat::OMX_FILL_BUFFER_DONE: {
49 OmxCodecBuffer omxBuffer;
50 (void)info.param->GetValue("omxBuffer", omxBuffer);
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::STOP:
60 case MsgWhat::RELEASE: {
61 OnShutDown(info);
62 return;
63 }
64 default: {
65 const char* msgWhat = HCodec::ToString(static_cast<MsgWhat>(info.type));
66 if (info.id == ASYNC_MSG_ID) {
67 SLOGI("ignore msg %s in current state", msgWhat);
68 } else { // Make sure that all sync message are replied
69 SLOGE("%s cannot be called at this state", msgWhat);
70 ReplyErrorCode(info.id, AVCS_ERR_INVALID_STATE);
71 }
72 return;
73 }
74 }
75 }
76
ReplyErrorCode(MsgId id,int32_t err)77 void HCodec::BaseState::ReplyErrorCode(MsgId id, int32_t err)
78 {
79 if (id == ASYNC_MSG_ID) {
80 return;
81 }
82 ParamSP reply = make_shared<ParamBundle>();
83 reply->SetValue("err", err);
84 codec_->PostReply(id, reply);
85 }
86
OnCodecEvent(const MsgInfo & info)87 void HCodec::BaseState::OnCodecEvent(const MsgInfo &info)
88 {
89 CodecEventType event{};
90 uint32_t data1 = 0;
91 uint32_t data2 = 0;
92 (void)info.param->GetValue("event", event);
93 (void)info.param->GetValue("data1", data1);
94 (void)info.param->GetValue("data2", data2);
95 if (event == CODEC_EVENT_CMD_COMPLETE &&
96 data1 == static_cast<uint32_t>(CODEC_COMMAND_FLUSH) &&
97 data2 == static_cast<uint32_t>(OMX_ALL)) {
98 SLOGD("ignore flush all complete event");
99 } else {
100 OnCodecEvent(event, data1, data2);
101 }
102 }
103
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)104 void HCodec::BaseState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
105 {
106 if (event == CODEC_EVENT_ERROR) {
107 SLOGE("omx report error event, data1 = %u, data2 = %u", data1, data2);
108 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
109 if (data1 == static_cast<uint32_t>(OMX_ErrorUnsupportedSetting) ||
110 data1 == static_cast<uint32_t>(OMX_ErrorInsufficientResources)) {
111 SLOGE("unsupport or insufficient resources, need force shut down");
112 (void)codec_->ForceShutdown(codec_->stateGeneration_, false);
113 }
114 } else {
115 SLOGW("ignore event %d, data1 = %u, data2 = %u", event, data1, data2);
116 }
117 }
118
OnGetFormat(const MsgInfo & info)119 void HCodec::BaseState::OnGetFormat(const MsgInfo &info)
120 {
121 shared_ptr<Format> fmt = (info.type == MsgWhat::GET_INPUT_FORMAT) ?
122 codec_->inputFormat_ : codec_->outputFormat_;
123 ParamSP reply = make_shared<ParamBundle>();
124 if (fmt) {
125 reply->SetValue<int32_t>("err", AVCS_ERR_OK);
126 reply->SetValue("format", *fmt);
127 codec_->PostReply(info.id, reply);
128 } else {
129 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
130 }
131 }
132
OnSetParameters(const MsgInfo & info)133 void HCodec::BaseState::OnSetParameters(const MsgInfo &info)
134 {
135 Format params;
136 (void)info.param->GetValue("params", params);
137 ReplyErrorCode(info.id, codec_->OnSetParameters(params));
138 }
139
OnCheckIfStuck(const MsgInfo & info)140 void HCodec::BaseState::OnCheckIfStuck(const MsgInfo &info)
141 {
142 int32_t generation = 0;
143 (void)info.param->GetValue("generation", generation);
144 if (generation == codec_->stateGeneration_) {
145 SLOGE("stucked");
146 codec_->PrintAllBufferInfo();
147 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
148 }
149 }
150
OnForceShutDown(const MsgInfo & info)151 void HCodec::BaseState::OnForceShutDown(const MsgInfo &info)
152 {
153 int32_t generation = 0;
154 bool isNeedNotifyCaller;
155 (void)info.param->GetValue("generation", generation);
156 (void)info.param->GetValue("isNeedNotifyCaller", isNeedNotifyCaller);
157 codec_->ForceShutdown(generation, isNeedNotifyCaller);
158 }
159
OnSuspend(const MsgInfo & info)160 void HCodec::BaseState::OnSuspend(const MsgInfo &info)
161 {
162 SLOGI("begin to Suspend this codec");
163 int32_t errCode = codec_->DecreaseFreq();
164 if (errCode != AVCS_ERR_OK) {
165 SLOGE("Decrease Freq fail!");
166 }
167 ReplyErrorCode(info.id, errCode);
168 }
169
OnResume(const MsgInfo & info)170 void HCodec::BaseState::OnResume(const MsgInfo &info)
171 {
172 SLOGI("begin to Resume this codec");
173 int32_t errCode = codec_->RecoverFreq();
174 if (errCode != AVCS_ERR_OK) {
175 SLOGE("Recover Freq Fail!");
176 }
177 ReplyErrorCode(info.id, errCode);
178 }
179 /**************************** BaseState End ******************************/
180
181
182 /**************************** UninitializedState start ****************************/
OnStateEntered()183 void HCodec::UninitializedState::OnStateEntered()
184 {
185 codec_->gotFirstInput_ = false;
186 codec_->gotFirstOutput_ = false;
187 codec_->onePtsInToOutTotalCostUs_ = 0;
188 codec_->inTimeMap_.clear();
189 codec_->record_[OMX_DirInput].ResetAll();
190 codec_->record_[OMX_DirOutput].ResetAll();
191 codec_->circulateHasStopped_ = false;
192 codec_->OnEnterUninitializedState();
193 codec_->ReleaseComponent();
194 }
195
OnMsgReceived(const MsgInfo & info)196 void HCodec::UninitializedState::OnMsgReceived(const MsgInfo &info)
197 {
198 switch (info.type) {
199 case MsgWhat::INIT: {
200 int32_t err = codec_->OnAllocateComponent();
201 ReplyErrorCode(info.id, err);
202 if (err == AVCS_ERR_OK) {
203 codec_->ChangeStateTo(codec_->initializedState_);
204 }
205 break;
206 }
207 default: {
208 BaseState::OnMsgReceived(info);
209 }
210 }
211 }
212
OnShutDown(const MsgInfo & info)213 void HCodec::UninitializedState::OnShutDown(const MsgInfo &info)
214 {
215 ReplyErrorCode(info.id, AVCS_ERR_OK);
216 }
217
218 /**************************** UninitializedState End ******************************/
219
220 /**************************** InitializedState Start **********************************/
OnStateEntered()221 void HCodec::InitializedState::OnStateEntered()
222 {
223 codec_->inputPortEos_ = false;
224 codec_->outputPortEos_ = false;
225 codec_->outPortHasChanged_ = false;
226 codec_->inputFormat_.reset();
227 codec_->outputFormat_.reset();
228
229 ProcessShutDownFromRunning();
230 codec_->notifyCallerAfterShutdownComplete_ = false;
231 codec_->ProcessDeferredMessages();
232 }
233
ProcessShutDownFromRunning()234 void HCodec::InitializedState::ProcessShutDownFromRunning()
235 {
236 if (!codec_->isShutDownFromRunning_) {
237 return;
238 }
239 SLOGI(">>");
240 bool keepComponentAllocated = codec_->keepComponentAllocated_;
241 if (keepComponentAllocated) {
242 if (codec_->configFormat_ == nullptr) {
243 SLOGW("stored configuration is null");
244 } else {
245 Format copyOfCurConfig(*codec_->configFormat_);
246 codec_->OnConfigure(copyOfCurConfig);
247 }
248 } else {
249 codec_->ChangeStateTo(codec_->uninitializedState_);
250 }
251 if (codec_->notifyCallerAfterShutdownComplete_) {
252 SLOGI("reply to %s msg", keepComponentAllocated ? "stop" : "release");
253 MsgInfo msg { keepComponentAllocated ? MsgWhat::STOP : MsgWhat::RELEASE, 0, nullptr };
254 if (codec_->GetFirstSyncMsgToReply(msg)) {
255 ReplyErrorCode(msg.id, AVCS_ERR_OK);
256 }
257 codec_->notifyCallerAfterShutdownComplete_ = false;
258 }
259 codec_->isShutDownFromRunning_ = false;
260 codec_->keepComponentAllocated_ = false;
261 }
262
OnMsgReceived(const MsgInfo & info)263 void HCodec::InitializedState::OnMsgReceived(const MsgInfo &info)
264 {
265 switch (info.type) {
266 case MsgWhat::SET_CALLBACK: {
267 OnSetCallBack(info);
268 return;
269 }
270 case MsgWhat::CONFIGURE: {
271 OnConfigure(info);
272 return;
273 }
274 case MsgWhat::CONFIGURE_BUFFER: {
275 std::shared_ptr<AVBuffer> buffer;
276 (void)info.param->GetValue("buffer", buffer);
277 ReplyErrorCode(info.id, codec_->OnConfigureBuffer(buffer));
278 return;
279 }
280 case MsgWhat::CREATE_INPUT_SURFACE: {
281 sptr<Surface> surface = codec_->OnCreateInputSurface();
282 ParamSP reply = make_shared<ParamBundle>();
283 reply->SetValue<int32_t>("err", surface != nullptr ? AVCS_ERR_OK : AVCS_ERR_UNKNOWN);
284 reply->SetValue("surface", surface);
285 codec_->PostReply(info.id, reply);
286 return;
287 }
288 case MsgWhat::SET_INPUT_SURFACE: {
289 sptr<Surface> surface;
290 (void)info.param->GetValue("surface", surface);
291 ReplyErrorCode(info.id, codec_->OnSetInputSurface(surface));
292 return;
293 }
294 case MsgWhat::SET_OUTPUT_SURFACE: {
295 codec_->OnSetOutputSurface(info, outputMode_);
296 return;
297 }
298 case MsgWhat::START: {
299 OnStart(info);
300 return;
301 }
302 default: {
303 BaseState::OnMsgReceived(info);
304 }
305 }
306 }
307
OnSetCallBack(const MsgInfo & info)308 void HCodec::InitializedState::OnSetCallBack(const MsgInfo &info)
309 {
310 int32_t err;
311 shared_ptr<MediaCodecCallback> cb;
312 (void)info.param->GetValue("callback", cb);
313 if (cb == nullptr) {
314 err = AVCS_ERR_INVALID_VAL;
315 SLOGE("invalid param");
316 } else {
317 codec_->callback_ = cb;
318 err = AVCS_ERR_OK;
319 }
320 ReplyErrorCode(info.id, err);
321 }
322
OnConfigure(const MsgInfo & info)323 void HCodec::InitializedState::OnConfigure(const MsgInfo &info)
324 {
325 Format fmt;
326 (void)info.param->GetValue("format", fmt);
327 ReplyErrorCode(info.id, codec_->OnConfigure(fmt));
328 }
329
OnStart(const MsgInfo & info)330 void HCodec::InitializedState::OnStart(const MsgInfo &info)
331 {
332 if (!codec_->ReadyToStart()) {
333 SLOGE("callback not set or format is not configured, can't start");
334 ReplyErrorCode(info.id, AVCS_ERR_INVALID_OPERATION);
335 return;
336 }
337 SLOGI("set omx to idle");
338 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
339 if (ret == HDF_SUCCESS) {
340 codec_->ReplyToSyncMsgLater(info);
341 codec_->ChangeStateTo(codec_->startingState_);
342 } else {
343 SLOGE("set omx to idle failed, ret=%d", ret);
344 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
345 }
346 }
347
OnShutDown(const MsgInfo & info)348 void HCodec::InitializedState::OnShutDown(const MsgInfo &info)
349 {
350 if (info.type == MsgWhat::STOP) {
351 SLOGI("receive STOP");
352 } else {
353 SLOGI("receive RELEASE");
354 codec_->ChangeStateTo(codec_->uninitializedState_);
355 }
356 codec_->notifyCallerAfterShutdownComplete_ = false;
357 ReplyErrorCode(info.id, AVCS_ERR_OK);
358 }
359 /**************************** InitializedState End ******************************/
360
361
362 /**************************** StartingState Start ******************************/
OnStateEntered()363 void HCodec::StartingState::OnStateEntered()
364 {
365 hasError_ = false;
366
367 ParamSP msg = make_shared<ParamBundle>();
368 msg->SetValue("generation", codec_->stateGeneration_);
369
370 int32_t ret = AllocateBuffers();
371 if (ret != AVCS_ERR_OK) {
372 SLOGE("AllocateBuffers failed, back to init state");
373 hasError_ = true;
374 ReplyStartMsg(ret);
375 codec_->ChangeStateTo(codec_->initializedState_);
376 } else {
377 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
378 }
379 }
380
AllocateBuffers()381 int32_t HCodec::StartingState::AllocateBuffers()
382 {
383 int32_t ret = codec_->AllocateBuffersOnPort(OMX_DirInput);
384 if (ret != AVCS_ERR_OK) {
385 return ret;
386 }
387 ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
388 if (ret != AVCS_ERR_OK) {
389 return ret;
390 }
391 codec_->UpdateOwner();
392 return AVCS_ERR_OK;
393 }
394
OnMsgReceived(const MsgInfo & info)395 void HCodec::StartingState::OnMsgReceived(const MsgInfo &info)
396 {
397 switch (info.type) {
398 case MsgWhat::GET_BUFFER_FROM_SURFACE:
399 case MsgWhat::SET_PARAMETERS:
400 case MsgWhat::GET_INPUT_FORMAT:
401 case MsgWhat::GET_OUTPUT_FORMAT: {
402 codec_->DeferMessage(info);
403 return;
404 }
405 case MsgWhat::START:
406 case MsgWhat::FLUSH: {
407 ReplyErrorCode(info.id, AVCS_ERR_OK);
408 return;
409 }
410 case MsgWhat::CHECK_IF_STUCK: {
411 int32_t generation = 0;
412 if (info.param->GetValue("generation", generation) &&
413 generation == codec_->stateGeneration_) {
414 SLOGE("stucked, force state transition");
415 hasError_ = true;
416 ReplyStartMsg(AVCS_ERR_UNKNOWN);
417 codec_->ChangeStateTo(codec_->initializedState_);
418 }
419 return;
420 }
421 default: {
422 BaseState::OnMsgReceived(info);
423 }
424 }
425 }
426
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)427 void HCodec::StartingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
428 {
429 if (event != CODEC_EVENT_CMD_COMPLETE) {
430 return BaseState::OnCodecEvent(event, data1, data2);
431 }
432 if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
433 SLOGW("ignore event: data1=%u, data2=%u", data1, data2);
434 return;
435 }
436 if (data2 == (uint32_t)CODEC_STATE_IDLE) {
437 SLOGI("now idle, set omx to executing");
438 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
439 if (ret != HDF_SUCCESS) {
440 SLOGE("set omx to executing failed, ret=%d", ret);
441 hasError_ = true;
442 ReplyStartMsg(AVCS_ERR_UNKNOWN);
443 codec_->ChangeStateTo(codec_->initializedState_);
444 }
445 } else if (data2 == (uint32_t)CODEC_STATE_EXECUTING) {
446 SLOGI("omx now executing");
447 ReplyStartMsg(AVCS_ERR_OK);
448 codec_->SubmitAllBuffersOwnedByUs();
449 codec_->ChangeStateTo(codec_->runningState_);
450 }
451 }
452
OnShutDown(const MsgInfo & info)453 void HCodec::StartingState::OnShutDown(const MsgInfo &info)
454 {
455 codec_->DeferMessage(info);
456 }
457
ReplyStartMsg(int32_t errCode)458 void HCodec::StartingState::ReplyStartMsg(int32_t errCode)
459 {
460 MsgInfo msg {MsgWhat::START, 0, nullptr};
461 if (codec_->GetFirstSyncMsgToReply(msg)) {
462 SLOGI("start %s", (errCode == 0) ? "succ" : "failed");
463 ReplyErrorCode(msg.id, errCode);
464 } else {
465 SLOGE("there should be a start msg to reply");
466 }
467 }
468
OnStateExited()469 void HCodec::StartingState::OnStateExited()
470 {
471 if (hasError_) {
472 SLOGW("error occured, roll omx back to loaded and free allocated buffers");
473 if (codec_->RollOmxBackToLoaded()) {
474 codec_->ClearBufferPool(OMX_DirInput);
475 codec_->ClearBufferPool(OMX_DirOutput);
476 }
477 }
478 codec_->lastOwnerChangeTime_ = chrono::steady_clock::now();
479 ParamSP param = make_shared<ParamBundle>();
480 param->SetValue(KEY_LAST_OWNER_CHANGE_TIME, codec_->lastOwnerChangeTime_);
481 codec_->SendAsyncMsg(MsgWhat::PRINT_ALL_BUFFER_OWNER, param, THREE_SECONDS_IN_US);
482 BaseState::OnStateExited();
483 }
484
485 /**************************** StartingState End ******************************/
486
487 /**************************** RunningState Start ********************************/
OnStateEntered()488 void HCodec::RunningState::OnStateEntered()
489 {
490 codec_->ProcessDeferredMessages();
491 }
492
OnMsgReceived(const MsgInfo & info)493 void HCodec::RunningState::OnMsgReceived(const MsgInfo &info)
494 {
495 switch (info.type) {
496 case MsgWhat::START:
497 ReplyErrorCode(info.id, codec_->SubmitAllBuffersOwnedByUs());
498 break;
499 case MsgWhat::SET_PARAMETERS:
500 OnSetParameters(info);
501 break;
502 case MsgWhat::REQUEST_IDR_FRAME:
503 ReplyErrorCode(info.id, codec_->RequestIDRFrame());
504 break;
505 case MsgWhat::FLUSH:
506 SetThreadInteractiveQos(true);
507 OnFlush(info);
508 break;
509 case MsgWhat::GET_BUFFER_FROM_SURFACE:
510 codec_->OnGetBufferFromSurface(info.param);
511 break;
512 case MsgWhat::CHECK_IF_REPEAT:
513 codec_->RepeatIfNecessary(info.param);
514 break;
515 case MsgWhat::QUEUE_INPUT_BUFFER:
516 if (codec_->outPortHasChanged_) {
517 codec_->DynamicModeSubmitBuffer();
518 }
519 codec_->OnQueueInputBuffer(info, inputMode_);
520 break;
521 case MsgWhat::SUBMIT_DYNAMIC_IF_EOS:
522 if (codec_->inputPortEos_ && !codec_->outputPortEos_) {
523 codec_->DynamicModeSubmitBuffer();
524 codec_->DynamicModeSubmitIfEos();
525 }
526 break;
527 case MsgWhat::NOTIFY_EOS:
528 codec_->OnSignalEndOfInputStream(info);
529 break;
530 case MsgWhat::RENDER_OUTPUT_BUFFER:
531 codec_->OnRenderOutputBuffer(info, outputMode_);
532 break;
533 case MsgWhat::RELEASE_OUTPUT_BUFFER:
534 codec_->OnReleaseOutputBuffer(info, outputMode_);
535 break;
536 case MsgWhat::SET_OUTPUT_SURFACE:
537 codec_->OnSetOutputSurface(info, outputMode_);
538 return;
539 case MsgWhat::PRINT_ALL_BUFFER_OWNER:
540 codec_->OnPrintAllBufferOwner(info);
541 return;
542 case MsgWhat::CHECK_IF_STUCK:
543 return;
544 case MsgWhat::BUFFER_RECYCLE: {
545 OnBufferRecycle(info);
546 break;
547 }
548 case MsgWhat::SUSPEND:{
549 OnSuspend(info);
550 break;
551 }
552 case MsgWhat::RESUME:{
553 OnResume(info);
554 return;
555 }
556 default:
557 BaseState::OnMsgReceived(info);
558 break;
559 }
560 }
561
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)562 void HCodec::RunningState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
563 {
564 switch (event) {
565 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
566 if (data1 != OMX_DirOutput) {
567 SLOGI("ignore input port changed");
568 return;
569 }
570 if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
571 SLOGI("output port settings changed, disable out port");
572 codec_->UpdateOutPortFormat();
573 int32_t ret = codec_->compNode_->SendCommand(
574 CODEC_COMMAND_PORT_DISABLE, OMX_DirOutput, {});
575 if (ret == HDF_SUCCESS) {
576 codec_->EraseOutBuffersOwnedByUsOrSurface();
577 codec_->ChangeStateTo(codec_->outputPortChangedState_);
578 } else {
579 SLOGE("ask omx to disable out port failed");
580 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
581 }
582 } else if (data2 == OMX_IndexColorAspects) {
583 codec_->UpdateColorAspects();
584 } else {
585 SLOGI("unknown data2 0x%x for CODEC_EVENT_PORT_SETTINGS_CHANGED", data2);
586 }
587 return;
588 }
589 default: {
590 BaseState::OnCodecEvent(event, data1, data2);
591 }
592 }
593 }
594
OnShutDown(const MsgInfo & info)595 void HCodec::RunningState::OnShutDown(const MsgInfo &info)
596 {
597 SetThreadInteractiveQos(true);
598 codec_->isShutDownFromRunning_ = true;
599 codec_->notifyCallerAfterShutdownComplete_ = true;
600 codec_->keepComponentAllocated_ = (info.type == MsgWhat::STOP);
601 codec_->isBufferCirculating_ = false;
602 codec_->PrintAllBufferInfo();
603 SLOGI("receive %s msg, set omx to idle", info.type == MsgWhat::RELEASE ? "release" : "stop");
604 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
605 if (ret == HDF_SUCCESS) {
606 codec_->ReplyToSyncMsgLater(info);
607 codec_->ChangeStateTo(codec_->stoppingState_);
608 } else {
609 SLOGE("set omx to idle failed, ret=%d", ret);
610 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
611 }
612 }
613
OnFlush(const MsgInfo & info)614 void HCodec::RunningState::OnFlush(const MsgInfo &info)
615 {
616 codec_->isBufferCirculating_ = false;
617 SLOGD("begin to ask omx to flush");
618 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_FLUSH, OMX_ALL, {});
619 if (ret == HDF_SUCCESS) {
620 codec_->ReplyToSyncMsgLater(info);
621 codec_->ChangeStateTo(codec_->flushingState_);
622 } else {
623 SLOGI("ask omx to flush failed, ret=%d", ret);
624 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
625 }
626 }
627 /**************************** RunningState End ********************************/
628
629
630 /**************************** OutputPortChangedState Start ********************************/
OnStateEntered()631 void HCodec::OutputPortChangedState::OnStateEntered()
632 {
633 ParamSP msg = make_shared<ParamBundle>();
634 msg->SetValue("generation", codec_->stateGeneration_);
635 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
636 }
637
638 // LCOV_EXCL_START
OnMsgReceived(const MsgInfo & info)639 void HCodec::OutputPortChangedState::OnMsgReceived(const MsgInfo &info)
640 {
641 switch (info.type) {
642 case MsgWhat::FLUSH:
643 OnFlush(info);
644 return;
645 case MsgWhat::START:
646 codec_->DeferMessage(info);
647 return;
648 case MsgWhat::SET_PARAMETERS:
649 OnSetParameters(info);
650 return;
651 case MsgWhat::QUEUE_INPUT_BUFFER: {
652 codec_->OnQueueInputBuffer(info, inputMode_);
653 return;
654 }
655 case MsgWhat::NOTIFY_EOS: {
656 codec_->OnSignalEndOfInputStream(info);
657 return;
658 }
659 case MsgWhat::RENDER_OUTPUT_BUFFER: {
660 codec_->OnRenderOutputBuffer(info, outputMode_);
661 return;
662 }
663 case MsgWhat::RELEASE_OUTPUT_BUFFER: {
664 codec_->OnReleaseOutputBuffer(info, outputMode_);
665 return;
666 }
667 case MsgWhat::FORCE_SHUTDOWN: {
668 OnForceShutDown(info);
669 return;
670 }
671 case MsgWhat::CHECK_IF_STUCK: {
672 OnCheckIfStuck(info);
673 return;
674 }
675 case MsgWhat::SET_OUTPUT_SURFACE: {
676 codec_->OnSetOutputSurface(info, outputMode_);
677 return;
678 }
679 case MsgWhat::PRINT_ALL_BUFFER_OWNER: {
680 codec_->OnPrintAllBufferOwner(info);
681 return;
682 }
683 case MsgWhat::GET_BUFFER_FROM_SURFACE:
684 return;
685 default: {
686 BaseState::OnMsgReceived(info);
687 }
688 }
689 }
690 // LCOV_EXCL_STOP
691
OnShutDown(const MsgInfo & info)692 void HCodec::OutputPortChangedState::OnShutDown(const MsgInfo &info)
693 {
694 if (codec_->hasFatalError_) {
695 ParamSP stopMsg = make_shared<ParamBundle>();
696 stopMsg->SetValue("generation", codec_->stateGeneration_);
697 stopMsg->SetValue("isNeedNotifyCaller", true);
698 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
699 }
700 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER, true);
701 codec_->DeferMessage(info);
702 }
703
OnCheckIfStuck(const MsgInfo & info)704 void HCodec::OutputPortChangedState::OnCheckIfStuck(const MsgInfo &info)
705 {
706 int32_t generation = 0;
707 (void)info.param->GetValue("generation", generation);
708 if (generation != codec_->stateGeneration_) {
709 return;
710 }
711
712 if (std::none_of(codec_->outputBufferPool_.begin(), codec_->outputBufferPool_.end(), [](const BufferInfo& info) {
713 return info.owner == BufferOwner::OWNED_BY_OMX;
714 })) {
715 SLOGI("output buffers owned by omx has been returned");
716 return;
717 }
718 codec_->PrintAllBufferInfo();
719 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
720 SLOGE("stucked, need force shut down");
721 (void)codec_->ForceShutdown(codec_->stateGeneration_, false);
722 }
723
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)724 void HCodec::OutputPortChangedState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
725 {
726 switch (event) {
727 case CODEC_EVENT_CMD_COMPLETE: {
728 if (data1 == CODEC_COMMAND_PORT_DISABLE) {
729 if (data2 != OMX_DirOutput) {
730 SLOGW("ignore input port disable complete");
731 return;
732 }
733 SLOGI("output port is disabled");
734 HandleOutputPortDisabled();
735 } else if (data1 == CODEC_COMMAND_PORT_ENABLE) {
736 if (data2 != OMX_DirOutput) {
737 SLOGW("ignore input port enable complete");
738 return;
739 }
740 SLOGI("output port is enabled");
741 HandleOutputPortEnabled();
742 }
743 return;
744 }
745 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
746 if (data2 == OMX_IndexColorAspects) {
747 codec_->UpdateColorAspects();
748 }
749 break;
750 }
751 default: {
752 BaseState::OnCodecEvent(event, data1, data2);
753 }
754 }
755 }
756
HandleOutputPortDisabled()757 void HCodec::OutputPortChangedState::HandleOutputPortDisabled()
758 {
759 int32_t ret = AVCS_ERR_OK;
760 if (!codec_->outputBufferPool_.empty()) {
761 SLOGE("output port is disabled but not empty: %zu", codec_->outputBufferPool_.size());
762 ret = AVCS_ERR_UNKNOWN;
763 }
764
765 if (ret == AVCS_ERR_OK) {
766 SLOGI("enable out port");
767 if (codec_->isLpp_) {
768 codec_->callback_->OnOutputBufferUnbinded();
769 }
770 int32_t err = codec_->compNode_->SendCommand(CODEC_COMMAND_PORT_ENABLE, OMX_DirOutput, {});
771 if (err == HDF_SUCCESS) {
772 ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
773 codec_->UpdateOwner(OMX_DirOutput);
774 } else {
775 SLOGE("ask omx to enable out port failed, ret=%d", ret);
776 ret = AVCS_ERR_UNKNOWN;
777 }
778 }
779 if (ret != AVCS_ERR_OK) {
780 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
781 (void)codec_->ForceShutdown(codec_->stateGeneration_, false);
782 }
783 }
784
HandleOutputPortEnabled()785 void HCodec::OutputPortChangedState::HandleOutputPortEnabled()
786 {
787 if (codec_->isBufferCirculating_) {
788 codec_->SubmitOutBufToOmx();
789 }
790 codec_->outPortHasChanged_ = true;
791 SLOGI("output format changed: %s", codec_->outputFormat_->Stringify().c_str());
792 codec_->callback_->OnOutputFormatChanged(*(codec_->outputFormat_.get()));
793 codec_->ChangeStateTo(codec_->runningState_);
794 }
795
OnFlush(const MsgInfo & info)796 void HCodec::OutputPortChangedState::OnFlush(const MsgInfo &info)
797 {
798 if (codec_->hasFatalError_) {
799 ParamSP stopMsg = make_shared<ParamBundle>();
800 stopMsg->SetValue("generation", codec_->stateGeneration_);
801 stopMsg->SetValue("isNeedNotifyCaller", false);
802 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
803 }
804 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER, true);
805 codec_->DeferMessage(info);
806 }
807 /**************************** OutputPortChangedState End ********************************/
808
809
810 /**************************** FlushingState Start ********************************/
OnStateEntered()811 void HCodec::FlushingState::OnStateEntered()
812 {
813 flushCompleteFlag_[OMX_DirInput] = false;
814 flushCompleteFlag_[OMX_DirOutput] = false;
815 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
816 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
817 SLOGD("all buffer owned by user are now owned by us");
818
819 ParamSP msg = make_shared<ParamBundle>();
820 msg->SetValue("generation", codec_->stateGeneration_);
821 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
822 }
823
824 // LCOV_EXCL_START
OnMsgReceived(const MsgInfo & info)825 void HCodec::FlushingState::OnMsgReceived(const MsgInfo &info)
826 {
827 switch (info.type) {
828 case MsgWhat::GET_BUFFER_FROM_SURFACE: {
829 codec_->DeferMessage(info);
830 return;
831 }
832 case MsgWhat::FLUSH: {
833 ReplyErrorCode(info.id, AVCS_ERR_OK);
834 return;
835 }
836 case MsgWhat::FORCE_SHUTDOWN: {
837 OnForceShutDown(info);
838 return;
839 }
840 case MsgWhat::CHECK_IF_STUCK: {
841 OnCheckIfStuck(info);
842 return;
843 }
844 case MsgWhat::PRINT_ALL_BUFFER_OWNER: {
845 codec_->OnPrintAllBufferOwner(info);
846 return;
847 }
848 default: {
849 BaseState::OnMsgReceived(info);
850 }
851 }
852 }
853 // LCOV_EXCL_STOP
854
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)855 void HCodec::FlushingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
856 {
857 switch (event) {
858 case CODEC_EVENT_CMD_COMPLETE: {
859 auto ret = UpdateFlushStatusOnPorts(data1, data2);
860 if (ret == AVCS_ERR_OK && IsFlushCompleteOnAllPorts()) {
861 ChangeStateIfWeOwnAllBuffers();
862 }
863 return;
864 }
865 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
866 ParamSP portSettingChangedMsg = make_shared<ParamBundle>();
867 portSettingChangedMsg->SetValue("generation", codec_->stateGeneration_);
868 portSettingChangedMsg->SetValue("event", event);
869 portSettingChangedMsg->SetValue("data1", data1);
870 portSettingChangedMsg->SetValue("data2", data2);
871 codec_->DeferMessage(MsgInfo {MsgWhat::CODEC_EVENT, 0, portSettingChangedMsg});
872 SLOGI("deferring CODEC_EVENT_PORT_SETTINGS_CHANGED");
873 return;
874 }
875 default: {
876 BaseState::OnCodecEvent(event, data1, data2);
877 }
878 }
879 }
880
UpdateFlushStatusOnPorts(uint32_t data1,uint32_t data2)881 int32_t HCodec::FlushingState::UpdateFlushStatusOnPorts(uint32_t data1, uint32_t data2)
882 {
883 if (data2 == OMX_DirInput || data2 == OMX_DirOutput) {
884 if (flushCompleteFlag_[data2]) {
885 SLOGE("flush already completed for port (%u)", data2);
886 return AVCS_ERR_OK;
887 }
888 flushCompleteFlag_[data2] = true;
889 } else if (data2 == OMX_ALL) {
890 if (!IsFlushCompleteOnAllPorts()) {
891 SLOGW("received flush complete event for OMX_ALL, portFlushStatue=(%d/%d)",
892 flushCompleteFlag_[OMX_DirInput], flushCompleteFlag_[OMX_DirOutput]);
893 return AVCS_ERR_INVALID_VAL;
894 }
895 } else {
896 SLOGW("unexpected data2(%d) for CODEC_COMMAND_FLUSH complete", data2);
897 }
898 return AVCS_ERR_OK;
899 }
900
IsFlushCompleteOnAllPorts()901 bool HCodec::FlushingState::IsFlushCompleteOnAllPorts()
902 {
903 return flushCompleteFlag_[OMX_DirInput] && flushCompleteFlag_[OMX_DirOutput];
904 }
905
ChangeStateIfWeOwnAllBuffers()906 void HCodec::FlushingState::ChangeStateIfWeOwnAllBuffers()
907 {
908 if (!IsFlushCompleteOnAllPorts()) {
909 return;
910 }
911 int32_t ret = AVCS_ERR_OK;
912 if (!codec_->IsAllBufferOwnedByUsOrSurface()) {
913 ParamSP stopMsg = make_shared<ParamBundle>();
914 stopMsg->SetValue("generation", codec_->stateGeneration_);
915 stopMsg->SetValue("isNeedNotifyCaller", false);
916 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg);
917 SLOGE("Try to change state but buffer state error");
918 ret = AVCS_ERR_UNKNOWN;
919 }
920 MsgInfo msg {MsgWhat::FLUSH, 0, nullptr};
921 if (codec_->GetFirstSyncMsgToReply(msg)) {
922 ReplyErrorCode(msg.id, ret);
923 }
924 if (ret == AVCS_ERR_OK) {
925 codec_->inputPortEos_ = false;
926 codec_->outputPortEos_ = false;
927 codec_->gotFirstInput_ = false;
928 codec_->gotFirstOutput_ = false;
929 codec_->ChangeStateTo(codec_->runningState_);
930 }
931 }
932
OnShutDown(const MsgInfo & info)933 void HCodec::FlushingState::OnShutDown(const MsgInfo &info)
934 {
935 codec_->DeferMessage(info);
936 if (codec_->hasFatalError_) {
937 ParamSP stopMsg = make_shared<ParamBundle>();
938 stopMsg->SetValue("generation", codec_->stateGeneration_);
939 stopMsg->SetValue("isNeedNotifyCaller", true);
940 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
941 }
942 }
943 /**************************** FlushingState End ********************************/
944
945
946 /**************************** StoppingState Start ********************************/
OnStateEntered()947 void HCodec::StoppingState::OnStateEntered()
948 {
949 omxNodeInIdleState_ = false;
950 omxNodeIsChangingToLoadedState_ = false;
951 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
952 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
953 SLOGD("all buffer owned by user are now owned by us");
954
955 ParamSP msg = make_shared<ParamBundle>();
956 msg->SetValue("generation", codec_->stateGeneration_);
957 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
958 }
959
OnMsgReceived(const MsgInfo & info)960 void HCodec::StoppingState::OnMsgReceived(const MsgInfo &info)
961 {
962 switch (info.type) {
963 case MsgWhat::CHECK_IF_STUCK: {
964 int32_t generation = 0;
965 (void)info.param->GetValue("generation", generation);
966 if (generation == codec_->stateGeneration_) {
967 SLOGE("stucked, force state transition");
968 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_OMX);
969 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_OMX);
970 SLOGI("all buffer owned by omx are now owned by us");
971 ChangeOmxNodeToLoadedState(true);
972 codec_->ChangeStateTo(codec_->initializedState_);
973 }
974 return;
975 }
976 default: {
977 BaseState::OnMsgReceived(info);
978 }
979 }
980 }
981
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)982 void HCodec::StoppingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
983 {
984 switch (event) {
985 case CODEC_EVENT_CMD_COMPLETE: {
986 if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
987 SLOGW("unexpected CODEC_EVENT_CMD_COMPLETE: %u %u", data1, data2);
988 return;
989 }
990 if (data2 == (uint32_t)CODEC_STATE_IDLE) {
991 SLOGI("omx now idle");
992 omxNodeInIdleState_ = true;
993 ChangeStateIfWeOwnAllBuffers();
994 } else if (data2 == (uint32_t)CODEC_STATE_LOADED) {
995 SLOGI("omx now loaded");
996 codec_->ChangeStateTo(codec_->initializedState_);
997 }
998 return;
999 }
1000 default: {
1001 BaseState::OnCodecEvent(event, data1, data2);
1002 }
1003 }
1004 }
1005
ChangeStateIfWeOwnAllBuffers()1006 void HCodec::StoppingState::ChangeStateIfWeOwnAllBuffers()
1007 {
1008 if (omxNodeInIdleState_ && codec_->IsAllBufferOwnedByUsOrSurface()) {
1009 ChangeOmxNodeToLoadedState(false);
1010 } else {
1011 SLOGD("cannot change state yet");
1012 }
1013 }
1014
ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)1015 void HCodec::StoppingState::ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)
1016 {
1017 if (!omxNodeIsChangingToLoadedState_) {
1018 SLOGI("set omx to loaded");
1019 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
1020 if (ret == HDF_SUCCESS) {
1021 omxNodeIsChangingToLoadedState_ = true;
1022 } else {
1023 SLOGE("set omx to loaded failed, ret=%d", ret);
1024 }
1025 }
1026 if (forceToFreeBuffer || omxNodeIsChangingToLoadedState_) {
1027 codec_->ClearBufferPool(OMX_DirInput);
1028 codec_->ClearBufferPool(OMX_DirOutput);
1029 return;
1030 }
1031 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
1032 }
1033
OnShutDown(const MsgInfo & info)1034 void HCodec::StoppingState::OnShutDown(const MsgInfo &info)
1035 {
1036 codec_->DeferMessage(info);
1037 }
1038
1039 /**************************** StoppingState End ********************************/
1040 }