1 /*
2  * Copyright (c) 2023-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 #if defined(VIDEO_SUPPORT)
16 
17 #define HST_LOG_TAG "CodecCmdExecutor"
18 
19 #include "codec_cmd_executor.h"
20 #include "codec_utils.h"
21 #include "foundation/log.h"
22 #include "hdf_base.h"
23 
24 namespace OHOS {
25 namespace Media {
26 namespace Plugin {
27 namespace CodecAdapter {
CodecCmdExecutor(CodecComponentType * component,uint32_t inPortIndex)28 CodecCmdExecutor::CodecCmdExecutor(CodecComponentType* component, uint32_t inPortIndex)
29     : codecComp_(component), inPortIndex_(inPortIndex)
30 {
31     resultMap_[OMX_CommandStateSet] = OMX_StateInvalid;
32     resultMap_[OMX_CommandFlush] = std::pair<Result, Result>{Result::INVALID, Result::INVALID};
33     resultMap_[OMX_CommandPortEnable] = std::pair<Result, Result>{Result::INVALID, Result::INVALID};
34     resultMap_[OMX_CommandPortDisable] = std::pair<Result, Result>{Result::INVALID, Result::INVALID};
35 }
36 
OnEvent(OMX_EVENTTYPE event,EventInfo * info)37 Status CodecCmdExecutor::OnEvent(OMX_EVENTTYPE event, EventInfo* info)
38 {
39     MEDIA_LOG_I("OnEvent begin - eEvent: " PUBLIC_LOG_D32 ", nData1: " PUBLIC_LOG_U32 ", nData2: " PUBLIC_LOG_U32,
40         static_cast<int>(event), info->data1, info->data2);
41     switch (event) {
42         case OMX_EventCmdComplete:
43             HandleEventCmdComplete(info->data1, info->data2); // data2 indicates a state
44             break;
45         case OMX_EventPortSettingsChanged:
46             HandleEventPortSettingsChanged(info->data1, info->data2);
47             break;
48         case OMX_EventBufferFlag:
49             HandleEventBufferFlag(info->data1, info->data2);
50             break;
51         case OMX_EventError:
52             HandleEventError(info->data1, info->data2);
53             break;
54         default:
55             break;
56     }
57     MEDIA_LOG_D("OnEvent end");
58     return Status::OK;
59 }
60 
SendCmd(OMX_COMMANDTYPE cmd,const Plugin::Any & param)61 Status CodecCmdExecutor::SendCmd(OMX_COMMANDTYPE cmd, const Plugin::Any& param)
62 {
63     MEDIA_LOG_D("SendCmd Start");
64     switch (cmd) {
65         case OMX_CommandStateSet: {
66             resultMap_[cmd] = OMX_StateInvalid;
67             auto ret = HdiSendCommand(codecComp_, cmd,  Plugin::AnyCast<OMX_STATETYPE>(param), 0);
68             FALSE_RETURN_V_MSG(ret == HDF_SUCCESS, Status::ERROR_INVALID_OPERATION, "HdiSendCommand failed");
69             break;
70         }
71         case OMX_CommandFlush: {
72             uint32_t portIndex;
73             if (Plugin::Any::IsSameTypeWith<int32_t >(param) && Plugin::AnyCast<int32_t>(param) == -1) {
74                 portIndex = static_cast<uint32_t>(-1);
75             } else {
76                 portIndex = Plugin::AnyCast<uint32_t>(param);
77             }
78             auto ret = HdiSendCommand(codecComp_, cmd, portIndex, 0);
79             FALSE_RETURN_V_MSG(ret == HDF_SUCCESS, Status::ERROR_INVALID_OPERATION, "HdiSendCommand failed");
80             break;
81         }
82         case OMX_CommandPortEnable:
83         case OMX_CommandPortDisable: {
84             auto ret = HdiSendCommand(codecComp_, cmd, Plugin::AnyCast<uint32_t>(param), 0);
85             FALSE_RETURN_V_MSG(ret == HDF_SUCCESS, Status::ERROR_INVALID_OPERATION, "HdiSendCommand failed");
86             break;
87         }
88         default:
89             break;
90     }
91     return Status::OK;
92 }
93 
WaitCmdResult(OMX_COMMANDTYPE cmd,const Plugin::Any & param)94 bool CodecCmdExecutor::WaitCmdResult(OMX_COMMANDTYPE cmd, const Plugin::Any& param)
95 {
96     OSAL::ScopedLock lock(mutex_);
97     MEDIA_LOG_D("WaitCmdResult lastCmd: " PUBLIC_LOG_D32 ", cmd:" PUBLIC_LOG_D32, lastCmd_,  static_cast<int32_t>(cmd));
98     bool result {true};
99     static constexpr int32_t timeout = 2000; // ms
100     switch (cmd) {
101         case OMX_CommandStateSet: {
102             cond_.WaitFor(lock, timeout, [&] {
103                 if (lastCmd_ == -1) {
104                     resultMap_[cmd] = OMX_StateInvalid;
105                     result = false;
106                     return true;
107                 }
108                 return Plugin::AnyCast<OMX_STATETYPE>(resultMap_[cmd]) == AnyCast<OMX_STATETYPE>(param);
109             });
110             return result;
111         }
112         case OMX_CommandFlush:
113         case OMX_CommandPortEnable:
114         case OMX_CommandPortDisable: {
115             auto portIndex = AnyCast<uint32_t>(param);
116             cond_.WaitFor(lock, timeout, [&] {
117                 auto tempPair = AnyCast<std::pair<Result, Result>>(resultMap_[cmd]);
118                 if (lastCmd_ == -1) {
119                     if (portIndex == inPortIndex_) {
120                         resultMap_[cmd] = std::pair<Result, Result>{Result::FAIL, tempPair.second};
121                     } else {
122                         resultMap_[cmd] = std::pair<Result, Result>{tempPair.second, Result::FAIL};
123                     }
124                     result = false;
125                     return true;
126                 }
127                 if (portIndex == inPortIndex_) {
128                     if (tempPair.first != Result::INVALID) {
129                         resultMap_[cmd] = std::pair<Result, Result>{Result::INVALID, tempPair.second};
130                     }
131                     return tempPair.first == Result::SUCCESS;
132                 } else {
133                     if (tempPair.second != Result::INVALID) {
134                         resultMap_[cmd] = std::pair<Result, Result>{tempPair.second, Result::INVALID};
135                     }
136                     return tempPair.second == Result::SUCCESS;
137                 }
138             });
139             return result;
140         }
141         default:
142             return true;
143     }
144 }
145 
SetCallback(Callback * cb)146 Status CodecCmdExecutor::SetCallback(Callback* cb)
147 {
148     callback_ = cb;
149     return Status::OK;
150 }
151 
HandleEventCmdComplete(uint32_t data1,uint32_t data2)152 void CodecCmdExecutor::HandleEventCmdComplete(uint32_t data1, uint32_t data2)
153 {
154     MEDIA_LOG_D("HandleEventCmdComplete begin");
155     OSAL::ScopedLock lock(mutex_);
156     auto cmd = static_cast<OMX_COMMANDTYPE>(data1);
157     switch (data1) {
158         case OMX_CommandStateSet:
159             resultMap_[cmd] = static_cast<OMX_STATETYPE>(data2);
160             break;
161         case OMX_CommandFlush:
162         case OMX_CommandPortEnable:
163         case OMX_CommandPortDisable: {
164             auto tempPair = AnyCast<std::pair<Result, Result>>(resultMap_[cmd]);
165             if (data2 == inPortIndex_) {
166                 resultMap_[cmd] = std::pair<Result, Result>{Result::SUCCESS, tempPair.second};
167             } else {
168                 resultMap_[cmd] = std::pair<Result, Result>{tempPair.second, Result::SUCCESS};
169             }
170             break;
171         }
172         default:
173             break;
174     }
175     lastCmd_ = static_cast<int32_t>(cmd);
176     cond_.NotifyAll();
177     MEDIA_LOG_D("HandelCmdCompleteEvent end");
178 }
179 
HandleEventPortSettingsChanged(OMX_U32 data1,OMX_U32 data2)180 void CodecCmdExecutor::HandleEventPortSettingsChanged(OMX_U32 data1, OMX_U32 data2)
181 {
182     MEDIA_LOG_I("HandleEventPortSettingsChanged begin");
183     OSAL::ScopedLock lock(mutex_);
184 }
185 
HandleEventBufferFlag(OMX_U32 data1,OMX_U32 data2)186 void CodecCmdExecutor::HandleEventBufferFlag(OMX_U32 data1, OMX_U32 data2)
187 {
188     MEDIA_LOG_I("HandleEventBufferFlag begin");
189     OSAL::ScopedLock lock(mutex_);
190     if (data1 == 1 && (data2 & OMX_BUFFERFLAG_EOS)) {
191         MEDIA_LOG_D("it is eos, wait buffer eos");
192     }
193 }
194 
HandleEventError(OMX_U32 data1,OMX_U32 data2)195 void CodecCmdExecutor::HandleEventError(OMX_U32 data1, OMX_U32 data2)
196 {
197     {
198         OSAL::ScopedLock lock(mutex_);
199         lastCmd_ = -1;
200         cond_.NotifyAll();
201     }
202     // Sometimes, hdi return data1 does not indicate an OMX_ERRORTYPE, call OmxErrorType2String() return OMX_ErrorNone
203     auto errorType = OmxErrorType2String(data1);
204     MEDIA_LOG_E("HandleEventError begin, error msg: " PUBLIC_LOG_S, errorType.c_str());
205     if (errorType == "OMX_ErrorNone" && static_cast<OMX_INDEXTYPE>(data2) == OMX_IndexParamPortDefinition) {
206         if (data1 == inPortIndex_) {
207             MEDIA_LOG_E("Unknown error on input port");
208         } else {
209             MEDIA_LOG_E("Input data does not contain keyframes, unable to obtain output data.");
210         }
211     }
212 }
213 } // namespace CodecAdapter
214 } // namespace Plugin
215 } // namespace Media
216 } // namespace OHOS
217 #endif