media: Fix not-thread-safe access to variables in android media code.

There are 3 big changes;
1. Initialize and bind StreamTextureProxy to the impl thread when the main
thread is blocked.
2. Set stream texture size when the video size is changed, instead of adhoc in
rendering code.
3. Add lots of thread checks.

BUG=N/A

Review URL: https://codereview.chromium.org/448063003

Cr-Commit-Position: refs/heads/master@{#289315}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289315 0039d316-1c4b-4281-b951-d872f2087c98
parent 599d5ac1
...@@ -168,6 +168,7 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid( ...@@ -168,6 +168,7 @@ WebMediaPlayerAndroid::WebMediaPlayerAndroid(
} }
WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
DCHECK(main_thread_checker_.CalledOnValidThread());
SetVideoFrameProviderClient(NULL); SetVideoFrameProviderClient(NULL);
client_->setWebLayer(NULL); client_->setWebLayer(NULL);
...@@ -196,6 +197,7 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() { ...@@ -196,6 +197,7 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
void WebMediaPlayerAndroid::load(LoadType load_type, void WebMediaPlayerAndroid::load(LoadType load_type,
const blink::WebURL& url, const blink::WebURL& url,
CORSMode cors_mode) { CORSMode cors_mode) {
DCHECK(main_thread_checker_.CalledOnValidThread());
ReportMediaSchemeUma(GURL(url)); ReportMediaSchemeUma(GURL(url));
switch (load_type) { switch (load_type) {
...@@ -261,6 +263,7 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo( ...@@ -261,6 +263,7 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo(
const GURL& redirected_url, const GURL& redirected_url,
const GURL& first_party_for_cookies, const GURL& first_party_for_cookies,
bool allow_stored_credentials) { bool allow_stored_credentials) {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(!media_source_delegate_); DCHECK(!media_source_delegate_);
if (status == MediaInfoLoader::kFailed) { if (status == MediaInfoLoader::kFailed) {
info_loader_.reset(); info_loader_.reset();
...@@ -275,6 +278,7 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo( ...@@ -275,6 +278,7 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo(
} }
void WebMediaPlayerAndroid::play() { void WebMediaPlayerAndroid::play() {
DCHECK(main_thread_checker_.CalledOnValidThread());
#if defined(VIDEO_HOLE) #if defined(VIDEO_HOLE)
if (hasVideo() && needs_external_surface_ && if (hasVideo() && needs_external_surface_ &&
!player_manager_->IsInFullscreen(frame_)) { !player_manager_->IsInFullscreen(frame_)) {
...@@ -298,6 +302,7 @@ void WebMediaPlayerAndroid::play() { ...@@ -298,6 +302,7 @@ void WebMediaPlayerAndroid::play() {
} }
void WebMediaPlayerAndroid::pause() { void WebMediaPlayerAndroid::pause() {
DCHECK(main_thread_checker_.CalledOnValidThread());
Pause(true); Pause(true);
} }
...@@ -354,10 +359,12 @@ void WebMediaPlayerAndroid::setRate(double rate) { ...@@ -354,10 +359,12 @@ void WebMediaPlayerAndroid::setRate(double rate) {
} }
void WebMediaPlayerAndroid::setVolume(double volume) { void WebMediaPlayerAndroid::setVolume(double volume) {
DCHECK(main_thread_checker_.CalledOnValidThread());
player_manager_->SetVolume(player_id_, volume); player_manager_->SetVolume(player_id_, volume);
} }
bool WebMediaPlayerAndroid::hasVideo() const { bool WebMediaPlayerAndroid::hasVideo() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
// If we have obtained video size information before, use it. // If we have obtained video size information before, use it.
if (has_size_info_) if (has_size_info_)
return !natural_size_.isEmpty(); return !natural_size_.isEmpty();
...@@ -379,6 +386,7 @@ bool WebMediaPlayerAndroid::hasVideo() const { ...@@ -379,6 +386,7 @@ bool WebMediaPlayerAndroid::hasVideo() const {
} }
bool WebMediaPlayerAndroid::hasAudio() const { bool WebMediaPlayerAndroid::hasAudio() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!url_.has_path()) if (!url_.has_path())
return false; return false;
std::string mime; std::string mime;
...@@ -402,6 +410,7 @@ bool WebMediaPlayerAndroid::seeking() const { ...@@ -402,6 +410,7 @@ bool WebMediaPlayerAndroid::seeking() const {
} }
double WebMediaPlayerAndroid::duration() const { double WebMediaPlayerAndroid::duration() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
// HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING // HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING
if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
return std::numeric_limits<double>::quiet_NaN(); return std::numeric_limits<double>::quiet_NaN();
...@@ -413,6 +422,7 @@ double WebMediaPlayerAndroid::duration() const { ...@@ -413,6 +422,7 @@ double WebMediaPlayerAndroid::duration() const {
} }
double WebMediaPlayerAndroid::timelineOffset() const { double WebMediaPlayerAndroid::timelineOffset() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
base::Time timeline_offset; base::Time timeline_offset;
if (media_source_delegate_) if (media_source_delegate_)
timeline_offset = media_source_delegate_->GetTimelineOffset(); timeline_offset = media_source_delegate_->GetTimelineOffset();
...@@ -424,6 +434,7 @@ double WebMediaPlayerAndroid::timelineOffset() const { ...@@ -424,6 +434,7 @@ double WebMediaPlayerAndroid::timelineOffset() const {
} }
double WebMediaPlayerAndroid::currentTime() const { double WebMediaPlayerAndroid::currentTime() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
// If the player is processing a seek, return the seek time. // If the player is processing a seek, return the seek time.
// Blink may still query us if updatePlaybackState() occurs while seeking. // Blink may still query us if updatePlaybackState() occurs while seeking.
if (seeking()) { if (seeking()) {
...@@ -472,6 +483,7 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr, ...@@ -472,6 +483,7 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr,
const WebSize& size, const WebSize& size,
GrSurfaceOrigin origin, GrSurfaceOrigin origin,
GrPixelConfig config) { GrPixelConfig config) {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!bitmap.getTexture() || bitmap.width() != size.width if (!bitmap.getTexture() || bitmap.width() != size.width
|| bitmap.height() != size.height) { || bitmap.height() != size.height) {
if (!gr) if (!gr)
...@@ -502,6 +514,7 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr, ...@@ -502,6 +514,7 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr,
void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas, void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
const blink::WebRect& rect, const blink::WebRect& rect,
unsigned char alpha) { unsigned char alpha) {
DCHECK(main_thread_checker_.CalledOnValidThread());
scoped_ptr<blink::WebGraphicsContext3DProvider> provider = scoped_ptr<blink::WebGraphicsContext3DProvider> provider =
scoped_ptr<blink::WebGraphicsContext3DProvider>(blink::Platform::current( scoped_ptr<blink::WebGraphicsContext3DProvider>(blink::Platform::current(
)->createSharedOffscreenGraphicsContext3DProvider()); )->createSharedOffscreenGraphicsContext3DProvider());
...@@ -550,6 +563,7 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture( ...@@ -550,6 +563,7 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
unsigned int type, unsigned int type,
bool premultiply_alpha, bool premultiply_alpha,
bool flip_y) { bool flip_y) {
DCHECK(main_thread_checker_.CalledOnValidThread());
// Don't allow clients to copy an encrypted video frame. // Don't allow clients to copy an encrypted video frame.
if (needs_external_surface_) if (needs_external_surface_)
return false; return false;
...@@ -568,16 +582,6 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture( ...@@ -568,16 +582,6 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES) || mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES) ||
(is_remote_ && mailbox_holder->texture_target == GL_TEXTURE_2D)); (is_remote_ && mailbox_holder->texture_target == GL_TEXTURE_2D));
// For hidden video element (with style "display:none"), ensure the texture
// size is set.
if (!is_remote_ &&
(cached_stream_texture_size_.width != natural_size_.width ||
cached_stream_texture_size_.height != natural_size_.height)) {
stream_texture_factory_->SetStreamTextureSize(
stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
cached_stream_texture_size_ = natural_size_;
}
web_graphics_context->waitSyncPoint(mailbox_holder->sync_point); web_graphics_context->waitSyncPoint(mailbox_holder->sync_point);
// Ensure the target of texture is set before copyTextureCHROMIUM, otherwise // Ensure the target of texture is set before copyTextureCHROMIUM, otherwise
...@@ -611,6 +615,7 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture( ...@@ -611,6 +615,7 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
} }
bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const { bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (player_type_ != MEDIA_PLAYER_TYPE_URL) if (player_type_ != MEDIA_PLAYER_TYPE_URL)
return true; return true;
...@@ -631,6 +636,7 @@ bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const { ...@@ -631,6 +636,7 @@ bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
} }
bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const { bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (info_loader_) if (info_loader_)
return info_loader_->DidPassCORSAccessCheck(); return info_loader_->DidPassCORSAccessCheck();
return false; return false;
...@@ -670,6 +676,7 @@ unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const { ...@@ -670,6 +676,7 @@ unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
void WebMediaPlayerAndroid::OnMediaMetadataChanged( void WebMediaPlayerAndroid::OnMediaMetadataChanged(
const base::TimeDelta& duration, int width, int height, bool success) { const base::TimeDelta& duration, int width, int height, bool success) {
DCHECK(main_thread_checker_.CalledOnValidThread());
bool need_to_signal_duration_changed = false; bool need_to_signal_duration_changed = false;
if (url_.SchemeIs("file")) if (url_.SchemeIs("file"))
...@@ -773,6 +780,7 @@ void WebMediaPlayerAndroid::OnMediaError(int error_type) { ...@@ -773,6 +780,7 @@ void WebMediaPlayerAndroid::OnMediaError(int error_type) {
} }
void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
DCHECK(main_thread_checker_.CalledOnValidThread());
has_size_info_ = true; has_size_info_ = true;
if (natural_size_.width == width && natural_size_.height == height) if (natural_size_.width == width && natural_size_.height == height)
return; return;
...@@ -792,6 +800,9 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { ...@@ -792,6 +800,9 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
SetNeedsEstablishPeer(true); SetNeedsEstablishPeer(true);
} }
#endif // defined(VIDEO_HOLE) #endif // defined(VIDEO_HOLE)
natural_size_.width = width;
natural_size_.height = height;
// When play() gets called, |natural_size_| may still be empty and // When play() gets called, |natural_size_| may still be empty and
// EstablishSurfaceTexturePeer() will not get called. As a result, the video // EstablishSurfaceTexturePeer() will not get called. As a result, the video
// may play without a surface texture. When we finally get the valid video // may play without a surface texture. When we finally get the valid video
...@@ -800,10 +811,16 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) { ...@@ -800,10 +811,16 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
if (!paused() && needs_establish_peer_) if (!paused() && needs_establish_peer_)
EstablishSurfaceTexturePeer(); EstablishSurfaceTexturePeer();
natural_size_.width = width;
natural_size_.height = height;
ReallocateVideoFrame(); ReallocateVideoFrame();
// For hidden video element (with style "display:none"), ensure the texture
// size is set.
if (!is_remote_ && cached_stream_texture_size_ != natural_size_) {
stream_texture_factory_->SetStreamTextureSize(
stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
cached_stream_texture_size_ = natural_size_;
}
// Lazily allocate compositing layer. // Lazily allocate compositing layer.
if (!video_weblayer_) { if (!video_weblayer_) {
video_weblayer_.reset(new WebLayerImpl( video_weblayer_.reset(new WebLayerImpl(
...@@ -977,7 +994,6 @@ void WebMediaPlayerAndroid::Pause(bool is_media_related_action) { ...@@ -977,7 +994,6 @@ void WebMediaPlayerAndroid::Pause(bool is_media_related_action) {
void WebMediaPlayerAndroid::DrawRemotePlaybackText( void WebMediaPlayerAndroid::DrawRemotePlaybackText(
const std::string& remote_playback_message) { const std::string& remote_playback_message) {
DCHECK(main_thread_checker_.CalledOnValidThread()); DCHECK(main_thread_checker_.CalledOnValidThread());
if (!video_weblayer_) if (!video_weblayer_)
return; return;
...@@ -1099,6 +1115,7 @@ void WebMediaPlayerAndroid::DrawRemotePlaybackText( ...@@ -1099,6 +1115,7 @@ void WebMediaPlayerAndroid::DrawRemotePlaybackText(
} }
void WebMediaPlayerAndroid::ReallocateVideoFrame() { void WebMediaPlayerAndroid::ReallocateVideoFrame() {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (needs_external_surface_) { if (needs_external_surface_) {
// VideoFrame::CreateHoleFrame is only defined under VIDEO_HOLE. // VideoFrame::CreateHoleFrame is only defined under VIDEO_HOLE.
#if defined(VIDEO_HOLE) #if defined(VIDEO_HOLE)
...@@ -1143,12 +1160,22 @@ void WebMediaPlayerAndroid::SetVideoFrameProviderClient( ...@@ -1143,12 +1160,22 @@ void WebMediaPlayerAndroid::SetVideoFrameProviderClient(
video_frame_provider_client_ = client; video_frame_provider_client_ = client;
// Set the callback target when a frame is produced. // Set the callback target when a frame is produced.
if (stream_texture_proxy_) if (stream_texture_proxy_) {
stream_texture_proxy_->SetClient(client); stream_texture_proxy_->SetClient(client);
// If client exists, the compositor thread calls it. At that time,
// stream_id_, needs_external_surface_, is_remote_ can be accessed because
// the main thread is blocked.
if (client && !stream_texture_proxy_initialized_ && stream_id_ &&
!needs_external_surface_ && !is_remote_) {
stream_texture_proxy_->BindToCurrentThread(stream_id_);
stream_texture_proxy_initialized_ = true;
}
}
} }
void WebMediaPlayerAndroid::SetCurrentFrameInternal( void WebMediaPlayerAndroid::SetCurrentFrameInternal(
scoped_refptr<media::VideoFrame>& video_frame) { scoped_refptr<media::VideoFrame>& video_frame) {
DCHECK(main_thread_checker_.CalledOnValidThread());
base::AutoLock auto_lock(current_frame_lock_); base::AutoLock auto_lock(current_frame_lock_);
current_frame_ = video_frame; current_frame_ = video_frame;
} }
...@@ -1160,16 +1187,6 @@ scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() { ...@@ -1160,16 +1187,6 @@ scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
video_frame = current_frame_; video_frame = current_frame_;
} }
if (!stream_texture_proxy_initialized_ && stream_texture_proxy_ &&
stream_id_ && !needs_external_surface_ && !is_remote_) {
gfx::Size natural_size = video_frame->natural_size();
// TODO(sievers): These variables are accessed on the wrong thread here.
stream_texture_proxy_->BindToCurrentThread(stream_id_);
stream_texture_factory_->SetStreamTextureSize(stream_id_, natural_size);
stream_texture_proxy_initialized_ = true;
cached_stream_texture_size_ = natural_size;
}
return video_frame; return video_frame;
} }
...@@ -1178,6 +1195,7 @@ void WebMediaPlayerAndroid::PutCurrentFrame( ...@@ -1178,6 +1195,7 @@ void WebMediaPlayerAndroid::PutCurrentFrame(
} }
void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() { void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
DCHECK(main_thread_checker_.CalledOnValidThread());
// Already created. // Already created.
if (stream_texture_proxy_) if (stream_texture_proxy_)
return; return;
...@@ -1197,15 +1215,25 @@ void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() { ...@@ -1197,15 +1215,25 @@ void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
} }
void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() { void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!stream_texture_proxy_) if (!stream_texture_proxy_)
return; return;
if (stream_texture_factory_.get() && stream_id_) if (stream_texture_factory_.get() && stream_id_)
stream_texture_factory_->EstablishPeer(stream_id_, player_id_); stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
// Set the deferred size because the size was changed in remote mode.
if (!is_remote_ && cached_stream_texture_size_ != natural_size_) {
stream_texture_factory_->SetStreamTextureSize(
stream_id_, gfx::Size(natural_size_.width, natural_size_.height));
cached_stream_texture_size_ = natural_size_;
}
needs_establish_peer_ = false; needs_establish_peer_ = false;
} }
void WebMediaPlayerAndroid::DoCreateStreamTexture() { void WebMediaPlayerAndroid::DoCreateStreamTexture() {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(!stream_id_); DCHECK(!stream_id_);
DCHECK(!texture_id_); DCHECK(!texture_id_);
stream_id_ = stream_texture_factory_->CreateStreamTexture( stream_id_ = stream_texture_factory_->CreateStreamTexture(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment