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
16 #define HST_LOG_TAG "CodecFilterBase"
17
18 #include "pipeline/filters/codec/codec_filter_base.h"
19 #include "foundation/cpp_ext/memory_ext.h"
20 #include "foundation/utils/steady_clock.h"
21 #include "pipeline/filters/common/plugin_settings.h"
22 #include "plugin/common/plugin_attr_desc.h"
23
24 namespace {
25 constexpr uint32_t DEFAULT_OUT_BUFFER_POOL_SIZE = 5;
26 constexpr int32_t MAX_OUT_DECODED_DATA_SIZE_PER_FRAME = 20 * 1024; // 20kB
27 };
28
29 namespace OHOS {
30 namespace Media {
31 namespace Pipeline {
CodecFilterBase(const std::string & name)32 CodecFilterBase::CodecFilterBase(const std::string &name): FilterBase(name) {}
33
~CodecFilterBase()34 CodecFilterBase::~CodecFilterBase()
35 {
36 MEDIA_LOG_D("codec filter base dtor called");
37 }
38
Start()39 ErrorCode CodecFilterBase::Start()
40 {
41 MEDIA_LOG_I("codec filter base start called");
42 if (state_ != FilterState::READY && state_ != FilterState::PAUSED) {
43 MEDIA_LOG_W("call decoder start() when state is not ready or working");
44 return ErrorCode::ERROR_INVALID_OPERATION;
45 }
46 return FilterBase::Start();
47 }
48
Stop()49 ErrorCode CodecFilterBase::Stop()
50 {
51 MEDIA_LOG_D("CodecFilterBase stop start.");
52 // 先改变底层状态 然后停掉上层线程 否则会产生死锁
53 FALSE_RETURN_V_MSG_W(plugin_!= nullptr, ErrorCode::ERROR_NULL_POINTER, "plugin is null");
54 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Flush()), "Flush plugin fail");
55 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->Stop()), "Stop plugin fail");
56 FAIL_RETURN_MSG(codecMode_->Stop(), "Codec mode stop fail");
57 MEDIA_LOG_D("CodecFilterBase stop end.");
58 return FilterBase::Stop();
59 }
60
Prepare()61 ErrorCode CodecFilterBase::Prepare()
62 {
63 MEDIA_LOG_I("codec filter base prepare called");
64 if (state_ != FilterState::INITIALIZED) {
65 MEDIA_LOG_W("codec filter is not in init state");
66 return ErrorCode::ERROR_INVALID_OPERATION;
67 }
68 auto err = FilterBase::Prepare();
69 FAIL_RETURN_MSG(err, "codec prepare error because of filter base prepare error");
70 return err;
71 }
72
UpdateMetaFromPlugin(Plugin::Meta & meta)73 ErrorCode CodecFilterBase::UpdateMetaFromPlugin(Plugin::Meta& meta)
74 {
75 auto parameterMap = PluginParameterTable::GetInstance().FindAllowedParameterMap(filterType_);
76 for (const auto& keyPair : parameterMap) {
77 if ((keyPair.second.second & PARAM_GET) == 0) {
78 continue;
79 }
80 Plugin::ValueType tmpVal;
81 auto ret = TranslatePluginStatus(plugin_->GetParameter(keyPair.first, tmpVal));
82 if (ret != ErrorCode::SUCCESS) {
83 if (Plugin::HasTagInfo(keyPair.first)) {
84 MEDIA_LOG_I("GetParameter " PUBLIC_LOG_S " from plugin " PUBLIC_LOG_S "failed with code "
85 PUBLIC_LOG_D32, Plugin::GetTagStrName(keyPair.first), pluginInfo_->name.c_str(), ret);
86 } else {
87 MEDIA_LOG_I("Tag " PUBLIC_LOG_D32 " is not is map, may be update it?", keyPair.first);
88 MEDIA_LOG_I("GetParameter " PUBLIC_LOG_D32 " from plugin " PUBLIC_LOG_S " failed with code "
89 PUBLIC_LOG_D32, keyPair.first, pluginInfo_->name.c_str(), ret);
90 }
91 continue;
92 }
93 if (!keyPair.second.first(keyPair.first, tmpVal)) {
94 if (Plugin::HasTagInfo(keyPair.first)) {
95 MEDIA_LOG_I("Type of Tag " PUBLIC_LOG_S " should be " PUBLIC_LOG_S,
96 Plugin::GetTagStrName(keyPair.first), std::get<2>(Plugin::g_tagInfoMap.at(keyPair.first)));
97 } else {
98 MEDIA_LOG_I("Tag " PUBLIC_LOG_D32 " is not is map, may be update it?", keyPair.first);
99 MEDIA_LOG_I("Type of Tag " PUBLIC_LOG_D32 "mismatch", keyPair.first);
100 }
101 continue;
102 }
103 meta.SetData(static_cast<Plugin::Tag>(keyPair.first), tmpVal);
104 }
105 return ErrorCode::SUCCESS;
106 }
107
SetPluginParameterLocked(Tag tag,const Plugin::ValueType & value)108 ErrorCode CodecFilterBase::SetPluginParameterLocked(Tag tag, const Plugin::ValueType& value)
109 {
110 return TranslatePluginStatus(plugin_->SetParameter(tag, value));
111 }
112
SetParameter(int32_t key,const Plugin::Any & value)113 ErrorCode CodecFilterBase::SetParameter(int32_t key, const Plugin::Any& value)
114 {
115 if (state_.load() == FilterState::CREATED) {
116 return ErrorCode::ERROR_AGAIN;
117 }
118 Tag tag = Tag::INVALID;
119 FALSE_RETURN_V_MSG_E(TranslateIntoParameter(key, tag), ErrorCode::ERROR_INVALID_PARAMETER_VALUE,
120 "key " PUBLIC_LOG_D32 " is out of boundary", key);
121 RETURN_AGAIN_IF_NULL(plugin_);
122 return SetPluginParameterLocked(tag, value);
123 }
124
GetParameter(int32_t key,Plugin::Any & outVal)125 ErrorCode CodecFilterBase::GetParameter(int32_t key, Plugin::Any& outVal)
126 {
127 if (state_.load() == FilterState::CREATED) {
128 return ErrorCode::ERROR_AGAIN;
129 }
130 Tag tag = Tag::INVALID;
131 FALSE_RETURN_V_MSG_E(TranslateIntoParameter(key, tag), ErrorCode::ERROR_INVALID_PARAMETER_VALUE,
132 "key " PUBLIC_LOG_D32 " is out of boundary", key);
133 RETURN_AGAIN_IF_NULL(plugin_);
134 return TranslatePluginStatus(plugin_->GetParameter(tag, outVal));
135 }
136
UpdateParams(const std::shared_ptr<const Plugin::Meta> & upMeta,std::shared_ptr<Plugin::Meta> & meta)137 void CodecFilterBase::UpdateParams(const std::shared_ptr<const Plugin::Meta>& upMeta,
138 std::shared_ptr<Plugin::Meta>& meta)
139 {
140 }
141
GetAllocator()142 std::shared_ptr<Allocator> CodecFilterBase::GetAllocator()
143 {
144 return plugin_->GetAllocator();
145 }
146
GetOutBufferPoolSize()147 uint32_t CodecFilterBase::GetOutBufferPoolSize()
148 {
149 return DEFAULT_OUT_BUFFER_POOL_SIZE;
150 }
151
CalculateBufferSize(const std::shared_ptr<const Plugin::Meta> & meta)152 uint32_t CodecFilterBase::CalculateBufferSize(const std::shared_ptr<const Plugin::Meta>& meta)
153 {
154 return 0;
155 }
156
GetNegotiateParams(const Plugin::Meta & upstreamParams)157 Plugin::Meta CodecFilterBase::GetNegotiateParams(const Plugin::Meta& upstreamParams)
158 {
159 return upstreamParams;
160 }
161
CheckRequiredOutCapKeys(const Capability & capability)162 bool CodecFilterBase::CheckRequiredOutCapKeys(const Capability& capability)
163 {
164 std::vector<Capability::Key> outCapKeys = GetRequiredOutCapKeys();
165 for (auto outCapKey : outCapKeys) {
166 if (capability.keys.count(outCapKey) == 0) {
167 MEDIA_LOG_W("decoder plugin must specify key " PUBLIC_LOG_S " in out caps",
168 Plugin::Tag2String(static_cast<Plugin::Tag>(outCapKey)));
169 return false;
170 }
171 }
172 return true;
173 }
174
GetRequiredOutCapKeys()175 std::vector<Capability::Key> CodecFilterBase::GetRequiredOutCapKeys()
176 {
177 // Not required by default
178 return {};
179 }
180
Negotiate(const std::string & inPort,const std::shared_ptr<const Plugin::Capability> & upstreamCap,Plugin::Capability & negotiatedCap,const Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)181 bool CodecFilterBase::Negotiate(const std::string& inPort,
182 const std::shared_ptr<const Plugin::Capability>& upstreamCap,
183 Plugin::Capability& negotiatedCap,
184 const Plugin::Meta& upstreamParams,
185 Plugin::Meta& downstreamParams)
186 {
187 PROFILE_BEGIN("CodecFilterBase negotiate start");
188 FALSE_RETURN_V_MSG_W(state_ == FilterState::PREPARING, false, "filter is not preparing when negotiate");
189 auto targetOutPort = GetRouteOutPort(inPort);
190 FALSE_RETURN_V_MSG_W(targetOutPort != nullptr, false, "codec outPort is not found");
191 std::shared_ptr<Plugin::PluginInfo> selectedPluginInfo = nullptr;
192 bool atLeastOutCapMatched = false;
193 auto candidatePlugins = FindAvailablePlugins(*upstreamCap, pluginType_, preferredCodecMode_);
194 for (const auto& candidate : candidatePlugins) {
195 FALSE_LOG_MSG(!candidate.first->outCaps.empty(),
196 "plugin " PUBLIC_LOG_S " has no out caps", candidate.first->name.c_str());
197 for (const auto& outCap : candidate.first->outCaps) { // each codec plugin should have at least one out cap
198 if (!CheckRequiredOutCapKeys(outCap)) {
199 continue;
200 }
201 auto thisOut = std::make_shared<Plugin::Capability>();
202 if (!MergeCapabilityKeys(*upstreamCap, outCap, *thisOut)) {
203 MEDIA_LOG_W("one cap of plugin " PUBLIC_LOG_S " mismatch upstream cap", candidate.first->name.c_str());
204 continue;
205 }
206 atLeastOutCapMatched = true;
207 thisOut->mime = outCap.mime;
208 Plugin::Meta proposeParams;
209 if (targetOutPort->Negotiate(thisOut, capNegWithDownstream_, proposeParams, downstreamParams)) {
210 negotiatedCap = candidate.second;
211 selectedPluginInfo = candidate.first;
212 MEDIA_LOG_I("use plugin " PUBLIC_LOG_S, candidate.first->name.c_str());
213 MEDIA_LOG_I("neg upstream cap " PUBLIC_LOG_S, Capability2String(negotiatedCap).c_str());
214 MEDIA_LOG_I("neg downstream cap " PUBLIC_LOG_S, Capability2String(capNegWithDownstream_).c_str());
215 break;
216 }
217 }
218 if (selectedPluginInfo != nullptr) { // select the first one
219 break;
220 }
221 }
222 FALSE_RETURN_V_MSG_E(atLeastOutCapMatched && selectedPluginInfo != nullptr, false,
223 "can't find available codec plugin with " PUBLIC_LOG_S, Capability2String(*upstreamCap).c_str());
224
225 auto res = UpdateAndInitPluginByInfo<Plugin::Codec>(plugin_, pluginInfo_, selectedPluginInfo,
226 [this](const std::string& name)-> std::shared_ptr<Plugin::Codec> {
227 return Plugin::PluginManager::Instance().CreateCodecPlugin(name, pluginType_);
228 });
229 FALSE_RETURN_V(codecMode_->Init(plugin_, outPorts_), false);
230 PROFILE_END("async codec negotiate end");
231 MEDIA_LOG_D("codec filter base negotiate end");
232 return res;
233 }
234
Configure(const std::string & inPort,const std::shared_ptr<const Plugin::Meta> & upstreamMeta,Plugin::Meta & upstreamParams,Plugin::Meta & downstreamParams)235 bool CodecFilterBase::Configure(const std::string& inPort, const std::shared_ptr<const Plugin::Meta>& upstreamMeta,
236 Plugin::Meta& upstreamParams, Plugin::Meta& downstreamParams)
237 {
238 MEDIA_LOG_I("receive upstream meta " PUBLIC_LOG_S, Meta2String(*upstreamMeta).c_str());
239 FALSE_RETURN_V_MSG_E(plugin_ != nullptr && pluginInfo_ != nullptr, false,
240 "can't configure codec when no plugin available");
241 auto thisMeta = std::make_shared<Plugin::Meta>();
242 FALSE_RETURN_V_MSG_E(MergeMetaWithCapability(*upstreamMeta, capNegWithDownstream_, *thisMeta), false,
243 "can't configure codec plugin since meta is not compatible with negotiated caps");
244 UpdateParams(upstreamMeta, thisMeta);
245
246 // When use hdi as codec plugin interfaces, must set width & height into hdi,
247 // Hdi use these params to calc out buffer size & count then return to filter
248 if (ConfigPluginWithMeta(*plugin_, *thisMeta) != ErrorCode::SUCCESS) {
249 MEDIA_LOG_E("set params into plugin failed");
250 return false;
251 }
252 uint32_t bufferCnt = 0;
253 if (GetPluginParameterLocked(Tag::REQUIRED_OUT_BUFFER_CNT, bufferCnt) != ErrorCode::SUCCESS) {
254 bufferCnt = GetOutBufferPoolSize();
255 }
256 MEDIA_LOG_D("bufferCnt: " PUBLIC_LOG_U32, bufferCnt);
257
258 upstreamParams.Set<Plugin::Tag::VIDEO_MAX_SURFACE_NUM>(bufferCnt);
259 auto targetOutPort = GetRouteOutPort(inPort);
260 if (targetOutPort == nullptr || !targetOutPort->Configure(thisMeta, upstreamParams, downstreamParams)) {
261 MEDIA_LOG_E("decoder filter downstream Configure failed");
262 return false;
263 }
264 sinkParams_ = downstreamParams;
265 uint32_t bufferSize = 0;
266 if (GetPluginParameterLocked(Tag::REQUIRED_OUT_BUFFER_SIZE, bufferSize) != ErrorCode::SUCCESS) {
267 bufferSize = CalculateBufferSize(thisMeta);
268 if (bufferSize == 0) {
269 bufferSize = MAX_OUT_DECODED_DATA_SIZE_PER_FRAME;
270 }
271 }
272 std::shared_ptr<Allocator> outAllocator = GetAllocator();
273 codecMode_->CreateOutBufferPool(outAllocator, bufferCnt, bufferSize, bufferMetaType_);
274 MEDIA_LOG_D("AllocateOutputBuffers success");
275 auto err = ConfigureToStartPluginLocked(thisMeta);
276 if (err != ErrorCode::SUCCESS) {
277 MEDIA_LOG_E("CodecFilterBase configure error");
278 OnEvent({name_, EventType::EVENT_ERROR, err});
279 return false;
280 }
281 state_ = FilterState::READY;
282 OnEvent({name_, EventType::EVENT_READY});
283 MEDIA_LOG_I("CodecFilterBase send EVENT_READY");
284 return true;
285 }
286
ConfigureToStartPluginLocked(const std::shared_ptr<const Plugin::Meta> & meta)287 ErrorCode CodecFilterBase::ConfigureToStartPluginLocked(const std::shared_ptr<const Plugin::Meta>& meta)
288 {
289 MEDIA_LOG_D("CodecFilterBase configure called");
290 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->SetCallback(this)), "plugin set callback fail");
291 FAIL_RETURN_MSG(TranslatePluginStatus(plugin_->SetDataCallback(this)), "plugin set data callback fail");
292 FAIL_RETURN_MSG(codecMode_->Configure(), "codec mode configure error");
293 return ErrorCode::SUCCESS;
294 }
295
FlushStart()296 void CodecFilterBase::FlushStart()
297 {
298 MEDIA_LOG_D("FlushStart entered.");
299 isFlushing_ = true;
300 if (plugin_ != nullptr) {
301 auto err = TranslatePluginStatus(plugin_->Flush());
302 if (err != ErrorCode::SUCCESS) {
303 MEDIA_LOG_E("codec plugin flush error");
304 }
305 }
306 MEDIA_LOG_D("FlushStart exit.");
307 }
308
FlushEnd()309 void CodecFilterBase::FlushEnd()
310 {
311 MEDIA_LOG_I("FlushEnd entered");
312 isFlushing_ = false;
313 }
314
PushData(const std::string & inPort,const AVBufferPtr & buffer,int64_t offset)315 ErrorCode CodecFilterBase::PushData(const std::string &inPort, const AVBufferPtr& buffer, int64_t offset)
316 {
317 if (state_ != FilterState::READY && state_ != FilterState::PAUSED && state_ != FilterState::RUNNING) {
318 MEDIA_LOG_W("pushing data to decoder when state is " PUBLIC_LOG_D32, static_cast<int>(state_.load()));
319 return ErrorCode::ERROR_INVALID_OPERATION;
320 }
321 if (isFlushing_) {
322 MEDIA_LOG_I("Flushing, discarding this data from port " PUBLIC_LOG_S, inPort.c_str());
323 return ErrorCode::SUCCESS;
324 }
325 return codecMode_->PushData(inPort, buffer, offset);
326 }
327 } // namespace Pipeline
328 } // namespace Media
329 } // namespace OHOS
330