| 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..dc95dc6596fdf1ac1b04424e90b9ee0954c1342c 100644
|
| --- a/media/filters/skcanvas_video_renderer.cc
|
| +++ b/media/filters/skcanvas_video_renderer.cc
|
| @@ -9,6 +9,7 @@
|
| #include "media/base/yuv_convert.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 "ui/gfx/skbitmap_operations.h"
|
|
|
| // Skia internal format depends on a platform. On Android it is ABGR, on others
|
| @@ -40,12 +41,11 @@ static bool IsYUVOrNative(media::VideoFrame::Format format) {
|
| return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE;
|
| }
|
|
|
| -// Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data.
|
| -//
|
| -// |bitmap| will be (re)allocated to match the dimensions of |video_frame|.
|
| -static void ConvertVideoFrameToBitmap(
|
| +// Converts a |video_frame| to raw |rgb_pixels|.
|
| +static void ConvertVideoFrameToRGBPixels(
|
| const scoped_refptr<media::VideoFrame>& video_frame,
|
| - SkBitmap* bitmap) {
|
| + void* rgb_pixels,
|
| + size_t row_bytes) {
|
| DCHECK(IsYUVOrNative(video_frame->format()))
|
| << video_frame->format();
|
| if (IsYUV(video_frame->format())) {
|
| @@ -53,17 +53,6 @@ static void ConvertVideoFrameToBitmap(
|
| video_frame->stride(media::VideoFrame::kVPlane));
|
| }
|
|
|
| - // Check if |bitmap| needs to be (re)allocated.
|
| - if (bitmap->isNull() ||
|
| - bitmap->width() != video_frame->visible_rect().width() ||
|
| - bitmap->height() != video_frame->visible_rect().height()) {
|
| - bitmap->allocN32Pixels(video_frame->visible_rect().width(),
|
| - video_frame->visible_rect().height());
|
| - bitmap->setIsVolatile(true);
|
| - }
|
| -
|
| - bitmap->lockPixels();
|
| -
|
| size_t y_offset = 0;
|
| size_t uv_offset = 0;
|
| if (IsYUV(video_frame->format())) {
|
| @@ -90,8 +79,8 @@ static void ConvertVideoFrameToBitmap(
|
| video_frame->stride(media::VideoFrame::kUPlane),
|
| video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
|
| video_frame->stride(media::VideoFrame::kVPlane),
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| - bitmap->rowBytes(),
|
| + static_cast<uint8*>(rgb_pixels),
|
| + row_bytes,
|
| video_frame->visible_rect().width(),
|
| video_frame->visible_rect().height());
|
| break;
|
| @@ -101,12 +90,12 @@ static void ConvertVideoFrameToBitmap(
|
| video_frame->data(media::VideoFrame::kYPlane) + y_offset,
|
| video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
|
| video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| + static_cast<uint8*>(rgb_pixels),
|
| video_frame->visible_rect().width(),
|
| video_frame->visible_rect().height(),
|
| video_frame->stride(media::VideoFrame::kYPlane),
|
| video_frame->stride(media::VideoFrame::kUPlane),
|
| - bitmap->rowBytes(),
|
| + row_bytes,
|
| media::YV12J);
|
| break;
|
|
|
| @@ -118,8 +107,8 @@ static void ConvertVideoFrameToBitmap(
|
| video_frame->stride(media::VideoFrame::kUPlane),
|
| video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
|
| video_frame->stride(media::VideoFrame::kVPlane),
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| - bitmap->rowBytes(),
|
| + static_cast<uint8*>(rgb_pixels),
|
| + row_bytes,
|
| video_frame->visible_rect().width(),
|
| video_frame->visible_rect().height());
|
| break;
|
| @@ -133,13 +122,13 @@ static void ConvertVideoFrameToBitmap(
|
| video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
|
| video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
|
| video_frame->data(media::VideoFrame::kAPlane),
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| + static_cast<uint8*>(rgb_pixels),
|
| video_frame->visible_rect().width(),
|
| video_frame->visible_rect().height(),
|
| video_frame->stride(media::VideoFrame::kYPlane),
|
| video_frame->stride(media::VideoFrame::kUPlane),
|
| video_frame->stride(media::VideoFrame::kAPlane),
|
| - bitmap->rowBytes(),
|
| + row_bytes,
|
| media::YV12);
|
| break;
|
|
|
| @@ -151,42 +140,112 @@ static void ConvertVideoFrameToBitmap(
|
| video_frame->stride(media::VideoFrame::kUPlane),
|
| video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
|
| video_frame->stride(media::VideoFrame::kVPlane),
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| - bitmap->rowBytes(),
|
| + static_cast<uint8*>(rgb_pixels),
|
| + row_bytes,
|
| video_frame->visible_rect().width(),
|
| video_frame->visible_rect().height());
|
| #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
|
| SK_A32_SHIFT == 24
|
| - libyuv::ARGBToABGR(
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| - bitmap->rowBytes(),
|
| - static_cast<uint8*>(bitmap->getPixels()),
|
| - bitmap->rowBytes(),
|
| - video_frame->visible_rect().width(),
|
| - video_frame->visible_rect().height());
|
| + libyuv::ARGBToABGR(static_cast<uint8*>(rgb_pixels),
|
| + row_bytes,
|
| + static_cast<uint8*>(rgb_pixels),
|
| + row_bytes,
|
| + video_frame->visible_rect().width(),
|
| + video_frame->visible_rect().height());
|
| #endif
|
| break;
|
|
|
| - case media::VideoFrame::NATIVE_TEXTURE:
|
| + case media::VideoFrame::NATIVE_TEXTURE: {
|
| DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE);
|
| - video_frame->ReadPixelsFromNativeTexture(*bitmap);
|
| + SkBitmap tmp;
|
| + tmp.installPixels(
|
| + SkImageInfo::MakeN32Premul(video_frame->visible_rect().width(),
|
| + video_frame->visible_rect().height()),
|
| + rgb_pixels,
|
| + row_bytes);
|
| + video_frame->ReadPixelsFromNativeTexture(tmp);
|
| break;
|
| -
|
| + }
|
| default:
|
| NOTREACHED();
|
| break;
|
| }
|
| - bitmap->notifyPixelsChanged();
|
| - bitmap->unlockPixels();
|
| }
|
|
|
| +// Generates an RGB image from a VideoFrame.
|
| +class VideoImageGenerator : public SkImageGenerator {
|
| + public:
|
| + VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {}
|
| + virtual ~VideoImageGenerator() {}
|
| +
|
| + protected:
|
| + virtual bool onGetInfo(SkImageInfo* info) OVERRIDE {
|
| + info->fWidth = frame_->visible_rect().width();
|
| + info->fHeight = frame_->visible_rect().height();
|
| + info->fColorType = kN32_SkColorType;
|
| + info->fAlphaType = kPremul_SkAlphaType;
|
| + return true;
|
| + }
|
| +
|
| + virtual bool onGetPixels(const SkImageInfo& info,
|
| + void* pixels,
|
| + size_t row_bytes,
|
| + SkPMColor ctable[],
|
| + int* ctable_count) OVERRIDE {
|
| + if (!frame_.get())
|
| + return false;
|
| + if (!pixels)
|
| + return true;
|
| + // If skia couldn't do the YUV conversion, we will.
|
| + ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes);
|
| + frame_ = NULL;
|
| + return true;
|
| + }
|
| +
|
| + virtual bool onGetYUV8Planes(SkISize sizes[3],
|
| + void* planes[3],
|
| + size_t row_bytes[3]) OVERRIDE {
|
| + if (!frame_.get())
|
| + return false;
|
| + // Currently Skia only supports JPEG color range YUV.
|
| + if (frame_->format() != VideoFrame::YV12J)
|
| + return false;
|
| + for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
|
| + ++plane) {
|
| + if (sizes) {
|
| + gfx::Size size;
|
| + size = VideoFrame::PlaneSize(
|
| + frame_->format(), plane, frame_->coded_size());
|
| + sizes[plane].set(size.width(), size.height());
|
| + }
|
| + if (row_bytes)
|
| + row_bytes[plane] = frame_->stride(plane);
|
| + if (planes)
|
| + planes[plane] = frame_->data(plane);
|
| + }
|
| + if (planes && row_bytes)
|
| + frame_ = NULL;
|
| + return true;
|
| + }
|
| + public:
|
| +
|
| + virtual void set_frame(const scoped_refptr<VideoFrame>& frame) {
|
| + frame_ = frame;
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<VideoFrame> frame_;
|
| +};
|
| +
|
| SkCanvasVideoRenderer::SkCanvasVideoRenderer()
|
| - : last_frame_timestamp_(media::kNoTimestamp()) {
|
| + : generator_(NULL),
|
| + last_frame_timestamp_(media::kNoTimestamp()) {
|
| + last_frame_.setIsVolatile(true);
|
| }
|
|
|
| SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {}
|
|
|
| -void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
|
| +void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame,
|
| SkCanvas* canvas,
|
| const gfx::RectF& dest_rect,
|
| uint8 alpha,
|
| @@ -204,7 +263,7 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
|
|
|
| // Paint black rectangle if there isn't a frame available or the
|
| // frame has an unexpected format.
|
| - if (!video_frame || !IsYUVOrNative(video_frame->format())) {
|
| + if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) {
|
| canvas->drawRect(dest, paint);
|
| return;
|
| }
|
| @@ -212,8 +271,15 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
|
| // Check if we should convert and update |last_frame_|.
|
| if (last_frame_.isNull() ||
|
| video_frame->timestamp() != last_frame_timestamp_) {
|
| - ConvertVideoFrameToBitmap(video_frame, &last_frame_);
|
| + generator_ = new VideoImageGenerator(video_frame);
|
| +
|
| + // Note: This takes ownership of |generator_|.
|
| + if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) {
|
| + NOTREACHED();
|
| + }
|
|
|
| + // TODO(rileya): Perform this rotation on the canvas, rather than allocating
|
| + // a new bitmap and copying.
|
| switch (video_rotation) {
|
| case VIDEO_ROTATION_0:
|
| break;
|
| @@ -232,6 +298,8 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
|
| }
|
|
|
| last_frame_timestamp_ = video_frame->timestamp();
|
| + } else {
|
| + generator_->set_frame(video_frame);
|
| }
|
|
|
| paint.setXfermodeMode(mode);
|
| @@ -241,7 +309,7 @@ void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
|
| canvas->drawBitmapRect(last_frame_, NULL, dest, &paint);
|
| }
|
|
|
| -void SkCanvasVideoRenderer::Copy(media::VideoFrame* video_frame,
|
| +void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame,
|
| SkCanvas* canvas) {
|
| Paint(video_frame,
|
| canvas,
|
|
|