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

Unified Diff: media/filters/skcanvas_video_renderer.cc

Issue 445013002: media: Optimize HW Video to 2D Canvas copy. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Resolve comments, rebase to ToT Created 6 years, 2 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
Index: media/filters/skcanvas_video_renderer.cc
diff --git a/media/filters/skcanvas_video_renderer.cc b/media/filters/skcanvas_video_renderer.cc
index 2243445d459e903f6d230604a757f6c36cc4c0cb..993b8587f0877cd85d660dd1627db2283dfd1347 100644
--- a/media/filters/skcanvas_video_renderer.cc
+++ b/media/filters/skcanvas_video_renderer.cc
@@ -5,12 +5,16 @@
#include "media/filters/skcanvas_video_renderer.h"
#include "base/logging.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/video_frame.h"
#include "media/base/yuv_convert.h"
+#include "skia/ext/refptr.h"
#include "third_party/libyuv/include/libyuv.h"
-#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImageGenerator.h"
#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/SkGrPixelRef.h"
#include "ui/gfx/skbitmap_operations.h"
// Skia internal format depends on a platform. On Android it is ABGR, on others
@@ -214,6 +218,86 @@ void ConvertVideoFrameToRGBPixels(
}
}
+bool IsSkBitmapProperlySizedTexture(const SkBitmap* bitmap,
+ const gfx::Size& size) {
+ return bitmap->getTexture() && bitmap->width() == size.width() &&
+ bitmap->height() == size.height();
+}
+
+bool AllocateSkBitmapTexture(GrContext* gr,
+ SkBitmap* bitmap,
+ const gfx::Size& size) {
+ DCHECK(gr);
+ GrTextureDesc desc;
+ // Use kRGBA_8888_GrPixelConfig, not kSkia8888_GrPixelConfig, because
+ // glCopyTextureChromium doesn't support GL_BGRA_EXT as internal format.
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
+ desc.fSampleCnt = 0;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fWidth = size.width();
+ desc.fHeight = size.height();
+ skia::RefPtr<GrTexture> texture = skia::AdoptRef(
+ gr->refScratchTexture(desc, GrContext::kExact_ScratchTexMatch));
+ if (!texture.get())
+ return false;
+
+ SkImageInfo info = SkImageInfo::MakeN32Premul(desc.fWidth, desc.fHeight);
+ SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, texture.get()));
scherkus (not reviewing) 2014/10/30 20:40:12 pixelRef -> pixel_ref
dshwang 2014/10/31 09:29:17 oops, Thank you.
+ if (!pixelRef)
+ return false;
+ bitmap->setInfo(info);
+ bitmap->setPixelRef(pixelRef)->unref();
+ return true;
+}
+
+bool CopyVideoFrameTextureToSkBitmapTexture(
+ VideoFrame* video_frame,
scherkus (not reviewing) 2014/10/30 20:40:13 const scoped_refptr<VideoFrame>&
dshwang 2014/10/31 09:29:17 not needed because it doesn't take a ref
+ SkBitmap* bitmap,
+ const Context3DProvider& context_provider) {
+ // Check if we could reuse existing texture based bitmap.
+ // Otherwise, release existing texture based bitmap and allocate
+ // a new one based on video size.
+ if (!IsSkBitmapProperlySizedTexture(bitmap,
+ video_frame->visible_rect().size())) {
+ if (!AllocateSkBitmapTexture(context_provider.gr_context,
+ bitmap,
+ video_frame->visible_rect().size())) {
+ return false;
+ }
+ }
+
+ unsigned texture_id =
+ static_cast<unsigned>((bitmap->getTexture())->getTextureHandle());
+ // If CopyVideoFrameToTexture() changes the state of the |texture_id|, it's
scherkus (not reviewing) 2014/10/30 20:40:12 "CopyVideoFrameToTexture" doesn't refer to a funct
dshwang 2014/10/31 09:29:17 Thank you!
+ // needed to invalidate the state cached in skia, but currently the state
+ // isn't changed.
+ SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(context_provider.gl,
+ video_frame,
+ texture_id,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true,
+ false);
+ return true;
+}
+
+class SyncPointClientImpl : public VideoFrame::SyncPointClient {
+ public:
+ explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
+ virtual ~SyncPointClientImpl() {}
scherkus (not reviewing) 2014/10/30 20:40:12 s/virtual/override/ everywhere
dshwang 2014/10/31 09:29:17 interesting. Done.
+ virtual uint32 InsertSyncPoint() override {
+ return gl_->InsertSyncPointCHROMIUM();
+ }
+ virtual void WaitSyncPoint(uint32 sync_point) override {
+ gl_->WaitSyncPointCHROMIUM(sync_point);
+ }
+
+ private:
+ gpu::gles2::GLES2Interface* gl_;
+};
scherkus (not reviewing) 2014/10/30 20:40:12 DISALLOW_COPY_AND_ASSIGN()
dshwang 2014/10/31 09:29:17 Done.
+
} // anonymous namespace
// Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
@@ -306,7 +390,7 @@ SkCanvasVideoRenderer::SkCanvasVideoRenderer()
base::TimeDelta::FromSeconds(kTemporaryResourceDeletionDelay),
this,
&SkCanvasVideoRenderer::ResetLastFrame),
- accelerated_generator_(NULL),
+ accelerated_generator_(nullptr),
accelerated_last_frame_timestamp_(media::kNoTimestamp()),
accelerated_frame_deleting_timer_(
FROM_HERE,
@@ -323,7 +407,8 @@ void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
const gfx::RectF& dest_rect,
uint8 alpha,
SkXfermode::Mode mode,
- VideoRotation video_rotation) {
+ VideoRotation video_rotation,
+ const Context3DProvider& context_provider) {
if (alpha == 0) {
return;
}
@@ -343,16 +428,36 @@ void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
return;
}
- SkBitmap* target_frame = NULL;
+ SkBitmap* target_frame = nullptr;
if (canvas->getGrContext()) {
+ // TODO(dshwang): Android video decoder doesn't update the timestamp on a
+ // VideoFrame. To reduce redundant copy, Android should update the
+ // timestamp.
if (accelerated_last_frame_.isNull() ||
+#if defined(OS_ANDROID)
+ video_frame->timestamp() == base::TimeDelta() ||
+#endif
video_frame->timestamp() != accelerated_last_frame_timestamp_) {
- accelerated_generator_ = new VideoImageGenerator(video_frame);
-
- // Note: This takes ownership of |accelerated_generator_|.
- if (!SkInstallDiscardablePixelRef(accelerated_generator_,
- &accelerated_last_frame_)) {
- NOTREACHED();
+ if (video_frame->format() == media::VideoFrame::NATIVE_TEXTURE) {
+ // Draw HW Video on HW Canvas.
+ DCHECK(context_provider.gl && context_provider.gr_context);
scherkus (not reviewing) 2014/10/30 20:40:13 nit: break out into two DCHECKs so we know which o
dshwang 2014/10/31 09:29:17 Done.
+ DCHECK(!accelerated_generator_);
+ if (!CopyVideoFrameTextureToSkBitmapTexture(video_frame.get(),
scherkus (not reviewing) 2014/10/30 20:40:13 you can drop the .get() if you switch to using con
dshwang 2014/10/31 09:29:17 CopyVideoFrameTextureToSkBitmapTexture doesn't tak
+ &accelerated_last_frame_,
+ context_provider)) {
+ NOTREACHED();
+ return;
+ }
+ } else {
+ // Draw SW Video on HW Canvas.
+ accelerated_generator_ = new VideoImageGenerator(video_frame);
+
+ // Note: This takes ownership of |accelerated_generator_|.
+ if (!SkInstallDiscardablePixelRef(accelerated_generator_,
+ &accelerated_last_frame_)) {
+ NOTREACHED();
+ return;
+ }
}
DCHECK(video_frame->visible_rect().width() ==
accelerated_last_frame_.width() &&
@@ -360,13 +465,13 @@ void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
accelerated_last_frame_.height());
accelerated_last_frame_timestamp_ = video_frame->timestamp();
- } else {
+ } else if (accelerated_generator_) {
accelerated_generator_->set_frame(video_frame);
}
target_frame = &accelerated_last_frame_;
accelerated_frame_deleting_timer_.Reset();
} else {
- // Check if we should convert and update |last_frame_|.
+ // Draw both SW and HW Video on SW Canvas.
if (last_frame_.isNull() ||
video_frame->timestamp() != last_frame_timestamp_) {
// Check if |bitmap| needs to be (re)allocated.
@@ -434,8 +539,8 @@ void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
canvas->flush();
// SkCanvas::flush() causes the generator to generate SkImage, so delete
// |video_frame| not to be outlived.
- if (canvas->getGrContext())
- accelerated_generator_->set_frame(NULL);
+ if (canvas->getGrContext() && accelerated_generator_)
+ accelerated_generator_->set_frame(nullptr);
}
void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
@@ -445,7 +550,47 @@ void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
video_frame->visible_rect(),
0xff,
SkXfermode::kSrc_Mode,
- media::VIDEO_ROTATION_0);
+ media::VIDEO_ROTATION_0,
+ media::Context3DProvider());
+}
+
+// static
+void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture(
+ gpu::gles2::GLES2Interface* gl,
+ VideoFrame* video_frame,
+ unsigned int texture,
+ unsigned int level,
+ unsigned int internal_format,
+ unsigned int type,
+ bool premultiply_alpha,
+ bool flip_y) {
+ DCHECK(video_frame && video_frame->format() == VideoFrame::NATIVE_TEXTURE);
+ const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
+ DCHECK(mailbox_holder->texture_target == GL_TEXTURE_2D ||
+ mailbox_holder->texture_target == GL_TEXTURE_EXTERNAL_OES);
+
+ gl->WaitSyncPointCHROMIUM(mailbox_holder->sync_point);
+ uint32 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
+ mailbox_holder->texture_target, mailbox_holder->mailbox.name);
+
+ // The video is stored in a unmultiplied format, so premultiply
+ // if necessary.
+ gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, premultiply_alpha);
+ // Application itself needs to take care of setting the right |flip_y|
+ // value down to get the expected result.
+ // "flip_y == true" means to reverse the video orientation while
+ // "flip_y == false" means to keep the intrinsic orientation.
+ gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
+ gl->CopyTextureCHROMIUM(
+ GL_TEXTURE_2D, source_texture, texture, level, internal_format, type);
+ gl->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, false);
+ gl->PixelStorei(GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false);
+
+ gl->DeleteTextures(1, &source_texture);
+ gl->Flush();
+
+ SyncPointClientImpl client(gl);
+ video_frame->UpdateReleaseSyncPoint(&client);
}
void SkCanvasVideoRenderer::ResetLastFrame() {

Powered by Google App Engine
This is Rietveld 408576698