| 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/libyuv/include/libyuv.h" | 10 #include "third_party/libyuv/include/libyuv.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 SK_A32_SHIFT == 24 | 22 SK_A32_SHIFT == 24 |
| 23 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR | 23 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR |
| 24 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR | 24 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR |
| 25 #else | 25 #else |
| 26 #error Unexpected Skia ARGB_8888 layout! | 26 #error Unexpected Skia ARGB_8888 layout! |
| 27 #endif | 27 #endif |
| 28 | 28 |
| 29 namespace media { | 29 namespace media { |
| 30 | 30 |
| 31 static bool IsYUV(media::VideoFrame::Format format) { | 31 static bool IsYUV(media::VideoFrame::Format format) { |
| 32 return format == media::VideoFrame::YV12 || | 32 switch (format) { |
| 33 format == media::VideoFrame::YV16 || | 33 case VideoFrame::YV12: |
| 34 format == media::VideoFrame::I420 || | 34 case VideoFrame::YV16: |
| 35 format == media::VideoFrame::YV12A || | 35 case VideoFrame::I420: |
| 36 format == media::VideoFrame::YV12J || | 36 case VideoFrame::YV12A: |
| 37 format == media::VideoFrame::YV24; | 37 case VideoFrame::YV12J: |
| 38 case VideoFrame::YV24: |
| 39 case VideoFrame::NV12: |
| 40 return true; |
| 41 case VideoFrame::UNKNOWN: |
| 42 case VideoFrame::NATIVE_TEXTURE: |
| 43 #if defined(VIDEO_HOLE) |
| 44 case VideoFrame::HOLE: |
| 45 #endif // defined(VIDEO_HOLE) |
| 46 return false; |
| 47 } |
| 48 NOTREACHED() << "Invalid videoframe format provided: " << format; |
| 49 return false; |
| 50 } |
| 51 |
| 52 static bool IsJPEGColorSpace(media::VideoFrame::Format format) { |
| 53 switch (format) { |
| 54 case VideoFrame::YV12J: |
| 55 return true; |
| 56 case VideoFrame::YV12: |
| 57 case VideoFrame::YV16: |
| 58 case VideoFrame::I420: |
| 59 case VideoFrame::YV12A: |
| 60 case VideoFrame::YV24: |
| 61 case VideoFrame::NV12: |
| 62 case VideoFrame::UNKNOWN: |
| 63 case VideoFrame::NATIVE_TEXTURE: |
| 64 #if defined(VIDEO_HOLE) |
| 65 case VideoFrame::HOLE: |
| 66 #endif // defined(VIDEO_HOLE) |
| 67 return false; |
| 68 } |
| 69 NOTREACHED() << "Invalid videoframe format provided: " << format; |
| 70 return false; |
| 38 } | 71 } |
| 39 | 72 |
| 40 static bool IsYUVOrNative(media::VideoFrame::Format format) { | 73 static bool IsYUVOrNative(media::VideoFrame::Format format) { |
| 41 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; | 74 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; |
| 42 } | 75 } |
| 43 | 76 |
| 44 // Converts a |video_frame| to raw |rgb_pixels|. | 77 // Converts a |video_frame| to raw |rgb_pixels|. |
| 45 static void ConvertVideoFrameToRGBPixels( | 78 static void ConvertVideoFrameToRGBPixels( |
| 46 const scoped_refptr<media::VideoFrame>& video_frame, | 79 const scoped_refptr<media::VideoFrame>& video_frame, |
| 47 void* rgb_pixels, | 80 void* rgb_pixels, |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 171 break; | 204 break; |
| 172 } | 205 } |
| 173 } | 206 } |
| 174 | 207 |
| 175 // Generates an RGB image from a VideoFrame. | 208 // Generates an RGB image from a VideoFrame. |
| 176 class VideoImageGenerator : public SkImageGenerator { | 209 class VideoImageGenerator : public SkImageGenerator { |
| 177 public: | 210 public: |
| 178 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {} | 211 VideoImageGenerator(const scoped_refptr<VideoFrame>& frame) : frame_(frame) {} |
| 179 virtual ~VideoImageGenerator() {} | 212 virtual ~VideoImageGenerator() {} |
| 180 | 213 |
| 214 void set_frame(const scoped_refptr<VideoFrame>& frame) { frame_ = frame; } |
| 215 |
| 181 protected: | 216 protected: |
| 182 virtual bool onGetInfo(SkImageInfo* info) OVERRIDE { | 217 virtual bool onGetInfo(SkImageInfo* info) OVERRIDE { |
| 183 info->fWidth = frame_->visible_rect().width(); | 218 info->fWidth = frame_->visible_rect().width(); |
| 184 info->fHeight = frame_->visible_rect().height(); | 219 info->fHeight = frame_->visible_rect().height(); |
| 185 info->fColorType = kN32_SkColorType; | 220 info->fColorType = kN32_SkColorType; |
| 186 info->fAlphaType = kPremul_SkAlphaType; | 221 info->fAlphaType = kPremul_SkAlphaType; |
| 187 return true; | 222 return true; |
| 188 } | 223 } |
| 189 | 224 |
| 190 virtual bool onGetPixels(const SkImageInfo& info, | 225 virtual bool onGetPixels(const SkImageInfo& info, |
| 191 void* pixels, | 226 void* pixels, |
| 192 size_t row_bytes, | 227 size_t row_bytes, |
| 193 SkPMColor ctable[], | 228 SkPMColor ctable[], |
| 194 int* ctable_count) OVERRIDE { | 229 int* ctable_count) OVERRIDE { |
| 195 if (!frame_.get()) | 230 if (!frame_.get()) |
| 196 return false; | 231 return false; |
| 197 if (!pixels) | 232 if (!pixels) |
| 198 return true; | 233 return true; |
| 199 // If skia couldn't do the YUV conversion, we will. | 234 // If skia couldn't do the YUV conversion, we will. |
| 200 ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes); | 235 ConvertVideoFrameToRGBPixels(frame_, pixels, row_bytes); |
| 201 frame_ = NULL; | 236 frame_ = NULL; |
| 202 return true; | 237 return true; |
| 203 } | 238 } |
| 204 | 239 |
| 205 virtual bool onGetYUV8Planes(SkISize sizes[3], | 240 virtual bool onGetYUV8Planes(SkISize sizes[3], |
| 206 void* planes[3], | 241 void* planes[3], |
| 207 size_t row_bytes[3]) OVERRIDE { | 242 size_t row_bytes[3], |
| 208 if (!frame_.get()) | 243 SkYUVColorSpace* color_space) OVERRIDE { |
| 244 if (!frame_.get() || !IsYUV(frame_->format())) |
| 209 return false; | 245 return false; |
| 210 // Currently Skia only supports JPEG color range YUV. | 246 |
| 211 if (frame_->format() != VideoFrame::YV12J) | 247 if (color_space) { |
| 212 return false; | 248 if (IsJPEGColorSpace(frame_->format())) |
| 249 *color_space = kJPEG_SkYUVColorSpace; |
| 250 else |
| 251 *color_space = kRec601_SkYUVColorSpace; |
| 252 } |
| 253 |
| 213 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane; | 254 for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane; |
| 214 ++plane) { | 255 ++plane) { |
| 215 if (sizes) { | 256 if (sizes) { |
| 216 gfx::Size size; | 257 gfx::Size size; |
| 217 size = VideoFrame::PlaneSize( | 258 size = |
| 218 frame_->format(), plane, frame_->coded_size()); | 259 VideoFrame::PlaneSize(frame_->format(), |
| 260 plane, |
| 261 gfx::Size(frame_->visible_rect().width(), |
| 262 frame_->visible_rect().height())); |
| 219 sizes[plane].set(size.width(), size.height()); | 263 sizes[plane].set(size.width(), size.height()); |
| 220 } | 264 } |
| 221 if (row_bytes) | 265 if (row_bytes && planes) { |
| 222 row_bytes[plane] = frame_->stride(plane); | 266 size_t offset; |
| 223 if (planes) | 267 int y_shift = (frame_->format() == media::VideoFrame::YV16) ? 0 : 1; |
| 224 planes[plane] = frame_->data(plane); | 268 if (plane == media::VideoFrame::kYPlane) { |
| 269 offset = (frame_->stride(media::VideoFrame::kYPlane) * |
| 270 frame_->visible_rect().y()) + |
| 271 frame_->visible_rect().x(); |
| 272 } else { |
| 273 offset = (frame_->stride(media::VideoFrame::kUPlane) * |
| 274 (frame_->visible_rect().y() >> y_shift)) + |
| 275 (frame_->visible_rect().x() >> 1); |
| 276 } |
| 277 row_bytes[plane] = static_cast<size_t>(frame_->stride(plane)); |
| 278 planes[plane] = frame_->data(plane) + offset; |
| 279 } |
| 225 } | 280 } |
| 226 if (planes && row_bytes) | 281 if (planes && row_bytes) |
| 227 frame_ = NULL; | 282 frame_ = NULL; |
| 228 return true; | 283 return true; |
| 229 } | 284 } |
| 230 public: | |
| 231 | |
| 232 virtual void set_frame(const scoped_refptr<VideoFrame>& frame) { | |
| 233 frame_ = frame; | |
| 234 } | |
| 235 | 285 |
| 236 private: | 286 private: |
| 237 scoped_refptr<VideoFrame> frame_; | 287 scoped_refptr<VideoFrame> frame_; |
| 238 }; | 288 }; |
| 239 | 289 |
| 240 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 290 SkCanvasVideoRenderer::SkCanvasVideoRenderer() |
| 241 : generator_(NULL), | 291 : generator_(NULL), last_frame_timestamp_(media::kNoTimestamp()) { |
| 242 last_frame_timestamp_(media::kNoTimestamp()) { | |
| 243 last_frame_.setIsVolatile(true); | 292 last_frame_.setIsVolatile(true); |
| 244 } | 293 } |
| 245 | 294 |
| 246 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 295 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |
| 247 | 296 |
| 248 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, | 297 void SkCanvasVideoRenderer::Paint(const scoped_refptr<VideoFrame>& video_frame, |
| 249 SkCanvas* canvas, | 298 SkCanvas* canvas, |
| 250 const gfx::RectF& dest_rect, | 299 const gfx::RectF& dest_rect, |
| 251 uint8 alpha, | 300 uint8 alpha, |
| 252 SkXfermode::Mode mode, | 301 SkXfermode::Mode mode, |
| 253 VideoRotation video_rotation) { | 302 VideoRotation video_rotation) { |
| 254 if (alpha == 0) { | 303 if (alpha == 0) { |
| 255 return; | 304 return; |
| 256 } | 305 } |
| 257 | 306 |
| 258 SkRect dest; | 307 SkRect dest; |
| 259 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 308 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
| 260 | 309 |
| 261 SkPaint paint; | 310 SkPaint paint; |
| 262 paint.setAlpha(alpha); | 311 paint.setAlpha(alpha); |
| 263 | 312 |
| 264 // Paint black rectangle if there isn't a frame available or the | 313 // Paint black rectangle if there isn't a frame available or the |
| 265 // frame has an unexpected format. | 314 // frame has an unexpected format. |
| 266 if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) { | 315 if (!video_frame.get() || !IsYUVOrNative(video_frame->format())) { |
| 267 canvas->drawRect(dest, paint); | 316 canvas->drawRect(dest, paint); |
| 317 canvas->flush(); |
| 268 return; | 318 return; |
| 269 } | 319 } |
| 270 | 320 |
| 271 // Check if we should convert and update |last_frame_|. | 321 // Check if we should convert and update |last_frame_|. |
| 272 if (last_frame_.isNull() || | 322 if (last_frame_.isNull() || |
| 273 video_frame->timestamp() != last_frame_timestamp_) { | 323 video_frame->timestamp() != last_frame_timestamp_) { |
| 274 generator_ = new VideoImageGenerator(video_frame); | 324 generator_ = new VideoImageGenerator(video_frame); |
| 275 | 325 |
| 276 // Note: This takes ownership of |generator_|. | 326 // Note: This takes ownership of |generator_|. |
| 277 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { | 327 if (!SkInstallDiscardablePixelRef(generator_, &last_frame_)) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 290 case VIDEO_ROTATION_180: | 340 case VIDEO_ROTATION_180: |
| 291 last_frame_ = SkBitmapOperations::Rotate( | 341 last_frame_ = SkBitmapOperations::Rotate( |
| 292 last_frame_, SkBitmapOperations::ROTATION_180_CW); | 342 last_frame_, SkBitmapOperations::ROTATION_180_CW); |
| 293 break; | 343 break; |
| 294 case VIDEO_ROTATION_270: | 344 case VIDEO_ROTATION_270: |
| 295 last_frame_ = SkBitmapOperations::Rotate( | 345 last_frame_ = SkBitmapOperations::Rotate( |
| 296 last_frame_, SkBitmapOperations::ROTATION_270_CW); | 346 last_frame_, SkBitmapOperations::ROTATION_270_CW); |
| 297 break; | 347 break; |
| 298 } | 348 } |
| 299 | 349 |
| 350 // We copied the frame into a new bitmap and threw out the old one, so we |
| 351 // no longer have a |generator_| around. This should be removed when the |
| 352 // above TODO is addressed. |
| 353 if (video_rotation != VIDEO_ROTATION_0) |
| 354 generator_ = NULL; |
| 355 |
| 300 last_frame_timestamp_ = video_frame->timestamp(); | 356 last_frame_timestamp_ = video_frame->timestamp(); |
| 301 } else { | 357 } else if (generator_) { |
| 302 generator_->set_frame(video_frame); | 358 generator_->set_frame(video_frame); |
| 303 } | 359 } |
| 304 | 360 |
| 305 paint.setXfermodeMode(mode); | 361 paint.setXfermodeMode(mode); |
| 306 | 362 |
| 307 // Paint using |last_frame_|. | 363 // Paint using |last_frame_|. |
| 308 paint.setFilterLevel(SkPaint::kLow_FilterLevel); | 364 paint.setFilterLevel(SkPaint::kLow_FilterLevel); |
| 309 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); | 365 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); |
| 366 canvas->flush(); |
| 310 } | 367 } |
| 311 | 368 |
| 312 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, | 369 void SkCanvasVideoRenderer::Copy(const scoped_refptr<VideoFrame>& video_frame, |
| 313 SkCanvas* canvas) { | 370 SkCanvas* canvas) { |
| 314 Paint(video_frame, | 371 Paint(video_frame, |
| 315 canvas, | 372 canvas, |
| 316 video_frame->visible_rect(), | 373 video_frame->visible_rect(), |
| 317 0xff, | 374 0xff, |
| 318 SkXfermode::kSrc_Mode, | 375 SkXfermode::kSrc_Mode, |
| 319 media::VIDEO_ROTATION_0); | 376 media::VIDEO_ROTATION_0); |
| 320 } | 377 } |
| 321 | 378 |
| 322 } // namespace media | 379 } // namespace media |
| OLD | NEW |