Enabled cropping support in SurfaceTexture
SurfaceTexture will modify the crop rect so it matches
the desired output aspect ratio when the scaling
mode is NATIVE_WINDOW_SCALING_MODE_CROP. Added a test
for this new scaling mode.
Change-Id: I60f24dcbc294b65cd10a393d9e27d40f07d27bb6
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index ddbfe05..3c1fcc5 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -531,7 +531,8 @@
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
- ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
+ ST_LOGV("queueBuffer: slot=%d time=%lld crop=[%d,%d,%d,%d]", buf, timestamp,
+ crop.left, crop.top, crop.right, crop.bottom);
sp<ConsumerListener> listener;
@@ -592,6 +593,7 @@
switch (scalingMode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
break;
default:
ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 4fe2cca..0fa9ca1 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -168,6 +168,8 @@
status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
{
Mutex::Autolock lock(mMutex);
+ mDefaultWidth = w;
+ mDefaultHeight = h;
return mBufferQueue->setDefaultBufferSize(w, h);
}
@@ -621,7 +623,40 @@
Rect SurfaceTexture::getCurrentCrop() const {
Mutex::Autolock lock(mMutex);
- return mCurrentCrop;
+
+ Rect outCrop = mCurrentCrop;
+ if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
+ int32_t newWidth = mCurrentCrop.width();
+ int32_t newHeight = mCurrentCrop.height();
+
+ if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
+ newWidth = newHeight * mDefaultWidth / mDefaultHeight;
+ ST_LOGV("too wide: newWidth = %d", newWidth);
+ } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
+ newHeight = newWidth * mDefaultHeight / mDefaultWidth;
+ ST_LOGV("too tall: newHeight = %d", newHeight);
+ }
+
+ // The crop is too wide
+ if (newWidth < mCurrentCrop.width()) {
+ int32_t dw = (newWidth - mCurrentCrop.width())/2;
+ outCrop.left -=dw;
+ outCrop.right += dw;
+ // The crop is too tall
+ } else if (newHeight < mCurrentCrop.height()) {
+ int32_t dh = (newHeight - mCurrentCrop.height())/2;
+ outCrop.top -= dh;
+ outCrop.bottom += dh;
+ }
+
+ ST_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
+ outCrop.left, outCrop.top,
+ outCrop.right,outCrop.bottom);
+ }
+
+
+
+ return outCrop;
}
uint32_t SurfaceTexture::getCurrentTransform() const {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index aa114ed..99c025f 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -555,6 +555,7 @@
switch (mode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
break;
default:
ALOGE("unknown scaling mode: %d", mode);
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index ec4f8a4..cfe89bc 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -236,6 +236,44 @@
}
}
+ ::testing::AssertionResult assertRectEq(const Rect &r1,
+ const Rect &r2, int tolerance=1) {
+
+ String8 msg;
+
+ if (abs(r1.left - r2.left) > tolerance) {
+ msg += String8::format("left(%d isn't %d)", r1.left, r2.left);
+ }
+ if (abs(r1.top - r2.top) > tolerance) {
+ if (!msg.isEmpty()) {
+ msg += " ";
+ }
+ msg += String8::format("top(%d isn't %d)", r1.top, r2.top);
+ }
+ if (abs(r1.right - r2.right) > tolerance) {
+ if (!msg.isEmpty()) {
+ msg += " ";
+ }
+ msg += String8::format("right(%d isn't %d)", r1.right, r2.right);
+ }
+ if (abs(r1.bottom - r2.bottom) > tolerance) {
+ if (!msg.isEmpty()) {
+ msg += " ";
+ }
+ msg += String8::format("bottom(%d isn't %d)", r1.bottom, r2.bottom);
+ }
+ if (!msg.isEmpty()) {
+ msg += String8::format(" R1: [%d %d %d %d] R2: [%d %d %d %d]",
+ r1.left, r1.top, r1.right, r1.bottom,
+ r2.left, r2.top, r2.right, r2.bottom);
+ fprintf(stderr, "assertRectEq: %s\n", msg.string());
+ return ::testing::AssertionFailure(
+ ::testing::Message(msg.string()));
+ } else {
+ return ::testing::AssertionSuccess();
+ }
+ }
+
int mDisplaySecs;
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
@@ -1129,6 +1167,88 @@
EXPECT_EQ(OK,mST->updateTexImage());
}
+TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
+ ASSERT_EQ(OK, mST->setSynchronousMode(true));
+
+ ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
+
+ // The producer image size
+ ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 512, 512));
+
+ // The consumer image size (16 x 9) ratio
+ mST->setDefaultBufferSize(1280, 720);
+
+ native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU);
+
+ ANativeWindowBuffer *anb;
+
+ android_native_rect_t odd = {23, 78, 123, 477};
+ ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &odd));
+ EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(OK,mST->updateTexImage());
+ Rect r = mST->getCurrentCrop();
+ assertRectEq(Rect(23, 78, 123, 477), r);
+
+ native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_EGL);
+}
+
+// This test ensures the scaling mode does the right thing
+// ie NATIVE_WINDOW_SCALING_MODE_CROP should crop
+// the image such that it has the same aspect ratio as the
+// default buffer size
+TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
+ ASSERT_EQ(OK, mST->setSynchronousMode(true));
+
+ ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_CROP));
+
+ // The producer image size
+ ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 512, 512));
+
+ // The consumer image size (16 x 9) ratio
+ mST->setDefaultBufferSize(1280, 720);
+
+ native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_CPU);
+
+ ANativeWindowBuffer *anb;
+
+ // The crop is in the shape of (320, 180) === 16 x 9
+ android_native_rect_t standard = {10, 20, 330, 200};
+ ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &standard));
+ EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(OK,mST->updateTexImage());
+ Rect r = mST->getCurrentCrop();
+ // crop should be the same as crop (same aspect ratio)
+ assertRectEq(Rect(10, 20, 330, 200), r);
+
+ // make this wider then desired aspect 239 x 100 (2.39:1)
+ android_native_rect_t wide = {20, 30, 259, 130};
+ ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &wide));
+ EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(OK,mST->updateTexImage());
+ r = mST->getCurrentCrop();
+ // crop should be the same height, but have cropped left and right borders
+ // offset is 30.6 px L+, R-
+ assertRectEq(Rect(51, 30, 228, 130), r);
+
+ // This image is taller then desired aspect 400 x 300 (4:3)
+ android_native_rect_t narrow = {0, 0, 400, 300};
+ ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &narrow));
+ EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(OK,mST->updateTexImage());
+ r = mST->getCurrentCrop();
+ // crop should be the same width, but have cropped top and bottom borders
+ // offset is 37.5 px
+ assertRectEq(Rect(0, 37, 400, 262), r);
+
+ native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU);
+}
+
TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
class ProducerThread : public Thread {
public: