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(
}
WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
DCHECK(main_thread_checker_.CalledOnValidThread());
SetVideoFrameProviderClient(NULL);
client_->setWebLayer(NULL);
......@@ -196,6 +197,7 @@ WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
void WebMediaPlayerAndroid::load(LoadType load_type,
const blink::WebURL& url,
CORSMode cors_mode) {
DCHECK(main_thread_checker_.CalledOnValidThread());
ReportMediaSchemeUma(GURL(url));
switch (load_type) {
......@@ -261,6 +263,7 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo(
const GURL& redirected_url,
const GURL& first_party_for_cookies,
bool allow_stored_credentials) {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(!media_source_delegate_);
if (status == MediaInfoLoader::kFailed) {
info_loader_.reset();
......@@ -275,6 +278,7 @@ void WebMediaPlayerAndroid::DidLoadMediaInfo(
}
void WebMediaPlayerAndroid::play() {
DCHECK(main_thread_checker_.CalledOnValidThread());
#if defined(VIDEO_HOLE)
if (hasVideo() && needs_external_surface_ &&
!player_manager_->IsInFullscreen(frame_)) {
......@@ -298,6 +302,7 @@ void WebMediaPlayerAndroid::play() {
}
void WebMediaPlayerAndroid::pause() {
DCHECK(main_thread_checker_.CalledOnValidThread());
Pause(true);
}
......@@ -354,10 +359,12 @@ void WebMediaPlayerAndroid::setRate(double rate) {
}
void WebMediaPlayerAndroid::setVolume(double volume) {
DCHECK(main_thread_checker_.CalledOnValidThread());
player_manager_->SetVolume(player_id_, volume);
}
bool WebMediaPlayerAndroid::hasVideo() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
// If we have obtained video size information before, use it.
if (has_size_info_)
return !natural_size_.isEmpty();
......@@ -379,6 +386,7 @@ bool WebMediaPlayerAndroid::hasVideo() const {
}
bool WebMediaPlayerAndroid::hasAudio() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!url_.has_path())
return false;
std::string mime;
......@@ -402,6 +410,7 @@ bool WebMediaPlayerAndroid::seeking() const {
}
double WebMediaPlayerAndroid::duration() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
// HTML5 spec requires duration to be NaN if readyState is HAVE_NOTHING
if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing)
return std::numeric_limits<double>::quiet_NaN();
......@@ -413,6 +422,7 @@ double WebMediaPlayerAndroid::duration() const {
}
double WebMediaPlayerAndroid::timelineOffset() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
base::Time timeline_offset;
if (media_source_delegate_)
timeline_offset = media_source_delegate_->GetTimelineOffset();
......@@ -424,6 +434,7 @@ double WebMediaPlayerAndroid::timelineOffset() const {
}
double WebMediaPlayerAndroid::currentTime() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
// If the player is processing a seek, return the seek time.
// Blink may still query us if updatePlaybackState() occurs while seeking.
if (seeking()) {
......@@ -472,6 +483,7 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr,
const WebSize& size,
GrSurfaceOrigin origin,
GrPixelConfig config) {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!bitmap.getTexture() || bitmap.width() != size.width
|| bitmap.height() != size.height) {
if (!gr)
......@@ -502,6 +514,7 @@ bool WebMediaPlayerAndroid::EnsureTextureBackedSkBitmap(GrContext* gr,
void WebMediaPlayerAndroid::paint(blink::WebCanvas* canvas,
const blink::WebRect& rect,
unsigned char alpha) {
DCHECK(main_thread_checker_.CalledOnValidThread());
scoped_ptr<blink::WebGraphicsContext3DProvider> provider =
scoped_ptr<blink::WebGraphicsContext3DProvider>(blink::Platform::current(
)->createSharedOffscreenGraphicsContext3DProvider());
......@@ -550,6 +563,7 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
unsigned int type,
bool premultiply_alpha,
bool flip_y) {
DCHECK(main_thread_checker_.CalledOnValidThread());
// Don't allow clients to copy an encrypted video frame.
if (needs_external_surface_)
return false;
......@@ -568,16 +582,6 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES) ||
(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);
// Ensure the target of texture is set before copyTextureCHROMIUM, otherwise
......@@ -611,6 +615,7 @@ bool WebMediaPlayerAndroid::copyVideoTextureToPlatformTexture(
}
bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (player_type_ != MEDIA_PLAYER_TYPE_URL)
return true;
......@@ -631,6 +636,7 @@ bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
}
bool WebMediaPlayerAndroid::didPassCORSAccessCheck() const {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (info_loader_)
return info_loader_->DidPassCORSAccessCheck();
return false;
......@@ -670,6 +676,7 @@ unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
void WebMediaPlayerAndroid::OnMediaMetadataChanged(
const base::TimeDelta& duration, int width, int height, bool success) {
DCHECK(main_thread_checker_.CalledOnValidThread());
bool need_to_signal_duration_changed = false;
if (url_.SchemeIs("file"))
......@@ -773,6 +780,7 @@ void WebMediaPlayerAndroid::OnMediaError(int error_type) {
}
void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
DCHECK(main_thread_checker_.CalledOnValidThread());
has_size_info_ = true;
if (natural_size_.width == width && natural_size_.height == height)
return;
......@@ -792,6 +800,9 @@ void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
SetNeedsEstablishPeer(true);
}
#endif // defined(VIDEO_HOLE)
natural_size_.width = width;
natural_size_.height = height;
// When play() gets called, |natural_size_| may still be empty and
// EstablishSurfaceTexturePeer() will not get called. As a result, the 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) {
if (!paused() && needs_establish_peer_)
EstablishSurfaceTexturePeer();
natural_size_.width = width;
natural_size_.height = height;
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.
if (!video_weblayer_) {
video_weblayer_.reset(new WebLayerImpl(
......@@ -977,7 +994,6 @@ void WebMediaPlayerAndroid::Pause(bool is_media_related_action) {
void WebMediaPlayerAndroid::DrawRemotePlaybackText(
const std::string& remote_playback_message) {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!video_weblayer_)
return;
......@@ -1099,6 +1115,7 @@ void WebMediaPlayerAndroid::DrawRemotePlaybackText(
}
void WebMediaPlayerAndroid::ReallocateVideoFrame() {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (needs_external_surface_) {
// VideoFrame::CreateHoleFrame is only defined under VIDEO_HOLE.
#if defined(VIDEO_HOLE)
......@@ -1143,12 +1160,22 @@ void WebMediaPlayerAndroid::SetVideoFrameProviderClient(
video_frame_provider_client_ = client;
// Set the callback target when a frame is produced.
if (stream_texture_proxy_)
if (stream_texture_proxy_) {
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(
scoped_refptr<media::VideoFrame>& video_frame) {
DCHECK(main_thread_checker_.CalledOnValidThread());
base::AutoLock auto_lock(current_frame_lock_);
current_frame_ = video_frame;
}
......@@ -1160,16 +1187,6 @@ scoped_refptr<media::VideoFrame> WebMediaPlayerAndroid::GetCurrentFrame() {
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;
}
......@@ -1178,6 +1195,7 @@ void WebMediaPlayerAndroid::PutCurrentFrame(
}
void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
DCHECK(main_thread_checker_.CalledOnValidThread());
// Already created.
if (stream_texture_proxy_)
return;
......@@ -1197,15 +1215,25 @@ void WebMediaPlayerAndroid::TryCreateStreamTextureProxyIfNeeded() {
}
void WebMediaPlayerAndroid::EstablishSurfaceTexturePeer() {
DCHECK(main_thread_checker_.CalledOnValidThread());
if (!stream_texture_proxy_)
return;
if (stream_texture_factory_.get() && stream_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;
}
void WebMediaPlayerAndroid::DoCreateStreamTexture() {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(!stream_id_);
DCHECK(!texture_id_);
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