Index: remoting/base/util.cc |
diff --git a/remoting/base/util.cc b/remoting/base/util.cc |
index 486b6a3510e6f42efa1680d449d7363628aa4b14..30691ea065531f9300883092de8dc55d5316b65b 100644 |
--- a/remoting/base/util.cc |
+++ b/remoting/base/util.cc |
@@ -11,6 +11,7 @@ |
#include "base/time.h" |
#include "media/base/video_frame.h" |
#include "media/base/yuv_convert.h" |
+#include "third_party/skia/include/core/SkRegion.h" |
using media::VideoFrame; |
@@ -48,38 +49,15 @@ static int CalculateRGBOffset(int x, int y, int stride) { |
} |
static int CalculateYOffset(int x, int y, int stride) { |
+ DCHECK(((x & 1) == 0) && ((y & 1) == 0)); |
return stride * y + x; |
} |
static int CalculateUVOffset(int x, int y, int stride) { |
+ DCHECK(((x & 1) == 0) && ((y & 1) == 0)); |
return stride * y / 2 + x / 2; |
} |
-void ConvertYUVToRGB32WithRect(const uint8* y_plane, |
- const uint8* u_plane, |
- const uint8* v_plane, |
- uint8* rgb_plane, |
- const SkIRect& rect, |
- int y_stride, |
- int uv_stride, |
- int rgb_stride) { |
- DCHECK((rect.x() & 1) == 0 && (rect.y() & 1) == 0); |
- int rgb_offset = CalculateRGBOffset(rect.left(), rect.top(), rgb_stride); |
- int y_offset = CalculateYOffset(rect.left(), rect.top(), y_stride); |
- int uv_offset = CalculateUVOffset(rect.left(), rect.top(), uv_stride); |
- |
- media::ConvertYUVToRGB32(y_plane + y_offset, |
- u_plane + uv_offset, |
- v_plane + uv_offset, |
- rgb_plane + rgb_offset, |
- rect.width(), |
- rect.height(), |
- y_stride, |
- uv_stride, |
- rgb_stride, |
- media::YV12); |
-} |
- |
void ConvertRGB32ToYUVWithRect(const uint8* rgb_plane, |
uint8* y_plane, |
uint8* u_plane, |
@@ -106,6 +84,126 @@ void ConvertRGB32ToYUVWithRect(const uint8* rgb_plane, |
uv_stride); |
} |
+void ConvertAndScaleYUVToRGB32Rect(const uint8* source_yplane, |
+ const uint8* source_uplane, |
+ const uint8* source_vplane, |
+ int source_ystride, |
+ int source_uvstride, |
+ const SkISize& source_size, |
+ const SkIRect& source_buffer_rect, |
+ uint8* dest_buffer, |
+ int dest_stride, |
+ const SkISize& dest_size, |
+ const SkIRect& dest_buffer_rect, |
+ const SkIRect& dest_rect) { |
+ // N.B. It is caller's responsibility to check if strides are large enough. We |
+ // cannot do it here anyway. |
+ DCHECK(SkIRect::MakeSize(source_size).contains(source_buffer_rect)); |
+ DCHECK(SkIRect::MakeSize(dest_size).contains(dest_buffer_rect)); |
+ DCHECK(dest_buffer_rect.contains(dest_rect)); |
+ DCHECK(ScaleRect(source_buffer_rect, source_size, dest_size). |
+ contains(dest_rect)); |
+ |
+ // If the source and/or destination buffers don't start at (0, 0) |
+ // offset the pointers to pretend we have complete buffers. |
+ int y_offset = - CalculateYOffset(source_buffer_rect.x(), |
+ source_buffer_rect.y(), |
+ source_ystride); |
+ int uv_offset = - CalculateUVOffset(source_buffer_rect.x(), |
+ source_buffer_rect.y(), |
+ source_uvstride); |
+ int rgb_offset = - CalculateRGBOffset(dest_buffer_rect.x(), |
+ dest_buffer_rect.y(), |
+ dest_stride); |
+ |
+ // See if scaling is needed. |
+ if (source_size == dest_size) { |
+ // Calculate the inner rectangle that can be copied by the optimized |
+ // ConvertYUVToRGB32(). |
+ SkIRect inner_rect = |
+ SkIRect::MakeLTRB(RoundToTwosMultiple(dest_rect.left() + 1), |
+ RoundToTwosMultiple(dest_rect.top() + 1), |
+ dest_rect.right(), |
+ dest_rect.bottom()); |
+ |
+ // Offset pointers to point to the top left corner of the inner rectangle. |
+ y_offset += CalculateYOffset(inner_rect.x(), inner_rect.y(), |
+ source_ystride); |
+ uv_offset += CalculateUVOffset(inner_rect.x(), inner_rect.y(), |
+ source_uvstride); |
+ rgb_offset += CalculateRGBOffset(inner_rect.x(), inner_rect.y(), |
+ dest_stride); |
+ |
+ media::ConvertYUVToRGB32(source_yplane + y_offset, |
+ source_uplane + uv_offset, |
+ source_vplane + uv_offset, |
+ dest_buffer + rgb_offset, |
+ inner_rect.width(), |
+ inner_rect.height(), |
+ source_ystride, |
+ source_uvstride, |
+ dest_stride, |
+ media::YV12); |
+ |
+ // Now see if some pixels weren't copied due to alignment. |
+ if (dest_rect != inner_rect) { |
+ SkIRect outer_rect = |
+ SkIRect::MakeLTRB(RoundToTwosMultiple(dest_rect.left()), |
+ RoundToTwosMultiple(dest_rect.top()), |
+ dest_rect.right(), |
+ dest_rect.bottom()); |
+ |
+ SkIPoint offset = SkIPoint::Make(outer_rect.x() - inner_rect.x(), |
+ outer_rect.y() - inner_rect.y()); |
+ |
+ // Offset the pointers to point to the top left corner of the outer |
+ // rectangle. |
+ y_offset += CalculateYOffset(offset.x(), offset.y(), source_ystride); |
+ uv_offset += CalculateUVOffset(offset.x(), offset.y(), source_uvstride); |
+ rgb_offset += CalculateRGBOffset(offset.x(), offset.y(), dest_stride); |
+ |
+ // Draw unaligned edges. |
+ SkRegion edges(dest_rect); |
+ edges.op(inner_rect, SkRegion::kDifference_Op); |
+ for (SkRegion::Iterator i(edges); !i.done(); i.next()) { |
+ SkIRect rect(i.rect()); |
+ rect.offset(- outer_rect.left(), - outer_rect.top()); |
+ media::ScaleYUVToRGB32WithRect(source_yplane + y_offset, |
+ source_uplane + uv_offset, |
+ source_vplane + uv_offset, |
+ dest_buffer + rgb_offset, |
+ source_size.width(), |
+ source_size.height(), |
+ dest_size.width(), |
+ dest_size.height(), |
+ rect.left(), |
+ rect.top(), |
+ rect.right(), |
+ rect.bottom(), |
+ source_ystride, |
+ source_uvstride, |
+ dest_stride); |
+ } |
+ } |
+ } else { |
+ media::ScaleYUVToRGB32WithRect(source_yplane + y_offset, |
+ source_uplane + uv_offset, |
+ source_vplane + uv_offset, |
+ dest_buffer + rgb_offset, |
+ source_size.width(), |
+ source_size.height(), |
+ dest_size.width(), |
+ dest_size.height(), |
+ dest_rect.left(), |
+ dest_rect.top(), |
+ dest_rect.right(), |
+ dest_rect.bottom(), |
+ source_ystride, |
+ source_uvstride, |
+ dest_stride); |
+ } |
+} |
+ |
int RoundToTwosMultiple(int x) { |
return x & (~1); |
} |
@@ -153,4 +251,31 @@ void CopyRect(const uint8* src_plane, |
} |
} |
+void CopyRGB32Rect(const uint8* source_buffer, |
+ int source_stride, |
+ const SkIRect& source_buffer_rect, |
+ uint8* dest_buffer, |
+ int dest_stride, |
+ const SkIRect& dest_buffer_rect, |
+ const SkIRect& dest_rect) { |
+ DCHECK(dest_buffer_rect.contains(dest_rect)); |
+ DCHECK(source_buffer_rect.contains(dest_rect)); |
+ |
+ // Get the address of the starting point. |
+ int source_offset = CalculateRGBOffset(dest_rect.x() - source_buffer_rect.x(), |
+ dest_rect.y() - source_buffer_rect.y(), |
+ source_stride); |
+ int dest_offset = CalculateRGBOffset(dest_rect.x() - dest_buffer_rect.x(), |
+ dest_rect.y() - dest_buffer_rect.y(), |
+ source_stride); |
+ |
+ // Copy bits. |
+ CopyRect(source_buffer + source_offset, |
+ source_stride, |
+ dest_buffer + dest_offset, |
+ dest_stride, |
+ GetBytesPerPixel(media::VideoFrame::RGB32), |
+ SkIRect::MakeWH(dest_rect.width(), dest_rect.height())); |
+} |
+ |
} // namespace remoting |