| 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() { |
| 94 if (manager_) | 57 Destroy(); |
| 95 manager_->UnregisterMediaPlayer(player_id_); | |
| 96 | 58 |
| 97 if (stream_id_) | 59 if (stream_id_) |
| 98 stream_texture_factory_->DestroyStreamTexture(texture_id_); | 60 stream_texture_factory_->DestroyStreamTexture(texture_id_); |
| 99 | 61 |
| 62 if (manager_) |
| 63 manager_->UnregisterMediaPlayer(player_id_); |
| 64 |
| 100 if (main_loop_) | 65 if (main_loop_) |
| 101 main_loop_->RemoveDestructionObserver(this); | 66 main_loop_->RemoveDestructionObserver(this); |
| 102 } | 67 } |
| 103 | 68 |
| 104 void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) { | |
| 105 incognito_mode_ = incognito_mode; | |
| 106 } | |
| 107 | |
| 108 void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) { | 69 void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) { |
| 109 if (cors_mode != CORSModeUnspecified) | 70 if (cors_mode != CORSModeUnspecified) |
| 110 NOTIMPLEMENTED() << "No CORS support"; | 71 NOTIMPLEMENTED() << "No CORS support"; |
| 111 | 72 |
| 112 url_ = url; | 73 url_ = url; |
| 113 | 74 |
| 114 UpdateNetworkState(WebMediaPlayer::NetworkStateLoading); | 75 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 } | 76 } |
| 139 | 77 |
| 140 void WebMediaPlayerAndroid::cancelLoad() { | 78 void WebMediaPlayerAndroid::cancelLoad() { |
| 141 NOTIMPLEMENTED(); | 79 NOTIMPLEMENTED(); |
| 142 } | 80 } |
| 143 | 81 |
| 144 void WebMediaPlayerAndroid::play() { | 82 void WebMediaPlayerAndroid::play() { |
| 145 if (media_player_.get()) { | 83 if (hasVideo() && needs_establish_peer_) |
| 146 if (!prepared_) | 84 EstablishSurfaceTexturePeer(); |
| 147 pending_play_event_ = true; | 85 |
| 148 else | 86 PlayInternal(); |
| 149 PlayInternal(); | 87 is_playing_ = true; |
| 150 } else { | |
| 151 pending_play_event_ = true; | |
| 152 InitializeMediaPlayer(); | |
| 153 } | |
| 154 } | 88 } |
| 155 | 89 |
| 156 void WebMediaPlayerAndroid::pause() { | 90 void WebMediaPlayerAndroid::pause() { |
| 157 if (media_player_.get()) { | 91 PauseInternal(); |
| 158 if (!prepared_) | 92 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 } | 93 } |
| 167 | 94 |
| 168 void WebMediaPlayerAndroid::seek(float seconds) { | 95 void WebMediaPlayerAndroid::seek(float seconds) { |
| 169 // Record the time to seek when OnMediaPrepared() is called. | |
| 170 pending_seek_ = seconds; | 96 pending_seek_ = seconds; |
| 97 seeking_ = true; |
| 171 | 98 |
| 172 // Reset |playback_completed_| so that we return the correct current time. | 99 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 } | 100 } |
| 182 | 101 |
| 183 bool WebMediaPlayerAndroid::supportsFullscreen() const { | 102 bool WebMediaPlayerAndroid::supportsFullscreen() const { |
| 184 return true; | 103 return true; |
| 185 } | 104 } |
| 186 | 105 |
| 187 bool WebMediaPlayerAndroid::supportsSave() const { | 106 bool WebMediaPlayerAndroid::supportsSave() const { |
| 188 return false; | 107 return false; |
| 189 } | 108 } |
| 190 | 109 |
| 191 void WebMediaPlayerAndroid::setEndTime(float seconds) { | 110 void WebMediaPlayerAndroid::setEndTime(float seconds) { |
| 192 // Deprecated. | 111 // Deprecated. |
| 193 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 112 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 194 } | 113 } |
| 195 | 114 |
| 196 void WebMediaPlayerAndroid::setRate(float rate) { | 115 void WebMediaPlayerAndroid::setRate(float rate) { |
| 197 NOTIMPLEMENTED(); | 116 NOTIMPLEMENTED(); |
| 198 } | 117 } |
| 199 | 118 |
| 200 void WebMediaPlayerAndroid::setVolume(float volume) { | 119 void WebMediaPlayerAndroid::setVolume(float volume) { |
| 201 if (media_player_.get()) | 120 NOTIMPLEMENTED(); |
| 202 media_player_->SetVolume(volume, volume); | |
| 203 } | 121 } |
| 204 | 122 |
| 205 void WebMediaPlayerAndroid::setVisible(bool visible) { | 123 void WebMediaPlayerAndroid::setVisible(bool visible) { |
| 206 // Deprecated. | 124 // Deprecated. |
| 207 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 125 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 208 } | 126 } |
| 209 | 127 |
| 210 bool WebMediaPlayerAndroid::totalBytesKnown() { | 128 bool WebMediaPlayerAndroid::totalBytesKnown() { |
| 211 NOTIMPLEMENTED(); | 129 NOTIMPLEMENTED(); |
| 212 return false; | 130 return false; |
| 213 } | 131 } |
| 214 | 132 |
| 215 bool WebMediaPlayerAndroid::hasVideo() const { | 133 bool WebMediaPlayerAndroid::hasVideo() const { |
| 134 // If we have obtained video size information before, use it. |
| 135 if (!natural_size_.isEmpty()) |
| 136 return true; |
| 137 |
| 216 // TODO(qinmin): need a better method to determine whether the current media | 138 // TODO(qinmin): need a better method to determine whether the current media |
| 217 // content contains video. Android does not provide any function to do | 139 // content contains video. Android does not provide any function to do |
| 218 // this. | 140 // this. |
| 219 // We don't know whether the current media content has video unless | 141 // 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 | 142 // 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. | 143 // 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 | 144 // In that case, we conservatively assume it contains video so that |
| 223 // enterfullscreen call will not fail. | 145 // enterfullscreen call will not fail. |
| 224 if (!prepared_) { | 146 if (!url_.has_path()) |
| 225 if (!url_.has_path()) | 147 return false; |
| 226 return false; | 148 std::string mime; |
| 227 std::string mime; | 149 if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime)) |
| 228 if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime)) | 150 return true; |
| 229 return true; | 151 return mime.find("audio/") == std::string::npos; |
| 230 return mime.find("audio/") == std::string::npos; | |
| 231 } | |
| 232 | |
| 233 return !natural_size_.isEmpty(); | |
| 234 } | 152 } |
| 235 | 153 |
| 236 bool WebMediaPlayerAndroid::hasAudio() const { | 154 bool WebMediaPlayerAndroid::hasAudio() const { |
| 237 // TODO(hclam): Query status of audio and return the actual value. | 155 // TODO(hclam): Query status of audio and return the actual value. |
| 238 return true; | 156 return true; |
| 239 } | 157 } |
| 240 | 158 |
| 241 bool WebMediaPlayerAndroid::paused() const { | 159 bool WebMediaPlayerAndroid::paused() const { |
| 242 if (!prepared_) | 160 return !is_playing_; |
| 243 return !pending_play_event_; | |
| 244 return !media_player_->IsPlaying(); | |
| 245 } | 161 } |
| 246 | 162 |
| 247 bool WebMediaPlayerAndroid::seeking() const { | 163 bool WebMediaPlayerAndroid::seeking() const { |
| 248 return seeking_; | 164 return seeking_; |
| 249 } | 165 } |
| 250 | 166 |
| 251 float WebMediaPlayerAndroid::duration() const { | 167 float WebMediaPlayerAndroid::duration() const { |
| 252 return duration_; | 168 return static_cast<float>(duration_.InSecondsF()); |
| 253 } | 169 } |
| 254 | 170 |
| 255 float WebMediaPlayerAndroid::currentTime() const { | 171 float WebMediaPlayerAndroid::currentTime() const { |
| 256 // If the player is pending for a seek, return the seek time. | 172 // If the player is pending for a seek, return the seek time. |
| 257 if (!prepared_ || seeking()) | 173 if (seeking()) |
| 258 return pending_seek_; | 174 return pending_seek_; |
| 259 | 175 |
| 260 // When playback is about to finish, android media player often stops | 176 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 } | 177 } |
| 270 | 178 |
| 271 int WebMediaPlayerAndroid::dataRate() const { | 179 int WebMediaPlayerAndroid::dataRate() const { |
| 272 // Deprecated. | 180 // Deprecated. |
| 273 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 181 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 274 return 0; | 182 return 0; |
| 275 } | 183 } |
| 276 | 184 |
| 277 WebSize WebMediaPlayerAndroid::naturalSize() const { | 185 WebSize WebMediaPlayerAndroid::naturalSize() const { |
| 278 return natural_size_; | 186 return natural_size_; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 300 did_loading_progress_ = false; | 208 did_loading_progress_ = false; |
| 301 return ret; | 209 return ret; |
| 302 } | 210 } |
| 303 | 211 |
| 304 unsigned long long WebMediaPlayerAndroid::totalBytes() const { | 212 unsigned long long WebMediaPlayerAndroid::totalBytes() const { |
| 305 // Deprecated. | 213 // Deprecated. |
| 306 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 214 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 307 return 0; | 215 return 0; |
| 308 } | 216 } |
| 309 | 217 |
| 310 void WebMediaPlayerAndroid::setSize(const WebSize& size) { | 218 void WebMediaPlayerAndroid::setSize(const WebKit::WebSize& size) { |
| 311 texture_size_ = size; | |
| 312 } | 219 } |
| 313 | 220 |
| 314 void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas, | 221 void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas, |
| 315 const WebKit::WebRect& rect, | 222 const WebKit::WebRect& rect, |
| 316 uint8_t alpha) { | 223 uint8_t alpha) { |
| 317 NOTIMPLEMENTED(); | 224 NOTIMPLEMENTED(); |
| 318 } | 225 } |
| 319 | 226 |
| 320 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const { | 227 bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const { |
| 321 return false; | 228 return false; |
| 322 } | 229 } |
| 323 | 230 |
| 324 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const { | 231 bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const { |
| 325 return false; | 232 return false; |
| 326 } | 233 } |
| 327 | 234 |
| 328 WebMediaPlayer::MovieLoadType | 235 WebMediaPlayer::MovieLoadType WebMediaPlayerAndroid::movieLoadType() const { |
| 329 WebMediaPlayerAndroid::movieLoadType() const { | |
| 330 // Deprecated. | 236 // Deprecated. |
| 331 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. | 237 // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used. |
| 332 return WebMediaPlayer::MovieLoadTypeUnknown; | 238 return WebMediaPlayer::MovieLoadTypeUnknown; |
| 333 } | 239 } |
| 334 | 240 |
| 335 float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const { | 241 float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const { |
| 336 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); | 242 return ConvertSecondsToTimestamp(timeValue).InSecondsF(); |
| 337 } | 243 } |
| 338 | 244 |
| 339 unsigned WebMediaPlayerAndroid::decodedFrameCount() const { | 245 unsigned WebMediaPlayerAndroid::decodedFrameCount() const { |
| 340 NOTIMPLEMENTED(); | 246 NOTIMPLEMENTED(); |
| 341 return 0; | 247 return 0; |
| 342 } | 248 } |
| 343 | 249 |
| 344 unsigned WebMediaPlayerAndroid::droppedFrameCount() const { | 250 unsigned WebMediaPlayerAndroid::droppedFrameCount() const { |
| 345 NOTIMPLEMENTED(); | 251 NOTIMPLEMENTED(); |
| 346 return 0; | 252 return 0; |
| 347 } | 253 } |
| 348 | 254 |
| 349 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const { | 255 unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const { |
| 350 NOTIMPLEMENTED(); | 256 NOTIMPLEMENTED(); |
| 351 return 0; | 257 return 0; |
| 352 } | 258 } |
| 353 | 259 |
| 354 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { | 260 unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { |
| 355 NOTIMPLEMENTED(); | 261 NOTIMPLEMENTED(); |
| 356 return 0; | 262 return 0; |
| 357 } | 263 } |
| 358 | 264 |
| 359 void WebMediaPlayerAndroid::OnMediaPrepared() { | 265 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")) | 266 if (url_.SchemeIs("file")) |
| 371 UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); | 267 UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); |
| 372 | 268 |
| 373 if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) { | 269 if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) { |
| 374 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 270 UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| 375 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 271 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 376 } else { | 272 } else { |
| 377 // If the status is already set to ReadyStateHaveEnoughData, set it again | 273 // If the status is already set to ReadyStateHaveEnoughData, set it again |
| 378 // to make sure that Videolayerchromium will get created. | 274 // to make sure that Videolayerchromium will get created. |
| 379 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 275 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 380 } | 276 } |
| 381 | 277 |
| 382 if (!url_.SchemeIs("file")) { | 278 // In we have skipped loading, we have to update webkit about the new |
| 383 // In we have skipped loading, the duration was preset to | 279 // duration. |
| 384 // kTemporaryDuration. We have to update webkit about the new duration. | 280 if (duration_ != duration) { |
| 385 if (duration_ != dur) { | 281 duration_ = duration; |
| 386 // Scale the |pending_seek_| according to the new duration. | 282 client_->durationChanged(); |
| 387 pending_seek_ = pending_seek_ * duration_ / kTemporaryDuration; | |
| 388 client_->durationChanged(); | |
| 389 } | |
| 390 } | 283 } |
| 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 } | 284 } |
| 401 | 285 |
| 402 void WebMediaPlayerAndroid::OnPlaybackComplete() { | 286 void WebMediaPlayerAndroid::OnPlaybackComplete() { |
| 403 // Set the current time equal to duration to let webkit know that play back | 287 // When playback is about to finish, android media player often stops |
| 404 // is completed. | 288 // at a time which is smaller than the duration. This makes webkit never |
| 405 playback_completed_ = true; | 289 // know that the playback has finished. To solve this, we set the |
| 290 // current time to media duration when OnPlaybackComplete() get called. |
| 291 OnTimeUpdate(duration_); |
| 406 client_->timeChanged(); | 292 client_->timeChanged(); |
| 407 } | 293 } |
| 408 | 294 |
| 409 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) { | 295 void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) { |
| 410 buffered_[0].end = duration() * percentage / 100; | 296 buffered_[0].end = duration() * percentage / 100; |
| 411 did_loading_progress_ = true; | 297 did_loading_progress_ = true; |
| 412 } | 298 } |
| 413 | 299 |
| 414 void WebMediaPlayerAndroid::OnSeekComplete() { | 300 void WebMediaPlayerAndroid::OnSeekComplete(base::TimeDelta current_time) { |
| 415 seeking_ = false; | 301 seeking_ = false; |
| 416 | 302 |
| 303 OnTimeUpdate(current_time); |
| 304 |
| 417 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 305 UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 418 | 306 |
| 419 client_->timeChanged(); | 307 client_->timeChanged(); |
| 420 } | 308 } |
| 421 | 309 |
| 422 void WebMediaPlayerAndroid::OnMediaError(int error_type) { | 310 void WebMediaPlayerAndroid::OnMediaError(int error_type) { |
| 423 switch (error_type) { | 311 switch (error_type) { |
| 424 case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN: | 312 case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN: |
| 425 // When playing an bogus URL or bad file we fire a MEDIA_ERROR_UNKNOWN. | 313 // 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 | 314 // As WebKit uses FormatError to indicate an error for bogus URL or bad |
| 427 // file we default a MEDIA_ERROR_UNKNOWN to NetworkStateFormatError. | 315 // file we default a MEDIA_ERROR_UNKNOWN to NetworkStateFormatError. |
| 428 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); | 316 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); |
| 429 break; | 317 break; |
| 430 case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED: | 318 case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED: |
| 431 // TODO(zhenghao): Media server died. In this case, the application must | 319 // TODO(zhenghao): Media server died. In this case, the application must |
| 432 // release the MediaPlayer object and instantiate a new one. | 320 // release the MediaPlayer object and instantiate a new one. |
| 433 UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError); | 321 UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError); |
| 434 break; | 322 break; |
| 435 case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: | 323 case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: |
| 436 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); | 324 UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError); |
| 437 break; | 325 break; |
| 438 case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE: | 326 case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE: |
| 439 break; | 327 break; |
| 440 } | 328 } |
| 441 client_->repaint(); | 329 client_->repaint(); |
| 442 } | 330 } |
| 443 | 331 |
| 444 void WebMediaPlayerAndroid::OnMediaInfo(int info_type) { | |
| 445 NOTIMPLEMENTED(); | |
| 446 } | |
| 447 | |
| 448 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { | 332 void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { |
| 449 if (natural_size_.width == width && natural_size_.height == height) | 333 if (natural_size_.width == width && natural_size_.height == height) |
| 450 return; | 334 return; |
| 451 | 335 |
| 452 natural_size_.width = width; | 336 natural_size_.width = width; |
| 453 natural_size_.height = height; | 337 natural_size_.height = height; |
| 454 if (texture_id_) { | 338 if (texture_id_) { |
| 455 video_frame_.reset(new WebVideoFrameImpl(VideoFrame::WrapNativeTexture( | 339 video_frame_.reset(new WebVideoFrameImpl(VideoFrame::WrapNativeTexture( |
| 456 texture_id_, kGLTextureExternalOES, natural_size_, natural_size_, | 340 texture_id_, kGLTextureExternalOES, natural_size_, natural_size_, |
| 457 base::TimeDelta(), | 341 base::TimeDelta(), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 468 void WebMediaPlayerAndroid::UpdateReadyState( | 352 void WebMediaPlayerAndroid::UpdateReadyState( |
| 469 WebMediaPlayer::ReadyState state) { | 353 WebMediaPlayer::ReadyState state) { |
| 470 ready_state_ = state; | 354 ready_state_ = state; |
| 471 client_->readyStateChanged(); | 355 client_->readyStateChanged(); |
| 472 } | 356 } |
| 473 | 357 |
| 474 void WebMediaPlayerAndroid::ReleaseMediaResources() { | 358 void WebMediaPlayerAndroid::ReleaseMediaResources() { |
| 475 // Pause the media player first. | 359 // Pause the media player first. |
| 476 pause(); | 360 pause(); |
| 477 client_->playbackStateChanged(); | 361 client_->playbackStateChanged(); |
| 362 needs_establish_peer_ = true; |
| 478 | 363 |
| 479 if (media_player_.get()) { | 364 ReleaseResourcesInternal(); |
| 480 // Save the current media player status. | |
| 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 } | 365 } |
| 544 | 366 |
| 545 void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { | 367 void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { |
| 368 Destroy(); |
| 369 |
| 370 if (stream_id_) { |
| 371 stream_texture_factory_->DestroyStreamTexture(texture_id_); |
| 372 stream_id_ = 0; |
| 373 } |
| 374 |
| 375 video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())); |
| 376 |
| 377 if (manager_) |
| 378 manager_->UnregisterMediaPlayer(player_id_); |
| 379 |
| 546 manager_ = NULL; | 380 manager_ = NULL; |
| 547 main_loop_ = NULL; | 381 main_loop_ = NULL; |
| 548 } | 382 } |
| 549 | 383 |
| 550 WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() { | 384 WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() { |
| 551 if (!stream_texture_proxy_->IsInitialized() && stream_id_) { | 385 if (stream_texture_proxy_.get() && !stream_texture_proxy_->IsInitialized() |
| 386 && stream_id_) { |
| 552 stream_texture_proxy_->Initialize( | 387 stream_texture_proxy_->Initialize( |
| 553 stream_id_, video_frame_->width(), video_frame_->height()); | 388 stream_id_, video_frame_->width(), video_frame_->height()); |
| 554 } | 389 } |
| 555 | 390 |
| 556 return video_frame_.get(); | 391 return video_frame_.get(); |
| 557 } | 392 } |
| 558 | 393 |
| 559 void WebMediaPlayerAndroid::putCurrentFrame( | 394 void WebMediaPlayerAndroid::putCurrentFrame( |
| 560 WebVideoFrame* web_video_frame) { | 395 WebVideoFrame* web_video_frame) { |
| 561 } | 396 } |
| 562 | 397 |
| 563 // This gets called both on compositor and main thread. | |
| 564 void WebMediaPlayerAndroid::setStreamTextureClient( | 398 void WebMediaPlayerAndroid::setStreamTextureClient( |
| 565 WebKit::WebStreamTextureClient* client) { | 399 WebKit::WebStreamTextureClient* client) { |
| 566 if (stream_texture_proxy_.get()) | 400 if (stream_texture_proxy_.get()) |
| 567 stream_texture_proxy_->SetClient(client); | 401 stream_texture_proxy_->SetClient(client); |
| 568 } | 402 } |
| 569 | 403 |
| 404 void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() { |
| 405 if (stream_texture_factory_.get() && stream_id_) |
| 406 stream_texture_factory_->EstablishPeer(stream_id_, player_id_); |
| 407 needs_establish_peer_ = false; |
| 408 } |
| 409 |
| 410 void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) { |
| 411 is_playing_ = is_playing; |
| 412 } |
| 413 |
| 570 } // namespace webkit_media | 414 } // namespace webkit_media |
| OLD | NEW |