diff options
author | wjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-19 18:51:01 +0000 |
---|---|---|
committer | wjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-19 18:51:01 +0000 |
commit | 30591e06f6c96933813d700ae255b2182f6e15e5 (patch) | |
tree | 9721347c1de135304b0e2766f7c3a99e6c5fe4bd | |
parent | c667115d4da70673aea8e6ff069872bd1197339c (diff) | |
download | chromium_src-30591e06f6c96933813d700ae255b2182f6e15e5.zip chromium_src-30591e06f6c96933813d700ae255b2182f6e15e5.tar.gz chromium_src-30591e06f6c96933813d700ae255b2182f6e15e5.tar.bz2 |
Add test for RotatePlaneByPixels.
This is a follow-up patch for https://codereview.chromium.org/11860002/
BUG=161417
Review URL: https://codereview.chromium.org/12207190
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@183257 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/base/video_util.cc | 101 | ||||
-rw-r--r-- | media/base/video_util.h | 19 | ||||
-rw-r--r-- | media/base/video_util_unittest.cc | 244 | ||||
-rw-r--r-- | media/video/capture/android/video_capture_device_android.cc | 99 |
4 files changed, 365 insertions, 98 deletions
diff --git a/media/base/video_util.cc b/media/base/video_util.cc index 487c595..d7498ad 100644 --- a/media/base/video_util.cc +++ b/media/base/video_util.cc @@ -85,4 +85,105 @@ void FillYUV(VideoFrame* frame, uint8 y, uint8 u, uint8 v) { } } +void RotatePlaneByPixels( + uint8* src, + uint8* dest, + int width, + int height, + int rotation, // Clockwise. + bool flip_vert, + bool flip_horiz) { + DCHECK((width > 0) && (height > 0) && + ((width & 1) == 0) && ((height & 1) == 0) && + (rotation >= 0) && (rotation < 360) && (rotation % 90 == 0)); + + // Consolidate cases. Only 0 and 90 are left. + if (rotation == 180 || rotation == 270) { + rotation -= 180; + flip_vert = !flip_vert; + flip_horiz = !flip_horiz; + } + + int num_rows = height; + int num_cols = width; + int src_stride = width; + // During pixel copying, the corresponding incremental of dest pointer + // when src pointer moves to next row. + int dest_row_step = width; + // During pixel copying, the corresponding incremental of dest pointer + // when src pointer moves to next column. + int dest_col_step = 1; + + if (rotation == 0) { + if (flip_horiz) { + // Use pixel copying. + dest_col_step = -1; + if (flip_vert) { + // Rotation 180. + dest_row_step = -width; + dest += height * width - 1; + } else { + dest += width - 1; + } + } else { + if (flip_vert) { + // Fast copy by rows. + dest += width * (height - 1); + for (int row = 0; row < height; ++row) { + memcpy(dest, src, width); + src += width; + dest -= width; + } + } else { + memcpy(dest, src, width * height); + } + return; + } + } else if (rotation == 90) { + int offset; + if (width > height) { + offset = (width - height) / 2; + src += offset; + num_rows = num_cols = height; + } else { + offset = (height - width) / 2; + src += width * offset; + num_rows = num_cols = width; + } + + dest_col_step = (flip_vert ? -width : width); + dest_row_step = (flip_horiz ? 1 : -1); + if (flip_horiz) { + if (flip_vert) { + dest += (width > height ? width * (height - 1) + offset : + width * (height - offset - 1)); + } else { + dest += (width > height ? offset : width * offset); + } + } else { + if (flip_vert) { + dest += (width > height ? width * height - offset - 1 : + width * (height - offset) - 1); + } else { + dest += (width > height ? width - offset - 1 : + width * (offset + 1) - 1); + } + } + } else { + NOTREACHED(); + } + + // Copy pixels. + for (int row = 0; row < num_rows; ++row) { + uint8* src_ptr = src; + uint8* dest_ptr = dest; + for (int col = 0; col < num_cols; ++col) { + *dest_ptr = *src_ptr++; + dest_ptr += dest_col_step; + } + src += src_stride; + dest += dest_row_step; + } +} + } // namespace media diff --git a/media/base/video_util.h b/media/base/video_util.h index fd71605..0be1f4c 100644 --- a/media/base/video_util.h +++ b/media/base/video_util.h @@ -37,6 +37,25 @@ MEDIA_EXPORT void CopyPlane(size_t plane, const uint8* source, int stride, // Fills |frame| containing YUV data to the given color values. MEDIA_EXPORT void FillYUV(VideoFrame* frame, uint8 y, uint8 u, uint8 v); +// Rotates |src| plane by |rotation| degree with possible flipping vertically +// and horizontally. +// |rotation| is limited to {0, 90, 180, 270}. +// |width| and |height| are expected to be even numbers. +// Both |src| and |dest| planes are packed and have same |width| and |height|. +// When |width| != |height| and rotated by 90/270, only the maximum square +// portion located in the center is rotated. For example, for width=640 and +// height=480, the rotated area is 480x480 located from row 0 through 479 and +// from column 80 through 559. The leftmost and rightmost 80 columns are +// ignored for both |src| and |dest|. +// The caller is responsible for blanking out the margin area. +MEDIA_EXPORT void RotatePlaneByPixels( + uint8* src, + uint8* dest, + int width, + int height, + int rotation, // Clockwise. + bool flip_vert, + bool flip_horiz); } // namespace media #endif // MEDIA_BASE_VIDEO_UTIL_H_ diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc index d4f2e29..e263762 100644 --- a/media/base/video_util_unittest.cc +++ b/media/base/video_util_unittest.cc @@ -82,4 +82,248 @@ TEST_F(VideoUtilTest, CopyPlane_SmallerDestination) { CopyPlanes(); } +namespace { + +uint8 src6x4[] = { + 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23 +}; + +// Target images, name pattern target_rotation_flipV_flipH. +uint8* target6x4_0_n_n = src6x4; + +uint8 target6x4_0_n_y[] = { + 5, 4, 3, 2, 1, 0, + 11, 10, 9, 8, 7, 6, + 17, 16, 15, 14, 13, 12, + 23, 22, 21, 20, 19, 18 +}; + +uint8 target6x4_0_y_n[] = { + 18, 19, 20, 21, 22, 23, + 12, 13, 14, 15, 16, 17, + 6, 7, 8, 9, 10, 11, + 0, 1, 2, 3, 4, 5 +}; + +uint8 target6x4_0_y_y[] = { + 23, 22, 21, 20, 19, 18, + 17, 16, 15, 14, 13, 12, + 11, 10, 9, 8, 7, 6, + 5, 4, 3, 2, 1, 0 +}; + +uint8 target6x4_90_n_n[] = { + 255, 19, 13, 7, 1, 255, + 255, 20, 14, 8, 2, 255, + 255, 21, 15, 9, 3, 255, + 255, 22, 16, 10, 4, 255 +}; + +uint8 target6x4_90_n_y[] = { + 255, 1, 7, 13, 19, 255, + 255, 2, 8, 14, 20, 255, + 255, 3, 9, 15, 21, 255, + 255, 4, 10, 16, 22, 255 +}; + +uint8 target6x4_90_y_n[] = { + 255, 22, 16, 10, 4, 255, + 255, 21, 15, 9, 3, 255, + 255, 20, 14, 8, 2, 255, + 255, 19, 13, 7, 1, 255 +}; + +uint8 target6x4_90_y_y[] = { + 255, 4, 10, 16, 22, 255, + 255, 3, 9, 15, 21, 255, + 255, 2, 8, 14, 20, 255, + 255, 1, 7, 13, 19, 255 +}; + +uint8* target6x4_180_n_n = target6x4_0_y_y; +uint8* target6x4_180_n_y = target6x4_0_y_n; +uint8* target6x4_180_y_n = target6x4_0_n_y; +uint8* target6x4_180_y_y = target6x4_0_n_n; + +uint8* target6x4_270_n_n = target6x4_90_y_y; +uint8* target6x4_270_n_y = target6x4_90_y_n; +uint8* target6x4_270_y_n = target6x4_90_n_y; +uint8* target6x4_270_y_y = target6x4_90_n_n; + +uint8 src4x6[] = { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15, + 16, 17, 18, 19, + 20, 21, 22, 23 +}; + +uint8* target4x6_0_n_n = src4x6; + +uint8 target4x6_0_n_y[] = { + 3, 2, 1, 0, + 7, 6, 5, 4, + 11, 10, 9, 8, + 15, 14, 13, 12, + 19, 18, 17, 16, + 23, 22, 21, 20 +}; + +uint8 target4x6_0_y_n[] = { + 20, 21, 22, 23, + 16, 17, 18, 19, + 12, 13, 14, 15, + 8, 9, 10, 11, + 4, 5, 6, 7, + 0, 1, 2, 3 +}; + +uint8 target4x6_0_y_y[] = { + 23, 22, 21, 20, + 19, 18, 17, 16, + 15, 14, 13, 12, + 11, 10, 9, 8, + 7, 6, 5, 4, + 3, 2, 1, 0 +}; + +uint8 target4x6_90_n_n[] = { + 255, 255, 255, 255, + 16, 12, 8, 4, + 17, 13, 9, 5, + 18, 14, 10, 6, + 19, 15, 11, 7, + 255, 255, 255, 255 +}; + +uint8 target4x6_90_n_y[] = { + 255, 255, 255, 255, + 4, 8, 12, 16, + 5, 9, 13, 17, + 6, 10, 14, 18, + 7, 11, 15, 19, + 255, 255, 255, 255 +}; + +uint8 target4x6_90_y_n[] = { + 255, 255, 255, 255, + 19, 15, 11, 7, + 18, 14, 10, 6, + 17, 13, 9, 5, + 16, 12, 8, 4, + 255, 255, 255, 255 +}; + +uint8 target4x6_90_y_y[] = { + 255, 255, 255, 255, + 7, 11, 15, 19, + 6, 10, 14, 18, + 5, 9, 13, 17, + 4, 8, 12, 16, + 255, 255, 255, 255 +}; + +uint8* target4x6_180_n_n = target4x6_0_y_y; +uint8* target4x6_180_n_y = target4x6_0_y_n; +uint8* target4x6_180_y_n = target4x6_0_n_y; +uint8* target4x6_180_y_y = target4x6_0_n_n; + +uint8* target4x6_270_n_n = target4x6_90_y_y; +uint8* target4x6_270_n_y = target4x6_90_y_n; +uint8* target4x6_270_y_n = target4x6_90_n_y; +uint8* target4x6_270_y_y = target4x6_90_n_n; + +struct VideoRotationTestData { + uint8* src; + uint8* target; + int width; + int height; + int rotation; + bool flip_vert; + bool flip_horiz; +}; + +const VideoRotationTestData kVideoRotationTestData[] = { + { src6x4, target6x4_0_n_n, 6, 4, 0, false, false }, + { src6x4, target6x4_0_n_y, 6, 4, 0, false, true }, + { src6x4, target6x4_0_y_n, 6, 4, 0, true, false }, + { src6x4, target6x4_0_y_y, 6, 4, 0, true, true }, + + { src6x4, target6x4_90_n_n, 6, 4, 90, false, false }, + { src6x4, target6x4_90_n_y, 6, 4, 90, false, true }, + { src6x4, target6x4_90_y_n, 6, 4, 90, true, false }, + { src6x4, target6x4_90_y_y, 6, 4, 90, true, true }, + + { src6x4, target6x4_180_n_n, 6, 4, 180, false, false }, + { src6x4, target6x4_180_n_y, 6, 4, 180, false, true }, + { src6x4, target6x4_180_y_n, 6, 4, 180, true, false }, + { src6x4, target6x4_180_y_y, 6, 4, 180, true, true }, + + { src6x4, target6x4_270_n_n, 6, 4, 270, false, false }, + { src6x4, target6x4_270_n_y, 6, 4, 270, false, true }, + { src6x4, target6x4_270_y_n, 6, 4, 270, true, false }, + { src6x4, target6x4_270_y_y, 6, 4, 270, true, true }, + + { src4x6, target4x6_0_n_n, 4, 6, 0, false, false }, + { src4x6, target4x6_0_n_y, 4, 6, 0, false, true }, + { src4x6, target4x6_0_y_n, 4, 6, 0, true, false }, + { src4x6, target4x6_0_y_y, 4, 6, 0, true, true }, + + { src4x6, target4x6_90_n_n, 4, 6, 90, false, false }, + { src4x6, target4x6_90_n_y, 4, 6, 90, false, true }, + { src4x6, target4x6_90_y_n, 4, 6, 90, true, false }, + { src4x6, target4x6_90_y_y, 4, 6, 90, true, true }, + + { src4x6, target4x6_180_n_n, 4, 6, 180, false, false }, + { src4x6, target4x6_180_n_y, 4, 6, 180, false, true }, + { src4x6, target4x6_180_y_n, 4, 6, 180, true, false }, + { src4x6, target4x6_180_y_y, 4, 6, 180, true, true }, + + { src4x6, target4x6_270_n_n, 4, 6, 270, false, false }, + { src4x6, target4x6_270_n_y, 4, 6, 270, false, true }, + { src4x6, target4x6_270_y_n, 4, 6, 270, true, false }, + { src4x6, target4x6_270_y_y, 4, 6, 270, true, true } +}; + +} // namespace + +class VideoUtilRotationTest + : public testing::TestWithParam<VideoRotationTestData> { + public: + VideoUtilRotationTest() { + dest_.reset(new uint8[GetParam().width * GetParam().height]); + } + + virtual ~VideoUtilRotationTest() {} + + uint8* dest_plane() { return dest_.get(); } + + private: + scoped_ptr<uint8[]> dest_; + + DISALLOW_COPY_AND_ASSIGN(VideoUtilRotationTest); +}; + +TEST_P(VideoUtilRotationTest, Rotate) { + int rotation = GetParam().rotation; + EXPECT_TRUE((rotation >= 0) && (rotation < 360) && (rotation % 90 == 0)); + + int size = GetParam().width * GetParam().height; + uint8* dest = dest_plane(); + memset(dest, 255, size); + + RotatePlaneByPixels(GetParam().src, dest, GetParam().width, + GetParam().height, rotation, + GetParam().flip_vert, GetParam().flip_horiz); + + EXPECT_EQ(memcmp(dest, GetParam().target, size), 0); +} + +INSTANTIATE_TEST_CASE_P(, VideoUtilRotationTest, + testing::ValuesIn(kVideoRotationTestData)); + } // namespace media diff --git a/media/video/capture/android/video_capture_device_android.cc b/media/video/capture/android/video_capture_device_android.cc index 06daab4..26b80a8 100644 --- a/media/video/capture/android/video_capture_device_android.cc +++ b/media/video/capture/android/video_capture_device_android.cc @@ -12,6 +12,7 @@ #include "base/stringprintf.h" #include "jni/Camera_jni.h" #include "jni/VideoCapture_jni.h" +#include "media/base/video_util.h" using base::android::AttachCurrentThread; using base::android::CheckException; @@ -30,104 +31,6 @@ void ResetBufferI420(uint8* buffer, int width, int height) { memset(buffer, 128, y_size / 2); } -// TODO(wjia): add test for this function. -void RotatePlaneByPixels( - uint8* src, - uint8* dest, - int width, - int height, - int rotation, // Clockwise. - bool flip_vert, - bool flip_horiz) { - // Consolidate cases. Only 0 and 90 are left. - if (rotation == 180 || rotation == 270) { - rotation -= 180; - flip_vert = !flip_vert; - flip_horiz = !flip_horiz; - } - - int num_rows = height; - int num_cols = width; - int src_stride = width; - // During pixel copying, the corresponding incremental of dest pointer - // when src pointer moves to next row. - int dest_row_step = width; - // During pixel copying, the corresponding incremental of dest pointer - // when src pointer moves to next column. - int dest_col_step = 1; - - if (rotation == 0) { - if (flip_horiz) { - // Use pixel copying. - dest_col_step = -1; - if (flip_vert) { - // Rotation 180. - dest_row_step = -width; - dest += height * width - 1; - } else { - dest += width - 1; - } - } else { - if (flip_vert) { - // Fast copy by rows. - dest += width * (height - 1); - for (int row = 0; row < height; ++row) { - memcpy(dest, src, width); - src += width; - dest -= width; - } - } else { - memcpy(dest, src, width * height); - } - return; - } - } else if (rotation == 90) { - int offset; - if (width > height) { - offset = (width - height) / 2; - src += offset; - num_rows = num_cols = height; - } else { - offset = (height - width) / 2; - src += width * offset; - num_rows = num_cols = width; - } - - dest_col_step = (flip_vert ? -width : width); - dest_row_step = (flip_horiz ? 1 : -1); - if (flip_horiz) { - if (flip_vert) { - dest += (width > height ? width * (height - 1) + offset : - width * (height - offset - 1)); - } else { - dest += (width > height ? offset : width * offset); - } - } else { - if (flip_vert) { - dest += (width > height ? width * height - offset - 1 : - width * (height - offset) - 1); - } else { - dest += (width > height ? width - offset - 1 : - width * (offset + 1) - 1); - } - } - } else { - NOTREACHED(); - } - - // Copy pixels. - for (int row = 0; row < num_rows; ++row) { - uint8* src_ptr = src; - uint8* dest_ptr = dest; - for (int col = 0; col < num_cols; ++col) { - *dest_ptr = *src_ptr++; - dest_ptr += dest_col_step; - } - src += src_stride; - dest += dest_row_step; - } -} - int GetIntField(JNIEnv* env, const JavaRef<jclass>& clazz, const JavaRef<jobject>& instance, |