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 "hcodec_list.h"
19 #include "hcodec_log.h"
20
21 namespace OHOS::MediaAVCodec {
22 using namespace std;
23 using namespace OHOS::HDI::Codec::V1_0;
24
25 /**************************** BaseState Start ****************************/
OnMsgReceived(const MsgInfo & info)26 void HCodec::BaseState::OnMsgReceived(const MsgInfo &info)
27 {
28 switch (info.type) {
29 case MsgWhat::CODEC_EVENT: {
30 OnCodecEvent(info);
31 return;
32 }
33 case MsgWhat::OMX_EMPTY_BUFFER_DONE: {
34 uint32_t bufferId;
35 (void)info.param->GetValue(BUFFER_ID, bufferId);
36 codec_->OnOMXEmptyBufferDone(bufferId, inputMode_);
37 return;
38 }
39 case MsgWhat::OMX_FILL_BUFFER_DONE: {
40 OmxCodecBuffer omxBuffer;
41 (void)info.param->GetValue("omxBuffer", omxBuffer);
42 codec_->OnOMXFillBufferDone(omxBuffer, outputMode_);
43 return;
44 }
45 case MsgWhat::GET_INPUT_FORMAT:
46 case MsgWhat::GET_OUTPUT_FORMAT: {
47 OnGetFormat(info);
48 return;
49 }
50 case MsgWhat::STOP:
51 case MsgWhat::RELEASE: {
52 OnShutDown(info);
53 return;
54 }
55 default: {
56 const char* msgWhat = HCodec::ToString(static_cast<MsgWhat>(info.type));
57 if (info.id == ASYNC_MSG_ID) {
58 SLOGI("ignore msg %{public}s in current state", msgWhat);
59 } else { // Make sure that all sync message are replied
60 SLOGE("%{public}s cannot be called at this state", msgWhat);
61 ReplyErrorCode(info.id, AVCS_ERR_INVALID_STATE);
62 }
63 return;
64 }
65 }
66 }
67
ReplyErrorCode(MsgId id,int32_t err)68 void HCodec::BaseState::ReplyErrorCode(MsgId id, int32_t err)
69 {
70 if (id == ASYNC_MSG_ID) {
71 return;
72 }
73 ParamSP reply = ParamBundle::Create();
74 reply->SetValue("err", err);
75 codec_->PostReply(id, reply);
76 }
77
OnCodecEvent(const MsgInfo & info)78 void HCodec::BaseState::OnCodecEvent(const MsgInfo &info)
79 {
80 CodecEventType event;
81 uint32_t data1;
82 uint32_t data2;
83 (void)info.param->GetValue("event", event);
84 (void)info.param->GetValue("data1", data1);
85 (void)info.param->GetValue("data2", data2);
86 if (event == CODEC_EVENT_CMD_COMPLETE &&
87 data1 == static_cast<uint32_t>(CODEC_COMMAND_FLUSH) &&
88 data2 == static_cast<uint32_t>(OMX_ALL)) {
89 SLOGD("ignore flush all complete event");
90 } else {
91 OnCodecEvent(event, data1, data2);
92 }
93 }
94
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)95 void HCodec::BaseState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
96 {
97 if (event == CODEC_EVENT_ERROR) {
98 SLOGE("omx report error event, data1 = %{public}u, data2 = %{public}u", data1, data2);
99 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_SERVICE_DIED);
100 } else {
101 SLOGW("ignore event %{public}d, data1 = %{public}u, data2 = %{public}u", event, data1, data2);
102 }
103 }
104
OnGetFormat(const MsgInfo & info)105 void HCodec::BaseState::OnGetFormat(const MsgInfo &info)
106 {
107 shared_ptr<Format> fmt = (info.type == MsgWhat::GET_INPUT_FORMAT) ?
108 codec_->inputFormat_ : codec_->outputFormat_;
109 ParamSP reply = ParamBundle::Create();
110 if (fmt) {
111 reply->SetValue<int32_t>("err", AVCS_ERR_OK);
112 reply->SetValue("format", *fmt);
113 codec_->PostReply(info.id, reply);
114 } else {
115 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
116 }
117 }
118
OnCheckIfStuck(const MsgInfo & info)119 void HCodec::BaseState::OnCheckIfStuck(const MsgInfo &info)
120 {
121 int32_t generation;
122 (void)info.param->GetValue("generation", generation);
123 if (generation == codec_->stateGeneration_) {
124 SLOGE("stucked");
125 codec_->PrintAllBufferInfo();
126 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
127 }
128 }
129
OnForceShutDown(const MsgInfo & info)130 void HCodec::BaseState::OnForceShutDown(const MsgInfo &info)
131 {
132 int32_t generation;
133 (void)info.param->GetValue("generation", generation);
134 codec_->ForceShutdown(generation);
135 }
136 /**************************** BaseState End ******************************/
137
138
139 /**************************** UninitializedState start ****************************/
OnStateEntered()140 void HCodec::UninitializedState::OnStateEntered()
141 {
142 codec_->ReleaseComponent();
143 }
144
OnMsgReceived(const MsgInfo & info)145 void HCodec::UninitializedState::OnMsgReceived(const MsgInfo &info)
146 {
147 switch (info.type) {
148 case MsgWhat::INIT: {
149 string name;
150 (void)info.param->GetValue("name", name);
151 int32_t err = OnAllocateComponent(name);
152 ReplyErrorCode(info.id, err);
153 if (err == AVCS_ERR_OK) {
154 codec_->ChangeStateTo(codec_->initializedState_);
155 }
156 break;
157 }
158 default: {
159 BaseState::OnMsgReceived(info);
160 }
161 }
162 }
163
OnAllocateComponent(const std::string & name)164 int32_t HCodec::UninitializedState::OnAllocateComponent(const std::string &name)
165 {
166 codec_->compMgr_ = GetManager();
167 if (codec_->compMgr_ == nullptr) {
168 SLOGE("GetCodecComponentManager failed");
169 return AVCS_ERR_UNKNOWN;
170 }
171 codec_->compCb_ = new HdiCallback(codec_);
172 int32_t ret = codec_->compMgr_->CreateComponent(codec_->compNode_, codec_->componentId_, name,
173 0, codec_->compCb_);
174 if (ret != HDF_SUCCESS || codec_->compNode_ == nullptr) {
175 codec_->compCb_ = nullptr;
176 codec_->compMgr_ = nullptr;
177 SLOGE("CreateComponent failed, ret=%{public}d", ret);
178 return AVCS_ERR_UNKNOWN;
179 }
180 codec_->componentName_ = name;
181 SLOGI("create omx node succ");
182 return AVCS_ERR_OK;
183 }
184
OnShutDown(const MsgInfo & info)185 void HCodec::UninitializedState::OnShutDown(const MsgInfo &info)
186 {
187 ReplyErrorCode(info.id, AVCS_ERR_OK);
188 }
189
190 /**************************** UninitializedState End ******************************/
191
192 /**************************** InitializedState Start **********************************/
OnStateEntered()193 void HCodec::InitializedState::OnStateEntered()
194 {
195 codec_->inputPortEos_ = false;
196 codec_->outputPortEos_ = false;
197 codec_->inputFormat_.reset();
198 codec_->outputFormat_.reset();
199 codec_->sharedBufferFormat_.reset();
200
201 ProcessShutDownFromRunning();
202 codec_->notifyCallerAfterShutdownComplete_ = false;
203 codec_->ProcessDeferredMessages();
204 }
205
ProcessShutDownFromRunning()206 void HCodec::InitializedState::ProcessShutDownFromRunning()
207 {
208 if (!codec_->isShutDownFromRunning_) {
209 return;
210 }
211 SLOGI("we are doing shutdown from running/portchange/flush -> stopping -> initialized");
212 bool keepComponentAllocated = codec_->keepComponentAllocated_;
213 if (keepComponentAllocated) {
214 if (codec_->configFormat_ == nullptr) {
215 SLOGW("stored configuration is null");
216 } else {
217 Format copyOfCurConfig(*codec_->configFormat_);
218 codec_->OnConfigure(copyOfCurConfig);
219 }
220 } else {
221 codec_->ChangeStateTo(codec_->uninitializedState_);
222 }
223 if (codec_->notifyCallerAfterShutdownComplete_) {
224 SLOGI("reply to %{public}s msg", keepComponentAllocated ? "stop" : "release");
225 MsgInfo msg { keepComponentAllocated ? MsgWhat::STOP : MsgWhat::RELEASE, 0, nullptr };
226 if (codec_->GetFirstSyncMsgToReply(msg)) {
227 ReplyErrorCode(msg.id, AVCS_ERR_OK);
228 }
229 codec_->notifyCallerAfterShutdownComplete_ = false;
230 }
231 codec_->isShutDownFromRunning_ = false;
232 codec_->keepComponentAllocated_ = false;
233 }
234
OnMsgReceived(const MsgInfo & info)235 void HCodec::InitializedState::OnMsgReceived(const MsgInfo &info)
236 {
237 switch (info.type) {
238 case MsgWhat::SET_CALLBACK: {
239 OnSetCallBack(info);
240 return;
241 }
242 case MsgWhat::CONFIGURE: {
243 OnConfigure(info);
244 return;
245 }
246 case MsgWhat::CREATE_INPUT_SURFACE: {
247 sptr<Surface> surface = codec_->OnCreateInputSurface();
248 ParamSP reply = ParamBundle::Create();
249 reply->SetValue<int32_t>("err", surface != nullptr ? AVCS_ERR_OK : AVCS_ERR_UNKNOWN);
250 reply->SetValue("surface", surface);
251 codec_->PostReply(info.id, reply);
252 return;
253 }
254 case MsgWhat::SET_INPUT_SURFACE: {
255 OnSetSurface(info, true);
256 return;
257 }
258 case MsgWhat::SET_OUTPUT_SURFACE: {
259 OnSetSurface(info, false);
260 return;
261 }
262 case MsgWhat::START: {
263 OnStart(info);
264 return;
265 }
266 default: {
267 BaseState::OnMsgReceived(info);
268 }
269 }
270 }
271
OnSetCallBack(const MsgInfo & info)272 void HCodec::InitializedState::OnSetCallBack(const MsgInfo &info)
273 {
274 int32_t err;
275 shared_ptr<AVCodecCallback> cb;
276 (void)info.param->GetValue("callback", cb);
277 if (cb == nullptr) {
278 err = AVCS_ERR_INVALID_VAL;
279 SLOGE("invalid param");
280 } else {
281 codec_->callback_ = cb;
282 err = AVCS_ERR_OK;
283 }
284 ReplyErrorCode(info.id, err);
285 }
286
OnConfigure(const MsgInfo & info)287 void HCodec::InitializedState::OnConfigure(const MsgInfo &info)
288 {
289 Format fmt;
290 (void)info.param->GetValue("format", fmt);
291 ReplyErrorCode(info.id, codec_->OnConfigure(fmt));
292 }
293
OnSetSurface(const MsgInfo & info,bool isInput)294 void HCodec::InitializedState::OnSetSurface(const MsgInfo &info, bool isInput)
295 {
296 sptr<Surface> surface;
297 (void)info.param->GetValue("surface", surface);
298 int32_t err = isInput ? codec_->OnSetInputSurface(surface) : codec_->OnSetOutputSurface(surface);
299 ReplyErrorCode(info.id, err);
300 }
301
OnStart(const MsgInfo & info)302 void HCodec::InitializedState::OnStart(const MsgInfo &info)
303 {
304 if (!codec_->ReadyToStart()) {
305 SLOGE("callback not set or format is not configured, can't start");
306 ReplyErrorCode(info.id, AVCS_ERR_INVALID_OPERATION);
307 return;
308 }
309 SLOGI("begin to set omx to idle");
310 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
311 if (ret == HDF_SUCCESS) {
312 codec_->ReplyToSyncMsgLater(info);
313 codec_->ChangeStateTo(codec_->startingState_);
314 } else {
315 SLOGE("set omx to idle failed, ret=%{public}d", ret);
316 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
317 }
318 }
319
OnShutDown(const MsgInfo & info)320 void HCodec::InitializedState::OnShutDown(const MsgInfo &info)
321 {
322 if (info.type == MsgWhat::STOP) {
323 SLOGI("receive STOP");
324 } else {
325 SLOGI("receive RELEASE");
326 codec_->ChangeStateTo(codec_->uninitializedState_);
327 }
328 codec_->notifyCallerAfterShutdownComplete_ = false;
329 ReplyErrorCode(info.id, AVCS_ERR_OK);
330 }
331 /**************************** InitializedState End ******************************/
332
333
334 /**************************** StartingState Start ******************************/
OnStateEntered()335 void HCodec::StartingState::OnStateEntered()
336 {
337 hasError_ = false;
338
339 ParamSP msg = ParamBundle::Create();
340 msg->SetValue("generation", codec_->stateGeneration_);
341 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
342
343 int32_t ret = AllocateBuffers();
344 if (ret != AVCS_ERR_OK) {
345 SLOGE("AllocateBuffers failed, back to init state");
346 hasError_ = true;
347 ReplyStartMsg(ret);
348 codec_->ChangeStateTo(codec_->initializedState_);
349 }
350 }
351
AllocateBuffers()352 int32_t HCodec::StartingState::AllocateBuffers()
353 {
354 int32_t ret = codec_->AllocateBuffersOnPort(OMX_DirInput);
355 if (ret != AVCS_ERR_OK) {
356 return ret;
357 }
358 ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
359 if (ret != AVCS_ERR_OK) {
360 return ret;
361 }
362 return AVCS_ERR_OK;
363 }
364
OnMsgReceived(const MsgInfo & info)365 void HCodec::StartingState::OnMsgReceived(const MsgInfo &info)
366 {
367 switch (info.type) {
368 case MsgWhat::GET_BUFFER_FROM_SURFACE:
369 case MsgWhat::SET_PARAMETERS:
370 case MsgWhat::GET_INPUT_FORMAT:
371 case MsgWhat::GET_OUTPUT_FORMAT: {
372 codec_->DeferMessage(info);
373 return;
374 }
375 case MsgWhat::START:
376 case MsgWhat::FLUSH: {
377 ReplyErrorCode(info.id, AVCS_ERR_OK);
378 return;
379 }
380 case MsgWhat::CHECK_IF_STUCK: {
381 int32_t generation;
382 if (info.param->GetValue("generation", generation) &&
383 generation == codec_->stateGeneration_) {
384 SLOGE("stucked, force state transition");
385 hasError_ = true;
386 ReplyStartMsg(AVCS_ERR_UNKNOWN);
387 codec_->ChangeStateTo(codec_->initializedState_);
388 }
389 return;
390 }
391 default: {
392 BaseState::OnMsgReceived(info);
393 }
394 }
395 }
396
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)397 void HCodec::StartingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
398 {
399 if (event != CODEC_EVENT_CMD_COMPLETE) {
400 return BaseState::OnCodecEvent(event, data1, data2);
401 }
402 if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
403 SLOGW("ignore event: data1=%{public}u, data2=%{public}u", data1, data2);
404 return;
405 }
406 if (data2 == (uint32_t)CODEC_STATE_IDLE) {
407 SLOGI("omx now idle, begin to set omx to executing");
408 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
409 if (ret != HDF_SUCCESS) {
410 SLOGE("set omx to executing failed, ret=%{public}d", ret);
411 hasError_ = true;
412 ReplyStartMsg(AVCS_ERR_UNKNOWN);
413 codec_->ChangeStateTo(codec_->initializedState_);
414 }
415 } else if (data2 == (uint32_t)CODEC_STATE_EXECUTING) {
416 SLOGI("omx now executing");
417 ReplyStartMsg(AVCS_ERR_OK);
418 codec_->SubmitAllBuffersOwnedByUs();
419 codec_->etbCnt_ = 0;
420 codec_->fbdCnt_ = 0;
421 codec_->ChangeStateTo(codec_->runningState_);
422 }
423 }
424
OnShutDown(const MsgInfo & info)425 void HCodec::StartingState::OnShutDown(const MsgInfo &info)
426 {
427 codec_->DeferMessage(info);
428 }
429
ReplyStartMsg(int32_t errCode)430 void HCodec::StartingState::ReplyStartMsg(int32_t errCode)
431 {
432 MsgInfo msg {MsgWhat::START, 0, nullptr};
433 if (codec_->GetFirstSyncMsgToReply(msg)) {
434 SLOGI("start %{public}s", (errCode == 0) ? "succ" : "failed");
435 ReplyErrorCode(msg.id, errCode);
436 } else {
437 SLOGE("there should be a start msg to reply");
438 }
439 }
440
OnStateExited()441 void HCodec::StartingState::OnStateExited()
442 {
443 if (hasError_) {
444 SLOGW("error occured, roll omx back to loaded and free allocated buffers");
445 if (codec_->RollOmxBackToLoaded()) {
446 codec_->ClearBufferPool(OMX_DirInput);
447 codec_->ClearBufferPool(OMX_DirOutput);
448 }
449 }
450 BaseState::OnStateExited();
451 }
452
453 /**************************** StartingState End ******************************/
454
455 /**************************** RunningState Start ********************************/
OnStateEntered()456 void HCodec::RunningState::OnStateEntered()
457 {
458 codec_->ProcessDeferredMessages();
459 }
460
OnMsgReceived(const MsgInfo & info)461 void HCodec::RunningState::OnMsgReceived(const MsgInfo &info)
462 {
463 switch (info.type) {
464 case MsgWhat::START:
465 ReplyErrorCode(info.id, codec_->SubmitAllBuffersOwnedByUs());
466 break;
467 case MsgWhat::SET_PARAMETERS:
468 OnSetParameters(info);
469 break;
470 case MsgWhat::REQUEST_IDR_FRAME:
471 ReplyErrorCode(info.id, codec_->RequestIDRFrame());
472 break;
473 case MsgWhat::FLUSH:
474 OnFlush(info);
475 break;
476 case MsgWhat::GET_BUFFER_FROM_SURFACE:
477 codec_->OnGetBufferFromSurface();
478 break;
479 case MsgWhat::QUEUE_INPUT_BUFFER:
480 codec_->OnQueueInputBuffer(info, inputMode_);
481 break;
482 case MsgWhat::NOTIFY_EOS:
483 codec_->OnSignalEndOfInputStream(info);
484 break;
485 case MsgWhat::RENDER_OUTPUT_BUFFER:
486 codec_->OnRenderOutputBuffer(info, outputMode_);
487 break;
488 case MsgWhat::RELEASE_OUTPUT_BUFFER:
489 codec_->OnReleaseOutputBuffer(info, outputMode_);
490 break;
491 default:
492 BaseState::OnMsgReceived(info);
493 break;
494 }
495 }
496
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)497 void HCodec::RunningState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
498 {
499 switch (event) {
500 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
501 if (data1 != OMX_DirOutput) {
502 SLOGI("ignore input port changed");
503 return;
504 }
505 if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
506 SLOGI("output port settings changed");
507 if (codec_->UpdateOutPortFormat() == AVCS_ERR_OK) {
508 codec_->callback_->OnOutputFormatChanged(*(codec_->outputFormat_.get()));
509 }
510 SLOGI("begin to ask omx to disable out port");
511 int32_t ret = codec_->compNode_->SendCommand(
512 CODEC_COMMAND_PORT_DISABLE, OMX_DirOutput, {});
513 if (ret == HDF_SUCCESS) {
514 codec_->EraseOutBuffersOwnedByUsOrSurface();
515 codec_->ChangeStateTo(codec_->outputPortChangedState_);
516 } else {
517 SLOGE("ask omx to disable out port failed");
518 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
519 }
520 } else {
521 SLOGW("unknown data2 for CODEC_EVENT_PORT_SETTINGS_CHANGED");
522 }
523 return;
524 }
525 default: {
526 BaseState::OnCodecEvent(event, data1, data2);
527 }
528 }
529 }
530
OnShutDown(const MsgInfo & info)531 void HCodec::RunningState::OnShutDown(const MsgInfo &info)
532 {
533 codec_->isShutDownFromRunning_ = true;
534 codec_->notifyCallerAfterShutdownComplete_ = true;
535 codec_->keepComponentAllocated_ = (info.type == MsgWhat::STOP);
536 codec_->isBufferCirculating_ = false;
537
538 SLOGI("receive %{public}s msg, begin to set omx to idle", info.type == MsgWhat::RELEASE ? "release" : "stop");
539 auto costUs = chrono::duration_cast<chrono::microseconds>(
540 chrono::steady_clock::now() - codec_->firstFbdTime_).count();
541 SLOGI("etb cnt %{public}" PRIu64 ", fbd cnt %{public}" PRIu64 ", fbd fps %{public}.2f",
542 codec_->etbCnt_, codec_->fbdCnt_,
543 static_cast<double>(codec_->fbdCnt_) / costUs * codec_->TIME_RATIO_S_TO_US);
544 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
545 if (ret == HDF_SUCCESS) {
546 codec_->ReplyToSyncMsgLater(info);
547 codec_->ChangeStateTo(codec_->stoppingState_);
548 } else {
549 SLOGE("set omx to idle failed, ret=%{public}d", ret);
550 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
551 }
552 }
553
OnFlush(const MsgInfo & info)554 void HCodec::RunningState::OnFlush(const MsgInfo &info)
555 {
556 codec_->isBufferCirculating_ = false;
557 SLOGI("begin to ask omx to flush");
558 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_FLUSH, OMX_ALL, {});
559 if (ret == HDF_SUCCESS) {
560 codec_->ReplyToSyncMsgLater(info);
561 codec_->ChangeStateTo(codec_->flushingState_);
562 } else {
563 SLOGI("ask omx to flush failed, ret=%{public}d", ret);
564 ReplyErrorCode(info.id, AVCS_ERR_UNKNOWN);
565 }
566 }
567
OnSetParameters(const MsgInfo & info)568 void HCodec::RunningState::OnSetParameters(const MsgInfo &info)
569 {
570 Format params;
571 (void)info.param->GetValue("params", params);
572 ReplyErrorCode(info.id, codec_->OnSetParameters(params));
573 }
574 /**************************** RunningState End ********************************/
575
576
577 /**************************** OutputPortChangedState Start ********************************/
OnStateEntered()578 void HCodec::OutputPortChangedState::OnStateEntered()
579 {
580 ParamSP msg = ParamBundle::Create();
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 }
592 case MsgWhat::START:
593 case MsgWhat::SET_PARAMETERS:
594 case MsgWhat::GET_INPUT_FORMAT:
595 case MsgWhat::GET_OUTPUT_FORMAT: {
596 codec_->DeferMessage(info);
597 return;
598 }
599 case MsgWhat::QUEUE_INPUT_BUFFER: {
600 codec_->OnQueueInputBuffer(info, inputMode_);
601 return;
602 }
603 case MsgWhat::NOTIFY_EOS: {
604 codec_->OnSignalEndOfInputStream(info);
605 return;
606 }
607 case MsgWhat::RENDER_OUTPUT_BUFFER: {
608 codec_->OnRenderOutputBuffer(info, outputMode_);
609 return;
610 }
611 case MsgWhat::RELEASE_OUTPUT_BUFFER: {
612 codec_->OnReleaseOutputBuffer(info, outputMode_);
613 return;
614 }
615 case MsgWhat::FORCE_SHUTDOWN: {
616 OnForceShutDown(info);
617 return;
618 }
619 case MsgWhat::CHECK_IF_STUCK: {
620 OnCheckIfStuck(info);
621 return;
622 }
623 default: {
624 BaseState::OnMsgReceived(info);
625 }
626 }
627 }
628
OnShutDown(const MsgInfo & info)629 void HCodec::OutputPortChangedState::OnShutDown(const MsgInfo &info)
630 {
631 if (codec_->hasFatalError_) {
632 ParamSP stopMsg = ParamBundle::Create();
633 stopMsg->SetValue("generation", codec_->stateGeneration_);
634 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
635 }
636 codec_->DeferMessage(info);
637 }
638
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)639 void HCodec::OutputPortChangedState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
640 {
641 switch (event) {
642 case CODEC_EVENT_CMD_COMPLETE: {
643 if (data1 == CODEC_COMMAND_PORT_DISABLE) {
644 if (data2 != OMX_DirOutput) {
645 SLOGW("ignore input port disable complete");
646 return;
647 }
648 SLOGI("output port is disabled");
649 HandleOutputPortDisabled();
650 } else if (data1 == CODEC_COMMAND_PORT_ENABLE) {
651 if (data2 != OMX_DirOutput) {
652 SLOGW("ignore input port enable complete");
653 return;
654 }
655 SLOGI("output port is enabled");
656 HandleOutputPortEnabled();
657 }
658 return;
659 }
660 default: {
661 BaseState::OnCodecEvent(event, data1, data2);
662 }
663 }
664 }
665
HandleOutputPortDisabled()666 void HCodec::OutputPortChangedState::HandleOutputPortDisabled()
667 {
668 int32_t ret = AVCS_ERR_OK;
669 if (!codec_->outputBufferPool_.empty()) {
670 SLOGE("output port is disabled but not empty: %{public}zu", codec_->outputBufferPool_.size());
671 ret = AVCS_ERR_UNKNOWN;
672 }
673
674 if (ret == AVCS_ERR_OK) {
675 SLOGI("begin to ask omx to enable out port");
676 int32_t err = codec_->compNode_->SendCommand(CODEC_COMMAND_PORT_ENABLE, OMX_DirOutput, {});
677 if (err == HDF_SUCCESS) {
678 ret = codec_->AllocateBuffersOnPort(OMX_DirOutput);
679 } else {
680 SLOGE("ask omx to enable out port failed, ret=%{public}d", ret);
681 ret = AVCS_ERR_UNKNOWN;
682 }
683 }
684 if (ret != AVCS_ERR_OK) {
685 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_INVALID_VAL);
686 }
687 }
688
HandleOutputPortEnabled()689 void HCodec::OutputPortChangedState::HandleOutputPortEnabled()
690 {
691 if (codec_->isBufferCirculating_) {
692 codec_->SubmitOutputBuffersToOmxNode();
693 }
694 codec_->ChangeStateTo(codec_->runningState_);
695 }
696
OnFlush(const MsgInfo & info)697 void HCodec::OutputPortChangedState::OnFlush(const MsgInfo &info)
698 {
699 if (codec_->hasFatalError_) {
700 ParamSP stopMsg = ParamBundle::Create();
701 stopMsg->SetValue("generation", codec_->stateGeneration_);
702 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
703 }
704 codec_->DeferMessage(info);
705 }
706 /**************************** OutputPortChangedState End ********************************/
707
708
709 /**************************** FlushingState Start ********************************/
OnStateEntered()710 void HCodec::FlushingState::OnStateEntered()
711 {
712 flushCompleteFlag_[OMX_DirInput] = false;
713 flushCompleteFlag_[OMX_DirOutput] = false;
714 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
715 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
716 SLOGI("all buffer owned by user are now owned by us");
717
718 ParamSP msg = ParamBundle::Create();
719 msg->SetValue("generation", codec_->stateGeneration_);
720 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
721 }
722
OnMsgReceived(const MsgInfo & info)723 void HCodec::FlushingState::OnMsgReceived(const MsgInfo &info)
724 {
725 switch (info.type) {
726 case MsgWhat::GET_BUFFER_FROM_SURFACE: {
727 codec_->DeferMessage(info);
728 return;
729 }
730 case MsgWhat::FLUSH: {
731 ReplyErrorCode(info.id, AVCS_ERR_OK);
732 return;
733 }
734 case MsgWhat::FORCE_SHUTDOWN: {
735 OnForceShutDown(info);
736 return;
737 }
738 case MsgWhat::CHECK_IF_STUCK: {
739 OnCheckIfStuck(info);
740 return;
741 }
742 default: {
743 BaseState::OnMsgReceived(info);
744 }
745 }
746 }
747
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)748 void HCodec::FlushingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
749 {
750 switch (event) {
751 case CODEC_EVENT_CMD_COMPLETE: {
752 auto ret = UpdateFlushStatusOnPorts(data1, data2);
753 if (ret == AVCS_ERR_OK && IsFlushCompleteOnAllPorts()) {
754 ChangeStateIfWeOwnAllBuffers();
755 }
756 return;
757 }
758 case CODEC_EVENT_PORT_SETTINGS_CHANGED: {
759 ParamSP portSettingChangedMsg = ParamBundle::Create();
760 portSettingChangedMsg->SetValue("generation", codec_->stateGeneration_);
761 portSettingChangedMsg->SetValue("event", event);
762 portSettingChangedMsg->SetValue("data1", data1);
763 portSettingChangedMsg->SetValue("data2", data2);
764 codec_->DeferMessage(MsgInfo {MsgWhat::CODEC_EVENT, 0, portSettingChangedMsg});
765 SLOGI("deferring CODEC_EVENT_PORT_SETTINGS_CHANGED");
766 return;
767 }
768 default: {
769 BaseState::OnCodecEvent(event, data1, data2);
770 }
771 }
772 }
773
UpdateFlushStatusOnPorts(uint32_t data1,uint32_t data2)774 int32_t HCodec::FlushingState::UpdateFlushStatusOnPorts(uint32_t data1, uint32_t data2)
775 {
776 if (data2 == OMX_DirInput || data2 == OMX_DirOutput) {
777 if (flushCompleteFlag_[data2]) {
778 SLOGE("flush already completed for port (%{public}u)", data2);
779 return AVCS_ERR_OK;
780 }
781 flushCompleteFlag_[data2] = true;
782 } else if (data2 == OMX_ALL) {
783 if (!IsFlushCompleteOnAllPorts()) {
784 SLOGW("received flush complete event for OMX_ALL, portFlushStatue=(%{public}d/%{public}d)",
785 flushCompleteFlag_[OMX_DirInput], flushCompleteFlag_[OMX_DirOutput]);
786 return AVCS_ERR_INVALID_VAL;
787 }
788 } else {
789 SLOGW("unexpected data2(%{public}d) for CODEC_COMMAND_FLUSH complete", data2);
790 }
791 return AVCS_ERR_OK;
792 }
793
IsFlushCompleteOnAllPorts()794 bool HCodec::FlushingState::IsFlushCompleteOnAllPorts()
795 {
796 return flushCompleteFlag_[OMX_DirInput] && flushCompleteFlag_[OMX_DirOutput];
797 }
798
ChangeStateIfWeOwnAllBuffers()799 void HCodec::FlushingState::ChangeStateIfWeOwnAllBuffers()
800 {
801 if (!IsFlushCompleteOnAllPorts() || !codec_->IsAllBufferOwnedByUsOrSurface()) {
802 return;
803 }
804 MsgInfo msg {MsgWhat::FLUSH, 0, nullptr};
805 if (codec_->GetFirstSyncMsgToReply(msg)) {
806 ReplyErrorCode(msg.id, AVCS_ERR_OK);
807 }
808 codec_->inputPortEos_ = false;
809 codec_->outputPortEos_ = false;
810 codec_->ChangeStateTo(codec_->runningState_);
811 }
812
OnShutDown(const MsgInfo & info)813 void HCodec::FlushingState::OnShutDown(const MsgInfo &info)
814 {
815 codec_->DeferMessage(info);
816 if (codec_->hasFatalError_) {
817 ParamSP stopMsg = ParamBundle::Create();
818 stopMsg->SetValue("generation", codec_->stateGeneration_);
819 codec_->SendAsyncMsg(MsgWhat::FORCE_SHUTDOWN, stopMsg, THREE_SECONDS_IN_US);
820 }
821 }
822 /**************************** FlushingState End ********************************/
823
824
825 /**************************** StoppingState Start ********************************/
OnStateEntered()826 void HCodec::StoppingState::OnStateEntered()
827 {
828 omxNodeInIdleState_ = false;
829 omxNodeIsChangingToLoadedState_ = false;
830 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_USER);
831 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_USER);
832 SLOGI("all buffer owned by user are now owned by us");
833
834 ParamSP msg = ParamBundle::Create();
835 msg->SetValue("generation", codec_->stateGeneration_);
836 codec_->SendAsyncMsg(MsgWhat::CHECK_IF_STUCK, msg, THREE_SECONDS_IN_US);
837 }
838
OnMsgReceived(const MsgInfo & info)839 void HCodec::StoppingState::OnMsgReceived(const MsgInfo &info)
840 {
841 switch (info.type) {
842 case MsgWhat::CHECK_IF_STUCK: {
843 int32_t generation;
844 (void)info.param->GetValue("generation", generation);
845 if (generation == codec_->stateGeneration_) {
846 SLOGE("stucked, force state transition");
847 codec_->ReclaimBuffer(OMX_DirInput, BufferOwner::OWNED_BY_OMX);
848 codec_->ReclaimBuffer(OMX_DirOutput, BufferOwner::OWNED_BY_OMX);
849 SLOGI("all buffer owned by omx are now owned by us");
850 ChangeOmxNodeToLoadedState(true);
851 codec_->ChangeStateTo(codec_->initializedState_);
852 }
853 return;
854 }
855 default: {
856 BaseState::OnMsgReceived(info);
857 }
858 }
859 }
860
OnCodecEvent(CodecEventType event,uint32_t data1,uint32_t data2)861 void HCodec::StoppingState::OnCodecEvent(CodecEventType event, uint32_t data1, uint32_t data2)
862 {
863 switch (event) {
864 case CODEC_EVENT_CMD_COMPLETE: {
865 if (data1 != (uint32_t)CODEC_COMMAND_STATE_SET) {
866 SLOGW("unexpected CODEC_EVENT_CMD_COMPLETE: %{public}u %{public}u", data1, data2);
867 return;
868 }
869 if (data2 == (uint32_t)CODEC_STATE_IDLE) {
870 SLOGI("omx now idle");
871 omxNodeInIdleState_ = true;
872 ChangeStateIfWeOwnAllBuffers();
873 } else if (data2 == (uint32_t)CODEC_STATE_LOADED) {
874 SLOGI("omx now loaded");
875 codec_->ChangeStateTo(codec_->initializedState_);
876 }
877 return;
878 }
879 default: {
880 BaseState::OnCodecEvent(event, data1, data2);
881 }
882 }
883 }
884
ChangeStateIfWeOwnAllBuffers()885 void HCodec::StoppingState::ChangeStateIfWeOwnAllBuffers()
886 {
887 if (omxNodeInIdleState_ && codec_->IsAllBufferOwnedByUsOrSurface()) {
888 ChangeOmxNodeToLoadedState(false);
889 } else {
890 SLOGD("cannot change state yet");
891 }
892 }
893
ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)894 void HCodec::StoppingState::ChangeOmxNodeToLoadedState(bool forceToFreeBuffer)
895 {
896 if (!omxNodeIsChangingToLoadedState_) {
897 SLOGI("begin to set omx to loaded");
898 int32_t ret = codec_->compNode_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
899 if (ret == HDF_SUCCESS) {
900 omxNodeIsChangingToLoadedState_ = true;
901 } else {
902 SLOGE("set omx to loaded failed, ret=%{public}d", ret);
903 }
904 }
905 if (forceToFreeBuffer || omxNodeIsChangingToLoadedState_) {
906 codec_->ClearBufferPool(OMX_DirInput);
907 codec_->ClearBufferPool(OMX_DirOutput);
908 return;
909 }
910 codec_->SignalError(AVCODEC_ERROR_INTERNAL, AVCS_ERR_UNKNOWN);
911 }
912
OnShutDown(const MsgInfo & info)913 void HCodec::StoppingState::OnShutDown(const MsgInfo &info)
914 {
915 codec_->DeferMessage(info);
916 }
917
918 /**************************** StoppingState End ********************************/
919 }