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

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

Issue 289373011: Support for YUV 4:4:4 subsampling. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Try that again. 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 | « media/filters/ffmpeg_video_decoder.cc ('k') | no next file » | 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"
(...skipping 11 matching lines...) Expand all
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::I420 || 33 format == media::VideoFrame::I420 ||
34 format == media::VideoFrame::YV12A ||
35 format == media::VideoFrame::YV12J ||
36 format == media::VideoFrame::YV24;
37 }
38
39 static bool IsFastPaintYUV(media::VideoFrame::Format format) {
40 return format == media::VideoFrame::YV12 ||
33 format == media::VideoFrame::YV16 || 41 format == media::VideoFrame::YV16 ||
42 format == media::VideoFrame::I420 ||
34 format == media::VideoFrame::YV12J; 43 format == media::VideoFrame::YV12J;
35 } 44 }
36 45
37 static bool IsEitherYUVOrNative(media::VideoFrame::Format format) { 46 static bool IsYUVOrNative(media::VideoFrame::Format format) {
38 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE; 47 return IsYUV(format) || format == media::VideoFrame::NATIVE_TEXTURE;
39 } 48 }
40 49
41 static bool IsEitherYUVOrYUVA(media::VideoFrame::Format format) {
42 return IsYUV(format) || format == media::VideoFrame::YV12A;
43 }
44
45 static bool IsEitherYUVOrYUVAOrNative(media::VideoFrame::Format format) {
46 return IsEitherYUVOrNative(format) || format == media::VideoFrame::YV12A;
47 }
48
49 // CanFastPaint is a helper method to determine the conditions for fast 50 // CanFastPaint is a helper method to determine the conditions for fast
50 // painting. The conditions are: 51 // painting. The conditions are:
51 // 1. No skew in canvas matrix. 52 // 1. No skew in canvas matrix.
52 // 2. No flipping nor mirroring. 53 // 2. No flipping nor mirroring.
53 // 3. Canvas has pixel format ARGB8888. 54 // 3. Canvas has pixel format ARGB8888.
54 // 4. Canvas is opaque. 55 // 4. Canvas is opaque.
55 // 5. Frame format is YV12, I420 or YV16. 56 // 5. Frame format is YV12, I420 or YV16.
56 // 57 //
57 // TODO(hclam): The fast paint method should support flipping and mirroring. 58 // TODO(hclam): The fast paint method should support flipping and mirroring.
58 // Disable the flipping and mirroring checks once we have it. 59 // Disable the flipping and mirroring checks once we have it.
59 static bool CanFastPaint(SkCanvas* canvas, uint8 alpha, 60 static bool CanFastPaint(SkCanvas* canvas, uint8 alpha,
60 media::VideoFrame::Format format) { 61 media::VideoFrame::Format format) {
61 if (alpha != 0xFF || !IsYUV(format)) 62 if (alpha != 0xFF || !IsFastPaintYUV(format))
62 return false; 63 return false;
63 64
64 const SkMatrix& total_matrix = canvas->getTotalMatrix(); 65 const SkMatrix& total_matrix = canvas->getTotalMatrix();
65 // Perform the following checks here: 66 // Perform the following checks here:
66 // 1. Check for skewing factors of the transformation matrix. They should be 67 // 1. Check for skewing factors of the transformation matrix. They should be
67 // zero. 68 // zero.
68 // 2. Check for mirroring and flipping. Make sure they are greater than zero. 69 // 2. Check for mirroring and flipping. Make sure they are greater than zero.
69 if (SkScalarNearlyZero(total_matrix.getSkewX()) && 70 if (SkScalarNearlyZero(total_matrix.getSkewX()) &&
70 SkScalarNearlyZero(total_matrix.getSkewY()) && 71 SkScalarNearlyZero(total_matrix.getSkewY()) &&
71 total_matrix.getScaleX() > 0 && 72 total_matrix.getScaleX() > 0 &&
72 total_matrix.getScaleY() > 0) { 73 total_matrix.getScaleY() > 0) {
73 SkBaseDevice* device = canvas->getDevice(); 74 SkBaseDevice* device = canvas->getDevice();
74 const SkBitmap::Config config = device->config(); 75 const SkBitmap::Config config = device->config();
75 76
76 if (config == SkBitmap::kARGB_8888_Config && device->isOpaque()) { 77 if (config == SkBitmap::kARGB_8888_Config && device->isOpaque()) {
77 return true; 78 return true;
78 } 79 }
79 } 80 }
80 81
81 return false; 82 return false;
82 } 83 }
83 84
84 // Fast paint does YUV => RGB, scaling, blitting all in one step into the 85 // 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 // canvas. It's not always safe and appropriate to perform fast paint.
86 // CanFastPaint() is used to determine the conditions. 87 // CanFastPaint() is used to determine the conditions.
87 static void FastPaint( 88 static void FastPaint(
88 const scoped_refptr<media::VideoFrame>& video_frame, 89 const scoped_refptr<media::VideoFrame>& video_frame,
89 SkCanvas* canvas, 90 SkCanvas* canvas,
90 const SkRect& dest_rect) { 91 const SkRect& dest_rect) {
91 DCHECK(IsYUV(video_frame->format())) << video_frame->format(); 92 DCHECK(IsFastPaintYUV(video_frame->format())) << video_frame->format();
92 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), 93 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
93 video_frame->stride(media::VideoFrame::kVPlane)); 94 video_frame->stride(media::VideoFrame::kVPlane));
94 95
95 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); 96 const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true);
96 media::YUVType yuv_type = media::YV16; 97 media::YUVType yuv_type = media::YV16;
97 int y_shift = 0; 98 int y_shift = 0;
98 if (video_frame->format() == media::VideoFrame::YV12 || 99 if (video_frame->format() == media::VideoFrame::YV12 ||
99 video_frame->format() == media::VideoFrame::I420 || 100 video_frame->format() == media::VideoFrame::I420) {
100 video_frame->format() == media::VideoFrame::YV12A) {
101 yuv_type = media::YV12; 101 yuv_type = media::YV12;
102 y_shift = 1; 102 y_shift = 1;
103 } 103 }
104 104
105 if (video_frame->format() == media::VideoFrame::YV12J) { 105 if (video_frame->format() == media::VideoFrame::YV12J) {
106 yuv_type = media::YV12J; 106 yuv_type = media::YV12J;
107 y_shift = 1; 107 y_shift = 1;
108 } 108 }
109 109
110 // Transform the destination rectangle to local coordinates. 110 // Transform the destination rectangle to local coordinates.
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 media::FILTER_BILINEAR); 244 media::FILTER_BILINEAR);
245 bitmap.unlockPixels(); 245 bitmap.unlockPixels();
246 } 246 }
247 247
248 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. 248 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data.
249 // 249 //
250 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. 250 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|.
251 static void ConvertVideoFrameToBitmap( 251 static void ConvertVideoFrameToBitmap(
252 const scoped_refptr<media::VideoFrame>& video_frame, 252 const scoped_refptr<media::VideoFrame>& video_frame,
253 SkBitmap* bitmap) { 253 SkBitmap* bitmap) {
254 DCHECK(IsEitherYUVOrYUVAOrNative(video_frame->format())) 254 DCHECK(IsYUVOrNative(video_frame->format()))
255 << video_frame->format(); 255 << video_frame->format();
256 if (IsEitherYUVOrYUVA(video_frame->format())) { 256 if (IsYUV(video_frame->format())) {
257 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), 257 DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane),
258 video_frame->stride(media::VideoFrame::kVPlane)); 258 video_frame->stride(media::VideoFrame::kVPlane));
259 } 259 }
260 260
261 // Check if |bitmap| needs to be (re)allocated. 261 // Check if |bitmap| needs to be (re)allocated.
262 if (bitmap->isNull() || 262 if (bitmap->isNull() ||
263 bitmap->width() != video_frame->visible_rect().width() || 263 bitmap->width() != video_frame->visible_rect().width() ||
264 bitmap->height() != video_frame->visible_rect().height()) { 264 bitmap->height() != video_frame->visible_rect().height()) {
265 bitmap->setConfig(SkBitmap::kARGB_8888_Config, 265 bitmap->setConfig(SkBitmap::kARGB_8888_Config,
266 video_frame->visible_rect().width(), 266 video_frame->visible_rect().width(),
267 video_frame->visible_rect().height()); 267 video_frame->visible_rect().height());
268 bitmap->allocPixels(); 268 bitmap->allocPixels();
269 bitmap->setIsVolatile(true); 269 bitmap->setIsVolatile(true);
270 } 270 }
271 271
272 bitmap->lockPixels(); 272 bitmap->lockPixels();
273 273
274 size_t y_offset = 0; 274 size_t y_offset = 0;
275 size_t uv_offset = 0; 275 size_t uv_offset = 0;
276 if (IsEitherYUVOrYUVA(video_frame->format())) { 276 if (IsYUV(video_frame->format())) {
277 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1; 277 int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1;
278 // Use the "left" and "top" of the destination rect to locate the offset 278 // Use the "left" and "top" of the destination rect to locate the offset
279 // in Y, U and V planes. 279 // in Y, U and V planes.
280 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * 280 y_offset = (video_frame->stride(media::VideoFrame::kYPlane) *
281 video_frame->visible_rect().y()) + 281 video_frame->visible_rect().y()) +
282 video_frame->visible_rect().x(); 282 video_frame->visible_rect().x();
283 // For format YV12, there is one U, V value per 2x2 block. 283 // For format YV12, there is one U, V value per 2x2 block.
284 // For format YV16, there is one U, V value per 2x1 block. 284 // For format YV16, there is one U, V value per 2x1 block.
285 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * 285 uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) *
286 (video_frame->visible_rect().y() >> y_shift)) + 286 (video_frame->visible_rect().y() >> y_shift)) +
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 static_cast<uint8*>(bitmap->getPixels()), 343 static_cast<uint8*>(bitmap->getPixels()),
344 video_frame->visible_rect().width(), 344 video_frame->visible_rect().width(),
345 video_frame->visible_rect().height(), 345 video_frame->visible_rect().height(),
346 video_frame->stride(media::VideoFrame::kYPlane), 346 video_frame->stride(media::VideoFrame::kYPlane),
347 video_frame->stride(media::VideoFrame::kUPlane), 347 video_frame->stride(media::VideoFrame::kUPlane),
348 video_frame->stride(media::VideoFrame::kAPlane), 348 video_frame->stride(media::VideoFrame::kAPlane),
349 bitmap->rowBytes(), 349 bitmap->rowBytes(),
350 media::YV12); 350 media::YV12);
351 break; 351 break;
352 352
353 case media::VideoFrame::YV24:
354 libyuv::I444ToARGB(
355 video_frame->data(media::VideoFrame::kYPlane) + y_offset,
356 video_frame->stride(media::VideoFrame::kYPlane),
357 video_frame->data(media::VideoFrame::kUPlane) + uv_offset,
358 video_frame->stride(media::VideoFrame::kUPlane),
359 video_frame->data(media::VideoFrame::kVPlane) + uv_offset,
360 video_frame->stride(media::VideoFrame::kVPlane),
361 static_cast<uint8*>(bitmap->getPixels()),
362 bitmap->rowBytes(),
363 video_frame->visible_rect().width(),
364 video_frame->visible_rect().height());
365 #if SK_R32_SHIFT == 0 && SK_G32_SHIFT == 8 && SK_B32_SHIFT == 16 && \
366 SK_A32_SHIFT == 24
367 libyuv::ARGBToABGR(
368 static_cast<uint8*>(bitmap->getPixels()),
369 bitmap->rowBytes(),
370 static_cast<uint8*>(bitmap->getPixels()),
371 bitmap->rowBytes(),
372 video_frame->visible_rect().width(),
373 video_frame->visible_rect().height());
374 #endif
375 break;
376
353 case media::VideoFrame::NATIVE_TEXTURE: 377 case media::VideoFrame::NATIVE_TEXTURE:
354 DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE); 378 DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE);
355 video_frame->ReadPixelsFromNativeTexture(*bitmap); 379 video_frame->ReadPixelsFromNativeTexture(*bitmap);
356 break; 380 break;
357 381
358 default: 382 default:
359 NOTREACHED(); 383 NOTREACHED();
360 break; 384 break;
361 } 385 }
362 bitmap->notifyPixelsChanged(); 386 bitmap->notifyPixelsChanged();
(...skipping 15 matching lines...) Expand all
378 } 402 }
379 403
380 SkRect dest; 404 SkRect dest;
381 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); 405 dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom());
382 406
383 SkPaint paint; 407 SkPaint paint;
384 paint.setAlpha(alpha); 408 paint.setAlpha(alpha);
385 409
386 // Paint black rectangle if there isn't a frame available or the 410 // Paint black rectangle if there isn't a frame available or the
387 // frame has an unexpected format. 411 // frame has an unexpected format.
388 if (!video_frame || !IsEitherYUVOrYUVAOrNative(video_frame->format())) { 412 if (!video_frame || !IsYUVOrNative(video_frame->format())) {
389 canvas->drawRect(dest, paint); 413 canvas->drawRect(dest, paint);
390 return; 414 return;
391 } 415 }
392 416
393 // Scale and convert to RGB in one step if we can. 417 // Scale and convert to RGB in one step if we can.
394 if (CanFastPaint(canvas, alpha, video_frame->format())) { 418 if (CanFastPaint(canvas, alpha, video_frame->format())) {
395 FastPaint(video_frame, canvas, dest); 419 FastPaint(video_frame, canvas, dest);
396 return; 420 return;
397 } 421 }
398 422
399 // Check if we should convert and update |last_frame_|. 423 // Check if we should convert and update |last_frame_|.
400 if (last_frame_.isNull() || 424 if (last_frame_.isNull() ||
401 video_frame->timestamp() != last_frame_timestamp_) { 425 video_frame->timestamp() != last_frame_timestamp_) {
402 ConvertVideoFrameToBitmap(video_frame, &last_frame_); 426 ConvertVideoFrameToBitmap(video_frame, &last_frame_);
403 last_frame_timestamp_ = video_frame->timestamp(); 427 last_frame_timestamp_ = video_frame->timestamp();
404 } 428 }
405 429
406 // Do a slower paint using |last_frame_|. 430 // Paint using |last_frame_|.
407 paint.setFilterLevel(SkPaint::kLow_FilterLevel); 431 paint.setFilterLevel(SkPaint::kLow_FilterLevel);
408 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); 432 canvas->drawBitmapRect(last_frame_, NULL, dest, &paint);
409 } 433 }
410 434
411 } // namespace media 435 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_video_decoder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698