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