blob: 2d55566349bfc2e448e861130130dbf1a1b0340b [file] [log] [blame]
Changyeon Jo2400b692019-07-18 21:32:48 -07001/*
2 * Copyright (C) 2019 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.1-service"
18
19#include "EvsCamera.h"
20#include "EvsEnumerator.h"
21
22#include <ui/GraphicBufferAllocator.h>
23#include <ui/GraphicBufferMapper.h>
24
25
26namespace android {
27namespace hardware {
28namespace automotive {
29namespace evs {
30namespace V1_1 {
31namespace implementation {
32
33
34// Special camera names for which we'll initialize alternate test data
35const 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
40const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
41
42
43EvsCamera::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
68EvsCamera::~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//
77void 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.
108Return<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
117Return<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
142Return<EvsResult> EvsCamera::startVideoStream(const ::android::sp<IEvsCameraStream_1_0>& 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 = IEvsCameraStream_1_1::castFrom(stream).withDefault(nullptr);
166 if (mStream == nullptr) {
167 ALOGE("Default implementation does not support v1.0 IEvsCameraStream");
168 return EvsResult::INVALID_ARG;
169 }
170
171 // Start the frame generation thread
172 mStreamState = RUNNING;
173 mCaptureThread = std::thread([this](){ generateFrames(); });
174
175 return EvsResult::OK;
176}
177
178
179Return<void> EvsCamera::doneWithFrame(const BufferDesc_1_0& buffer) {
180 std::lock_guard <std::mutex> lock(mAccessLock);
181 returnBuffer(buffer.bufferId, buffer.memHandle);
182
183 return Void();
184}
185
186
187Return<void> EvsCamera::stopVideoStream() {
188 ALOGD("stopVideoStream");
189 std::unique_lock <std::mutex> lock(mAccessLock);
190
191 if (mStreamState == RUNNING) {
192 // Tell the GenerateFrames loop we want it to stop
193 mStreamState = STOPPING;
194
195 // Block outside the mutex until the "stop" flag has been acknowledged
196 // We won't send any more frames, but the client might still get some already in flight
197 ALOGD("Waiting for stream thread to end..");
198 lock.unlock();
199 mCaptureThread.join();
200 lock.lock();
201
202 mStreamState = STOPPED;
203 mStream = nullptr;
204 ALOGD("Stream marked STOPPED.");
205 }
206
207 return Void();
208}
209
210
211Return<int32_t> EvsCamera::getExtendedInfo(uint32_t opaqueIdentifier) {
212 ALOGD("getExtendedInfo");
213 std::lock_guard<std::mutex> lock(mAccessLock);
214
215 // For any single digit value, return the index itself as a test value
216 if (opaqueIdentifier <= 9) {
217 return opaqueIdentifier;
218 }
219
220 // Return zero by default as required by the spec
221 return 0;
222}
223
224
225Return<EvsResult> EvsCamera::setExtendedInfo(uint32_t /*opaqueIdentifier*/, int32_t /*opaqueValue*/) {
226 ALOGD("setExtendedInfo");
227 std::lock_guard<std::mutex> lock(mAccessLock);
228
229 // If we've been displaced by another owner of the camera, then we can't do anything else
230 if (mStreamState == DEAD) {
231 ALOGE("ignoring setExtendedInfo call when camera has been lost.");
232 return EvsResult::OWNERSHIP_LOST;
233 }
234
235 // We don't store any device specific information in this implementation
236 return EvsResult::INVALID_ARG;
237}
238
239
240// Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
241Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc) {
242 std::lock_guard <std::mutex> lock(mAccessLock);
243 returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
244
245 return EvsResult::OK;
246}
247
248
249Return<EvsResult> EvsCamera::pauseVideoStream() {
250 // Default implementation does not support this.
251 return EvsResult::UNDERLYING_SERVICE_ERROR;
252}
253
254
255Return<EvsResult> EvsCamera::resumeVideoStream() {
256 // Default implementation does not support this.
257 return EvsResult::UNDERLYING_SERVICE_ERROR;
258}
259
260
Changyeon Jod2a82462019-07-30 11:57:17 -0700261Return<EvsResult> EvsCamera::setMaster() {
262 // Default implementation does not expect multiple subscribers and therefore
263 // return a success code always.
264 return EvsResult::OK;
265}
266
Changyeon Jo0d0228d2019-08-17 21:40:28 -0700267Return<EvsResult> EvsCamera::forceMaster(const sp<IEvsDisplay>& ) {
268 // Default implementation does not expect multiple subscribers and therefore
269 // return a success code always.
270 return EvsResult::OK;
271}
272
Changyeon Jod2a82462019-07-30 11:57:17 -0700273
274Return<EvsResult> EvsCamera::unsetMaster() {
275 // Default implementation does not expect multiple subscribers and therefore
276 // return a success code always.
277 return EvsResult::OK;
278}
279
280
281Return<void> EvsCamera::setParameter(CameraParam id, int32_t value,
282 setParameter_cb _hidl_cb) {
283 // Default implementation does not support this.
284 (void)id;
285 (void)value;
286 _hidl_cb(EvsResult::INVALID_ARG, 0);
287 return Void();
288}
289
290
291Return<void> EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) {
292 // Default implementation does not support this.
293 (void)id;
294 _hidl_cb(EvsResult::INVALID_ARG, 0);
295 return Void();
296}
297
298
Changyeon Jo2400b692019-07-18 21:32:48 -0700299bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
300 if (bufferCount < 1) {
301 ALOGE("Ignoring request to set buffer count to zero");
302 return false;
303 }
304 if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
305 ALOGE("Rejecting buffer request in excess of internal limit");
306 return false;
307 }
308
309 // Is an increase required?
310 if (mFramesAllowed < bufferCount) {
311 // An increase is required
312 unsigned needed = bufferCount - mFramesAllowed;
313 ALOGI("Allocating %d buffers for camera frames", needed);
314
315 unsigned added = increaseAvailableFrames_Locked(needed);
316 if (added != needed) {
317 // If we didn't add all the frames we needed, then roll back to the previous state
318 ALOGE("Rolling back to previous frame queue size");
319 decreaseAvailableFrames_Locked(added);
320 return false;
321 }
322 } else if (mFramesAllowed > bufferCount) {
323 // A decrease is required
324 unsigned framesToRelease = mFramesAllowed - bufferCount;
325 ALOGI("Returning %d camera frame buffers", framesToRelease);
326
327 unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
328 if (released != framesToRelease) {
329 // This shouldn't happen with a properly behaving client because the client
330 // should only make this call after returning sufficient outstanding buffers
331 // to allow a clean resize.
332 ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
333 }
334 }
335
336 return true;
337}
338
339
340unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
341 // Acquire the graphics buffer allocator
342 GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
343
344 unsigned added = 0;
345
346 while (added < numToAdd) {
347 buffer_handle_t memHandle = nullptr;
348 status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
349 &memHandle, &mStride, 0, "EvsCamera");
350 if (result != NO_ERROR) {
351 ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
352 break;
353 }
354 if (!memHandle) {
355 ALOGE("We didn't get a buffer handle back from the allocator");
356 break;
357 }
358
359 // Find a place to store the new buffer
360 bool stored = false;
361 for (auto&& rec : mBuffers) {
362 if (rec.handle == nullptr) {
363 // Use this existing entry
364 rec.handle = memHandle;
365 rec.inUse = false;
366 stored = true;
367 break;
368 }
369 }
370 if (!stored) {
371 // Add a BufferRecord wrapping this handle to our set of available buffers
372 mBuffers.emplace_back(memHandle);
373 }
374
375 mFramesAllowed++;
376 added++;
377 }
378
379 return added;
380}
381
382
383unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
384 // Acquire the graphics buffer allocator
385 GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
386
387 unsigned removed = 0;
388
389 for (auto&& rec : mBuffers) {
390 // Is this record not in use, but holding a buffer that we can free?
391 if ((rec.inUse == false) && (rec.handle != nullptr)) {
392 // Release buffer and update the record so we can recognize it as "empty"
393 alloc.free(rec.handle);
394 rec.handle = nullptr;
395
396 mFramesAllowed--;
397 removed++;
398
399 if (removed == numToRemove) {
400 break;
401 }
402 }
403 }
404
405 return removed;
406}
407
408
409// This is the asynchronous frame generation thread that runs in parallel with the
410// main serving thread. There is one for each active camera instance.
411void EvsCamera::generateFrames() {
412 ALOGD("Frame generation loop started");
413
414 unsigned idx;
415
416 while (true) {
417 bool timeForFrame = false;
418 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
419
420 // Lock scope for updating shared state
421 {
422 std::lock_guard<std::mutex> lock(mAccessLock);
423
424 if (mStreamState != RUNNING) {
425 // Break out of our main thread loop
426 break;
427 }
428
429 // Are we allowed to issue another buffer?
430 if (mFramesInUse >= mFramesAllowed) {
431 // Can't do anything right now -- skip this frame
432 ALOGW("Skipped a frame because too many are in flight\n");
433 } else {
434 // Identify an available buffer to fill
435 for (idx = 0; idx < mBuffers.size(); idx++) {
436 if (!mBuffers[idx].inUse) {
437 if (mBuffers[idx].handle != nullptr) {
438 // Found an available record, so stop looking
439 break;
440 }
441 }
442 }
443 if (idx >= mBuffers.size()) {
444 // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
445 ALOGE("Failed to find an available buffer slot\n");
446 } else {
447 // We're going to make the frame busy
448 mBuffers[idx].inUse = true;
449 mFramesInUse++;
450 timeForFrame = true;
451 }
452 }
453 }
454
455 if (timeForFrame) {
456 // Assemble the buffer description we'll transmit below
457 BufferDesc_1_1 newBuffer = {};
458 AHardwareBuffer_Desc* pDesc =
459 reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
460 pDesc->width = mWidth;
461 pDesc->height = mHeight;
462 pDesc->layers = 1;
463 pDesc->format = mFormat;
464 pDesc->usage = mUsage;
465 pDesc->stride = mStride;
466 newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
467 newBuffer.pixelSize = sizeof(uint32_t);
468 newBuffer.bufferId = idx;
469
470 // Write test data into the image buffer
471 fillTestFrame(newBuffer);
472
473 // Issue the (asynchronous) callback to the client -- can't be holding the lock
474 EvsEvent event;
475 event.buffer(newBuffer);
476 auto result = mStream->notifyEvent(event);
477 if (result.isOk()) {
478 ALOGD("Delivered %p as id %d",
479 newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
480 } else {
481 // This can happen if the client dies and is likely unrecoverable.
482 // To avoid consuming resources generating failing calls, we stop sending
483 // frames. Note, however, that the stream remains in the "STREAMING" state
484 // until cleaned up on the main thread.
485 ALOGE("Frame delivery call failed in the transport layer.");
486
487 // Since we didn't actually deliver it, mark the frame as available
488 std::lock_guard<std::mutex> lock(mAccessLock);
489 mBuffers[idx].inUse = false;
490 mFramesInUse--;
491
492 break;
493 }
494 }
495
496 // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
497 static const int kTargetFrameRate = 12;
498 static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
499 const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
500 const nsecs_t workTimeUs = (now - startTime) / 1000;
501 const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
502 if (sleepDurationUs > 0) {
503 usleep(sleepDurationUs);
504 }
505 }
506
507 // If we've been asked to stop, send an event to signal the actual end of stream
508 EvsEvent event;
Changyeon Jod2a82462019-07-30 11:57:17 -0700509 InfoEventDesc desc = {};
510 desc.aType = InfoEventType::STREAM_STOPPED;
511 event.info(desc);
Changyeon Jo2400b692019-07-18 21:32:48 -0700512 auto result = mStream->notifyEvent(event);
513 if (!result.isOk()) {
514 ALOGE("Error delivering end of stream marker");
515 }
516
517 return;
518}
519
520
521void EvsCamera::fillTestFrame(const BufferDesc_1_1& buff) {
522 // Lock our output buffer for writing
523 uint32_t *pixels = nullptr;
524 const AHardwareBuffer_Desc* pDesc =
525 reinterpret_cast<const AHardwareBuffer_Desc *>(&buff.buffer.description);
526 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
527 mapper.lock(buff.buffer.nativeHandle,
528 GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
529 android::Rect(pDesc->width, pDesc->height),
530 (void **) &pixels);
531
532 // If we failed to lock the pixel buffer, we're about to crash, but log it first
533 if (!pixels) {
534 ALOGE("Camera failed to gain access to image buffer for writing");
535 }
536
537 // Fill in the test pixels
538 for (unsigned row = 0; row < pDesc->height; row++) {
539 for (unsigned col = 0; col < pDesc->width; col++) {
540 // Index into the row to check the pixel at this column.
541 // We expect 0xFF in the LSB channel, a vertical gradient in the
542 // second channel, a horitzontal gradient in the third channel, and
543 // 0xFF in the MSB.
544 // The exception is the very first 32 bits which is used for the
545 // time varying frame signature to avoid getting fooled by a static image.
546 uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
547 ((row & 0xFF) << 8) | // vertical gradient
548 ((col & 0xFF) << 16); // horizontal gradient
549 if ((row | col) == 0) {
550 static uint32_t sFrameTicker = 0;
551 expectedPixel = (sFrameTicker) & 0xFF;
552 sFrameTicker++;
553 }
554 pixels[col] = expectedPixel;
555 }
556 // Point to the next row
557 // NOTE: stride retrieved from gralloc is in units of pixels
558 pixels = pixels + pDesc->stride;
559 }
560
561 // Release our output buffer
562 mapper.unlock(buff.buffer.nativeHandle);
563}
564
565
566void EvsCamera::fillTestFrame(const BufferDesc_1_0& buff) {
567 BufferDesc_1_1 newBufDesc = {};
568 AHardwareBuffer_Desc desc = {
569 buff.width, // width
570 buff.height, // height
571 1, // layers, always 1 for EVS
572 buff.format, // One of AHardwareBuffer_Format
573 buff.usage, // Combination of AHardwareBuffer_UsageFlags
574 buff.stride, // Row stride in pixels
575 0, // Reserved
576 0 // Reserved
577 };
578 memcpy(&desc, &newBufDesc.buffer.description, sizeof(desc));
579 newBufDesc.buffer.nativeHandle = buff.memHandle;
580 newBufDesc.pixelSize = buff.pixelSize;
581 newBufDesc.bufferId = buff.bufferId;
582
583 return fillTestFrame(newBufDesc);
584}
585
586
587void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle) {
588 std::lock_guard <std::mutex> lock(mAccessLock);
589
590 if (memHandle == nullptr) {
591 ALOGE("ignoring doneWithFrame called with null handle");
592 } else if (bufferId >= mBuffers.size()) {
593 ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
594 bufferId, mBuffers.size()-1);
595 } else if (!mBuffers[bufferId].inUse) {
596 ALOGE("ignoring doneWithFrame called on frame %d which is already free",
597 bufferId);
598 } else {
599 // Mark the frame as available
600 mBuffers[bufferId].inUse = false;
601 mFramesInUse--;
602
603 // If this frame's index is high in the array, try to move it down
604 // to improve locality after mFramesAllowed has been reduced.
605 if (bufferId >= mFramesAllowed) {
606 // Find an empty slot lower in the array (which should always exist in this case)
607 for (auto&& rec : mBuffers) {
608 if (rec.handle == nullptr) {
609 rec.handle = mBuffers[bufferId].handle;
610 mBuffers[bufferId].handle = nullptr;
611 break;
612 }
613 }
614 }
615 }
616}
617
618
619} // namespace implementation
620} // namespace V1_0
621} // namespace evs
622} // namespace automotive
623} // namespace hardware
624} // namespace android