X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tizen_src%2Fchromium_impl%2Fmedia%2Ffilters%2Fmedia_player_bridge_capi_tv.cc;h=b18eaa33be711f3aecb3688992dc234dbab4dfb2;hb=refs%2Fchanges%2F83%2F307683%2F3;hp=5b79cef8a1984584f4cc1e482d9e086ced6192be;hpb=0f658866eaf7cd938b41f3488d064a1c981ba730;p=platform%2Fframework%2Fweb%2Fchromium-efl.git diff --git a/tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.cc b/tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.cc index 5b79cef..b18eaa3 100644 --- a/tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.cc +++ b/tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.cc @@ -4,16 +4,38 @@ #include "media/filters/media_player_bridge_capi_tv.h" +#include "base/strings/string_split.h" +#include "media/base/efl/media_player_util_efl.h" #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h" +#include + namespace { const int kSeekableTimeUpdateInterval = 500; } +static void PlayerPreLoadingCb(void* data) { + if (!data) { + LOG(ERROR) << "input data is null"; + return; + } + media::MediaPlayerBridgeCapiTV* player = + static_cast(data); + player->OnPlayerPreloading(); +} + +static void DrmErrorCb(int err_code, char* err_str, void* data) { + DCHECK(data); + media::MediaPlayerBridgeCapiTV* player = + static_cast(data); + + player->OnDrmError(err_code, err_str); +} + namespace media { MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url, - std::string& user_agent, + const std::string& user_agent, double volume) : MediaPlayerBridgeCapi(url, user_agent, volume), weak_factory_(this) { LOG(INFO) << "(" << static_cast(this) << ") " << __func__; @@ -31,29 +53,124 @@ void MediaPlayerBridgeCapiTV::SetContentMimeType(const std::string& mime_type) { } void MediaPlayerBridgeCapiTV::Prepare() { + bool media_resource_acquired = false; + std::string translated_url; + std::string drm_info; + + if (GetMediaPlayerClient()) + GetMediaPlayerClient()->NotifyPlaybackState( + kPlaybackLoad, player_id_, url_.spec(), mime_type_, + &media_resource_acquired, &translated_url, &drm_info); + + LOG(INFO) << "media_resource_acquired: " << media_resource_acquired + << ",translated_url:" << translated_url + << ",drm_info: " << drm_info; + + if (mime_type_.find("application/vnd.oipf.contentaccessstreaming+xml") != + std::string::npos) { + LOG(INFO) << "CASD url,waiting for hbbtv parse the real url and set " + "translated url"; + return; + } + + if (GetMediaPlayerClient() && + GetMediaPlayerClient()->PlaybackNotificationEnabled() && + blink::IsHbbTV()) { + if (!SetDrmInfo(drm_info)) { + LOG(ERROR) << "SetDrmInfo failed"; + return; + } + if (!translated_url.empty()) + url_ = media::GetCleanURL(translated_url); + } + + if (url_.spec().find(".mpd") != std::string::npos) + stream_type_ = DASH_STREAM; + else if (url_.spec().find(".m3u") != std::string::npos) + stream_type_ = HLS_STREAM; + else if (mime_type_.find("application/dash+xml") != std::string::npos) { + char steaming_type_dash[] = "DASH"; + char steaming_type_dash_ex[] = "DASHEX"; + player_set_streaming_type( + player_, blink::IsHbbTV() ? steaming_type_dash_ex : steaming_type_dash); + stream_type_ = DASH_STREAM; + } + + if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM) + AppendUrlHighBitRate(url_.spec()); + player_prepared_ = false; + + parental_rating_pass_ = true; MediaPlayerBridgeCapi::Prepare(); + if (GetMediaPlayerClient()) + GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_); } void MediaPlayerBridgeCapiTV::Release() { + is_preloaded_ = false; + player_prepared_ = false; StopSeekableTimeUpdateTimer(); MediaPlayerBridgeCapi::Release(); + if (GetMediaPlayerClient()) + GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_); } bool MediaPlayerBridgeCapiTV::Play() { + LOG(INFO) << "(" << static_cast(this) << ") " << __func__ + << ",current_time:" << GetCurrentTime().InSecondsF(); + + // HBBTV run in preloading and preplay mode. If no prepread do prepare + // in PlayerPrePlay(), otherwise do normal Play. + if (blink::IsHbbTV() && !player_prepared_) { + if (!PlayerPrePlay()) + LOG(ERROR) << "HBBTV prePlay fail."; + return false; + } + + if (blink::IsHbbTV() && !parental_rating_pass_) { + LOG(INFO) << "parental rating authenticatoin is not pass yet,waiting..."; + delayed_player_state_ = PLAYER_STATE_DELAYED_PLAY; + MediaPlayerBridgeCapi::ExecuteDelayedPlayerState(); + return false; + } + if (!MediaPlayerBridgeCapi::Play()) return false; + if (GetMediaPlayerClient()) + GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_); return true; } +void MediaPlayerBridgeCapiTV::Pause(bool is_media_related_action) { + if (!player_prepared_) { + LOG(INFO) << "(" << static_cast(this) + << "), pause while player is not prepared, pause delay"; + delayed_player_state_ = PLAYER_STATE_DELAYED_PAUSE; + return; + } + MediaPlayerBridgeCapi::Pause(is_media_related_action); +} + void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() { MediaPlayerBridgeCapi::PlaybackCompleteUpdate(); + if (GetMediaPlayerClient()) { + GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_); + if (is_live_stream_) + GetMediaPlayerClient()->OnLivePlaybackComplete(); + } } // namespace media void MediaPlayerBridgeCapiTV::PlayerPrepared() { + player_prepared_ = true; MediaPlayerBridgeCapi::PlayerPrepared(); + int canSeek = 0; + int retVal = player_seek_available(player_, &canSeek); + if (retVal == PLAYER_ERROR_NONE && !canSeek) + is_player_seek_available_ = false; + GetAdaptiveStreamingInfo(); - if (/*!blink::IsHbbTV() && */is_live_stream_) { + if (!blink::IsHbbTV() && is_live_stream_) { UpdateSeekableTime(); StartSeekableTimeUpdateTimer(); } @@ -79,7 +196,7 @@ void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() { void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() { int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_, PLAYER_ADAPTIVE_INFO_IS_LIVE); - if (ret != PLAYER_ERROR_NONE || is_live_stream_) { + if (ret == PLAYER_ERROR_NONE && is_live_stream_) { LOG(INFO) << "(" << static_cast(this) << ") " << __func__ << " A live stream."; } @@ -123,7 +240,7 @@ bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min, }; char* live_ptr = live_duration; const auto err = player_get_adaptive_streaming_info( - player_, live_duration, PLAYER_ADAPTIVE_INFO_LIVE_DURATION); + player_, &live_ptr, PLAYER_ADAPTIVE_INFO_LIVE_DURATION); if (err != PLAYER_ERROR_NONE) { LOG(ERROR) << "(" << static_cast(this) << ") " << __func__ << " |player_get_adaptive_streaming_info| failed " << err; @@ -172,4 +289,379 @@ bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min, return true; } +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(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(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(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 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 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(); + } +} } // namespace media