+void MediaPlayerBridgeCapiTV::ParseDashInfo() {
+ std::string dash_info = GetDashInfo();
+ Json::CharReaderBuilder builder;
+ Json::CharReader* reader(builder.newCharReader());
+ Json::Value value;
+
+ if (reader->parse(dash_info.c_str(), dash_info.c_str() + dash_info.length(),
+ &value, nullptr)) {
+ mrs_url_ = value["mrsUrl"].asString();
+ std::string periodId = value["periodId"].asString();
+ if (periodId != "")
+ content_id_ = clean_url_ + "#period=" + periodId;
+ }
+ LOG(INFO) << "mrsUrl: " << mrs_url_ << ",contentId: " << content_id_;
+}
+
+std::string MediaPlayerBridgeCapiTV::GetDashInfo() {
+ char* dash_info = nullptr;
+ // dash_info format:
+ // {"type":0,"minBufferTime":4000,"mrsUrl":"","periodId":"first"}
+ const int ret = player_get_dash_info(player_, &dash_info);
+ if (ret != PLAYER_ERROR_NONE) {
+ if (dash_info)
+ free(dash_info);
+ LOG(ERROR) << "Fail to call player_get_dash_info,ret:" << ret;
+ return "";
+ }
+
+ if (!dash_info) {
+ LOG(ERROR) << "empty dash_info.";
+ return "";
+ }
+
+ const std::string info(dash_info);
+ free(dash_info);
+ LOG(INFO) << "dash info str: " << info;
+
+ return info;
+}
+
+bool MediaPlayerBridgeCapiTV::GetDashLiveDuration(int64_t* duration) {
+ DCHECK(duration);
+ std::string dash_info = GetDashInfo();
+ Json::CharReaderBuilder builder;
+ Json::CharReader* reader(builder.newCharReader());
+ Json::Value value;
+ int64_t out_duration = 0;
+
+ if (reader->parse(dash_info.c_str(), dash_info.c_str() + dash_info.length(),
+ &value, nullptr)) {
+ out_duration = value["mediaPresentationDuration"].asInt();
+ }
+
+ // According to dash spec, if duration == -1, set max time as duration.
+ if (out_duration == -1)
+ out_duration = base::TimeDelta::Max().InMilliseconds();
+ *duration = out_duration;
+
+ return true;
+}
+
+void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
+ // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
+ // "|" will be replaced with "%7C"
+ const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
+ int len = url.length() + strlen(high_bitrate) + 1;
+ char* str_url = new char[len];
+ if (!str_url) {
+ return;
+ }
+
+ memset(str_url, 0, len);
+ strncat(str_url, url.c_str(), url.length());
+ strncat(str_url, high_bitrate, strlen(high_bitrate));
+ hbbtv_url_ = str_url;
+ BLINKFREE(str_url);
+ LOG(INFO) << "hbbtv url:" << hbbtv_url_.c_str();
+}
+
+bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
+ if (!GetMediaPlayerClient()) {
+ LOG(ERROR) << "MediaPlayerClient is null";
+ return false;
+ }
+ content::WebContentsDelegate* web_contents_delegate =
+ GetMediaPlayerClient()->GetWebContentsDelegate();
+ if (!web_contents_delegate) {
+ LOG(ERROR) << "get web_contents_delegate fail";
+ return false;
+ }
+ bool ret = web_contents_delegate->IsHighBitRate();
+ LOG(INFO) << "get high bit rate: " << std::boolalpha << ret;
+ return ret;
+}
+
+void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
+ const std::string& scheme_id_uri,
+ const std::string& value,
+ const std::string& data,
+ int type) {
+ content::WebContentsDelegate* web_contents_delegate =
+ GetMediaPlayerClient()->GetWebContentsDelegate();
+ if (!web_contents_delegate)
+ return;
+ web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
+ type);
+}
+
+bool MediaPlayerBridgeCapiTV::PreloadIfNeeded(int& ret) {
+ LOG(INFO) << "PreloadIfNeeded, is_preloaded_ " << is_preloaded_;
+ if (blink::IsHbbTV() && !is_preloaded_) {
+ ret = player_preloading_async(player_, -1, PlayerPreLoadingCb, this);
+ return true;
+ }
+
+ // fixup : kPlaybackReady status need checked by HBBTVResourceAcquired() patch
+ if (GetMediaPlayerClient())
+ GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
+ else
+ LOG(ERROR) << "(" << static_cast<void*>(this)
+ << "), GetMediaPlayerClient return null";
+ SetDisplayAtPausedState();
+ return false;
+}
+
+void MediaPlayerBridgeCapiTV::SetDisplayAtPausedState() {
+ int ret = PLAYER_ERROR_NONE;
+ if (!pending_seek_duration_.is_zero())
+ ret = player_display_video_at_paused_state(player_, false);
+ else
+ ret = player_display_video_at_paused_state(player_, true);
+
+ if (ret != PLAYER_ERROR_NONE)
+ LOG(ERROR) << "player_display_video_at_paused_state() failed";
+}
+
+void MediaPlayerBridgeCapiTV::UpdateDuration() {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+ if (blink::IsHbbTV() && !is_preloaded_) {
+ LOG(INFO) << "HBBTV preload not finished, no need update duration. ";
+ return;
+ }
+ if (is_live_stream_) {
+ int64_t duration = 0;
+ if (stream_type_ == HLS_STREAM) {
+ int64_t min = 0;
+ if (!GetLiveStreamingDuration(&min, &duration)) {
+ LOG(ERROR) << "Fail to get duration for hls live stream.";
+ return;
+ }
+ } else if (stream_type_ == DASH_STREAM) {
+ if (!GetDashLiveDuration(&duration)) {
+ if (duration_ != base::TimeDelta::Max()) {
+ duration_ = base::TimeDelta::Max();
+ OnDurationChange(player_id_, duration_.InSecondsF());
+ }
+ return;
+ }
+ } else {
+ LOG(ERROR) << "Unknown live stream type : " << stream_type_;
+ }
+
+ if (duration == 0) {
+ LOG(WARNING) << "live stream type : convert duration to max";
+ duration_ = base::TimeDelta::Max();
+ OnDurationChange(player_id_, duration_.InSecondsF());
+ } else if (duration_.InSecondsF() !=
+ ConvertMilliSecondsToSeconds(duration)) {
+ duration_ = base::Milliseconds(duration);
+ OnDurationChange(player_id_, duration_.InSecondsF());
+ }
+ } else { // non-live stream sequence
+ MediaPlayerBridgeCapi::UpdateDuration();
+ }
+}
+
+void MediaPlayerBridgeCapiTV::UpdateMediaType() {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+
+ if (blink::IsHbbTV() && !is_preloaded_) {
+ LOG(INFO) << "HBBTV preload not finished, no need update media type. ";
+ return;
+ }
+ MediaPlayerBridgeCapi::UpdateMediaType();
+}
+
+bool MediaPlayerBridgeCapiTV::CheckLiveStreaming() const {
+ int isLive = 0;
+ int retVal = player_get_adaptive_streaming_info(player_, &isLive,
+ PLAYER_ADAPTIVE_INFO_IS_LIVE);
+ if (retVal != PLAYER_ERROR_NONE) {
+ LOG(ERROR) << "player_get_adaptive_streaming_info failed, error: "
+ << retVal;
+ return false;
+ }
+
+ if (!isLive)
+ return false;
+
+ LOG(INFO) << "This is a live streaming.";
+ return true;
+}
+
+void MediaPlayerBridgeCapiTV::OnPlayerPreloading() {
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapiTV::PlayerPreloaded,
+ weak_factory_.GetWeakPtr()));
+}
+
+bool MediaPlayerBridgeCapiTV::HBBTVResourceAcquired() {
+ bool media_resource_acquired = false;
+ if (!GetMediaPlayerClient()) {
+ LOG(ERROR) << "MediaPlayerTizenClient is nullptr";
+ return false;
+ }
+
+ GetMediaPlayerClient()->NotifyPlaybackState(
+ kPlaybackReady, player_id_, url_.spec(), mime_type_,
+ &media_resource_acquired, NULL, NULL);
+ if (!media_resource_acquired) {
+ GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
+ LOG(ERROR) << "HBBTV media resource acquired failed";
+ }
+ return media_resource_acquired;
+}
+
+void MediaPlayerBridgeCapiTV::PlayerPreloaded() {
+ LOG(INFO) << "PlayerPreloaded,this: " << this
+ << ",player_prepared_:" << player_prepared_;
+
+ is_preloaded_ = true;
+ is_live_stream_ = CheckLiveStreaming();
+ if (stream_type_ == DASH_STREAM)
+ ParseDashInfo();
+ if (is_live_stream_ && stream_type_ != OTHER_STREAM) {
+ // UpdateSeekableTime();
+ // StartSeekableTimeUpdateTimer();
+ }
+ // UpdateAudioTrackInfo();
+ // UpdateVideoTrackInfo();
+ // UpdateTextTrackInfo();
+ UpdateDuration();
+ UpdateMediaType();
+ if (GetMediaType() == MediaType::Invalid) {
+ LOG(ERROR) << "Media type is not valid!";
+ return;
+ }
+
+ OnReadyStateChange(player_id_,
+ blink::WebMediaPlayer::kReadyStateHaveFutureData);
+ OnNetworkStateChange(player_id_, blink::WebMediaPlayer::kNetworkStateLoading);
+
+ if (!player_prepared_ && HBBTVResourceAcquired()) {
+ int ret = SetPlayerPrepareAsync();
+ if (ret != PLAYER_ERROR_NONE) {
+ OnHandlePlayerError(ret, FROM_HERE);
+ }
+ }
+}
+
+bool MediaPlayerBridgeCapiTV::PlayerPrePlay() {
+ LOG(INFO) << "PlayerPrePlay, this: " << this
+ << ",is_player_prepared : " << player_prepared_;
+ if (IsPlayerSuspended()) {
+ LOG(INFO) << "PlayerPrePlay while player is suspended";
+ return false;
+ }
+
+ if (!HBBTVResourceAcquired()) {
+ LOG(INFO)
+ << "PlayerPrePlay while it's not in case of HBBTV Resource Acquired";
+ return false;
+ }
+
+ delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY;
+ LOG(INFO) << "begin to |player_prepare_async|";
+
+ SetDisplayAtPausedState();
+ int ret = SetPlayerPrepareAsync();
+ if (ret != PLAYER_ERROR_NONE) {
+ OnHandlePlayerError(ret, FROM_HERE);
+ return false;
+ }
+
+ return true;
+}
+void MediaPlayerBridgeCapiTV::Initialize(VideoRendererSink* sink) {
+ player_set_drm_error_cb(player_, DrmErrorCb, this);
+ MediaPlayerBridgeCapi::Initialize(sink);
+}
+
+bool MediaPlayerBridgeCapiTV::SetDrmInfo(std::string& drm_info) {
+ // The DRM info from HbbTV comes as a JSON-like string in the following
+ // format:
+ // pair = Property ':' Value
+ // string = pair {',' pair}
+ std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
+ drm_info, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
+ std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
+ *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+ if (drm_info_pair.size() != 2)
+ continue;
+
+ std::string trim_key = drm_info_pair.at(0);
+ std::string trim_value = drm_info_pair.at(1);
+ LOG(INFO) << "trim_key: " << trim_key.c_str()
+ << ",trim_value: " << trim_value.c_str();
+
+ if (!SetMediaDRMInfo(trim_key, trim_value)) {
+ LOG(ERROR)
+ << "MediaPlayerBridgeCapiTV::SetDrmInfo SetMediaDRMInfo failed";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
+ const std::string& value_data) {
+ LOG(INFO) << "player_set_drm_info(type_length(" << type_data.length() << ") "
+ << " value_length(" << value_data.length() << ")) ";
+ int ret = PLAYER_ERROR_INVALID_OPERATION;
+ const void* type_data_ptr = type_data.c_str();
+ const void* value_data_ptr = value_data.c_str();
+ player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
+ ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
+ value_data_ptr, value_data.length(), drm_type);
+ if (ret != PLAYER_ERROR_NONE) {
+ MediaPlayerBridgeCapi::OnHandlePlayerError(ret, FROM_HERE);
+ return false;
+ }
+
+ return true;
+}
+
+void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
+ LOG(ERROR) << "OnDrmError err_str[" << err_str << "]";
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
+ weak_factory_.GetWeakPtr(), err_code, err_str));
+ }
+ MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);
+}
+
+void MediaPlayerBridgeCapiTV::HandleParentalRatingInfo(const std::string& info,
+ const std::string& url) {
+ content::WebContentsDelegate* web_contents_delegate =
+ GetMediaPlayerClient()->GetWebContentsDelegate();
+ if (!web_contents_delegate){
+ LOG(ERROR) << "web_contents_delegate is null";
+ return;
+ }
+ web_contents_delegate->NotifyParentalRatingInfo(info, url);
+}
+
+void MediaPlayerBridgeCapiTV::SetParentalRatingResult(bool is_pass) {
+ LOG(INFO) << "ParentalRatingResult:" << std::boolalpha << is_pass;
+ parental_rating_pass_ = is_pass;
+
+ // if authentication fail, raise MEDIA_ERROR_DECODE
+ if (!parental_rating_pass_) {
+ OnHandlePlayerError(PLAYER_ERROR_INVALID_OPERATION, FROM_HERE);
+ return;
+ }
+
+ if (player_prepared_) {
+ LOG(INFO) << "player already prepared,execute play";
+ ExecuteDelayedPlayerState();
+ }
+}