1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/media/video_renderer_impl.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "media/base/video_frame.h" 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "media/base/yuv_convert.h" 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "webkit/glue/webmediaplayer_impl.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace webkit_glue { 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 13513209b27ff55e2841eac0e4120199c23acce758Ben MurdochVideoRendererImpl::VideoRendererImpl(bool pts_logging) 14513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch : last_converted_frame_(NULL), 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pts_logging_(pts_logging) { 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickVideoRendererImpl::~VideoRendererImpl() {} 19731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool VideoRendererImpl::OnInitialize(media::VideoDecoder* decoder) { 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_size_.SetSize(width(), height()); 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap_.setConfig(SkBitmap::kARGB_8888_Config, width(), height()); 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (bitmap_.allocPixels(NULL, NULL)) { 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap_.eraseRGB(0x00, 0x00, 0x00); 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED(); 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VideoRendererImpl::OnStop(media::FilterCallback* callback) { 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (callback) { 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch callback->Run(); 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete callback; 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VideoRendererImpl::OnFrameAvailable() { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch proxy_->Repaint(); 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 43513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid VideoRendererImpl::SetWebMediaPlayerImplProxy( 44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch WebMediaPlayerImpl::Proxy* proxy) { 45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch proxy_ = proxy; 46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VideoRendererImpl::SetRect(const gfx::Rect& rect) { 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This method is always called on the renderer's thread. 52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid VideoRendererImpl::Paint(SkCanvas* canvas, 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& dest_rect) { 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scoped_refptr<media::VideoFrame> video_frame; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GetCurrentFrame(&video_frame); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!video_frame) { 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkPaint paint; 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paint.setColor(SK_ColorBLACK); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canvas->drawRectCoords( 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<float>(dest_rect.x()), 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<float>(dest_rect.y()), 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<float>(dest_rect.right()), 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<float>(dest_rect.bottom()), 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paint); 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (CanFastPaint(canvas, dest_rect)) { 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch FastPaint(video_frame, canvas, dest_rect); 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SlowPaint(video_frame, canvas, dest_rect); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Presentation timestamp logging is primarily used to measure performance 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // on low-end devices. When profiled on an Intel Atom N280 @ 1.66GHz this 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // code had a ~63 microsecond perf hit when logging to a file (not stdout), 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // which is neglible enough for measuring playback performance. 76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (pts_logging_) 77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick VLOG(1) << "pts=" << video_frame->GetTimestamp().InMicroseconds(); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch PutCurrentFrame(video_frame); 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid VideoRendererImpl::GetCurrentFrame( 843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_refptr<media::VideoFrame>* frame_out) { 853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick VideoRendererBase::GetCurrentFrame(frame_out); 863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid VideoRendererImpl::PutCurrentFrame( 893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick scoped_refptr<media::VideoFrame> frame) { 903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick VideoRendererBase::PutCurrentFrame(frame); 913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick} 923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// CanFastPaint is a helper method to determine the conditions for fast 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// painting. The conditions are: 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 1. No skew in canvas matrix. 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 2. No flipping nor mirroring. 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 3. Canvas has pixel format ARGB8888. 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 4. Canvas is opaque. 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(hclam): The fast paint method should support flipping and mirroring. 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Disable the flipping and mirroring checks once we have it. 101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool VideoRendererImpl::CanFastPaint(SkCanvas* canvas, 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& dest_rect) { 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Fast paint does not handle opacity value other than 1.0. Hence use slow 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // paint if opacity is not 1.0. Since alpha = opacity * 0xFF, we check that 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // alpha != 0xFF. 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Additonal notes: If opacity = 0.0, the chrome display engine does not try 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to render the video. So, this method is never called. However, if the 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // opacity = 0.0001, alpha is again 0, but the display engine tries to render 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the video. If we use Fast paint, the video shows up with opacity = 1.0. 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Hence we use slow paint also in the case where alpha = 0. It would be ideal 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // if rendering was never called even for cases where alpha is 0. Created 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // bug 48090 for this. 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkCanvas::LayerIter layer_iter(canvas, false); 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkColor sk_color = layer_iter.paint().getColor(); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkAlpha sk_alpha = SkColorGetA(sk_color); 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (sk_alpha != 0xFF) { 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkMatrix& total_matrix = canvas->getTotalMatrix(); 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Perform the following checks here: 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 1. Check for skewing factors of the transformation matrix. They should be 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // zero. 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 2. Check for mirroring and flipping. Make sure they are greater than zero. 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (SkScalarNearlyZero(total_matrix.getSkewX()) && 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkScalarNearlyZero(total_matrix.getSkewY()) && 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch total_matrix.getScaleX() > 0 && 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch total_matrix.getScaleY() > 0) { 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the properties of the SkDevice and the clip rect. 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkDevice* device = canvas->getDevice(); 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the boundary of the device. 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIRect device_rect; 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch device->getBounds(&device_rect); 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the pixel config of the device. 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkBitmap::Config config = device->config(); 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Get the total clip rect associated with the canvas. 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkRegion& total_clip = canvas->getTotalClip(); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIRect dest_irect; 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TransformToSkIRect(canvas->getTotalMatrix(), dest_rect, &dest_irect); 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (config == SkBitmap::kARGB_8888_Config && device->isOpaque() && 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch device_rect.contains(total_clip.getBounds())) { 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VideoRendererImpl::SlowPaint(media::VideoFrame* video_frame, 155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkCanvas* canvas, 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& dest_rect) { 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 1. Convert YUV frame to RGB. 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch base::TimeDelta timestamp = video_frame->GetTimestamp(); 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (video_frame != last_converted_frame_ || 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch timestamp != last_converted_timestamp_) { 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_converted_frame_ = video_frame; 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch last_converted_timestamp_ = timestamp; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(video_frame->format() == media::VideoFrame::YV12 || 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->format() == media::VideoFrame::YV16); 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(video_frame->stride(media::VideoFrame::kUPlane) == 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->stride(media::VideoFrame::kVPlane)); 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(video_frame->planes() == media::VideoFrame::kNumYUVPlanes); 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap_.lockPixels(); 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::YUVType yuv_type = 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (video_frame->format() == media::VideoFrame::YV12) ? 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::YV12 : media::YV16; 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane), 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->data(media::VideoFrame::kUPlane), 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->data(media::VideoFrame::kVPlane), 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<uint8*>(bitmap_.getPixels()), 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->width(), 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->height(), 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->stride(media::VideoFrame::kYPlane), 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->stride(media::VideoFrame::kUPlane), 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap_.rowBytes(), 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch yuv_type); 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap_.unlockPixels(); 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 2. Paint the bitmap to canvas. 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkMatrix matrix; 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matrix.setTranslate(static_cast<SkScalar>(dest_rect.x()), 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch static_cast<SkScalar>(dest_rect.y())); 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (dest_rect.width() != video_size_.width() || 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dest_rect.height() != video_size_.height()) { 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matrix.preScale(SkIntToScalar(dest_rect.width()) / 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIntToScalar(video_size_.width()), 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIntToScalar(dest_rect.height()) / 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIntToScalar(video_size_.height())); 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkPaint paint; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch paint.setFlags(SkPaint::kFilterBitmap_Flag); 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch canvas->drawBitmapMatrix(bitmap_, matrix, &paint); 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VideoRendererImpl::FastPaint(media::VideoFrame* video_frame, 202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen SkCanvas* canvas, 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& dest_rect) { 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(video_frame->format() == media::VideoFrame::YV12 || 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->format() == media::VideoFrame::YV16); 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(video_frame->stride(media::VideoFrame::kUPlane) == 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->stride(media::VideoFrame::kVPlane)); 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(video_frame->planes() == media::VideoFrame::kNumYUVPlanes); 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12) ? 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::YV12 : media::YV16; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch int y_shift = yuv_type; // 1 for YV12, 0 for YV16. 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Create a rectangle backed by SkScalar. 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkRect scalar_dest_rect; 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch scalar_dest_rect.iset(dest_rect.x(), dest_rect.y(), 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dest_rect.right(), dest_rect.bottom()); 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Transform the destination rectangle to local coordinates. 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const SkMatrix& local_matrix = canvas->getTotalMatrix(); 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkRect local_dest_rect; 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_matrix.mapRect(&local_dest_rect, scalar_dest_rect); 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // After projecting the destination rectangle to local coordinates, round 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the projected rectangle to integer values, this will give us pixel values 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // of the rectangle. 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIRect local_dest_irect, local_dest_irect_saved; 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_dest_rect.round(&local_dest_irect); 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_dest_rect.round(&local_dest_irect_saved); 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only does the paint if the destination rect intersects with the clip 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // rect. 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (local_dest_irect.intersect(canvas->getTotalClip().getBounds())) { 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // At this point |local_dest_irect| contains the rect that we should draw 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // to within the clipping rect. 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Calculate the address for the top left corner of destination rect in 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the canvas that we will draw to. The address is obtained by the base 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // address of the canvas shifted by "left" and "top" of the rect. 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint8* dest_rect_pointer = static_cast<uint8*>(bitmap.getPixels()) + 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_dest_irect.fTop * bitmap.rowBytes() + 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_dest_irect.fLeft * 4; 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Project the clip rect to the original video frame, obtains the 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // dimensions of the projected clip rect, "left" and "top" of the rect. 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // The math here are all integer math so we won't have rounding error and 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // write outside of the canvas. 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We have the assumptions of dest_rect.width() and dest_rect.height() 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // being non-zero, these are valid assumptions since finding intersection 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // above rejects empty rectangle so we just do a DCHECK here. 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_NE(0, dest_rect.width()); 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK_NE(0, dest_rect.height()); 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t frame_clip_width = local_dest_irect.width() * 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->width() / local_dest_irect_saved.width(); 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t frame_clip_height = local_dest_irect.height() * 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->height() / local_dest_irect_saved.height(); 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Project the "left" and "top" of the final destination rect to local 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // coordinates of the video frame, use these values to find the offsets 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in the video frame to start reading. 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t frame_clip_left = 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (local_dest_irect.fLeft - local_dest_irect_saved.fLeft) * 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->width() / local_dest_irect_saved.width(); 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t frame_clip_top = 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (local_dest_irect.fTop - local_dest_irect_saved.fTop) * 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->height() / local_dest_irect_saved.height(); 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Use the "left" and "top" of the destination rect to locate the offset 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // in Y, U and V planes. 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t y_offset = video_frame->stride(media::VideoFrame::kYPlane) * 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_clip_top + frame_clip_left; 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For format YV12, there is one U, V value per 2x2 block. 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For format YV16, there is one u, V value per 2x1 block. 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch (frame_clip_top >> y_shift)) + (frame_clip_left >> 1); 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint8* frame_clip_y = 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->data(media::VideoFrame::kYPlane) + y_offset; 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint8* frame_clip_u = 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->data(media::VideoFrame::kUPlane) + uv_offset; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch uint8* frame_clip_v = 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->data(media::VideoFrame::kVPlane) + uv_offset; 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap.lockPixels(); 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(hclam): do rotation and mirroring here. 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(fbarchard): switch filtering based on performance. 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::ScaleYUVToRGB32(frame_clip_y, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_clip_u, 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_clip_v, 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch dest_rect_pointer, 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_clip_width, 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame_clip_height, 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_dest_irect.width(), 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch local_dest_irect.height(), 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->stride(media::VideoFrame::kYPlane), 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch video_frame->stride(media::VideoFrame::kUPlane), 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap.rowBytes(), 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch yuv_type, 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::ROTATE_0, 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch media::FILTER_BILINEAR); 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bitmap.unlockPixels(); 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid VideoRendererImpl::TransformToSkIRect(const SkMatrix& matrix, 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& src_rect, 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkIRect* dest_rect) { 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Transform destination rect to local coordinates. 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkRect transformed_rect; 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SkRect skia_dest_rect; 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch skia_dest_rect.iset(src_rect.x(), src_rect.y(), 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch src_rect.right(), src_rect.bottom()); 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch matrix.mapRect(&transformed_rect, skia_dest_rect); 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch transformed_rect.round(dest_rect); 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace webkit_glue 317