| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/media/android/webmediaplayer_android.h" | 5 #include "webkit/media/android/webmediaplayer_android.h" |
| 6 | 6 |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/command_line.h" | |
| 11 #include "base/file_path.h" | 7 #include "base/file_path.h" |
| 12 #include "base/logging.h" | 8 #include "base/logging.h" |
| 13 #include "base/utf_string_conversions.h" | |
| 14 #include "media/base/android/media_player_bridge.h" | 9 #include "media/base/android/media_player_bridge.h" |
| 15 #include "net/base/mime_util.h" | 10 #include "net/base/mime_util.h" |
| 16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | |
| 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.
h" | 11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.
h" |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCookieJar
.h" | |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" | |
| 22 #include "webkit/media/android/stream_texture_factory_android.h" | 12 #include "webkit/media/android/stream_texture_factory_android.h" |
| 23 #include "webkit/media/android/webmediaplayer_manager_android.h" | 13 #include "webkit/media/android/webmediaplayer_manager_android.h" |
| 24 #include "webkit/media/android/webmediaplayer_proxy_android.h" | |
| 25 #include "webkit/media/webmediaplayer_util.h" | 14 #include "webkit/media/webmediaplayer_util.h" |
| 26 #include "webkit/media/webvideoframe_impl.h" | 15 #include "webkit/media/webvideoframe_impl.h" |
| 27 | 16 |
| 28 using WebKit::WebCanvas; | 17 static const uint32 kGLTextureExternalOES = 0x8D65; |
| 29 using WebKit::WebMediaPlayerClient; | 18 |
| 30 using WebKit::WebMediaPlayer; | 19 using WebKit::WebMediaPlayer; |
| 31 using WebKit::WebRect; | |
| 32 using WebKit::WebSize; | 20 using WebKit::WebSize; |
| 33 using WebKit::WebTimeRanges; | 21 using WebKit::WebTimeRanges; |
| 34 using WebKit::WebURL; | 22 using WebKit::WebURL; |
| 35 using WebKit::WebVideoFrame; | 23 using WebKit::WebVideoFrame; |
| 36 using media::MediaPlayerBridge; | 24 using media::MediaPlayerBridge; |
| 37 using media::VideoFrame; | 25 using media::VideoFrame; |
| 38 using webkit_media::WebVideoFrameImpl; | |
| 39 | |
| 40 // TODO(qinmin): Figure out where we should define this more appropriately | |
| 41 static const uint32 kGLTextureExternalOES = 0x8D65; | |
| 42 | 26 |
| 43 namespace webkit_media { | 27 namespace webkit_media { |
| 44 | 28 |
| 45 // Because we create the media player lazily on android, the duration of the | |
| 46 // media is initially unknown to us. This makes the user unable to perform | |
| 47 // seek. To solve this problem, we use a temporary duration of 100 seconds when | |
| 48 // the duration is unknown. And we scale the seek position later when duration | |
| 49 // is available. | |
| 50 // TODO(qinmin): create a thread and use android MediaMetadataRetriever | |
| 51 // class to extract the duration. | |
| 52 static const float kTemporaryDuration = 100.0f; | |
| 53 | |
| 54 bool WebMediaPlayerAndroid::incognito_mode_ = false; | |
| 55 | |
| 56 WebMediaPlayerAndroid::WebMediaPlayerAndroid( | 29 WebMediaPlayerAndroid::WebMediaPlayerAndroid( |
| 57 WebKit::WebFrame* frame, | 30 WebKit::WebMediaPlayerClient* client, |
| 58 WebMediaPlayerClient* client, | 31 WebMediaPlayerManagerAndroid* manager, |
| 59 WebKit::WebCookieJar* cookie_jar, | 32 StreamTextureFactory* factory) |
| 60 webkit_media::WebMediaPlayerManagerAndroid* manager, | 33 : client_(client), |
| 61 webkit_media::StreamTextureFactory* factory) | |
| 62 : frame_(frame), | |
| 63 client_(client), | |
| 64 buffered_(1u), | 34 buffered_(1u), |
| 65 video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())), | 35 video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())), |
| 66 main_loop_(MessageLoop::current()), | 36 main_loop_(MessageLoop::current()), |
| 67 proxy_(new WebMediaPlayerProxyAndroid(main_loop_->message_loop_proxy(), | |
| 68 AsWeakPtr())), | |
| 69 prepared_(false), | |
| 70 duration_(0), | |
| 71 pending_seek_(0), | 37 pending_seek_(0), |
| 72 seeking_(false), | 38 seeking_(false), |
| 73 playback_completed_(false), | |
| 74 did_loading_progress_(false), | 39 did_loading_progress_(false), |
| 75 cookie_jar_(cookie_jar), | |
| 76 manager_(manager), | 40 manager_(manager), |
| 77 pending_play_event_(false), | |
| 78 network_state_(WebMediaPlayer::NetworkStateEmpty), | 41 network_state_(WebMediaPlayer::NetworkStateEmpty), |
| 79 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 42 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| 80 texture_id_(0), | 43 is_playing_(false), |
| 81 stream_id_(0), | |
| 82 needs_establish_peer_(true), | 44 needs_establish_peer_(true), |
| 83 stream_texture_factory_(factory) { | 45 stream_texture_factory_(factory) { |
| 84 main_loop_->AddDestructionObserver(this); | 46 main_loop_->AddDestructionObserver(this); |
| 85 if (manager_) | 47 if (manager_) |
| 86 player_id_ = manager_->RegisterMediaPlayer(this); | 48 player_id_ = manager_->RegisterMediaPlayer(this); |
| 49 |
| 87 if (stream_texture_factory_.get()) { | 50 if (stream_texture_factory_.get()) { |
| 88 stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy()); | 51 stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy()); |
| 89 stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_); | 52 stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_); |
| 90 } | 53 } |
| 91 } | 54 } |
| 92 | 55 |
| 93 WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { | 56 WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { |
| 57 if (stream_id_) |
| 58 stream_texture_factory_->DestroyStreamTexture(texture_id_); |
| 59 |
| 94 if (manager_) | 60 if (manager_) |
| 95 manager_->UnregisterMediaPlayer(player_id_); | 61 manager_->UnregisterMediaPlayer(player_id_); |
| 96 | 62 |
| 97 if (stream_id_) | |
| 98 stream_texture_factory_->DestroyStreamTexture(texture_id_); | |
| 99 | |
| 100 if (main_loop_) | 63 if (main_loop_) |
| 101 main_loop_->RemoveDestructionObserver(this); | 64 main_loop_->RemoveDestructionObserver(this); |
| 102 } | 65 } |
| 103 | 66 |
| 104 void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) { | |
| 105 incognito_mode_ = incognito_mode; | |
| 106 } | |
| 107 | |
| 108 void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) { | 67 void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) { |
| 109 if (cors_mode != CORSModeUnspecified) | 68 if (cors_mode != CORSModeUnspecified) |
| 110 NOTIMPLEMENTED() << "No CORS support"; | 69 NOTIMPLEMENTED() << "No CORS support"; |
| 111 | 70 |
| 112 url_ = url; | 71 url_ = url; |
| 113 | 72 |
| 114 UpdateNetworkState(WebMediaPlayer::NetworkStateLoading); | 73 InitializeMediaPlayer(url_); |
| 115 UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing); | |
| 116 | |
| 117 // Calling InitializeMediaPlayer() will cause android mediaplayer to start | |
| 118 // buffering and decoding the data. On mobile devices, this costs a lot of | |
| 119 // data usage and could even introduce performance issues. So we don't | |
| 120 // initialize the player unless it is a local file. We will start loading | |
| 121 // the media only when play/seek/fullsceen button is clicked. | |
| 122 if (url_.SchemeIs("file")) { | |
| 123 InitializeMediaPlayer(); | |
| 124 return; | |
| 125 } | |
| 126 | |
| 127 // TODO(qinmin): we need a method to calculate the duration of the media. | |
| 128 // Android does not provide any function to do that. | |
| 129 // Set the initial duration value to kTemporaryDuration so that user can | |
| 130 // touch the seek bar to perform seek. We will scale the seek position later | |
| 131 // when we got the actual duration. | |
| 132 duration_ = kTemporaryDuration; | |
| 133 | |
| 134 // Pretend everything has been loaded so that webkit can | |
| 135 // still call play() and seek(). | |
| 136 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | |
| 137 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | |
| 138 } | 74 } |
| 139 | 75 |
| 140 void WebMediaPlayerAndroid::cancelLoad() { | 76 void WebMediaPlayerAndroid::cancelLoad() { |
| 141 NOTIMPLEMENTED(); | 77 NOTIMPLEMENTED(); |
| 142 } | 78 } |
| 143 | 79 |
| 144 void WebMediaPlayerAndroid::play() { | 80 void WebMediaPlayerAndroid::play() { |
| 145 if (media_player_.get()) { | 81 if (hasVideo() && needs_establish_peer_) |
| 146 if (!prepared_) | 82 EstablishSurfaceTexturePeer(); |
| 147 pending_play_event_ = true; | 83 |
| 148 else | 84 PlayInternal(); |
| 149 PlayInternal(); | 85 is_playing_ = true; |
| 150 } else { | |
| 151 pending_play_event_ = true; | |
| 152 InitializeMediaPlayer(); | |
| 153 } | |
| 154 } | 86 } |
| 155 | 87 |
| 156 void WebMediaPlayerAndroid::pause() { | 88 void WebMediaPlayerAndroid::pause() { |
| 157 if (media_player_.get()) { | 89 PauseInternal(); |
| 158 if (!prepared_) | 90 is_playing_ = false; |
| 159 pending_play_event_ = false; | |
| 160 else | |
| 161 PauseInternal(); | |
| 162 } else { | |
| 163 // We don't need to load media if pause() is called. | |
| 164 pending_play_event_ = false; | |
| 165 } | |
| 166 } | 91 } |
| 167 | 92 |
| 168 void WebMediaPlayerAndroid::seek(float seconds) { | 93 void WebMediaPlayerAndroid::seek(float seconds) { |
| 169 // Record the time to seek when OnMediaPrepared() is called. | |
| 170 pending_seek_ = seconds; | 94 pending_seek_ = seconds; |
| 95 seeking_ = true; |
| 171 | 96 |
| 172 // Reset |playback_completed_| so that we return the correct current time. | 97 SeekInternal(ConvertSecondsToTimestamp(seconds)); |
| 173 playback_completed_ = false; | |
| 174 | |
| 175 if (media_player_.get()) { | |
| 176 if (prepared_) | |
| 177 SeekInternal(seconds); | |
| 178 } else { | |
| 179 InitializeMediaPlayer(); | |
| 180 } | |
| 181 } | 98 } |
| 182 | 99 |
| 183 bool WebMediaPlayerAndroid::supportsFullscreen() const { | 100 bool WebMediaPlayerAndroid::supportsFullscreen() const { |
| 184 return true; | 101 return true; |
| 185 } | 102 } |
| 186 | 103 |
| 187 bool WebMediaPlayerAndroid::supportsSave() const { | 104 bool WebMediaPlayerAndroid::supportsSave() const { |
| 188 return false; | 105 return false; |
| 189 } | 106 } |
| 190 | 107 |
| 191 void WebMediaPlayerAndroid::setEndTime(float seconds) { | 108 void WebMediaPlayerAndroid::setEndTime(float seconds) { |
| 192 // Deprecated. | 109 // Deprecated. |
| 193 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 110 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 194 } | 111 } |
| 195 | 112 |
| 196 void WebMediaPlayerAndroid::setRate(float rate) { | 113 void WebMediaPlayerAndroid::setRate(float rate) { |
| 197 NOTIMPLEMENTED(); | 114 NOTIMPLEMENTED(); |
| 198 } | 115 } |
| 199 | 116 |
| 200 void WebMediaPlayerAndroid::setVolume(float volume) { | 117 void WebMediaPlayerAndroid::setVolume(float volume) { |
| 201 if (media_player_.get()) | 118 NOTIMPLEMENTED(); |
| 202 media_player_->SetVolume(volume, volume); | |
| 203 } | 119 } |
| 204 | 120 |
| 205 void WebMediaPlayerAndroid::setVisible(bool visible) { | 121 void WebMediaPlayerAndroid::setVisible(bool visible) { |
| 206 // Deprecated. | 122 // Deprecated. |
| 207 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 123 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 208 } | 124 } |
| 209 | 125 |
| 210 bool WebMediaPlayerAndroid::totalBytesKnown() { | 126 bool WebMediaPlayerAndroid::totalBytesKnown() { |
| 211 NOTIMPLEMENTED(); | 127 NOTIMPLEMENTED(); |
| 212 return false; | 128 return false; |
| 213 } | 129 } |
| 214 | 130 |
| 215 bool WebMediaPlayerAndroid::hasVideo() const { | 131 bool WebMediaPlayerAndroid::hasVideo() const { |
| 132 // If we have obtained video size information before, use it. |
| 133 if (!natural_size_.isEmpty()) |
| 134 return true; |
| 135 |
| 216 // TODO(qinmin): need a better method to determine whether the current media | 136 // TODO(qinmin): need a better method to determine whether the current media |
| 217 // content contains video. Android does not provide any function to do | 137 // content contains video. Android does not provide any function to do |
| 218 // this. | 138 // this. |
| 219 // We don't know whether the current media content has video unless | 139 // We don't know whether the current media content has video unless |
| 220 // the player is prepared. If the player is not prepared, we fall back | 140 // the player is prepared. If the player is not prepared, we fall back |
| 221 // to the mime-type. There may be no mime-type on a redirect URL. | 141 // to the mime-type. There may be no mime-type on a redirect URL. |
| 222 // In that case, we conservatively assume it contains video so that | 142 // In that case, we conservatively assume it contains video so that |
| 223 // enterfullscreen call will not fail. | 143 // enterfullscreen call will not fail. |
| 224 if (!prepared_) { | 144 if (!url_.has_path()) |
| 225 if (!url_.has_path()) | 145 return false; |
| 226 return false; | 146 std::string mime; |
| 227 std::string mime; | 147 if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime)) |
| 228 if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime)) | 148 return true; |
| 229 return true; | 149 return mime.find("audio/") == std::string::npos; |
| 230 return mime.find("audio/") == std::string::npos; | |
| 231 } | |
| 232 | |
| 233 return !natural_size_.isEmpty(); | |
| 234 } | 150 } |
| 235 | 151 |
| 236 bool WebMediaPlayerAndroid::hasAudio() const { | 152 bool WebMediaPlayerAndroid::hasAudio() const { |
| 237 // TODO(hclam): Query status of audio and return the actual value. | 153 // TODO(hclam): Query status of audio and return the actual value. |
| 238 return true; | 154 return true; |
| 239 } | 155 } |
| 240 | 156 |
| 241 bool WebMediaPlayerAndroid::paused() const { | 157 bool WebMediaPlayerAndroid::paused() const { |
| 242 if (!prepared_) | 158 return !is_playing_; |
| 243 return !pending_play_event_; | |
| 244 return !media_player_->IsPlaying(); | |
| 245 } | 159 } |
| 246 | 160 |
| 247 bool WebMediaPlayerAndroid::seeking() const { | 161 bool WebMediaPlayerAndroid::seeking() const { |
| 248 return seeking_; | 162 return seeking_; |
| 249 } | 163 } |
| 250 | 164 |
| 251 float WebMediaPlayerAndroid::duration() const { | 165 float WebMediaPlayerAndroid::duration() const { |
| 252 return duration_; | 166 return static_cast<float>(duration_.InSecondsF()); |
| 253 } | 167 } |
| 254 | 168 |
| 255 float WebMediaPlayerAndroid::currentTime() const { | 169 float WebMediaPlayerAndroid::currentTime() const { |
| 256 // If the player is pending for a seek, return the seek time. | 170 // If the player is pending for a seek, return the seek time. |
| 257 if (!prepared_ || seeking()) | 171 if (seeking()) |
| 258 return pending_seek_; | 172 return pending_seek_; |
| 259 | 173 |
| 260 // When playback is about to finish, android media player often stops | 174 return GetCurrentTimeInternal(); |
| 261 // at a time which is smaller than the duration. This makes webkit never | |
| 262 // know that the playback has finished. To solve this, we set the | |
| 263 // current time to media duration when OnPlaybackComplete() get called. | |
| 264 // And return the greater of the two values so that the current | |
| 265 // time is most updated. | |
| 266 if (playback_completed_) | |
| 267 return duration(); | |
| 268 return static_cast<float>(media_player_->GetCurrentTime().InSecondsF()); | |
| 269 } | 175 } |
| 270 | 176 |
| 271 int WebMediaPlayerAndroid::dataRate() const { | 177 int WebMediaPlayerAndroid::dataRate() const { |
| 272 // Deprecated. | 178 // Deprecated. |
| 273 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 179 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 274 return 0; | 180 return 0; |
| 275 } | 181 } |
| 276 | 182 |
| 277 WebSize WebMediaPlayerAndroid::naturalSize() const { | 183 WebSize WebMediaPlayerAndroid::naturalSize() const { |
| 278 return natural_size_; | 184 return natural_size_; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 300 did_loading_progress_ = false; | 206 did_loading_progress_ = false; |
| 301 return ret; | 207 return ret; |
| 302 } | 208 } |
| 303 | 209 |
| 304 unsigned long long WebMediaPlayerAndroid::totalBytes() const { | 210 unsigned long long WebMediaPlayerAndroid::totalBytes() const { |
| 305 // Deprecated. | 211 // Deprecated. |
| 306 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 212 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 307 return 0; | 213 return 0; |
| 308 } | 214 } |
| 309 | 215 |
| 310 void WebMediaPlayerAndroid::setSize(const WebSize& size) { | 216 void WebMediaPlayerAndroid::setSize(const WebKit::WebSize& size) { |
| 311 texture_size_ = size; | |
| 312 } | 217 } |
| 313 | 218 |
| 314 void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas, | 219 void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas, |
| 315 const WebKit::WebRect& rect, | 220 const WebKit::WebRect& rect, |
| 316 uint8_t alpha) { | 221 uint8_t alpha) { |
| 317 NOTIMPLEMENTED(); | 222 NOTIMPLEMENTED(); |
| 318 } | 223 } |
| 319 | 224 |
| 320 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const { | 225 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const { |
| 321 return false; | 226 return false; |
| 322 } | 227 } |
| 323 | 228 |
| 324 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const { | 229 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const { |
| 325 return false; | 230 return false; |
| 326 } | 231 } |
| 327 | 232 |
| 328 WebMediaPlayer::MovieLoadType | 233 WebMediaPlayer::MovieLoadType WebMediaPlayerAndroid::movieLoadType() const { |
| 329 WebMediaPlayerAndroid::movieLoadType() const { | |
| 330 // Deprecated. | 234 // Deprecated. |
| 331 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 235 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 332 return WebMediaPlayer::MovieLoadTypeUnknown; | 236 return WebMediaPlayer::MovieLoadTypeUnknown; |
| 333 } | 237 } |
| 334 | 238 |
| 335 float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const { | 239 float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const { |
| 336 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); | 240 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); |
| 337 } | 241 } |
| 338 | 242 |
| 339 unsigned WebMediaPlayerAndroid::decodedFrameCount() const { | 243 unsigned WebMediaPlayerAndroid::decodedFrameCount() const { |
| 340 NOTIMPLEMENTED(); | 244 NOTIMPLEMENTED(); |
| 341 return 0; | 245 return 0; |
| 342 } | 246 } |
| 343 | 247 |
| 344 unsigned WebMediaPlayerAndroid::droppedFrameCount() const { | 248 unsigned WebMediaPlayerAndroid::droppedFrameCount() const { |
| 345 NOTIMPLEMENTED(); | 249 NOTIMPLEMENTED(); |
| 346 return 0; | 250 return 0; |
| 347 } | 251 } |
| 348 | 252 |
| 349 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const { | 253 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const { |
| 350 NOTIMPLEMENTED(); | 254 NOTIMPLEMENTED(); |
| 351 return 0; | 255 return 0; |
| 352 } | 256 } |
| 353 | 257 |
| 354 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { | 258 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { |
| 355 NOTIMPLEMENTED(); | 259 NOTIMPLEMENTED(); |
| 356 return 0; | 260 return 0; |
| 357 } | 261 } |
| 358 | 262 |
| 359 void WebMediaPlayerAndroid::OnMediaPrepared() { | 263 void WebMediaPlayerAndroid::OnMediaPrepared(base::TimeDelta duration) { |
| 360 if (!media_player_.get()) | |
| 361 return; | |
| 362 | |
| 363 prepared_ = true; | |
| 364 | |
| 365 // Update the media duration first so that webkit will get the correct | |
| 366 // duration when UpdateReadyState is called. | |
| 367 float dur = duration_; | |
| 368 duration_ = media_player_->GetDuration().InSecondsF(); | |
| 369 | |
| 370 if (url_.SchemeIs("file")) | 264 if (url_.SchemeIs("file")) |
| 371 UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); | 265 UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); |
| 372 | 266 |
| 373 if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) { | 267 if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) { |
| 374 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 268 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| 375 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 269 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 376 } else { | 270 } else { |
| 377 // If the status is already set to ReadyStateHaveEnoughData, set it again | 271 // If the status is already set to ReadyStateHaveEnoughData, set it again |
| 378 // to make sure that Videolayerchromium will get created. | 272 // to make sure that Videolayerchromium will get created. |
| 379 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 273 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 380 } | 274 } |
| 381 | 275 |
| 382 if (!url_.SchemeIs("file")) { | 276 // In we have skipped loading, we have to update webkit about the new |
| 383 // In we have skipped loading, the duration was preset to | 277 // duration. |
| 384 // kTemporaryDuration. We have to update webkit about the new duration. | 278 if (duration_ != duration) { |
| 385 if (duration_ != dur) { | 279 duration_ = duration; |
| 386 // Scale the |pending_seek_| according to the new duration. | 280 client_->durationChanged(); |
| 387 pending_seek_ = pending_seek_ * duration_ / kTemporaryDuration; | |
| 388 client_->durationChanged(); | |
| 389 } | |
| 390 } | 281 } |
| 391 | |
| 392 // If media player was recovered from a saved state, consume all the pending | |
| 393 // events. | |
| 394 seek(pending_seek_); | |
| 395 | |
| 396 if (pending_play_event_) | |
| 397 PlayInternal(); | |
| 398 | |
| 399 pending_play_event_ = false; | |
| 400 } | 282 } |
| 401 | 283 |
| 402 void WebMediaPlayerAndroid::OnPlaybackComplete() { | 284 void WebMediaPlayerAndroid::OnPlaybackComplete() { |
| 403 // Set the current time equal to duration to let webkit know that play back | 285 // When playback is about to finish, android media player often stops |
| 404 // is completed. | 286 // at a time which is smaller than the duration. This makes webkit never |
| 405 playback_completed_ = true; | 287 // know that the playback has finished. To solve this, we set the |
| 288 // current time to media duration when OnPlaybackComplete() get called. |
| 289 OnTimeUpdate(duration_); |
| 406 client_->timeChanged(); | 290 client_->timeChanged(); |
| 407 } | 291 } |
| 408 | 292 |
| 409 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) { | 293 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) { |
| 410 buffered_[0].end = duration() * percentage / 100; | 294 buffered_[0].end = duration() * percentage / 100; |
| 411 did_loading_progress_ = true; | 295 did_loading_progress_ = true; |
| 412 } | 296 } |
| 413 | 297 |
| 414 void WebMediaPlayerAndroid::OnSeekComplete() { | 298 void WebMediaPlayerAndroid::OnSeekComplete(base::TimeDelta current_time) { |
| 415 seeking_ = false; | 299 seeking_ = false; |
| 416 | 300 |
| 301 OnTimeUpdate(current_time); |
| 302 |
| 417 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 303 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 418 | 304 |
| 419 client_->timeChanged(); | 305 client_->timeChanged(); |
| 420 } | 306 } |
| 421 | 307 |
| 422 void WebMediaPlayerAndroid::OnMediaError(int error_type) { | 308 void WebMediaPlayerAndroid::OnMediaError(int error_type) { |
| 423 switch (error_type) { | 309 switch (error_type) { |
| 424 case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN: | 310 case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN: |
| 425 // When playing an bogus URL or bad file we fire a MEDIA_ERROR_UNKNOWN. | 311 // When playing an bogus URL or bad file we fire a MEDIA_ERROR_UNKNOWN. |
| 426 // As WebKit uses FormatError to indicate an error for bogus URL or bad | 312 // As WebKit uses FormatError to indicate an error for bogus URL or bad |
| 427 // file we default a MEDIA_ERROR_UNKNOWN to NetworkStateFormatError. | 313 // file we default a MEDIA_ERROR_UNKNOWN to NetworkStateFormatError. |
| 428 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); | 314 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); |
| 429 break; | 315 break; |
| 430 case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED: | 316 case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED: |
| 431 // TODO(zhenghao): Media server died. In this case, the application must | 317 // TODO(zhenghao): Media server died. In this case, the application must |
| 432 // release the MediaPlayer object and instantiate a new one. | 318 // release the MediaPlayer object and instantiate a new one. |
| 433 UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError); | 319 UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError); |
| 434 break; | 320 break; |
| 435 case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: | 321 case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: |
| 436 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); | 322 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); |
| 437 break; | 323 break; |
| 438 case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE: | 324 case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE: |
| 439 break; | 325 break; |
| 440 } | 326 } |
| 441 client_->repaint(); | 327 client_->repaint(); |
| 442 } | 328 } |
| 443 | 329 |
| 444 void WebMediaPlayerAndroid::OnMediaInfo(int info_type) { | |
| 445 NOTIMPLEMENTED(); | |
| 446 } | |
| 447 | |
| 448 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { | 330 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { |
| 449 if (natural_size_.width == width && natural_size_.height == height) | 331 if (natural_size_.width == width && natural_size_.height == height) |
| 450 return; | 332 return; |
| 451 | 333 |
| 452 natural_size_.width = width; | 334 natural_size_.width = width; |
| 453 natural_size_.height = height; | 335 natural_size_.height = height; |
| 454 if (texture_id_) { | 336 if (texture_id_) { |
| 455 video_frame_.reset(new WebVideoFrameImpl(VideoFrame::WrapNativeTexture( | 337 video_frame_.reset(new WebVideoFrameImpl(VideoFrame::WrapNativeTexture( |
| 456 texture_id_, kGLTextureExternalOES, natural_size_, natural_size_, | 338 texture_id_, kGLTextureExternalOES, natural_size_, natural_size_, |
| 457 base::TimeDelta(), | 339 base::TimeDelta(), |
| 458 base::Closure()))); | 340 base::Closure()))); |
| 459 } | 341 } |
| 460 } | 342 } |
| 461 | 343 |
| 462 void WebMediaPlayerAndroid::UpdateNetworkState( | 344 void WebMediaPlayerAndroid::UpdateNetworkState( |
| 463 WebMediaPlayer::NetworkState state) { | 345 WebMediaPlayer::NetworkState state) { |
| 464 network_state_ = state; | 346 network_state_ = state; |
| 465 client_->networkStateChanged(); | 347 client_->networkStateChanged(); |
| 466 } | 348 } |
| 467 | 349 |
| 468 void WebMediaPlayerAndroid::UpdateReadyState( | 350 void WebMediaPlayerAndroid::UpdateReadyState( |
| 469 WebMediaPlayer::ReadyState state) { | 351 WebMediaPlayer::ReadyState state) { |
| 470 ready_state_ = state; | 352 ready_state_ = state; |
| 471 client_->readyStateChanged(); | 353 client_->readyStateChanged(); |
| 472 } | 354 } |
| 473 | 355 |
| 356 void WebMediaPlayerAndroid::OnPlayerReleased() { |
| 357 needs_establish_peer_ = true; |
| 358 } |
| 359 |
| 474 void WebMediaPlayerAndroid::ReleaseMediaResources() { | 360 void WebMediaPlayerAndroid::ReleaseMediaResources() { |
| 475 // Pause the media player first. | 361 // Pause the media player first. |
| 476 pause(); | 362 pause(); |
| 477 client_->playbackStateChanged(); | 363 client_->playbackStateChanged(); |
| 478 | 364 |
| 479 if (media_player_.get()) { | 365 ReleaseResourcesInternal(); |
| 480 // Save the current media player status. | 366 OnPlayerReleased(); |
| 481 pending_seek_ = currentTime(); | |
| 482 duration_ = duration(); | |
| 483 | |
| 484 media_player_.reset(); | |
| 485 needs_establish_peer_ = true; | |
| 486 } | |
| 487 prepared_ = false; | |
| 488 } | |
| 489 | |
| 490 bool WebMediaPlayerAndroid::IsInitialized() const { | |
| 491 return (media_player_ != NULL); | |
| 492 } | |
| 493 | |
| 494 void WebMediaPlayerAndroid::InitializeMediaPlayer() { | |
| 495 CHECK(!media_player_.get()); | |
| 496 prepared_ = false; | |
| 497 media_player_.reset(new MediaPlayerBridge()); | |
| 498 media_player_->SetStayAwakeWhilePlaying(); | |
| 499 | |
| 500 std::string cookies; | |
| 501 if (cookie_jar_ != NULL) { | |
| 502 WebURL first_party_url(frame_->document().firstPartyForCookies()); | |
| 503 cookies = UTF16ToUTF8(cookie_jar_->cookies(url_, first_party_url)); | |
| 504 } | |
| 505 media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_); | |
| 506 | |
| 507 if (manager_) | |
| 508 manager_->RequestMediaResources(player_id_); | |
| 509 | |
| 510 media_player_->Prepare( | |
| 511 base::Bind(&WebMediaPlayerProxyAndroid::MediaInfoCallback, proxy_), | |
| 512 base::Bind(&WebMediaPlayerProxyAndroid::MediaErrorCallback, proxy_), | |
| 513 base::Bind(&WebMediaPlayerProxyAndroid::VideoSizeChangedCallback, proxy_), | |
| 514 base::Bind(&WebMediaPlayerProxyAndroid::BufferingUpdateCallback, proxy_), | |
| 515 base::Bind(&WebMediaPlayerProxyAndroid::MediaPreparedCallback, proxy_)); | |
| 516 } | |
| 517 | |
| 518 void WebMediaPlayerAndroid::PlayInternal() { | |
| 519 CHECK(prepared_); | |
| 520 | |
| 521 if (hasVideo() && stream_texture_factory_.get()) { | |
| 522 if (needs_establish_peer_) { | |
| 523 stream_texture_factory_->EstablishPeer(stream_id_, player_id_); | |
| 524 needs_establish_peer_ = false; | |
| 525 } | |
| 526 } | |
| 527 | |
| 528 if (paused()) | |
| 529 media_player_->Start(base::Bind( | |
| 530 &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_)); | |
| 531 } | |
| 532 | |
| 533 void WebMediaPlayerAndroid::PauseInternal() { | |
| 534 CHECK(prepared_); | |
| 535 media_player_->Pause(); | |
| 536 } | |
| 537 | |
| 538 void WebMediaPlayerAndroid::SeekInternal(float seconds) { | |
| 539 CHECK(prepared_); | |
| 540 seeking_ = true; | |
| 541 media_player_->SeekTo(ConvertSecondsToTimestamp(seconds), base::Bind( | |
| 542 &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_)); | |
| 543 } | 367 } |
| 544 | 368 |
| 545 void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { | 369 void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { |
| 370 Destroy(); |
| 371 |
| 372 if (stream_id_) { |
| 373 stream_texture_factory_->DestroyStreamTexture(texture_id_); |
| 374 stream_id_ = 0; |
| 375 } |
| 376 |
| 377 video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())); |
| 378 |
| 379 if (manager_) |
| 380 manager_->UnregisterMediaPlayer(player_id_); |
| 381 |
| 546 manager_ = NULL; | 382 manager_ = NULL; |
| 547 main_loop_ = NULL; | 383 main_loop_ = NULL; |
| 548 } | 384 } |
| 549 | 385 |
| 550 WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() { | 386 WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() { |
| 551 if (!stream_texture_proxy_->IsInitialized() && stream_id_) { | 387 if (stream_texture_proxy_.get() && !stream_texture_proxy_->IsInitialized() |
| 388 && stream_id_) { |
| 552 stream_texture_proxy_->Initialize( | 389 stream_texture_proxy_->Initialize( |
| 553 stream_id_, video_frame_->width(), video_frame_->height()); | 390 stream_id_, video_frame_->width(), video_frame_->height()); |
| 554 } | 391 } |
| 555 | 392 |
| 556 return video_frame_.get(); | 393 return video_frame_.get(); |
| 557 } | 394 } |
| 558 | 395 |
| 559 void WebMediaPlayerAndroid::putCurrentFrame( | 396 void WebMediaPlayerAndroid::putCurrentFrame( |
| 560 WebVideoFrame* web_video_frame) { | 397 WebVideoFrame* web_video_frame) { |
| 561 } | 398 } |
| 562 | 399 |
| 563 // This gets called both on compositor and main thread. | |
| 564 void WebMediaPlayerAndroid::setStreamTextureClient( | 400 void WebMediaPlayerAndroid::setStreamTextureClient( |
| 565 WebKit::WebStreamTextureClient* client) { | 401 WebKit::WebStreamTextureClient* client) { |
| 566 if (stream_texture_proxy_.get()) | 402 if (stream_texture_proxy_.get()) |
| 567 stream_texture_proxy_->SetClient(client); | 403 stream_texture_proxy_->SetClient(client); |
| 568 } | 404 } |
| 569 | 405 |
| 406 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() { |
| 407 if (stream_texture_factory_.get() && stream_id_) |
| 408 stream_texture_factory_->EstablishPeer(stream_id_, player_id_); |
| 409 needs_establish_peer_ = false; |
| 410 } |
| 411 |
| 412 void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) { |
| 413 is_playing_ = is_playing; |
| 414 } |
| 415 |
| 570 } // namespace webkit_media | 416 } // namespace webkit_media |
| OLD | NEW |