2 // @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
4 // to manipulate TrackRenderer objects
5 // to provide optimized control of TrackRenderer
7 #include "esplayer/esplayer.h"
10 #include <boost/scope_exit.hpp>
19 #include "core/gst_utils.h"
20 #include "core/track_util.h"
21 #include "core/utils/performance_checker.h"
22 #include "core/utils/plusplayer_cfg.h"
23 #include "core/utils/plusplayer_log.h"
24 #include "esplayer/esplayer_drm.h"
25 #include "json/json.h"
27 namespace plusplayer {
31 // get values from /etc/multimedia/esplusplayer.ini
32 static std::once_flag loaded;
33 static std::map<std::string, bool> ini_property;
36 void LoadIniProperty(const Json::Value& root);
38 } // namespace es_conf
42 std::uint64_t ConvertMsToNs(std::uint64_t ms) {
43 constexpr std::uint64_t ns_unit = 1000000;
44 if (ms > (G_MAXUINT64 / ns_unit)) return G_MAXUINT64;
47 std::uint64_t ConvertNsToMs(std::uint64_t ns) {
48 constexpr std::uint64_t ms_unit = 1000000;
52 std::int64_t ConvertMsToNs(std::int64_t ms) {
53 constexpr std::int64_t ns_unit = 1000000;
54 if (ms > (G_MAXINT64 / ns_unit)) return G_MAXINT64;
57 std::int64_t ConvertNsToMs(std::int64_t ns) {
58 constexpr std::int64_t ms_unit = 1000000;
62 std::string GetStringFromMatroskaColor(const MatroskaColor& color_info) {
63 std::ostringstream oss;
64 oss << "matrixCoefficients:" << color_info.matrix_coefficients
65 << " bitsPerChannel:" << color_info.bits_per_channel
66 << " chromaSubsamplingHorz:" << color_info.chroma_subsampling_horizontal
67 << " chromaSubsamplingVert:" << color_info.chroma_subsampling_vertical
68 << " cbSubsamplingHorz:" << color_info.cb_subsampling_horizontal
69 << " cbSubsamplingVert:" << color_info.cb_subsampling_vertical
70 << " chromaSitingHorz:" << color_info.chroma_siting_horizontal
71 << " chromaSitingVert:" << color_info.chroma_siting_vertical
72 << " range:" << color_info.range
73 << " transferCharacteristics:" << color_info.transfer_characteristics
74 << " primaries:" << color_info.primaries
75 << " maxCLL:" << color_info.max_cll << " maxFALL:" << color_info.max_fall
76 << " RX:" << color_info.metadata.primary_r_chromaticity_x
77 << " RY:" << color_info.metadata.primary_r_chromaticity_y
78 << " GX:" << color_info.metadata.primary_g_chromaticity_x
79 << " GY:" << color_info.metadata.primary_g_chromaticity_y
80 << " BX:" << color_info.metadata.primary_b_chromaticity_x
81 << " BY:" << color_info.metadata.primary_b_chromaticity_y
82 << " wX:" << color_info.metadata.white_point_chromaticity_x
83 << " wY:" << color_info.metadata.white_point_chromaticity_y
84 << " luminanceMax:" << color_info.metadata.luminance_max
85 << " luminanceMin:" << color_info.metadata.luminance_min
86 << " isHDR10p:" << color_info.is_hdr_10p;
93 // const std::uint64_t kMaxByteOfVideoSrcQueue = 70 * 1024 * 1024; // 70 MB
94 // const std::uint64_t kMaxByteOfAudioSrcQueue = 10 * 1024 * 1024; // 10 MB
95 // const std::uint64_t kMaxTimeOfVideoSrcQueue = 10000000000; // 10 s
96 // const std::uint64_t kMaxTimeOfAudioSrcQueue = 10000000000; // 10 s
98 constexpr uint32_t kNdecodingMode = 0x04;
100 enum VolumeLevel { kVolumeMin = 0, kVolumeMax = 100 };
101 constexpr int kMaxFhdWidth = 1920;
102 constexpr int kMaxFhdHeight = 1080;
104 inline bool IsPcmMimeType(const std::string& mimetype) {
105 return (mimetype.find("audio/x-raw") != std::string::npos);
107 inline bool IsAacCodec(const Track& track) {
108 return (track.mimetype.find("audio/mpeg") != std::string::npos &&
111 inline bool IsEac3Codec(const std::string& mimetype) {
112 return mimetype.find("audio/x-eac3") != std::string::npos;
114 inline bool IsAc3Codec(const std::string& mimetype) {
115 return mimetype.find("audio/x-ac3") != std::string::npos;
117 inline bool IsAvailableCodecSwitch(const Track& track) {
118 if (internal::IsAacCodec(track) || internal::IsAc3Codec(track.mimetype) ||
119 internal::IsEac3Codec(track.mimetype))
124 int ResetEosStatus(const TrackType& type, int eos_status) {
125 if (type == kTrackTypeVideo)
126 eos_status &= ~EosStatus::kVideoEos;
127 else if (type == kTrackTypeAudio)
128 eos_status &= ~EosStatus::kAudioEos;
132 void UpdateCodecTypeTracks(std::vector<Track>& tracks,
133 const PlayerAudioCodecType& audio_codec_type,
134 const PlayerVideoCodecType& video_codec_type,
135 bool force_audio_swdecoder_use) {
136 for (auto& track : tracks) {
137 switch (track.type) {
138 case kTrackTypeAudio: {
139 if (audio_codec_type == kPlayerAudioCodecTypeSW ||
140 force_audio_swdecoder_use)
141 track.use_swdecoder = true;
143 track.use_swdecoder = false;
146 case kTrackTypeVideo: {
147 if (video_codec_type == kPlayerVideoCodecTypeSW)
148 track.use_swdecoder = true;
150 track.use_swdecoder = false;
158 inline bool IsSupportedDrmType(const drm::Type& drm_type) {
159 static const std::map<drm::Type, bool> kSupportedDrmType = {
160 {drm::Type::kPlayready, true},
162 if (kSupportedDrmType.count(drm_type) == 0) return false;
163 return kSupportedDrmType.at(drm_type);
165 inline void ResetDrmProperty(drm::Property& drm_property) {
166 drm_property = drm::Property();
168 inline StreamType ConvertToStreamType(TrackType type) {
169 return (type == kTrackTypeAudio) ? StreamType::kAudio : StreamType::kVideo;
171 struct AppsrcQueueSizeOption {
172 std::uint64_t current_size = 0;
173 std::uint64_t max_size = 0;
174 std::uint32_t threshold = 0;
176 inline bool IsUnderRun(AppsrcQueueSizeOption& byte_based,
177 AppsrcQueueSizeOption& time_based) {
178 bool need_data_by_byte = false, need_data_by_time = false;
179 need_data_by_byte = (byte_based.max_size > 0) &&
180 (byte_based.current_size * 100 / byte_based.max_size <=
181 byte_based.threshold);
182 need_data_by_time = (time_based.max_size > 0) &&
183 (time_based.current_size * 100 / time_based.max_size <=
184 time_based.threshold);
185 if (need_data_by_byte || need_data_by_time)
190 inline bool IsLowLatencyModeDisableAVSync(std::uint32_t mode) {
191 constexpr std::uint32_t kAVSync = 0x0100;
192 return (mode & kAVSync) ? true : false;
194 inline bool IsLowLatencyModeDisablePreroll(std::uint32_t mode) {
195 constexpr std::uint32_t kPreroll = 0x0200;
196 return (mode & kPreroll) ? true : false;
198 inline bool IsLowLatencyMode(std::uint32_t mode) {
199 return (mode != static_cast<std::uint32_t>(kLowLatencyModeNone)) ? true
202 inline bool IsSupportedTsOffset(std::uint32_t mode) {
203 return IsLowLatencyMode(mode) && !IsLowLatencyModeDisableAVSync(mode) ? true
206 inline bool IsSetLowLatencyModeForCatchUp(std::uint32_t low_latency_mode) {
207 std::uint32_t precondition = 0;
208 precondition |= static_cast<std::uint32_t>(kLowLatencyModeAudio);
209 precondition |= static_cast<std::uint32_t>(kLowLatencyModeVideo);
210 precondition |= static_cast<std::uint32_t>(kLowLatencyModeDisableAVSync);
212 static_cast<std::uint32_t>(kLowLatencyModeDisableVideoQuality);
213 return (low_latency_mode == precondition) ? true : false;
216 } // namespace internal
218 EsPlayer::EsPlayer() {
219 std::call_once(es_conf::loaded, [this]() { es_conf::LoadIniFile(); });
222 EsPlayer::~EsPlayer() {
227 LOG_ERROR("Close failed");
232 bool EsPlayer::Open() {
233 LOG_INFO_P(this, "state manager > %p", &state_manager_);
235 state_manager_.Start();
236 auto op = [this]() noexcept -> bool {
237 const auto start = performance_checker::Start();
238 if (trackrenderer_) {
239 assert(0 && "trackrenderer already exist");
242 std::async(std::launch::async, &EsPlayer::MsgTask_, this);
243 trackrenderer_ = TrackRendererAdapter::Create();
244 assert(trackrenderer_);
246 trackrenderer_->RegisterListenerForEsplayer(
247 trackrenderer_event_listener_.get());
248 performance_checker::End(start, "Open");
251 es_event::Open event{op};
252 return state_manager_.ProcessEvent(event);
255 bool EsPlayer::Close() {
257 std::lock_guard<std::mutex> lk(submit_mutex_);
258 if (state_manager_.GetState() >= EsState::kIdle) {
261 auto op = [this]() noexcept {
262 if (is_msg_task_stop_ == false) {
263 is_msg_task_stop_ = true;
264 msg_task_cv_.notify_one();
265 if (msg_handler_task_.valid()) msg_handler_task_.wait();
268 if (trackrenderer_) trackrenderer_.reset();
269 ResetContextForClose_();
273 es_event::Close event{op};
274 state_manager_.ProcessEvent(event);
275 state_manager_.Stop();
279 bool EsPlayer::Deactivate(const StreamType type) {
281 if (state_manager_.GetState() < EsState::kReady) {
282 LOG_ERROR_P(this, "Invalid State , current %d",
283 state_manager_.GetStateEnum());
286 if (!trackrenderer_->Deactivate(static_cast<TrackType>(type))) {
290 std::lock_guard<std::mutex> lock(eos_mutex_);
292 case StreamType::kAudio:
293 eos_status_ |= EosStatus::kAudioEos;
295 case StreamType::kVideo:
296 eos_status_ |= EosStatus::kVideoEos;
302 for (auto& track : track_) {
303 if (track.type == static_cast<TrackType>(type)) {
304 track.active = false;
310 bool EsPlayer::Activate(const StreamType type) {
312 if (state_manager_.GetState() < EsState::kReady) {
313 LOG_ERROR_P(this, "Invalid State , current %d",
314 state_manager_.GetStateEnum());
317 if (!track_.empty()) {
318 auto has_track = [type](const Track& item) -> bool {
319 return item.type == static_cast<TrackType>(type);
321 auto target = std::find_if(track_.begin(), track_.end(), has_track);
322 if (target == track_.end()) {
323 LOG_ERROR_P(this, "there is no track to activate");
326 if (target->active != false) {
327 LOG_ERROR_P(this, "The track should be deactivated in advance.");
330 target->active = true;
331 internal::UpdateCodecTypeTracks(track_, audio_codec_type_,
333 force_audio_swdecoder_use_);
334 SetTrackRendererAttributes_();
335 if (!trackrenderer_->Activate(target->type, *target)) {
336 target->active = false;
339 std::lock_guard<std::mutex> lock2(eos_mutex_);
341 internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
347 bool EsPlayer::Start() {
350 LOG_ERROR_P(this, "Stop already, no need to Start,leave...");
353 auto op = [this]() noexcept {
354 if (!trackrenderer_->Start()) {
359 es_event::Start event{op};
360 return state_manager_.ProcessEvent(event);
363 bool EsPlayer::Stop() {
366 auto stop = [this]() noexcept -> bool {
367 const auto start = performance_checker::Start();
368 if (trackrenderer_) trackrenderer_->Stop();
369 ResetContextForStop_();
370 performance_checker::End(start, "Stop");
373 for (const auto& track : track_) {
374 es_packet_logger_.PrintStoredPacketInfo(
375 internal::ConvertToStreamType(track.type), true);
377 es_event::Stop event{stop};
378 bool res = state_manager_.ProcessEventStop(event);
380 if (preparetask_.valid()) {
381 LOG_INFO_P(this, "Stopped , Wait Prepare() finish...");
383 LOG_INFO_P(this, "Wait , Wait Prepare() Done...");
389 void EsPlayer::SetTrackRendererAttributes_() {
390 if (trackrenderer_ == nullptr) return;
391 trackrenderer_->SetAttribute(
392 TrackRendererAdapter::Attribute::kVideoQueueMaxByte,
393 src_queue_size_.kMaxByteOfVideoSrcQueue);
394 trackrenderer_->SetAttribute(
395 TrackRendererAdapter::Attribute::kAudioQueueMaxByte,
396 src_queue_size_.kMaxByteOfAudioSrcQueue);
397 trackrenderer_->SetAttribute(
398 TrackRendererAdapter::Attribute::kVideoMinByteThreshold,
399 src_queue_size_.kMinByteThresholdOfVideoSrcQueue);
400 trackrenderer_->SetAttribute(
401 TrackRendererAdapter::Attribute::kAudioMinByteThreshold,
402 src_queue_size_.kMinByteThresholdOfAudioSrcQueue);
403 trackrenderer_->SetAttribute(
404 TrackRendererAdapter::Attribute::kVideoQueueMaxBuffer,
405 src_queue_size_.kMaxBufferOfVideoSrcQueue);
406 trackrenderer_->SetAttribute(
407 TrackRendererAdapter::Attribute::kAudioQueueMaxBuffer,
408 src_queue_size_.kMaxBufferOfAudioSrcQueue);
409 trackrenderer_->SetAttribute(TrackRendererAdapter::Attribute::kLowLatencyMode,
411 trackrenderer_->SetAttribute(
412 TrackRendererAdapter::Attribute::kUnlimitedMaxBufferMode,
413 unlimited_max_buffer_mode_);
414 trackrenderer_->SetAttribute(
415 TrackRendererAdapter::Attribute::kAccurateSeekMode, accurate_seek_mode_);
416 trackrenderer_->SetAttribute(
417 TrackRendererAdapter::Attribute::kVideoPreDisplayMode,
418 video_pre_display_mode_);
419 if (resume_time_.is_set) {
420 trackrenderer_->SetAttribute(
421 TrackRendererAdapter::Attribute::kStartRenderingTime,
423 resume_time_.is_set = false;
427 bool EsPlayer::Prepare_() {
430 LOG_ERROR_P(this, "Stop already, no need to prepare,leave...");
433 auto op = [this]() noexcept -> bool {
434 const auto start = performance_checker::Start();
436 internal::UpdateCodecTypeTracks(track_, audio_codec_type_,
438 force_audio_swdecoder_use_);
439 std::vector<Track> active_track;
440 if (!track_util::GetActiveTrackList(track_, active_track)) {
443 trackrenderer_->SetIniProperty(es_conf::ini_property);
444 for (const auto& track : active_track) {
445 switch (track.type) {
446 case kTrackTypeAudio: {
447 std::lock_guard<std::mutex> lock2(eos_mutex_);
448 eos_status_ = internal::ResetEosStatus(kTrackTypeAudio, eos_status_);
449 need_data_[track.type].mask |= kNeedDataMaskByPrepare;
452 case kTrackTypeVideo: {
453 std::lock_guard<std::mutex> lock2(eos_mutex_);
454 eos_status_ = internal::ResetEosStatus(kTrackTypeVideo, eos_status_);
455 need_data_[track.type].mask |= kNeedDataMaskByPrepare;
462 trackrenderer_->SetTrack(active_track);
464 SetTrackRendererAttributes_();
466 LOG_ERROR_P(this, "SetTrackRendererAttributes_ failed");
469 if (!trackrenderer_->Prepare()) {
472 performance_checker::End(start, "Prepare");
475 es_event::Prepare event{op};
476 if (!state_manager_.ProcessEvent(event)) {
483 void EsPlayer::PrepareTask_() {
484 bool ret = Prepare_();
486 state_manager_.SetPreparingState(false);
487 if (eventlistener_) {
488 LOG_INFO_P(this, "Prepare completely, call OnPrepareDone(%d)", ret);
489 eventlistener_->OnPrepareDone(ret, eventlistener_userdata_);
495 bool EsPlayer::PrepareAsync() {
497 state_manager_.SetPreparingState(true);
498 preparetask_ = std::async(std::launch::async, &EsPlayer::PrepareTask_, this);
499 if (!preparetask_.valid()) {
500 state_manager_.SetPreparingState(false);
506 bool EsPlayer::Pause() {
509 LOG_ERROR_P(this, "Stop already, no need to pause,leave...");
512 if (state_manager_.GetState() < EsState::kReady) {
513 LOG_ERROR_P(this, "Invalid State , current %d",
514 state_manager_.GetStateEnum());
517 auto op = [this]() noexcept -> bool {
518 if (!trackrenderer_) return false;
519 if (!trackrenderer_->Pause()) {
524 for (const auto& track : track_) {
525 es_packet_logger_.PrintStoredPacketInfo(
526 internal::ConvertToStreamType(track.type), true);
528 es_event::Pause event{op};
529 return state_manager_.ProcessEvent(event);
532 bool EsPlayer::Resume() {
535 LOG_ERROR_P(this, "Stop already, no need to Resume,leave...");
538 if (state_manager_.GetState() <= EsState::kReady) {
539 LOG_ERROR_P(this, "Invalid State , current %d",
540 state_manager_.GetStateEnum());
543 if (is_resource_conflicted_) {
544 LOG_ERROR_P(this, "Resume fail resource conflicted");
547 auto op = [this]() noexcept -> bool {
548 if (!trackrenderer_) return false;
549 if (!trackrenderer_->Resume()) {
554 for (const auto& track : track_) {
555 es_packet_logger_.PrintStoredPacketInfo(
556 internal::ConvertToStreamType(track.type), true);
558 es_event::Resume event{op};
559 return state_manager_.ProcessEvent(event);
562 bool EsPlayer::Seek(const uint64_t time_millisecond) {
563 if (state_manager_.GetState() < EsState::kIdle) {
564 LOG_ERROR_P(this, "Invalid State , current %d",
565 state_manager_.GetStateEnum());
568 if (state_manager_.GetState() == EsState::kIdle) {
569 if (state_manager_.GetPreparingState()) {
570 LOG_ERROR_P(this, "Invalid State , during preparing");
573 LOG_ERROR("[%p] > resume time [%" PRIu64 " ms]", this, time_millisecond);
574 resume_time_.is_set = true;
575 resume_time_.time = time_millisecond;
578 is_seek_done_need_drop = true;
579 LOG_DEBUG("[%p] > [ENTER] seek time [%" PRIu64 " ms]", this, time_millisecond);
580 for (const auto& track : track_) {
581 std::lock_guard<std::mutex> lock2(eos_mutex_);
582 eos_status_ = internal::ResetEosStatus(track.type, eos_status_);
583 es_packet_logger_.PrintStoredPacketInfo(
584 internal::ConvertToStreamType(track.type), true);
586 auto op = [this, time_millisecond]() -> bool {
587 if (!trackrenderer_->Seek(time_millisecond, current_playback_rate_,
588 current_audio_mute_)) {
593 es_event::Seek event{op};
595 bool ret = state_manager_.ProcessEvent(event);
596 is_seek_done_need_drop = false;
598 if (eventlistener_) {
599 if (internal::IsLowLatencyModeDisableAVSync(low_latency_mode_) ||
600 internal::IsLowLatencyModeDisablePreroll(low_latency_mode_)) {
601 auto listener = std::bind(&plusplayer::EsEventListener::OnSeekDone,
602 eventlistener_, std::placeholders::_1);
603 auto msg = es_msg::Simple::Make(listener, eventlistener_userdata_);
604 std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
605 msg_queue_.push(std::move(msg));
607 msg_task_cv_.notify_one();
611 LOG_DEBUG("%p, [LEAVE] seek end ", this);
616 bool EsPlayer::SetPlaybackRate(const double rate, const bool audio_mute) {
619 if (rate <= 0 || rate > 2.0) {
620 LOG_ERROR_P(this, "Not a valid PlaybackRate");
624 if (state_manager_.GetState() < EsState::kReady) {
625 LOG_ERROR_P(this, "Invalid State , current %d",
626 state_manager_.GetStateEnum());
630 auto op = [this, rate, audio_mute]() -> bool {
631 if (!trackrenderer_->SetPlaybackRate(rate, audio_mute)) {
634 current_playback_rate_ = rate;
635 current_audio_mute_ = audio_mute;
638 es_event::PlaybackRate event{op};
639 bool ret = state_manager_.ProcessEvent(event);
645 bool EsPlayer::SetDisplay(const DisplayType& type, void* obj) {
646 if (state_manager_.GetState() != EsState::kIdle) {
647 LOG_ERROR_P(this, "Invalid State , current %d",
648 state_manager_.GetStateEnum());
651 return trackrenderer_->SetDisplay(type, obj);
654 bool EsPlayer::SetDisplay(const DisplayType& type, void* ecore_wl2_window,
655 const int x, const int y, const int w, const int h) {
656 if (state_manager_.GetState() != EsState::kIdle) {
657 LOG_ERROR_P(this, "Invalid State , current %d",
658 state_manager_.GetStateEnum());
661 return trackrenderer_->SetDisplay(type, ecore_wl2_window, x, y, w, h);
664 bool EsPlayer::SetDisplay(const DisplayType& type, unsigned int surface_id,
665 const int x, const int y, const int w, const int h) {
666 if (state_manager_.GetState() != EsState::kIdle) {
667 LOG_ERROR_P(this, "Invalid State , current %d",
668 state_manager_.GetStateEnum());
671 return trackrenderer_->SetDisplay(type, surface_id, x, y, w, h);
674 bool EsPlayer::SetDisplayMode(const DisplayMode& mode) {
675 if (state_manager_.GetState() < EsState::kIdle) {
676 LOG_ERROR_P(this, "Invalid State , current %d",
677 state_manager_.GetStateEnum());
680 trackrenderer_->SetDisplayMode(mode);
684 bool EsPlayer::SetDisplayRoi(const Geometry& roi) {
685 if (state_manager_.GetState() < EsState::kIdle) {
686 LOG_ERROR_P(this, "Invalid State , current %d",
687 state_manager_.GetStateEnum());
690 return trackrenderer_->SetDisplayRoi(roi);
693 bool EsPlayer::SetVideoRoi(const CropArea& area) {
694 if (state_manager_.GetState() < EsState::kIdle) {
695 LOG_ERROR_P(this, "Invalid State , current %d",
696 state_manager_.GetStateEnum());
699 return trackrenderer_->SetVideoRoi(area);
702 bool EsPlayer::SetDisplayRotate(const DisplayRotation& rotate) {
703 if (state_manager_.GetState() < EsState::kIdle) {
704 LOG_ERROR_P(this, "Invalid State , current %d",
705 state_manager_.GetStateEnum());
708 return trackrenderer_->SetDisplayRotate(rotate);
711 bool EsPlayer::GetDisplayRotate(DisplayRotation* rotate) {
712 if (state_manager_.GetState() < EsState::kIdle) {
713 LOG_ERROR_P(this, "Invalid State , current %d",
714 state_manager_.GetStateEnum());
717 if (trackrenderer_->GetDisplayRotate(rotate)) {
723 bool EsPlayer::SetDisplayVisible(bool is_visible) {
724 if (state_manager_.GetState() < EsState::kIdle) {
725 LOG_ERROR_P(this, "Invalid State , current %d",
726 state_manager_.GetStateEnum());
729 return trackrenderer_->SetDisplayVisible(is_visible);
732 bool EsPlayer::SetTrustZoneUse(bool is_using_tz) {
733 if (state_manager_.GetState() != EsState::kIdle) {
734 LOG_ERROR_P(this, "Invalid State , current %d",
735 state_manager_.GetStateEnum());
738 if (drm_property_.type != drm::Type::kNone) {
739 LOG_ERROR_P(this, "drm type is already set for sending encrypted packets");
742 LOG_INFO_P(this, "set trust zone use [%d]", is_using_tz);
743 drm_property_.external_decryption = is_using_tz;
745 drm::Property drm_property = drm_property_;
746 drm_property.type = drm::Type::kPlayready;
747 trackrenderer_->SetDrm(drm_property);
751 bool EsPlayer::SetSubmitDataType(SubmitDataType type) {
752 if (state_manager_.GetState() != EsState::kIdle) {
753 LOG_ERROR_P(this, "Invalid State , current %d",
754 state_manager_.GetStateEnum());
757 LOG_INFO_P(this, "set submit data type [%d]", static_cast<int>(type));
759 if (type == SubmitDataType::kCleanData) return true;
760 submit_data_type_ = type;
761 if (type == SubmitDataType::kEncryptedData) {
762 drm_property_.type = drm::Type::kPlayready;
763 // TODO: following SubmitDataType, need to set external_decryption
764 drm_property_.external_decryption = true;
765 drm::Property drm_property = drm_property_;
766 trackrenderer_->SetDrm(drm_property);
771 bool EsPlayer::SetTrack_(const Track& track) {
773 track_.push_back(std::move(track));
777 bool EsPlayer::ChangeStream_(const Track& track) {
778 TrackType type = track.type;
779 if (track_.empty()) return false;
780 auto has_track = [type](const Track& item) -> bool {
781 return item.type == type;
783 std::lock_guard<std::mutex> lk(submit_mutex_);
784 auto target = std::find_if(track_.begin(), track_.end(), has_track);
785 if (target == track_.end()) {
786 LOG_ERROR_P(this, "Add a new stream.");
790 if (target->active != false) {
791 LOG_ERROR_P(this, "The track should be deactivated in advance.");
794 track_.erase(target);
795 LOG_ERROR_P(this, "previously added %s stream is deleted",
796 (type == kTrackTypeAudio) ? "audio" : "video");
797 return SetTrack_(track);
800 bool EsPlayer::SetStream_(const Track& track) {
801 TrackType type = track.type;
802 if (!track_.empty()) {
803 auto has_track = [type](const Track& item) -> bool {
804 return item.type == type;
806 auto target = std::find_if(track_.begin(), track_.end(), has_track);
807 if (target != track_.end()) {
808 LOG_ERROR_P(this, "Stream is already exist");
812 auto op = [this, track]() noexcept {
813 if (!SetTrack_(track)) {
818 es_event::SetStream event{op};
819 return state_manager_.ProcessEvent(event);
822 bool EsPlayer::SetStream(const AudioStreamPtr& stream) {
825 BOOST_SCOPE_EXIT(&ret, &stream, &force_audio_swdecoder_use_) {
826 if (ret) force_audio_swdecoder_use_ = stream->GetForceSwDecoderUse();
829 if (state_manager_.GetState() < EsState::kIdle) {
830 LOG_ERROR_P(this, "Invalid State , current %d",
831 state_manager_.GetStateEnum());
834 Track track = stream->GetTrack_();
835 if (state_manager_.GetState() >= EsState::kReady) {
836 track.active = false;
837 ret = ChangeStream_(track);
840 ret = SetStream_(track);
844 bool EsPlayer::SetStream(const VideoStreamPtr& stream) {
846 if (state_manager_.GetState() < EsState::kIdle) {
847 LOG_ERROR_P(this, "Invalid State , current %d",
848 state_manager_.GetStateEnum());
851 Track track = stream->GetTrack_();
852 if (state_manager_.GetState() >= EsState::kReady) {
853 track.active = false;
854 return ChangeStream_(track);
856 return SetStream_(track);
859 GetDecodedVideoFrameStatus EsPlayer::GetDecodedPacket(
860 DecodedVideoPacket& packet) {
861 if (state_manager_.GetState() < EsState::kReady) {
862 LOG_ERROR_P(this, "Invalid State , current %d",
863 state_manager_.GetStateEnum());
864 return GetDecodedVideoFrameStatus::kUnknown;
866 return trackrenderer_->GetDecodedPacket(packet);
869 bool EsPlayer::ReturnDecodedPacket(const DecodedVideoPacket& packet) {
870 if (state_manager_.GetState() < EsState::kReady) {
871 LOG_ERROR_P(this, "Invalid State , current %d",
872 state_manager_.GetStateEnum());
875 return trackrenderer_->ReturnDecodedPacket(packet);
878 void EsPlayer::ResetContextForClose_() {
879 internal::ResetDrmProperty(drm_property_);
881 submit_data_type_ = SubmitDataType::kCleanData;
882 low_latency_mode_ = 0;
883 resume_time_.is_set = false;
884 unlimited_max_buffer_mode_ = 0;
885 audio_codec_type_ = kPlayerAudioCodecTypeHW;
886 video_codec_type_ = kPlayerVideoCodecTypeHW;
887 is_resource_conflicted_ = false;
888 src_queue_size_ = SrcQueueSize();
889 is_msg_task_stop_ = false;
892 void EsPlayer::ResetContextForStop_() {
893 for (int i = 0; i < kTrackTypeMax; ++i) {
894 need_data_[i].mask = kNeedDataMaskNone;
895 need_data_[i].seek_offset = 0;
898 std::lock_guard<std::mutex> lock(eos_mutex_);
899 eos_status_ = EosStatus::kAllEos;
901 current_playback_rate_ = 1.0;
902 current_audio_mute_ = false;
905 void EsPlayer::GetSrcQueueCurrentSize_(const TrackType& type,
907 uint64_t* time_size) {
908 boost::any byte_size_, time_size_;
909 if (type == TrackType::kTrackTypeVideo) {
910 trackrenderer_->GetAttribute(
911 TrackRendererAdapter::Attribute::kVideoQueueCurrentLevelByte,
913 } else if (type == TrackType::kTrackTypeAudio) {
914 trackrenderer_->GetAttribute(
915 TrackRendererAdapter::Attribute::kAudioQueueCurrentLevelByte,
919 *byte_size = boost::any_cast<std::uint64_t>(byte_size_);
923 GstBuffer* EsPlayer::GetGstBuffer_(const EsPacketPtr& packet,
924 MakeBufferStatus* status) {
925 std::shared_ptr<char> buffer = packet->GetBuffer();
926 uint32_t size = packet->GetSize();
927 if (packet->IsEosPacket()) {
928 *status = MakeBufferStatus::kEos;
931 GstBuffer* gstbuffer = gst_buffer_new_and_alloc(size);
933 *status = MakeBufferStatus::kOutOfMemory;
936 if (buffer != nullptr) {
938 gst_buffer_map(gstbuffer, &map, GST_MAP_WRITE);
939 memcpy(map.data, buffer.get(), size);
940 gst_buffer_unmap(gstbuffer, &map);
943 uint64_t pts = packet->GetPts();
944 uint64_t duration = packet->GetDuration();
945 /* if pts or duration are -1(=GST_CLOCK_TIME_NONE), some of the elements don't
946 * adjust the buffer. */
947 GST_BUFFER_PTS(gstbuffer) = (pts == GST_CLOCK_TIME_NONE)
948 ? GST_CLOCK_TIME_NONE
949 : (GstClockTime)util::ConvertMsToNs(pts);
950 GST_BUFFER_DURATION(gstbuffer) =
951 (duration == GST_CLOCK_TIME_NONE)
952 ? GST_CLOCK_TIME_NONE
953 : (GstClockTime)util::ConvertMsToNs(duration);
954 uint32_t hdr10p_size = packet->GetHdr10pSize();
955 std::shared_ptr<char> hdr10p_metadata = packet->GetHdr10pData();
957 if (hdr10p_size > 0 && hdr10p_metadata != nullptr) {
958 guint32* blockadditional_size = (guint32*)g_malloc(sizeof(uint32_t));
959 *blockadditional_size = hdr10p_size;
960 gst_mini_object_set_qdata(
961 GST_MINI_OBJECT(gstbuffer),
962 g_quark_from_static_string("matroska_blockadditional_size"),
963 blockadditional_size, g_free);
965 /* blockadditional_data : the data sent to omx, size (4 bytes) + metadata */
966 guint8* blockadditional_data =
967 (guint8*)g_malloc(((*blockadditional_size) + 4) * sizeof(guint8));
968 memcpy(blockadditional_data, blockadditional_size, sizeof(uint32_t));
969 memcpy(blockadditional_data + 4, hdr10p_metadata.get(),
970 (*blockadditional_size));
971 gst_mini_object_set_qdata(
972 GST_MINI_OBJECT(gstbuffer),
973 g_quark_from_static_string("matroska_blockadditional_info"),
974 blockadditional_data, g_free);
976 *status = MakeBufferStatus::kSuccess;
980 PacketSubmitStatus EsPlayer::SubmitEosPacket_(const TrackType& type) {
981 PacketSubmitStatus submitstate = PacketSubmitStatus::kSuccess;
983 std::lock_guard<std::mutex> lock(eos_mutex_);
985 case kTrackTypeAudio:
986 eos_status_ |= EosStatus::kAudioEos;
988 case kTrackTypeVideo:
989 eos_status_ |= EosStatus::kVideoEos;
994 if (eos_status_ != EosStatus::kAllEos) {
998 for (int tracktype = kTrackTypeAudio; tracktype < kTrackTypeMax;
1001 DecoderInputBuffer::Create(static_cast<TrackType>(tracktype));
1002 if (!trackrenderer_->SubmitPacket2(inbuffer, nullptr)) {
1003 std::lock_guard<std::mutex> lock(eos_mutex_);
1004 eos_status_ = EosStatus::kAllEos;
1005 submitstate = PacketSubmitStatus::kNotPrepared;
1012 void EsPlayer::UnsetTzQdata_(const DecoderInputBufferPtr& buffer) {
1013 const GstBuffer* gstbuf = buffer->Get();
1014 if (!gstbuf) return;
1015 GstStructure* tzqdata = GST_STRUCTURE(gst_mini_object_steal_qdata(
1016 GST_MINI_OBJECT(gstbuf), g_quark_from_static_string("GstTzHandleData")));
1017 if (tzqdata) gst_structure_free(tzqdata);
1020 PacketSubmitStatus EsPlayer::SubmitDecoderInputBuffer_(
1021 const DecoderInputBufferPtr& buffer) {
1022 PacketSubmitStatus status = PacketSubmitStatus::kSuccess;
1023 TrackRendererAdapter::SubmitStatus submitstate =
1024 TrackRendererAdapter::SubmitStatus::kSuccess;
1025 trackrenderer_->SubmitPacket2(buffer, &submitstate);
1027 switch (submitstate) {
1028 case TrackRendererAdapter::SubmitStatus::kSuccess:
1029 case TrackRendererAdapter::SubmitStatus::kDrop:
1030 status = PacketSubmitStatus::kSuccess;
1032 case TrackRendererAdapter::SubmitStatus::kFull:
1033 UnsetTzQdata_(buffer);
1034 trackrenderer_event_listener_->OnBufferStatus(buffer->GetType(),
1035 BufferStatus::kOverrun);
1036 status = PacketSubmitStatus::kFull;
1039 UnsetTzQdata_(buffer);
1040 status = PacketSubmitStatus::kNotPrepared;
1046 void EsPlayer::MakeGstBufferForTzHandle_(GstBuffer* gstbuffer,
1047 const TrackType& type,
1048 const uint32_t& tz_handle,
1049 const uint32_t& packet_size) {
1050 GstStructure* gst_tz_handle_data_structure =
1051 gst_structure_new("GstTzHandleData", "packet_handle", G_TYPE_UINT,
1052 static_cast<guint32>(tz_handle), "packet_size",
1053 G_TYPE_UINT, static_cast<guint32>(packet_size),
1054 "secure", G_TYPE_BOOLEAN, true, nullptr);
1055 gst_mini_object_set_qdata(
1056 GST_MINI_OBJECT(gstbuffer), g_quark_from_string("GstTzHandleData"),
1057 gst_tz_handle_data_structure, (GDestroyNotify)gst_structure_free);
1059 if (type == kTrackTypeAudio) {
1061 bool has_active_audio_track =
1062 track_util::GetActiveTrack(track_, kTrackTypeAudio, &audio_track);
1063 if (has_active_audio_track) {
1064 GstStructure* audio_info_structure =
1065 gst_structure_new("AudioInfo", "mime_type", G_TYPE_STRING,
1066 audio_track.mimetype.c_str(), nullptr);
1067 gst_mini_object_set_qdata(
1068 GST_MINI_OBJECT(gstbuffer), g_quark_from_string("AudioInfo"),
1069 audio_info_structure, (GDestroyNotify)gst_structure_free);
1074 void EsPlayer::MakeGstBufferForEncryptedPacket_(
1075 GstBuffer* gstbuffer, const EsPacketPtr& packet,
1076 const drm::EsPlayerEncryptedInfo& drm_info) {
1077 if (drm_info.handle == 0) return;
1078 auto serialized_drm_info_ptr = esplayer_drm::Serialize(packet, drm_info);
1079 GstStructure* gst_drm_info_structure =
1080 gst_structure_new("drm_info", "drm_specific_info", G_TYPE_BYTES,
1081 serialized_drm_info_ptr.get(), nullptr);
1082 if (gst_drm_info_structure) {
1083 gst_mini_object_set_qdata(
1084 GST_MINI_OBJECT(gstbuffer), g_quark_from_static_string("drm_info"),
1085 gst_drm_info_structure, (GDestroyNotify)gst_structure_free);
1089 PacketSubmitStatus EsPlayer::SubmitPacketCommon_(const EsPacketPtr& packet,
1090 SubmitPacketOperator op) {
1091 if (state_manager_.GetState() < EsState::kIdle) {
1092 return PacketSubmitStatus::kNotPrepared;
1094 if (!packet) return PacketSubmitStatus::kInvalidPacket;
1096 TrackType type = static_cast<TrackType>(packet->GetType());
1097 Track activated_track;
1098 if (!track_util::GetActiveTrack(track_, type, &activated_track))
1099 return PacketSubmitStatus::kInvalidPacket;
1101 if (state_manager_.GetState() == EsState::kPaused ||
1102 state_manager_.GetState() == EsState::kReady) {
1103 internal::AppsrcQueueSizeOption byte_based, time_based;
1105 case kTrackTypeAudio:
1106 byte_based.max_size = src_queue_size_.kMaxByteOfAudioSrcQueue;
1107 time_based.max_size = src_queue_size_.kMaxTimeOfAudioSrcQueue;
1108 byte_based.threshold = src_queue_size_.kMinByteThresholdOfAudioSrcQueue;
1109 time_based.threshold = src_queue_size_.kMinTimeThresholdOfAudioSrcQueue;
1111 case kTrackTypeVideo:
1112 byte_based.max_size = src_queue_size_.kMaxByteOfVideoSrcQueue;
1113 time_based.max_size = src_queue_size_.kMaxTimeOfVideoSrcQueue;
1114 byte_based.threshold = src_queue_size_.kMinByteThresholdOfVideoSrcQueue;
1115 time_based.threshold = src_queue_size_.kMinTimeThresholdOfVideoSrcQueue;
1120 GetSrcQueueCurrentSize_(type, &(byte_based.current_size),
1121 &(time_based.current_size));
1122 if (internal::IsUnderRun(byte_based, time_based))
1123 trackrenderer_event_listener_->OnBufferStatus(type,
1124 BufferStatus::kUnderrun);
1127 es_packet_logger_.StorePacketInfo(packet);
1128 es_packet_logger_.PrintStoredPacketInfo(packet->GetType());
1130 MakeBufferStatus make_buffer_status;
1131 GstBuffer* gstbuffer = GetGstBuffer_(packet, &make_buffer_status);
1133 if (make_buffer_status == MakeBufferStatus::kEos)
1134 return SubmitEosPacket_(type);
1135 else if (make_buffer_status == MakeBufferStatus::kOutOfMemory)
1136 return PacketSubmitStatus::kOutOfMemory;
1138 if (op != nullptr) {
1139 PacketSubmitStatus op_status = op(gstbuffer);
1140 if (op_status != PacketSubmitStatus::kSuccess) {
1145 auto inbuffer = DecoderInputBuffer::Create(type, 0, gstbuffer);
1146 gst_buffer_unref(gstbuffer);
1148 if (packet->HasMatroskaColorInfo()) {
1149 std::string color_info_str =
1150 util::GetStringFromMatroskaColor(packet->GetMatroskaColorInfo());
1151 LOG_DEBUG_P(this, "Detected MatroskaColor : %s", color_info_str.c_str());
1152 if (trackrenderer_->SetMatroskaColorInfo(color_info_str) == false)
1153 return PacketSubmitStatus::kNotPrepared;
1156 return SubmitDecoderInputBuffer_(inbuffer);
1159 PacketSubmitStatus EsPlayer::SubmitPacket(const EsPacketPtr& packet) {
1160 std::lock_guard<std::mutex> lk(submit_mutex_);
1161 return SubmitPacketCommon_(packet, nullptr);
1164 PacketSubmitStatus EsPlayer::SubmitTrustZonePacket(const EsPacketPtr& packet,
1165 uint32_t tz_handle) {
1166 std::lock_guard<std::mutex> lk(submit_mutex_);
1167 if (submit_data_type_ != SubmitDataType::kTrustZoneData)
1168 return PacketSubmitStatus::kInvalidPacket;
1169 auto submitpacket_op = [this, &tz_handle,
1170 &packet](GstBuffer* gstbuffer) -> PacketSubmitStatus {
1171 if (tz_handle > 0) {
1172 TrackType type = static_cast<TrackType>(packet->GetType());
1173 uint32_t packet_size = packet->GetSize();
1174 MakeGstBufferForTzHandle_(gstbuffer, type, tz_handle, packet_size);
1176 return PacketSubmitStatus::kSuccess;
1178 return SubmitPacketCommon_(packet, submitpacket_op);
1181 PacketSubmitStatus EsPlayer::SubmitEncryptedPacket(
1182 const EsPacketPtr& packet, const drm::EsPlayerEncryptedInfo& drm_info) {
1183 std::lock_guard<std::mutex> lk(submit_mutex_);
1184 if (submit_data_type_ != SubmitDataType::kEncryptedData)
1185 return PacketSubmitStatus::kInvalidPacket;
1186 auto submitpacket_op =
1187 [this, &packet, &drm_info](GstBuffer* gstbuffer) -> PacketSubmitStatus {
1188 MakeGstBufferForEncryptedPacket_(gstbuffer, packet, drm_info);
1189 return PacketSubmitStatus::kSuccess;
1191 return SubmitPacketCommon_(packet, submitpacket_op);
1194 EsState EsPlayer::GetState() { return state_manager_.GetState(); }
1196 bool EsPlayer::GetPlayingTime(uint64_t* time_in_milliseconds) {
1197 if (!time_in_milliseconds) return false;
1198 if (state_manager_.GetState() <= EsState::kReady) {
1199 *time_in_milliseconds = 0;
1202 return trackrenderer_->GetPlayingTime(time_in_milliseconds);
1205 bool EsPlayer::SetAudioMute(bool is_mute) {
1206 if (state_manager_.GetState() < EsState::kIdle) {
1207 LOG_ERROR_P(this, "Invalid State , current %d",
1208 state_manager_.GetStateEnum());
1211 return trackrenderer_->SetAudioMute(is_mute);
1214 bool EsPlayer::SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
1215 if (state_manager_.GetState() != EsState::kIdle) {
1216 LOG_ERROR("Invalid State , current %d", state_manager_.GetStateEnum());
1219 trackrenderer_->SetVideoFrameBufferType(type);
1223 void EsPlayer::RegisterListener(EsEventListener* listener,
1224 EsEventListener::UserData userdata) {
1225 // assert(listener); // allow unregister by setting nullptr
1226 assert(!eventlistener_);
1227 eventlistener_ = listener;
1228 eventlistener_userdata_ = userdata;
1231 bool EsPlayer::GetAdaptiveInfo(void* padaptive_info,
1232 const PlayerAdaptiveInfo& adaptive_type) {
1233 if (!padaptive_info || adaptive_type <= PlayerAdaptiveInfo::kMinType ||
1234 adaptive_type >= PlayerAdaptiveInfo::kMaxType)
1236 switch (adaptive_type) {
1237 case PlayerAdaptiveInfo::kVideoDroppedFrames:
1238 if (state_manager_.GetState() < EsState::kReady) {
1239 LOG_ERROR_P(this, "Wrong state, we aren't started yet");
1242 return trackrenderer_->GetDroppedFrames(padaptive_info);
1243 case PlayerAdaptiveInfo::kDroppedVideoFramesForCatchup:
1244 if (state_manager_.GetState() < EsState::kReady) {
1245 LOG_ERROR_P(this, "Wrong state, we aren't started yet");
1248 return trackrenderer_->GetDroppedFramesForCatchup(kTrackTypeVideo,
1250 case PlayerAdaptiveInfo::kDroppedAudioFramesForCatchup:
1251 if (state_manager_.GetState() < EsState::kReady) {
1252 LOG_ERROR_P(this, "Wrong state, we aren't started yet");
1255 return trackrenderer_->GetDroppedFramesForCatchup(kTrackTypeAudio,
1263 bool EsPlayer::SetVolume(const int& volume) {
1264 if (volume < internal::kVolumeMin || volume > internal::kVolumeMax) {
1265 LOG_ERROR_P(this, "Invalid volume level %d", volume);
1268 if (state_manager_.GetState() < EsState::kIdle) {
1269 LOG_ERROR_P(this, "Invalid State , current %d",
1270 state_manager_.GetStateEnum());
1273 return trackrenderer_->SetVolume(volume);
1276 bool EsPlayer::GetVolume(int* volume) {
1277 if (state_manager_.GetState() < EsState::kIdle) {
1278 LOG_ERROR_P(this, "Invalid State , current %d",
1279 state_manager_.GetStateEnum());
1282 return trackrenderer_->GetVolume(volume);
1285 bool EsPlayer::Flush(const StreamType& type) {
1286 if (state_manager_.GetState() <= EsState::kIdle) {
1287 LOG_ERROR_P(this, "Invalid State , current %d",
1288 state_manager_.GetStateEnum());
1291 std::lock_guard<std::mutex> lock2(eos_mutex_);
1293 internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
1294 es_packet_logger_.ResetLog(type);
1295 return trackrenderer_->Flush(type);
1298 void EsPlayer::SetBufferSize(const BufferOption& option, uint64_t size) {
1299 if (state_manager_.GetState() != EsState::kIdle) {
1300 LOG_ERROR_P(this, "Invalid State , current %d",
1301 state_manager_.GetStateEnum());
1305 case BufferOption::kBufferAudioMaxByteSize:
1306 src_queue_size_.kMaxByteOfAudioSrcQueue = size;
1308 case BufferOption::kBufferVideoMaxByteSize:
1309 src_queue_size_.kMaxByteOfVideoSrcQueue = size;
1311 case BufferOption::kBufferAudioMinByteThreshold:
1312 src_queue_size_.kMinByteThresholdOfAudioSrcQueue =
1313 static_cast<uint32_t>(size);
1315 case BufferOption::kBufferVideoMinByteThreshold:
1316 src_queue_size_.kMinByteThresholdOfVideoSrcQueue =
1317 static_cast<uint32_t>(size);
1319 case BufferOption::kBufferAudioMaxTimeSize:
1320 src_queue_size_.kMaxTimeOfAudioSrcQueue = size;
1322 case BufferOption::kBufferVideoMaxTimeSize:
1323 src_queue_size_.kMaxTimeOfVideoSrcQueue = size;
1325 case BufferOption::kBufferAudioMinTimeThreshold:
1326 src_queue_size_.kMinTimeThresholdOfAudioSrcQueue =
1327 static_cast<uint32_t>(size);
1329 case BufferOption::kBufferVideoMinTimeThreshold:
1330 src_queue_size_.kMinTimeThresholdOfVideoSrcQueue =
1331 static_cast<uint32_t>(size);
1334 LOG_ERROR_P(this, "Invalid option!!!");
1339 bool EsPlayer::SetLowLatencyMode(const PlayerLowLatencyMode& mode) {
1340 if (state_manager_.GetState() != EsState::kIdle) {
1341 LOG_ERROR_P(this, "Invalid State , current %d",
1342 state_manager_.GetStateEnum());
1345 low_latency_mode_ |= static_cast<std::uint32_t>(mode);
1349 bool EsPlayer::SetUnlimitedMaxBufferMode() {
1350 if (state_manager_.GetState() != EsState::kIdle) {
1351 LOG_ERROR_P(this, "Invalid State , current %d",
1352 state_manager_.GetStateEnum());
1355 constexpr std::uint32_t unlimited_max_buffer_mode_on = 1;
1356 unlimited_max_buffer_mode_ = unlimited_max_buffer_mode_on;
1360 bool EsPlayer::SetAudioCodecType(const PlayerAudioCodecType& type) {
1361 Track activated_track;
1363 track_util::GetActiveTrack(track_, kTrackTypeAudio, &activated_track);
1364 EsState state = state_manager_.GetState();
1365 if ((state < EsState::kIdle) || (state > EsState::kIdle && is_existed)) {
1367 "Invalid State [state:%d] or audio stream already exists[%d],",
1368 state_manager_.GetStateEnum(), is_existed);
1371 if (force_audio_swdecoder_use_ && type == kPlayerAudioCodecTypeHW) {
1372 LOG_ERROR_P(this, "Not support hw decoder");
1375 LOG_INFO_P(this, "PlayerAudioCodecType [%s]",
1376 (type == kPlayerAudioCodecTypeHW) ? "hardware" : "software");
1377 audio_codec_type_ = type;
1381 bool EsPlayer::SetVideoCodecType(const PlayerVideoCodecType& type) {
1382 Track activated_track;
1384 track_util::GetActiveTrack(track_, kTrackTypeVideo, &activated_track);
1385 EsState state = state_manager_.GetState();
1386 if ((state < EsState::kIdle) || (state > EsState::kIdle && is_existed)) {
1388 "Invalid State [state:%d] or video stream already exists[%d],",
1389 state_manager_.GetStateEnum(), is_existed);
1392 if (type == kPlayerVideoCodecTypeSW &&
1393 vidoe_frame_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
1395 "sw video decoder is not supported when video frame buffer "
1399 LOG_INFO_P(this, "PlayerVideoCodecType [%s]",
1400 (type == kPlayerVideoCodecTypeHW) ? "hardware" : "software");
1401 video_codec_type_ = type;
1406 bool EsPlayer::SetRenderTimeOffset(const StreamType type, int64_t offset) {
1407 if (state_manager_.GetState() < EsState::kReady) {
1408 LOG_ERROR_P(this, "Invalid State , current %d",
1409 state_manager_.GetStateEnum());
1412 if (!internal::IsSupportedTsOffset(low_latency_mode_)) {
1414 "low latency mode have to be set except disable_sync mode");
1417 /* FIME: time unit api will be added to support both ms and us */
1418 if ((offset * 1000000 > G_MAXINT64) || (offset * 1000000 < G_MININT64)) {
1419 LOG_ERROR("%p, wrong value : G_MAXINT64 < offset[%" PRId64
1420 "] * 1000000 < G_MAXINT64",
1424 if (type == StreamType::kMax) return false;
1425 if (type == StreamType::kAudio)
1426 trackrenderer_->SetAttribute(
1427 TrackRendererAdapter::Attribute::kAudioRenderTimeOffset,
1428 util::ConvertMsToNs(offset));
1429 else if (type == StreamType::kVideo)
1430 trackrenderer_->SetAttribute(
1431 TrackRendererAdapter::Attribute::kVideoRenderTimeOffset,
1432 util::ConvertMsToNs(offset));
1436 bool EsPlayer::GetRenderTimeOffset(const StreamType type, int64_t* offset) {
1437 if (state_manager_.GetState() < EsState::kReady) {
1438 LOG_ERROR_P(this, "Invalid State , current %d",
1439 state_manager_.GetStateEnum());
1442 if (!internal::IsSupportedTsOffset(low_latency_mode_)) {
1443 LOG_ERROR_P(this, "low latency mode have to be set");
1446 if (type == StreamType::kMax) return false;
1448 if (type == StreamType::kAudio)
1449 trackrenderer_->GetAttribute(
1450 TrackRendererAdapter::Attribute::kAudioRenderTimeOffset, &off_set);
1451 else if (type == StreamType::kVideo)
1452 trackrenderer_->GetAttribute(
1453 TrackRendererAdapter::Attribute::kVideoRenderTimeOffset, &off_set);
1455 *offset = util::ConvertNsToMs(boost::any_cast<int64_t>(off_set));
1460 void EsPlayer::Init_() {
1462 is_stopped_ = false;
1466 void EsPlayer::MsgTask_() {
1467 while (!is_msg_task_stop_) {
1468 std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
1469 if (msg_queue_.empty()) {
1470 msg_task_cv_.wait(msg_mutex);
1473 msg_queue_.front()->Execute();
1478 while (!msg_queue_.empty()) {
1479 std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
1482 LOG_INFO_P(this, "Stop MsgTask");
1485 void EsPlayer::TrackRendererEventListener::OnEos() {
1486 LOG_ENTER_P(handler_);
1487 if (!handler_->eventlistener_) return;
1488 auto listener = std::bind(&plusplayer::EsEventListener::OnEos,
1489 handler_->eventlistener_, std::placeholders::_1);
1490 auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
1491 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1492 handler_->msg_queue_.push(std::move(msg));
1494 handler_->msg_task_cv_.notify_one();
1495 LOG_LEAVE_P(handler_);
1498 void EsPlayer::TrackRendererEventListener::OnSeekDone() {
1499 LOG_ENTER_P(handler_);
1500 if (!handler_->eventlistener_) return;
1501 if (handler_->is_seek_done_need_drop == true) return;
1502 auto listener = std::bind(&plusplayer::EsEventListener::OnSeekDone,
1503 handler_->eventlistener_, std::placeholders::_1);
1504 auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
1505 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1506 handler_->msg_queue_.push(std::move(msg));
1508 handler_->msg_task_cv_.notify_one();
1509 LOG_LEAVE_P(handler_);
1512 void EsPlayer::TrackRendererEventListener::OnResourceConflicted() {
1513 LOG_ENTER_P(handler_);
1514 if (handler_->is_stopped_) {
1515 LOG_INFO_P(handler_, "LEAVE ~ Stop is called already");
1518 LOG_INFO_P(handler_, "Handling resource conflict...");
1519 handler_->is_resource_conflicted_ = true;
1520 handler_->trackrenderer_->Stop();
1521 if (!handler_->eventlistener_ || handler_->is_stopped_) return;
1522 auto listener = std::bind(&plusplayer::EsEventListener::OnResourceConflicted,
1523 handler_->eventlistener_, std::placeholders::_1);
1524 auto msg = es_msg::Simple::Make(listener, handler_->eventlistener_userdata_);
1525 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1526 handler_->msg_queue_.push(std::move(msg));
1528 if (handler_->is_stopped_) {
1529 LOG_LEAVE_P(handler_);
1532 handler_->msg_task_cv_.notify_one();
1533 LOG_LEAVE_P(handler_);
1536 void EsPlayer::TrackRendererEventListener::OnError(
1537 const ErrorType& error_code) {
1538 if (!handler_->eventlistener_) return;
1539 if (error_code == ErrorType::kResourceLimit) return;
1541 std::bind(&plusplayer::EsEventListener::OnError, handler_->eventlistener_,
1542 std::placeholders::_1, std::placeholders::_2);
1543 auto msg = es_msg::Error::Make(error_code, listener,
1544 handler_->eventlistener_userdata_);
1546 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1547 handler_->msg_queue_.push(std::move(msg));
1549 handler_->msg_task_cv_.notify_one();
1552 void EsPlayer::TrackRendererEventListener::ReadyToPrepare_(
1553 const TrackType& type) {
1554 LOG_INFO_P(handler_, "OnReadyToPrepare [%s]",
1555 (type == kTrackTypeAudio) ? "audio" : "video");
1557 handler_->need_data_[type].mask &= ~kNeedDataMaskByPrepare;
1559 auto listener = std::bind(&plusplayer::EsEventListener::OnReadyToPrepare,
1560 handler_->eventlistener_, std::placeholders::_1,
1561 std::placeholders::_2);
1562 StreamType stream_type = internal::ConvertToStreamType(type);
1563 auto msg = es_msg::ReadyToPrepare::Make(stream_type, listener,
1564 handler_->eventlistener_userdata_);
1565 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1566 handler_->msg_queue_.push(std::move(msg));
1568 handler_->msg_task_cv_.notify_one();
1571 void EsPlayer::TrackRendererEventListener::ReadyToSeek_(const TrackType& type) {
1572 uint64_t offset = handler_->need_data_[type].seek_offset;
1574 LOG_INFO("[%p] > OnReadyToSeek [%s] offset [%" PRIu64 "]ms", handler_,
1575 (type == kTrackTypeAudio) ? "audio" : "video", offset);
1577 handler_->need_data_[type].mask &= ~kNeedDataMaskBySeek;
1578 handler_->need_data_[type].seek_offset = 0;
1580 auto listener = std::bind(&plusplayer::EsEventListener::OnReadyToSeek,
1581 handler_->eventlistener_, std::placeholders::_1,
1582 std::placeholders::_2, std::placeholders::_3);
1583 StreamType stream_type = internal::ConvertToStreamType(type);
1584 handler_->es_packet_logger_.ResetLog(stream_type);
1585 auto msg = es_msg::ReadyToSeek::Make(stream_type, offset, listener,
1586 handler_->eventlistener_userdata_);
1587 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1588 handler_->msg_queue_.push(std::move(msg));
1590 handler_->msg_task_cv_.notify_one();
1593 void EsPlayer::TrackRendererEventListener::BufferStatus_(
1594 const TrackType& type, const BufferStatus& status) {
1595 uint64_t byte_size, time_size;
1596 // LOG_INFO_P(handler_, "OnBufferStatus [%s] [%s]",
1597 // (type == kTrackTypeAudio) ? "audio" : "video",
1598 // (status == BufferStatus::kUnderrun) ? "underrun" : "overrun");
1599 handler_->GetSrcQueueCurrentSize_(type, &byte_size, &time_size);
1600 auto listener = std::bind(&plusplayer::EsEventListener::OnBufferStatus,
1601 handler_->eventlistener_, std::placeholders::_1,
1602 std::placeholders::_2, std::placeholders::_3,
1603 std::placeholders::_4, std::placeholders::_5);
1604 StreamType stream_type = internal::ConvertToStreamType(type);
1606 es_msg::Bufferstatus::Make(stream_type, status, byte_size, time_size,
1607 listener, handler_->eventlistener_userdata_);
1608 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1609 handler_->msg_queue_.push(std::move(msg));
1611 handler_->msg_task_cv_.notify_one();
1614 void EsPlayer::TrackRendererEventListener::OnBufferStatus(
1615 const TrackType& type, const BufferStatus& status) {
1616 if (!handler_->eventlistener_) return;
1617 if (internal::IsLowLatencyModeDisableAVSync(handler_->low_latency_mode_))
1620 if (handler_->need_data_[type].mask == kNeedDataMaskByPrepare &&
1621 status == BufferStatus::kUnderrun) {
1622 ReadyToPrepare_(type);
1623 } else if (handler_->need_data_[type].mask == kNeedDataMaskBySeek &&
1624 status == BufferStatus::kUnderrun) {
1627 BufferStatus_(type, status);
1631 void EsPlayer::TrackRendererEventListener::OnMediaPacketVideoDecoded(
1632 const DecodedVideoPacket& packet) {
1633 if (!handler_->eventlistener_) return;
1635 handler_->eventlistener_->OnMediaPacketVideoDecoded(packet);
1638 void EsPlayer::TrackRendererEventListener::OnSeekData(const TrackType& type,
1639 const uint64_t offset) {
1640 if (!handler_->eventlistener_) return;
1642 if (handler_->need_data_[type].mask != kNeedDataMaskByPrepare) {
1643 handler_->need_data_[type].mask |= kNeedDataMaskBySeek;
1644 handler_->need_data_[type].seek_offset = offset;
1648 void EsPlayer::TrackRendererEventListener::OnClosedCaptionData(const char* data,
1650 if (size <= 0) return;
1651 if (!handler_->eventlistener_) return;
1652 auto listener = std::bind(&plusplayer::EsEventListener::OnClosedCaptionData,
1653 handler_->eventlistener_, std::placeholders::_1,
1654 std::placeholders::_2, std::placeholders::_3);
1655 auto msg = es_msg::ClosedCaption::Make(data, size, listener,
1656 handler_->eventlistener_userdata_);
1657 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1658 handler_->msg_queue_.push(std::move(msg));
1660 handler_->msg_task_cv_.notify_one();
1663 void EsPlayer::TrackRendererEventListener::OnFlushDone() {
1664 LOG_ENTER_P(handler_);
1665 if (!handler_->eventlistener_) return;
1667 auto listener = std::bind(&plusplayer::EsEventListener::OnFlushDone,
1668 handler_->eventlistener_, std::placeholders::_1);
1670 es_msg::FlushDone::Make(listener, handler_->eventlistener_userdata_);
1671 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1672 handler_->msg_queue_.push(std::move(msg));
1674 handler_->msg_task_cv_.notify_one();
1675 LOG_LEAVE_P(handler_);
1678 void EsPlayer::TrackRendererEventListener::OnEvent(const EventType& event,
1679 const EventMsg& msg_data) {
1680 if (!handler_->eventlistener_) return;
1682 auto listener = std::bind(&plusplayer::EsEventListener::OnEvent,
1683 handler_->eventlistener_, std::placeholders::_1,
1684 std::placeholders::_2, std::placeholders::_3);
1685 auto msg = es_msg::OnEvent::Make(event, msg_data, listener,
1686 handler_->eventlistener_userdata_);
1687 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1688 handler_->msg_queue_.push(std::move(msg));
1690 handler_->msg_task_cv_.notify_one();
1691 LOG_LEAVE_P(handler_);
1694 void EsPlayer::TrackRendererEventListener::OnFirstDecodingDone() {
1695 LOG_ENTER_P(handler_);
1696 if (!handler_->eventlistener_) return;
1697 auto listener = std::bind(&plusplayer::EsEventListener::OnFirstDecodingDone,
1698 handler_->eventlistener_, std::placeholders::_1);
1699 auto msg = es_msg::FirstDecodingDone::Make(listener,
1700 handler_->eventlistener_userdata_);
1701 std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1702 handler_->msg_queue_.push(std::move(msg));
1704 handler_->msg_task_cv_.notify_one();
1705 LOG_LEAVE_P(handler_);
1708 bool EsPlayer::EnableVideoHole(bool value) {
1709 if (state_manager_.GetState() < EsState::kIdle) {
1710 LOG_ERROR_P(this, "Invalid State , current %d",
1711 state_manager_.GetStateEnum());
1714 return trackrenderer_->EnableVideoHole(value);
1719 void LoadIniProperty(const Json::Value& root) {
1720 gst_util::GstInit(root);
1721 std::string key = "generate_dot";
1722 es_conf::ini_property[key] = root.get(key, "").asBool();
1723 LOG_DEBUG("[%s] : [%d]", key.c_str(), es_conf::ini_property[key]);
1725 key = "use_default_video_codec_sw";
1726 es_conf::ini_property[key] = root.get(key, "").asBool();
1727 LOG_DEBUG("[%s] : [%d]", key.c_str(), es_conf::ini_property[key]);
1730 bool LoadIniFile() {
1731 const char* path = plusplayer_cfg::GetIniPath();
1732 LOG_INFO("path : %s", path);
1733 std::streampos size;
1734 char* buf = nullptr;
1735 std::ifstream file(path, std::ios::binary | std::ios::ate);
1736 if (file.is_open() == false) {
1737 gst_util::GstInit();
1738 LOG_ERROR("Can't open file !!");
1741 BOOST_SCOPE_EXIT(&file) { file.close(); }
1742 BOOST_SCOPE_EXIT_END
1744 size = file.tellg();
1746 LOG_ERROR("Wrong file size");
1750 buf = static_cast<char*>(calloc(size, sizeof(char)));
1751 if (buf == nullptr) {
1752 LOG_ERROR("Fail to calloc buf");
1755 BOOST_SCOPE_EXIT(&buf) {
1758 BOOST_SCOPE_EXIT_END
1760 file.seekg(0, std::ios::beg);
1761 file.read(buf, size);
1763 std::string config = buf;
1765 Json::Reader reader;
1766 if (!reader.parse(config, root)) {
1767 LOG_ERROR("Fail to parse configuration file %s",
1768 (reader.getFormatedErrorMessages()).c_str());
1772 es_conf::LoadIniProperty(root);
1776 } // namespace es_conf
1778 } // namespace plusplayer