diff options
Diffstat (limited to 'remoting/base')
-rw-r--r-- | remoting/base/decoder_vp8.cc | 102 | ||||
-rw-r--r-- | remoting/base/decoder_vp8.h | 13 | ||||
-rw-r--r-- | remoting/base/util.cc | 175 | ||||
-rw-r--r-- | remoting/base/util.h | 43 | ||||
-rw-r--r-- | remoting/base/util_unittest.cc | 187 |
5 files changed, 125 insertions, 395 deletions
diff --git a/remoting/base/decoder_vp8.cc b/remoting/base/decoder_vp8.cc index fc6670f..40746913 100644 --- a/remoting/base/decoder_vp8.cc +++ b/remoting/base/decoder_vp8.cc @@ -142,17 +142,71 @@ void DecoderVp8::RefreshRegion(const SkRegion& region) { if (output_size_.height() > static_cast<int>(frame_->height())) output_size_.set(output_size_.width(), frame_->height()); + if (!DoScaling()) { + ConvertRegion(region, &updated_region_); + } else { + ScaleAndConvertRegion(region, &updated_region_); + } +} + +bool DecoderVp8::DoScaling() const { + DCHECK(last_image_); + return !output_size_.equals(last_image_->d_w, last_image_->d_h); +} + +void DecoderVp8::ConvertRegion(const SkRegion& input_region, + SkRegion* output_region) { if (!last_image_) return; - updated_region_.setEmpty(); + output_region->setEmpty(); // Clip based on both the output dimensions and Pepper clip rect. - // ConvertAndScaleYUVToRGB32Rect() requires even X and Y coordinates, so we - // align |clip_rect| to prevent clipping from breaking alignment. We then - // clamp it to the image dimensions, which may lead to odd width & height, - // which we can cope with. + // ConvertYUVToRGB32WithRect() requires even X and Y coordinates, so we align + // |clip_rect| to prevent clipping from breaking alignment. We then clamp it + // to the image dimensions, which may lead to odd width & height, which we + // can cope with. SkIRect clip_rect = AlignRect(clip_rect_); + if (!clip_rect.intersect(SkIRect::MakeWH(last_image_->d_w, last_image_->d_h))) + return; + + uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); + const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); + + for (SkRegion::Iterator i(input_region); !i.done(); i.next()) { + // Align the rectangle so the top-left coordinates are even, for + // ConvertYUVToRGB32WithRect(). + SkIRect dest_rect(AlignRect(i.rect())); + + // Clip the rectangle, preserving alignment since |clip_rect| is aligned. + if (!dest_rect.intersect(clip_rect)) + continue; + + ConvertYUVToRGB32WithRect(last_image_->planes[0], + last_image_->planes[1], + last_image_->planes[2], + output_rgb_buf, + dest_rect, + last_image_->stride[0], + last_image_->stride[1], + output_stride); + + output_region->op(dest_rect, SkRegion::kUnion_Op); + } +} + +void DecoderVp8::ScaleAndConvertRegion(const SkRegion& input_region, + SkRegion* output_region) { + if (!last_image_) + return; + + DCHECK(output_size_.width() <= static_cast<int>(frame_->width())); + DCHECK(output_size_.height() <= static_cast<int>(frame_->height())); + + output_region->setEmpty(); + + // Clip based on both the output dimensions and Pepper clip rect. + SkIRect clip_rect = clip_rect_; if (!clip_rect.intersect(SkIRect::MakeSize(output_size_))) return; @@ -160,30 +214,30 @@ void DecoderVp8::RefreshRegion(const SkRegion& region) { uint8* output_rgb_buf = frame_->data(media::VideoFrame::kRGBPlane); const int output_stride = frame_->stride(media::VideoFrame::kRGBPlane); - for (SkRegion::Iterator i(region); !i.done(); i.next()) { + for (SkRegion::Iterator i(input_region); !i.done(); i.next()) { // Determine the scaled area affected by this rectangle changing. - // Align the rectangle so the top-left coordinates are even, for - // ConvertAndScaleYUVToRGB32Rect(). - SkIRect output_rect = ScaleRect(AlignRect(i.rect()), - image_size, output_size_); + SkIRect output_rect = ScaleRect(i.rect(), image_size, output_size_); if (!output_rect.intersect(clip_rect)) continue; // The scaler will not to read outside the input dimensions. - ConvertAndScaleYUVToRGB32Rect(last_image_->planes[0], - last_image_->planes[1], - last_image_->planes[2], - last_image_->stride[0], - last_image_->stride[1], - image_size, - SkIRect::MakeSize(image_size), - output_rgb_buf, - output_stride, - output_size_, - SkIRect::MakeSize(output_size_), - output_rect); - - updated_region_.op(output_rect, SkRegion::kUnion_Op); + media::ScaleYUVToRGB32WithRect(last_image_->planes[0], + last_image_->planes[1], + last_image_->planes[2], + output_rgb_buf, + image_size.width(), + image_size.height(), + output_size_.width(), + output_size_.height(), + output_rect.x(), + output_rect.y(), + output_rect.right(), + output_rect.bottom(), + last_image_->stride[0], + last_image_->stride[1], + output_stride); + + output_region->op(output_rect, SkRegion::kUnion_Op); } } diff --git a/remoting/base/decoder_vp8.h b/remoting/base/decoder_vp8.h index 0549f03..76fd547 100644 --- a/remoting/base/decoder_vp8.h +++ b/remoting/base/decoder_vp8.h @@ -35,6 +35,19 @@ class DecoderVp8 : public Decoder { kError, }; + // Return true if scaling is enabled + bool DoScaling() const; + + // Perform color space conversion on the specified region. + // Writes the updated region to |output_region|. + void ConvertRegion(const SkRegion& region, + SkRegion* output_region); + + // Perform scaling and color space conversion on the specified + // region. Writes the updated rectangles to |output_region|. + void ScaleAndConvertRegion(const SkRegion& region, + SkRegion* output_region); + // The internal state of the decoder. State state_; diff --git a/remoting/base/util.cc b/remoting/base/util.cc index 30691ea..486b6a3 100644 --- a/remoting/base/util.cc +++ b/remoting/base/util.cc @@ -11,7 +11,6 @@ #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; @@ -49,15 +48,38 @@ 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, @@ -84,126 +106,6 @@ 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); } @@ -251,31 +153,4 @@ 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 diff --git a/remoting/base/util.h b/remoting/base/util.h index c4621cc..c05ef2f 100644 --- a/remoting/base/util.h +++ b/remoting/base/util.h @@ -18,33 +18,16 @@ std::string GetTimestampString(); // TODO(sergeyu): Move these methods to media. int GetBytesPerPixel(media::VideoFrame::Format format); -// Convert and scale YUV to RGB32 on a specific rectangle. The source and -// destination buffers are assumed to contain only |source_buffer_rect| and -// |dest_buffer_rect| areas correspondingly. The scaling factor is determined -// as ratio between |dest_size| and |source_size|. The target rectangle -// |dect_rect| is specified in the destination coordinates. -// -// |source_buffer_rect| and |dest_buffer_rect| must fall entirely within -// the source and destination dimensions, respectively. |dest_rect| must be -// completely contained within the source and destinations buffers boundaries -// including the case when scaling is requested. -// -// N.B. The top left corner coordinates of YUV buffer should have even X and Y -// coordinates. -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); +// Convert YUV to RGB32 on a specific rectangle. +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); -// Convert RGB32 to YUV on a specific rectangle. void ConvertRGB32ToYUVWithRect(const uint8* rgb_plane, uint8* y_plane, uint8* u_plane, @@ -77,14 +60,6 @@ void CopyRect(const uint8* src_plane, int bytes_per_pixel, const SkIRect& rect); -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); - } // namespace remoting #endif // REMOTING_BASE_UTIL_H_ diff --git a/remoting/base/util_unittest.cc b/remoting/base/util_unittest.cc deleted file mode 100644 index 24e628d..0000000 --- a/remoting/base/util_unittest.cc +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <algorithm> - -#include "remoting/base/util.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/skia/include/core/SkRect.h" -#include "third_party/skia/include/core/SkSize.h" - -static const int kWidth = 32 ; -static const int kHeight = 24 ; -static const int kBytesPerPixel = 4; -static const int kYStride = kWidth; -static const int kUvStride = kWidth / 2; -static const int kRgbStride = kWidth * kBytesPerPixel; -static const uint32 kFillColor = 0xffffff; - -namespace remoting { - -class YuvToRgbTester { - public: - YuvToRgbTester() { - yuv_buffer_size_ = (kYStride + kUvStride) * kHeight; - yuv_buffer_.reset(new uint8[yuv_buffer_size_]); - yplane_ = yuv_buffer_.get(); - uplane_ = yplane_ + (kYStride * kHeight); - vplane_ = uplane_ + (kUvStride * kHeight / 2); - - rgb_buffer_size_ = kWidth * kHeight * kBytesPerPixel; - rgb_buffer_.reset(new uint8[rgb_buffer_size_]); - - ResetYuvBuffer(); - ResetRgbBuffer(); - } - - ~YuvToRgbTester() {} - - void ResetYuvBuffer() { - memset(yuv_buffer_.get(), 0, yuv_buffer_size_); - } - - void ResetRgbBuffer() { - memset(rgb_buffer_.get(), 0, rgb_buffer_size_); - } - - void FillRgbBuffer(const SkIRect& rect) { - uint32* ptr = reinterpret_cast<uint32*>( - rgb_buffer_.get() + (rect.top() * kRgbStride) + - (rect.left() * kBytesPerPixel)); - int width = rect.width(); - for (int height = rect.height(); height > 0; --height) { - std::fill(ptr, ptr + width, kFillColor); - ptr += kRgbStride / kBytesPerPixel; - } - } - - // Check the the desination buffer is filled within expected bounds. - void CheckRgbBuffer(const SkIRect& rect) { - uint32* ptr = reinterpret_cast<uint32*>(rgb_buffer_.get()); - for (int y = 0; y < kHeight; ++y) { - if (y < rect.top() || rect.bottom() <= y) { - // The whole line should be intact. - EXPECT_EQ((ptrdiff_t)kWidth, - std::count(ptr, ptr + kWidth, 0u)); - } else { - // The space before the painted rectangle should be intact. - EXPECT_EQ((ptrdiff_t)rect.left(), - std::count(ptr, ptr + rect.left(), 0u)); - - // All pixels of the target rectangle should be touched. - EXPECT_EQ(ptr + rect.right(), - std::find(ptr + rect.left(), ptr + rect.right(), 0u)); - - // The space after the painted rectangle should be intact. - EXPECT_EQ((ptrdiff_t)kWidth - rect.right(), - std::count(ptr + rect.right(), ptr + kWidth, 0u)); - } - ptr += kRgbStride / kBytesPerPixel; - } - } - - void RunTest(const SkISize dest_size, const SkIRect& rect) { - ASSERT_TRUE(SkIRect::MakeSize(dest_size).contains(rect)); - - // Reset buffers. - ResetYuvBuffer(); - ResetRgbBuffer(); - FillRgbBuffer(rect); - - // RGB -> YUV - ConvertRGB32ToYUVWithRect(rgb_buffer_.get(), - yplane_, - uplane_, - vplane_, - 0, - 0, - kWidth, - kHeight, - kRgbStride, - kYStride, - kUvStride); - - // Reset RGB buffer and do opposite conversion. - ResetRgbBuffer(); - ConvertAndScaleYUVToRGB32Rect(yplane_, - uplane_, - vplane_, - kYStride, - kUvStride, - SkISize::Make(kWidth, kHeight), - SkIRect::MakeWH(kWidth, kHeight), - rgb_buffer_.get(), - kRgbStride, - dest_size, - SkIRect::MakeSize(dest_size), - rect); - - // Check if it worked out. - CheckRgbBuffer(rect); - } - - void TestBasicConversion() { - // Whole buffer. - RunTest(SkISize::Make(kWidth, kHeight), SkIRect::MakeWH(kWidth, kHeight)); - } - - private: - size_t yuv_buffer_size_; - scoped_array<uint8> yuv_buffer_; - uint8* yplane_; - uint8* uplane_; - uint8* vplane_; - - size_t rgb_buffer_size_; - scoped_array<uint8> rgb_buffer_; - - DISALLOW_COPY_AND_ASSIGN(YuvToRgbTester); -}; - -TEST(YuvToRgbTest, BasicConversion) { - YuvToRgbTester tester; - tester.TestBasicConversion(); -} - -TEST(YuvToRgbTest, Clipping) { - YuvToRgbTester tester; - - SkISize dest_size = SkISize::Make(kWidth, kHeight); - SkIRect rect = SkIRect::MakeLTRB(0, 0, kWidth - 1, kHeight - 1); - for (int i = 0; i < 16; ++i) { - SkIRect dest_rect = rect; - if ((i & 1) != 0) - dest_rect.fLeft += 1; - if ((i & 2) != 0) - dest_rect.fTop += 1; - if ((i & 4) != 0) - dest_rect.fRight += 1; - if ((i & 8) != 0) - dest_rect.fBottom += 1; - - tester.RunTest(dest_size, dest_rect); - } -} - -TEST(YuvToRgbTest, ClippingAndScaling) { - YuvToRgbTester tester; - - SkISize dest_size = SkISize::Make(kWidth - 10, kHeight - 10); - SkIRect rect = SkIRect::MakeLTRB(5, 5, kWidth - 11, kHeight - 11); - for (int i = 0; i < 16; ++i) { - SkIRect dest_rect = rect; - if ((i & 1) != 0) - dest_rect.fLeft += 1; - if ((i & 2) != 0) - dest_rect.fTop += 1; - if ((i & 4) != 0) - dest_rect.fRight += 1; - if ((i & 8) != 0) - dest_rect.fBottom += 1; - - tester.RunTest(dest_size, dest_rect); - } -} - -} // namespace remoting |