Chromium Code Reviews| Index: media/blink/skcanvas_video_renderer.cc |
| diff --git a/media/blink/skcanvas_video_renderer.cc b/media/blink/skcanvas_video_renderer.cc |
| index 2d3a416b3fd80fa4dc4d69e73ad2fd833e0cb9d2..f34daf041cc3dcd6faf94f495d4afde702f61a7e 100644 |
| --- a/media/blink/skcanvas_video_renderer.cc |
| +++ b/media/blink/skcanvas_video_renderer.cc |
| @@ -12,9 +12,13 @@ |
| #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/SkImage.h" |
| #include "third_party/skia/include/core/SkImageGenerator.h" |
| #include "third_party/skia/include/gpu/GrContext.h" |
| +#include "third_party/skia/include/gpu/GrPaint.h" |
| +#include "third_party/skia/include/gpu/GrTexture.h" |
| #include "third_party/skia/include/gpu/GrTextureProvider.h" |
| +#include "third_party/skia/include/gpu/SkGr.h" |
| #include "third_party/skia/include/gpu/SkGrPixelRef.h" |
| #include "ui/gfx/skbitmap_operations.h" |
| @@ -84,9 +88,68 @@ bool AllocateSkBitmapTexture(GrContext* gr, |
| return true; |
| } |
| -bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame, |
| - SkBitmap* bitmap, |
| - const Context3D& context_3d) { |
| +class SyncPointClientImpl : public VideoFrame::SyncPointClient { |
| + public: |
| + explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} |
| + ~SyncPointClientImpl() override {} |
| + uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } |
| + void WaitSyncPoint(uint32 sync_point) override { |
| + gl_->WaitSyncPointCHROMIUM(sync_point); |
| + } |
| + |
| + private: |
| + gpu::gles2::GLES2Interface* gl_; |
| + |
| + DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); |
| +}; |
| + |
| +scoped_ptr<SkImage> CreateSkImageFromVideoFrameNativeTextures( |
| + VideoFrame* video_frame, |
| + const Context3D& context_3d) { |
| + // Support only TEXTURE_YUV_420. |
| + DCHECK(video_frame->storage_type() == VideoFrame::STORAGE_TEXTURE); |
| + DCHECK_EQ(media::VideoFrame::I420, video_frame->format()); |
| + DCHECK_EQ(3u, media::VideoFrame::NumPlanes(video_frame->format())); |
| + |
| + gpu::gles2::GLES2Interface* gl = context_3d.gl; |
| + DCHECK(gl); |
| + gfx::Size ya_tex_size = video_frame->coded_size(); |
| + gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2, |
| + (ya_tex_size.height() + 1) / 2); |
| + |
| + unsigned source_textures[3] = {0}; |
| + for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format()); |
| + ++i) { |
| + // Get the texture from the mailbox and wrap it in a GrTexture. |
| + const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(i); |
| + DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || |
| + mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES || |
| + mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB); |
| + gl->WaitSyncPointCHROMIUM(mailbox_holder.sync_point); |
| + source_textures[i] = gl->CreateAndConsumeTextureCHROMIUM( |
| + mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
| + } |
| + GrBackendObject handles[3] = { |
| + source_textures[0], source_textures[1], source_textures[2]}; |
| + |
| + SkISize yuvSizes[] = { |
| + {ya_tex_size.width(), ya_tex_size.height()}, |
| + {uv_tex_size.width(), uv_tex_size.height()}, |
| + {uv_tex_size.width(), uv_tex_size.height()}, |
| + }; |
| + SkImage* img = SkImage::NewFromYUVTexturesCopy( |
| + context_3d.gr_context, kRec601_SkYUVColorSpace, handles, yuvSizes, |
| + kTopLeft_GrSurfaceOrigin); |
| + DCHECK(img); |
| + gl->DeleteTextures(3, source_textures); |
| + SyncPointClientImpl client(gl); |
| + video_frame->UpdateReleaseSyncPoint(&client); |
| + return make_scoped_ptr(img); |
| +} |
| + |
| +bool CopyVideoFrameSingleTextureToSkBitmap(VideoFrame* video_frame, |
| + SkBitmap* bitmap, |
| + const Context3D& context_3d) { |
| // Check if we could reuse existing texture based bitmap. |
| // Otherwise, release existing texture based bitmap and allocate |
| // a new one based on video size. |
| @@ -100,31 +163,17 @@ bool CopyVideoFrameTextureToSkBitmapTexture(VideoFrame* video_frame, |
| unsigned texture_id = |
| static_cast<unsigned>((bitmap->getTexture())->getTextureHandle()); |
| - // If CopyVideoFrameTextureToGLTexture() changes the state of the |
| + // If CopyVideoFrameSingleTextureToGLTexture() changes the state of the |
| // |texture_id|, it's needed to invalidate the state cached in skia, |
| // but currently the state isn't changed. |
| - SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( |
| + |
| + SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| context_3d.gl, video_frame, texture_id, GL_RGBA, GL_UNSIGNED_BYTE, true, |
| false); |
| bitmap->notifyPixelsChanged(); |
| return true; |
| } |
| -class SyncPointClientImpl : public VideoFrame::SyncPointClient { |
| - public: |
| - explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {} |
| - ~SyncPointClientImpl() override {} |
| - uint32 InsertSyncPoint() override { return gl_->InsertSyncPointCHROMIUM(); } |
| - void WaitSyncPoint(uint32 sync_point) override { |
| - gl_->WaitSyncPointCHROMIUM(sync_point); |
| - } |
| - |
| - private: |
| - gpu::gles2::GLES2Interface* gl_; |
| - |
| - DISALLOW_IMPLICIT_CONSTRUCTORS(SyncPointClientImpl); |
| -}; |
| - |
| } // anonymous namespace |
| // Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU. |
| @@ -290,16 +339,23 @@ void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, |
| accelerated_last_frame_.reset(); |
| accelerated_generator_ = nullptr; |
| } |
| - if (!CopyVideoFrameTextureToSkBitmapTexture( |
| - video_frame.get(), &accelerated_last_frame_, context_3d)) { |
| - NOTREACHED(); |
| - return; |
| - } |
| - DCHECK(video_frame->visible_rect().width() == |
| - accelerated_last_frame_.width() && |
| - video_frame->visible_rect().height() == |
| - accelerated_last_frame_.height()); |
| + if (media::VideoFrame::NumPlanes(video_frame->format()) == 1) { |
| + accelerated_last_image_.reset(); |
| + if (!CopyVideoFrameSingleTextureToSkBitmap( |
| + video_frame.get(), &accelerated_last_frame_, context_3d)) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + DCHECK(video_frame->visible_rect().width() == |
| + accelerated_last_frame_.width() && |
| + video_frame->visible_rect().height() == |
| + accelerated_last_frame_.height()); |
| + } else { |
| + accelerated_last_image_ = CreateSkImageFromVideoFrameNativeTextures( |
|
dshwang
2015/06/10 17:38:37
I'm not good at naming but I think the function na
Daniele Castagna
2015/06/10 17:42:34
How do you like CreateSkImageFromVideoFrameYUVText
dshwang
2015/06/10 17:45:05
I buy it :)
Daniele Castagna
2015/06/10 18:02:27
Done.
|
| + video_frame.get(), context_3d); |
| + DCHECK(accelerated_last_image_); |
| + } |
| accelerated_last_frame_timestamp_ = video_frame->timestamp(); |
| } |
| target_frame = &accelerated_last_frame_; |
| @@ -395,7 +451,11 @@ void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, |
| canvas->translate(-SkFloatToScalar(target_frame->width() * 0.5f), |
| -SkFloatToScalar(target_frame->height() * 0.5f)); |
| } |
| - canvas->drawBitmap(*target_frame, 0, 0, &paint); |
| + if (accelerated_last_image_) { |
| + canvas->drawImage(accelerated_last_image_.get(), 0, 0, &paint); |
| + } else { |
| + canvas->drawBitmap(*target_frame, 0, 0, &paint); |
| + } |
| if (need_transform) |
| canvas->restore(); |
| canvas->flush(); |
| @@ -548,7 +608,7 @@ void SkCanvasVideoRenderer::ConvertVideoFrameToRGBPixels( |
| } |
| // static |
| -void SkCanvasVideoRenderer::CopyVideoFrameTextureToGLTexture( |
| +void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( |
| gpu::gles2::GLES2Interface* gl, |
| VideoFrame* video_frame, |
| unsigned int texture, |
| @@ -595,6 +655,7 @@ void SkCanvasVideoRenderer::ResetLastFrame() { |
| } |
| void SkCanvasVideoRenderer::ResetAcceleratedLastFrame() { |
| + accelerated_last_image_.reset(); |
| accelerated_last_frame_.reset(); |
| accelerated_generator_ = nullptr; |
| accelerated_last_frame_timestamp_ = media::kNoTimestamp(); |