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 IsEitherYV12OrYV16(media::VideoFrame::Format format) { |
16 return format == media::VideoFrame::YV12 || format == media::VideoFrame::YV16; | 16 return format == media::VideoFrame::YV12 || format == media::VideoFrame::YV16; |
17 } | 17 } |
18 | 18 |
19 static bool IsEitherYV12OrYV16OrNative(media::VideoFrame::Format format) { | 19 static bool IsEitherYV12OrYV16OrNative(media::VideoFrame::Format format) { |
20 return IsEitherYV12OrYV16(format) || | 20 return IsEitherYV12OrYV16(format) || |
21 format == media::VideoFrame::NATIVE_TEXTURE; | 21 format == media::VideoFrame::NATIVE_TEXTURE; |
22 } | 22 } |
23 | 23 |
24 static bool IsEitherYV12OrYV12AOrYV16(media::VideoFrame::Format format) { | |
25 return IsEitherYV12OrYV16(format) || | |
26 format == media::VideoFrame::YV12A; | |
27 } | |
28 | |
29 static bool IsEitherYV12OrYV12AOrYV16OrNative( | |
30 media::VideoFrame::Format format) { | |
31 return IsEitherYV12OrYV16OrNative(format) || | |
32 format == media::VideoFrame::YV12A; | |
33 } | |
34 | |
24 // CanFastPaint is a helper method to determine the conditions for fast | 35 // CanFastPaint is a helper method to determine the conditions for fast |
25 // painting. The conditions are: | 36 // painting. The conditions are: |
26 // 1. No skew in canvas matrix. | 37 // 1. No skew in canvas matrix. |
27 // 2. No flipping nor mirroring. | 38 // 2. No flipping nor mirroring. |
28 // 3. Canvas has pixel format ARGB8888. | 39 // 3. Canvas has pixel format ARGB8888. |
29 // 4. Canvas is opaque. | 40 // 4. Canvas is opaque. |
30 // 5. Frame format is YV12 or YV16. | 41 // 5. Frame format is YV12 or YV16. |
31 // | 42 // |
32 // TODO(hclam): The fast paint method should support flipping and mirroring. | 43 // TODO(hclam): The fast paint method should support flipping and mirroring. |
33 // Disable the flipping and mirroring checks once we have it. | 44 // Disable the flipping and mirroring checks once we have it. |
(...skipping 27 matching lines...) Expand all Loading... | |
61 // CanFastPaint() is used to determine the conditions. | 72 // CanFastPaint() is used to determine the conditions. |
62 static void FastPaint( | 73 static void FastPaint( |
63 const scoped_refptr<media::VideoFrame>& video_frame, | 74 const scoped_refptr<media::VideoFrame>& video_frame, |
64 SkCanvas* canvas, | 75 SkCanvas* canvas, |
65 const SkRect& dest_rect) { | 76 const SkRect& dest_rect) { |
66 DCHECK(IsEitherYV12OrYV16(video_frame->format())) << video_frame->format(); | 77 DCHECK(IsEitherYV12OrYV16(video_frame->format())) << video_frame->format(); |
67 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 78 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
68 video_frame->stride(media::VideoFrame::kVPlane)); | 79 video_frame->stride(media::VideoFrame::kVPlane)); |
69 | 80 |
70 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); | 81 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); |
71 media::YUVType yuv_type = media::YV16; | 82 media::YUVType yuv_type = video_frame->format() == media::VideoFrame::YV12 || |
83 video_frame->format() == media::VideoFrame::YV12A ? | |
84 media::YV12 : media::YV16; | |
72 int y_shift = 0; | 85 int y_shift = 0; |
73 if (video_frame->format() == media::VideoFrame::YV12) { | 86 if (video_frame->format() == media::VideoFrame::YV12 || |
87 video_frame->format() == media::VideoFrame::YV12A) { | |
74 yuv_type = media::YV12; | 88 yuv_type = media::YV12; |
75 y_shift = 1; | 89 y_shift = 1; |
76 } | 90 } |
77 | 91 |
78 // Transform the destination rectangle to local coordinates. | 92 // Transform the destination rectangle to local coordinates. |
79 const SkMatrix& local_matrix = canvas->getTotalMatrix(); | 93 const SkMatrix& local_matrix = canvas->getTotalMatrix(); |
80 SkRect local_dest_rect; | 94 SkRect local_dest_rect; |
81 local_matrix.mapRect(&local_dest_rect, dest_rect); | 95 local_matrix.mapRect(&local_dest_rect, dest_rect); |
82 | 96 |
83 // After projecting the destination rectangle to local coordinates, round | 97 // After projecting the destination rectangle to local coordinates, round |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
163 media::FILTER_BILINEAR); | 177 media::FILTER_BILINEAR); |
164 bitmap.unlockPixels(); | 178 bitmap.unlockPixels(); |
165 } | 179 } |
166 | 180 |
167 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. | 181 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. |
168 // | 182 // |
169 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. | 183 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. |
170 static void ConvertVideoFrameToBitmap( | 184 static void ConvertVideoFrameToBitmap( |
171 const scoped_refptr<media::VideoFrame>& video_frame, | 185 const scoped_refptr<media::VideoFrame>& video_frame, |
172 SkBitmap* bitmap) { | 186 SkBitmap* bitmap) { |
173 DCHECK(IsEitherYV12OrYV16OrNative(video_frame->format())) | 187 DCHECK(IsEitherYV12OrYV12AOrYV16OrNative(video_frame->format())) |
174 << video_frame->format(); | 188 << video_frame->format(); |
175 if (IsEitherYV12OrYV16(video_frame->format())) { | 189 if (IsEitherYV12OrYV12AOrYV16(video_frame->format())) { |
176 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 190 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
177 video_frame->stride(media::VideoFrame::kVPlane)); | 191 video_frame->stride(media::VideoFrame::kVPlane)); |
178 } | 192 } |
179 | 193 |
180 // Check if |bitmap| needs to be (re)allocated. | 194 // Check if |bitmap| needs to be (re)allocated. |
181 if (bitmap->isNull() || | 195 if (bitmap->isNull() || |
182 bitmap->width() != video_frame->visible_rect().width() || | 196 bitmap->width() != video_frame->visible_rect().width() || |
183 bitmap->height() != video_frame->visible_rect().height()) { | 197 bitmap->height() != video_frame->visible_rect().height()) { |
184 bitmap->setConfig(SkBitmap::kARGB_8888_Config, | 198 bitmap->setConfig(SkBitmap::kARGB_8888_Config, |
185 video_frame->visible_rect().width(), | 199 video_frame->visible_rect().width(), |
186 video_frame->visible_rect().height()); | 200 video_frame->visible_rect().height()); |
187 bitmap->allocPixels(); | 201 bitmap->allocPixels(); |
188 bitmap->setIsVolatile(true); | 202 bitmap->setIsVolatile(true); |
189 } | 203 } |
190 | 204 |
191 bitmap->lockPixels(); | 205 bitmap->lockPixels(); |
192 if (IsEitherYV12OrYV16(video_frame->format())) { | 206 |
193 media::YUVType yuv_type = media::YV16; | 207 media::YUVType yuv_type; |
208 uint8* frame_clip_y; | |
209 uint8* frame_clip_u; | |
210 uint8* frame_clip_v; | |
211 if (IsEitherYV12OrYV12AOrYV16(video_frame->format())) { | |
212 yuv_type = media::YV16; | |
213 | |
194 int y_shift = 0; | 214 int y_shift = 0; |
195 if (video_frame->format() == media::VideoFrame::YV12) { | 215 if (video_frame->format() == media::VideoFrame::YV12 || |
216 video_frame->format() == media::VideoFrame::YV12A) { | |
196 yuv_type = media::YV12; | 217 yuv_type = media::YV12; |
197 y_shift = 1; | 218 y_shift = 1; |
198 } | 219 } |
199 | 220 |
200 // Use the "left" and "top" of the destination rect to locate the offset | 221 // Use the "left" and "top" of the destination rect to locate the offset |
201 // in Y, U and V planes. | 222 // in Y, U and V planes. |
202 size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * | 223 size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * |
203 video_frame->visible_rect().y()) + | 224 video_frame->visible_rect().y()) + |
204 video_frame->visible_rect().x(); | 225 video_frame->visible_rect().x(); |
205 | 226 |
206 // For format YV12, there is one U, V value per 2x2 block. | 227 // For format YV12, there is one U, V value per 2x2 block. |
207 // For format YV16, there is one U, V value per 2x1 block. | 228 // For format YV16, there is one U, V value per 2x1 block. |
208 size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * | 229 size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * |
209 (video_frame->visible_rect().y() >> y_shift)) + | 230 (video_frame->visible_rect().y() >> y_shift)) + |
210 (video_frame->visible_rect().x() >> 1); | 231 (video_frame->visible_rect().x() >> 1); |
211 uint8* frame_clip_y = | 232 frame_clip_y = video_frame->data(media::VideoFrame::kYPlane) + y_offset; |
212 video_frame->data(media::VideoFrame::kYPlane) + y_offset; | 233 frame_clip_u = video_frame->data(media::VideoFrame::kUPlane) + uv_offset; |
213 uint8* frame_clip_u = | 234 frame_clip_v = video_frame->data(media::VideoFrame::kVPlane) + uv_offset; |
214 video_frame->data(media::VideoFrame::kUPlane) + uv_offset; | 235 } |
215 uint8* frame_clip_v = | 236 switch (video_frame->format()) { |
216 video_frame->data(media::VideoFrame::kVPlane) + uv_offset; | 237 case media::VideoFrame::YV12: |
238 case media::VideoFrame::YV16: | |
239 media::ConvertYUVToRGB32(frame_clip_y, | |
240 frame_clip_u, | |
241 frame_clip_v, | |
242 static_cast<uint8*>(bitmap->getPixels()), | |
243 video_frame->visible_rect().width(), | |
244 video_frame->visible_rect().height(), | |
245 video_frame->stride(media::VideoFrame::kYPlane), | |
246 video_frame->stride(media::VideoFrame::kUPlane), | |
247 bitmap->rowBytes(), | |
248 yuv_type); | |
249 break; | |
217 | 250 |
218 media::ConvertYUVToRGB32(frame_clip_y, | 251 case media::VideoFrame::YV12A: |
219 frame_clip_u, | 252 media::ConvertYUVAToARGB(frame_clip_y, |
220 frame_clip_v, | 253 frame_clip_u, |
221 static_cast<uint8*>(bitmap->getPixels()), | 254 frame_clip_v, |
222 video_frame->visible_rect().width(), | 255 video_frame->data(media::VideoFrame::kAPlane), |
223 video_frame->visible_rect().height(), | 256 static_cast<uint8*>(bitmap->getPixels()), |
224 video_frame->stride(media::VideoFrame::kYPlane), | 257 video_frame->visible_rect().width(), |
225 video_frame->stride(media::VideoFrame::kUPlane), | 258 video_frame->visible_rect().height(), |
226 bitmap->rowBytes(), | 259 video_frame->stride(media::VideoFrame::kYPlane), |
227 yuv_type); | 260 video_frame->stride(media::VideoFrame::kUPlane), |
228 } else { | 261 video_frame->stride(media::VideoFrame::kAPlane), |
229 DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE); | 262 bitmap->rowBytes(), |
230 video_frame->ReadPixelsFromNativeTexture(bitmap->getPixels()); | 263 media::YV12); |
Tom Finegan
2013/02/25 22:56:06
Do we need a comment here about why this is YV12?
| |
264 break; | |
265 | |
266 case media::VideoFrame::NATIVE_TEXTURE: | |
267 DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE); | |
268 video_frame->ReadPixelsFromNativeTexture(bitmap->getPixels()); | |
269 break; | |
270 | |
271 default: | |
272 NOTREACHED(); | |
273 break; | |
231 } | 274 } |
232 bitmap->notifyPixelsChanged(); | 275 bitmap->notifyPixelsChanged(); |
233 bitmap->unlockPixels(); | 276 bitmap->unlockPixels(); |
234 } | 277 } |
235 | 278 |
236 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 279 SkCanvasVideoRenderer::SkCanvasVideoRenderer() |
237 : last_frame_timestamp_(media::kNoTimestamp()) { | 280 : last_frame_timestamp_(media::kNoTimestamp()) { |
238 } | 281 } |
239 | 282 |
240 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 283 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |
241 | 284 |
242 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, | 285 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, |
243 SkCanvas* canvas, | 286 SkCanvas* canvas, |
244 const gfx::RectF& dest_rect, | 287 const gfx::RectF& dest_rect, |
245 uint8_t alpha) { | 288 uint8_t alpha) { |
246 if (alpha == 0) { | 289 if (alpha == 0) { |
247 return; | 290 return; |
248 } | 291 } |
249 | 292 |
250 SkRect dest; | 293 SkRect dest; |
251 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 294 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
252 | 295 |
253 SkPaint paint; | 296 SkPaint paint; |
254 paint.setAlpha(alpha); | 297 paint.setAlpha(alpha); |
255 | 298 |
256 // Paint black rectangle if there isn't a frame available or the | 299 // Paint black rectangle if there isn't a frame available or the |
257 // frame has an unexpected format. | 300 // frame has an unexpected format. |
258 if (!video_frame || !IsEitherYV12OrYV16OrNative(video_frame->format())) { | 301 if (!video_frame || |
302 !IsEitherYV12OrYV12AOrYV16OrNative(video_frame->format())) { | |
259 canvas->drawRect(dest, paint); | 303 canvas->drawRect(dest, paint); |
260 return; | 304 return; |
261 } | 305 } |
262 | 306 |
263 // Scale and convert to RGB in one step if we can. | 307 // Scale and convert to RGB in one step if we can. |
264 if (CanFastPaint(canvas, alpha, video_frame->format())) { | 308 if (CanFastPaint(canvas, alpha, video_frame->format())) { |
265 FastPaint(video_frame, canvas, dest); | 309 FastPaint(video_frame, canvas, dest); |
266 return; | 310 return; |
267 } | 311 } |
268 | 312 |
269 // Check if we should convert and update |last_frame_|. | 313 // Check if we should convert and update |last_frame_|. |
270 if (last_frame_.isNull() || | 314 if (last_frame_.isNull() || |
271 video_frame->GetTimestamp() != last_frame_timestamp_) { | 315 video_frame->GetTimestamp() != last_frame_timestamp_) { |
272 ConvertVideoFrameToBitmap(video_frame, &last_frame_); | 316 ConvertVideoFrameToBitmap(video_frame, &last_frame_); |
273 last_frame_timestamp_ = video_frame->GetTimestamp(); | 317 last_frame_timestamp_ = video_frame->GetTimestamp(); |
274 } | 318 } |
275 | 319 |
276 // Do a slower paint using |last_frame_|. | 320 // Do a slower paint using |last_frame_|. |
277 paint.setFilterBitmap(true); | 321 paint.setFilterBitmap(true); |
278 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); | 322 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); |
279 } | 323 } |
280 | 324 |
281 } // namespace media | 325 } // namespace media |
OLD | NEW |