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