summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-19 18:51:01 +0000
committerwjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-19 18:51:01 +0000
commit30591e06f6c96933813d700ae255b2182f6e15e5 (patch)
tree9721347c1de135304b0e2766f7c3a99e6c5fe4bd
parentc667115d4da70673aea8e6ff069872bd1197339c (diff)
downloadchromium_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.cc101
-rw-r--r--media/base/video_util.h19
-rw-r--r--media/base/video_util_unittest.cc244
-rw-r--r--media/video/capture/android/video_capture_device_android.cc99
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,