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 "skia/ext/refptr.h" |
10 #include "third_party/libyuv/include/libyuv.h" | 11 #include "third_party/libyuv/include/libyuv.h" |
11 #include "third_party/skia/include/core/SkCanvas.h" | 12 #include "third_party/skia/include/core/SkCanvas.h" |
| 13 #include "third_party/skia/include/gpu/SkGr.h" |
| 14 #include "third_party/skia/src/gpu/effects/GrYUVtoRGBEffect.h" |
12 #include "ui/gfx/skbitmap_operations.h" | 15 #include "ui/gfx/skbitmap_operations.h" |
13 | 16 |
14 // Skia internal format depends on a platform. On Android it is ABGR, on others | 17 // Skia internal format depends on a platform. On Android it is ABGR, on others |
15 // it is ARGB. | 18 // it is ARGB. |
16 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ | 19 #if SK_B32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_R32_SHIFT == 16 && \ |
17 SK_A32_SHIFT == 24 | 20 SK_A32_SHIFT == 24 |
18 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB | 21 #define LIBYUV_I420_TO_ARGB libyuv::I420ToARGB |
19 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB | 22 #define LIBYUV_I422_TO_ARGB libyuv::I422ToARGB |
20 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ | 23 #elif SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \ |
21 SK_A32_SHIFT == 24 | 24 SK_A32_SHIFT == 24 |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 | 177 |
175 default: | 178 default: |
176 NOTREACHED(); | 179 NOTREACHED(); |
177 break; | 180 break; |
178 } | 181 } |
179 bitmap->notifyPixelsChanged(); | 182 bitmap->notifyPixelsChanged(); |
180 bitmap->unlockPixels(); | 183 bitmap->unlockPixels(); |
181 } | 184 } |
182 | 185 |
183 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 186 SkCanvasVideoRenderer::SkCanvasVideoRenderer() |
184 : last_frame_timestamp_(media::kNoTimestamp()) { | 187 : last_frame_timestamp_(media::kNoTimestamp()), |
| 188 yuv_planes_timestamp_(media::kNoTimestamp()) { |
185 } | 189 } |
186 | 190 |
187 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 191 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |
188 | 192 |
189 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, | 193 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, |
190 SkCanvas* canvas, | 194 SkCanvas* canvas, |
191 const gfx::RectF& dest_rect, | 195 const gfx::RectF& dest_rect, |
192 uint8 alpha, | 196 uint8 alpha, |
193 SkXfermode::Mode mode, | 197 SkXfermode::Mode mode, |
194 VideoRotation video_rotation) { | 198 VideoRotation video_rotation) { |
195 if (alpha == 0) { | 199 if (alpha == 0) { |
196 return; | 200 return; |
197 } | 201 } |
198 | 202 |
199 SkRect dest; | 203 SkRect dest; |
200 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 204 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |
201 | 205 |
202 SkPaint paint; | 206 SkPaint paint; |
203 paint.setAlpha(alpha); | 207 paint.setAlpha(alpha); |
204 | 208 |
205 // Paint black rectangle if there isn't a frame available or the | 209 // Paint black rectangle if there isn't a frame available or the |
206 // frame has an unexpected format. | 210 // frame has an unexpected format. |
207 if (!video_frame || !IsYUVOrNative(video_frame->format())) { | 211 if (!video_frame || !IsYUVOrNative(video_frame->format())) { |
208 canvas->drawRect(dest, paint); | 212 canvas->drawRect(dest, paint); |
209 return; | 213 return; |
210 } | 214 } |
211 | 215 |
| 216 // If we have a hardware accelerated canvas, we can try to do YUV conversion |
| 217 // directly from our frame to the output canvas. |
| 218 if (canvas->getGrContext() && |
| 219 HardwarePaint( |
| 220 video_frame, canvas->getGrContext(), dest, mode, video_rotation)) { |
| 221 // If HardwarePaint() succeeded, then we're all done! |
| 222 return; |
| 223 } |
| 224 |
212 // Check if we should convert and update |last_frame_|. | 225 // Check if we should convert and update |last_frame_|. |
213 if (last_frame_.isNull() || | 226 if (last_frame_.isNull() || |
214 video_frame->timestamp() != last_frame_timestamp_) { | 227 video_frame->timestamp() != last_frame_timestamp_) { |
215 ConvertVideoFrameToBitmap(video_frame, &last_frame_); | 228 ConvertVideoFrameToBitmap(video_frame, &last_frame_); |
216 | 229 |
217 switch (video_rotation) { | 230 switch (video_rotation) { |
218 case VIDEO_ROTATION_0: | 231 case VIDEO_ROTATION_0: |
219 break; | 232 break; |
220 case VIDEO_ROTATION_90: | 233 case VIDEO_ROTATION_90: |
221 last_frame_ = SkBitmapOperations::Rotate( | 234 last_frame_ = SkBitmapOperations::Rotate( |
(...skipping 22 matching lines...) Expand all Loading... |
244 void SkCanvasVideoRenderer::Copy(media::VideoFrame* video_frame, | 257 void SkCanvasVideoRenderer::Copy(media::VideoFrame* video_frame, |
245 SkCanvas* canvas) { | 258 SkCanvas* canvas) { |
246 Paint(video_frame, | 259 Paint(video_frame, |
247 canvas, | 260 canvas, |
248 video_frame->visible_rect(), | 261 video_frame->visible_rect(), |
249 0xff, | 262 0xff, |
250 SkXfermode::kSrc_Mode, | 263 SkXfermode::kSrc_Mode, |
251 media::VIDEO_ROTATION_0); | 264 media::VIDEO_ROTATION_0); |
252 } | 265 } |
253 | 266 |
| 267 bool SkCanvasVideoRenderer::HardwarePaint(media::VideoFrame* video_frame, |
| 268 GrContext* gr, |
| 269 const SkRect& dest_rect, |
| 270 SkXfermode::Mode mode, |
| 271 VideoRotation video_rotation) { |
| 272 if (!IsYUV(video_frame->format()) || |
| 273 video_frame->format() == VideoFrame::YV12A) |
| 274 return false; |
| 275 |
| 276 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |
| 277 video_frame->stride(media::VideoFrame::kVPlane)); |
| 278 |
| 279 // Wrap our planes in SkBitmaps. |
| 280 if (video_frame->timestamp() != yuv_planes_timestamp_) { |
| 281 yuv_planes_[0].installPixels( |
| 282 SkImageInfo::MakeA8(video_frame->coded_size().width(), |
| 283 video_frame->coded_size().height()), |
| 284 video_frame->data(VideoFrame::kYPlane), |
| 285 video_frame->stride(VideoFrame::kYPlane)); |
| 286 yuv_planes_[1].installPixels( |
| 287 SkImageInfo::MakeA8(video_frame->coded_size().width() / 2, |
| 288 video_frame->coded_size().height() / 2), |
| 289 video_frame->data(VideoFrame::kUPlane), |
| 290 video_frame->stride(VideoFrame::kUPlane)); |
| 291 yuv_planes_[2].installPixels( |
| 292 SkImageInfo::MakeA8(video_frame->coded_size().width() / 2, |
| 293 video_frame->coded_size().height() / 2), |
| 294 video_frame->data(VideoFrame::kVPlane), |
| 295 video_frame->stride(VideoFrame::kVPlane)); |
| 296 } |
| 297 |
| 298 // Populate GrTextures from the bitmaps. We let Ganesh handle caching here. |
| 299 GrTexture* planes[3]; |
| 300 planes[0] = GrLockAndRefCachedBitmapTexture(gr, yuv_planes_[0], NULL); |
| 301 planes[1] = GrLockAndRefCachedBitmapTexture(gr, yuv_planes_[1], NULL); |
| 302 planes[2] = GrLockAndRefCachedBitmapTexture(gr, yuv_planes_[2], NULL); |
| 303 |
| 304 skia::RefPtr<GrEffect> effect = skia::AdoptRef<GrEffect>( |
| 305 GrYUVtoRGBEffect::Create(planes[0], planes[1], planes[2])); |
| 306 |
| 307 if (!effect) |
| 308 return false; |
| 309 |
| 310 SkXfermode::Coeff src, dest; |
| 311 if (!SkXfermode::ModeAsCoeff(mode, &src, &dest)) |
| 312 return false; |
| 313 |
| 314 GrPaint paint; |
| 315 paint.addColorEffect(effect.get()); |
| 316 paint.setBlendFunc(sk_blend_to_grblend(src), sk_blend_to_grblend(dest)); |
| 317 |
| 318 GrContext::AutoMatrix auto_matrix; |
| 319 auto_matrix.setIdentity(gr, &paint); |
| 320 SkMatrix rotation; |
| 321 |
| 322 switch (video_rotation) { |
| 323 case VIDEO_ROTATION_0: |
| 324 rotation.reset(); |
| 325 break; |
| 326 case VIDEO_ROTATION_90: |
| 327 rotation.setRotate(90); |
| 328 rotation.postTranslate(video_frame->coded_size().height(), 0); |
| 329 break; |
| 330 case VIDEO_ROTATION_180: |
| 331 rotation.setRotate(180); |
| 332 rotation.postTranslate(video_frame->coded_size().width(), |
| 333 video_frame->coded_size().height()); |
| 334 break; |
| 335 case VIDEO_ROTATION_270: |
| 336 rotation.setRotate(270); |
| 337 rotation.postTranslate(0, video_frame->coded_size().width()); |
| 338 break; |
| 339 } |
| 340 |
| 341 gr->concatMatrix(rotation); |
| 342 gr->drawRect(paint, dest_rect); |
| 343 |
| 344 GrUnlockAndUnrefCachedBitmapTexture(planes[0]); |
| 345 GrUnlockAndUnrefCachedBitmapTexture(planes[1]); |
| 346 GrUnlockAndUnrefCachedBitmapTexture(planes[2]); |
| 347 |
| 348 gr->flush(); |
| 349 |
| 350 yuv_planes_timestamp_ = video_frame->timestamp(); |
| 351 |
| 352 return true; |
| 353 } |
| 354 |
254 } // namespace media | 355 } // namespace media |
OLD | NEW |