Chromium Code Reviews| 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 || |
|
scherkus (not reviewing)
2013/02/27 07:28:26
is this change required?
it seems like assigning
vignesh
2013/03/28 21:45:12
Done.
| |
| 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: | |
|
scherkus (not reviewing)
2013/02/27 07:28:26
I'm not a fan of duplicating the format checks and
vignesh
2013/03/28 21:45:12
Done.
| |
| 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); |
| 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 |