#include "media/base/efl/media_player_util_efl.h"
#include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
+#include <jsoncpp/json/json.h>
+
namespace {
const int kSeekableTimeUpdateInterval = 500;
}
+static void PlayerPreLoadingCb(void* data) {
+ if (!data) {
+ LOG(ERROR) << "input data is null";
+ return;
+ }
+ media::MediaPlayerBridgeCapiTV* player =
+ static_cast<media::MediaPlayerBridgeCapiTV*>(data);
+ player->OnPlayerPreloading();
+}
+
static void DrmErrorCb(int err_code, char* err_str, void* data) {
DCHECK(data);
media::MediaPlayerBridgeCapiTV* player =
<< ",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()) {
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())
}
bool MediaPlayerBridgeCapiTV::Play() {
+ LOG(INFO) << "(" << static_cast<void*>(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())
return true;
}
+void MediaPlayerBridgeCapiTV::Pause(bool is_media_related_action) {
+ if (!player_prepared_) {
+ LOG(INFO) << "(" << static_cast<void*>(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())
+ 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();
}
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<void*>(this) << ") " << __func__
<< " A live stream.";
}
};
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<void*>(this) << ") " << __func__
<< " |player_get_adaptive_streaming_info| failed " << err;
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"
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);
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