Add additional parameters for the captureLayer functions.
1. Added new captureLayers function that will return a GraphicBuffer
instead of storing into a Surface.
2. Added crop to captureLayers function.
3. Added frameScale to allow captures to scale.
4. Removed rotation parameter from captureLayers since it will always be
in the correct orientation.
Test: Transaction_test ScreenCaptureTest.CaptureCrop, .CaptureSize
Change-Id: Ib16d8575cf0c103126b9427ad32e2d28d568ea61
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 973302c..c21c5e3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -124,12 +124,13 @@
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<IGraphicBufferProducer>& producer,
- ISurfaceComposer::Rotation rotation) {
+ const Rect& sourceCrop, float frameScale) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(layerHandleBinder);
data.writeStrongBinder(IInterface::asBinder(producer));
- data.writeInt32(static_cast<int32_t>(rotation));
+ data.write(sourceCrop);
+ data.writeFloat(frameScale);
remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
return reply.readInt32();
}
@@ -605,10 +606,11 @@
sp<IBinder> layerHandleBinder = data.readStrongBinder();
sp<IGraphicBufferProducer> producer =
interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
- int32_t rotation = data.readInt32();
+ Rect sourceCrop(Rect::EMPTY_RECT);
+ data.read(sourceCrop);
+ float frameScale = data.readFloat();
- status_t res = captureLayers(layerHandleBinder, producer,
- static_cast<ISurfaceComposer::Rotation>(rotation));
+ status_t res = captureLayers(layerHandleBinder, producer, sourceCrop, frameScale);
reply->writeInt32(res);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2adc273..2466d25 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -757,11 +757,34 @@
status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
const sp<IGraphicBufferProducer>& producer,
- uint32_t rotation) {
+ Rect sourceCrop, float frameScale) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
- return s->captureLayers(layerHandle, producer,
- static_cast<ISurfaceComposer::Rotation>(rotation));
+ return s->captureLayers(layerHandle, producer, sourceCrop, frameScale);
+}
+
+status_t ScreenshotClient::captureLayersToBuffer(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+
+ sp<IGraphicBufferConsumer> gbpConsumer;
+ sp<IGraphicBufferProducer> producer;
+ BufferQueue::createBufferQueue(&producer, &gbpConsumer);
+ sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
+ GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_SW_READ_NEVER |
+ GRALLOC_USAGE_SW_WRITE_NEVER,
+ 1, true));
+
+ status_t ret = s->captureLayers(layerHandle, producer, sourceCrop, frameScale);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ BufferItem b;
+ consumer->acquireBuffer(&b, 0, true);
+ *outBuffer = b.mGraphicBuffer;
+ return ret;
}
ScreenshotClient::ScreenshotClient()
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 13e7473..1e4c329 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -176,7 +176,7 @@
virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<IGraphicBufferProducer>& producer,
- Rotation rotation = eRotateNone) = 0;
+ const Rect& sourceCrop, float frameScale = 1.0) = 0;
/* Clears the frame statistics for animations.
*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 87fdfae..b0fa922 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -297,8 +297,12 @@
bool useIdentityTransform,
uint32_t rotation,
sp<GraphicBuffer>* outbuffer);
+
static status_t captureLayers(const sp<IBinder>& layerHandle,
- const sp<IGraphicBufferProducer>& producer, uint32_t rotation);
+ const sp<IGraphicBufferProducer>& producer, Rect sourceCrop,
+ float frameScale);
+ static status_t captureLayersToBuffer(const sp<IBinder>& layerHandle, Rect sourceCrop,
+ float frameScale, sp<GraphicBuffer>* outBuffer);
private:
mutable sp<CpuConsumer> mCpuConsumer;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 660680b..ac4eb0c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -531,7 +531,7 @@
Rotation /*rotation*/) override { return NO_ERROR; }
virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
const sp<IGraphicBufferProducer>& /*producer*/,
- ISurfaceComposer::Rotation /*rotation*/) override {
+ const Rect& /*sourceCrop*/, float /*frameScale*/) override {
return NO_ERROR;
}
status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 44b9dc9..fa4df83 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -6,7 +6,8 @@
class RenderArea {
public:
- RenderArea(uint32_t reqHeight, uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+ RenderArea(uint32_t reqHeight, uint32_t reqWidth,
+ ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
: mReqHeight(reqHeight), mReqWidth(reqWidth) {
mRotationFlags = Transform::fromRotation(rotation);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ec2a459..ea4f495 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4398,15 +4398,14 @@
status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
const sp<IGraphicBufferProducer>& producer,
- ISurfaceComposer::Rotation rotation) {
+ const Rect& sourceCrop, float frameScale) {
ATRACE_CALL();
class LayerRenderArea : public RenderArea {
public:
- LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation)
- : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w,
- rotation),
- mLayer(layer) {}
+ LayerRenderArea(const sp<Layer>& layer, const Rect crop, int32_t reqWidth,
+ int32_t reqHeight)
+ : RenderArea(reqHeight, reqWidth), mLayer(layer), mCrop(crop) {}
const Transform& getTransform() const override {
// Make the top level transform the inverse the transform and it's parent so it sets
// the whole capture back to 0,0
@@ -4421,18 +4420,45 @@
bool isSecure() const override { return false; }
bool needsFiltering() const override { return false; }
- Rect getSourceCrop() const override { return getBounds(); }
+ Rect getSourceCrop() const override {
+ if (mCrop.isEmpty()) {
+ return getBounds();
+ } else {
+ return mCrop;
+ }
+ }
bool getWideColorSupport() const override { return false; }
android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; }
private:
- const sp<Layer>& mLayer;
+ const sp<Layer> mLayer;
+ const Rect mCrop;
};
auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
auto parent = layerHandle->owner.promote();
- LayerRenderArea renderArea(parent, rotation);
+ if (parent == nullptr || parent->isPendingRemoval()) {
+ ALOGE("captureLayers called with a removed parent");
+ return NAME_NOT_FOUND;
+ }
+
+ Rect crop(sourceCrop);
+ if (sourceCrop.width() <= 0) {
+ crop.left = 0;
+ crop.right = parent->getCurrentState().active.w;
+ }
+
+ if (sourceCrop.height() <= 0) {
+ crop.top = 0;
+ crop.bottom = parent->getCurrentState().active.h;
+ }
+
+ int32_t reqWidth = crop.width() * frameScale;
+ int32_t reqHeight = crop.height() * frameScale;
+
+ LayerRenderArea renderArea(parent, crop, reqWidth, reqHeight);
+
auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
if (!layer->isVisible()) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 386d42b..f61dc75 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -298,7 +298,7 @@
bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
virtual status_t captureLayers(const sp<IBinder>& parentHandle,
const sp<IGraphicBufferProducer>& producer,
- ISurfaceComposer::Rotation rotation);
+ const Rect& sourceCrop, float frameScale);
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats);
virtual status_t getDisplayConfigs(const sp<IBinder>& display,
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 943fafd..39aef81 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -276,15 +276,15 @@
class CaptureLayer {
public:
- static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle) {
+ static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
SurfaceComposerClient::Transaction().apply(true);
- ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer));
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer, crop, frameScale));
*sc = std::make_unique<CaptureLayer>(cpuConsumer);
}
@@ -2412,4 +2412,89 @@
mCapture->checkPixel(4, 4, 50, 50, 50);
}
-} // namespace android
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+ sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+ String8("Red surface"),
+ 60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+ sp<SurfaceControl> blueLayer = mComposerClient->createSurface(
+ String8("Blue surface"),
+ 30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ fillSurfaceRGBA8(redLayer, 255, 0, 0);
+ fillSurfaceRGBA8(blueLayer, 0, 0, 255);
+
+ SurfaceComposerClient::Transaction()
+ .setLayer(redLayer, INT32_MAX-1)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle);
+ mCapture->checkPixel(29, 29, 0, 0, 255);
+ mCapture->checkPixel(30, 30, 255, 0, 0);
+
+ Rect crop = Rect(0, 0, 30, 30);
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle, crop);
+ // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+ // area visible.
+ mCapture->checkPixel(29, 29, 0, 0, 255);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+ sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+ String8("Red surface"),
+ 60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+ sp<SurfaceControl> blueLayer = mComposerClient->createSurface(
+ String8("Blue surface"),
+ 30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ fillSurfaceRGBA8(redLayer, 255, 0, 0);
+ fillSurfaceRGBA8(blueLayer, 0, 0, 255);
+
+ SurfaceComposerClient::Transaction()
+ .setLayer(redLayer, INT32_MAX-1)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle);
+ mCapture->checkPixel(29, 29, 0, 0, 255);
+ mCapture->checkPixel(30, 30, 255, 0, 0);
+
+ CaptureLayer::captureScreen(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+ // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+ mCapture->checkPixel(14, 14, 0, 0, 255);
+ mCapture->checkPixel(15, 15, 255, 0, 0);
+ mCapture->checkPixel(29, 29, 255, 0, 0);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+ sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+ String8("Red surface"),
+ 60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+
+ fillSurfaceRGBA8(redLayer, 255, 0, 0);
+
+ auto redLayerHandle = redLayer->getHandle();
+ mComposerClient->destroySurface(redLayerHandle);
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+ ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, producer, Rect::EMPTY_RECT, 1.0));
+}
+
+}
\ No newline at end of file