blob: e17494386f41f72ecb85b026eeda5bfe9b9932a5 [file] [log] [blame]
Alex Vakulenkoa8a92782017-01-27 14:41:57 -08001#include "screenshot_service.h"
2
3#include <utils/Trace.h>
4
5#include <pdx/default_transport/service_endpoint.h>
6#include <private/dvr/display_types.h>
7
8using android::pdx::Message;
9using android::pdx::MessageInfo;
10using android::pdx::default_transport::Endpoint;
11using android::pdx::rpc::DispatchRemoteMethod;
12using android::pdx::rpc::RemoteMethodError;
13using android::pdx::rpc::RemoteMethodReturn;
14
15namespace android {
16namespace dvr {
17
18ScreenshotService::~ScreenshotService() { instance_ = nullptr; }
19
20int ScreenshotService::HandleMessage(pdx::Message& message) {
21 switch (message.GetOp()) {
22 case DisplayScreenshotRPC::GetFormat::Opcode:
23 DispatchRemoteMethod<DisplayScreenshotRPC::GetFormat>(
24 *this, &ScreenshotService::OnGetFormat, message);
25 return 0;
26
27 case DisplayScreenshotRPC::TakeScreenshot::Opcode:
28 DispatchRemoteMethod<DisplayScreenshotRPC::TakeScreenshot>(
29 *this, &ScreenshotService::OnTakeScreenshot, message);
30 return 0;
31
32 default:
33 return Service::HandleMessage(message);
34 }
35}
36
37int ScreenshotService::OnGetFormat(pdx::Message&) {
38 return HAL_PIXEL_FORMAT_RGB_888;
39}
40
41ScreenshotData ScreenshotService::OnTakeScreenshot(pdx::Message& message,
42 int layer_index) {
43 AddWaiter(std::move(message), layer_index);
44 return {};
45}
46
47void ScreenshotService::AddWaiter(pdx::Message&& message, int layer_index) {
48 std::lock_guard<std::mutex> lock(mutex_);
49 waiters_.emplace_back(std::move(message), layer_index);
50}
51
52void ScreenshotService::TakeIfNeeded(
53 std::array<Layer*, HardwareComposer::kMaxHardwareLayers>& hw_layers,
54 Compositor& compositor) {
55 std::lock_guard<std::mutex> lock(mutex_);
56
57 // Send the buffer contents to all of our waiting clients.
58 for (auto& waiter : waiters_) {
59 if (waiter.IsDone())
60 continue;
61
62 if (waiter.layer_index() == 0) {
63 ALOGE(
64 "ScreenshotService::TakeIfNeeded: Capturing the composited display "
65 "output is not yet supported.");
66
67 waiter.Error(EINVAL);
68 continue;
69 }
70
71 if (waiter.layer_index() > 0) {
72 // Check for hardware layer screenshot requests.
73 // Hardware layers are requested with positive indices starting at 1.
74 const size_t layer_index = static_cast<size_t>(waiter.layer_index() - 1);
75
76 if (layer_index >= hw_layers.size()) {
77 waiter.Error(EINVAL);
78 continue;
79 }
80
81 auto buffer = hw_layers[layer_index]->GetBuffer();
82 if (!buffer) {
83 waiter.Error(ENOBUFS);
84 continue;
85 }
86
87 auto data = compositor.ReadBufferPixels(buffer);
88 if (data.empty()) {
89 waiter.Error(ENOBUFS);
90 continue;
91 }
92
93 Take(&waiter, data.data(), buffer->width(), buffer->height(),
94 buffer->width());
95 } else {
96 // Check for compositor input layer screenshot requests.
97 // Prewarp surfaces are requested with negative indices starting at -1.
98 const size_t layer_index = static_cast<size_t>(-waiter.layer_index() - 1);
99
100 if (layer_index >= compositor.GetLayerCount()) {
101 waiter.Error(EINVAL);
102 continue;
103 }
104
105 int width = 0;
106 int height = 0;
107 auto data = compositor.ReadLayerPixels(layer_index, &width, &height);
108 if (data.empty()) {
109 waiter.Error(ENOBUFS);
110 continue;
111 }
112
113 Take(&waiter, data.data(), width, height, width);
114 }
115 }
116
117 // Reply with error to requests that did not match up with a source layer.
118 for (auto& waiter : waiters_) {
119 if (!waiter.IsDone())
120 waiter.Error(EAGAIN);
121 }
122 waiters_.clear();
123}
124
125void ScreenshotWaiter::Reply(const ScreenshotData& screenshot) {
126 ALOGI("Returning screenshot: size=%zu recv_size=%zu",
127 screenshot.buffer.size(), message_.GetReceiveLength());
128 RemoteMethodReturn<DisplayScreenshotRPC::TakeScreenshot>(message_,
129 screenshot);
130}
131
132void ScreenshotWaiter::Error(int error) { RemoteMethodError(message_, error); }
133
134void ScreenshotService::Take(ScreenshotWaiter* waiter, const void* rgba_data,
135 int32_t width, int32_t height, int buffer_stride) {
136 ATRACE_NAME(__PRETTY_FUNCTION__);
137
138 bool is_portrait = height > width;
139 if (is_portrait) {
140 std::swap(width, height);
141 }
142 int response_stride = width;
143
144 // Convert from RGBA to RGB and if in portrait, rotates to landscape; store
145 // the result in the response buffer.
146 ScreenshotData screenshot{width, height,
147 std::vector<uint8_t>(width * height * 3)};
148
149 const auto rgba_bytes = static_cast<const uint8_t*>(rgba_data);
150 for (int j = 0; j < height; ++j) {
151 for (int i = 0; i < width; ++i) {
152 // If the screenshot is in portrait mode, rotate into landscape mode.
153 const int response_index = is_portrait
154 ? (height - j - 1) * response_stride + i
155 : j * response_stride + i;
156 const int buffer_index =
157 is_portrait ? i * buffer_stride + j : j * buffer_stride + i;
158 screenshot.buffer[response_index * 3 + 0] =
159 rgba_bytes[buffer_index * 4 + 0];
160 screenshot.buffer[response_index * 3 + 1] =
161 rgba_bytes[buffer_index * 4 + 1];
162 screenshot.buffer[response_index * 3 + 2] =
163 rgba_bytes[buffer_index * 4 + 2];
164 }
165 }
166
167 waiter->Reply(screenshot);
168}
169
170ScreenshotService::ScreenshotService()
171 : BASE("ScreenshotService",
172 Endpoint::Create(DisplayScreenshotRPC::kClientPath)) {
173 instance_ = this;
174}
175
176ScreenshotService* ScreenshotService::GetInstance() { return instance_; }
177
178ScreenshotService* ScreenshotService::instance_ = nullptr;
179
180} // namespace dvr
181} // namespace android