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