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
This commit is contained in:
Daniel Lam 2012-04-03 15:54:58 -07:00
parent 3bc59682cd
commit 016c8cbce4
5 changed files with 162 additions and 2 deletions

View File

@ -283,6 +283,8 @@ private:
// gets set each time updateTexImage is called.
int64_t mCurrentTimestamp;
uint32_t mDefaultWidth, mDefaultHeight;
// mTexName is the name of the OpenGL texture to which streamed images will
// be bound when updateTexImage is called. It is set at construction time
// and can be changed with a call to attachToContext.

View File

@ -531,7 +531,8 @@ status_t BufferQueue::queueBuffer(int buf,
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 @@ status_t BufferQueue::queueBuffer(int buf,
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);

View File

@ -168,6 +168,8 @@ status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
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 @@ sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
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 {

View File

@ -555,6 +555,7 @@ int SurfaceTextureClient::setScalingMode(int mode)
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);

View File

@ -236,6 +236,44 @@ protected:
}
}
::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 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
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: