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