| 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
|
|
|