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