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 "Source"
17 #define MEDIA_ATOMIC_ABILITY
18
19 #include "avcodec_trace.h"
20 #include "cpp_ext/type_traits_ext.h"
21 #include "common/log.h"
22 #include "osal/utils/util.h"
23 #include "common/media_source.h"
24 #include "plugin/plugin_manager_v2.h"
25 #include "source.h"
26
27 namespace {
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "Source" };
29 }
30
31 namespace OHOS {
32 namespace Media {
33 using namespace Plugins;
34
35 static std::map<std::string, ProtocolType> g_protocolStringToType = {
36 {"http", ProtocolType::HTTP},
37 {"https", ProtocolType::HTTPS},
38 {"file", ProtocolType::FILE},
39 {"stream", ProtocolType::STREAM},
40 {"fd", ProtocolType::FD}
41 };
42
Source()43 Source::Source()
44 : protocol_(),
45 uri_(),
46 seekable_(Seekable::INVALID),
47 plugin_(nullptr),
48 isPluginReady_(false),
49 isAboveWaterline_(false),
50 mediaDemuxerCallback_(std::make_shared<CallbackImpl>())
51 {
52 MEDIA_LOG_D("Source called");
53 }
54
~Source()55 Source::~Source()
56 {
57 MEDIA_LOG_D("~Source called");
58 if (plugin_) {
59 plugin_->Deinit();
60 }
61 }
62
SetCallback(Callback * callback)63 void Source::SetCallback(Callback* callback)
64 {
65 MEDIA_LOG_I("SetCallback entered.");
66 FALSE_RETURN_MSG(callback != nullptr, "callback is nullptr");
67 FALSE_RETURN_MSG(mediaDemuxerCallback_ != nullptr, "mediaDemuxerCallback is nullptr");
68 mediaDemuxerCallback_->SetCallbackWrap(callback);
69 }
70
ClearData()71 void Source::ClearData()
72 {
73 protocol_.clear();
74 uri_.clear();
75 seekable_ = Seekable::INVALID;
76 isPluginReady_ = false;
77 isAboveWaterline_ = false;
78 seekToTimeFlag_ = false;
79 }
80
SetSource(const std::shared_ptr<MediaSource> & source)81 Status Source::SetSource(const std::shared_ptr<MediaSource>& source)
82 {
83 MediaAVCodec::AVCodecTrace trace("Source::SetSource");
84 MEDIA_LOG_I("SetSource enter.");
85 FALSE_RETURN_V_MSG_E(source != nullptr, Status::ERROR_INVALID_PARAMETER, "SetSource invalid source");
86
87 ClearData();
88 Status ret = FindPlugin(source);
89 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "SetSource FindPlugin failed");
90
91 ret = InitPlugin(source);
92 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "SetSource InitPlugin failed");
93
94 if (plugin_ != nullptr) {
95 seekToTimeFlag_ = plugin_->IsSeekToTimeSupported();
96 }
97 MEDIA_LOG_I("SetSource seekToTimeFlag: " PUBLIC_LOG_D32, seekToTimeFlag_);
98 MEDIA_LOG_I("SetSource exit.");
99 return Status::OK;
100 }
101
SetBundleName(const std::string & bundleName)102 void Source::SetBundleName(const std::string& bundleName)
103 {
104 if (plugin_ != nullptr) {
105 MEDIA_LOG_I("SetBundleName bundleName: " PUBLIC_LOG_S, bundleName.c_str());
106 plugin_->SetBundleName(bundleName);
107 }
108 }
109
SetDemuxerState(int32_t streamId)110 void Source::SetDemuxerState(int32_t streamId)
111 {
112 plugin_->SetDemuxerState(streamId);
113 }
114
InitPlugin(const std::shared_ptr<MediaSource> & source)115 Status Source::InitPlugin(const std::shared_ptr<MediaSource>& source)
116 {
117 MediaAVCodec::AVCodecTrace trace("Source::InitPlugin");
118 MEDIA_LOG_I("InitPlugin enter");
119 FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "InitPlugin, Source plugin is nullptr!");
120
121 Status ret = plugin_->Init();
122 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "InitPlugin failed");
123
124 plugin_->SetCallback(this);
125 plugin_->SetEnableOnlineFdCache(isEnableFdCache_);
126 ret = plugin_->SetSource(source);
127
128 MEDIA_LOG_I("InitPlugin exit");
129 return ret;
130 }
131
Prepare()132 Status Source::Prepare()
133 {
134 MEDIA_LOG_I("Prepare entered.");
135 if (plugin_ == nullptr) {
136 return Status::OK;
137 }
138 Status ret = plugin_->Prepare();
139 if (ret == Status::OK) {
140 MEDIA_LOG_D("media source send EVENT_READY");
141 } else if (ret == Status::ERROR_DELAY_READY) {
142 if (isAboveWaterline_) {
143 MEDIA_LOG_D("media source send EVENT_READY");
144 isPluginReady_ = false;
145 isAboveWaterline_ = false;
146 }
147 }
148 return ret;
149 }
150
IsSeekToTimeSupported()151 bool Source::IsSeekToTimeSupported()
152 {
153 return seekToTimeFlag_;
154 }
155
Start()156 Status Source::Start()
157 {
158 MEDIA_LOG_I("Start entered.");
159 return plugin_ ? plugin_->Start() : Status::ERROR_INVALID_OPERATION;
160 }
161
GetBitRates(std::vector<uint32_t> & bitRates)162 Status Source::GetBitRates(std::vector<uint32_t>& bitRates)
163 {
164 MEDIA_LOG_I("GetBitRates");
165 if (plugin_ == nullptr) {
166 MEDIA_LOG_E("GetBitRates failed, plugin_ is nullptr");
167 return Status::ERROR_INVALID_OPERATION;
168 }
169 return plugin_->GetBitRates(bitRates);
170 }
171
SelectBitRate(uint32_t bitRate)172 Status Source::SelectBitRate(uint32_t bitRate)
173 {
174 MEDIA_LOG_I("SelectBitRate");
175 if (plugin_ == nullptr) {
176 MEDIA_LOG_E("SelectBitRate failed, plugin_ is nullptr");
177 return Status::ERROR_INVALID_OPERATION;
178 }
179 return plugin_->SelectBitRate(bitRate);
180 }
181
SetCurrentBitRate(int32_t bitRate,int32_t streamID)182 Status Source::SetCurrentBitRate(int32_t bitRate, int32_t streamID)
183 {
184 MEDIA_LOG_I("SetCurrentBitRate");
185 if (plugin_ == nullptr) {
186 MEDIA_LOG_E("SetCurrentBitRate failed, plugin_ is nullptr");
187 return Status::ERROR_INVALID_OPERATION;
188 }
189 return plugin_->SetCurrentBitRate(bitRate, streamID);
190 }
191
SeekToTime(int64_t seekTime,SeekMode mode)192 Status Source::SeekToTime(int64_t seekTime, SeekMode mode)
193 {
194 if (seekable_ != Seekable::SEEKABLE) {
195 GetSeekable();
196 }
197 int64_t timeNs;
198 if (Plugins::Ms2HstTime(seekTime, timeNs)) {
199 return plugin_->SeekToTime(timeNs, mode);
200 } else {
201 return Status::ERROR_INVALID_PARAMETER;
202 }
203 }
204
GetDownloadInfo(DownloadInfo & downloadInfo)205 Status Source::GetDownloadInfo(DownloadInfo& downloadInfo)
206 {
207 MEDIA_LOG_I("GetDownloadInfo");
208 if (plugin_ == nullptr) {
209 MEDIA_LOG_E("GetDownloadInfo failed, plugin_ is nullptr");
210 return Status::ERROR_INVALID_OPERATION;
211 }
212 return plugin_->GetDownloadInfo(downloadInfo);
213 }
214
GetPlaybackInfo(PlaybackInfo & playbackInfo)215 Status Source::GetPlaybackInfo(PlaybackInfo& playbackInfo)
216 {
217 MEDIA_LOG_I("GetPlaybackInfo");
218 if (plugin_ == nullptr) {
219 MEDIA_LOG_E("GetPlaybackInfo failed, plugin_ is nullptr");
220 return Status::ERROR_INVALID_OPERATION;
221 }
222 return plugin_->GetPlaybackInfo(playbackInfo);
223 }
224
IsNeedPreDownload()225 bool Source::IsNeedPreDownload()
226 {
227 if (plugin_ == nullptr) {
228 MEDIA_LOG_E("IsNeedPreDownload failed, plugin_ is nullptr");
229 return false;
230 }
231 return plugin_->IsNeedPreDownload();
232 }
233
Stop()234 Status Source::Stop()
235 {
236 MEDIA_LOG_I("Stop entered.");
237 seekable_ = Seekable::INVALID;
238 protocol_.clear();
239 uri_.clear();
240 return plugin_->Stop();
241 }
242
Pause()243 Status Source::Pause()
244 {
245 MEDIA_LOG_I("Pause entered.");
246 if (plugin_ != nullptr) {
247 plugin_->Pause();
248 }
249 return Status::OK;
250 }
251
Resume()252 Status Source::Resume()
253 {
254 MEDIA_LOG_I("Resume entered.");
255 if (plugin_ != nullptr) {
256 plugin_->Resume();
257 }
258 return Status::OK;
259 }
260
SetReadBlockingFlag(bool isReadBlockingAllowed)261 Status Source::SetReadBlockingFlag(bool isReadBlockingAllowed)
262 {
263 MEDIA_LOG_D("SetReadBlockingFlag entered, IsReadBlockingAllowed %{public}d", isReadBlockingAllowed);
264 FALSE_RETURN_V(plugin_ != nullptr, Status::OK);
265 return plugin_->SetReadBlockingFlag(isReadBlockingAllowed);
266 }
267
OnEvent(const Plugins::PluginEvent & event)268 void Source::OnEvent(const Plugins::PluginEvent& event)
269 {
270 MEDIA_LOG_D("OnEvent");
271 if (protocol_ == "http" && isInterruptNeeded_) {
272 MEDIA_LOG_I("http OnEvent isInterruptNeeded, return");
273 return;
274 }
275 if (event.type == PluginEventType::ABOVE_LOW_WATERLINE) {
276 if (isPluginReady_ && isAboveWaterline_) {
277 isPluginReady_ = false;
278 isAboveWaterline_ = false;
279 }
280 return;
281 }
282 FALSE_RETURN_MSG(mediaDemuxerCallback_ != nullptr, "mediaDemuxerCallback is nullptr");
283 if (event.type == PluginEventType::CLIENT_ERROR || event.type == PluginEventType::SERVER_ERROR) {
284 MEDIA_LOG_I("Error happened, need notify client by OnEvent");
285 mediaDemuxerCallback_->OnEvent(event);
286 } else if (event.type == PluginEventType::SOURCE_DRM_INFO_UPDATE) {
287 MEDIA_LOG_I("Drminfo updates from source");
288 mediaDemuxerCallback_->OnEvent(event);
289 } else if (event.type == PluginEventType::BUFFERING_END || event.type == PluginEventType::BUFFERING_START) {
290 MEDIA_LOG_I("Buffering start or end.");
291 mediaDemuxerCallback_->OnEvent(event);
292 } else if (event.type == PluginEventType::SOURCE_BITRATE_START) {
293 MEDIA_LOG_I("source bitrate start from source.");
294 mediaDemuxerCallback_->OnEvent(event);
295 } else if (event.type == PluginEventType::CACHED_DURATION) {
296 MEDIA_LOG_D("Onevent cached duration.");
297 mediaDemuxerCallback_->OnEvent(event);
298 } else if (event.type == PluginEventType::EVENT_BUFFER_PROGRESS) {
299 MEDIA_LOG_I("buffer percent update.");
300 mediaDemuxerCallback_->OnEvent(event);
301 } else if (event.type == PluginEventType::DASH_SEEK_READY) {
302 MEDIA_LOG_D("Onevent dash seek ready.");
303 mediaDemuxerCallback_->OnEvent(event);
304 } else {
305 MEDIA_LOG_I("on event type undefined.");
306 }
307 }
308
SetSelectBitRateFlag(bool flag,uint32_t desBitRate)309 void Source::SetSelectBitRateFlag(bool flag, uint32_t desBitRate)
310 {
311 if (mediaDemuxerCallback_) {
312 mediaDemuxerCallback_->SetSelectBitRateFlag(flag, desBitRate);
313 }
314 }
315
CanAutoSelectBitRate()316 bool Source::CanAutoSelectBitRate()
317 {
318 FALSE_RETURN_V_MSG_E(mediaDemuxerCallback_ != nullptr, false, "mediaDemuxerCallback_ is nullptr.");
319 return mediaDemuxerCallback_->CanAutoSelectBitRate();
320 }
321
SetInterruptState(bool isInterruptNeeded)322 void Source::SetInterruptState(bool isInterruptNeeded)
323 {
324 isInterruptNeeded_ = isInterruptNeeded;
325 if (plugin_) {
326 plugin_->SetInterruptState(isInterruptNeeded_);
327 }
328 }
329
GetSeekable()330 Plugins::Seekable Source::GetSeekable()
331 {
332 FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Plugins::Seekable::INVALID, "GetSeekable, Source plugin is nullptr");
333 int32_t retry {0};
334 seekable_ = Seekable::INVALID;
335 do {
336 seekable_ = plugin_->GetSeekable();
337 retry++;
338 if (seekable_ == Seekable::INVALID) {
339 if (retry >= 20) { // 20 means retry times
340 break;
341 }
342 OSAL::SleepFor(10); // 10 means sleep time pre retry
343 }
344 } while (seekable_ == Seekable::INVALID);
345 return seekable_;
346 }
347
GetUriSuffix(const std::string & uri)348 std::string Source::GetUriSuffix(const std::string& uri)
349 {
350 MEDIA_LOG_D("IN");
351 std::string suffix;
352 auto const pos = uri.find_last_of('.');
353 if (pos != std::string::npos) {
354 suffix = uri.substr(pos + 1);
355 }
356 return suffix;
357 }
358
Read(int32_t streamID,std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)359 Status Source::Read(int32_t streamID, std::shared_ptr<Buffer>& buffer, uint64_t offset, size_t expectedLen)
360 {
361 FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "Read, Source plugin is nullptr");
362 if (seekToTimeFlag_) {
363 return plugin_->Read(streamID, buffer, offset, expectedLen);
364 }
365 return plugin_->Read(buffer, offset, expectedLen);
366 }
SeekTo(uint64_t offset)367 Status Source::SeekTo(uint64_t offset)
368 {
369 FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "SeekTo, Source plugin is nullptr");
370 return plugin_->SeekTo(offset);
371 }
372
GetStreamInfo(std::vector<StreamInfo> & streams)373 Status Source::GetStreamInfo(std::vector<StreamInfo>& streams)
374 {
375 FALSE_RETURN_V_MSG_E(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION,
376 "GetStreamInfo, Source plugin is nullptr");
377 Status ret = plugin_->GetStreamInfo(streams);
378 if (ret == Status::OK && streams.size() == 0) {
379 MEDIA_LOG_I("GetStreamInfo empty, MIX Stream");
380 Plugins::StreamInfo info;
381 info.streamId = 0;
382 info.bitRate = 0;
383 info.type = Plugins::MIXED;
384 streams.push_back(info);
385 }
386 for (auto& iter : streams) {
387 MEDIA_LOG_I("Source GetStreamInfo id = " PUBLIC_LOG_D32 " type = " PUBLIC_LOG_D32,
388 iter.streamId, iter.type);
389 }
390 return ret;
391 }
392
GetProtocolByUri()393 bool Source::GetProtocolByUri()
394 {
395 auto ret = true;
396 auto const pos = uri_.find("://");
397 if (pos != std::string::npos) {
398 auto prefix = uri_.substr(0, pos);
399 protocol_.append(prefix);
400 } else {
401 protocol_.append("file");
402 std::string fullPath;
403 ret = OSAL::ConvertFullPath(uri_, fullPath); // convert path to full path
404 if (ret && !fullPath.empty()) {
405 uri_ = fullPath;
406 }
407 }
408 return ret;
409 }
410
ParseProtocol(const std::shared_ptr<MediaSource> & source)411 bool Source::ParseProtocol(const std::shared_ptr<MediaSource>& source)
412 {
413 bool ret = true;
414 SourceType srcType = source->GetSourceType();
415 MEDIA_LOG_D("sourceType = " PUBLIC_LOG_D32, CppExt::to_underlying(srcType));
416 if (srcType == SourceType::SOURCE_TYPE_URI) {
417 uri_ = source->GetSourceUri();
418 std::string mimeType = source->GetMimeType();
419 if (mimeType == AVMimeTypes::APPLICATION_M3U8) {
420 protocol_ = "http";
421 } else {
422 ret = GetProtocolByUri();
423 }
424 } else if (srcType == SourceType::SOURCE_TYPE_FD) {
425 protocol_.append("fd");
426 uri_ = source->GetSourceUri();
427 } else if (srcType == SourceType::SOURCE_TYPE_STREAM) {
428 protocol_.append("stream");
429 uri_.append("stream://");
430 }
431 return ret;
432 }
433
FindPlugin(const std::shared_ptr<MediaSource> & source)434 Status Source::FindPlugin(const std::shared_ptr<MediaSource>& source)
435 {
436 MediaAVCodec::AVCodecTrace trace("Source::FindPlugin");
437 if (!ParseProtocol(source)) {
438 MEDIA_LOG_E("Invalid source!");
439 return Status::ERROR_INVALID_PARAMETER;
440 }
441 if (protocol_.empty()) {
442 MEDIA_LOG_E("protocol_ is empty");
443 return Status::ERROR_INVALID_PARAMETER;
444 }
445 auto plugin = Plugins::PluginManagerV2::Instance().CreatePluginByMime(Plugins::PluginType::SOURCE, protocol_);
446 if (plugin != nullptr) {
447 plugin_ = std::static_pointer_cast<SourcePlugin>(plugin);
448 plugin_->SetInterruptState(isInterruptNeeded_);
449 return Status::OK;
450 }
451 MEDIA_LOG_E("Cannot find any plugin");
452 return Status::ERROR_UNSUPPORTED_FORMAT;
453 }
454
GetDuration()455 int64_t Source::GetDuration()
456 {
457 FALSE_RETURN_V_MSG_W(seekToTimeFlag_, Plugins::HST_TIME_NONE, "Source GetDuration return -1 for isHls false");
458 FALSE_RETURN_V_MSG_W(plugin_ != nullptr, Plugins::HST_TIME_NONE, "Source GetDuration error, plugin_ is nullptr");
459
460 int64_t duration;
461 Status ret = plugin_->GetDuration(duration);
462 FALSE_RETURN_V_MSG_W(ret == Status::OK, Plugins::HST_TIME_NONE, "Source GetDuration from source plugin failed");
463 return duration;
464 }
465
GetSize(uint64_t & fileSize)466 Status Source::GetSize(uint64_t &fileSize)
467 {
468 FALSE_RETURN_V_MSG_W(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "GetSize Source plugin is nullptr!");
469 return plugin_->GetSize(fileSize);
470 }
471
SelectStream(int32_t streamID)472 Status Source::SelectStream(int32_t streamID)
473 {
474 FALSE_RETURN_V_MSG_W(plugin_ != nullptr, Status::ERROR_INVALID_OPERATION, "SelectStream Source plugin is nullptr!");
475 return plugin_->SelectStream(streamID);
476 }
477
GetSegmentOffset()478 size_t Source::GetSegmentOffset()
479 {
480 FALSE_RETURN_V_MSG_W(plugin_ != nullptr, 0, "GetSegmentOffset source pulgin is nullptr!");
481 return plugin_->GetSegmentOffset();
482 }
483
GetHLSDiscontinuity()484 bool Source::GetHLSDiscontinuity()
485 {
486 FALSE_RETURN_V_MSG_W(plugin_ != nullptr, false, "GetHLSDiscontinuity source pulgin is nullptr!");
487 return plugin_->GetHLSDiscontinuity();
488 }
489
SetEnableOnlineFdCache(bool isEnableFdCache)490 void Source::SetEnableOnlineFdCache(bool isEnableFdCache)
491 {
492 isEnableFdCache_ = isEnableFdCache;
493 }
494
WaitForBufferingEnd()495 void Source::WaitForBufferingEnd()
496 {
497 FALSE_RETURN_MSG(plugin_ != nullptr, "WaitForBufferingEnd source plugin is nullptr");
498 return plugin_->WaitForBufferingEnd();
499 }
500 } // namespace Media
501 } // namespace OHOS
502