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