| 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 |