OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/filters/skcanvas_video_renderer.h" | 5 #include "media/filters/skcanvas_video_renderer.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "media/base/video_frame.h" | 8 #include "media/base/video_frame.h" |
9 #include "media/base/yuv_convert.h" | 9 #include "media/base/yuv_convert.h" |
10 #include "third_party/skia/include/core/SkCanvas.h" | 10 #include "third_party/skia/include/core/SkCanvas.h" |
11 #include "third_party/skia/include/core/SkDevice.h" | 11 #include "third_party/skia/include/core/SkDevice.h" |
12 | 12 |
13 namespace media { | 13 namespace media { |
14 | 14 |
15 static bool IsEitherYV12OrYV16(media::VideoFrame::Format format) { | 15 static bool IsYUV(media::VideoFrame::Format format) { |
16 return format == media::VideoFrame::YV12 || | 16 return format == media::VideoFrame::YV12 || |
| 17 format == media::VideoFrame::I420 || |
17 format == media::VideoFrame::YV16 || | 18 format == media::VideoFrame::YV16 || |
18 format == media::VideoFrame::YV12J; | 19 format == media::VideoFrame::YV12J; |
19 } | 20 } |
20 | 21 |
21 static bool IsEitherYV12OrYV16OrNative(media::VideoFrame::Format format) { | 22 static bool IsEitherYUVOrNative(media::VideoFrame::Format format) { |
22 return IsEitherYV12OrYV16(format) || | 23 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; |
23 format == media::VideoFrame::NATIVE_TEXTURE; | |
24 } | 24 } |
25 | 25 |
26 static bool IsEitherYV12OrYV12AOrYV16(media::VideoFrame::Format format) { | 26 static bool IsEitherYUVOrYUVA(media::VideoFrame::Format format) { |
27 return IsEitherYV12OrYV16(format) || | 27 return IsYUV(format) || format == media::VideoFrame::YV12A; |
28 format == media::VideoFrame::YV12A; | |
29 } | 28 } |
30 | 29 |
31 static bool IsEitherYV12OrYV12AOrYV16OrNative( | 30 static bool IsEitherYUVOrYUVAOrNative(media::VideoFrame::Format format) { |
32 media::VideoFrame::Format format) { | 31 return IsEitherYUVOrNative(format) || format == media::VideoFrame::YV12A; |
33 return IsEitherYV12OrYV16OrNative(format) || | |
34 format == media::VideoFrame::YV12A; | |
35 } | 32 } |
36 | 33 |
37 // CanFastPaint is a helper method to determine the conditions for fast | 34 // CanFastPaint is a helper method to determine the conditions for fast |
38 // painting. The conditions are: | 35 // painting. The conditions are: |
39 // 1. No skew in canvas matrix. | 36 // 1. No skew in canvas matrix. |
40 // 2. No flipping nor mirroring. | 37 // 2. No flipping nor mirroring. |
41 // 3. Canvas has pixel format ARGB8888. | 38 // 3. Canvas has pixel format ARGB8888. |
42 // 4. Canvas is opaque. | 39 // 4. Canvas is opaque. |
43 // 5. Frame format is YV12 or YV16. | 40 // 5. Frame format is YV12, I420 or YV16. |
44 // | 41 // |
45 // TODO(hclam): The fast paint method should support flipping and mirroring. | 42 // TODO(hclam): The fast paint method should support flipping and mirroring. |
46 // Disable the flipping and mirroring checks once we have it. | 43 // Disable the flipping and mirroring checks once we have it. |
47 static bool CanFastPaint(SkCanvas* canvas, uint8 alpha, | 44 static bool CanFastPaint(SkCanvas* canvas, uint8 alpha, |
48 media::VideoFrame::Format format) { | 45 media::VideoFrame::Format format) { |
49 if (alpha != 0xFF || !IsEitherYV12OrYV16(format)) | 46 if (alpha != 0xFF || !IsYUV(format)) |
50 return false; | 47 return false; |
51 | 48 |
52 const SkMatrix& total_matrix = canvas->getTotalMatrix(); | 49 const SkMatrix& total_matrix = canvas->getTotalMatrix(); |
53 // Perform the following checks here: | 50 // Perform the following checks here: |
54 // 1. Check for skewing factors of the transformation matrix. They should be | 51 // 1. Check for skewing factors of the transformation matrix. They should be |
55 // zero. | 52 // zero. |
56 // 2. Check for mirroring and flipping. Make sure they are greater than zero. | 53 // 2. Check for mirroring and flipping. Make sure they are greater than zero. |
57 if (SkScalarNearlyZero(total_matrix.getSkewX()) && | 54 if (SkScalarNearlyZero(total_matrix.getSkewX()) && |
58 SkScalarNearlyZero(total_matrix.getSkewY()) && | 55 SkScalarNearlyZero(total_matrix.getSkewY()) && |
59 total_matrix.getScaleX() > 0 && | 56 total_matrix.getScaleX() > 0 && |
60 total_matrix.getScaleY() > 0) { | 57 total_matrix.getScaleY() > 0) { |
61 SkBaseDevice* device = canvas->getDevice(); | 58 SkBaseDevice* device = canvas->getDevice(); |
62 const SkBitmap::Config config = device->config(); | 59 const SkBitmap::Config config = device->config(); |
63 | 60 |
64 if (config == SkBitmap::kARGB_8888_Config && device->isOpaque()) { | 61 if (config == SkBitmap::kARGB_8888_Config && device->isOpaque()) { |
65 return true; | 62 return true; |
66 } | 63 } |
67 } | 64 } |
68 | 65 |
69 return false; | 66 return false; |
70 } | 67 } |
71 | 68 |
72 // Fast paint does YUV => RGB, scaling, blitting all in one step into the | 69 // Fast paint does YUV => RGB, scaling, blitting all in one step into the |
73 // canvas. It's not always safe and appropriate to perform fast paint. | 70 // canvas. It's not always safe and appropriate to perform fast paint. |
74 // CanFastPaint() is used to determine the conditions. | 71 // CanFastPaint() is used to determine the conditions. |
75 static void FastPaint( | 72 static void FastPaint( |
76 const scoped_refptr<media::VideoFrame>& video_frame, | 73 const scoped_refptr<media::VideoFrame>& video_frame, |
77 SkCanvas* canvas, | 74 SkCanvas* canvas, |
78 const SkRect& dest_rect) { | 75 const SkRect& dest_rect) { |
79 DCHECK(IsEitherYV12OrYV16(video_frame->format())) << video_frame->format(); | 76 DCHECK(IsYUV(video_frame->format())) << video_frame->format(); |
80 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 77 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
81 video_frame->stride(media::VideoFrame::kVPlane)); | 78 video_frame->stride(media::VideoFrame::kVPlane)); |
82 | 79 |
83 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); | 80 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); |
84 media::YUVType yuv_type = media::YV16; | 81 media::YUVType yuv_type = media::YV16; |
85 int y_shift = 0; | 82 int y_shift = 0; |
86 if (video_frame->format() == media::VideoFrame::YV12 || | 83 if (video_frame->format() == media::VideoFrame::YV12 || |
| 84 video_frame->format() == media::VideoFrame::I420 || |
87 video_frame->format() == media::VideoFrame::YV12A) { | 85 video_frame->format() == media::VideoFrame::YV12A) { |
88 yuv_type = media::YV12; | 86 yuv_type = media::YV12; |
89 y_shift = 1; | 87 y_shift = 1; |
90 } | 88 } |
91 | 89 |
92 if (video_frame->format() == media::VideoFrame::YV12J) { | 90 if (video_frame->format() == media::VideoFrame::YV12J) { |
93 yuv_type = media::YV12; | 91 yuv_type = media::YV12; |
94 y_shift = 1; | 92 y_shift = 1; |
95 } | 93 } |
96 | 94 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 media::FILTER_BILINEAR); | 180 media::FILTER_BILINEAR); |
183 bitmap.unlockPixels(); | 181 bitmap.unlockPixels(); |
184 } | 182 } |
185 | 183 |
186 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. | 184 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. |
187 // | 185 // |
188 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. | 186 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. |
189 static void ConvertVideoFrameToBitmap( | 187 static void ConvertVideoFrameToBitmap( |
190 const scoped_refptr<media::VideoFrame>& video_frame, | 188 const scoped_refptr<media::VideoFrame>& video_frame, |
191 SkBitmap* bitmap) { | 189 SkBitmap* bitmap) { |
192 DCHECK(IsEitherYV12OrYV12AOrYV16OrNative(video_frame->format())) | 190 DCHECK(IsEitherYUVOrYUVAOrNative(video_frame->format())) |
193 << video_frame->format(); | 191 << video_frame->format(); |
194 if (IsEitherYV12OrYV12AOrYV16(video_frame->format())) { | 192 if (IsEitherYUVOrYUVA(video_frame->format())) { |
195 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 193 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
196 video_frame->stride(media::VideoFrame::kVPlane)); | 194 video_frame->stride(media::VideoFrame::kVPlane)); |
197 } | 195 } |
198 | 196 |
199 // Check if |bitmap| needs to be (re)allocated. | 197 // Check if |bitmap| needs to be (re)allocated. |
200 if (bitmap->isNull() || | 198 if (bitmap->isNull() || |
201 bitmap->width() != video_frame->visible_rect().width() || | 199 bitmap->width() != video_frame->visible_rect().width() || |
202 bitmap->height() != video_frame->visible_rect().height()) { | 200 bitmap->height() != video_frame->visible_rect().height()) { |
203 bitmap->setConfig(SkBitmap::kARGB_8888_Config, | 201 bitmap->setConfig(SkBitmap::kARGB_8888_Config, |
204 video_frame->visible_rect().width(), | 202 video_frame->visible_rect().width(), |
205 video_frame->visible_rect().height()); | 203 video_frame->visible_rect().height()); |
206 bitmap->allocPixels(); | 204 bitmap->allocPixels(); |
207 bitmap->setIsVolatile(true); | 205 bitmap->setIsVolatile(true); |
208 } | 206 } |
209 | 207 |
210 bitmap->lockPixels(); | 208 bitmap->lockPixels(); |
211 | 209 |
212 size_t y_offset = 0; | 210 size_t y_offset = 0; |
213 size_t uv_offset = 0; | 211 size_t uv_offset = 0; |
214 if (IsEitherYV12OrYV12AOrYV16(video_frame->format())) { | 212 if (IsEitherYUVOrYUVA(video_frame->format())) { |
215 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1; | 213 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1; |
216 // Use the "left" and "top" of the destination rect to locate the offset | 214 // Use the "left" and "top" of the destination rect to locate the offset |
217 // in Y, U and V planes. | 215 // in Y, U and V planes. |
218 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * | 216 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * |
219 video_frame->visible_rect().y()) + | 217 video_frame->visible_rect().y()) + |
220 video_frame->visible_rect().x(); | 218 video_frame->visible_rect().x(); |
221 // For format YV12, there is one U, V value per 2x2 block. | 219 // For format YV12, there is one U, V value per 2x2 block. |
222 // For format YV16, there is one U, V value per 2x1 block. | 220 // For format YV16, there is one U, V value per 2x1 block. |
223 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * | 221 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * |
224 (video_frame->visible_rect().y() >> y_shift)) + | 222 (video_frame->visible_rect().y() >> y_shift)) + |
225 (video_frame->visible_rect().x() >> 1); | 223 (video_frame->visible_rect().x() >> 1); |
226 } | 224 } |
227 | 225 |
228 switch (video_frame->format()) { | 226 switch (video_frame->format()) { |
229 case media::VideoFrame::YV12: | 227 case media::VideoFrame::YV12: |
| 228 case media::VideoFrame::I420: |
230 case media::VideoFrame::YV12J: | 229 case media::VideoFrame::YV12J: |
231 media::ConvertYUVToRGB32( | 230 media::ConvertYUVToRGB32( |
232 video_frame->data(media::VideoFrame::kYPlane) + y_offset, | 231 video_frame->data(media::VideoFrame::kYPlane) + y_offset, |
233 video_frame->data(media::VideoFrame::kUPlane) + uv_offset, | 232 video_frame->data(media::VideoFrame::kUPlane) + uv_offset, |
234 video_frame->data(media::VideoFrame::kVPlane) + uv_offset, | 233 video_frame->data(media::VideoFrame::kVPlane) + uv_offset, |
235 static_cast<uint8*>(bitmap->getPixels()), | 234 static_cast<uint8*>(bitmap->getPixels()), |
236 video_frame->visible_rect().width(), | 235 video_frame->visible_rect().width(), |
237 video_frame->visible_rect().height(), | 236 video_frame->visible_rect().height(), |
238 video_frame->stride(media::VideoFrame::kYPlane), | 237 video_frame->stride(media::VideoFrame::kYPlane), |
239 video_frame->stride(media::VideoFrame::kUPlane), | 238 video_frame->stride(media::VideoFrame::kUPlane), |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 } | 298 } |
300 | 299 |
301 SkRect dest; | 300 SkRect dest; |
302 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 301 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
303 | 302 |
304 SkPaint paint; | 303 SkPaint paint; |
305 paint.setAlpha(alpha); | 304 paint.setAlpha(alpha); |
306 | 305 |
307 // Paint black rectangle if there isn't a frame available or the | 306 // Paint black rectangle if there isn't a frame available or the |
308 // frame has an unexpected format. | 307 // frame has an unexpected format. |
309 if (!video_frame || | 308 if (!video_frame || !IsEitherYUVOrYUVAOrNative(video_frame->format())) { |
310 !IsEitherYV12OrYV12AOrYV16OrNative(video_frame->format())) { | |
311 canvas->drawRect(dest, paint); | 309 canvas->drawRect(dest, paint); |
312 return; | 310 return; |
313 } | 311 } |
314 | 312 |
315 // Scale and convert to RGB in one step if we can. | 313 // Scale and convert to RGB in one step if we can. |
316 if (CanFastPaint(canvas, alpha, video_frame->format())) { | 314 if (CanFastPaint(canvas, alpha, video_frame->format())) { |
317 FastPaint(video_frame, canvas, dest); | 315 FastPaint(video_frame, canvas, dest); |
318 return; | 316 return; |
319 } | 317 } |
320 | 318 |
321 // Check if we should convert and update |last_frame_|. | 319 // Check if we should convert and update |last_frame_|. |
322 if (last_frame_.isNull() || | 320 if (last_frame_.isNull() || |
323 video_frame->GetTimestamp() != last_frame_timestamp_) { | 321 video_frame->GetTimestamp() != last_frame_timestamp_) { |
324 ConvertVideoFrameToBitmap(video_frame, &last_frame_); | 322 ConvertVideoFrameToBitmap(video_frame, &last_frame_); |
325 last_frame_timestamp_ = video_frame->GetTimestamp(); | 323 last_frame_timestamp_ = video_frame->GetTimestamp(); |
326 } | 324 } |
327 | 325 |
328 // Do a slower paint using |last_frame_|. | 326 // Do a slower paint using |last_frame_|. |
329 paint.setFilterBitmap(true); | 327 paint.setFilterBitmap(true); |
330 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); | 328 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); |
331 } | 329 } |
332 | 330 |
333 } // namespace media | 331 } // namespace media |
OLD | NEW |