Support video capture during playback
[platform/core/multimedia/esplusplayer.git] / src / esplusplayer / src / esplayer.cpp
1 //
2 // @ Copyright [2018] <S/W Platform, Visual Display, Samsung Electronics>
3 //
4 // to manipulate TrackRenderer objects
5 // to provide optimized control of TrackRenderer
6
7 #include "esplayer/esplayer.h"
8
9 #include <inttypes.h>
10 #include <boost/scope_exit.hpp>
11 #include <cassert>
12 #include <chrono>
13 #include <fstream>
14 #include <functional>
15 #include <memory>
16 #include <sstream>
17 #include <thread>
18
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"
26
27 namespace plusplayer {
28
29 namespace es_conf {
30
31 // get values from /etc/multimedia/esplusplayer.ini
32 static std::once_flag loaded;
33 static std::map<std::string, bool> ini_property;
34
35 bool LoadIniFile();
36 void LoadIniProperty(const Json::Value& root);
37
38 }  // namespace es_conf
39
40 namespace util {
41
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;
45   return ms * ns_unit;
46 }
47 std::uint64_t ConvertNsToMs(std::uint64_t ns) {
48   constexpr std::uint64_t ms_unit = 1000000;
49   return ns / ms_unit;
50 }
51
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;
55   return ms * ns_unit;
56 }
57 std::int64_t ConvertNsToMs(std::int64_t ns) {
58   constexpr std::int64_t ms_unit = 1000000;
59   return ns / ms_unit;
60 }
61
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;
87   return oss.str();
88 }
89
90 }  // namespace util
91
92 namespace internal {
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
97
98 constexpr uint32_t kNdecodingMode = 0x04;
99
100 enum VolumeLevel { kVolumeMin = 0, kVolumeMax = 100 };
101 constexpr int kMaxFhdWidth = 1920;
102 constexpr int kMaxFhdHeight = 1080;
103
104 inline bool IsPcmMimeType(const std::string& mimetype) {
105   return (mimetype.find("audio/x-raw") != std::string::npos);
106 }
107 inline bool IsAacCodec(const Track& track) {
108   return (track.mimetype.find("audio/mpeg") != std::string::npos &&
109           track.version == 2);
110 }
111 inline bool IsEac3Codec(const std::string& mimetype) {
112   return mimetype.find("audio/x-eac3") != std::string::npos;
113 }
114 inline bool IsAc3Codec(const std::string& mimetype) {
115   return mimetype.find("audio/x-ac3") != std::string::npos;
116 }
117 inline bool IsAvailableCodecSwitch(const Track& track) {
118   if (internal::IsAacCodec(track) || internal::IsAc3Codec(track.mimetype) ||
119       internal::IsEac3Codec(track.mimetype))
120     return true;
121   return false;
122 }
123
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;
129   return eos_status;
130 }
131
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;
142         else
143           track.use_swdecoder = false;
144         break;
145       }
146       case kTrackTypeVideo: {
147         if (video_codec_type == kPlayerVideoCodecTypeSW)
148           track.use_swdecoder = true;
149         else
150           track.use_swdecoder = false;
151         break;
152       }
153       default:
154         break;
155     }
156   }
157 }
158 inline bool IsSupportedDrmType(const drm::Type& drm_type) {
159   static const std::map<drm::Type, bool> kSupportedDrmType = {
160       {drm::Type::kPlayready, true},
161   };
162   if (kSupportedDrmType.count(drm_type) == 0) return false;
163   return kSupportedDrmType.at(drm_type);
164 }
165 inline void ResetDrmProperty(drm::Property& drm_property) {
166   drm_property = drm::Property();
167 }
168 inline StreamType ConvertToStreamType(TrackType type) {
169   return (type == kTrackTypeAudio) ? StreamType::kAudio : StreamType::kVideo;
170 }
171 struct AppsrcQueueSizeOption {
172   std::uint64_t current_size = 0;
173   std::uint64_t max_size = 0;
174   std::uint32_t threshold = 0;
175 };
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)
186     return true;
187   else
188     return false;
189 }
190 inline bool IsLowLatencyModeDisableAVSync(std::uint32_t mode) {
191   constexpr std::uint32_t kAVSync = 0x0100;
192   return (mode & kAVSync) ? true : false;
193 }
194 inline bool IsLowLatencyModeDisablePreroll(std::uint32_t mode) {
195   constexpr std::uint32_t kPreroll = 0x0200;
196   return (mode & kPreroll) ? true : false;
197 }
198 inline bool IsLowLatencyMode(std::uint32_t mode) {
199   return (mode != static_cast<std::uint32_t>(kLowLatencyModeNone)) ? true
200                                                                    : false;
201 }
202 inline bool IsSupportedTsOffset(std::uint32_t mode) {
203   return IsLowLatencyMode(mode) && !IsLowLatencyModeDisableAVSync(mode) ? true
204                                                                         : false;
205 }
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);
211   precondition |=
212       static_cast<std::uint32_t>(kLowLatencyModeDisableVideoQuality);
213   return (low_latency_mode == precondition) ? true : false;
214 }
215
216 }  // namespace internal
217
218 EsPlayer::EsPlayer() {
219   std::call_once(es_conf::loaded, [this]() { es_conf::LoadIniFile(); });
220 }
221
222 EsPlayer::~EsPlayer() {
223   LOG_ENTER_P(this);
224   try {
225     Close();
226   } catch (...) {
227     LOG_ERROR("Close failed");
228   }
229   LOG_LEAVE_P(this);
230 }
231
232 bool EsPlayer::Open() {
233   LOG_INFO_P(this, "state manager > %p", &state_manager_);
234   Init_();
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");
240     }
241     msg_handler_task_ =
242         std::async(std::launch::async, &EsPlayer::MsgTask_, this);
243     trackrenderer_ = TrackRendererAdapter::Create();
244     assert(trackrenderer_);
245
246     trackrenderer_->RegisterListenerForEsplayer(
247         trackrenderer_event_listener_.get());
248     performance_checker::End(start, "Open");
249     return true;
250   };
251   es_event::Open event{op};
252   return state_manager_.ProcessEvent(event);
253 }
254
255 bool EsPlayer::Close() {
256   LOG_ENTER_P(this);
257   std::lock_guard<std::mutex> lk(submit_mutex_);
258   if (state_manager_.GetState() >= EsState::kIdle) {
259     Stop();
260   }
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();
266     }
267
268     if (trackrenderer_) trackrenderer_.reset();
269     ResetContextForClose_();
270     LOG_LEAVE_P(this);
271     return true;
272   };
273   es_event::Close event{op};
274   state_manager_.ProcessEvent(event);
275   state_manager_.Stop();
276   return true;
277 }
278
279 bool EsPlayer::Deactivate(const StreamType type) {
280   LOG_ENTER_P(this);
281   if (state_manager_.GetState() < EsState::kReady) {
282     LOG_ERROR_P(this, "Invalid State , current %d",
283                 state_manager_.GetStateEnum());
284     return false;
285   }
286   if (!trackrenderer_->Deactivate(static_cast<TrackType>(type))) {
287     return false;
288   }
289   {
290     std::lock_guard<std::mutex> lock(eos_mutex_);
291     switch (type) {
292       case StreamType::kAudio:
293         eos_status_ |= EosStatus::kAudioEos;
294         break;
295       case StreamType::kVideo:
296         eos_status_ |= EosStatus::kVideoEos;
297         break;
298       default:
299         break;
300     }
301   }
302   for (auto& track : track_) {
303     if (track.type == static_cast<TrackType>(type)) {
304       track.active = false;
305     }
306   }
307   return true;
308 }
309
310 bool EsPlayer::Activate(const StreamType type) {
311   LOG_ENTER_P(this);
312   if (state_manager_.GetState() < EsState::kReady) {
313     LOG_ERROR_P(this, "Invalid State , current %d",
314                 state_manager_.GetStateEnum());
315     return false;
316   }
317   if (!track_.empty()) {
318     auto has_track = [type](const Track& item) -> bool {
319       return item.type == static_cast<TrackType>(type);
320     };
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");
324       return false;
325     }
326     if (target->active != false) {
327       LOG_ERROR_P(this, "The track should be deactivated in advance.");
328       return false;
329     }
330     target->active = true;
331     internal::UpdateCodecTypeTracks(track_, audio_codec_type_,
332                                     video_codec_type_,
333                                     force_audio_swdecoder_use_);
334     SetTrackRendererAttributes_();
335     if (!trackrenderer_->Activate(target->type, *target)) {
336       target->active = false;
337       return false;
338     }
339     std::lock_guard<std::mutex> lock2(eos_mutex_);
340     eos_status_ =
341         internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
342     return true;
343   }
344   return false;
345 }
346
347 bool EsPlayer::Start() {
348   LOG_ENTER_P(this);
349   if (is_stopped_) {
350     LOG_ERROR_P(this, "Stop already, no need to Start,leave...");
351     return false;
352   }
353   auto op = [this]() noexcept {
354     if (!trackrenderer_->Start()) {
355       return false;
356     }
357     return true;
358   };
359   es_event::Start event{op};
360   return state_manager_.ProcessEvent(event);
361 }
362
363 bool EsPlayer::Stop() {
364   LOG_ENTER_P(this);
365   is_stopped_ = true;
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");
371     return true;
372   };
373   for (const auto& track : track_) {
374     es_packet_logger_.PrintStoredPacketInfo(
375         internal::ConvertToStreamType(track.type), true);
376   }
377   es_event::Stop event{stop};
378   bool res = state_manager_.ProcessEventStop(event);
379
380   if (preparetask_.valid()) {
381     LOG_INFO_P(this, "Stopped , Wait Prepare() finish...");
382     preparetask_.wait();
383     LOG_INFO_P(this, "Wait , Wait Prepare() Done...");
384   }
385
386   return res;
387 }
388
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,
410                                low_latency_mode_);
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,
422         resume_time_.time);
423     resume_time_.is_set = false;
424   }
425 }
426
427 bool EsPlayer::Prepare_() {
428   LOG_ENTER_P(this);
429   if (is_stopped_) {
430     LOG_ERROR_P(this, "Stop already, no need to prepare,leave...");
431     return false;
432   }
433   auto op = [this]() noexcept -> bool {
434     const auto start = performance_checker::Start();
435
436     internal::UpdateCodecTypeTracks(track_, audio_codec_type_,
437                                     video_codec_type_,
438                                     force_audio_swdecoder_use_);
439     std::vector<Track> active_track;
440     if (!track_util::GetActiveTrackList(track_, active_track)) {
441       return false;
442     }
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;
450           break;
451         }
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;
456           break;
457         }
458         default:
459           break;
460       }
461     }
462     trackrenderer_->SetTrack(active_track);
463     try {
464       SetTrackRendererAttributes_();
465     } catch (...) {
466       LOG_ERROR_P(this, "SetTrackRendererAttributes_ failed");
467       return false;
468     }
469     if (!trackrenderer_->Prepare()) {
470       return false;
471     }
472     performance_checker::End(start, "Prepare");
473     return true;
474   };
475   es_event::Prepare event{op};
476   if (!state_manager_.ProcessEvent(event)) {
477     return false;
478   }
479   LOG_LEAVE_P(this);
480   return true;
481 }
482
483 void EsPlayer::PrepareTask_() {
484   bool ret = Prepare_();
485
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_);
490   }
491
492   LOG_LEAVE_P(this);
493 }
494
495 bool EsPlayer::PrepareAsync() {
496   LOG_ENTER_P(this);
497   state_manager_.SetPreparingState(true);
498   preparetask_ = std::async(std::launch::async, &EsPlayer::PrepareTask_, this);
499   if (!preparetask_.valid()) {
500     state_manager_.SetPreparingState(false);
501     return false;
502   }
503   return true;
504 }
505
506 bool EsPlayer::Pause() {
507   LOG_ENTER_P(this);
508   if (is_stopped_) {
509     LOG_ERROR_P(this, "Stop already, no need to pause,leave...");
510     return false;
511   }
512   if (state_manager_.GetState() < EsState::kReady) {
513     LOG_ERROR_P(this, "Invalid State , current %d",
514                 state_manager_.GetStateEnum());
515     return false;
516   }
517   auto op = [this]() noexcept -> bool {
518     if (!trackrenderer_) return false;
519     if (!trackrenderer_->Pause()) {
520       return false;
521     }
522     return true;
523   };
524   for (const auto& track : track_) {
525     es_packet_logger_.PrintStoredPacketInfo(
526         internal::ConvertToStreamType(track.type), true);
527   }
528   es_event::Pause event{op};
529   return state_manager_.ProcessEvent(event);
530 }
531
532 bool EsPlayer::Resume() {
533   LOG_ENTER_P(this);
534   if (is_stopped_) {
535     LOG_ERROR_P(this, "Stop already, no need to Resume,leave...");
536     return false;
537   }
538   if (state_manager_.GetState() <= EsState::kReady) {
539     LOG_ERROR_P(this, "Invalid State , current %d",
540                 state_manager_.GetStateEnum());
541     return false;
542   }
543   if (is_resource_conflicted_) {
544     LOG_ERROR_P(this, "Resume fail resource conflicted");
545     return false;
546   }
547   auto op = [this]() noexcept -> bool {
548     if (!trackrenderer_) return false;
549     if (!trackrenderer_->Resume()) {
550       return false;
551     }
552     return true;
553   };
554   for (const auto& track : track_) {
555     es_packet_logger_.PrintStoredPacketInfo(
556         internal::ConvertToStreamType(track.type), true);
557   }
558   es_event::Resume event{op};
559   return state_manager_.ProcessEvent(event);
560 }
561
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());
566     return false;
567   }
568   if (state_manager_.GetState() == EsState::kIdle) {
569     if (state_manager_.GetPreparingState()) {
570       LOG_ERROR_P(this, "Invalid State , during preparing");
571       return false;
572     }
573     LOG_ERROR("[%p] > resume time [%" PRIu64 " ms]", this, time_millisecond);
574     resume_time_.is_set = true;
575     resume_time_.time = time_millisecond;
576     return true;
577   }
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);
585   }
586   auto op = [this, time_millisecond]() -> bool {
587     if (!trackrenderer_->Seek(time_millisecond, current_playback_rate_,
588                               current_audio_mute_)) {
589       return false;
590     }
591     return true;
592   };
593   es_event::Seek event{op};
594
595   bool ret = state_manager_.ProcessEvent(event);
596   is_seek_done_need_drop = false;
597
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));
606       msg_mutex.unlock();
607       msg_task_cv_.notify_one();
608     }
609   }
610
611   LOG_DEBUG("%p, [LEAVE] seek end ", this);
612
613   return ret;
614 }
615
616 bool EsPlayer::SetPlaybackRate(const double rate, const bool audio_mute) {
617   LOG_ENTER_P(this);
618
619   if (rate <= 0 || rate > 2.0) {
620     LOG_ERROR_P(this, "Not a valid PlaybackRate");
621     return false;
622   }
623
624   if (state_manager_.GetState() < EsState::kReady) {
625     LOG_ERROR_P(this, "Invalid State , current %d",
626                 state_manager_.GetStateEnum());
627     return false;
628   }
629
630   auto op = [this, rate, audio_mute]() -> bool {
631     if (!trackrenderer_->SetPlaybackRate(rate, audio_mute)) {
632       return false;
633     }
634     current_playback_rate_ = rate;
635     current_audio_mute_ = audio_mute;
636     return true;
637   };
638   es_event::PlaybackRate event{op};
639   bool ret = state_manager_.ProcessEvent(event);
640
641   LOG_LEAVE_P(this);
642   return ret;
643 }
644
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());
649     return false;
650   }
651   return trackrenderer_->SetDisplay(type, obj);
652 }
653
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());
659     return false;
660   }
661   return trackrenderer_->SetDisplay(type, ecore_wl2_window, x, y, w, h);
662 }
663
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());
669     return false;
670   }
671   return trackrenderer_->SetDisplay(type, surface_id, x, y, w, h);
672 }
673
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());
678     return false;
679   }
680   trackrenderer_->SetDisplayMode(mode);
681   return true;
682 }
683
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());
688     return false;
689   }
690   return trackrenderer_->SetDisplayRoi(roi);
691 }
692
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());
697     return false;
698   }
699   return trackrenderer_->SetVideoRoi(area);
700 }
701
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());
706     return false;
707   }
708   return trackrenderer_->SetDisplayRotate(rotate);
709 }
710
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());
715     return false;
716   }
717   if (trackrenderer_->GetDisplayRotate(rotate)) {
718     return true;
719   }
720   return false;
721 }
722
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());
727     return false;
728   }
729   return trackrenderer_->SetDisplayVisible(is_visible);
730 }
731
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());
736     return false;
737   }
738   if (drm_property_.type != drm::Type::kNone) {
739     LOG_ERROR_P(this, "drm type is already set for sending encrypted packets");
740     return false;
741   }
742   LOG_INFO_P(this, "set trust zone use [%d]", is_using_tz);
743   drm_property_.external_decryption = is_using_tz;
744
745   drm::Property drm_property = drm_property_;
746   drm_property.type = drm::Type::kPlayready;
747   trackrenderer_->SetDrm(drm_property);
748   return true;
749 }
750
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());
755     return false;
756   }
757   LOG_INFO_P(this, "set submit data type [%d]", static_cast<int>(type));
758
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);
767   }
768   return true;
769 }
770
771 bool EsPlayer::SetTrack_(const Track& track) {
772   LOG_ENTER_P(this);
773   track_.push_back(std::move(track));
774   return true;
775 }
776
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;
782   };
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.");
787     SetTrack_(track);
788     return true;
789   }
790   if (target->active != false) {
791     LOG_ERROR_P(this, "The track should be deactivated in advance.");
792     return false;
793   }
794   track_.erase(target);
795   LOG_ERROR_P(this, "previously added %s stream is deleted",
796               (type == kTrackTypeAudio) ? "audio" : "video");
797   return SetTrack_(track);
798 }
799
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;
805     };
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");
809       return false;
810     }
811   }
812   auto op = [this, track]() noexcept {
813     if (!SetTrack_(track)) {
814       return false;
815     }
816     return true;
817   };
818   es_event::SetStream event{op};
819   return state_manager_.ProcessEvent(event);
820 }
821
822 bool EsPlayer::SetStream(const AudioStreamPtr& stream) {
823   LOG_ENTER_P(this);
824   bool ret = false;
825   BOOST_SCOPE_EXIT(&ret, &stream, &force_audio_swdecoder_use_) {
826     if (ret) force_audio_swdecoder_use_ = stream->GetForceSwDecoderUse();
827   }
828   BOOST_SCOPE_EXIT_END
829   if (state_manager_.GetState() < EsState::kIdle) {
830     LOG_ERROR_P(this, "Invalid State , current %d",
831                 state_manager_.GetStateEnum());
832     return ret;
833   }
834   Track track = stream->GetTrack_();
835   if (state_manager_.GetState() >= EsState::kReady) {
836     track.active = false;
837     ret = ChangeStream_(track);
838     return ret;
839   }
840   ret = SetStream_(track);
841   return ret;
842 }
843
844 bool EsPlayer::SetStream(const VideoStreamPtr& stream) {
845   LOG_ENTER_P(this);
846   if (state_manager_.GetState() < EsState::kIdle) {
847     LOG_ERROR_P(this, "Invalid State , current %d",
848                 state_manager_.GetStateEnum());
849     return false;
850   }
851   Track track = stream->GetTrack_();
852   if (state_manager_.GetState() >= EsState::kReady) {
853     track.active = false;
854     return ChangeStream_(track);
855   }
856   return SetStream_(track);
857 }
858
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;
865   }
866   return trackrenderer_->GetDecodedPacket(packet);
867 }
868
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());
873     return false;
874   }
875   return trackrenderer_->ReturnDecodedPacket(packet);
876 }
877
878 void EsPlayer::ResetContextForClose_() {
879   internal::ResetDrmProperty(drm_property_);
880   track_.clear();
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;
890 }
891
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;
896   }
897   {
898     std::lock_guard<std::mutex> lock(eos_mutex_);
899     eos_status_ = EosStatus::kAllEos;
900   }
901   current_playback_rate_ = 1.0;
902   current_audio_mute_ = false;
903 }
904
905 void EsPlayer::GetSrcQueueCurrentSize_(const TrackType& type,
906                                        uint64_t* byte_size,
907                                        uint64_t* time_size) {
908   boost::any byte_size_, time_size_;
909   if (type == TrackType::kTrackTypeVideo) {
910     trackrenderer_->GetAttribute(
911         TrackRendererAdapter::Attribute::kVideoQueueCurrentLevelByte,
912         &byte_size_);
913   } else if (type == TrackType::kTrackTypeAudio) {
914     trackrenderer_->GetAttribute(
915         TrackRendererAdapter::Attribute::kAudioQueueCurrentLevelByte,
916         &byte_size_);
917   } else
918     return;
919   *byte_size = boost::any_cast<std::uint64_t>(byte_size_);
920   *time_size = 0;
921 }
922
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;
929     return nullptr;
930   }
931   GstBuffer* gstbuffer = gst_buffer_new_and_alloc(size);
932   if (!gstbuffer) {
933     *status = MakeBufferStatus::kOutOfMemory;
934     return nullptr;
935   }
936   if (buffer != nullptr) {
937     GstMapInfo map;
938     gst_buffer_map(gstbuffer, &map, GST_MAP_WRITE);
939     memcpy(map.data, buffer.get(), size);
940     gst_buffer_unmap(gstbuffer, &map);
941   }
942
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();
956
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);
964
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);
975   }
976   *status = MakeBufferStatus::kSuccess;
977   return gstbuffer;
978 }
979
980 PacketSubmitStatus EsPlayer::SubmitEosPacket_(const TrackType& type) {
981   PacketSubmitStatus submitstate = PacketSubmitStatus::kSuccess;
982   {
983     std::lock_guard<std::mutex> lock(eos_mutex_);
984     switch (type) {
985       case kTrackTypeAudio:
986         eos_status_ |= EosStatus::kAudioEos;
987         break;
988       case kTrackTypeVideo:
989         eos_status_ |= EosStatus::kVideoEos;
990         break;
991       default:
992         break;
993     }
994     if (eos_status_ != EosStatus::kAllEos) {
995       return submitstate;
996     }
997   }
998   for (int tracktype = kTrackTypeAudio; tracktype < kTrackTypeMax;
999        ++tracktype) {
1000     auto inbuffer =
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;
1006       return submitstate;
1007     }
1008   }
1009   return submitstate;
1010 }
1011
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);
1018 }
1019
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);
1026
1027   switch (submitstate) {
1028     case TrackRendererAdapter::SubmitStatus::kSuccess:
1029     case TrackRendererAdapter::SubmitStatus::kDrop:
1030       status = PacketSubmitStatus::kSuccess;
1031       break;
1032     case TrackRendererAdapter::SubmitStatus::kFull:
1033       UnsetTzQdata_(buffer);
1034       trackrenderer_event_listener_->OnBufferStatus(buffer->GetType(),
1035                                                     BufferStatus::kOverrun);
1036       status = PacketSubmitStatus::kFull;
1037       break;
1038     default:
1039       UnsetTzQdata_(buffer);
1040       status = PacketSubmitStatus::kNotPrepared;
1041       break;
1042   }
1043   return status;
1044 }
1045
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);
1058
1059   if (type == kTrackTypeAudio) {
1060     Track audio_track;
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);
1070     }
1071   }
1072 }
1073
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);
1086   }
1087 }
1088
1089 PacketSubmitStatus EsPlayer::SubmitPacketCommon_(const EsPacketPtr& packet,
1090                                                  SubmitPacketOperator op) {
1091   if (state_manager_.GetState() < EsState::kIdle) {
1092     return PacketSubmitStatus::kNotPrepared;
1093   }
1094   if (!packet) return PacketSubmitStatus::kInvalidPacket;
1095
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;
1100
1101   if (state_manager_.GetState() == EsState::kPaused ||
1102       state_manager_.GetState() == EsState::kReady) {
1103     internal::AppsrcQueueSizeOption byte_based, time_based;
1104     switch (type) {
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;
1110         break;
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;
1116         break;
1117       default:
1118         break;
1119     }
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);
1125   }
1126
1127   es_packet_logger_.StorePacketInfo(packet);
1128   es_packet_logger_.PrintStoredPacketInfo(packet->GetType());
1129
1130   MakeBufferStatus make_buffer_status;
1131   GstBuffer* gstbuffer = GetGstBuffer_(packet, &make_buffer_status);
1132   if (!gstbuffer) {
1133     if (make_buffer_status == MakeBufferStatus::kEos)
1134       return SubmitEosPacket_(type);
1135     else if (make_buffer_status == MakeBufferStatus::kOutOfMemory)
1136       return PacketSubmitStatus::kOutOfMemory;
1137   }
1138   if (op != nullptr) {
1139     PacketSubmitStatus op_status = op(gstbuffer);
1140     if (op_status != PacketSubmitStatus::kSuccess) {
1141       return op_status;
1142     }
1143   }
1144
1145   auto inbuffer = DecoderInputBuffer::Create(type, 0, gstbuffer);
1146   gst_buffer_unref(gstbuffer);
1147
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;
1154   }
1155
1156   return SubmitDecoderInputBuffer_(inbuffer);
1157 }
1158
1159 PacketSubmitStatus EsPlayer::SubmitPacket(const EsPacketPtr& packet) {
1160   std::lock_guard<std::mutex> lk(submit_mutex_);
1161   return SubmitPacketCommon_(packet, nullptr);
1162 }
1163
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);
1175     }
1176     return PacketSubmitStatus::kSuccess;
1177   };
1178   return SubmitPacketCommon_(packet, submitpacket_op);
1179 }
1180
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;
1190   };
1191   return SubmitPacketCommon_(packet, submitpacket_op);
1192 }
1193
1194 EsState EsPlayer::GetState() { return state_manager_.GetState(); }
1195
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;
1200     return false;
1201   }
1202   return trackrenderer_->GetPlayingTime(time_in_milliseconds);
1203 }
1204
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());
1209     return false;
1210   }
1211   return trackrenderer_->SetAudioMute(is_mute);
1212 }
1213
1214 bool EsPlayer::SetVideoFrameBufferType(DecodedVideoFrameBufferType type) {
1215   if (state_manager_.GetState() != EsState::kIdle) {
1216     LOG_ERROR("Invalid State , current %d", state_manager_.GetStateEnum());
1217     return false;
1218   }
1219   trackrenderer_->SetVideoFrameBufferType(type);
1220   return true;
1221 }
1222
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;
1229 }
1230
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)
1235     return false;
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");
1240         return false;
1241       }
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");
1246         return false;
1247       }
1248       return trackrenderer_->GetDroppedFramesForCatchup(kTrackTypeVideo,
1249                                                         padaptive_info);
1250     case PlayerAdaptiveInfo::kDroppedAudioFramesForCatchup:
1251       if (state_manager_.GetState() < EsState::kReady) {
1252         LOG_ERROR_P(this, "Wrong state, we aren't started yet");
1253         return false;
1254       }
1255       return trackrenderer_->GetDroppedFramesForCatchup(kTrackTypeAudio,
1256                                                         padaptive_info);
1257     default:
1258       break;
1259   }
1260   return false;
1261 }
1262
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);
1266     return false;
1267   }
1268   if (state_manager_.GetState() < EsState::kIdle) {
1269     LOG_ERROR_P(this, "Invalid State , current %d",
1270                 state_manager_.GetStateEnum());
1271     return false;
1272   }
1273   return trackrenderer_->SetVolume(volume);
1274 }
1275
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());
1280     return false;
1281   }
1282   return trackrenderer_->GetVolume(volume);
1283 }
1284
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());
1289     return false;
1290   }
1291   std::lock_guard<std::mutex> lock2(eos_mutex_);
1292   eos_status_ =
1293       internal::ResetEosStatus(static_cast<TrackType>(type), eos_status_);
1294   es_packet_logger_.ResetLog(type);
1295   return trackrenderer_->Flush(type);
1296 }
1297
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());
1302     return;
1303   }
1304   switch (option) {
1305     case BufferOption::kBufferAudioMaxByteSize:
1306       src_queue_size_.kMaxByteOfAudioSrcQueue = size;
1307       break;
1308     case BufferOption::kBufferVideoMaxByteSize:
1309       src_queue_size_.kMaxByteOfVideoSrcQueue = size;
1310       break;
1311     case BufferOption::kBufferAudioMinByteThreshold:
1312       src_queue_size_.kMinByteThresholdOfAudioSrcQueue =
1313           static_cast<uint32_t>(size);
1314       break;
1315     case BufferOption::kBufferVideoMinByteThreshold:
1316       src_queue_size_.kMinByteThresholdOfVideoSrcQueue =
1317           static_cast<uint32_t>(size);
1318       break;
1319     case BufferOption::kBufferAudioMaxTimeSize:
1320       src_queue_size_.kMaxTimeOfAudioSrcQueue = size;
1321       break;
1322     case BufferOption::kBufferVideoMaxTimeSize:
1323       src_queue_size_.kMaxTimeOfVideoSrcQueue = size;
1324       break;
1325     case BufferOption::kBufferAudioMinTimeThreshold:
1326       src_queue_size_.kMinTimeThresholdOfAudioSrcQueue =
1327           static_cast<uint32_t>(size);
1328       break;
1329     case BufferOption::kBufferVideoMinTimeThreshold:
1330       src_queue_size_.kMinTimeThresholdOfVideoSrcQueue =
1331           static_cast<uint32_t>(size);
1332       break;
1333     default:
1334       LOG_ERROR_P(this, "Invalid option!!!");
1335       break;
1336   }
1337 }
1338
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());
1343     return false;
1344   }
1345   low_latency_mode_ |= static_cast<std::uint32_t>(mode);
1346   return true;
1347 }
1348
1349 bool EsPlayer::SetUnlimitedMaxBufferMode() {
1350   if (state_manager_.GetState() != EsState::kIdle) {
1351     LOG_ERROR_P(this, "Invalid State , current %d",
1352                 state_manager_.GetStateEnum());
1353     return false;
1354   }
1355   constexpr std::uint32_t unlimited_max_buffer_mode_on = 1;
1356   unlimited_max_buffer_mode_ = unlimited_max_buffer_mode_on;
1357   return true;
1358 }
1359
1360 bool EsPlayer::SetAudioCodecType(const PlayerAudioCodecType& type) {
1361   Track activated_track;
1362   bool is_existed =
1363       track_util::GetActiveTrack(track_, kTrackTypeAudio, &activated_track);
1364   EsState state = state_manager_.GetState();
1365   if ((state < EsState::kIdle) || (state > EsState::kIdle && is_existed)) {
1366     LOG_ERROR_P(this,
1367                 "Invalid State [state:%d] or audio stream already exists[%d],",
1368                 state_manager_.GetStateEnum(), is_existed);
1369     return false;
1370   }
1371   if (force_audio_swdecoder_use_ && type == kPlayerAudioCodecTypeHW) {
1372     LOG_ERROR_P(this, "Not support hw decoder");
1373     return false;
1374   }
1375   LOG_INFO_P(this, "PlayerAudioCodecType [%s]",
1376              (type == kPlayerAudioCodecTypeHW) ? "hardware" : "software");
1377   audio_codec_type_ = type;
1378   return true;
1379 }
1380
1381 bool EsPlayer::SetVideoCodecType(const PlayerVideoCodecType& type) {
1382   Track activated_track;
1383   bool is_existed =
1384       track_util::GetActiveTrack(track_, kTrackTypeVideo, &activated_track);
1385   EsState state = state_manager_.GetState();
1386   if ((state < EsState::kIdle) || (state > EsState::kIdle && is_existed)) {
1387     LOG_ERROR_P(this,
1388                 "Invalid State [state:%d] or video stream already exists[%d],",
1389                 state_manager_.GetStateEnum(), is_existed);
1390     return false;
1391   }
1392   if (type == kPlayerVideoCodecTypeSW &&
1393       vidoe_frame_buffer_type_ == DecodedVideoFrameBufferType::kScale) {
1394     LOG_ERROR_P(this,
1395                 "sw video decoder is not supported when video frame buffer "
1396                 "type is scale");
1397     return false;
1398   }
1399   LOG_INFO_P(this, "PlayerVideoCodecType [%s]",
1400              (type == kPlayerVideoCodecTypeHW) ? "hardware" : "software");
1401   video_codec_type_ = type;
1402   return true;
1403 }
1404
1405
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());
1410     return false;
1411   }
1412   if (!internal::IsSupportedTsOffset(low_latency_mode_)) {
1413     LOG_ERROR_P(this,
1414                 "low latency mode have to be set except disable_sync mode");
1415     return false;
1416   }
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",
1421         this, offset);
1422     return false;
1423   }
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));
1433   return true;
1434 }
1435
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());
1440     return false;
1441   }
1442   if (!internal::IsSupportedTsOffset(low_latency_mode_)) {
1443     LOG_ERROR_P(this, "low latency mode have to be set");
1444     return false;
1445   }
1446   if (type == StreamType::kMax) return false;
1447   boost::any off_set;
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);
1454
1455   *offset = util::ConvertNsToMs(boost::any_cast<int64_t>(off_set));
1456
1457   return true;
1458 }
1459
1460 void EsPlayer::Init_() {
1461   track_.clear();
1462   is_stopped_ = false;
1463   LOG_LEAVE_P(this);
1464 }
1465
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);
1471     } else {
1472       msg_mutex.unlock();
1473       msg_queue_.front()->Execute();
1474       msg_mutex.lock();
1475       msg_queue_.pop();
1476     }
1477   }
1478   while (!msg_queue_.empty()) {
1479     std::unique_lock<std::mutex> msg_mutex(msg_task_mutex_);
1480     msg_queue_.pop();
1481   }
1482   LOG_INFO_P(this, "Stop MsgTask");
1483 }
1484
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));
1493   msg_mutex.unlock();
1494   handler_->msg_task_cv_.notify_one();
1495   LOG_LEAVE_P(handler_);
1496 }
1497
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));
1507   msg_mutex.unlock();
1508   handler_->msg_task_cv_.notify_one();
1509   LOG_LEAVE_P(handler_);
1510 }
1511
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");
1516     return;
1517   }
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));
1527   msg_mutex.unlock();
1528   if (handler_->is_stopped_) {
1529     LOG_LEAVE_P(handler_);
1530     return;
1531   }
1532   handler_->msg_task_cv_.notify_one();
1533   LOG_LEAVE_P(handler_);
1534 }
1535
1536 void EsPlayer::TrackRendererEventListener::OnError(
1537     const ErrorType& error_code) {
1538   if (!handler_->eventlistener_) return;
1539   if (error_code == ErrorType::kResourceLimit) return;
1540   auto listener =
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_);
1545
1546   std::unique_lock<std::mutex> msg_mutex(handler_->msg_task_mutex_);
1547   handler_->msg_queue_.push(std::move(msg));
1548   msg_mutex.unlock();
1549   handler_->msg_task_cv_.notify_one();
1550 }
1551
1552 void EsPlayer::TrackRendererEventListener::ReadyToPrepare_(
1553     const TrackType& type) {
1554   LOG_INFO_P(handler_, "OnReadyToPrepare [%s]",
1555              (type == kTrackTypeAudio) ? "audio" : "video");
1556
1557   handler_->need_data_[type].mask &= ~kNeedDataMaskByPrepare;
1558
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));
1567   msg_mutex.unlock();
1568   handler_->msg_task_cv_.notify_one();
1569 }
1570
1571 void EsPlayer::TrackRendererEventListener::ReadyToSeek_(const TrackType& type) {
1572   uint64_t offset = handler_->need_data_[type].seek_offset;
1573
1574   LOG_INFO("[%p] > OnReadyToSeek [%s] offset [%" PRIu64 "]ms", handler_,
1575              (type == kTrackTypeAudio) ? "audio" : "video", offset);
1576
1577   handler_->need_data_[type].mask &= ~kNeedDataMaskBySeek;
1578   handler_->need_data_[type].seek_offset = 0;
1579
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));
1589   msg_mutex.unlock();
1590   handler_->msg_task_cv_.notify_one();
1591 }
1592
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);
1605   auto msg =
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));
1610   msg_mutex.unlock();
1611   handler_->msg_task_cv_.notify_one();
1612 }
1613
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_))
1618     return;
1619
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) {
1625     ReadyToSeek_(type);
1626   } else {
1627     BufferStatus_(type, status);
1628   }
1629 }
1630
1631 void EsPlayer::TrackRendererEventListener::OnMediaPacketVideoDecoded(
1632     const DecodedVideoPacket& packet) {
1633   if (!handler_->eventlistener_) return;
1634
1635   handler_->eventlistener_->OnMediaPacketVideoDecoded(packet);
1636 }
1637
1638 void EsPlayer::TrackRendererEventListener::OnSeekData(const TrackType& type,
1639                                                       const uint64_t offset) {
1640   if (!handler_->eventlistener_) return;
1641
1642   if (handler_->need_data_[type].mask != kNeedDataMaskByPrepare) {
1643     handler_->need_data_[type].mask |= kNeedDataMaskBySeek;
1644     handler_->need_data_[type].seek_offset = offset;
1645   }
1646 }
1647
1648 void EsPlayer::TrackRendererEventListener::OnClosedCaptionData(const char* data,
1649                                                                const int size) {
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));
1659   msg_mutex.unlock();
1660   handler_->msg_task_cv_.notify_one();
1661 }
1662
1663 void EsPlayer::TrackRendererEventListener::OnFlushDone() {
1664   LOG_ENTER_P(handler_);
1665   if (!handler_->eventlistener_) return;
1666
1667   auto listener = std::bind(&plusplayer::EsEventListener::OnFlushDone,
1668                             handler_->eventlistener_, std::placeholders::_1);
1669   auto msg =
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));
1673   msg_mutex.unlock();
1674   handler_->msg_task_cv_.notify_one();
1675   LOG_LEAVE_P(handler_);
1676 }
1677
1678 void EsPlayer::TrackRendererEventListener::OnEvent(const EventType& event,
1679                                                    const EventMsg& msg_data) {
1680   if (!handler_->eventlistener_) return;
1681
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));
1689   msg_mutex.unlock();
1690   handler_->msg_task_cv_.notify_one();
1691   LOG_LEAVE_P(handler_);
1692 }
1693
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));
1703   msg_mutex.unlock();
1704   handler_->msg_task_cv_.notify_one();
1705   LOG_LEAVE_P(handler_);
1706 }
1707
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());
1712     return false;
1713   }
1714   return trackrenderer_->EnableVideoHole(value);
1715 }
1716
1717 namespace es_conf {
1718
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]);
1724
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]);
1728 }
1729
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 !!");
1739     return false;
1740   }
1741   BOOST_SCOPE_EXIT(&file) { file.close(); }
1742   BOOST_SCOPE_EXIT_END
1743
1744   size = file.tellg();
1745   if (size <= 0) {
1746     LOG_ERROR("Wrong file size");
1747     return false;
1748   }
1749   size += 1;
1750   buf = static_cast<char*>(calloc(size, sizeof(char)));
1751   if (buf == nullptr) {
1752     LOG_ERROR("Fail to calloc buf");
1753     return false;
1754   }
1755   BOOST_SCOPE_EXIT(&buf) {
1756     if (buf) free(buf);
1757   }
1758   BOOST_SCOPE_EXIT_END
1759
1760   file.seekg(0, std::ios::beg);
1761   file.read(buf, size);
1762
1763   std::string config = buf;
1764   Json::Value root;
1765   Json::Reader reader;
1766   if (!reader.parse(config, root)) {
1767     LOG_ERROR("Fail to parse configuration file %s",
1768               (reader.getFormatedErrorMessages()).c_str());
1769     return false;
1770   }
1771
1772   es_conf::LoadIniProperty(root);
1773   return true;
1774 }
1775
1776 }  // namespace es_conf
1777
1778 }  // namespace plusplayer