1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "StreamHandler.h"
18
19 #include "Utils.h"
20
21 #include <aidl/android/hardware/automotive/evs/BufferDesc.h>
22 #include <aidl/android/hardware/automotive/evs/EvsEventDesc.h>
23 #include <aidl/android/hardware/automotive/evs/EvsEventType.h>
24 #include <aidlcommonsupport/NativeHandle.h>
25 #include <android-base/logging.h>
26 #include <cutils/native_handle.h>
27 #include <ui/GraphicBufferAllocator.h>
28
29 #include <stdio.h>
30 #include <string.h>
31
32 namespace {
33
34 using aidl::android::hardware::automotive::evs::BufferDesc;
35 using aidl::android::hardware::automotive::evs::EvsEventDesc;
36 using aidl::android::hardware::automotive::evs::EvsEventType;
37 using aidl::android::hardware::automotive::evs::IEvsCamera;
38
39 } // namespace
40
StreamHandler(const std::shared_ptr<IEvsCamera> & pCamera,uint32_t numBuffers,bool useOwnBuffers,android_pixel_format_t format,int32_t width,int32_t height)41 StreamHandler::StreamHandler(const std::shared_ptr<IEvsCamera>& pCamera, uint32_t numBuffers,
42 bool useOwnBuffers, android_pixel_format_t format, int32_t width,
43 int32_t height) :
44 mCamera(pCamera), mUseOwnBuffers(useOwnBuffers) {
45 if (!useOwnBuffers) {
46 // We rely on the camera having at least two buffers available since we'll hold one and
47 // expect the camera to be able to capture a new image in the background.
48 pCamera->setMaxFramesInFlight(numBuffers);
49 } else {
50 mOwnBuffers.resize(numBuffers);
51
52 // Acquire the graphics buffer allocator
53 buffer_handle_t memHandle = nullptr;
54 android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
55 const auto usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY |
56 GRALLOC_USAGE_SW_WRITE_OFTEN;
57 for (size_t i = 0; i < numBuffers; ++i) {
58 unsigned pixelsPerLine;
59 android::status_t result = alloc.allocate(width, height, format, 1, usage, &memHandle,
60 &pixelsPerLine, 0, "EvsApp");
61 if (result != android::NO_ERROR) {
62 LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
63 } else {
64 BufferDesc buf;
65 AHardwareBuffer_Desc* pDesc =
66 reinterpret_cast<AHardwareBuffer_Desc*>(&buf.buffer.description);
67 pDesc->width = width;
68 pDesc->height = height;
69 pDesc->layers = 1;
70 pDesc->format = format;
71 pDesc->usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY |
72 GRALLOC_USAGE_SW_WRITE_OFTEN;
73 pDesc->stride = pixelsPerLine;
74 buf.buffer.handle = android::dupToAidl(memHandle);
75 buf.bufferId = i; // Unique number to identify this buffer
76 mOwnBuffers[i] = std::move(buf);
77 }
78 }
79
80 int delta = 0;
81 if (auto status = pCamera->importExternalBuffers(mOwnBuffers, &delta); !status.isOk()) {
82 PLOG(ERROR) << "Failed to import buffers.";
83 return;
84 }
85
86 LOG(INFO) << delta << " buffers are imported by EVS.";
87 }
88 }
89
shutdown()90 void StreamHandler::shutdown() {
91 // Make sure we're not still streaming
92 blockingStopStream();
93
94 // At this point, the receiver thread is no longer running, so we can safely drop
95 // our remote object references so they can be freed
96 mCamera = nullptr;
97
98 if (!mUseOwnBuffers) {
99 return;
100 }
101
102 android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
103 for (auto& b : mOwnBuffers) {
104 alloc.free(android::makeFromAidl(b.buffer.handle));
105 }
106
107 mOwnBuffers.resize(0);
108 }
109
startStream()110 bool StreamHandler::startStream() {
111 std::lock_guard lock(mLock);
112 if (mRunning) {
113 return true;
114 }
115
116 // Tell the camera to start streaming
117 if (auto status = mCamera->startVideoStream(ref<StreamHandler>()); !status.isOk()) {
118 LOG(ERROR) << "Failed to request a video stream.";
119 return false;
120 }
121
122 // Mark ourselves as running
123 mRunning = true;
124 return true;
125 }
126
asyncStopStream()127 void StreamHandler::asyncStopStream() {
128 // Tell the camera to stop streaming.
129 // This will result in a null frame being delivered when the stream actually stops.
130 if (auto status = mCamera->stopVideoStream(); !status.isOk()) {
131 LOG(WARNING) << "Failed to stop a video stream.";
132 }
133 }
134
blockingStopStream()135 void StreamHandler::blockingStopStream() {
136 // Tell the stream to stop
137 asyncStopStream();
138
139 // Wait until the stream has actually stopped
140 std::unique_lock lock(mLock);
141 if (mRunning) {
142 mSignal.wait(lock, [this]() { return !mRunning; });
143 }
144 }
145
isRunning()146 bool StreamHandler::isRunning() {
147 std::lock_guard lock(mLock);
148 return mRunning;
149 }
150
newFrameAvailable()151 bool StreamHandler::newFrameAvailable() {
152 std::lock_guard lock(mLock);
153 return (mReadyBuffer >= 0);
154 }
155
getNewFrame()156 const BufferDesc& StreamHandler::getNewFrame() {
157 std::lock_guard lock(mLock);
158
159 if (mHeldBuffer >= 0) {
160 LOG(ERROR) << "Ignored call for new frame while still holding the old one.";
161 } else {
162 if (mReadyBuffer < 0) {
163 LOG(ERROR) << "Returning invalid buffer because we don't have any. "
164 << "Call newFrameAvailable first?";
165 mReadyBuffer = 0; // This is a lie!
166 }
167
168 // Move the ready buffer into the held position, and clear the ready position
169 mHeldBuffer = mReadyBuffer;
170 mReadyBuffer = -1;
171 }
172
173 return mBuffers[mHeldBuffer];
174 }
175
doneWithFrame(const BufferDesc & bufDesc)176 void StreamHandler::doneWithFrame(const BufferDesc& bufDesc) {
177 std::lock_guard lock(mLock);
178
179 // We better be getting back the buffer we original delivered!
180 if (mHeldBuffer < 0) {
181 // Safely ignores a call with an invalid buffer reference.
182 return;
183 }
184
185 if (bufDesc.bufferId != mBuffers[mHeldBuffer].bufferId) {
186 LOG(WARNING) << __FUNCTION__ << " ignores an unexpected buffer; expected = "
187 << mBuffers[mHeldBuffer].bufferId << ", received = " << bufDesc.bufferId;
188 return;
189 }
190
191 // Send the buffer back to the underlying camera
192 std::vector<BufferDesc> frames(1);
193 frames[0] = std::move(mBuffers[mHeldBuffer]);
194 if (auto status = mCamera->doneWithFrame(frames); !status.isOk()) {
195 LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
196 }
197
198 // Clear the held position
199 mHeldBuffer = -1;
200 }
201
deliverFrame(const std::vector<BufferDesc> & buffers)202 ndk::ScopedAStatus StreamHandler::deliverFrame(const std::vector<BufferDesc>& buffers) {
203 LOG(DEBUG) << "Received frames from the camera";
204
205 // Take the lock to protect our frame slots and running state variable
206 std::unique_lock lock(mLock);
207 const BufferDesc& bufferToUse = buffers[0];
208
209 // Do we already have a "ready" frame?
210 if (mReadyBuffer >= 0) {
211 // Send the previously saved buffer back to the camera unused
212 std::vector<BufferDesc> frames(1);
213 frames[0] = std::move(mBuffers[mReadyBuffer]);
214 if (auto status = mCamera->doneWithFrame(frames); !status.isOk()) {
215 LOG(WARNING) << __FUNCTION__ << " fails to return a buffer";
216 }
217
218 // We'll reuse the same ready buffer index
219 } else if (mHeldBuffer >= 0) {
220 // The client is holding a buffer, so use the other slot for "on deck"
221 mReadyBuffer = 1 - mHeldBuffer;
222 } else {
223 // This is our first buffer, so just pick a slot
224 mReadyBuffer = 0;
225 }
226
227 // Save this frame until our client is interested in it
228 mBuffers[mReadyBuffer] = dupBufferDesc(bufferToUse);
229
230 // Notify anybody who cares that things have changed
231 mSignal.notify_all();
232 lock.unlock();
233
234 return ndk::ScopedAStatus::ok();
235 }
236
notify(const EvsEventDesc & event)237 ndk::ScopedAStatus StreamHandler::notify(const EvsEventDesc& event) {
238 switch (event.aType) {
239 case EvsEventType::STREAM_STOPPED: {
240 {
241 std::lock_guard<std::mutex> lock(mLock);
242
243 // Signal that the last frame has been received and the stream is stopped
244 mRunning = false;
245 }
246 LOG(INFO) << "Received a STREAM_STOPPED event";
247 break;
248 }
249
250 case EvsEventType::PARAMETER_CHANGED:
251 LOG(INFO) << "Camera parameter " << std::hex << event.payload[0] << " is set to "
252 << event.payload[1];
253 break;
254
255 // Below events are ignored in reference implementation.
256 case EvsEventType::STREAM_STARTED:
257 [[fallthrough]];
258 case EvsEventType::FRAME_DROPPED:
259 [[fallthrough]];
260 case EvsEventType::TIMEOUT:
261 LOG(INFO) << "Event " << std::hex << static_cast<unsigned>(event.aType)
262 << "is received but ignored.";
263 break;
264 default:
265 LOG(ERROR) << "Unknown event id: " << static_cast<unsigned>(event.aType);
266 break;
267 }
268
269 return ndk::ScopedAStatus::ok();
270 }
271