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

Unified Diff: cc/resources/video_resource_updater.cc

Issue 13445009: cc: Move video upload to VideoResourceUpdater. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: consume textures that were produced Created 7 years, 8 months 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
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | cc/test/render_pass_test_common.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/resources/video_resource_updater.cc
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ca2d3bb9d7c211ef818b9bed2bb25e8613107212
--- /dev/null
+++ b/cc/resources/video_resource_updater.cc
@@ -0,0 +1,326 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/video_resource_updater.h"
+
+#include "base/bind.h"
+#include "cc/output/gl_renderer.h"
+#include "cc/resources/resource_provider.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "media/base/video_frame.h"
+#include "media/filters/skcanvas_video_renderer.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/size_conversions.h"
+
+const unsigned kYUVResourceFormat = GL_LUMINANCE;
+const unsigned kRGBResourceFormat = GL_RGBA;
+
+namespace cc {
+
+VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}
+
+VideoFrameExternalResources::~VideoFrameExternalResources() {}
+
+VideoResourceUpdater::VideoResourceUpdater(ResourceProvider* resource_provider)
+ : resource_provider_(resource_provider) {
+}
+
+VideoResourceUpdater::~VideoResourceUpdater() {}
+
+bool VideoResourceUpdater::VerifyFrame(
+ const scoped_refptr<media::VideoFrame>& video_frame) {
+ // If these fail, we'll have to add logic that handles offset bitmap/texture
+ // UVs. For now, just expect (0, 0) offset, since all our decoders so far
+ // don't offset.
+ DCHECK_EQ(video_frame->visible_rect().x(), 0);
+ DCHECK_EQ(video_frame->visible_rect().y(), 0);
+
+ switch (video_frame->format()) {
+ // Acceptable inputs.
+ case media::VideoFrame::YV12:
+ case media::VideoFrame::YV16:
+ case media::VideoFrame::NATIVE_TEXTURE:
+#if defined(GOOGLE_TV)
+ case media::VideoFrame::HOLE:
+#endif
+ return true;
+
+ // Unacceptable inputs. ¯\(°_o)/¯
+ case media::VideoFrame::INVALID:
+ case media::VideoFrame::RGB32:
+ case media::VideoFrame::EMPTY:
+ case media::VideoFrame::I420:
+ break;
+ }
+ return false;
+}
+
+// For frames that we receive in software format, determine the dimensions of
+// each plane in the frame.
+static gfx::Size SoftwarePlaneDimension(
+ media::VideoFrame::Format input_frame_format,
+ gfx::Size coded_size,
+ GLenum output_resource_format,
+ int plane_index) {
+ if (output_resource_format == kYUVResourceFormat) {
+ if (plane_index == media::VideoFrame::kYPlane)
+ return coded_size;
+
+ switch (input_frame_format) {
+ case media::VideoFrame::YV12:
+ return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 0.5f));
+ case media::VideoFrame::YV16:
+ return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 1.f));
+
+ case media::VideoFrame::INVALID:
+ case media::VideoFrame::RGB32:
+ case media::VideoFrame::EMPTY:
+ case media::VideoFrame::I420:
+ case media::VideoFrame::NATIVE_TEXTURE:
+#if defined(GOOGLE_TV)
+ case media::VideoFrame::HOLE:
+#endif
+ NOTREACHED();
+ }
+ }
+
+ DCHECK_EQ(output_resource_format, static_cast<unsigned>(kRGBResourceFormat));
+ return coded_size;
+}
+
+static void ReleaseResource(ResourceProvider* resource_provider,
+ ResourceProvider::ResourceId resource_id,
+ unsigned sync_point) {
+ resource_provider->DeleteResource(resource_id);
+}
+
+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)
+ if (input_frame_format == media::VideoFrame::HOLE) {
+ VideoFrameExternalResources external_resources;
+ external_resources.type = VideoFrameExternalResources::HOLE;
+ return external_resources;
+ }
+#endif
+
+ // Only YUV software video frames are supported.
+ DCHECK(input_frame_format == media::VideoFrame::YV12 ||
+ input_frame_format == media::VideoFrame::YV16);
+ if (input_frame_format != media::VideoFrame::YV12 &&
+ input_frame_format != media::VideoFrame::YV16)
+ return VideoFrameExternalResources();
+
+ bool software_compositor = !resource_provider_->GraphicsContext3D();
+
+ GLenum output_resource_format = kYUVResourceFormat;
+ size_t output_plane_count = 3;
+
+ // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
+ // conversion here. That involves an extra copy of each frame to a bitmap.
+ // Obviously, this is suboptimal and should be addressed once ubercompositor
+ // starts shaping up.
+ if (software_compositor) {
+ output_resource_format = kRGBResourceFormat;
+ output_plane_count = 1;
+ }
+
+ int max_resource_size = resource_provider_->max_texture_size();
+ gfx::Size coded_frame_size = video_frame->coded_size();
+
+ ResourceProvider::ResourceIdArray plane_resources;
+ bool allocation_success = true;
+
+ for (size_t i = 0; i < output_plane_count; ++i) {
+ gfx::Size plane_size =
+ SoftwarePlaneDimension(input_frame_format,
+ coded_frame_size,
+ output_resource_format,
+ i);
+ if (plane_size.IsEmpty() ||
+ plane_size.width() > max_resource_size ||
+ plane_size.height() > max_resource_size) {
+ allocation_success = false;
+ break;
+ }
+
+ // TODO(danakj): Could recycle resources that we previously allocated and
+ // were returned to us.
+ ResourceProvider::ResourceId resource_id =
+ resource_provider_->CreateResource(plane_size,
+ output_resource_format,
+ ResourceProvider::TextureUsageAny);
+ if (resource_id == 0) {
+ allocation_success = false;
+ break;
+ }
+
+ plane_resources.push_back(resource_id);
+ }
+
+ if (!allocation_success) {
+ for (size_t i = 0; i < plane_resources.size(); ++i)
+ resource_provider_->DeleteResource(plane_resources[i]);
+ return VideoFrameExternalResources();
+ }
+
+ VideoFrameExternalResources external_resources;
+
+ if (software_compositor) {
+ DCHECK_EQ(output_resource_format, kRGBResourceFormat);
+ DCHECK_EQ(plane_resources.size(), 1u);
+
+ if (!video_renderer_)
+ video_renderer_.reset(new media::SkCanvasVideoRenderer);
+
+ {
+ ResourceProvider::ScopedWriteLockSoftware lock(
+ resource_provider_, plane_resources[0]);
+ video_renderer_->Paint(video_frame,
+ lock.sk_canvas(),
+ video_frame->visible_rect(),
+ 0xff);
+ }
+
+ // In software mode, the resource provider won't be lost. Soon this callback
+ // will be called directly from the resource provider, same as 3d
+ // compositing mode, so this raw unretained resource_provider will always
+ // be valid when the callback is fired.
+ TextureMailbox::ReleaseCallback callback_to_free_resource =
+ base::Bind(&ReleaseResource,
+ base::Unretained(resource_provider_),
+ plane_resources[0]);
+ external_resources.software_resources.push_back(plane_resources[0]);
+ external_resources.software_release_callback = callback_to_free_resource;
+
+ external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
+ return external_resources;
+ }
+
+ DCHECK_EQ(output_resource_format,
+ static_cast<unsigned>(kYUVResourceFormat));
+
+ WebKit::WebGraphicsContext3D* context =
+ resource_provider_->GraphicsContext3D();
+ DCHECK(context);
+
+ for (size_t plane = 0; plane < plane_resources.size(); ++plane) {
+ // Update each plane's resource id with its content.
+ ResourceProvider::ResourceId output_plane_resource_id =
+ plane_resources[plane];
+ gfx::Size plane_size =
+ SoftwarePlaneDimension(input_frame_format,
+ coded_frame_size,
+ output_resource_format,
+ plane);
+ const uint8_t* input_plane_pixels = video_frame->data(plane);
+
+ gfx::Rect image_rect(
+ 0, 0, video_frame->stride(plane), plane_size.height());
+ gfx::Rect source_rect(plane_size);
+ resource_provider_->SetPixels(output_plane_resource_id,
+ input_plane_pixels,
+ image_rect,
+ source_rect,
+ gfx::Vector2d());
+
+ gpu::Mailbox mailbox;
+ {
+ ResourceProvider::ScopedWriteLockGL lock(
+ resource_provider_, output_plane_resource_id);
+
+ GLC(context, context->genMailboxCHROMIUM(mailbox.name));
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, lock.texture_id()));
+ GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D,
+ mailbox.name));
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, 0));
+ }
+
+ // This callback is called by the resource provider itself, so it's okay to
+ // use an unretained raw pointer here.
+ TextureMailbox::ReleaseCallback callback_to_free_resource =
+ base::Bind(&ReleaseResource,
+ base::Unretained(resource_provider_),
+ output_plane_resource_id);
+ external_resources.mailboxes.push_back(
+ TextureMailbox(mailbox, callback_to_free_resource));
+ }
+
+ external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
+ return external_resources;
+}
+
+VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
+ const scoped_refptr<media::VideoFrame>& video_frame,
+ const TextureMailbox::ReleaseCallback& release_callback) {
+ if (!VerifyFrame(video_frame))
+ return VideoFrameExternalResources();
+
+ media::VideoFrame::Format frame_format = video_frame->format();
+
+ DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE);
+ if (frame_format != media::VideoFrame::NATIVE_TEXTURE)
+ return VideoFrameExternalResources();
+
+ WebKit::WebGraphicsContext3D* context =
+ resource_provider_->GraphicsContext3D();
+ if (!context)
+ return VideoFrameExternalResources();
+
+ VideoFrameExternalResources external_resources;
+ switch (video_frame->texture_target()) {
+ case GL_TEXTURE_2D:
+ external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ external_resources.type =
+ VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ external_resources.type = VideoFrameExternalResources::IO_SURFACE;
+ break;
+ default:
+ NOTREACHED();
+ return VideoFrameExternalResources();
+ }
+
+ gpu::Mailbox mailbox;
+ GLC(context, context->genMailboxCHROMIUM(mailbox.name));
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, video_frame->texture_id()));
+ GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, 0));
+
+ TextureMailbox::ReleaseCallback callback_to_return_resource =
+ base::Bind(&ReturnTexture,
+ base::Unretained(resource_provider_),
+ release_callback,
+ video_frame->texture_id(),
+ mailbox);
+ external_resources.mailboxes.push_back(
+ TextureMailbox(mailbox, callback_to_return_resource));
+ return external_resources;
+}
+
+// static
+void VideoResourceUpdater::ReturnTexture(
+ ResourceProvider* resource_provider,
+ TextureMailbox::ReleaseCallback callback,
+ unsigned texture_id,
+ gpu::Mailbox mailbox,
+ unsigned sync_point) {
+ WebKit::WebGraphicsContext3D* context =
+ resource_provider->GraphicsContext3D();
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, texture_id));
+ GLC(context, context->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
+ GLC(context, context->bindTexture(GL_TEXTURE_2D, 0));
+ callback.Run(sync_point);
+}
+
+} // namespace cc
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | cc/test/render_pass_test_common.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698