summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolenetz@chromium.org <wolenetz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-12 01:09:49 +0000
committerwolenetz@chromium.org <wolenetz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-12 01:09:49 +0000
commit0f7a70415b0a4b8d2ff6bc958307965eca7b5667 (patch)
tree663cdabcf373ec49677a5eb2f1b3fa967d7546d3
parent1dec3e81277da1c7d710cb54d045b70093104261 (diff)
downloadchromium_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
-rw-r--r--content/browser/android/media_player_manager_impl.cc9
-rw-r--r--content/browser/android/media_player_manager_impl.h1
-rw-r--r--content/common/media/media_player_messages_android.h5
-rw-r--r--content/renderer/media/webmediaplayer_proxy_impl_android.cc6
-rw-r--r--content/renderer/media/webmediaplayer_proxy_impl_android.h2
-rw-r--r--media/base/android/media_player_android.cc4
-rw-r--r--media/base/android/media_player_android.h5
-rw-r--r--media/base/android/media_source_player.cc22
-rw-r--r--media/base/android/media_source_player.h7
-rw-r--r--webkit/renderer/media/android/media_source_delegate.cc16
-rw-r--r--webkit/renderer/media/android/media_source_delegate.h5
-rw-r--r--webkit/renderer/media/android/webmediaplayer_android.cc103
-rw-r--r--webkit/renderer/media/android/webmediaplayer_android.h18
-rw-r--r--webkit/renderer/media/android/webmediaplayer_proxy_android.h4
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