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 "utils/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 } else {
110 SLOGW("ignore event %d, data1 = %u, data2 = %u", event, data1, data2);
111 }
112 }
113
OnGetFormat(const MsgInfo & info)114 void HCodec::BaseState::OnGetFormat(const MsgInfo &info)
115 {
116 shared_ptr<Format> fmt = (info.type == MsgWhat::GET_INPUT_FORMAT) ?
117 codec_->inputFormat_ : codec_->outputFormat_;
118 ParamSP reply = make_shared<ParamBundle>();
119 if (fmt) {
120 reply->SetValue<int32_t>("err", AVCS_ERR_OK);
121 reply->SetValue("format", *fmt);
122 codec_->PostReply(info.id, reply);
123 } else {
124 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
125 }
126 }
127
OnSetParameters(const MsgInfo & info)128 void HCodec::BaseState::OnSetParameters(const MsgInfo &info)
129 {
130 Format params;
131 (void)info.param->GetValue("params", params);
132 ReplyErrorCode(info.id, codec_->OnSetParameters(params));
133 }
134
OnCheckIfStuck(const MsgInfo & info)135 void HCodec::BaseState::OnCheckIfStuck(const MsgInfo &info)
136 {
137 int32_t generation = 0;
138 (void)info.param->GetValue("generation", generation);
139 if (generation == codec_->stateGeneration_) {
140 SLOGE("stucked");
141 codec_->PrintAllBufferInfo();
142 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
143 }
144 }
145
OnForceShutDown(const MsgInfo & info)146 void HCodec::BaseState::OnForceShutDown(const MsgInfo &info)
147 {
148 int32_t generation = 0;
149 bool isNeedNotifyCaller;
150 (void)info.param->GetValue("generation", generation);
151 (void)info.param->GetValue("isNeedNotifyCaller", isNeedNotifyCaller);
152 codec_->ForceShutdown(generation, isNeedNotifyCaller);
153 }
154 /**************************** BaseState End ******************************/
155
156
157 /**************************** UninitializedState start ****************************/
OnStateEntered()158 void HCodec::UninitializedState::OnStateEntered()
159 {
160 codec_->gotFirstInput_ = false;
161 codec_->gotFirstOutput_ = false;
162 codec_->inTotalCnt_ = 0;
163 codec_->outRecord_.totalCnt = 0;
164 codec_->outRecord_.totalCostUs = 0;
165 codec_->inTimeMap_.clear();
166 codec_->lastInPts_ = -1;
167 codec_->lastOutPts_ = -1;
168 codec_->inputWaitFenceCostUs_ = 0;
169 codec_->outputWaitFenceCostUs_ = 0;
170 codec_->inputDiscardCnt_ = 0;
171 codec_->outputDiscardCnt_ = 0;
172 codec_->circulateHasStopped_ = false;
173 codec_->OnEnterUninitializedState();
174 codec_->ReleaseComponent();
175 }
176
OnMsgReceived(const MsgInfo & info)177 void HCodec::UninitializedState::OnMsgReceived(const MsgInfo &info)
178 {
179 switch (info.type) {
180 case MsgWhat::INIT: {
181 int32_t err = codec_->OnAllocateComponent();
182 ReplyErrorCode(info.id, err);
183 if (err == AVCS_ERR_OK) {
184 codec_->ChangeStateTo(codec_->initializedState_);
185 }
186 break;
187 }
188 default: {
189 BaseState::OnMsgReceived(info);
190 }
191 }
192 }
193
OnShutDown(const MsgInfo & info)194 void HCodec::UninitializedState::OnShutDown(const MsgInfo &info)
195 {
196 ReplyErrorCode(info.id, AVCS_ERR_OK);
197 }
198
199 /**************************** UninitializedState End ******************************/
200
201 /**************************** InitializedState Start **********************************/
OnStateEntered()202 void HCodec::InitializedState::OnStateEntered()
203 {
204 codec_->inputPortEos_ = false;
205 codec_->outputPortEos_ = false;
206 codec_->outPortHasChanged_ = false;
207 codec_->inputFormat_.reset();
208 codec_->outputFormat_.reset();
209
210 ProcessShutDownFromRunning();
211 codec_->notifyCallerAfterShutdownComplete_ = false;
212 codec_->ProcessDeferredMessages();
213 }
214
ProcessShutDownFromRunning()215 void HCodec::InitializedState::ProcessShutDownFromRunning()
216 {
217 if (!codec_->isShutDownFromRunning_) {
218 return;
219 }
220 SLOGI("we are doing shutdown from running/portchange/flush -> stopping -> initialized");
221 bool keepComponentAllocated = codec_->keepComponentAllocated_;
222 if (keepComponentAllocated) {
223 if (codec_->configFormat_ == nullptr) {
224 SLOGW("stored configuration is null");
225 } else {
226 Format copyOfCurConfig(*codec_->configFormat_);
227 codec_->OnConfigure(copyOfCurConfig);
228 }
229 } else {
230 codec_->ChangeStateTo(codec_->uninitializedState_);
231 }
232 if (codec_->notifyCallerAfterShutdownComplete_) {
233 SLOGI("reply to %s msg", keepComponentAllocated ? "stop" : "release");
234 MsgInfo msg { keepComponentAllocated ? MsgWhat::STOP : MsgWhat::RELEASE, 0, nullptr };
235 if (codec_->GetFirstSyncMsgToReply(msg)) {
236 ReplyErrorCode(msg.id, AVCS_ERR_OK);
237 }
238 codec_->notifyCallerAfterShutdownComplete_ = false;
239 }
240 codec_->isShutDownFromRunning_ = false;
241 codec_->keepComponentAllocated_ = false;
242 }
243
OnMsgReceived(const MsgInfo & info)244 void HCodec::InitializedState::OnMsgReceived(const MsgInfo &info)
245 {
246 switch (info.type) {
247 case MsgWhat::SET_CALLBACK: {
248 OnSetCallBack(info);
249 return;
250 }
251 case MsgWhat::CONFIGURE: {
252 OnConfigure(info);
253 return;
254 }
255 case MsgWhat::CONFIGURE_BUFFER: {
256 std::shared_ptr<AVBuffer> buffer;
257 (void)info.param->GetValue("buffer", buffer);
258 ReplyErrorCode(info.id, codec_->OnConfigureBuffer(buffer));
259 return;
260 }
261 case MsgWhat::CREATE_INPUT_SURFACE: {
262 sptr<Surface> surface = codec_->OnCreateInputSurface();
263 ParamSP reply = make_shared<ParamBundle>();
264 reply->SetValue<int32_t>("err", surface != nullptr ? AVCS_ERR_OK : AVCS_ERR_UNKNOWN);
265 reply->SetValue("surface", surface);
266 codec_->PostReply(info.id, reply);
267 return;
268 }
269 case MsgWhat::SET_INPUT_SURFACE: {
270 sptr<Surface> surface;
271 (void)info.param->GetValue("surface", surface);
272 ReplyErrorCode(info.id, codec_->OnSetInputSurface(surface));
273 return;
274 }
275 case MsgWhat::SET_OUTPUT_SURFACE: {
276 codec_->OnSetOutputSurface(info, outputMode_);
277 return;
278 }
279 case MsgWhat::START: {
280 OnStart(info);
281 return;
282 }
283 default: {
284 BaseState::OnMsgReceived(info);
285 }
286 }
287 }
288
OnSetCallBack(const MsgInfo & info)289 void HCodec::InitializedState::OnSetCallBack(const MsgInfo &info)
290 {
291 int32_t err;
292 shared_ptr<MediaCodecCallback> cb;
293 (void)info.param->GetValue("callback", cb);
294 if (cb == nullptr) {
295 err = AVCS_ERR_INVALID_VAL;
296 SLOGE("invalid param");
297 } else {
298 codec_->callback_ = cb;
299 err = AVCS_ERR_OK;
300 }
301 ReplyErrorCode(info.id, err);
302 }
303
OnConfigure(const MsgInfo & info)304 void HCodec::InitializedState::OnConfigure(const MsgInfo &info)
305 {
306 Format fmt;
307 (void)info.param->GetValue("format", fmt);
308 ReplyErrorCode(info.id, codec_->OnConfigure(fmt));
309 }
310
OnStart(const MsgInfo & info)311 void HCodec::InitializedState::OnStart(const MsgInfo &info)
312 {
313 if (!codec_->ReadyToStart()) {
314 SLOGE("callback not set or format is not configured, can't start");
315 ReplyErrorCode(info.id, AVCS_ERR_INVALID_OPERATION);
316 return;
317 }
318 SLOGI("begin to set omx to idle");
319 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
320 if (ret == HDF_SUCCESS) {
321 codec_->ReplyToSyncMsgLater(info);
322 codec_->ChangeStateTo(codec_->startingState_);
323 } else {
324 SLOGE("set omx to idle failed, ret=%d", ret);
325 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
326 }
327 }
328
OnShutDown(const MsgInfo & info)329 void HCodec::InitializedState::OnShutDown(const MsgInfo &info)
330 {
331 if (info.type == MsgWhat::STOP) {
332 SLOGI("receive STOP");
333 } else {
334 SLOGI("receive RELEASE");
335 codec_->ChangeStateTo(codec_->uninitializedState_);
336 }
337 codec_->notifyCallerAfterShutdownComplete_ = false;
338 ReplyErrorCode(info.id, AVCS_ERR_OK);
339 }
340 /**************************** InitializedState End ******************************/
341
342
343 /**************************** StartingState Start ******************************/
OnStateEntered()344 void HCodec::StartingState::OnStateEntered()
345 {
346 hasError_ = false;
347
348 ParamSP msg = make_shared<ParamBundle>();
349 msg->SetValue("generation", codec_->stateGeneration_);
350
351 int32_t ret = AllocateBuffers();
352 if (ret != AVCS_ERR_OK) {
353 SLOGE("AllocateBuffers failed, back to init state");
354 hasError_ = true;
355 ReplyStartMsg(ret);
356 codec_->ChangeStateTo(codec_->initializedState_);
357 } else {
358 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
359 }
360 }
361
AllocateBuffers()362 int32_t HCodec::StartingState::AllocateBuffers()
363 {
364 int32_t ret = codec_->AllocateBuffersOnPort(OMX_DirInput);
365 if (ret != AVCS_ERR_OK) {
366 return ret;
367 }
368 ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
369 if (ret != AVCS_ERR_OK) {
370 return ret;
371 }
372 codec_->UpdateOwner();
373 return AVCS_ERR_OK;
374 }
375
OnMsgReceived(const MsgInfo & info)376 void HCodec::StartingState::OnMsgReceived(const MsgInfo &info)
377 {
378 switch (info.type) {
379 case MsgWhat::GET_BUFFER_FROM_SURFACE:
380 case MsgWhat::SET_PARAMETERS:
381 case MsgWhat::GET_INPUT_FORMAT:
382 case MsgWhat::GET_OUTPUT_FORMAT: {
383 codec_->DeferMessage(info);
384 return;
385 }
386 case MsgWhat::START:
387 case MsgWhat::FLUSH: {
388 ReplyErrorCode(info.id, AVCS_ERR_OK);
389 return;
390 }
391 case MsgWhat::CHECK_IF_STUCK: {
392 int32_t generation = 0;
393 if (info.param->GetValue("generation", generation) &&
394 generation == codec_->stateGeneration_) {
395 SLOGE("stucked, force state transition");
396 hasError_ = true;
397 ReplyStartMsg(AVCS_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 HCodec::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 != (uint32_t)CODEC_COMMAND_STATE_SET) {
414 SLOGW("ignore event: data1=%u, data2=%u", data1, data2);
415 return;
416 }
417 if (data2 == (uint32_t)CODEC_STATE_IDLE) {
418 SLOGI("omx now idle, begin to set omx 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=%d", ret);
422 hasError_ = true;
423 ReplyStartMsg(AVCS_ERR_UNKNOWN);
424 codec_->ChangeStateTo(codec_->initializedState_);
425 }
426 } else if (data2 == (uint32_t)CODEC_STATE_EXECUTING) {
427 SLOGI("omx now executing");
428 ReplyStartMsg(AVCS_ERR_OK);
429 codec_->SubmitAllBuffersOwnedByUs();
430 codec_->ChangeStateTo(codec_->runningState_);
431 }
432 }
433
OnShutDown(const MsgInfo & info)434 void HCodec::StartingState::OnShutDown(const MsgInfo &info)
435 {
436 codec_->DeferMessage(info);
437 }
438
ReplyStartMsg(int32_t errCode)439 void HCodec::StartingState::ReplyStartMsg(int32_t errCode)
440 {
441 MsgInfo msg {MsgWhat::START, 0, nullptr};
442 if (codec_->GetFirstSyncMsgToReply(msg)) {
443 SLOGI("start %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 HCodec::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 codec_->lastOwnerChangeTime_ = chrono::steady_clock::now();
460 ParamSP param = make_shared<ParamBundle>();
461 param->SetValue(KEY_LAST_OWNER_CHANGE_TIME, codec_->lastOwnerChangeTime_);
462 codec_->SendAsyncMsg(MsgWhat::PRINT_ALL_BUFFER_OWNER, param, THREE_SECONDS_IN_US);
463 BaseState::OnStateExited();
464 }
465
466 /**************************** StartingState End ******************************/
467
468 /**************************** RunningState Start ********************************/
OnStateEntered()469 void HCodec::RunningState::OnStateEntered()
470 {
471 codec_->ProcessDeferredMessages();
472 }
473
OnMsgReceived(const MsgInfo & info)474 void HCodec::RunningState::OnMsgReceived(const MsgInfo &info)
475 {
476 switch (info.type) {
477 case MsgWhat::START:
478 ReplyErrorCode(info.id, codec_->SubmitAllBuffersOwnedByUs());
479 break;
480 case MsgWhat::SET_PARAMETERS:
481 OnSetParameters(info);
482 break;
483 case MsgWhat::REQUEST_IDR_FRAME:
484 ReplyErrorCode(info.id, codec_->RequestIDRFrame());
485 break;
486 case MsgWhat::FLUSH:
487 OnFlush(info);
488 break;
489 case MsgWhat::GET_BUFFER_FROM_SURFACE:
490 codec_->OnGetBufferFromSurface(info.param);
491 break;
492 case MsgWhat::CHECK_IF_REPEAT:
493 codec_->RepeatIfNecessary(info.param);
494 break;
495 case MsgWhat::QUEUE_INPUT_BUFFER:
496 if (codec_->outPortHasChanged_) {
497 codec_->DynamicModeSubmitBuffer();
498 }
499 codec_->OnQueueInputBuffer(info, inputMode_);
500 break;
501 case MsgWhat::SUBMIT_DYNAMIC_IF_EOS:
502 if (codec_->inputPortEos_ && !codec_->outputPortEos_) {
503 codec_->DynamicModeSubmitBuffer();
504 codec_->DynamicModeSubmitIfEos();
505 }
506 break;
507 case MsgWhat::NOTIFY_EOS:
508 codec_->OnSignalEndOfInputStream(info);
509 break;
510 case MsgWhat::RENDER_OUTPUT_BUFFER:
511 codec_->OnRenderOutputBuffer(info, outputMode_);
512 break;
513 case MsgWhat::RELEASE_OUTPUT_BUFFER:
514 codec_->OnReleaseOutputBuffer(info, outputMode_);
515 break;
516 case MsgWhat::SET_OUTPUT_SURFACE:
517 codec_->OnSetOutputSurface(info, outputMode_);
518 return;
519 case MsgWhat::PRINT_ALL_BUFFER_OWNER:
520 codec_->OnPrintAllBufferOwner(info);
521 return;
522 case MsgWhat::CHECK_IF_STUCK:
523 return;
524 case MsgWhat::FREEZE: {
525 OnFreeze(info);
526 break;
527 }
528 default:
529 BaseState::OnMsgReceived(info);
530 break;
531 }
532 }
533
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)534 void HCodec::RunningState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
535 {
536 switch (event) {
537 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
538 if (data1 != OMX_DirOutput) {
539 SLOGI("ignore input port changed");
540 return;
541 }
542 if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
543 SLOGI("output port settings changed, begin to ask omx to disable out port");
544 codec_->UpdateOutPortFormat();
545 int32_t ret = codec_->compNode_->SendCommand(
546 CODEC_COMMAND_PORT_DISABLE, OMX_DirOutput, {});
547 if (ret == HDF_SUCCESS) {
548 codec_->EraseOutBuffersOwnedByUsOrSurface();
549 codec_->ChangeStateTo(codec_->outputPortChangedState_);
550 } else {
551 SLOGE("ask omx to disable out port failed");
552 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
553 }
554 } else if (data2 == OMX_IndexColorAspects) {
555 codec_->UpdateColorAspects();
556 } else {
557 SLOGI("unknown data2 0x%x for CODEC_EVENT_PORT_SETTINGS_CHANGED", data2);
558 }
559 return;
560 }
561 default: {
562 BaseState::OnCodecEvent(event, data1, data2);
563 }
564 }
565 }
566
OnShutDown(const MsgInfo & info)567 void HCodec::RunningState::OnShutDown(const MsgInfo &info)
568 {
569 codec_->isShutDownFromRunning_ = true;
570 codec_->notifyCallerAfterShutdownComplete_ = true;
571 codec_->keepComponentAllocated_ = (info.type == MsgWhat::STOP);
572 codec_->isBufferCirculating_ = false;
573 codec_->PrintAllBufferInfo();
574 SLOGI("receive %s msg, begin to set omx to idle", info.type == MsgWhat::RELEASE ? "release" : "stop");
575 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
576 if (ret == HDF_SUCCESS) {
577 codec_->ReplyToSyncMsgLater(info);
578 codec_->ChangeStateTo(codec_->stoppingState_);
579 } else {
580 SLOGE("set omx to idle failed, ret=%d", ret);
581 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
582 }
583 }
584
OnFlush(const MsgInfo & info)585 void HCodec::RunningState::OnFlush(const MsgInfo &info)
586 {
587 codec_->isBufferCirculating_ = false;
588 SLOGD("begin to ask omx to flush");
589 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_FLUSH, OMX_ALL, {});
590 if (ret == HDF_SUCCESS) {
591 codec_->ReplyToSyncMsgLater(info);
592 codec_->ChangeStateTo(codec_->flushingState_);
593 } else {
594 SLOGI("ask omx to flush failed, ret=%d", ret);
595 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
596 }
597 }
598 /**************************** RunningState End ********************************/
599
600
601 /**************************** OutputPortChangedState Start ********************************/
OnStateEntered()602 void HCodec::OutputPortChangedState::OnStateEntered()
603 {
604 ParamSP msg = make_shared<ParamBundle>();
605 msg->SetValue("generation", codec_->stateGeneration_);
606 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
607 }
608
OnMsgReceived(const MsgInfo & info)609 void HCodec::OutputPortChangedState::OnMsgReceived(const MsgInfo &info)
610 {
611 switch (info.type) {
612 case MsgWhat::FLUSH:
613 OnFlush(info);
614 return;
615 case MsgWhat::START:
616 codec_->DeferMessage(info);
617 return;
618 case MsgWhat::SET_PARAMETERS:
619 OnSetParameters(info);
620 return;
621 case MsgWhat::QUEUE_INPUT_BUFFER: {
622 codec_->OnQueueInputBuffer(info, inputMode_);
623 return;
624 }
625 case MsgWhat::NOTIFY_EOS: {
626 codec_->OnSignalEndOfInputStream(info);
627 return;
628 }
629 case MsgWhat::RENDER_OUTPUT_BUFFER: {
630 codec_->OnRenderOutputBuffer(info, outputMode_);
631 return;
632 }
633 case MsgWhat::RELEASE_OUTPUT_BUFFER: {
634 codec_->OnReleaseOutputBuffer(info, outputMode_);
635 return;
636 }
637 case MsgWhat::FORCE_SHUTDOWN: {
638 OnForceShutDown(info);
639 return;
640 }
641 case MsgWhat::CHECK_IF_STUCK: {
642 OnCheckIfStuck(info);
643 return;
644 }
645 case MsgWhat::SET_OUTPUT_SURFACE: {
646 codec_->OnSetOutputSurface(info, outputMode_);
647 return;
648 }
649 case MsgWhat::PRINT_ALL_BUFFER_OWNER: {
650 codec_->OnPrintAllBufferOwner(info);
651 return;
652 }
653 case MsgWhat::GET_BUFFER_FROM_SURFACE:
654 return;
655 default: {
656 BaseState::OnMsgReceived(info);
657 }
658 }
659 }
660
OnShutDown(const MsgInfo & info)661 void HCodec::OutputPortChangedState::OnShutDown(const MsgInfo &info)
662 {
663 if (codec_->hasFatalError_) {
664 ParamSP stopMsg = make_shared<ParamBundle>();
665 stopMsg->SetValue("generation", codec_->stateGeneration_);
666 stopMsg->SetValue("isNeedNotifyCaller", true);
667 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
668 }
669 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER, true);
670 codec_->DeferMessage(info);
671 }
672
OnCheckIfStuck(const MsgInfo & info)673 void HCodec::OutputPortChangedState::OnCheckIfStuck(const MsgInfo &info)
674 {
675 int32_t generation = 0;
676 (void)info.param->GetValue("generation", generation);
677 if (generation != codec_->stateGeneration_) {
678 return;
679 }
680
681 if (std::none_of(codec_->outputBufferPool_.begin(), codec_->outputBufferPool_.end(), [](const BufferInfo& info) {
682 return info.owner == BufferOwner::OWNED_BY_OMX;
683 })) {
684 SLOGI("output buffers owned by omx has been returned");
685 return;
686 }
687 codec_->PrintAllBufferInfo();
688 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
689 SLOGE("stucked, need force shut down");
690 (void)codec_->ForceShutdown(codec_->stateGeneration_, false);
691 }
692
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)693 void HCodec::OutputPortChangedState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
694 {
695 switch (event) {
696 case CODEC_EVENT_CMD_COMPLETE: {
697 if (data1 == CODEC_COMMAND_PORT_DISABLE) {
698 if (data2 != OMX_DirOutput) {
699 SLOGW("ignore input port disable complete");
700 return;
701 }
702 SLOGI("output port is disabled");
703 HandleOutputPortDisabled();
704 } else if (data1 == CODEC_COMMAND_PORT_ENABLE) {
705 if (data2 != OMX_DirOutput) {
706 SLOGW("ignore input port enable complete");
707 return;
708 }
709 SLOGI("output port is enabled");
710 HandleOutputPortEnabled();
711 }
712 return;
713 }
714 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
715 if (data2 == OMX_IndexColorAspects) {
716 codec_->UpdateColorAspects();
717 }
718 break;
719 }
720 default: {
721 BaseState::OnCodecEvent(event, data1, data2);
722 }
723 }
724 }
725
HandleOutputPortDisabled()726 void HCodec::OutputPortChangedState::HandleOutputPortDisabled()
727 {
728 int32_t ret = AVCS_ERR_OK;
729 if (!codec_->outputBufferPool_.empty()) {
730 SLOGE("output port is disabled but not empty: %zu", codec_->outputBufferPool_.size());
731 ret = AVCS_ERR_UNKNOWN;
732 }
733
734 if (ret == AVCS_ERR_OK) {
735 SLOGI("begin to ask omx to enable out port");
736 int32_t err = codec_->compNode_->SendCommand(CODEC_COMMAND_PORT_ENABLE, OMX_DirOutput, {});
737 if (err == HDF_SUCCESS) {
738 ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
739 codec_->UpdateOwner(false);
740 } else {
741 SLOGE("ask omx to enable out port failed, ret=%d", ret);
742 ret = AVCS_ERR_UNKNOWN;
743 }
744 }
745 if (ret != AVCS_ERR_OK) {
746 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
747 (void)codec_->ForceShutdown(codec_->stateGeneration_, false);
748 }
749 }
750
HandleOutputPortEnabled()751 void HCodec::OutputPortChangedState::HandleOutputPortEnabled()
752 {
753 if (codec_->isBufferCirculating_) {
754 codec_->SubmitOutputBuffersToOmxNode();
755 }
756 codec_->outPortHasChanged_ = true;
757 SLOGI("output format changed: %s", codec_->outputFormat_->Stringify().c_str());
758 codec_->callback_->OnOutputFormatChanged(*(codec_->outputFormat_.get()));
759 codec_->ChangeStateTo(codec_->runningState_);
760 }
761
OnFlush(const MsgInfo & info)762 void HCodec::OutputPortChangedState::OnFlush(const MsgInfo &info)
763 {
764 if (codec_->hasFatalError_) {
765 ParamSP stopMsg = make_shared<ParamBundle>();
766 stopMsg->SetValue("generation", codec_->stateGeneration_);
767 stopMsg->SetValue("isNeedNotifyCaller", false);
768 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
769 }
770 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER, true);
771 codec_->DeferMessage(info);
772 }
773 /**************************** OutputPortChangedState End ********************************/
774
775
776 /**************************** FlushingState Start ********************************/
OnStateEntered()777 void HCodec::FlushingState::OnStateEntered()
778 {
779 flushCompleteFlag_[OMX_DirInput] = false;
780 flushCompleteFlag_[OMX_DirOutput] = false;
781 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
782 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
783 SLOGD("all buffer owned by user are now owned by us");
784
785 ParamSP msg = make_shared<ParamBundle>();
786 msg->SetValue("generation", codec_->stateGeneration_);
787 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
788 }
789
OnMsgReceived(const MsgInfo & info)790 void HCodec::FlushingState::OnMsgReceived(const MsgInfo &info)
791 {
792 switch (info.type) {
793 case MsgWhat::GET_BUFFER_FROM_SURFACE: {
794 codec_->DeferMessage(info);
795 return;
796 }
797 case MsgWhat::FLUSH: {
798 ReplyErrorCode(info.id, AVCS_ERR_OK);
799 return;
800 }
801 case MsgWhat::FORCE_SHUTDOWN: {
802 OnForceShutDown(info);
803 return;
804 }
805 case MsgWhat::CHECK_IF_STUCK: {
806 OnCheckIfStuck(info);
807 return;
808 }
809 case MsgWhat::PRINT_ALL_BUFFER_OWNER: {
810 codec_->OnPrintAllBufferOwner(info);
811 return;
812 }
813 default: {
814 BaseState::OnMsgReceived(info);
815 }
816 }
817 }
818
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)819 void HCodec::FlushingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
820 {
821 switch (event) {
822 case CODEC_EVENT_CMD_COMPLETE: {
823 auto ret = UpdateFlushStatusOnPorts(data1, data2);
824 if (ret == AVCS_ERR_OK && IsFlushCompleteOnAllPorts()) {
825 ChangeStateIfWeOwnAllBuffers();
826 }
827 return;
828 }
829 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
830 ParamSP portSettingChangedMsg = make_shared<ParamBundle>();
831 portSettingChangedMsg->SetValue("generation", codec_->stateGeneration_);
832 portSettingChangedMsg->SetValue("event", event);
833 portSettingChangedMsg->SetValue("data1", data1);
834 portSettingChangedMsg->SetValue("data2", data2);
835 codec_->DeferMessage(MsgInfo {MsgWhat::CODEC_EVENT, 0, portSettingChangedMsg});
836 SLOGI("deferring CODEC_EVENT_PORT_SETTINGS_CHANGED");
837 return;
838 }
839 default: {
840 BaseState::OnCodecEvent(event, data1, data2);
841 }
842 }
843 }
844
UpdateFlushStatusOnPorts(uint32_t data1,uint32_t data2)845 int32_t HCodec::FlushingState::UpdateFlushStatusOnPorts(uint32_t data1, uint32_t data2)
846 {
847 if (data2 == OMX_DirInput || data2 == OMX_DirOutput) {
848 if (flushCompleteFlag_[data2]) {
849 SLOGE("flush already completed for port (%u)", data2);
850 return AVCS_ERR_OK;
851 }
852 flushCompleteFlag_[data2] = true;
853 } else if (data2 == OMX_ALL) {
854 if (!IsFlushCompleteOnAllPorts()) {
855 SLOGW("received flush complete event for OMX_ALL, portFlushStatue=(%d/%d)",
856 flushCompleteFlag_[OMX_DirInput], flushCompleteFlag_[OMX_DirOutput]);
857 return AVCS_ERR_INVALID_VAL;
858 }
859 } else {
860 SLOGW("unexpected data2(%d) for CODEC_COMMAND_FLUSH complete", data2);
861 }
862 return AVCS_ERR_OK;
863 }
864
IsFlushCompleteOnAllPorts()865 bool HCodec::FlushingState::IsFlushCompleteOnAllPorts()
866 {
867 return flushCompleteFlag_[OMX_DirInput] && flushCompleteFlag_[OMX_DirOutput];
868 }
869
ChangeStateIfWeOwnAllBuffers()870 void HCodec::FlushingState::ChangeStateIfWeOwnAllBuffers()
871 {
872 if (!IsFlushCompleteOnAllPorts()) {
873 return;
874 }
875 int32_t ret = AVCS_ERR_OK;
876 if (!codec_->IsAllBufferOwnedByUsOrSurface()) {
877 ret = AVCS_ERR_UNKNOWN;
878 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, nullptr);
879 }
880 MsgInfo msg {MsgWhat::FLUSH, 0, nullptr};
881 if (codec_->GetFirstSyncMsgToReply(msg)) {
882 ReplyErrorCode(msg.id, ret);
883 }
884 if (ret == AVCS_ERR_OK) {
885 codec_->inputPortEos_ = false;
886 codec_->outputPortEos_ = false;
887 codec_->gotFirstInput_ = false;
888 codec_->gotFirstOutput_ = false;
889 codec_->ChangeStateTo(codec_->runningState_);
890 }
891 }
892
OnShutDown(const MsgInfo & info)893 void HCodec::FlushingState::OnShutDown(const MsgInfo &info)
894 {
895 codec_->DeferMessage(info);
896 if (codec_->hasFatalError_) {
897 ParamSP stopMsg = make_shared<ParamBundle>();
898 stopMsg->SetValue("generation", codec_->stateGeneration_);
899 stopMsg->SetValue("isNeedNotifyCaller", true);
900 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
901 }
902 }
903 /**************************** FlushingState End ********************************/
904
905
906 /**************************** StoppingState Start ********************************/
OnStateEntered()907 void HCodec::StoppingState::OnStateEntered()
908 {
909 omxNodeInIdleState_ = false;
910 omxNodeIsChangingToLoadedState_ = false;
911 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
912 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
913 SLOGI("all buffer owned by user are now owned by us");
914
915 ParamSP msg = make_shared<ParamBundle>();
916 msg->SetValue("generation", codec_->stateGeneration_);
917 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
918 }
919
OnMsgReceived(const MsgInfo & info)920 void HCodec::StoppingState::OnMsgReceived(const MsgInfo &info)
921 {
922 switch (info.type) {
923 case MsgWhat::CHECK_IF_STUCK: {
924 int32_t generation = 0;
925 (void)info.param->GetValue("generation", generation);
926 if (generation == codec_->stateGeneration_) {
927 SLOGE("stucked, force state transition");
928 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_OMX);
929 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_OMX);
930 SLOGI("all buffer owned by omx are now owned by us");
931 ChangeOmxNodeToLoadedState(true);
932 codec_->ChangeStateTo(codec_->initializedState_);
933 }
934 return;
935 }
936 default: {
937 BaseState::OnMsgReceived(info);
938 }
939 }
940 }
941
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)942 void HCodec::StoppingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
943 {
944 switch (event) {
945 case CODEC_EVENT_CMD_COMPLETE: {
946 if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
947 SLOGW("unexpected CODEC_EVENT_CMD_COMPLETE: %u %u", data1, data2);
948 return;
949 }
950 if (data2 == (uint32_t)CODEC_STATE_IDLE) {
951 SLOGI("omx now idle");
952 omxNodeInIdleState_ = true;
953 ChangeStateIfWeOwnAllBuffers();
954 } else if (data2 == (uint32_t)CODEC_STATE_LOADED) {
955 SLOGI("omx now loaded");
956 codec_->ChangeStateTo(codec_->initializedState_);
957 }
958 return;
959 }
960 default: {
961 BaseState::OnCodecEvent(event, data1, data2);
962 }
963 }
964 }
965
ChangeStateIfWeOwnAllBuffers()966 void HCodec::StoppingState::ChangeStateIfWeOwnAllBuffers()
967 {
968 if (omxNodeInIdleState_ && codec_->IsAllBufferOwnedByUsOrSurface()) {
969 ChangeOmxNodeToLoadedState(false);
970 } else {
971 SLOGD("cannot change state yet");
972 }
973 }
974
ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)975 void HCodec::StoppingState::ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)
976 {
977 if (!omxNodeIsChangingToLoadedState_) {
978 SLOGI("begin to set omx to loaded");
979 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
980 if (ret == HDF_SUCCESS) {
981 omxNodeIsChangingToLoadedState_ = true;
982 } else {
983 SLOGE("set omx to loaded failed, ret=%d", ret);
984 }
985 }
986 if (forceToFreeBuffer || omxNodeIsChangingToLoadedState_) {
987 codec_->ClearBufferPool(OMX_DirInput);
988 codec_->ClearBufferPool(OMX_DirOutput);
989 return;
990 }
991 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
992 }
993
OnShutDown(const MsgInfo & info)994 void HCodec::StoppingState::OnShutDown(const MsgInfo &info)
995 {
996 codec_->DeferMessage(info);
997 }
998
999 /**************************** StoppingState End ********************************/
1000 }