1 // Copyright 2023 Samsung Electronics Inc. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/media_player_bridge_capi_tv.h"
7 #include "base/strings/string_split.h"
8 #include "media/base/efl/media_player_util_efl.h"
9 #include "tizen_src/chromium_impl/media/filters/media_player_tizen_client.h"
12 const int kSeekableTimeUpdateInterval = 500;
15 static void DrmErrorCb(int err_code, char* err_str, void* data) {
17 media::MediaPlayerBridgeCapiTV* player =
18 static_cast<media::MediaPlayerBridgeCapiTV*>(data);
20 player->OnDrmError(err_code, err_str);
25 MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url,
26 const std::string& user_agent,
28 : MediaPlayerBridgeCapi(url, user_agent, volume), weak_factory_(this) {
29 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
32 MediaPlayerBridgeCapiTV::~MediaPlayerBridgeCapiTV() {
33 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
34 weak_factory_.InvalidateWeakPtrs();
37 void MediaPlayerBridgeCapiTV::SetContentMimeType(const std::string& mime_type) {
38 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
39 << " mime_type : " << mime_type;
40 mime_type_ = mime_type;
43 void MediaPlayerBridgeCapiTV::Prepare() {
44 bool media_resource_acquired = false;
45 std::string translated_url;
48 if (GetMediaPlayerClient())
49 GetMediaPlayerClient()->NotifyPlaybackState(
50 kPlaybackLoad, player_id_, url_.spec(), mime_type_,
51 &media_resource_acquired, &translated_url, &drm_info);
53 LOG(INFO) << "media_resource_acquired: " << media_resource_acquired
54 << ",translated_url:" << translated_url
55 << ",drm_info: " << drm_info;
57 if (mime_type_.find("application/vnd.oipf.contentaccessstreaming+xml") !=
59 LOG(INFO) << "CASD url,waiting for hbbtv parse the real url and set "
64 if (GetMediaPlayerClient() &&
65 GetMediaPlayerClient()->PlaybackNotificationEnabled() &&
67 if (!SetDrmInfo(drm_info)) {
68 LOG(ERROR) << "SetDrmInfo failed";
71 if (!translated_url.empty())
72 url_ = media::GetCleanURL(translated_url);
75 if (url_.spec().find(".mpd") != std::string::npos)
76 stream_type_ = DASH_STREAM;
77 else if (url_.spec().find(".m3u") != std::string::npos)
78 stream_type_ = HLS_STREAM;
79 else if (mime_type_.find("application/dash+xml") != std::string::npos) {
80 char steaming_type_dash[] = "DASH";
81 char steaming_type_dash_ex[] = "DASHEX";
82 player_set_streaming_type(
83 player_, blink::IsHbbTV() ? steaming_type_dash_ex : steaming_type_dash);
84 stream_type_ = DASH_STREAM;
87 if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM)
88 AppendUrlHighBitRate(url_.spec());
89 MediaPlayerBridgeCapi::Prepare();
90 if (GetMediaPlayerClient())
91 GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackReady, player_id_);
94 void MediaPlayerBridgeCapiTV::Release() {
95 StopSeekableTimeUpdateTimer();
96 MediaPlayerBridgeCapi::Release();
97 if (GetMediaPlayerClient())
98 GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
101 bool MediaPlayerBridgeCapiTV::Play() {
102 if (!MediaPlayerBridgeCapi::Play())
104 if (GetMediaPlayerClient())
105 GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStart, player_id_);
109 void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
110 MediaPlayerBridgeCapi::PlaybackCompleteUpdate();
111 if (GetMediaPlayerClient())
112 GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackFinish, player_id_);
115 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
116 MediaPlayerBridgeCapi::PlayerPrepared();
118 GetAdaptiveStreamingInfo();
119 if (/*!blink::IsHbbTV() && */is_live_stream_) {
120 UpdateSeekableTime();
121 StartSeekableTimeUpdateTimer();
125 void MediaPlayerBridgeCapiTV::StartSeekableTimeUpdateTimer() {
126 if (!seekable_time_update_timer_.IsRunning()) {
127 seekable_time_update_timer_.Start(
128 FROM_HERE, base::Milliseconds(kSeekableTimeUpdateInterval), this,
129 &MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired);
133 void MediaPlayerBridgeCapiTV::StopSeekableTimeUpdateTimer() {
134 if (seekable_time_update_timer_.IsRunning())
135 seekable_time_update_timer_.Stop();
138 void MediaPlayerBridgeCapiTV::OnSeekableTimeUpdateTimerFired() {
139 UpdateSeekableTime();
142 void MediaPlayerBridgeCapiTV::GetAdaptiveStreamingInfo() {
143 int ret = player_get_adaptive_streaming_info(player_, &is_live_stream_,
144 PLAYER_ADAPTIVE_INFO_IS_LIVE);
145 if (ret != PLAYER_ERROR_NONE || is_live_stream_) {
146 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
147 << " A live stream.";
151 void MediaPlayerBridgeCapiTV::UpdateSeekableTime() {
152 if (GetPlayerState() == PLAYER_STATE_NONE || !is_live_stream_)
155 int64_t min = 0, max = 0;
156 if (GetLiveStreamingDuration(&min, &max)) {
157 if (min_seekable_time_.InMilliseconds() != min ||
158 max_seekable_time_.InMilliseconds() != max) {
159 min_seekable_time_ = base::Milliseconds(min);
160 max_seekable_time_ = base::Milliseconds(max);
161 if (GetMediaPlayerClient())
162 GetMediaPlayerClient()->OnSeekableTimeChange(
163 min_seekable_time_, max_seekable_time_, is_live_stream_);
169 GetAdaptiveStreamingInfo();
170 if (!is_live_stream_) {
171 LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
172 << " changed to static stream";
173 if (GetMediaPlayerClient())
174 GetMediaPlayerClient()->OnSeekableTimeChange({}, {}, is_live_stream_);
175 MediaPlayerBridgeCapi::UpdateDuration();
179 bool MediaPlayerBridgeCapiTV::GetLiveStreamingDuration(int64_t* min,
183 constexpr const size_t kDurationBufferSize = 64;
184 char live_duration[kDurationBufferSize] = {
187 char* live_ptr = live_duration;
188 const auto err = player_get_adaptive_streaming_info(
189 player_, live_duration, PLAYER_ADAPTIVE_INFO_LIVE_DURATION);
190 if (err != PLAYER_ERROR_NONE) {
191 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
192 << " |player_get_adaptive_streaming_info| failed " << err;
196 const std::string duration(live_duration);
197 const std::string::size_type delimiter = duration.find('|');
198 if (delimiter == std::string::npos) {
199 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
200 << " Failed to find delimiter | in duration: " << duration;
204 const std::string duration_min = duration.substr(0, delimiter);
205 if (duration_min.empty()) {
206 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
207 << " Failed empty min sub str: " << duration << ", "
213 if (!base::StringToInt64(duration_min, &out_min)) {
214 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
215 << " Failed to get min from duration: " << duration;
219 const std::string duration_max = duration.substr(delimiter + 1);
220 if (duration_max.empty()) {
221 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
222 << " empty max sub str: " << duration << ", " << delimiter;
227 if (!base::StringToInt64(duration_max, &out_max)) {
228 LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
229 << " Failed to get max from duration: " << duration;
238 void MediaPlayerBridgeCapiTV::AppendUrlHighBitRate(const std::string& url) {
239 // don't use url.append("|STARTBITRATE=HIGHEST") to get hbbtv url
240 // "|" will be replaced with "%7C"
241 const char high_bitrate[] = "|STARTBITRATE=HIGHEST";
242 int len = url.length() + strlen(high_bitrate) + 1;
243 char* str_url = new char[len];
248 memset(str_url, 0, len);
249 strncat(str_url, url.c_str(), url.length());
250 strncat(str_url, high_bitrate, strlen(high_bitrate));
251 hbbtv_url_ = str_url;
253 LOG(INFO) << "hbbtv url:" << hbbtv_url_.c_str();
256 bool MediaPlayerBridgeCapiTV::CheckHighBitRate() {
257 if (!GetMediaPlayerClient()) {
258 LOG(ERROR) << "MediaPlayerClient is null";
261 content::WebContentsDelegate* web_contents_delegate =
262 GetMediaPlayerClient()->GetWebContentsDelegate();
263 if (!web_contents_delegate) {
264 LOG(ERROR) << "get web_contents_delegate fail";
267 bool ret = web_contents_delegate->IsHighBitRate();
268 LOG(INFO) << "get high bit rate: " << std::boolalpha << ret;
272 void MediaPlayerBridgeCapiTV::HandleDownloadableFontInfo(
273 const std::string& scheme_id_uri,
274 const std::string& value,
275 const std::string& data,
277 content::WebContentsDelegate* web_contents_delegate =
278 GetMediaPlayerClient()->GetWebContentsDelegate();
279 if (!web_contents_delegate)
281 web_contents_delegate->NotifyDownloadableFontInfo(scheme_id_uri, value, data,
285 void MediaPlayerBridgeCapiTV::Initialize(VideoRendererSink* sink) {
286 player_set_drm_error_cb(player_, DrmErrorCb, this);
287 MediaPlayerBridgeCapi::Initialize(sink);
290 bool MediaPlayerBridgeCapiTV::SetDrmInfo(std::string& drm_info) {
291 // The DRM info from HbbTV comes as a JSON-like string in the following
293 // pair = Property ':' Value
294 // string = pair {',' pair}
295 std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
296 drm_info, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
297 for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
298 std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
299 *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
301 if (drm_info_pair.size() != 2)
304 std::string trim_key = drm_info_pair.at(0);
305 std::string trim_value = drm_info_pair.at(1);
306 LOG(INFO) << "trim_key: " << trim_key.c_str()
307 << ",trim_value: " << trim_value.c_str();
309 if (!SetMediaDRMInfo(trim_key, trim_value)) {
311 << "MediaPlayerBridgeCapiTV::SetDrmInfo SetMediaDRMInfo failed";
319 bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
320 const std::string& value_data) {
321 LOG(INFO) << "player_set_drm_info(type_length(" << type_data.length() << ") "
322 << " value_length(" << value_data.length() << ")) ";
323 int ret = PLAYER_ERROR_INVALID_OPERATION;
324 const void* type_data_ptr = type_data.c_str();
325 const void* value_data_ptr = value_data.c_str();
326 player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
327 ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
328 value_data_ptr, value_data.length(), drm_type);
329 if (ret != PLAYER_ERROR_NONE) {
330 MediaPlayerBridgeCapi::OnHandlePlayerError(ret, FROM_HERE);
337 void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
338 LOG(ERROR) << "OnDrmError err_str[" << err_str << "]";
339 if (!task_runner_->BelongsToCurrentThread()) {
340 task_runner_->PostTask(
342 base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
343 weak_factory_.GetWeakPtr(), err_code, err_str));
345 MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);