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 }