Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Unified Diff: media/gpu/avda_picture_buffer_manager.cc

Issue 2461073002: Use MediaCodec.setOutputSurface() for fullscreen transitions on M. (Closed)
Patch Set: Simplify APIs. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/gpu/avda_picture_buffer_manager.cc
diff --git a/media/gpu/avda_picture_buffer_manager.cc b/media/gpu/avda_picture_buffer_manager.cc
index 135aa3a23c5fd9ef983e854a4d2248fbbb971b68..118a28dc59a57f1e43318756b9cb6d14d1ad7661 100644
--- a/media/gpu/avda_picture_buffer_manager.cc
+++ b/media/gpu/avda_picture_buffer_manager.cc
@@ -77,79 +77,29 @@ scoped_refptr<gl::SurfaceTexture> CreateAttachedSurfaceTexture(
} // namespace
-// Handle OnFrameAvailable callbacks safely. Since they occur asynchronously,
-// we take care that the object that wants them still exists. WeakPtrs cannot
-// be used because OnFrameAvailable callbacks can occur on any thread. We also
-// can't guarantee when the SurfaceTexture will quit sending callbacks to
-// coordinate with the destruction of the AVDA and PictureBufferManager, so we
-// have a separate object that the callback can own.
-class AVDAPictureBufferManager::OnFrameAvailableHandler
- : public base::RefCountedThreadSafe<OnFrameAvailableHandler> {
- public:
- // We do not retain ownership of |listener|. It must remain valid until after
- // ClearListener() is called. This will register with |surface_texture| to
- // receive OnFrameAvailable callbacks.
- OnFrameAvailableHandler(AVDASharedState* listener,
- gl::SurfaceTexture* surface_texture)
- : listener_(listener) {
- surface_texture->SetFrameAvailableCallbackOnAnyThread(
- base::Bind(&OnFrameAvailableHandler::OnFrameAvailable,
- scoped_refptr<OnFrameAvailableHandler>(this)));
- }
-
- // Forget about |listener_|, which is required before one deletes it.
- // No further callbacks will happen once this completes.
- void ClearListener() {
- base::AutoLock lock(lock_);
- listener_ = nullptr;
- }
-
- // Notify the listener if there is one.
- void OnFrameAvailable() {
- base::AutoLock auto_lock(lock_);
- if (listener_)
- listener_->SignalFrameAvailable();
- }
-
- private:
- friend class base::RefCountedThreadSafe<OnFrameAvailableHandler>;
-
- ~OnFrameAvailableHandler() { DCHECK(!listener_); }
-
- // Protects changes to listener_.
- base::Lock lock_;
-
- // The AVDASharedState that wants the OnFrameAvailable callback.
- AVDASharedState* listener_;
-
- DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler);
-};
-
-AVDAPictureBufferManager::AVDAPictureBufferManager()
- : state_provider_(nullptr), media_codec_(nullptr) {}
+AVDAPictureBufferManager::AVDAPictureBufferManager(
+ AVDAStateProvider* state_provider)
+ : state_provider_(state_provider), media_codec_(nullptr) {}
AVDAPictureBufferManager::~AVDAPictureBufferManager() {}
-gl::ScopedJavaSurface AVDAPictureBufferManager::Initialize(
- AVDAStateProvider* state_provider,
- int surface_view_id) {
- state_provider_ = state_provider;
+gl::ScopedJavaSurface AVDAPictureBufferManager::Initialize(int surface_id) {
shared_state_ = new AVDASharedState();
// Acquire the SurfaceView surface if given a valid id.
- if (surface_view_id != VideoDecodeAccelerator::Config::kNoSurfaceID) {
- return gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(
- surface_view_id);
+ if (surface_id != SurfaceManager::kNoSurfaceID) {
+ if (surface_texture_) {
+ surface_texture_->ReleaseSurfaceTexture();
+ surface_texture_ = nullptr;
+ }
+ return gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(surface_id);
}
- // Otherwise create a SurfaceTexture.
- GLuint service_id = 0;
+ // Always create a SurfaceTexture, we'll use it for entering and exiting from
+ // fullscreen mode.
+ GLuint service_id;
surface_texture_ = CreateAttachedSurfaceTexture(
state_provider_->GetGlDecoder(), &service_id);
- if (surface_texture_) {
- on_frame_available_handler_ = new OnFrameAvailableHandler(
- shared_state_.get(), surface_texture_.get());
- }
shared_state_->SetSurfaceTexture(surface_texture_, service_id);
return gl::ScopedJavaSurface(surface_texture_.get());
}
@@ -159,11 +109,6 @@ void AVDAPictureBufferManager::Destroy(const PictureBufferMap& buffers) {
if (!shared_state_)
return;
- // If we have an OnFrameAvailable handler, tell it that we no longer want
- // callbacks.
- if (on_frame_available_handler_)
- on_frame_available_handler_->ClearListener();
-
ReleaseCodecBuffers(buffers);
CodecChanged(nullptr);
@@ -174,22 +119,17 @@ void AVDAPictureBufferManager::Destroy(const PictureBufferMap& buffers) {
}
uint32_t AVDAPictureBufferManager::GetTextureTarget() const {
- // If we're using a surface texture, then we need an external texture target
- // to sample from it. If not, then we'll use 2D transparent textures to draw
- // a transparent hole through which to see the SurfaceView. This is normally
- // needed only for the devtools inspector, since the overlay mechanism handles
- // it otherwise.
- return surface_texture_ ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
+ // Always use OES textures even though this will cause flickering in dev tools
+ // when inspecting a fullscreen video. See http://crbug.com/592798
+ return GL_TEXTURE_EXTERNAL_OES;
}
gfx::Size AVDAPictureBufferManager::GetPictureBufferSize() const {
- // For SurfaceView, request a 1x1 2D texture to reduce memory during
- // initialization. For SurfaceTexture, allocate a picture buffer that is the
- // actual frame size. Note that it will be an external texture anyway, so it
- // doesn't allocate an image of that size. However, it's still important to
- // get the coded size right, so that VideoLayerImpl doesn't try to scale the
- // texture when building the quad for it.
- return surface_texture_ ? state_provider_->GetSize() : gfx::Size(1, 1);
+ // Allocate a picture buffer that is the actual frame size. Note that it will
+ // be an external texture anyway, so it doesn't allocate an image of that
+ // size. It's important to get the coded size right, so that VideoLayerImpl
+ // doesn't try to scale the texture when building the quad for it.
+ return state_provider_->GetSize();
}
gpu::gles2::TextureRef* AVDAPictureBufferManager::GetTextureForPicture(
@@ -212,7 +152,7 @@ gpu::gles2::TextureRef* AVDAPictureBufferManager::GetTextureForPicture(
void AVDAPictureBufferManager::SetImageForPicture(
const PictureBuffer& picture_buffer,
- const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image) {
+ gpu::gles2::GLStreamTextureImage* image) {
gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(picture_buffer);
RETURN_IF_NULL(texture_ref);
@@ -236,8 +176,7 @@ void AVDAPictureBufferManager::SetImageForPicture(
size.width(), size.height(), 1, 0, GL_RGBA,
GL_UNSIGNED_BYTE, gfx::Rect());
- static_cast<AVDACodecImage*>(image.get())
- ->set_texture(texture_ref->texture());
+ static_cast<AVDACodecImage*>(image)->set_texture(texture_ref->texture());
}
// If we're clearing the image, or setting a SurfaceTexture backed image, we
@@ -249,13 +188,19 @@ void AVDAPictureBufferManager::SetImageForPicture(
// requires it. If something tries to sample from this texture it won't work,
// but there's no way to sample from a SurfaceView anyway, so it doesn't
// matter.
- if (image && !surface_texture_)
+ if (image && !shared_state_->surface_texture_service_id())
image_state = gpu::gles2::Texture::BOUND;
texture_manager->SetLevelStreamTextureImage(texture_ref, GetTextureTarget(),
- 0, image.get(), image_state,
+ 0, image, image_state,
stream_texture_service_id);
}
+AVDACodecImage* AVDAPictureBufferManager::GetImageForPicture(
+ int picture_buffer_id) const {
+ auto it = codec_images_.find(picture_buffer_id);
+ return it == codec_images_.end() ? nullptr : it->second;
+}
+
void AVDAPictureBufferManager::UseCodecBufferForPictureBuffer(
int32_t codec_buf_index,
const PictureBuffer& picture_buffer) {
@@ -264,15 +209,26 @@ void AVDAPictureBufferManager::UseCodecBufferForPictureBuffer(
// Notify the AVDACodecImage for picture_buffer that it should use the
// decoded buffer codec_buf_index to render this frame.
- AVDACodecImage* avda_image =
- shared_state_->GetImageForPicture(picture_buffer.id());
+ AVDACodecImage* avda_image = GetImageForPicture(picture_buffer.id());
RETURN_IF_NULL(avda_image);
// Note that this is not a race, since we do not re-use a PictureBuffer
// until after the CC is done drawing it.
pictures_out_for_display_.push_back(picture_buffer.id());
- avda_image->set_media_codec_buffer_index(codec_buf_index);
- avda_image->set_size(state_provider_->GetSize());
+ avda_image->SetBufferMetadata(codec_buf_index,
+ !!shared_state_->surface_texture_service_id(),
+ state_provider_->GetSize());
+
+ // If the shared state has changed for this image, retarget its texture.
+ if (avda_image->SetSharedState(shared_state_)) {
+ gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(picture_buffer);
+ RETURN_IF_NULL(texture_ref);
+ texture_ref->texture()->SetStreamTextureServiceId(
+ shared_state_->surface_texture_service_id());
+
+ // TODO(dalecurtis): What about ImageState? For ST we set UNBOUND while we
+ // always set BOUND for SV.
liberato (no reviews please) 2016/11/03 20:51:04 we should do that here too, i think. actually, i
DaleCurtis 2016/11/03 20:59:35 Originally tried this, but there are some restrict
DaleCurtis 2016/11/03 23:25:05 Ah, this was because the last ref to the GLImage w
+ }
MaybeRenderEarly();
}
@@ -282,32 +238,32 @@ void AVDAPictureBufferManager::AssignOnePictureBuffer(
bool have_context) {
// Attach a GLImage to each texture that will use the surface texture.
// We use a refptr here in case SetImageForPicture fails.
- scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image =
- new AVDACodecImage(picture_buffer.id(), shared_state_, media_codec_,
- state_provider_->GetGlDecoder());
- SetImageForPicture(picture_buffer, gl_image);
-
- if (!surface_texture_ && have_context) {
- // To make devtools work, we're using a 2D texture. Make it transparent,
- // so that it draws a hole for the SV to show through. This is only
- // because devtools draws and reads back, which skips overlay processing.
- // It's unclear why devtools renders twice -- once normally, and once
- // including a readback layer. The result is that the device screen
- // flashes as we alternately draw the overlay hole and this texture,
- // unless we make the texture transparent.
- static const uint8_t rgba[] = {0, 0, 0, 0};
- const gfx::Size size(1, 1);
- DCHECK_LE(1u, picture_buffer.service_texture_ids().size());
- glBindTexture(GL_TEXTURE_2D, picture_buffer.service_texture_ids()[0]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
- GL_RGBA, GL_UNSIGNED_BYTE, rgba);
- }
+ scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image = new AVDACodecImage(
+ shared_state_, media_codec_, state_provider_->GetGlDecoder());
+ SetImageForPicture(picture_buffer, gl_image.get());
+ codec_images_[picture_buffer.id()] =
+ static_cast<AVDACodecImage*>(gl_image.get());
+
+ // if (!shared_state_->surface_texture_service_id() && have_context) {
+ // // To make devtools work, we're using a 2D texture. Make it transparent,
+ // // so that it draws a hole for the SV to show through. This is only
+ // // because devtools draws and reads back, which skips overlay processing.
+ // // It's unclear why devtools renders twice -- once normally, and once
+ // // including a readback layer. The result is that the device screen
+ // // flashes as we alternately draw the overlay hole and this texture,
+ // // unless we make the texture transparent.
+ // static const uint8_t rgba[] = {0, 0, 0, 0};
+ // const gfx::Size size(1, 1);
+ // DCHECK_LE(1u, picture_buffer.service_texture_ids().size());
+ // glBindTexture(GL_TEXTURE_2D, picture_buffer.service_texture_ids()[0]);
+ // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
+ // GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ // }
}
void AVDAPictureBufferManager::ReleaseCodecBufferForPicture(
const PictureBuffer& picture_buffer) {
- AVDACodecImage* avda_image =
- shared_state_->GetImageForPicture(picture_buffer.id());
+ AVDACodecImage* avda_image = GetImageForPicture(picture_buffer.id());
RETURN_IF_NULL(avda_image);
avda_image->UpdateSurface(AVDACodecImage::UpdateMode::DISCARD_CODEC_BUFFER);
}
@@ -344,7 +300,7 @@ void AVDAPictureBufferManager::MaybeRenderEarly() {
AVDACodecImage* first_renderable_image = nullptr;
for (int i = front_index; i >= 0; --i) {
const int id = pictures_out_for_display_[i];
- AVDACodecImage* avda_image = shared_state_->GetImageForPicture(id);
+ AVDACodecImage* avda_image = GetImageForPicture(id);
if (!avda_image)
continue;
@@ -369,14 +325,16 @@ void AVDAPictureBufferManager::MaybeRenderEarly() {
// Back buffer rendering is only available for surface textures. We'll always
// have at least one front buffer, so the next buffer must be the backbuffer.
size_t backbuffer_index = front_index + 1;
- if (!surface_texture_ || backbuffer_index >= pictures_out_for_display_.size())
+ if (!shared_state_->surface_texture_service_id() ||
+ backbuffer_index >= pictures_out_for_display_.size()) {
return;
+ }
// See if the back buffer is free. If so, then render the frame adjacent to
// the front buffer. The listing is in render order, so we can just use the
// first unrendered frame if there is back buffer space.
- first_renderable_image = shared_state_->GetImageForPicture(
- pictures_out_for_display_[backbuffer_index]);
+ first_renderable_image =
+ GetImageForPicture(pictures_out_for_display_[backbuffer_index]);
if (!first_renderable_image ||
first_renderable_image->was_rendered_to_back_buffer()) {
return;
@@ -390,13 +348,24 @@ void AVDAPictureBufferManager::MaybeRenderEarly() {
void AVDAPictureBufferManager::CodecChanged(VideoCodecBridge* codec) {
media_codec_ = codec;
- shared_state_->CodecChanged(codec);
+ for (auto& image_kv : codec_images_)
+ image_kv.second->CodecChanged(codec);
+ shared_state_->clear_release_time();
}
bool AVDAPictureBufferManager::ArePicturesOverlayable() {
// SurfaceView frames are always overlayable because that's the only way to
// display them.
- return !surface_texture_;
+ return !shared_state_->surface_texture_service_id();
+}
+
+bool AVDAPictureBufferManager::ArePicturesOutstanding() const {
+ for (int id : pictures_out_for_display_) {
+ AVDACodecImage* avda_image = GetImageForPicture(id);
+ if (avda_image && avda_image->has_unrendered_frame())
+ return true;
+ }
+ return false;
}
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698