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

Side by Side Diff: media/filters/skcanvas_video_renderer.cc

Issue 314833002: Remove FastPaint. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 months 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
« no previous file with comments | « no previous file | media/filters/skcanvas_video_renderer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
11 #include "third_party/skia/include/core/SkCanvas.h" 11 #include "third_party/skia/include/core/SkCanvas.h"
12 #include "third_party/skia/include/core/SkDevice.h" 12 #include "third_party/skia/include/core/SkDevice.h"
scherkus (not reviewing) 2014/06/05 18:25:59 nit: I think we can remove this include
13 13
14 // Skia internal format depends on a platform. On Android it is ABGR, on others 14 // Skia internal format depends on a platform. On Android it is ABGR, on others
15 // it is ARGB. 15 // it is ARGB.
16 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ 16 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \
17 SK_A32_SHIFT == 24 17 SK_A32_SHIFT == 24
18 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB 18 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB
19 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB 19 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB
20 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ 20 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
21 SK_A32_SHIFT == 24 21 SK_A32_SHIFT == 24
22 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR 22 #define LIBYUV_I420_TO_ARGB libyuv::I420ToABGR
23 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR 23 #define LIBYUV_I422_TO_ARGB libyuv::I422ToABGR
24 #else 24 #else
25 #error Unexpected Skia ARGB_8888 layout! 25 #error Unexpected Skia ARGB_8888 layout!
26 #endif 26 #endif
27 27
28 namespace media { 28 namespace media {
29 29
30 static bool IsYUV(media::VideoFrame::Format format) { 30 static bool IsYUV(media::VideoFrame::Format format) {
31 return format == media::VideoFrame::YV12 || 31 return format == media::VideoFrame::YV12 ||
32 format == media::VideoFrame::YV16 || 32 format == media::VideoFrame::YV16 ||
33 format == media::VideoFrame::I420 || 33 format == media::VideoFrame::I420 ||
34 format == media::VideoFrame::YV12A || 34 format == media::VideoFrame::YV12A ||
35 format == media::VideoFrame::YV12J || 35 format == media::VideoFrame::YV12J ||
36 format == media::VideoFrame::YV24; 36 format == media::VideoFrame::YV24;
37 } 37 }
38 38
39 static bool IsFastPaintYUV(media::VideoFrame::Format format) {
40 return format == media::VideoFrame::YV12 ||
41 format == media::VideoFrame::YV16 ||
42 format == media::VideoFrame::I420 ||
43 format == media::VideoFrame::YV12J;
44 }
45
46 static bool IsYUVOrNative(media::VideoFrame::Format format) { 39 static bool IsYUVOrNative(media::VideoFrame::Format format) {
47 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; 40 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE;
48 } 41 }
49 42
50 // CanFastPaint is a helper method to determine the conditions for fast
51 // painting. The conditions are:
52 // 1. No skew in canvas matrix.
53 // 2. No flipping nor mirroring.
54 // 3. Canvas has pixel format ARGB8888.
55 // 4. Canvas is opaque.
56 // 5. Frame format is YV12, I420 or YV16.
57 //
58 // TODO(hclam): The fast paint method should support flipping and mirroring.
59 // Disable the flipping and mirroring checks once we have it.
60 static bool CanFastPaint(SkCanvas* canvas, uint8 alpha,
61 media::VideoFrame::Format format) {
62 if (alpha != 0xFF || !IsFastPaintYUV(format))
63 return false;
64
65 const SkMatrix& total_matrix = canvas->getTotalMatrix();
66 // Perform the following checks here:
67 // 1. Check for skewing factors of the transformation matrix. They should be
68 // zero.
69 // 2. Check for mirroring and flipping. Make sure they are greater than zero.
70 if (SkScalarNearlyZero(total_matrix.getSkewX()) &&
71 SkScalarNearlyZero(total_matrix.getSkewY()) &&
72 total_matrix.getScaleX() > 0 &&
73 total_matrix.getScaleY() > 0) {
74 const SkImageInfo info = canvas->imageInfo();
75
76 if (info.colorType() == kN32_SkColorType && info.isOpaque()) {
77 return true;
78 }
79 }
80
81 return false;
82 }
83
84 // Fast paint does YUV => RGB, scaling, blitting all in one step into the
85 // canvas. It's not always safe and appropriate to perform fast paint.
86 // CanFastPaint() is used to determine the conditions.
87 static void FastPaint(
88 const scoped_refptr<media::VideoFrame>& video_frame,
89 SkCanvas* canvas,
90 const SkRect& dest_rect) {
91 DCHECK(IsFastPaintYUV(video_frame->format())) << video_frame->format();
92 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
93 video_frame->stride(media::VideoFrame::kVPlane));
94
95 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true);
96 media::YUVType yuv_type = media::YV16;
97 int y_shift = 0;
98 if (video_frame->format() == media::VideoFrame::YV12 ||
99 video_frame->format() == media::VideoFrame::I420) {
100 yuv_type = media::YV12;
101 y_shift = 1;
102 }
103
104 if (video_frame->format() == media::VideoFrame::YV12J) {
105 yuv_type = media::YV12J;
106 y_shift = 1;
107 }
108
109 // Transform the destination rectangle to local coordinates.
110 const SkMatrix& local_matrix = canvas->getTotalMatrix();
111 SkRect local_dest_rect;
112 local_matrix.mapRect(&local_dest_rect, dest_rect);
113
114 // After projecting the destination rectangle to local coordinates, round
115 // the projected rectangle to integer values, this will give us pixel values
116 // of the rectangle.
117 SkIRect local_dest_irect, local_dest_irect_saved;
118 local_dest_rect.round(&local_dest_irect);
119 local_dest_rect.round(&local_dest_irect_saved);
120
121 // No point painting if the destination rect doesn't intersect with the
122 // clip rect.
123 SkIRect device_bounds;
124 if (!canvas->getClipDeviceBounds(&device_bounds))
125 return;
126 if (!local_dest_irect.intersect(device_bounds))
127 return;
128
129 // At this point |local_dest_irect| contains the rect that we should draw
130 // to within the clipping rect.
131
132 // Project the clip rect to the original video frame, obtains the
133 // dimensions of the projected clip rect, "left" and "top" of the rect.
134 // The math here are all integer math so we won't have rounding error and
135 // write outside of the canvas.
136 // We have the assumptions of dest_rect.width() and dest_rect.height()
137 // being non-zero, these are valid assumptions since finding intersection
138 // above rejects empty rectangle so we just do a DCHECK here.
139 DCHECK_NE(0, dest_rect.width());
140 DCHECK_NE(0, dest_rect.height());
141 size_t frame_clip_width = local_dest_irect.width() *
142 video_frame->visible_rect().width() /
143 local_dest_irect_saved.width();
144 size_t frame_clip_height = local_dest_irect.height() *
145 video_frame->visible_rect().height() /
146 local_dest_irect_saved.height();
147
148 // Project the "left" and "top" of the final destination rect to local
149 // coordinates of the video frame, use these values to find the offsets
150 // in the video frame to start reading.
151 size_t frame_clip_left =
152 video_frame->visible_rect().x() +
153 (local_dest_irect.fLeft - local_dest_irect_saved.fLeft) *
154 video_frame->visible_rect().width() / local_dest_irect_saved.width();
155 size_t frame_clip_top =
156 video_frame->visible_rect().y() +
157 (local_dest_irect.fTop - local_dest_irect_saved.fTop) *
158 video_frame->visible_rect().height() /
159 local_dest_irect_saved.height();
160
161 // Use the "left" and "top" of the destination rect to locate the offset
162 // in Y, U and V planes.
163 size_t y_offset =
164 (video_frame->stride(media::VideoFrame::kYPlane) * frame_clip_top) +
165 frame_clip_left;
166
167 // For format YV12, there is one U, V value per 2x2 block.
168 // For format YV16, there is one U, V value per 2x1 block.
169 size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) *
170 (frame_clip_top >> y_shift)) +
171 (frame_clip_left >> 1);
172
173 // Calculate the address for the top left corner of destination rect in
174 // the canvas that we will draw to. The address is obtained by the base
175 // address of the canvas shifted by "left" and "top" of the rect.
176 uint8* dest_rect_pointer = static_cast<uint8*>(bitmap.getPixels()) +
177 local_dest_irect.fTop * bitmap.rowBytes() +
178 local_dest_irect.fLeft * 4;
179
180 uint8* frame_clip_y =
181 video_frame->data(media::VideoFrame::kYPlane) + y_offset;
182 uint8* frame_clip_u =
183 video_frame->data(media::VideoFrame::kUPlane) + uv_offset;
184 uint8* frame_clip_v =
185 video_frame->data(media::VideoFrame::kVPlane) + uv_offset;
186
187 // TODO(hclam): do rotation and mirroring here.
188 // TODO(fbarchard): switch filtering based on performance.
189 bitmap.lockPixels();
190
191 // If there is no scaling and the frame format is supported, then use faster
192 // libyuv.
193 if (frame_clip_width == static_cast<size_t>(local_dest_irect.width()) &&
194 frame_clip_height == static_cast<size_t>(local_dest_irect.height())) {
195 switch (yuv_type) {
196 case media::YV12:
197 LIBYUV_I420_TO_ARGB(frame_clip_y,
198 video_frame->stride(media::VideoFrame::kYPlane),
199 frame_clip_u,
200 video_frame->stride(media::VideoFrame::kUPlane),
201 frame_clip_v,
202 video_frame->stride(media::VideoFrame::kVPlane),
203 dest_rect_pointer,
204 bitmap.rowBytes(),
205 local_dest_irect.width(),
206 local_dest_irect.height());
207 bitmap.unlockPixels();
208 return;
209
210 case media::YV16:
211 LIBYUV_I422_TO_ARGB(frame_clip_y,
212 video_frame->stride(media::VideoFrame::kYPlane),
213 frame_clip_u,
214 video_frame->stride(media::VideoFrame::kUPlane),
215 frame_clip_v,
216 video_frame->stride(media::VideoFrame::kVPlane),
217 dest_rect_pointer,
218 bitmap.rowBytes(),
219 local_dest_irect.width(),
220 local_dest_irect.height());
221 bitmap.unlockPixels();
222 return;
223
224 default:
225 break;
226 }
227 }
228
229 // Fallback to media, since the operation is not supported by libyuv.
230 media::ScaleYUVToRGB32(frame_clip_y,
231 frame_clip_u,
232 frame_clip_v,
233 dest_rect_pointer,
234 frame_clip_width,
235 frame_clip_height,
236 local_dest_irect.width(),
237 local_dest_irect.height(),
238 video_frame->stride(media::VideoFrame::kYPlane),
239 video_frame->stride(media::VideoFrame::kUPlane),
240 bitmap.rowBytes(),
241 yuv_type,
242 media::ROTATE_0,
243 media::FILTER_BILINEAR);
244 bitmap.unlockPixels();
245 }
246
247 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. 43 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data.
248 // 44 //
249 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. 45 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|.
250 static void ConvertVideoFrameToBitmap( 46 static void ConvertVideoFrameToBitmap(
251 const scoped_refptr<media::VideoFrame>& video_frame, 47 const scoped_refptr<media::VideoFrame>& video_frame,
252 SkBitmap* bitmap) { 48 SkBitmap* bitmap) {
253 DCHECK(IsYUVOrNative(video_frame->format())) 49 DCHECK(IsYUVOrNative(video_frame->format()))
254 << video_frame->format(); 50 << video_frame->format();
255 if (IsYUV(video_frame->format())) { 51 if (IsYUV(video_frame->format())) {
256 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), 52 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 SkPaint paint; 202 SkPaint paint;
407 paint.setAlpha(alpha); 203 paint.setAlpha(alpha);
408 204
409 // Paint black rectangle if there isn't a frame available or the 205 // Paint black rectangle if there isn't a frame available or the
410 // frame has an unexpected format. 206 // frame has an unexpected format.
411 if (!video_frame || !IsYUVOrNative(video_frame->format())) { 207 if (!video_frame || !IsYUVOrNative(video_frame->format())) {
412 canvas->drawRect(dest, paint); 208 canvas->drawRect(dest, paint);
413 return; 209 return;
414 } 210 }
415 211
416 // Scale and convert to RGB in one step if we can.
417 if (CanFastPaint(canvas, alpha, video_frame->format())) {
418 FastPaint(video_frame, canvas, dest);
419 return;
420 }
421
422 // Check if we should convert and update |last_frame_|. 212 // Check if we should convert and update |last_frame_|.
423 if (last_frame_.isNull() || 213 if (last_frame_.isNull() ||
424 video_frame->timestamp() != last_frame_timestamp_) { 214 video_frame->timestamp() != last_frame_timestamp_) {
425 ConvertVideoFrameToBitmap(video_frame, &last_frame_); 215 ConvertVideoFrameToBitmap(video_frame, &last_frame_);
426 last_frame_timestamp_ = video_frame->timestamp(); 216 last_frame_timestamp_ = video_frame->timestamp();
427 } 217 }
428 218
429 // Paint using |last_frame_|. 219 // Paint using |last_frame_|.
430 paint.setFilterLevel(SkPaint::kLow_FilterLevel); 220 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
431 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); 221 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint);
432 } 222 }
433 223
434 } // namespace media 224 } // namespace media
OLDNEW
« no previous file with comments | « no previous file | media/filters/skcanvas_video_renderer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698