• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2021 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 "TypeFinder"
17 
18 #include "type_finder.h"
19 #include <algorithm>
20 #include "foundation/log.h"
21 #include "foundation/osal/utils/util.h"
22 #include "foundation/utils/steady_clock.h"
23 
24 namespace OHOS {
25 namespace Media {
26 namespace Pipeline {
27 namespace {
GetUriSuffix(const std::string & uri)28 std::string GetUriSuffix(const std::string& uri)
29 {
30     std::string suffix {""};
31     auto const pos = uri.find_last_of('.');
32     if (pos != std::string::npos) {
33         suffix = uri.substr(pos + 1);
34     }
35     return suffix;
36 }
37 
IsPluginSupportedExtension(Plugin::PluginInfo & pluginInfo,const std::string & extension)38 bool IsPluginSupportedExtension(Plugin::PluginInfo& pluginInfo, const std::string& extension)
39 {
40     if (pluginInfo.pluginType != Plugin::PluginType::DEMUXER) {
41         return false;
42     }
43     bool rtv = false;
44     auto info = pluginInfo.extra[PLUGIN_INFO_EXTRA_EXTENSIONS];
45     if (info.HasValue() && info.SameTypeWith(typeid(std::vector<std::string>))) {
46         for (const auto& ext : Plugin::AnyCast<std::vector<std::string>&>(info)) {
47             if (ext == extension) {
48                 rtv = true;
49                 break;
50             }
51         }
52     }
53     return rtv;
54 }
55 
ToLower(std::string & str)56 void ToLower(std::string& str)
57 {
58     std::transform(str.begin(), str.end(), str.begin(), [](unsigned char ch) { return std::tolower(ch); });
59 }
60 
61 } // namespace
62 
TypeFinder()63 TypeFinder::TypeFinder()
64     : sniffNeeded_(true),
65       uri_(),
66       mediaDataSize_(0),
67       pluginName_(),
68       plugins_(),
69       pluginRegistryChanged_(true),
70       task_(nullptr),
71       checkRange_(),
72       peekRange_(),
73       typeFound_()
74 {
75     MEDIA_LOG_D("TypeFinder ctor called...");
76 }
77 
~TypeFinder()78 TypeFinder::~TypeFinder()
79 {
80     MEDIA_LOG_D("TypeFinder dtor called...");
81     if (task_) {
82         task_->Stop();
83     }
84 }
85 
IsSniffNeeded(std::string uri)86 bool TypeFinder::IsSniffNeeded(std::string uri)
87 {
88     ToLower(uri);
89     bool uriChanged = uri_ != uri;
90     if (uriChanged || pluginRegistryChanged_ || uri.empty()) {
91         return true;
92     }
93     return uriChanged;
94 }
95 
Init(std::string uri,uint64_t mediaDataSize,std::function<bool (uint64_t,size_t)> checkRange,std::function<bool (uint64_t,size_t,AVBufferPtr &)> peekRange)96 void TypeFinder::Init(std::string uri, uint64_t mediaDataSize, std::function<bool(uint64_t, size_t)> checkRange,
97                       std::function<bool(uint64_t, size_t, AVBufferPtr&)> peekRange)
98 {
99     mediaDataSize_ = mediaDataSize;
100     checkRange_ = std::move(checkRange);
101     peekRange_ = std::move(peekRange);
102     sniffNeeded_ = IsSniffNeeded(uri);
103     if (sniffNeeded_) {
104         uri_.swap(uri);
105         pluginName_.clear();
106         if (GetPlugins()) {
107             SortPlugins(GetUriSuffix(uri_));
108         } else {
109             MEDIA_LOG_E("TypeFinder Init failed due to no demuxer plugins...");
110         }
111     }
112 }
113 
114 /**
115  * FindMediaType for seekable source, is a sync interface.
116  * @return plugin names for the found media type.
117  */
FindMediaType()118 std::string TypeFinder::FindMediaType()
119 {
120     if (sniffNeeded_) {
121         pluginName_ = SniffMediaType();
122         if (pluginName_.empty()) {
123             pluginName_ = GuessMediaType();
124         }
125         sniffNeeded_ = false;
126     }
127     return pluginName_;
128 }
129 
130 /**
131  * FindMediaTypeAsync for non-seekable source
132  * @param typeFound is a callback called when media type found.
133  */
FindMediaTypeAsync(std::function<void (std::string)> typeFound)134 void TypeFinder::FindMediaTypeAsync(std::function<void(std::string)> typeFound)
135 {
136     typeFound_ = std::move(typeFound);
137     task_ = std::make_shared<OSAL::Task>("TypeFinder");
138     task_->RegisterHandler([this]() { DoTask(); });
139     task_->Start();
140 }
141 
ReadAt(int64_t offset,std::shared_ptr<Plugin::Buffer> & buffer,size_t expectedLen)142 Plugin::Status TypeFinder::ReadAt(int64_t offset, std::shared_ptr<Plugin::Buffer>& buffer, size_t expectedLen)
143 {
144     if (!buffer || expectedLen == 0 || !IsOffsetValid(offset)) {
145         MEDIA_LOG_E("ReadAt failed, buffer empty: " PUBLIC_LOG_D32 ", expectedLen: " PUBLIC_LOG_ZU ", offset: "
146                     PUBLIC_LOG_D64, !buffer, expectedLen, offset);
147         return Plugin::Status::ERROR_INVALID_PARAMETER;
148     }
149     const int maxTryTimes = 3;
150     int i = 0;
151     while (!checkRange_(offset, expectedLen) && (i++ < maxTryTimes)) {
152         OSAL::SleepFor(5); // 5 ms
153     }
154     if (i == maxTryTimes) {
155         MEDIA_LOG_E("ReadAt exceed maximum allowed try times and failed.");
156         return Plugin::Status::ERROR_NOT_ENOUGH_DATA;
157     }
158     FALSE_LOG_MSG(peekRange_(static_cast<uint64_t>(offset), expectedLen, buffer), "peekRange failed.");
159     return Plugin::Status::OK;
160 }
161 
GetSize(uint64_t & size)162 Plugin::Status TypeFinder::GetSize(uint64_t& size)
163 {
164     size = mediaDataSize_;
165     return (mediaDataSize_ > 0) ? Plugin::Status::OK : Plugin::Status::ERROR_UNKNOWN;
166 }
167 
GetSeekable()168 Plugin::Seekable TypeFinder::GetSeekable()
169 {
170     return Plugin::Seekable::INVALID;
171 }
172 
DoTask()173 void TypeFinder::DoTask()
174 {
175     if (sniffNeeded_) {
176         pluginName_ = SniffMediaType();
177         if (pluginName_.empty()) {
178             pluginName_ = GuessMediaType();
179         }
180         sniffNeeded_ = false;
181     }
182     task_->StopAsync();
183     typeFound_(pluginName_);
184 }
185 
SniffMediaType()186 std::string TypeFinder::SniffMediaType()
187 {
188     PROFILE_BEGIN("SniffMediaType begin.");
189     constexpr int probThresh = 50; // valid range [0, 100]
190     std::string pluginName;
191     int maxProb = 0;
192     auto dataSource = shared_from_this();
193     int cnt = 0;
194     for (const auto& plugin : plugins_) {
195         auto prob = Plugin::PluginManager::Instance().Sniffer(plugin->name, dataSource);
196         ++cnt;
197         if (prob > probThresh) {
198             pluginName = plugin->name;
199             break;
200         }
201         if (prob > maxProb) {
202             maxProb = prob;
203             pluginName = plugin->name;
204         }
205     }
206     PROFILE_END("SniffMediaType end, sniffed plugin num = " PUBLIC_LOG_D32, cnt);
207     return pluginName;
208 }
209 
GuessMediaType() const210 std::string TypeFinder::GuessMediaType() const
211 {
212     std::string pluginName;
213     std::string uriSuffix = GetUriSuffix(uri_);
214     if (uriSuffix.empty()) {
215         return "";
216     }
217     for (const auto& pluginInfo : plugins_) {
218         if (IsPluginSupportedExtension(*pluginInfo, uriSuffix)) {
219             pluginName = pluginInfo->name;
220             break;
221         }
222     }
223     return pluginName;
224 }
225 
IsOffsetValid(int64_t offset) const226 bool TypeFinder::IsOffsetValid(int64_t offset) const
227 {
228     return (mediaDataSize_ == 0) || offset < static_cast<int64_t>(mediaDataSize_);
229 }
230 
GetPlugins()231 bool TypeFinder::GetPlugins()
232 {
233     MEDIA_LOG_I("TypeFinder::GetPlugins : " PUBLIC_LOG_D32 ", empty: " PUBLIC_LOG_D32,
234                 (pluginRegistryChanged_ == true), plugins_.empty());
235     if (pluginRegistryChanged_) {
236         pluginRegistryChanged_ = false;
237         auto pluginNames = Plugin::PluginManager::Instance().ListPlugins(Plugin::PluginType::DEMUXER);
238         for (auto& pluginName : pluginNames) {
239             auto pluginInfo = Plugin::PluginManager::Instance().GetPluginInfo(Plugin::PluginType::DEMUXER, pluginName);
240             if (!pluginInfo) {
241                 MEDIA_LOG_E("GetPlugins failed for plugin: " PUBLIC_LOG_S, pluginName.c_str());
242                 continue;
243             }
244             plugins_.emplace_back(std::move(pluginInfo));
245         }
246     }
247     return !plugins_.empty();
248 }
249 
SortPlugins(const std::string & uriSuffix)250 void TypeFinder::SortPlugins(const std::string& uriSuffix)
251 {
252     if (uriSuffix.empty()) {
253         return;
254     }
255     std::stable_sort(
256         plugins_.begin(), plugins_.end(),
257         [&uriSuffix](const std::shared_ptr<Plugin::PluginInfo>& lhs, const std::shared_ptr<Plugin::PluginInfo>& rhs) {
258             if (IsPluginSupportedExtension(*lhs, uriSuffix)) {
259                 return (lhs->rank >= rhs->rank) || !IsPluginSupportedExtension(*rhs, uriSuffix);
260             } else {
261                 return (lhs->rank >= rhs->rank) && !IsPluginSupportedExtension(*rhs, uriSuffix);
262             }
263         });
264 }
265 } // namespace Pipeline
266 } // namespace Media
267 } // namespace OHOS
268