1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/skcanvas_video_renderer.h"
7 #include "base/logging.h"
8 #include "media/base/video_frame.h"
9 #include "media/base/yuv_convert.h"
10 #include "third_party/libyuv/include/libyuv.h"
11 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "ui/gfx/skbitmap_operations.h"
14 // Skia internal format depends on a platform. On Android it is ABGR, on others
16 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
18 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
19 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
20 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
22 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
23 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
25 #error Unexpected Skia ARGB_8888 layout!
30 static bool IsYUV(media::VideoFrame::Format format) {
31 return format == media::VideoFrame::YV12 ||
32 format == media::VideoFrame::YV16 ||
33 format == media::VideoFrame::I420 ||
34 format == media::VideoFrame::YV12A ||
35 format == media::VideoFrame::YV12J ||
36 format == media::VideoFrame::YV24;
39 static bool IsYUVOrNative(media::VideoFrame::Format format) {
40 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE;
43 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data.
45 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|.
46 static void ConvertVideoFrameToBitmap(
47 const scoped_refptr<media::VideoFrame>& video_frame,
49 DCHECK(IsYUVOrNative(video_frame->format()))
50 << video_frame->format();
51 if (IsYUV(video_frame->format())) {
52 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
53 video_frame->stride(media::VideoFrame::kVPlane));
56 // Check if |bitmap| needs to be (re)allocated.
57 if (bitmap->isNull() ||
58 bitmap->width() != video_frame->visible_rect().width() ||
59 bitmap->height() != video_frame->visible_rect().height()) {
60 bitmap->allocN32Pixels(video_frame->visible_rect().width(),
61 video_frame->visible_rect().height());
62 bitmap->setIsVolatile(true);
69 if (IsYUV(video_frame->format())) {
70 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1;
71 // Use the "left" and "top" of the destination rect to locate the offset
72 // in Y, U and V planes.
73 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) *
74 video_frame->visible_rect().y()) +
75 video_frame->visible_rect().x();
76 // For format YV12, there is one U, V value per 2x2 block.
77 // For format YV16, there is one U, V value per 2x1 block.
78 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) *
79 (video_frame->visible_rect().y() >> y_shift)) +
80 (video_frame->visible_rect().x() >> 1);
83 switch (video_frame->format()) {
84 case media::VideoFrame::YV12:
85 case media::VideoFrame::I420:
87 video_frame->data(media::VideoFrame::kYPlane) + y_offset,
88 video_frame->stride(media::VideoFrame::kYPlane),
89 video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
90 video_frame->stride(media::VideoFrame::kUPlane),
91 video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
92 video_frame->stride(media::VideoFrame::kVPlane),
93 static_cast<uint8*>(bitmap->getPixels()),
95 video_frame->visible_rect().width(),
96 video_frame->visible_rect().height());
99 case media::VideoFrame::YV12J:
100 media::ConvertYUVToRGB32(
101 video_frame->data(media::VideoFrame::kYPlane) + y_offset,
102 video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
103 video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
104 static_cast<uint8*>(bitmap->getPixels()),
105 video_frame->visible_rect().width(),
106 video_frame->visible_rect().height(),
107 video_frame->stride(media::VideoFrame::kYPlane),
108 video_frame->stride(media::VideoFrame::kUPlane),
113 case media::VideoFrame::YV16:
115 video_frame->data(media::VideoFrame::kYPlane) + y_offset,
116 video_frame->stride(media::VideoFrame::kYPlane),
117 video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
118 video_frame->stride(media::VideoFrame::kUPlane),
119 video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
120 video_frame->stride(media::VideoFrame::kVPlane),
121 static_cast<uint8*>(bitmap->getPixels()),
123 video_frame->visible_rect().width(),
124 video_frame->visible_rect().height());
127 case media::VideoFrame::YV12A:
128 // Since libyuv doesn't support YUVA, fallback to media, which is not ARM
130 // TODO(fbarchard, mtomasz): Use libyuv, then copy the alpha channel.
131 media::ConvertYUVAToARGB(
132 video_frame->data(media::VideoFrame::kYPlane) + y_offset,
133 video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
134 video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
135 video_frame->data(media::VideoFrame::kAPlane),
136 static_cast<uint8*>(bitmap->getPixels()),
137 video_frame->visible_rect().width(),
138 video_frame->visible_rect().height(),
139 video_frame->stride(media::VideoFrame::kYPlane),
140 video_frame->stride(media::VideoFrame::kUPlane),
141 video_frame->stride(media::VideoFrame::kAPlane),
146 case media::VideoFrame::YV24:
148 video_frame->data(media::VideoFrame::kYPlane) + y_offset,
149 video_frame->stride(media::VideoFrame::kYPlane),
150 video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
151 video_frame->stride(media::VideoFrame::kUPlane),
152 video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
153 video_frame->stride(media::VideoFrame::kVPlane),
154 static_cast<uint8*>(bitmap->getPixels()),
156 video_frame->visible_rect().width(),
157 video_frame->visible_rect().height());
158 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
161 static_cast<uint8*>(bitmap->getPixels()),
163 static_cast<uint8*>(bitmap->getPixels()),
165 video_frame->visible_rect().width(),
166 video_frame->visible_rect().height());
170 case media::VideoFrame::NATIVE_TEXTURE:
171 DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE);
172 video_frame->ReadPixelsFromNativeTexture(*bitmap);
179 bitmap->notifyPixelsChanged();
180 bitmap->unlockPixels();
183 SkCanvasVideoRenderer::SkCanvasVideoRenderer()
184 : last_frame_timestamp_(media::kNoTimestamp()) {
187 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {}
189 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame,
191 const gfx::RectF& dest_rect,
193 VideoRotation video_rotation) {
199 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
202 paint.setAlpha(alpha);
204 // Paint black rectangle if there isn't a frame available or the
205 // frame has an unexpected format.
206 if (!video_frame || !IsYUVOrNative(video_frame->format())) {
207 canvas->drawRect(dest, paint);
211 // Check if we should convert and update |last_frame_|.
212 if (last_frame_.isNull() ||
213 video_frame->timestamp() != last_frame_timestamp_) {
214 ConvertVideoFrameToBitmap(video_frame, &last_frame_);
216 switch (video_rotation) {
217 case VIDEO_ROTATION_0:
219 case VIDEO_ROTATION_90:
220 last_frame_ = SkBitmapOperations::Rotate(
221 last_frame_, SkBitmapOperations::ROTATION_90_CW);
223 case VIDEO_ROTATION_180:
224 last_frame_ = SkBitmapOperations::Rotate(
225 last_frame_, SkBitmapOperations::ROTATION_180_CW);
227 case VIDEO_ROTATION_270:
228 last_frame_ = SkBitmapOperations::Rotate(
229 last_frame_, SkBitmapOperations::ROTATION_270_CW);
233 last_frame_timestamp_ = video_frame->timestamp();
236 // Use SRC mode so we completely overwrite the buffer (in case we have alpha)
237 // this means we don't need the extra cost of clearing the buffer first.
238 paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode));
240 // Paint using |last_frame_|.
241 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
242 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint);