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