Index: media/filters/skcanvas_video_renderer.cc |
diff --git a/media/filters/skcanvas_video_renderer.cc b/media/filters/skcanvas_video_renderer.cc |
index 003c1951a9b4010e93e612a347d645b22aa3f66a..3cdf25ac61b7a8d2248abfd49d9984187af627dd 100644 |
--- a/media/filters/skcanvas_video_renderer.cc |
+++ b/media/filters/skcanvas_video_renderer.cc |
@@ -7,8 +7,11 @@ |
#include "base/logging.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/gpu/SkGr.h" |
+#include "third_party/skia/src/gpu/effects/GrYUVtoRGBEffect.h" |
#include "ui/gfx/skbitmap_operations.h" |
// Skia internal format depends on a platform. On Android it is ABGR, on others |
@@ -181,7 +184,8 @@ static void ConvertVideoFrameToBitmap( |
} |
SkCanvasVideoRenderer::SkCanvasVideoRenderer() |
- : last_frame_timestamp_(media::kNoTimestamp()) { |
+ : last_frame_timestamp_(media::kNoTimestamp()), |
+ yuv_planes_timestamp_(media::kNoTimestamp()) { |
} |
SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |
@@ -209,6 +213,15 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, |
return; |
} |
+ // If we have a hardware accelerated canvas, we can try to do YUV conversion |
+ // directly from our frame to the output canvas. |
+ if (canvas->getGrContext() && |
+ HardwarePaint( |
+ video_frame, canvas->getGrContext(), dest, mode, video_rotation)) { |
+ // If HardwarePaint() succeeded, then we're all done! |
+ return; |
+ } |
+ |
// Check if we should convert and update |last_frame_|. |
if (last_frame_.isNull() || |
video_frame->timestamp() != last_frame_timestamp_) { |
@@ -251,4 +264,92 @@ void SkCanvasVideoRenderer::Copy(media::VideoFrame* video_frame, |
media::VIDEO_ROTATION_0); |
} |
+bool SkCanvasVideoRenderer::HardwarePaint(media::VideoFrame* video_frame, |
+ GrContext* gr, |
+ const SkRect& dest_rect, |
+ SkXfermode::Mode mode, |
+ VideoRotation video_rotation) { |
+ if (!IsYUV(video_frame->format()) || |
+ video_frame->format() == VideoFrame::YV12A) |
+ return false; |
+ |
+ DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
+ video_frame->stride(media::VideoFrame::kVPlane)); |
+ |
+ // Wrap our planes in SkBitmaps. |
+ if (video_frame->timestamp() != yuv_planes_timestamp_) { |
+ yuv_planes_[0].installPixels( |
+ SkImageInfo::MakeA8(video_frame->coded_size().width(), |
+ video_frame->coded_size().height()), |
+ video_frame->data(VideoFrame::kYPlane), |
+ video_frame->stride(VideoFrame::kYPlane)); |
+ yuv_planes_[1].installPixels( |
+ SkImageInfo::MakeA8(video_frame->coded_size().width() / 2, |
+ video_frame->coded_size().height() / 2), |
+ video_frame->data(VideoFrame::kUPlane), |
+ video_frame->stride(VideoFrame::kUPlane)); |
+ yuv_planes_[2].installPixels( |
+ SkImageInfo::MakeA8(video_frame->coded_size().width() / 2, |
+ video_frame->coded_size().height() / 2), |
+ video_frame->data(VideoFrame::kVPlane), |
+ video_frame->stride(VideoFrame::kVPlane)); |
+ } |
+ |
+ // Populate GrTextures from the bitmaps. We let Ganesh handle caching here. |
+ GrTexture* planes[3]; |
+ planes[0] = GrLockAndRefCachedBitmapTexture(gr, yuv_planes_[0], NULL); |
+ planes[1] = GrLockAndRefCachedBitmapTexture(gr, yuv_planes_[1], NULL); |
+ planes[2] = GrLockAndRefCachedBitmapTexture(gr, yuv_planes_[2], NULL); |
+ |
+ skia::RefPtr<GrEffect> effect = skia::AdoptRef<GrEffect>( |
+ GrYUVtoRGBEffect::Create(planes[0], planes[1], planes[2])); |
+ |
+ if (!effect) |
+ return false; |
+ |
+ SkXfermode::Coeff src, dest; |
+ if (!SkXfermode::ModeAsCoeff(mode, &src, &dest)) |
+ return false; |
+ |
+ GrPaint paint; |
+ paint.addColorEffect(effect.get()); |
+ paint.setBlendFunc(sk_blend_to_grblend(src), sk_blend_to_grblend(dest)); |
+ |
+ GrContext::AutoMatrix auto_matrix; |
+ auto_matrix.setIdentity(gr, &paint); |
+ SkMatrix rotation; |
+ |
+ switch (video_rotation) { |
+ case VIDEO_ROTATION_0: |
+ rotation.reset(); |
+ break; |
+ case VIDEO_ROTATION_90: |
+ rotation.setRotate(90); |
+ rotation.postTranslate(video_frame->coded_size().height(), 0); |
+ break; |
+ case VIDEO_ROTATION_180: |
+ rotation.setRotate(180); |
+ rotation.postTranslate(video_frame->coded_size().width(), |
+ video_frame->coded_size().height()); |
+ break; |
+ case VIDEO_ROTATION_270: |
+ rotation.setRotate(270); |
+ rotation.postTranslate(0, video_frame->coded_size().width()); |
+ break; |
+ } |
+ |
+ gr->concatMatrix(rotation); |
+ gr->drawRect(paint, dest_rect); |
+ |
+ GrUnlockAndUnrefCachedBitmapTexture(planes[0]); |
+ GrUnlockAndUnrefCachedBitmapTexture(planes[1]); |
+ GrUnlockAndUnrefCachedBitmapTexture(planes[2]); |
+ |
+ gr->flush(); |
+ |
+ yuv_planes_timestamp_ = video_frame->timestamp(); |
+ |
+ return true; |
+} |
+ |
} // namespace media |