diff options
author | wolenetz@chromium.org <wolenetz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-12 01:09:49 +0000 |
---|---|---|
committer | wolenetz@chromium.org <wolenetz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-12 01:09:49 +0000 |
commit | 0f7a70415b0a4b8d2ff6bc958307965eca7b5667 (patch) | |
tree | 663cdabcf373ec49677a5eb2f1b3fa967d7546d3 | |
parent | 1dec3e81277da1c7d710cb54d045b70093104261 (diff) | |
download | chromium_src-0f7a70415b0a4b8d2ff6bc958307965eca7b5667.zip chromium_src-0f7a70415b0a4b8d2ff6bc958307965eca7b5667.tar.gz chromium_src-0f7a70415b0a4b8d2ff6bc958307965eca7b5667.tar.bz2 |
Implement MediaSourceDelegate::SetDuration() for android
Notify MediaPlayerClient and (Android) MediaSourcePlayer when
MediaSourceDelegate's ChunkDemuxer duration changes:
* Bind WebMediaPlayerAndroid::OnDurationChanged() to
render loop to asynchronously handle callback from
MediaSourceDelegate::SetDuration().
* Cache the updated duration in WMPA. This needs
simplification in blink so this caching doesn't break MSE
spec conformance. Prerequisite blink change:
https://codereview.chromium.org/15735030/)
* Add IPC for WebMediaPlayerAndroid to notify (Android)
MediaSourcePlayer when MediaSourceDelegate/ChunkDemuxer updates duration.
With this patch, the following MSE layout tests now pass:
webkitmediasource-duration-boundaryconditions.html
webkitmediasource-duration-changed.html
webkitmediasource-seek-to-end-after-duration-change.html
BUG=246757,233420
TEST=manual verification of MSE layout tests show no regression
R=acolwell@chromium.org,yfriedman@chromium.org,qinmin@chromium.org,wonsik@chromium.org, jschuh@chromium.org
Review URL: https://chromiumcodereview.appspot.com/16372002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205697 0039d316-1c4b-4281-b951-d872f2087c98
14 files changed, 166 insertions, 41 deletions
diff --git a/content/browser/android/media_player_manager_impl.cc b/content/browser/android/media_player_manager_impl.cc index 0053ba5..6244ae0 100644 --- a/content/browser/android/media_player_manager_impl.cc +++ b/content/browser/android/media_player_manager_impl.cc @@ -69,6 +69,8 @@ bool MediaPlayerManagerImpl::OnMessageReceived(const IPC::Message& msg) { OnDemuxerReady) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_ReadFromDemuxerAck, OnReadFromDemuxerAck) + IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_DurationChanged, + OnDurationChanged) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_MediaSeekRequestAck, OnMediaSeekRequestAck) IPC_MESSAGE_HANDLER(MediaPlayerHostMsg_GenerateKeyRequest, @@ -279,6 +281,13 @@ void MediaPlayerManagerImpl::OnReadFromDemuxerAck( player->ReadFromDemuxerAck(params); } +void MediaPlayerManagerImpl::OnDurationChanged( + int player_id, const base::TimeDelta& duration) { + MediaPlayerAndroid* player = GetPlayer(player_id); + if (player) + player->DurationChanged(duration); +} + void MediaPlayerManagerImpl::OnMediaSeekRequestAck( int player_id, unsigned seek_request_id) { MediaPlayerAndroid* player = GetPlayer(player_id); diff --git a/content/browser/android/media_player_manager_impl.h b/content/browser/android/media_player_manager_impl.h index fbb1b94..3f84d9c 100644 --- a/content/browser/android/media_player_manager_impl.h +++ b/content/browser/android/media_player_manager_impl.h @@ -135,6 +135,7 @@ class MediaPlayerManagerImpl void OnCancelKeyRequest(int player_id, const std::string& key_system, const std::string& session_id); + void OnDurationChanged(int player_id, const base::TimeDelta& duration); #if defined(GOOGLE_TV) virtual void OnNotifyExternalSurface( diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h index 974e89c..47146ee 100644 --- a/content/common/media/media_player_messages_android.h +++ b/content/common/media/media_player_messages_android.h @@ -199,6 +199,11 @@ IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_ReadFromDemuxerAck, int /* player_id */, media::MediaPlayerHostMsg_ReadFromDemuxerAck_Params) +// Inform the media source player of changed media duration from demuxer. +IPC_MESSAGE_ROUTED2(MediaPlayerHostMsg_DurationChanged, + int /* player_id */, + base::TimeDelta /* duration */) + #if defined(GOOGLE_TV) // Notify the player about the external surface, requesting it if necessary. IPC_MESSAGE_ROUTED3(MediaPlayerHostMsg_NotifyExternalSurface, diff --git a/content/renderer/media/webmediaplayer_proxy_impl_android.cc b/content/renderer/media/webmediaplayer_proxy_impl_android.cc index 14b6da8..e89adb8 100644 --- a/content/renderer/media/webmediaplayer_proxy_impl_android.cc +++ b/content/renderer/media/webmediaplayer_proxy_impl_android.cc @@ -243,6 +243,12 @@ void WebMediaPlayerProxyImplAndroid::DemuxerReady( Send(new MediaPlayerHostMsg_DemuxerReady(routing_id(), player_id, params)); } +void WebMediaPlayerProxyImplAndroid::DurationChanged( + int player_id, const base::TimeDelta& duration) { + Send(new MediaPlayerHostMsg_DurationChanged( + routing_id(), player_id, duration)); +} + webkit_media::WebMediaPlayerAndroid* WebMediaPlayerProxyImplAndroid::GetWebMediaPlayer(int player_id) { return static_cast<webkit_media::WebMediaPlayerAndroid*>( diff --git a/content/renderer/media/webmediaplayer_proxy_impl_android.h b/content/renderer/media/webmediaplayer_proxy_impl_android.h index 3cf9cee..5f4f2d6a 100644 --- a/content/renderer/media/webmediaplayer_proxy_impl_android.h +++ b/content/renderer/media/webmediaplayer_proxy_impl_android.h @@ -66,6 +66,8 @@ class WebMediaPlayerProxyImplAndroid virtual void CancelKeyRequest(int player_id, const std::string& key_system, const std::string& session_id) OVERRIDE; + virtual void DurationChanged(int player_id, + const base::TimeDelta& duration) OVERRIDE; #if defined(GOOGLE_TV) virtual void RequestExternalSurface( diff --git a/media/base/android/media_player_android.cc b/media/base/android/media_player_android.cc index 2de4887..0eddd01 100644 --- a/media/base/android/media_player_android.cc +++ b/media/base/android/media_player_android.cc @@ -76,6 +76,10 @@ void MediaPlayerAndroid::OnSeekRequestAck(unsigned seek_request_id) { NOTREACHED() << "Unexpected ipc received"; } +void MediaPlayerAndroid::DurationChanged(const base::TimeDelta& duration) { + NOTREACHED() << "Unexpected ipc received"; +} + GURL MediaPlayerAndroid::GetUrl() { return GURL(); } diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h index c5abbb9..1310fbd 100644 --- a/media/base/android/media_player_android.h +++ b/media/base/android/media_player_android.h @@ -85,7 +85,7 @@ class MEDIA_EXPORT MediaPlayerAndroid { virtual GURL GetUrl(); virtual GURL GetFirstPartyForCookies(); - // Methods for DeumxerStreamPlayer. + // Methods for DemuxerStreamPlayer. // Informs DemuxerStreamPlayer that the demuxer is ready. virtual void DemuxerReady( const MediaPlayerHostMsg_DemuxerReady_Params& params); @@ -96,6 +96,9 @@ class MEDIA_EXPORT MediaPlayerAndroid { // Called when a seek request is acked by the render process. virtual void OnSeekRequestAck(unsigned seek_request_id); + // Called when the demuxer has changed the duration. + virtual void DurationChanged(const base::TimeDelta& duration); + int player_id() { return player_id_; } protected: diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc index f3aabe5..8cadb60 100644 --- a/media/base/android/media_source_player.cc +++ b/media/base/android/media_source_player.cc @@ -254,7 +254,6 @@ MediaSourcePlayer::MediaSourcePlayer( video_codec_(kUnknownVideoCodec), num_channels_(0), sampling_rate_(0), - seekable_(true), audio_finished_(true), video_finished_(true), playing_(false), @@ -281,6 +280,15 @@ void MediaSourcePlayer::SetVideoSurface(gfx::ScopedJavaSurface surface) { ProcessPendingEvents(); } +bool MediaSourcePlayer::Seekable() { + // If the duration TimeDelta, converted to milliseconds from microseconds, + // is >= 2^31, then the media is assumed to be unbounded and unseekable. + // 2^31 is the bound due to java player using 32-bit integer for time + // values at millisecond resolution. + return duration_ < + base::TimeDelta::FromMilliseconds(std::numeric_limits<int32>::max()); +} + void MediaSourcePlayer::Start() { playing_ = true; @@ -338,15 +346,15 @@ void MediaSourcePlayer::SetVolume(float leftVolume, float rightVolume) { } bool MediaSourcePlayer::CanPause() { - return seekable_; + return Seekable(); } bool MediaSourcePlayer::CanSeekForward() { - return seekable_; + return Seekable(); } bool MediaSourcePlayer::CanSeekBackward() { - return seekable_; + return Seekable(); } bool MediaSourcePlayer::IsPlayerReady() { @@ -376,8 +384,6 @@ void MediaSourcePlayer::StartInternal() { void MediaSourcePlayer::DemuxerReady( const MediaPlayerHostMsg_DemuxerReady_Params& params) { - if (params.duration_ms == std::numeric_limits<int>::max()) - seekable_ = false; duration_ = base::TimeDelta::FromMilliseconds(params.duration_ms); width_ = params.video_size.width(); height_ = params.video_size.height(); @@ -428,6 +434,10 @@ void MediaSourcePlayer::ReadFromDemuxerAck( } } +void MediaSourcePlayer::DurationChanged(const base::TimeDelta& duration) { + duration_ = duration; +} + void MediaSourcePlayer::OnSeekRequestAck(unsigned seek_request_id) { // Do nothing until the most recent seek request is processed. if (seek_request_id_ != seek_request_id) diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h index b2d5a72..3b12dd5 100644 --- a/media/base/android/media_source_player.h +++ b/media/base/android/media_source_player.h @@ -154,6 +154,9 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid { virtual void ReadFromDemuxerAck( const MediaPlayerHostMsg_ReadFromDemuxerAck_Params& params) OVERRIDE; + // Called when the demuxer has changed the duration. + virtual void DurationChanged(const base::TimeDelta& duration) OVERRIDE; + private: // Update the timestamps for A/V sync scheduling. void UpdateTimestamps( @@ -190,6 +193,9 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid { bool HasVideo(); bool HasAudio(); + // Determine seekability based on duration. + bool Seekable(); + enum PendingEventFlags { NO_EVENT_PENDING = 0, SEEK_EVENT_PENDING = 1 << 0, @@ -213,7 +219,6 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid { VideoCodec video_codec_; int num_channels_; int sampling_rate_; - bool seekable_; base::TimeDelta last_presentation_timestamp_; std::vector<uint8> audio_extra_data_; bool audio_finished_; diff --git a/webkit/renderer/media/android/media_source_delegate.cc b/webkit/renderer/media/android/media_source_delegate.cc index cd418e8..687a3fb 100644 --- a/webkit/renderer/media/android/media_source_delegate.cc +++ b/webkit/renderer/media/android/media_source_delegate.cc @@ -86,6 +86,7 @@ void MediaSourceDelegate::Destroy() { return; } + duration_change_cb_.Reset(); update_network_state_cb_.Reset(); media_source_.reset(); proxy_ = NULL; @@ -99,11 +100,13 @@ void MediaSourceDelegate::Destroy() { void MediaSourceDelegate::InitializeMediaSource( WebKit::WebMediaSource* media_source, const media::NeedKeyCB& need_key_cb, - const UpdateNetworkStateCB& update_network_state_cb) { + const UpdateNetworkStateCB& update_network_state_cb, + const DurationChangeCB& duration_change_cb) { DCHECK(media_source); media_source_.reset(media_source); need_key_cb_ = need_key_cb; update_network_state_cb_ = update_network_state_cb; + duration_change_cb_ = duration_change_cb; chunk_demuxer_.reset(new media::ChunkDemuxer( BIND_TO_RENDER_LOOP(&MediaSourceDelegate::OnDemuxerOpened), @@ -185,7 +188,12 @@ void MediaSourceDelegate::AddBufferedTimeRange(base::TimeDelta start, } void MediaSourceDelegate::SetDuration(base::TimeDelta duration) { - // Do nothing + DVLOG(1) << "MediaSourceDelegate::SetDuration(" << duration.InSecondsF() + << ") : " << player_id_; + // Notify our owner (e.g. WebMediaPlayerAndroid) that + // duration has changed. + if (!duration_change_cb_.is_null()) + duration_change_cb_.Run(duration); } void MediaSourceDelegate::OnReadFromDemuxer(media::DemuxerStream::Type type, @@ -377,10 +385,10 @@ int MediaSourceDelegate::GetDurationMs() { return -1; double duration_ms = chunk_demuxer_->GetDuration() * 1000; - if (duration_ms > std::numeric_limits<int>::max()) { + if (duration_ms > std::numeric_limits<int32>::max()) { LOG(WARNING) << "Duration from ChunkDemuxer is too large; probably " "something has gone wrong."; - return std::numeric_limits<int>::max(); + return std::numeric_limits<int32>::max(); } return duration_ms; } diff --git a/webkit/renderer/media/android/media_source_delegate.h b/webkit/renderer/media/android/media_source_delegate.h index ce7c958..b0db476 100644 --- a/webkit/renderer/media/android/media_source_delegate.h +++ b/webkit/renderer/media/android/media_source_delegate.h @@ -35,6 +35,7 @@ class MediaSourceDelegate : public media::DemuxerHost { public: typedef base::Callback<void(WebKit::WebMediaPlayer::NetworkState)> UpdateNetworkStateCB; + typedef base::Callback<void(const base::TimeDelta&)> DurationChangeCB; // Helper class used by scoped_ptr to destroy an instance of // MediaSourceDelegate. @@ -53,7 +54,8 @@ class MediaSourceDelegate : public media::DemuxerHost { void InitializeMediaSource( WebKit::WebMediaSource* media_source, const media::NeedKeyCB& need_key_cb, - const UpdateNetworkStateCB& update_network_state_cb); + const UpdateNetworkStateCB& update_network_state_cb, + const DurationChangeCB& duration_change_cb); #if defined(GOOGLE_TV) void InitializeMediaStream( media::Demuxer* demuxer, @@ -130,6 +132,7 @@ class MediaSourceDelegate : public media::DemuxerHost { scoped_refptr<media::MediaLog> media_log_; UpdateNetworkStateCB update_network_state_cb_; + DurationChangeCB duration_change_cb_; scoped_ptr<media::ChunkDemuxer> chunk_demuxer_; scoped_ptr<WebKit::WebMediaSource> media_source_; diff --git a/webkit/renderer/media/android/webmediaplayer_android.cc b/webkit/renderer/media/android/webmediaplayer_android.cc index 4539f45..4177670 100644 --- a/webkit/renderer/media/android/webmediaplayer_android.cc +++ b/webkit/renderer/media/android/webmediaplayer_android.cc @@ -13,6 +13,7 @@ #include "cc/layers/video_layer.h" #include "gpu/GLES2/gl2extchromium.h" #include "media/base/android/media_player_android.h" +#include "media/base/bind_to_loop.h" #include "media/base/media_switches.h" #include "media/base/video_frame.h" #include "net/base/mime_util.h" @@ -52,6 +53,9 @@ const char* kMediaEme = "Media.EME."; namespace webkit_media { +#define BIND_TO_RENDER_LOOP(function) \ + media::BindToLoop(main_loop_, base::Bind(function, AsWeakPtr())) + WebMediaPlayerAndroid::WebMediaPlayerAndroid( WebKit::WebFrame* frame, WebKit::WebMediaPlayerClient* client, @@ -62,7 +66,8 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( : frame_(frame), client_(client), buffered_(1u), - main_loop_(base::MessageLoop::current()), + main_loop_(base::MessageLoopProxy::current()), + ignore_metadata_duration_change_(false), pending_seek_(0), seeking_(false), did_loading_progress_(false), @@ -76,12 +81,15 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( stream_texture_factory_(factory), needs_external_surface_(false), video_frame_provider_client_(NULL), + source_type_(MediaPlayerAndroid::SOURCE_TYPE_URL), proxy_(proxy), current_time_(0), media_log_(media_log), media_stream_client_(NULL) { DCHECK(proxy_); - main_loop_->AddDestructionObserver(this); + + // We want to be notified of |main_loop_| destruction. + base::MessageLoop::current()->AddDestructionObserver(this); if (manager_) player_id_ = manager_->RegisterMediaPlayer(this); @@ -122,8 +130,8 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { if (manager_) manager_->UnregisterMediaPlayer(player_id_); - if (main_loop_) - main_loop_->RemoveDestructionObserver(this); + if (base::MessageLoop::current()) + base::MessageLoop::current()->RemoveDestructionObserver(this); #if defined(GOOGLE_TV) if (audio_renderer_) { if (audio_renderer_->IsLocalRenderer()) { @@ -153,31 +161,31 @@ void WebMediaPlayerAndroid::load(const WebURL& url, if (cors_mode != CORSModeUnspecified) NOTIMPLEMENTED() << "No CORS support"; - MediaPlayerAndroid::SourceType source_type = - MediaPlayerAndroid::SOURCE_TYPE_URL; + source_type_ = MediaPlayerAndroid::SOURCE_TYPE_URL; if (media_source) - source_type = MediaPlayerAndroid::SOURCE_TYPE_MSE; + source_type_ = MediaPlayerAndroid::SOURCE_TYPE_MSE; #if defined(GOOGLE_TV) if (media_stream_client_) { DCHECK(!media_source); - source_type = MediaPlayerAndroid::SOURCE_TYPE_STREAM; + source_type_ = MediaPlayerAndroid::SOURCE_TYPE_STREAM; } #endif - if (source_type != MediaPlayerAndroid::SOURCE_TYPE_URL) { + if (source_type_ != MediaPlayerAndroid::SOURCE_TYPE_URL) { media_source_delegate_.reset( new MediaSourceDelegate(proxy_, player_id_, media_log_)); // |media_source_delegate_| is owned, so Unretained() is safe here. - if (source_type == MediaPlayerAndroid::SOURCE_TYPE_MSE) { + if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE) { media_source_delegate_->InitializeMediaSource( media_source, base::Bind(&WebMediaPlayerAndroid::OnNeedKey, base::Unretained(this)), base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState, - base::Unretained(this))); + base::Unretained(this)), + BIND_TO_RENDER_LOOP(&WebMediaPlayerAndroid::OnDurationChange)); } #if defined(GOOGLE_TV) - if (source_type == MediaPlayerAndroid::SOURCE_TYPE_STREAM) { + if (source_type_ == MediaPlayerAndroid::SOURCE_TYPE_STREAM) { media_source_delegate_->InitializeMediaStream( demuxer_, base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState, @@ -189,15 +197,13 @@ void WebMediaPlayerAndroid::load(const WebURL& url, #endif } - InitializeMediaPlayer(url, source_type); + InitializeMediaPlayer(url); } -void WebMediaPlayerAndroid::InitializeMediaPlayer( - const WebURL& url, - MediaPlayerAndroid::SourceType source_type) { +void WebMediaPlayerAndroid::InitializeMediaPlayer(const WebURL& url) { url_ = url; GURL first_party_url = frame_->document().firstPartyForCookies(); - proxy_->Initialize(player_id_, url, source_type, first_party_url); + proxy_->Initialize(player_id_, url, source_type_, first_party_url); if (manager_->IsInFullscreen(frame_)) proxy_->EnterFullscreen(player_id_); @@ -298,6 +304,13 @@ bool WebMediaPlayerAndroid::seeking() const { } double WebMediaPlayerAndroid::duration() const { + // HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING + if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) + return std::numeric_limits<double>::quiet_NaN(); + + // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer + // considers unseekable, including kInfiniteDuration(). + // See http://crbug.com/248396 return duration_.InSecondsF(); } @@ -327,6 +340,11 @@ const WebTimeRanges& WebMediaPlayerAndroid::buffered() { } double WebMediaPlayerAndroid::maxTimeSeekable() const { + // If we haven't even gotten to ReadyStateHaveMetadata yet then just + // return 0 so that the seekable range is empty. + if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata) + return 0.0; + // TODO(hclam): If this stream is not seekable this should return 0. return duration(); } @@ -419,14 +437,37 @@ unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { void WebMediaPlayerAndroid::OnMediaMetadataChanged( base::TimeDelta duration, int width, int height, bool success) { + bool need_to_signal_duration_changed = false; + if (url_.SchemeIs("file")) UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded); + // Update duration, if necessary, prior to ready state updates that may + // cause duration() query. + // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer + // considers unseekable, including kInfiniteDuration(). + // See http://crbug.com/248396 + if (!ignore_metadata_duration_change_ && duration_ != duration) { + duration_ = duration; + + // Client readyState transition from HAVE_NOTHING to HAVE_METADATA + // already triggers a durationchanged event. If this is a different + // transition, remember to signal durationchanged. + // Do not ever signal durationchanged on metadata change in MSE case + // because OnDurationChange() handles this. + if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing && + source_type_ != MediaPlayerAndroid::SOURCE_TYPE_MSE) { + need_to_signal_duration_changed = true; + } + } + if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) { UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata); UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); } + // TODO(wolenetz): Should we just abort early and set network state to an + // error if success == false? See http://crbug.com/248399 if (success) OnVideoSizeChanged(width, height); @@ -436,12 +477,8 @@ void WebMediaPlayerAndroid::OnMediaMetadataChanged( client_->setWebLayer(video_weblayer_.get()); } - // In we have skipped loading, we have to update webkit about the new - // duration. - if (duration_ != duration) { - duration_ = duration; + if (need_to_signal_duration_changed) client_->durationChanged(); - } } void WebMediaPlayerAndroid::OnPlaybackComplete() { @@ -568,6 +605,27 @@ void WebMediaPlayerAndroid::OnMediaConfigRequest() { media_source_delegate_->OnMediaConfigRequest(); } +void WebMediaPlayerAndroid::OnDurationChange(const base::TimeDelta& duration) { + // Only MSE |source_type_| registers this callback. + DCHECK(source_type_ == MediaPlayerAndroid::SOURCE_TYPE_MSE); + + // Cache the new duration value and trust it over any subsequent duration + // values received in OnMediaMetadataChanged(). + // TODO(wolenetz): Correctly handle durations that MediaSourcePlayer + // considers unseekable, including kInfiniteDuration(). + // See http://crbug.com/248396 + duration_ = duration; + ignore_metadata_duration_change_ = true; + + // Send message to Android MediaSourcePlayer to update duration. + if (proxy_) + proxy_->DurationChanged(player_id_, duration_); + + // Notify MediaPlayerClient that duration has changed, if > HAVE_NOTHING. + if (ready_state_ > WebMediaPlayer::ReadyStateHaveNothing) + client_->durationChanged(); +} + void WebMediaPlayerAndroid::UpdateNetworkState( WebMediaPlayer::NetworkState state) { if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing && @@ -621,7 +679,6 @@ void WebMediaPlayerAndroid::WillDestroyCurrentMessageLoop() { if (manager_) manager_->UnregisterMediaPlayer(player_id_); Detach(); - main_loop_ = NULL; } void WebMediaPlayerAndroid::Detach() { diff --git a/webkit/renderer/media/android/webmediaplayer_android.h b/webkit/renderer/media/android/webmediaplayer_android.h index ead1707..4e625c1 100644 --- a/webkit/renderer/media/android/webmediaplayer_android.h +++ b/webkit/renderer/media/android/webmediaplayer_android.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/time.h" #include "cc/layers/video_frame_provider.h" @@ -55,7 +56,8 @@ class MediaStreamAudioRenderer; class WebMediaPlayerAndroid : public WebKit::WebMediaPlayer, public cc::VideoFrameProvider, - public base::MessageLoop::DestructionObserver { + public base::MessageLoop::DestructionObserver, + public base::SupportsWeakPtr<WebMediaPlayerAndroid> { public: // Construct a WebMediaPlayerAndroid object. This class communicates // with the MediaPlayerAndroid object in the browser process through @@ -156,6 +158,7 @@ class WebMediaPlayerAndroid void OnVideoSizeChanged(int width, int height); void OnMediaSeekRequest(base::TimeDelta time_to_seek); void OnMediaConfigRequest(); + void OnDurationChange(const base::TimeDelta& duration); // Called to update the current time. void OnTimeUpdate(base::TimeDelta current_time); @@ -242,9 +245,7 @@ class WebMediaPlayerAndroid // Requesting whether the surface texture peer needs to be reestablished. void SetNeedsEstablishPeer(bool needs_establish_peer); - void InitializeMediaPlayer( - const WebKit::WebURL& url, - media::MediaPlayerAndroid::SourceType source_type); + void InitializeMediaPlayer(const WebKit::WebURL& url); #if defined(GOOGLE_TV) // Request external surface for out-of-band composition. @@ -284,7 +285,7 @@ class WebMediaPlayerAndroid scoped_refptr<media::VideoFrame> current_frame_; // Message loop for main renderer thread. - base::MessageLoop* main_loop_; + const scoped_refptr<base::MessageLoopProxy> main_loop_; // URL of the media file to be fetched. GURL url_; @@ -292,6 +293,11 @@ class WebMediaPlayerAndroid // Media duration. base::TimeDelta duration_; + // Flag to remember if we have a trusted duration_ value provided by + // MediaSourceDelegate notifying OnDurationChange(). In this case, ignore + // any subsequent duration value passed to OnMediaMetadataChange(). + bool ignore_metadata_duration_change_; + // The time android media player is trying to seek. double pending_seek_; @@ -359,6 +365,8 @@ class WebMediaPlayerAndroid scoped_ptr<MediaSourceDelegate, MediaSourceDelegate::Destroyer> media_source_delegate_; + media::MediaPlayerAndroid::SourceType source_type_; + // Proxy object that delegates method calls on Render Thread. // This object is created on the Render Thread and is only called in the // destructor. diff --git a/webkit/renderer/media/android/webmediaplayer_proxy_android.h b/webkit/renderer/media/android/webmediaplayer_proxy_android.h index 03f377d..228a159a 100644 --- a/webkit/renderer/media/android/webmediaplayer_proxy_android.h +++ b/webkit/renderer/media/android/webmediaplayer_proxy_android.h @@ -80,6 +80,10 @@ class WebMediaPlayerProxyAndroid { virtual void CancelKeyRequest(int player_id, const std::string& key_system, const std::string& session_id) = 0; + + // Inform the media source player of changed duration from demuxer. + virtual void DurationChanged(int player_id, + const base::TimeDelta& duration) = 0; }; } // namespace webkit_media |