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