1 /*
2 * Copyright (C) 2016 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 #define LOG_TAG "android.hardware.automotive.evs@1.0-service"
18
19 #include "EvsCamera.h"
20 #include "EvsEnumerator.h"
21
22 #include <ui/GraphicBufferAllocator.h>
23 #include <ui/GraphicBufferMapper.h>
24
25
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace evs {
30 namespace V1_0 {
31 namespace implementation {
32
33
34 // Special camera names for which we'll initialize alternate test data
35 const char EvsCamera::kCameraName_Backup[] = "backup";
36
37
38 // Arbitrary limit on number of graphics buffers allowed to be allocated
39 // Safeguards against unreasonable resource consumption and provides a testable limit
40 const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
41
42
EvsCamera(const char * id)43 EvsCamera::EvsCamera(const char *id) :
44 mFramesAllowed(0),
45 mFramesInUse(0),
46 mStreamState(STOPPED) {
47
48 ALOGD("EvsCamera instantiated");
49
50 mDescription.cameraId = id;
51
52 // Set up dummy data for testing
53 if (mDescription.cameraId == kCameraName_Backup) {
54 mWidth = 640; // full NTSC/VGA
55 mHeight = 480; // full NTSC/VGA
56 mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value
57 } else {
58 mWidth = 320; // 1/2 NTSC/VGA
59 mHeight = 240; // 1/2 NTSC/VGA
60 }
61
62 mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
63 mUsage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
64 GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
65 }
66
67
~EvsCamera()68 EvsCamera::~EvsCamera() {
69 ALOGD("EvsCamera being destroyed");
70 forceShutdown();
71 }
72
73
74 //
75 // This gets called if another caller "steals" ownership of the camera
76 //
forceShutdown()77 void EvsCamera::forceShutdown()
78 {
79 ALOGD("EvsCamera forceShutdown");
80
81 // Make sure our output stream is cleaned up
82 // (It really should be already)
83 stopVideoStream();
84
85 // Claim the lock while we work on internal state
86 std::lock_guard <std::mutex> lock(mAccessLock);
87
88 // Drop all the graphics buffers we've been using
89 if (mBuffers.size() > 0) {
90 GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
91 for (auto&& rec : mBuffers) {
92 if (rec.inUse) {
93 ALOGE("Error - releasing buffer despite remote ownership");
94 }
95 alloc.free(rec.handle);
96 rec.handle = nullptr;
97 }
98 mBuffers.clear();
99 }
100
101 // Put this object into an unrecoverable error state since somebody else
102 // is going to own the underlying camera now
103 mStreamState = DEAD;
104 }
105
106
107 // Methods from ::android::hardware::automotive::evs::V1_0::IEvsCamera follow.
getCameraInfo(getCameraInfo_cb _hidl_cb)108 Return<void> EvsCamera::getCameraInfo(getCameraInfo_cb _hidl_cb) {
109 ALOGD("getCameraInfo");
110
111 // Send back our self description
112 _hidl_cb(mDescription);
113 return Void();
114 }
115
116
setMaxFramesInFlight(uint32_t bufferCount)117 Return<EvsResult> EvsCamera::setMaxFramesInFlight(uint32_t bufferCount) {
118 ALOGD("setMaxFramesInFlight");
119 std::lock_guard<std::mutex> lock(mAccessLock);
120
121 // If we've been displaced by another owner of the camera, then we can't do anything else
122 if (mStreamState == DEAD) {
123 ALOGE("ignoring setMaxFramesInFlight call when camera has been lost.");
124 return EvsResult::OWNERSHIP_LOST;
125 }
126
127 // We cannot function without at least one video buffer to send data
128 if (bufferCount < 1) {
129 ALOGE("Ignoring setMaxFramesInFlight with less than one buffer requested");
130 return EvsResult::INVALID_ARG;
131 }
132
133 // Update our internal state
134 if (setAvailableFrames_Locked(bufferCount)) {
135 return EvsResult::OK;
136 } else {
137 return EvsResult::BUFFER_NOT_AVAILABLE;
138 }
139 }
140
141
startVideoStream(const::android::sp<IEvsCameraStream> & stream)142 Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream>& stream) {
143 ALOGD("startVideoStream");
144 std::lock_guard<std::mutex> lock(mAccessLock);
145
146 // If we've been displaced by another owner of the camera, then we can't do anything else
147 if (mStreamState == DEAD) {
148 ALOGE("ignoring startVideoStream call when camera has been lost.");
149 return EvsResult::OWNERSHIP_LOST;
150 }
151 if (mStreamState != STOPPED) {
152 ALOGE("ignoring startVideoStream call when a stream is already running.");
153 return EvsResult::STREAM_ALREADY_RUNNING;
154 }
155
156 // If the client never indicated otherwise, configure ourselves for a single streaming buffer
157 if (mFramesAllowed < 1) {
158 if (!setAvailableFrames_Locked(1)) {
159 ALOGE("Failed to start stream because we couldn't get a graphics buffer");
160 return EvsResult::BUFFER_NOT_AVAILABLE;
161 }
162 }
163
164 // Record the user's callback for use when we have a frame ready
165 mStream = stream;
166
167 // Start the frame generation thread
168 mStreamState = RUNNING;
169 mCaptureThread = std::thread([this](){ generateFrames(); });
170
171 return EvsResult::OK;
172 }
173
174
doneWithFrame(const BufferDesc & buffer)175 Return<void> EvsCamera::doneWithFrame(const BufferDesc& buffer) {
176 ALOGD("doneWithFrame");
177 { // lock context
178 std::lock_guard <std::mutex> lock(mAccessLock);
179
180 if (buffer.memHandle == nullptr) {
181 ALOGE("ignoring doneWithFrame called with null handle");
182 } else if (buffer.bufferId >= mBuffers.size()) {
183 ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
184 buffer.bufferId, mBuffers.size()-1);
185 } else if (!mBuffers[buffer.bufferId].inUse) {
186 ALOGE("ignoring doneWithFrame called on frame %d which is already free",
187 buffer.bufferId);
188 } else {
189 // Mark the frame as available
190 mBuffers[buffer.bufferId].inUse = false;
191 mFramesInUse--;
192
193 // If this frame's index is high in the array, try to move it down
194 // to improve locality after mFramesAllowed has been reduced.
195 if (buffer.bufferId >= mFramesAllowed) {
196 // Find an empty slot lower in the array (which should always exist in this case)
197 for (auto&& rec : mBuffers) {
198 if (rec.handle == nullptr) {
199 rec.handle = mBuffers[buffer.bufferId].handle;
200 mBuffers[buffer.bufferId].handle = nullptr;
201 break;
202 }
203 }
204 }
205 }
206 }
207
208 return Void();
209 }
210
211
stopVideoStream()212 Return<void> EvsCamera::stopVideoStream() {
213 ALOGD("stopVideoStream");
214 std::unique_lock <std::mutex> lock(mAccessLock);
215
216 if (mStreamState == RUNNING) {
217 // Tell the GenerateFrames loop we want it to stop
218 mStreamState = STOPPING;
219
220 // Block outside the mutex until the "stop" flag has been acknowledged
221 // We won't send any more frames, but the client might still get some already in flight
222 ALOGD("Waiting for stream thread to end...");
223 lock.unlock();
224 mCaptureThread.join();
225 lock.lock();
226
227 mStreamState = STOPPED;
228 mStream = nullptr;
229 ALOGD("Stream marked STOPPED.");
230 }
231
232 return Void();
233 }
234
235
getExtendedInfo(uint32_t opaqueIdentifier)236 Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
237 ALOGD("getExtendedInfo");
238 std::lock_guard<std::mutex> lock(mAccessLock);
239
240 // For any single digit value, return the index itself as a test value
241 if (opaqueIdentifier <= 9) {
242 return opaqueIdentifier;
243 }
244
245 // Return zero by default as required by the spec
246 return 0;
247 }
248
249
setExtendedInfo(uint32_t,int32_t)250 Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) {
251 ALOGD("setExtendedInfo");
252 std::lock_guard<std::mutex> lock(mAccessLock);
253
254 // If we've been displaced by another owner of the camera, then we can't do anything else
255 if (mStreamState == DEAD) {
256 ALOGE("ignoring setExtendedInfo call when camera has been lost.");
257 return EvsResult::OWNERSHIP_LOST;
258 }
259
260 // We don't store any device specific information in this implementation
261 return EvsResult::INVALID_ARG;
262 }
263
264
setAvailableFrames_Locked(unsigned bufferCount)265 bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
266 if (bufferCount < 1) {
267 ALOGE("Ignoring request to set buffer count to zero");
268 return false;
269 }
270 if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
271 ALOGE("Rejecting buffer request in excess of internal limit");
272 return false;
273 }
274
275 // Is an increase required?
276 if (mFramesAllowed < bufferCount) {
277 // An increase is required
278 unsigned needed = bufferCount - mFramesAllowed;
279 ALOGI("Allocating %d buffers for camera frames", needed);
280
281 unsigned added = increaseAvailableFrames_Locked(needed);
282 if (added != needed) {
283 // If we didn't add all the frames we needed, then roll back to the previous state
284 ALOGE("Rolling back to previous frame queue size");
285 decreaseAvailableFrames_Locked(added);
286 return false;
287 }
288 } else if (mFramesAllowed > bufferCount) {
289 // A decrease is required
290 unsigned framesToRelease = mFramesAllowed - bufferCount;
291 ALOGI("Returning %d camera frame buffers", framesToRelease);
292
293 unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
294 if (released != framesToRelease) {
295 // This shouldn't happen with a properly behaving client because the client
296 // should only make this call after returning sufficient outstanding buffers
297 // to allow a clean resize.
298 ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
299 }
300 }
301
302 return true;
303 }
304
305
increaseAvailableFrames_Locked(unsigned numToAdd)306 unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
307 // Acquire the graphics buffer allocator
308 GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
309
310 unsigned added = 0;
311
312 while (added < numToAdd) {
313 buffer_handle_t memHandle = nullptr;
314 status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
315 &memHandle, &mStride, 0, "EvsCamera");
316 if (result != NO_ERROR) {
317 ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
318 break;
319 }
320 if (!memHandle) {
321 ALOGE("We didn't get a buffer handle back from the allocator");
322 break;
323 }
324
325 // Find a place to store the new buffer
326 bool stored = false;
327 for (auto&& rec : mBuffers) {
328 if (rec.handle == nullptr) {
329 // Use this existing entry
330 rec.handle = memHandle;
331 rec.inUse = false;
332 stored = true;
333 break;
334 }
335 }
336 if (!stored) {
337 // Add a BufferRecord wrapping this handle to our set of available buffers
338 mBuffers.emplace_back(memHandle);
339 }
340
341 mFramesAllowed++;
342 added++;
343 }
344
345 return added;
346 }
347
348
decreaseAvailableFrames_Locked(unsigned numToRemove)349 unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
350 // Acquire the graphics buffer allocator
351 GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
352
353 unsigned removed = 0;
354
355 for (auto&& rec : mBuffers) {
356 // Is this record not in use, but holding a buffer that we can free?
357 if ((rec.inUse == false) && (rec.handle != nullptr)) {
358 // Release buffer and update the record so we can recognize it as "empty"
359 alloc.free(rec.handle);
360 rec.handle = nullptr;
361
362 mFramesAllowed--;
363 removed++;
364
365 if (removed == numToRemove) {
366 break;
367 }
368 }
369 }
370
371 return removed;
372 }
373
374
375 // This is the asynchronous frame generation thread that runs in parallel with the
376 // main serving thread. There is one for each active camera instance.
generateFrames()377 void EvsCamera::generateFrames() {
378 ALOGD("Frame generation loop started");
379
380 unsigned idx;
381
382 while (true) {
383 bool timeForFrame = false;
384 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
385
386 // Lock scope for updating shared state
387 {
388 std::lock_guard<std::mutex> lock(mAccessLock);
389
390 if (mStreamState != RUNNING) {
391 // Break out of our main thread loop
392 break;
393 }
394
395 // Are we allowed to issue another buffer?
396 if (mFramesInUse >= mFramesAllowed) {
397 // Can't do anything right now -- skip this frame
398 ALOGW("Skipped a frame because too many are in flight\n");
399 } else {
400 // Identify an available buffer to fill
401 for (idx = 0; idx < mBuffers.size(); idx++) {
402 if (!mBuffers[idx].inUse) {
403 if (mBuffers[idx].handle != nullptr) {
404 // Found an available record, so stop looking
405 break;
406 }
407 }
408 }
409 if (idx >= mBuffers.size()) {
410 // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
411 ALOGE("Failed to find an available buffer slot\n");
412 } else {
413 // We're going to make the frame busy
414 mBuffers[idx].inUse = true;
415 mFramesInUse++;
416 timeForFrame = true;
417 }
418 }
419 }
420
421 if (timeForFrame) {
422 // Assemble the buffer description we'll transmit below
423 BufferDesc buff = {};
424 buff.width = mWidth;
425 buff.height = mHeight;
426 buff.stride = mStride;
427 buff.format = mFormat;
428 buff.usage = mUsage;
429 buff.bufferId = idx;
430 buff.memHandle = mBuffers[idx].handle;
431
432 // Write test data into the image buffer
433 fillTestFrame(buff);
434
435 // Issue the (asynchronous) callback to the client -- can't be holding the lock
436 auto result = mStream->deliverFrame(buff);
437 if (result.isOk()) {
438 ALOGD("Delivered %p as id %d", buff.memHandle.getNativeHandle(), buff.bufferId);
439 } else {
440 // This can happen if the client dies and is likely unrecoverable.
441 // To avoid consuming resources generating failing calls, we stop sending
442 // frames. Note, however, that the stream remains in the "STREAMING" state
443 // until cleaned up on the main thread.
444 ALOGE("Frame delivery call failed in the transport layer.");
445
446 // Since we didn't actually deliver it, mark the frame as available
447 std::lock_guard<std::mutex> lock(mAccessLock);
448 mBuffers[idx].inUse = false;
449 mFramesInUse--;
450
451 break;
452 }
453 }
454
455 // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
456 static const int kTargetFrameRate = 12;
457 static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
458 const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
459 const nsecs_t workTimeUs = (now - startTime) / 1000;
460 const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
461 if (sleepDurationUs > 0) {
462 usleep(sleepDurationUs);
463 }
464 }
465
466 // If we've been asked to stop, send one last NULL frame to signal the actual end of stream
467 BufferDesc nullBuff = {};
468 auto result = mStream->deliverFrame(nullBuff);
469 if (!result.isOk()) {
470 ALOGE("Error delivering end of stream marker");
471 }
472
473 return;
474 }
475
476
fillTestFrame(const BufferDesc & buff)477 void EvsCamera::fillTestFrame(const BufferDesc& buff) {
478 // Lock our output buffer for writing
479 uint32_t *pixels = nullptr;
480 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
481 mapper.lock(buff.memHandle,
482 GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
483 android::Rect(buff.width, buff.height),
484 (void **) &pixels);
485
486 // If we failed to lock the pixel buffer, we're about to crash, but log it first
487 if (!pixels) {
488 ALOGE("Camera failed to gain access to image buffer for writing");
489 }
490
491 // Fill in the test pixels
492 for (unsigned row = 0; row < buff.height; row++) {
493 for (unsigned col = 0; col < buff.width; col++) {
494 // Index into the row to check the pixel at this column.
495 // We expect 0xFF in the LSB channel, a vertical gradient in the
496 // second channel, a horitzontal gradient in the third channel, and
497 // 0xFF in the MSB.
498 // The exception is the very first 32 bits which is used for the
499 // time varying frame signature to avoid getting fooled by a static image.
500 uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
501 ((row & 0xFF) << 8) | // vertical gradient
502 ((col & 0xFF) << 16); // horizontal gradient
503 if ((row | col) == 0) {
504 static uint32_t sFrameTicker = 0;
505 expectedPixel = (sFrameTicker) & 0xFF;
506 sFrameTicker++;
507 }
508 pixels[col] = expectedPixel;
509 }
510 // Point to the next row
511 // NOTE: stride retrieved from gralloc is in units of pixels
512 pixels = pixels + buff.stride;
513 }
514
515 // Release our output buffer
516 mapper.unlock(buff.memHandle);
517 }
518
519
520 } // namespace implementation
521 } // namespace V1_0
522 } // namespace evs
523 } // namespace automotive
524 } // namespace hardware
525 } // namespace android
526