| 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 "third_party/skia/include/core/SkCanvas.h" |   10 #include "third_party/skia/include/core/SkCanvas.h" | 
|   11 #include "third_party/skia/include/core/SkDevice.h" |   11 #include "third_party/skia/include/core/SkDevice.h" | 
|   12  |   12  | 
|   13 namespace media { |   13 namespace media { | 
|   14  |   14  | 
|   15 static bool IsEitherYV12OrYV16(media::VideoFrame::Format format) { |   15 static bool IsEitherYV12OrYV16(media::VideoFrame::Format format) { | 
|   16   return format == media::VideoFrame::YV12 || format == media::VideoFrame::YV16; |   16   return format == media::VideoFrame::YV12 || format == media::VideoFrame::YV16; | 
|   17 } |   17 } | 
|   18  |   18  | 
|   19 static bool IsEitherYV12OrYV16OrNative(media::VideoFrame::Format format) { |   19 static bool IsEitherYV12OrYV16OrNative(media::VideoFrame::Format format) { | 
|   20   return IsEitherYV12OrYV16(format) || |   20   return IsEitherYV12OrYV16(format) || | 
|   21       format == media::VideoFrame::NATIVE_TEXTURE; |   21       format == media::VideoFrame::NATIVE_TEXTURE; | 
|   22 } |   22 } | 
|   23  |   23  | 
 |   24 static bool IsEitherYV12OrYV12AOrYV16(media::VideoFrame::Format format) { | 
 |   25   return IsEitherYV12OrYV16(format) || | 
 |   26       format == media::VideoFrame::YV12A; | 
 |   27 } | 
 |   28  | 
 |   29 static bool IsEitherYV12OrYV12AOrYV16OrNative( | 
 |   30     media::VideoFrame::Format format) { | 
 |   31   return IsEitherYV12OrYV16OrNative(format) || | 
 |   32       format == media::VideoFrame::YV12A; | 
 |   33 } | 
 |   34  | 
|   24 // CanFastPaint is a helper method to determine the conditions for fast |   35 // CanFastPaint is a helper method to determine the conditions for fast | 
|   25 // painting. The conditions are: |   36 // painting. The conditions are: | 
|   26 // 1. No skew in canvas matrix. |   37 // 1. No skew in canvas matrix. | 
|   27 // 2. No flipping nor mirroring. |   38 // 2. No flipping nor mirroring. | 
|   28 // 3. Canvas has pixel format ARGB8888. |   39 // 3. Canvas has pixel format ARGB8888. | 
|   29 // 4. Canvas is opaque. |   40 // 4. Canvas is opaque. | 
|   30 // 5. Frame format is YV12 or YV16. |   41 // 5. Frame format is YV12 or YV16. | 
|   31 // |   42 // | 
|   32 // TODO(hclam): The fast paint method should support flipping and mirroring. |   43 // TODO(hclam): The fast paint method should support flipping and mirroring. | 
|   33 // Disable the flipping and mirroring checks once we have it. |   44 // Disable the flipping and mirroring checks once we have it. | 
| (...skipping 29 matching lines...) Expand all  Loading... | 
|   63     const scoped_refptr<media::VideoFrame>& video_frame, |   74     const scoped_refptr<media::VideoFrame>& video_frame, | 
|   64     SkCanvas* canvas, |   75     SkCanvas* canvas, | 
|   65     const SkRect& dest_rect) { |   76     const SkRect& dest_rect) { | 
|   66   DCHECK(IsEitherYV12OrYV16(video_frame->format())) << video_frame->format(); |   77   DCHECK(IsEitherYV12OrYV16(video_frame->format())) << video_frame->format(); | 
|   67   DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |   78   DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 
|   68             video_frame->stride(media::VideoFrame::kVPlane)); |   79             video_frame->stride(media::VideoFrame::kVPlane)); | 
|   69  |   80  | 
|   70   const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); |   81   const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(true); | 
|   71   media::YUVType yuv_type = media::YV16; |   82   media::YUVType yuv_type = media::YV16; | 
|   72   int y_shift = 0; |   83   int y_shift = 0; | 
|   73   if (video_frame->format() == media::VideoFrame::YV12) { |   84   if (video_frame->format() == media::VideoFrame::YV12 || | 
 |   85       video_frame->format() == media::VideoFrame::YV12A) { | 
|   74     yuv_type = media::YV12; |   86     yuv_type = media::YV12; | 
|   75     y_shift = 1; |   87     y_shift = 1; | 
|   76   } |   88   } | 
|   77  |   89  | 
|   78   // Transform the destination rectangle to local coordinates. |   90   // Transform the destination rectangle to local coordinates. | 
|   79   const SkMatrix& local_matrix = canvas->getTotalMatrix(); |   91   const SkMatrix& local_matrix = canvas->getTotalMatrix(); | 
|   80   SkRect local_dest_rect; |   92   SkRect local_dest_rect; | 
|   81   local_matrix.mapRect(&local_dest_rect, dest_rect); |   93   local_matrix.mapRect(&local_dest_rect, dest_rect); | 
|   82  |   94  | 
|   83   // After projecting the destination rectangle to local coordinates, round |   95   // After projecting the destination rectangle to local coordinates, round | 
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  163                          media::FILTER_BILINEAR); |  175                          media::FILTER_BILINEAR); | 
|  164   bitmap.unlockPixels(); |  176   bitmap.unlockPixels(); | 
|  165 } |  177 } | 
|  166  |  178  | 
|  167 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. |  179 // Converts a VideoFrame containing YUV data to a SkBitmap containing RGB data. | 
|  168 // |  180 // | 
|  169 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. |  181 // |bitmap| will be (re)allocated to match the dimensions of |video_frame|. | 
|  170 static void ConvertVideoFrameToBitmap( |  182 static void ConvertVideoFrameToBitmap( | 
|  171     const scoped_refptr<media::VideoFrame>& video_frame, |  183     const scoped_refptr<media::VideoFrame>& video_frame, | 
|  172     SkBitmap* bitmap) { |  184     SkBitmap* bitmap) { | 
|  173   DCHECK(IsEitherYV12OrYV16OrNative(video_frame->format())) |  185   DCHECK(IsEitherYV12OrYV12AOrYV16OrNative(video_frame->format())) | 
|  174       << video_frame->format(); |  186       << video_frame->format(); | 
|  175   if (IsEitherYV12OrYV16(video_frame->format())) { |  187   if (IsEitherYV12OrYV12AOrYV16(video_frame->format())) { | 
|  176     DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), |  188     DCHECK_EQ(video_frame->stride(media::VideoFrame::kUPlane), | 
|  177               video_frame->stride(media::VideoFrame::kVPlane)); |  189               video_frame->stride(media::VideoFrame::kVPlane)); | 
|  178   } |  190   } | 
|  179  |  191  | 
|  180   // Check if |bitmap| needs to be (re)allocated. |  192   // Check if |bitmap| needs to be (re)allocated. | 
|  181   if (bitmap->isNull() || |  193   if (bitmap->isNull() || | 
|  182       bitmap->width() != video_frame->visible_rect().width() || |  194       bitmap->width() != video_frame->visible_rect().width() || | 
|  183       bitmap->height() != video_frame->visible_rect().height()) { |  195       bitmap->height() != video_frame->visible_rect().height()) { | 
|  184     bitmap->setConfig(SkBitmap::kARGB_8888_Config, |  196     bitmap->setConfig(SkBitmap::kARGB_8888_Config, | 
|  185                       video_frame->visible_rect().width(), |  197                       video_frame->visible_rect().width(), | 
|  186                       video_frame->visible_rect().height()); |  198                       video_frame->visible_rect().height()); | 
|  187     bitmap->allocPixels(); |  199     bitmap->allocPixels(); | 
|  188     bitmap->setIsVolatile(true); |  200     bitmap->setIsVolatile(true); | 
|  189   } |  201   } | 
|  190  |  202  | 
|  191   bitmap->lockPixels(); |  203   bitmap->lockPixels(); | 
|  192   if (IsEitherYV12OrYV16(video_frame->format())) { |  | 
|  193     media::YUVType yuv_type = media::YV16; |  | 
|  194     int y_shift = 0; |  | 
|  195     if (video_frame->format() == media::VideoFrame::YV12) { |  | 
|  196       yuv_type = media::YV12; |  | 
|  197       y_shift = 1; |  | 
|  198     } |  | 
|  199  |  204  | 
 |  205   size_t y_offset = 0; | 
 |  206   size_t uv_offset = 0; | 
 |  207   if (IsEitherYV12OrYV12AOrYV16(video_frame->format())) { | 
 |  208     int y_shift = (video_frame->format() == media::VideoFrame::YV16) ? 0 : 1; | 
|  200     // Use the "left" and "top" of the destination rect to locate the offset |  209     // Use the "left" and "top" of the destination rect to locate the offset | 
|  201     // in Y, U and V planes. |  210     // in Y, U and V planes. | 
|  202     size_t y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * |  211     y_offset = (video_frame->stride(media::VideoFrame::kYPlane) * | 
|  203                        video_frame->visible_rect().y()) + |  212                 video_frame->visible_rect().y()) + | 
|  204                       video_frame->visible_rect().x(); |  213                 video_frame->visible_rect().x(); | 
|  205  |  | 
|  206     // For format YV12, there is one U, V value per 2x2 block. |  214     // For format YV12, there is one U, V value per 2x2 block. | 
|  207     // For format YV16, there is one U, V value per 2x1 block. |  215     // For format YV16, there is one U, V value per 2x1 block. | 
|  208     size_t uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * |  216     uv_offset = (video_frame->stride(media::VideoFrame::kUPlane) * | 
|  209                         (video_frame->visible_rect().y() >> y_shift)) + |  217                 (video_frame->visible_rect().y() >> y_shift)) + | 
|  210                        (video_frame->visible_rect().x() >> 1); |  218                 (video_frame->visible_rect().x() >> 1); | 
|  211     uint8* frame_clip_y = |  219   } | 
|  212         video_frame->data(media::VideoFrame::kYPlane) + y_offset; |  220   switch (video_frame->format()) { | 
|  213     uint8* frame_clip_u = |  221     case media::VideoFrame::YV12: | 
|  214         video_frame->data(media::VideoFrame::kUPlane) + uv_offset; |  222       media::ConvertYUVToRGB32( | 
|  215     uint8* frame_clip_v = |  223           video_frame->data(media::VideoFrame::kYPlane) + y_offset, | 
|  216         video_frame->data(media::VideoFrame::kVPlane) + uv_offset; |  224           video_frame->data(media::VideoFrame::kUPlane) + uv_offset, | 
 |  225           video_frame->data(media::VideoFrame::kVPlane) + uv_offset, | 
 |  226           static_cast<uint8*>(bitmap->getPixels()), | 
 |  227           video_frame->visible_rect().width(), | 
 |  228           video_frame->visible_rect().height(), | 
 |  229           video_frame->stride(media::VideoFrame::kYPlane), | 
 |  230           video_frame->stride(media::VideoFrame::kUPlane), | 
 |  231           bitmap->rowBytes(), | 
 |  232           media::YV12); | 
 |  233       break; | 
|  217  |  234  | 
|  218     media::ConvertYUVToRGB32(frame_clip_y, |  235     case media::VideoFrame::YV16: | 
|  219                              frame_clip_u, |  236       media::ConvertYUVToRGB32( | 
|  220                              frame_clip_v, |  237           video_frame->data(media::VideoFrame::kYPlane) + y_offset, | 
|  221                              static_cast<uint8*>(bitmap->getPixels()), |  238           video_frame->data(media::VideoFrame::kUPlane) + uv_offset, | 
|  222                              video_frame->visible_rect().width(), |  239           video_frame->data(media::VideoFrame::kVPlane) + uv_offset, | 
|  223                              video_frame->visible_rect().height(), |  240           static_cast<uint8*>(bitmap->getPixels()), | 
|  224                              video_frame->stride(media::VideoFrame::kYPlane), |  241           video_frame->visible_rect().width(), | 
|  225                              video_frame->stride(media::VideoFrame::kUPlane), |  242           video_frame->visible_rect().height(), | 
|  226                              bitmap->rowBytes(), |  243           video_frame->stride(media::VideoFrame::kYPlane), | 
|  227                              yuv_type); |  244           video_frame->stride(media::VideoFrame::kUPlane), | 
|  228   } else { |  245           bitmap->rowBytes(), | 
|  229     DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE); |  246           media::YV16); | 
|  230     video_frame->ReadPixelsFromNativeTexture(*bitmap); |  247       break; | 
 |  248  | 
 |  249     case media::VideoFrame::YV12A: | 
 |  250       media::ConvertYUVAToARGB( | 
 |  251           video_frame->data(media::VideoFrame::kYPlane) + y_offset, | 
 |  252           video_frame->data(media::VideoFrame::kUPlane) + uv_offset, | 
 |  253           video_frame->data(media::VideoFrame::kVPlane) + uv_offset, | 
 |  254           video_frame->data(media::VideoFrame::kAPlane), | 
 |  255           static_cast<uint8*>(bitmap->getPixels()), | 
 |  256           video_frame->visible_rect().width(), | 
 |  257           video_frame->visible_rect().height(), | 
 |  258           video_frame->stride(media::VideoFrame::kYPlane), | 
 |  259           video_frame->stride(media::VideoFrame::kUPlane), | 
 |  260           video_frame->stride(media::VideoFrame::kAPlane), | 
 |  261           bitmap->rowBytes(), | 
 |  262           media::YV12); | 
 |  263       break; | 
 |  264  | 
 |  265     case media::VideoFrame::NATIVE_TEXTURE: | 
 |  266       DCHECK_EQ(video_frame->format(), media::VideoFrame::NATIVE_TEXTURE); | 
 |  267       video_frame->ReadPixelsFromNativeTexture(*bitmap); | 
 |  268       break; | 
 |  269  | 
 |  270     default: | 
 |  271       NOTREACHED(); | 
 |  272       break; | 
|  231   } |  273   } | 
|  232   bitmap->notifyPixelsChanged(); |  274   bitmap->notifyPixelsChanged(); | 
|  233   bitmap->unlockPixels(); |  275   bitmap->unlockPixels(); | 
|  234 } |  276 } | 
|  235  |  277  | 
|  236 SkCanvasVideoRenderer::SkCanvasVideoRenderer() |  278 SkCanvasVideoRenderer::SkCanvasVideoRenderer() | 
|  237     : last_frame_timestamp_(media::kNoTimestamp()) { |  279     : last_frame_timestamp_(media::kNoTimestamp()) { | 
|  238 } |  280 } | 
|  239  |  281  | 
|  240 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} |  282 SkCanvasVideoRenderer::~SkCanvasVideoRenderer() {} | 
|  241  |  283  | 
|  242 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, |  284 void SkCanvasVideoRenderer::Paint(media::VideoFrame* video_frame, | 
|  243                                   SkCanvas* canvas, |  285                                   SkCanvas* canvas, | 
|  244                                   const gfx::RectF& dest_rect, |  286                                   const gfx::RectF& dest_rect, | 
|  245                                   uint8_t alpha) { |  287                                   uint8_t alpha) { | 
|  246   if (alpha == 0) { |  288   if (alpha == 0) { | 
|  247     return; |  289     return; | 
|  248   } |  290   } | 
|  249  |  291  | 
|  250   SkRect dest; |  292   SkRect dest; | 
|  251   dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); |  293   dest.set(dest_rect.x(), dest_rect.y(), dest_rect.right(), dest_rect.bottom()); | 
|  252  |  294  | 
|  253   SkPaint paint; |  295   SkPaint paint; | 
|  254   paint.setAlpha(alpha); |  296   paint.setAlpha(alpha); | 
|  255  |  297  | 
|  256   // Paint black rectangle if there isn't a frame available or the |  298   // Paint black rectangle if there isn't a frame available or the | 
|  257   // frame has an unexpected format. |  299   // frame has an unexpected format. | 
|  258   if (!video_frame || !IsEitherYV12OrYV16OrNative(video_frame->format())) { |  300   if (!video_frame || | 
 |  301       !IsEitherYV12OrYV12AOrYV16OrNative(video_frame->format())) { | 
|  259     canvas->drawRect(dest, paint); |  302     canvas->drawRect(dest, paint); | 
|  260     return; |  303     return; | 
|  261   } |  304   } | 
|  262  |  305  | 
|  263   // Scale and convert to RGB in one step if we can. |  306   // Scale and convert to RGB in one step if we can. | 
|  264   if (CanFastPaint(canvas, alpha, video_frame->format())) { |  307   if (CanFastPaint(canvas, alpha, video_frame->format())) { | 
|  265     FastPaint(video_frame, canvas, dest); |  308     FastPaint(video_frame, canvas, dest); | 
|  266     return; |  309     return; | 
|  267   } |  310   } | 
|  268  |  311  | 
|  269   // Check if we should convert and update |last_frame_|. |  312   // Check if we should convert and update |last_frame_|. | 
|  270   if (last_frame_.isNull() || |  313   if (last_frame_.isNull() || | 
|  271       video_frame->GetTimestamp() != last_frame_timestamp_) { |  314       video_frame->GetTimestamp() != last_frame_timestamp_) { | 
|  272     ConvertVideoFrameToBitmap(video_frame, &last_frame_); |  315     ConvertVideoFrameToBitmap(video_frame, &last_frame_); | 
|  273     last_frame_timestamp_ = video_frame->GetTimestamp(); |  316     last_frame_timestamp_ = video_frame->GetTimestamp(); | 
|  274   } |  317   } | 
|  275  |  318  | 
|  276   // Do a slower paint using |last_frame_|. |  319   // Do a slower paint using |last_frame_|. | 
|  277   paint.setFilterBitmap(true); |  320   paint.setFilterBitmap(true); | 
|  278   canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); |  321   canvas->drawBitmapRect(last_frame_, NULL, dest, &paint); | 
|  279 } |  322 } | 
|  280  |  323  | 
|  281 }  // namespace media |  324 }  // namespace media | 
| OLD | NEW |