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 }