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