| Index: webkit/media/android/webmediaplayer_android.cc
|
| diff --git a/webkit/media/android/webmediaplayer_android.cc b/webkit/media/android/webmediaplayer_android.cc
|
| index 8032a8cea779b0ae778d20b3fdb19a50221f8348..fae25d6ffd800c028354feb528cefc1960a7c526 100644
|
| --- a/webkit/media/android/webmediaplayer_android.cc
|
| +++ b/webkit/media/android/webmediaplayer_android.cc
|
| @@ -4,86 +4,49 @@
|
|
|
| #include "webkit/media/android/webmediaplayer_android.h"
|
|
|
| -#include <string>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/command_line.h"
|
| #include "base/file_path.h"
|
| #include "base/logging.h"
|
| -#include "base/utf_string_conversions.h"
|
| #include "media/base/android/media_player_bridge.h"
|
| #include "net/base/mime_util.h"
|
| -#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
|
| -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
|
| -#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
| -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCookieJar.h"
|
| -#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
|
| #include "webkit/media/android/stream_texture_factory_android.h"
|
| #include "webkit/media/android/webmediaplayer_manager_android.h"
|
| -#include "webkit/media/android/webmediaplayer_proxy_android.h"
|
| #include "webkit/media/webmediaplayer_util.h"
|
| #include "webkit/media/webvideoframe_impl.h"
|
|
|
| -using WebKit::WebCanvas;
|
| -using WebKit::WebMediaPlayerClient;
|
| +static const uint32 kGLTextureExternalOES = 0x8D65;
|
| +
|
| using WebKit::WebMediaPlayer;
|
| -using WebKit::WebRect;
|
| using WebKit::WebSize;
|
| using WebKit::WebTimeRanges;
|
| using WebKit::WebURL;
|
| using WebKit::WebVideoFrame;
|
| using media::MediaPlayerBridge;
|
| using media::VideoFrame;
|
| -using webkit_media::WebVideoFrameImpl;
|
| -
|
| -// TODO(qinmin): Figure out where we should define this more appropriately
|
| -static const uint32 kGLTextureExternalOES = 0x8D65;
|
|
|
| namespace webkit_media {
|
|
|
| -// Because we create the media player lazily on android, the duration of the
|
| -// media is initially unknown to us. This makes the user unable to perform
|
| -// seek. To solve this problem, we use a temporary duration of 100 seconds when
|
| -// the duration is unknown. And we scale the seek position later when duration
|
| -// is available.
|
| -// TODO(qinmin): create a thread and use android MediaMetadataRetriever
|
| -// class to extract the duration.
|
| -static const float kTemporaryDuration = 100.0f;
|
| -
|
| -bool WebMediaPlayerAndroid::incognito_mode_ = false;
|
| -
|
| WebMediaPlayerAndroid::WebMediaPlayerAndroid(
|
| - WebKit::WebFrame* frame,
|
| - WebMediaPlayerClient* client,
|
| - WebKit::WebCookieJar* cookie_jar,
|
| - webkit_media::WebMediaPlayerManagerAndroid* manager,
|
| - webkit_media::StreamTextureFactory* factory)
|
| - : frame_(frame),
|
| - client_(client),
|
| + WebKit::WebMediaPlayerClient* client,
|
| + WebMediaPlayerManagerAndroid* manager,
|
| + StreamTextureFactory* factory)
|
| + : client_(client),
|
| buffered_(1u),
|
| video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())),
|
| main_loop_(MessageLoop::current()),
|
| - proxy_(new WebMediaPlayerProxyAndroid(main_loop_->message_loop_proxy(),
|
| - AsWeakPtr())),
|
| - prepared_(false),
|
| - duration_(0),
|
| pending_seek_(0),
|
| seeking_(false),
|
| - playback_completed_(false),
|
| did_loading_progress_(false),
|
| - cookie_jar_(cookie_jar),
|
| manager_(manager),
|
| - pending_play_event_(false),
|
| network_state_(WebMediaPlayer::NetworkStateEmpty),
|
| ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
|
| - texture_id_(0),
|
| - stream_id_(0),
|
| + is_playing_(false),
|
| needs_establish_peer_(true),
|
| stream_texture_factory_(factory) {
|
| main_loop_->AddDestructionObserver(this);
|
| if (manager_)
|
| player_id_ = manager_->RegisterMediaPlayer(this);
|
| +
|
| if (stream_texture_factory_.get()) {
|
| stream_texture_proxy_.reset(stream_texture_factory_->CreateProxy());
|
| stream_id_ = stream_texture_factory_->CreateStreamTexture(&texture_id_);
|
| @@ -91,50 +54,23 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
|
| }
|
|
|
| WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
|
| - if (manager_)
|
| - manager_->UnregisterMediaPlayer(player_id_);
|
| -
|
| if (stream_id_)
|
| stream_texture_factory_->DestroyStreamTexture(texture_id_);
|
|
|
| + if (manager_)
|
| + manager_->UnregisterMediaPlayer(player_id_);
|
| +
|
| if (main_loop_)
|
| main_loop_->RemoveDestructionObserver(this);
|
| }
|
|
|
| -void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) {
|
| - incognito_mode_ = incognito_mode;
|
| -}
|
| -
|
| void WebMediaPlayerAndroid::load(const WebURL& url, CORSMode cors_mode) {
|
| if (cors_mode != CORSModeUnspecified)
|
| NOTIMPLEMENTED() << "No CORS support";
|
|
|
| url_ = url;
|
|
|
| - UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
|
| - UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);
|
| -
|
| - // Calling InitializeMediaPlayer() will cause android mediaplayer to start
|
| - // buffering and decoding the data. On mobile devices, this costs a lot of
|
| - // data usage and could even introduce performance issues. So we don't
|
| - // initialize the player unless it is a local file. We will start loading
|
| - // the media only when play/seek/fullsceen button is clicked.
|
| - if (url_.SchemeIs("file")) {
|
| - InitializeMediaPlayer();
|
| - return;
|
| - }
|
| -
|
| - // TODO(qinmin): we need a method to calculate the duration of the media.
|
| - // Android does not provide any function to do that.
|
| - // Set the initial duration value to kTemporaryDuration so that user can
|
| - // touch the seek bar to perform seek. We will scale the seek position later
|
| - // when we got the actual duration.
|
| - duration_ = kTemporaryDuration;
|
| -
|
| - // Pretend everything has been loaded so that webkit can
|
| - // still call play() and seek().
|
| - UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
|
| - UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
|
| + InitializeMediaPlayer(url_);
|
| }
|
|
|
| void WebMediaPlayerAndroid::cancelLoad() {
|
| @@ -142,42 +78,23 @@ void WebMediaPlayerAndroid::cancelLoad() {
|
| }
|
|
|
| void WebMediaPlayerAndroid::play() {
|
| - if (media_player_.get()) {
|
| - if (!prepared_)
|
| - pending_play_event_ = true;
|
| - else
|
| - PlayInternal();
|
| - } else {
|
| - pending_play_event_ = true;
|
| - InitializeMediaPlayer();
|
| - }
|
| + if (hasVideo() && needs_establish_peer_)
|
| + EstablishSurfaceTexturePeer();
|
| +
|
| + PlayInternal();
|
| + is_playing_ = true;
|
| }
|
|
|
| void WebMediaPlayerAndroid::pause() {
|
| - if (media_player_.get()) {
|
| - if (!prepared_)
|
| - pending_play_event_ = false;
|
| - else
|
| - PauseInternal();
|
| - } else {
|
| - // We don't need to load media if pause() is called.
|
| - pending_play_event_ = false;
|
| - }
|
| + PauseInternal();
|
| + is_playing_ = false;
|
| }
|
|
|
| void WebMediaPlayerAndroid::seek(float seconds) {
|
| - // Record the time to seek when OnMediaPrepared() is called.
|
| pending_seek_ = seconds;
|
| + seeking_ = true;
|
|
|
| - // Reset |playback_completed_| so that we return the correct current time.
|
| - playback_completed_ = false;
|
| -
|
| - if (media_player_.get()) {
|
| - if (prepared_)
|
| - SeekInternal(seconds);
|
| - } else {
|
| - InitializeMediaPlayer();
|
| - }
|
| + SeekInternal(ConvertSecondsToTimestamp(seconds));
|
| }
|
|
|
| bool WebMediaPlayerAndroid::supportsFullscreen() const {
|
| @@ -198,8 +115,7 @@ void WebMediaPlayerAndroid::setRate(float rate) {
|
| }
|
|
|
| void WebMediaPlayerAndroid::setVolume(float volume) {
|
| - if (media_player_.get())
|
| - media_player_->SetVolume(volume, volume);
|
| + NOTIMPLEMENTED();
|
| }
|
|
|
| void WebMediaPlayerAndroid::setVisible(bool visible) {
|
| @@ -213,6 +129,10 @@ bool WebMediaPlayerAndroid::totalBytesKnown() {
|
| }
|
|
|
| bool WebMediaPlayerAndroid::hasVideo() const {
|
| + // If we have obtained video size information before, use it.
|
| + if (!natural_size_.isEmpty())
|
| + return true;
|
| +
|
| // TODO(qinmin): need a better method to determine whether the current media
|
| // content contains video. Android does not provide any function to do
|
| // this.
|
| @@ -221,16 +141,12 @@ bool WebMediaPlayerAndroid::hasVideo() const {
|
| // to the mime-type. There may be no mime-type on a redirect URL.
|
| // In that case, we conservatively assume it contains video so that
|
| // enterfullscreen call will not fail.
|
| - if (!prepared_) {
|
| - if (!url_.has_path())
|
| - return false;
|
| - std::string mime;
|
| - if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime))
|
| - return true;
|
| - return mime.find("audio/") == std::string::npos;
|
| - }
|
| -
|
| - return !natural_size_.isEmpty();
|
| + if (!url_.has_path())
|
| + return false;
|
| + std::string mime;
|
| + if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime))
|
| + return true;
|
| + return mime.find("audio/") == std::string::npos;
|
| }
|
|
|
| bool WebMediaPlayerAndroid::hasAudio() const {
|
| @@ -239,9 +155,7 @@ bool WebMediaPlayerAndroid::hasAudio() const {
|
| }
|
|
|
| bool WebMediaPlayerAndroid::paused() const {
|
| - if (!prepared_)
|
| - return !pending_play_event_;
|
| - return !media_player_->IsPlaying();
|
| + return !is_playing_;
|
| }
|
|
|
| bool WebMediaPlayerAndroid::seeking() const {
|
| @@ -249,23 +163,15 @@ bool WebMediaPlayerAndroid::seeking() const {
|
| }
|
|
|
| float WebMediaPlayerAndroid::duration() const {
|
| - return duration_;
|
| + return static_cast<float>(duration_.InSecondsF());
|
| }
|
|
|
| float WebMediaPlayerAndroid::currentTime() const {
|
| // If the player is pending for a seek, return the seek time.
|
| - if (!prepared_ || seeking())
|
| + if (seeking())
|
| return pending_seek_;
|
|
|
| - // When playback is about to finish, android media player often stops
|
| - // at a time which is smaller than the duration. This makes webkit never
|
| - // know that the playback has finished. To solve this, we set the
|
| - // current time to media duration when OnPlaybackComplete() get called.
|
| - // And return the greater of the two values so that the current
|
| - // time is most updated.
|
| - if (playback_completed_)
|
| - return duration();
|
| - return static_cast<float>(media_player_->GetCurrentTime().InSecondsF());
|
| + return GetCurrentTimeInternal();
|
| }
|
|
|
| int WebMediaPlayerAndroid::dataRate() const {
|
| @@ -307,8 +213,7 @@ unsigned long long WebMediaPlayerAndroid::totalBytes() const {
|
| return 0;
|
| }
|
|
|
| -void WebMediaPlayerAndroid::setSize(const WebSize& size) {
|
| - texture_size_ = size;
|
| +void WebMediaPlayerAndroid::setSize(const WebKit::WebSize& size) {
|
| }
|
|
|
| void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas,
|
| @@ -325,8 +230,7 @@ bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const {
|
| return false;
|
| }
|
|
|
| -WebMediaPlayer::MovieLoadType
|
| - WebMediaPlayerAndroid::movieLoadType() const {
|
| +WebMediaPlayer::MovieLoadType WebMediaPlayerAndroid::movieLoadType() const {
|
| // Deprecated.
|
| // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
|
| return WebMediaPlayer::MovieLoadTypeUnknown;
|
| @@ -356,17 +260,7 @@ unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
|
| return 0;
|
| }
|
|
|
| -void WebMediaPlayerAndroid::OnMediaPrepared() {
|
| - if (!media_player_.get())
|
| - return;
|
| -
|
| - prepared_ = true;
|
| -
|
| - // Update the media duration first so that webkit will get the correct
|
| - // duration when UpdateReadyState is called.
|
| - float dur = duration_;
|
| - duration_ = media_player_->GetDuration().InSecondsF();
|
| -
|
| +void WebMediaPlayerAndroid::OnMediaPrepared(base::TimeDelta duration) {
|
| if (url_.SchemeIs("file"))
|
| UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded);
|
|
|
| @@ -379,30 +273,20 @@ void WebMediaPlayerAndroid::OnMediaPrepared() {
|
| UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
|
| }
|
|
|
| - if (!url_.SchemeIs("file")) {
|
| - // In we have skipped loading, the duration was preset to
|
| - // kTemporaryDuration. We have to update webkit about the new duration.
|
| - if (duration_ != dur) {
|
| - // Scale the |pending_seek_| according to the new duration.
|
| - pending_seek_ = pending_seek_ * duration_ / kTemporaryDuration;
|
| - client_->durationChanged();
|
| - }
|
| + // In we have skipped loading, we have to update webkit about the new
|
| + // duration.
|
| + if (duration_ != duration) {
|
| + duration_ = duration;
|
| + client_->durationChanged();
|
| }
|
| -
|
| - // If media player was recovered from a saved state, consume all the pending
|
| - // events.
|
| - seek(pending_seek_);
|
| -
|
| - if (pending_play_event_)
|
| - PlayInternal();
|
| -
|
| - pending_play_event_ = false;
|
| }
|
|
|
| void WebMediaPlayerAndroid::OnPlaybackComplete() {
|
| - // Set the current time equal to duration to let webkit know that play back
|
| - // is completed.
|
| - playback_completed_ = true;
|
| + // When playback is about to finish, android media player often stops
|
| + // at a time which is smaller than the duration. This makes webkit never
|
| + // know that the playback has finished. To solve this, we set the
|
| + // current time to media duration when OnPlaybackComplete() get called.
|
| + OnTimeUpdate(duration_);
|
| client_->timeChanged();
|
| }
|
|
|
| @@ -411,9 +295,11 @@ void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
|
| did_loading_progress_ = true;
|
| }
|
|
|
| -void WebMediaPlayerAndroid::OnSeekComplete() {
|
| +void WebMediaPlayerAndroid::OnSeekComplete(base::TimeDelta current_time) {
|
| seeking_ = false;
|
|
|
| + OnTimeUpdate(current_time);
|
| +
|
| UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
|
|
|
| client_->timeChanged();
|
| @@ -441,10 +327,6 @@ void WebMediaPlayerAndroid::OnMediaError(int error_type) {
|
| client_->repaint();
|
| }
|
|
|
| -void WebMediaPlayerAndroid::OnMediaInfo(int info_type) {
|
| - NOTIMPLEMENTED();
|
| -}
|
| -
|
| void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
|
| if (natural_size_.width == width && natural_size_.height == height)
|
| return;
|
| @@ -471,84 +353,39 @@ void WebMediaPlayerAndroid::UpdateReadyState(
|
| client_->readyStateChanged();
|
| }
|
|
|
| +void WebMediaPlayerAndroid::OnPlayerReleased() {
|
| + needs_establish_peer_ = true;
|
| +}
|
| +
|
| void WebMediaPlayerAndroid::ReleaseMediaResources() {
|
| // Pause the media player first.
|
| pause();
|
| client_->playbackStateChanged();
|
|
|
| - if (media_player_.get()) {
|
| - // Save the current media player status.
|
| - pending_seek_ = currentTime();
|
| - duration_ = duration();
|
| -
|
| - media_player_.reset();
|
| - needs_establish_peer_ = true;
|
| - }
|
| - prepared_ = false;
|
| -}
|
| -
|
| -bool WebMediaPlayerAndroid::IsInitialized() const {
|
| - return (media_player_ != NULL);
|
| -}
|
| -
|
| -void WebMediaPlayerAndroid::InitializeMediaPlayer() {
|
| - CHECK(!media_player_.get());
|
| - prepared_ = false;
|
| - media_player_.reset(new MediaPlayerBridge());
|
| - media_player_->SetStayAwakeWhilePlaying();
|
| -
|
| - std::string cookies;
|
| - if (cookie_jar_ != NULL) {
|
| - WebURL first_party_url(frame_->document().firstPartyForCookies());
|
| - cookies = UTF16ToUTF8(cookie_jar_->cookies(url_, first_party_url));
|
| - }
|
| - media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_);
|
| -
|
| - if (manager_)
|
| - manager_->RequestMediaResources(player_id_);
|
| -
|
| - media_player_->Prepare(
|
| - base::Bind(&WebMediaPlayerProxyAndroid::MediaInfoCallback, proxy_),
|
| - base::Bind(&WebMediaPlayerProxyAndroid::MediaErrorCallback, proxy_),
|
| - base::Bind(&WebMediaPlayerProxyAndroid::VideoSizeChangedCallback, proxy_),
|
| - base::Bind(&WebMediaPlayerProxyAndroid::BufferingUpdateCallback, proxy_),
|
| - base::Bind(&WebMediaPlayerProxyAndroid::MediaPreparedCallback, proxy_));
|
| + ReleaseResourcesInternal();
|
| + OnPlayerReleased();
|
| }
|
|
|
| -void WebMediaPlayerAndroid::PlayInternal() {
|
| - CHECK(prepared_);
|
| +void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() {
|
| + Destroy();
|
|
|
| - if (hasVideo() && stream_texture_factory_.get()) {
|
| - if (needs_establish_peer_) {
|
| - stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
|
| - needs_establish_peer_ = false;
|
| - }
|
| + if (stream_id_) {
|
| + stream_texture_factory_->DestroyStreamTexture(texture_id_);
|
| + stream_id_ = 0;
|
| }
|
|
|
| - if (paused())
|
| - media_player_->Start(base::Bind(
|
| - &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_));
|
| -}
|
| -
|
| -void WebMediaPlayerAndroid::PauseInternal() {
|
| - CHECK(prepared_);
|
| - media_player_->Pause();
|
| -}
|
| + video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame()));
|
|
|
| -void WebMediaPlayerAndroid::SeekInternal(float seconds) {
|
| - CHECK(prepared_);
|
| - seeking_ = true;
|
| - media_player_->SeekTo(ConvertSecondsToTimestamp(seconds), base::Bind(
|
| - &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_));
|
| -}
|
| + if (manager_)
|
| + manager_->UnregisterMediaPlayer(player_id_);
|
|
|
| -void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() {
|
| manager_ = NULL;
|
| main_loop_ = NULL;
|
| }
|
|
|
| WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() {
|
| - if (!stream_texture_proxy_->IsInitialized() && stream_id_) {
|
| + if (stream_texture_proxy_.get() && !stream_texture_proxy_->IsInitialized()
|
| + && stream_id_) {
|
| stream_texture_proxy_->Initialize(
|
| stream_id_, video_frame_->width(), video_frame_->height());
|
| }
|
| @@ -560,11 +397,20 @@ void WebMediaPlayerAndroid::putCurrentFrame(
|
| WebVideoFrame* web_video_frame) {
|
| }
|
|
|
| -// This gets called both on compositor and main thread.
|
| void WebMediaPlayerAndroid::setStreamTextureClient(
|
| WebKit::WebStreamTextureClient* client) {
|
| if (stream_texture_proxy_.get())
|
| stream_texture_proxy_->SetClient(client);
|
| }
|
|
|
| +void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
|
| + if (stream_texture_factory_.get() && stream_id_)
|
| + stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
|
| + needs_establish_peer_ = false;
|
| +}
|
| +
|
| +void WebMediaPlayerAndroid::UpdatePlayingState(bool is_playing) {
|
| + is_playing_ = is_playing;
|
| +}
|
| +
|
| } // namespace webkit_media
|
|
|