Skip to content

Commit

Permalink
Send hardware video frames with mailboxes.
Browse files Browse the repository at this point in the history
Change media::VideoFrame from holding a raw texture id to
instead hold a gpu::Mailbox. The hardware video decoders
produce a mailbox on their context from the texture id
before putting it in the VideoFrame, and consume the
mailbox again when they receive the texture id back.

In the compositor, we hold onto the VideoFrame::MailboxHolder
as long as the mailboxed texture is in use in the compositor
(or its parent). This keeps the video decoders from writing
to the texture id, as they register a callback in the
VideoFrame to be called when it is destroyed.

BUG=179729

Review URL: https://chromiumcodereview.appspot.com/14199002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208568 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
danakj@chromium.org committed Jun 25, 2013
1 parent d30268a commit e56f88c
Show file tree
Hide file tree
Showing 23 changed files with 564 additions and 172 deletions.
55 changes: 15 additions & 40 deletions cc/layers/video_layer_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ scoped_ptr<VideoLayerImpl> VideoLayerImpl::Create(

VideoLayerImpl::VideoLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
frame_(NULL),
hardware_resource_(0) {}
frame_(NULL) {}

VideoLayerImpl::~VideoLayerImpl() {
if (!provider_client_impl_->Stopped()) {
Expand Down Expand Up @@ -96,12 +95,8 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
if (!updater_)
updater_.reset(new VideoResourceUpdater(resource_provider));

VideoFrameExternalResources external_resources;
if (frame_->format() == media::VideoFrame::NATIVE_TEXTURE)
external_resources = updater_->CreateForHardwarePlanes(frame_);
else
external_resources = updater_->CreateForSoftwarePlanes(frame_);

VideoFrameExternalResources external_resources =
updater_->CreateExternalResourcesFromVideoFrame(frame_);
frame_resource_type_ = external_resources.type;

if (external_resources.type ==
Expand All @@ -112,13 +107,6 @@ bool VideoLayerImpl::WillDraw(DrawMode draw_mode,
return true;
}

if (external_resources.hardware_resource) {
hardware_resource_ = external_resources.hardware_resource;
hardware_release_callback_ =
external_resources.hardware_release_callback;
return true;
}

for (size_t i = 0; i < external_resources.mailboxes.size(); ++i) {
frame_resources_.push_back(
resource_provider->CreateResourceFromTextureMailbox(
Expand Down Expand Up @@ -191,11 +179,9 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
break;
}
case VideoFrameExternalResources::RGB_RESOURCE: {
if (!hardware_resource_) {
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
}
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
bool premultiplied_alpha = true;
gfx::PointF uv_top_left(0.f, 0.f);
gfx::PointF uv_bottom_right(tex_width_scale, tex_height_scale);
Expand All @@ -205,8 +191,7 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
texture_quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
hardware_resource_ ? hardware_resource_
: frame_resources_[0],
frame_resources_[0],
premultiplied_alpha,
uv_top_left,
uv_bottom_right,
Expand All @@ -216,11 +201,9 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
break;
}
case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
if (!hardware_resource_) {
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
}
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
gfx::Transform transform(
provider_client_impl_->stream_texture_matrix());
transform.Scale(tex_width_scale, tex_height_scale);
Expand All @@ -229,28 +212,24 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
stream_video_quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
hardware_resource_ ? hardware_resource_
: frame_resources_[0],
frame_resources_[0],
transform);
quad_sink->Append(stream_video_quad.PassAs<DrawQuad>(),
append_quads_data);
break;
}
case VideoFrameExternalResources::IO_SURFACE: {
if (!hardware_resource_) {
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
}
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
gfx::Size visible_size(visible_rect.width(), visible_rect.height());
scoped_ptr<IOSurfaceDrawQuad> io_surface_quad =
IOSurfaceDrawQuad::Create();
io_surface_quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
visible_size,
hardware_resource_ ? hardware_resource_
: frame_resources_[0],
frame_resources_[0],
IOSurfaceDrawQuad::UNFLIPPED);
quad_sink->Append(io_surface_quad.PassAs<DrawQuad>(),
append_quads_data);
Expand Down Expand Up @@ -296,10 +275,6 @@ void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {

software_resources_.clear();
software_release_callback_.Reset();
} else if (hardware_resource_) {
hardware_release_callback_.Run(0, false);
hardware_resource_ = 0;
hardware_release_callback_.Reset();
} else {
for (size_t i = 0; i < frame_resources_.size(); ++i)
resource_provider->DeleteResource(frame_resources_[i]);
Expand Down
4 changes: 0 additions & 4 deletions cc/layers/video_layer_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl {
VideoFrameExternalResources::ResourceType frame_resource_type_;
std::vector<ResourceProvider::ResourceId> frame_resources_;

// TODO(danakj): Remove this when hardware frames come through a mailbox.
unsigned hardware_resource_;
TextureMailbox::ReleaseCallback hardware_release_callback_;

// TODO(danakj): Remove these, hide software path inside ResourceProvider and
// ExternalResource (aka TextureMailbox) classes.
std::vector<unsigned> software_resources_;
Expand Down
61 changes: 29 additions & 32 deletions cc/resources/video_resource_updater.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ const unsigned kRGBResourceFormat = GL_RGBA;

namespace cc {

VideoFrameExternalResources::VideoFrameExternalResources()
: type(NONE), hardware_resource(0) {}
VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}

VideoFrameExternalResources::~VideoFrameExternalResources() {}

Expand All @@ -42,6 +41,18 @@ void VideoResourceUpdater::DeleteResource(unsigned resource_id) {
resource_id));
}

VideoFrameExternalResources VideoResourceUpdater::
CreateExternalResourcesFromVideoFrame(
const scoped_refptr<media::VideoFrame>& video_frame) {
if (!VerifyFrame(video_frame))
return VideoFrameExternalResources();

if (video_frame->format() == media::VideoFrame::NATIVE_TEXTURE)
return CreateForHardwarePlanes(video_frame);
else
return CreateForSoftwarePlanes(video_frame);
}

bool VideoResourceUpdater::VerifyFrame(
const scoped_refptr<media::VideoFrame>& video_frame) {
// If these fail, we'll have to add logic that handles offset bitmap/texture
Expand Down Expand Up @@ -108,9 +119,6 @@ static gfx::Size SoftwarePlaneDimension(

VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame) {
if (!VerifyFrame(video_frame))
return VideoFrameExternalResources();

media::VideoFrame::Format input_frame_format = video_frame->format();

#if defined(GOOGLE_TV)
Expand Down Expand Up @@ -308,11 +316,15 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
return external_resources;
}

static void ReturnTexture(
scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder,
unsigned sync_point,
bool lost_resource) {
mailbox_holder->Return(sync_point);
}

VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame) {
if (!VerifyFrame(video_frame))
return VideoFrameExternalResources();

media::VideoFrame::Format frame_format = video_frame->format();

DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE);
Expand Down Expand Up @@ -341,33 +353,18 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
return VideoFrameExternalResources();
}

external_resources.hardware_resource =
resource_provider_->CreateResourceFromExternalTexture(
video_frame->texture_target(),
video_frame->texture_id());
if (external_resources.hardware_resource)
all_resources_.push_back(external_resources.hardware_resource);
scoped_refptr<media::VideoFrame::MailboxHolder> mailbox_holder =
video_frame->texture_mailbox();

TextureMailbox::ReleaseCallback callback_to_return_resource =
base::Bind(&ReturnTexture,
AsWeakPtr(),
external_resources.hardware_resource);
external_resources.hardware_release_callback = callback_to_return_resource;
return external_resources;
}
base::Bind(&ReturnTexture, mailbox_holder);

// static
void VideoResourceUpdater::ReturnTexture(
base::WeakPtr<VideoResourceUpdater> updater,
unsigned resource_id,
unsigned sync_point,
bool lost_resource) {
if (!updater.get()) {
// Resource was already deleted.
return;
}

updater->DeleteResource(resource_id);
external_resources.mailboxes.push_back(
TextureMailbox(mailbox_holder->mailbox(),
callback_to_return_resource,
video_frame->texture_target(),
mailbox_holder->sync_point()));
return external_resources;
}

// static
Expand Down
17 changes: 5 additions & 12 deletions cc/resources/video_resource_updater.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ class VideoFrameExternalResources {
ResourceType type;
std::vector<TextureMailbox> mailboxes;

// TODO(danakj): Remove these when we get a Mailbox from VideoFrame.
unsigned hardware_resource;
TextureMailbox::ReleaseCallback hardware_release_callback;

// TODO(danakj): Remove these too.
std::vector<unsigned> software_resources;
TextureMailbox::ReleaseCallback software_release_callback;
Expand All @@ -67,10 +63,7 @@ class VideoResourceUpdater
explicit VideoResourceUpdater(ResourceProvider* resource_provider);
~VideoResourceUpdater();

VideoFrameExternalResources CreateForHardwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame);

VideoFrameExternalResources CreateForSoftwarePlanes(
VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
const scoped_refptr<media::VideoFrame>& video_frame);

private:
Expand All @@ -92,6 +85,10 @@ class VideoResourceUpdater

void DeleteResource(unsigned resource_id);
bool VerifyFrame(const scoped_refptr<media::VideoFrame>& video_frame);
VideoFrameExternalResources CreateForHardwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame);
VideoFrameExternalResources CreateForSoftwarePlanes(
const scoped_refptr<media::VideoFrame>& video_frame);

struct RecycleResourceData {
unsigned resource_id;
Expand All @@ -103,10 +100,6 @@ class VideoResourceUpdater
RecycleResourceData data,
unsigned sync_point,
bool lost_resource);
static void ReturnTexture(base::WeakPtr<VideoResourceUpdater> updater,
unsigned resource_id,
unsigned sync_point,
bool lost_resource);

ResourceProvider* resource_provider_;
scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
Expand Down
45 changes: 26 additions & 19 deletions cc/trees/layer_tree_host_unittest_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1141,23 +1141,19 @@ class LayerTreeHostContextTestDontUseLostResources
video_color_->SetIsDrawable(true);
root_->AddChild(video_color_);

if (!delegating_renderer()) {
// TODO(danakj): Hardware video decode can not be transported.
// crbug.com/179729
scoped_refptr<VideoLayer> video_hw_ = VideoLayer::Create(
&hw_frame_provider_);
video_hw_->SetBounds(gfx::Size(10, 10));
video_hw_->SetAnchorPoint(gfx::PointF());
video_hw_->SetIsDrawable(true);
root_->AddChild(video_hw_);

scoped_refptr<VideoLayer> video_scaled_hw_ = VideoLayer::Create(
&scaled_hw_frame_provider_);
video_scaled_hw_->SetBounds(gfx::Size(10, 10));
video_scaled_hw_->SetAnchorPoint(gfx::PointF());
video_scaled_hw_->SetIsDrawable(true);
root_->AddChild(video_scaled_hw_);
}
scoped_refptr<VideoLayer> video_hw_ = VideoLayer::Create(
&hw_frame_provider_);
video_hw_->SetBounds(gfx::Size(10, 10));
video_hw_->SetAnchorPoint(gfx::PointF());
video_hw_->SetIsDrawable(true);
root_->AddChild(video_hw_);

scoped_refptr<VideoLayer> video_scaled_hw_ = VideoLayer::Create(
&scaled_hw_frame_provider_);
video_scaled_hw_->SetBounds(gfx::Size(10, 10));
video_scaled_hw_->SetAnchorPoint(gfx::PointF());
video_scaled_hw_->SetIsDrawable(true);
root_->AddChild(video_scaled_hw_);

if (!delegating_renderer()) {
// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
Expand Down Expand Up @@ -1240,17 +1236,28 @@ class LayerTreeHostContextTestDontUseLostResources
ResourceProvider::TextureUsageAny);
ResourceProvider::ScopedWriteLockGL lock(resource_provider, texture);

gpu::Mailbox mailbox;
resource_provider->GraphicsContext3D()->genMailboxCHROMIUM(mailbox.name);
unsigned sync_point =
resource_provider->GraphicsContext3D()->insertSyncPoint();

color_video_frame_ = VideoFrame::CreateColorFrame(
gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
hw_video_frame_ = VideoFrame::WrapNativeTexture(
lock.texture_id(),
new VideoFrame::MailboxHolder(
mailbox,
sync_point,
VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
GL_TEXTURE_2D,
gfx::Size(4, 4), gfx::Rect(0, 0, 4, 4), gfx::Size(4, 4),
base::TimeDelta(),
VideoFrame::ReadPixelsCB(),
base::Closure());
scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
lock.texture_id(),
new VideoFrame::MailboxHolder(
mailbox,
sync_point,
VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
GL_TEXTURE_2D,
gfx::Size(4, 4), gfx::Rect(0, 0, 3, 2), gfx::Size(4, 4),
base::TimeDelta(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class SurfaceRefAndroid : public GpuSurfaceTracker::SurfaceRef {
SurfaceTextureTransportClient::SurfaceTextureTransportClient()
: window_(NULL),
texture_id_(0),
texture_mailbox_sync_point_(0),
surface_id_(0),
weak_factory_(this) {
}
Expand Down Expand Up @@ -104,11 +105,20 @@ scoped_refptr<media::VideoFrame> SurfaceTextureTransportClient::
context->bindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
context->flush();
surface_texture_->AttachToGLContext();

context->genMailboxCHROMIUM(texture_mailbox_.name);
context->produceTextureCHROMIUM(kGLTextureExternalOES,
texture_mailbox_.name);
texture_mailbox_sync_point_ = context->insertSyncPoint();
}
if (!video_frame_.get()) {
const gfx::Size size = video_layer_->bounds();
video_frame_ = media::VideoFrame::WrapNativeTexture(
texture_id_, kGLTextureExternalOES,
new media::VideoFrame::MailboxHolder(
texture_mailbox_,
texture_mailbox_sync_point_,
media::VideoFrame::MailboxHolder::TextureNoLongerNeededCallback()),
kGLTextureExternalOES,
size,
gfx::Rect(gfx::Point(), size),
size,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "cc/layers/video_frame_provider.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"

Expand Down Expand Up @@ -48,6 +49,8 @@ class SurfaceTextureTransportClient : public cc::VideoFrameProvider {
ANativeWindow* window_;
scoped_refptr<media::VideoFrame> video_frame_;
uint32 texture_id_;
gpu::Mailbox texture_mailbox_;
uint32 texture_mailbox_sync_point_;
int surface_id_;
base::WeakPtrFactory<SurfaceTextureTransportClient> weak_factory_;

Expand Down
Loading

0 comments on commit e56f88c

Please sign in to comment.