Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(749)

Side by Side Diff: webkit/glue/media/video_renderer_impl.cc

Issue 8570010: Moving media-related files from webkit/glue/ to webkit/media/. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src
Patch Set: minor fixes Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/glue/media/video_renderer_impl.h ('k') | webkit/glue/media/web_data_source.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "webkit/glue/media/video_renderer_impl.h"
6
7 #include "base/logging.h"
8 #include "media/base/video_frame.h"
9 #include "media/base/yuv_convert.h"
10 #include "third_party/skia/include/core/SkCanvas.h"
11 #include "third_party/skia/include/core/SkDevice.h"
12 #include "webkit/glue/webmediaplayer_proxy.h"
13
14 namespace webkit_glue {
15
16 VideoRendererImpl::VideoRendererImpl(bool pts_logging)
17 : last_converted_frame_(NULL),
18 pts_logging_(pts_logging) {
19 }
20
21 VideoRendererImpl::~VideoRendererImpl() {}
22
23 bool VideoRendererImpl::OnInitialize(media::VideoDecoder* decoder) {
24 natural_size_ = decoder->natural_size();
25 bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
26 natural_size_.width(), natural_size_.height());
27 bitmap_.allocPixels();
28 bitmap_.eraseRGB(0x00, 0x00, 0x00);
29 bitmap_.setIsVolatile(true);
30 return true;
31 }
32
33 void VideoRendererImpl::OnStop(const base::Closure& callback) {
34 if (!callback.is_null())
35 callback.Run();
36 }
37
38 void VideoRendererImpl::OnFrameAvailable() {
39 proxy_->Repaint();
40 }
41
42 void VideoRendererImpl::SetWebMediaPlayerProxy(WebMediaPlayerProxy* proxy) {
43 proxy_ = proxy;
44 }
45
46 void VideoRendererImpl::SetRect(const gfx::Rect& rect) {}
47
48 // This method is always called on the renderer's thread.
49 void VideoRendererImpl::Paint(SkCanvas* canvas, const gfx::Rect& dest_rect) {
50 scoped_refptr<media::VideoFrame> video_frame;
51 GetCurrentFrame(&video_frame);
52 if (!video_frame) {
53 SkPaint paint;
54 paint.setColor(SK_ColorBLACK);
55 canvas->drawRectCoords(
56 static_cast<float>(dest_rect.x()),
57 static_cast<float>(dest_rect.y()),
58 static_cast<float>(dest_rect.right()),
59 static_cast<float>(dest_rect.bottom()),
60 paint);
61 } else {
62 if (CanFastPaint(canvas, dest_rect)) {
63 FastPaint(video_frame, canvas, dest_rect);
64 } else {
65 SlowPaint(video_frame, canvas, dest_rect);
66 }
67
68 // Presentation timestamp logging is primarily used to measure performance
69 // on low-end devices. When profiled on an Intel Atom N280 @ 1.66GHz this
70 // code had a ~63 microsecond perf hit when logging to a file (not stdout),
71 // which is neglible enough for measuring playback performance.
72 if (pts_logging_)
73 VLOG(1) << "pts=" << video_frame->GetTimestamp().InMicroseconds();
74 }
75
76 PutCurrentFrame(video_frame);
77 }
78
79 // CanFastPaint is a helper method to determine the conditions for fast
80 // painting. The conditions are:
81 // 1. No skew in canvas matrix.
82 // 2. No flipping nor mirroring.
83 // 3. Canvas has pixel format ARGB8888.
84 // 4. Canvas is opaque.
85 // TODO(hclam): The fast paint method should support flipping and mirroring.
86 // Disable the flipping and mirroring checks once we have it.
87 bool VideoRendererImpl::CanFastPaint(SkCanvas* canvas,
88 const gfx::Rect& dest_rect) {
89 // Fast paint does not handle opacity value other than 1.0. Hence use slow
90 // paint if opacity is not 1.0. Since alpha = opacity * 0xFF, we check that
91 // alpha != 0xFF.
92 //
93 // Additonal notes: If opacity = 0.0, the chrome display engine does not try
94 // to render the video. So, this method is never called. However, if the
95 // opacity = 0.0001, alpha is again 0, but the display engine tries to render
96 // the video. If we use Fast paint, the video shows up with opacity = 1.0.
97 // Hence we use slow paint also in the case where alpha = 0. It would be ideal
98 // if rendering was never called even for cases where alpha is 0. Created
99 // bug 48090 for this.
100 SkCanvas::LayerIter layer_iter(canvas, false);
101 SkColor sk_color = layer_iter.paint().getColor();
102 SkAlpha sk_alpha = SkColorGetA(sk_color);
103 if (sk_alpha != 0xFF) {
104 return false;
105 }
106
107 const SkMatrix& total_matrix = canvas->getTotalMatrix();
108 // Perform the following checks here:
109 // 1. Check for skewing factors of the transformation matrix. They should be
110 // zero.
111 // 2. Check for mirroring and flipping. Make sure they are greater than zero.
112 if (SkScalarNearlyZero(total_matrix.getSkewX()) &&
113 SkScalarNearlyZero(total_matrix.getSkewY()) &&
114 total_matrix.getScaleX() > 0 &&
115 total_matrix.getScaleY() > 0) {
116 SkDevice* device = canvas->getDevice();
117 const SkBitmap::Config config = device->config();
118
119 if (config == SkBitmap::kARGB_8888_Config && device->isOpaque()) {
120 return true;
121 }
122 }
123
124 return false;
125 }
126
127 void VideoRendererImpl::SlowPaint(media::VideoFrame* video_frame,
128 SkCanvas* canvas,
129 const gfx::Rect& dest_rect) {
130 // 1. Convert YUV frame to RGB.
131 base::TimeDelta timestamp = video_frame->GetTimestamp();
132 if (video_frame != last_converted_frame_ ||
133 timestamp != last_converted_timestamp_) {
134 last_converted_frame_ = video_frame;
135 last_converted_timestamp_ = timestamp;
136 DCHECK(video_frame->format() == media::VideoFrame::YV12 ||
137 video_frame->format() == media::VideoFrame::YV16);
138 DCHECK(video_frame->stride(media::VideoFrame::kUPlane) ==
139 video_frame->stride(media::VideoFrame::kVPlane));
140 DCHECK(video_frame->planes() == media::VideoFrame::kNumYUVPlanes);
141 bitmap_.lockPixels();
142 media::YUVType yuv_type =
143 (video_frame->format() == media::VideoFrame::YV12) ?
144 media::YV12 : media::YV16;
145 media::ConvertYUVToRGB32(video_frame->data(media::VideoFrame::kYPlane),
146 video_frame->data(media::VideoFrame::kUPlane),
147 video_frame->data(media::VideoFrame::kVPlane),
148 static_cast<uint8*>(bitmap_.getPixels()),
149 video_frame->width(),
150 video_frame->height(),
151 video_frame->stride(media::VideoFrame::kYPlane),
152 video_frame->stride(media::VideoFrame::kUPlane),
153 bitmap_.rowBytes(),
154 yuv_type);
155 bitmap_.notifyPixelsChanged();
156 bitmap_.unlockPixels();
157 }
158
159 // 2. Paint the bitmap to canvas.
160 SkMatrix matrix;
161 matrix.setTranslate(static_cast<SkScalar>(dest_rect.x()),
162 static_cast<SkScalar>(dest_rect.y()));
163 if (dest_rect.width() != natural_size_.width() ||
164 dest_rect.height() != natural_size_.height()) {
165 matrix.preScale(SkIntToScalar(dest_rect.width()) /
166 SkIntToScalar(natural_size_.width()),
167 SkIntToScalar(dest_rect.height()) /
168 SkIntToScalar(natural_size_.height()));
169 }
170 SkPaint paint;
171 paint.setFlags(SkPaint::kFilterBitmap_Flag);
172 canvas->drawBitmapMatrix(bitmap_, matrix, &paint);
173 }
174
175 void VideoRendererImpl::FastPaint(media::VideoFrame* video_frame,
176 SkCanvas* canvas,
177 const gfx::Rect& dest_rect) {
178 DCHECK(video_frame->format() == media::VideoFrame::YV12 ||
179 video_frame->format() == media::VideoFrame::YV16);
180 DCHECK(video_frame->stride(media::VideoFrame::kUPlane) ==
181 video_frame->stride(media::VideoFrame::kVPlane));
182 DCHECK(video_frame->planes() == media::VideoFrame::kNumYUVPlanes);
183 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true);
184 media::YUVType yuv_type = (video_frame->format() == media::VideoFrame::YV12) ?
185 media::YV12 : media::YV16;
186 int y_shift = yuv_type; // 1 for YV12, 0 for YV16.
187
188 // Create a rectangle backed by SkScalar.
189 SkRect scalar_dest_rect;
190 scalar_dest_rect.iset(dest_rect.x(), dest_rect.y(),
191 dest_rect.right(), dest_rect.bottom());
192
193 // Transform the destination rectangle to local coordinates.
194 const SkMatrix& local_matrix = canvas->getTotalMatrix();
195 SkRect local_dest_rect;
196 local_matrix.mapRect(&local_dest_rect, scalar_dest_rect);
197
198 // After projecting the destination rectangle to local coordinates, round
199 // the projected rectangle to integer values, this will give us pixel values
200 // of the rectangle.
201 SkIRect local_dest_irect, local_dest_irect_saved;
202 local_dest_rect.round(&local_dest_irect);
203 local_dest_rect.round(&local_dest_irect_saved);
204
205 // Only does the paint if the destination rect intersects with the clip
206 // rect.
207 if (local_dest_irect.intersect(canvas->getTotalClip().getBounds())) {
208 // At this point |local_dest_irect| contains the rect that we should draw
209 // to within the clipping rect.
210
211 // Calculate the address for the top left corner of destination rect in
212 // the canvas that we will draw to. The address is obtained by the base
213 // address of the canvas shifted by "left" and "top" of the rect.
214 uint8* dest_rect_pointer = static_cast<uint8*>(bitmap.getPixels()) +
215 local_dest_irect.fTop * bitmap.rowBytes() +
216 local_dest_irect.fLeft * 4;
217
218 // Project the clip rect to the original video frame, obtains the
219 // dimensions of the projected clip rect, "left" and "top" of the rect.
220 // The math here are all integer math so we won't have rounding error and
221 // write outside of the canvas.
222 // We have the assumptions of dest_rect.width() and dest_rect.height()
223 // being non-zero, these are valid assumptions since finding intersection
224 // above rejects empty rectangle so we just do a DCHECK here.
225 DCHECK_NE(0, dest_rect.width());
226 DCHECK_NE(0, dest_rect.height());
227 size_t frame_clip_width = local_dest_irect.width() *
228 video_frame->width() / local_dest_irect_saved.width();
229 size_t frame_clip_height = local_dest_irect.height() *
230 video_frame->height() / local_dest_irect_saved.height();
231
232 // Project the "left" and "top" of the final destination rect to local
233 // coordinates of the video frame, use these values to find the offsets
234 // in the video frame to start reading.
235 size_t frame_clip_left =
236 (local_dest_irect.fLeft - local_dest_irect_saved.fLeft) *
237 video_frame->width() / local_dest_irect_saved.width();
238 size_t frame_clip_top =
239 (local_dest_irect.fTop - local_dest_irect_saved.fTop) *
240 video_frame->height() / local_dest_irect_saved.height();
241
242 // Use the "left" and "top" of the destination rect to locate the offset
243 // in Y, U and V planes.
244 size_t y_offset = video_frame->stride(media::VideoFrame::kYPlane) *
245 frame_clip_top + frame_clip_left;
246 // For format YV12, there is one U, V value per 2x2 block.
247 // For format YV16, there is one u, V value per 2x1 block.
248 size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) *
249 (frame_clip_top >> y_shift)) + (frame_clip_left >> 1);
250 uint8* frame_clip_y =
251 video_frame->data(media::VideoFrame::kYPlane) + y_offset;
252 uint8* frame_clip_u =
253 video_frame->data(media::VideoFrame::kUPlane) + uv_offset;
254 uint8* frame_clip_v =
255 video_frame->data(media::VideoFrame::kVPlane) + uv_offset;
256 bitmap.lockPixels();
257
258 // TODO(hclam): do rotation and mirroring here.
259 // TODO(fbarchard): switch filtering based on performance.
260 media::ScaleYUVToRGB32(frame_clip_y,
261 frame_clip_u,
262 frame_clip_v,
263 dest_rect_pointer,
264 frame_clip_width,
265 frame_clip_height,
266 local_dest_irect.width(),
267 local_dest_irect.height(),
268 video_frame->stride(media::VideoFrame::kYPlane),
269 video_frame->stride(media::VideoFrame::kUPlane),
270 bitmap.rowBytes(),
271 yuv_type,
272 media::ROTATE_0,
273 media::FILTER_BILINEAR);
274 bitmap.unlockPixels();
275 }
276 }
277
278 } // namespace webkit_glue
OLDNEW
« no previous file with comments | « webkit/glue/media/video_renderer_impl.h ('k') | webkit/glue/media/web_data_source.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698