blob: ae293b6ba0be82157e9250a1c619c153d8185358 [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
267
268Return<EvsResult> EvsCamera::unsetMaster() {
269 // Default implementation does not expect multiple subscribers and therefore
270 // return a success code always.
271 return EvsResult::OK;
272}
273
274
275Return<void> EvsCamera::setParameter(CameraParam id, int32_t value,
276 setParameter_cb _hidl_cb) {
277 // Default implementation does not support this.
278 (void)id;
279 (void)value;
280 _hidl_cb(EvsResult::INVALID_ARG, 0);
281 return Void();
282}
283
284
285Return<void> EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) {
286 // Default implementation does not support this.
287 (void)id;
288 _hidl_cb(EvsResult::INVALID_ARG, 0);
289 return Void();
290}
291
292
Changyeon Jo2400b692019-07-18 21:32:48 -0700293bool EvsCamera::setAvailableFrames_Locked(unsigned bufferCount) {
294 if (bufferCount < 1) {
295 ALOGE("Ignoring request to set buffer count to zero");
296 return false;
297 }
298 if (bufferCount > MAX_BUFFERS_IN_FLIGHT) {
299 ALOGE("Rejecting buffer request in excess of internal limit");
300 return false;
301 }
302
303 // Is an increase required?
304 if (mFramesAllowed < bufferCount) {
305 // An increase is required
306 unsigned needed = bufferCount - mFramesAllowed;
307 ALOGI("Allocating %d buffers for camera frames", needed);
308
309 unsigned added = increaseAvailableFrames_Locked(needed);
310 if (added != needed) {
311 // If we didn't add all the frames we needed, then roll back to the previous state
312 ALOGE("Rolling back to previous frame queue size");
313 decreaseAvailableFrames_Locked(added);
314 return false;
315 }
316 } else if (mFramesAllowed > bufferCount) {
317 // A decrease is required
318 unsigned framesToRelease = mFramesAllowed - bufferCount;
319 ALOGI("Returning %d camera frame buffers", framesToRelease);
320
321 unsigned released = decreaseAvailableFrames_Locked(framesToRelease);
322 if (released != framesToRelease) {
323 // This shouldn't happen with a properly behaving client because the client
324 // should only make this call after returning sufficient outstanding buffers
325 // to allow a clean resize.
326 ALOGE("Buffer queue shrink failed -- too many buffers currently in use?");
327 }
328 }
329
330 return true;
331}
332
333
334unsigned EvsCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
335 // Acquire the graphics buffer allocator
336 GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
337
338 unsigned added = 0;
339
340 while (added < numToAdd) {
341 buffer_handle_t memHandle = nullptr;
342 status_t result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage,
343 &memHandle, &mStride, 0, "EvsCamera");
344 if (result != NO_ERROR) {
345 ALOGE("Error %d allocating %d x %d graphics buffer", result, mWidth, mHeight);
346 break;
347 }
348 if (!memHandle) {
349 ALOGE("We didn't get a buffer handle back from the allocator");
350 break;
351 }
352
353 // Find a place to store the new buffer
354 bool stored = false;
355 for (auto&& rec : mBuffers) {
356 if (rec.handle == nullptr) {
357 // Use this existing entry
358 rec.handle = memHandle;
359 rec.inUse = false;
360 stored = true;
361 break;
362 }
363 }
364 if (!stored) {
365 // Add a BufferRecord wrapping this handle to our set of available buffers
366 mBuffers.emplace_back(memHandle);
367 }
368
369 mFramesAllowed++;
370 added++;
371 }
372
373 return added;
374}
375
376
377unsigned EvsCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
378 // Acquire the graphics buffer allocator
379 GraphicBufferAllocator &alloc(GraphicBufferAllocator::get());
380
381 unsigned removed = 0;
382
383 for (auto&& rec : mBuffers) {
384 // Is this record not in use, but holding a buffer that we can free?
385 if ((rec.inUse == false) && (rec.handle != nullptr)) {
386 // Release buffer and update the record so we can recognize it as "empty"
387 alloc.free(rec.handle);
388 rec.handle = nullptr;
389
390 mFramesAllowed--;
391 removed++;
392
393 if (removed == numToRemove) {
394 break;
395 }
396 }
397 }
398
399 return removed;
400}
401
402
403// This is the asynchronous frame generation thread that runs in parallel with the
404// main serving thread. There is one for each active camera instance.
405void EvsCamera::generateFrames() {
406 ALOGD("Frame generation loop started");
407
408 unsigned idx;
409
410 while (true) {
411 bool timeForFrame = false;
412 nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
413
414 // Lock scope for updating shared state
415 {
416 std::lock_guard<std::mutex> lock(mAccessLock);
417
418 if (mStreamState != RUNNING) {
419 // Break out of our main thread loop
420 break;
421 }
422
423 // Are we allowed to issue another buffer?
424 if (mFramesInUse >= mFramesAllowed) {
425 // Can't do anything right now -- skip this frame
426 ALOGW("Skipped a frame because too many are in flight\n");
427 } else {
428 // Identify an available buffer to fill
429 for (idx = 0; idx < mBuffers.size(); idx++) {
430 if (!mBuffers[idx].inUse) {
431 if (mBuffers[idx].handle != nullptr) {
432 // Found an available record, so stop looking
433 break;
434 }
435 }
436 }
437 if (idx >= mBuffers.size()) {
438 // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
439 ALOGE("Failed to find an available buffer slot\n");
440 } else {
441 // We're going to make the frame busy
442 mBuffers[idx].inUse = true;
443 mFramesInUse++;
444 timeForFrame = true;
445 }
446 }
447 }
448
449 if (timeForFrame) {
450 // Assemble the buffer description we'll transmit below
451 BufferDesc_1_1 newBuffer = {};
452 AHardwareBuffer_Desc* pDesc =
453 reinterpret_cast<AHardwareBuffer_Desc *>(&newBuffer.buffer.description);
454 pDesc->width = mWidth;
455 pDesc->height = mHeight;
456 pDesc->layers = 1;
457 pDesc->format = mFormat;
458 pDesc->usage = mUsage;
459 pDesc->stride = mStride;
460 newBuffer.buffer.nativeHandle = mBuffers[idx].handle;
461 newBuffer.pixelSize = sizeof(uint32_t);
462 newBuffer.bufferId = idx;
463
464 // Write test data into the image buffer
465 fillTestFrame(newBuffer);
466
467 // Issue the (asynchronous) callback to the client -- can't be holding the lock
468 EvsEvent event;
469 event.buffer(newBuffer);
470 auto result = mStream->notifyEvent(event);
471 if (result.isOk()) {
472 ALOGD("Delivered %p as id %d",
473 newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
474 } else {
475 // This can happen if the client dies and is likely unrecoverable.
476 // To avoid consuming resources generating failing calls, we stop sending
477 // frames. Note, however, that the stream remains in the "STREAMING" state
478 // until cleaned up on the main thread.
479 ALOGE("Frame delivery call failed in the transport layer.");
480
481 // Since we didn't actually deliver it, mark the frame as available
482 std::lock_guard<std::mutex> lock(mAccessLock);
483 mBuffers[idx].inUse = false;
484 mFramesInUse--;
485
486 break;
487 }
488 }
489
490 // We arbitrarily choose to generate frames at 12 fps to ensure we pass the 10fps test requirement
491 static const int kTargetFrameRate = 12;
492 static const nsecs_t kTargetFrameTimeUs = 1000*1000 / kTargetFrameRate;
493 const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
494 const nsecs_t workTimeUs = (now - startTime) / 1000;
495 const nsecs_t sleepDurationUs = kTargetFrameTimeUs - workTimeUs;
496 if (sleepDurationUs > 0) {
497 usleep(sleepDurationUs);
498 }
499 }
500
501 // If we've been asked to stop, send an event to signal the actual end of stream
502 EvsEvent event;
Changyeon Jod2a82462019-07-30 11:57:17 -0700503 InfoEventDesc desc = {};
504 desc.aType = InfoEventType::STREAM_STOPPED;
505 event.info(desc);
Changyeon Jo2400b692019-07-18 21:32:48 -0700506 auto result = mStream->notifyEvent(event);
507 if (!result.isOk()) {
508 ALOGE("Error delivering end of stream marker");
509 }
510
511 return;
512}
513
514
515void EvsCamera::fillTestFrame(const BufferDesc_1_1& buff) {
516 // Lock our output buffer for writing
517 uint32_t *pixels = nullptr;
518 const AHardwareBuffer_Desc* pDesc =
519 reinterpret_cast<const AHardwareBuffer_Desc *>(&buff.buffer.description);
520 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
521 mapper.lock(buff.buffer.nativeHandle,
522 GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_NEVER,
523 android::Rect(pDesc->width, pDesc->height),
524 (void **) &pixels);
525
526 // If we failed to lock the pixel buffer, we're about to crash, but log it first
527 if (!pixels) {
528 ALOGE("Camera failed to gain access to image buffer for writing");
529 }
530
531 // Fill in the test pixels
532 for (unsigned row = 0; row < pDesc->height; row++) {
533 for (unsigned col = 0; col < pDesc->width; col++) {
534 // Index into the row to check the pixel at this column.
535 // We expect 0xFF in the LSB channel, a vertical gradient in the
536 // second channel, a horitzontal gradient in the third channel, and
537 // 0xFF in the MSB.
538 // The exception is the very first 32 bits which is used for the
539 // time varying frame signature to avoid getting fooled by a static image.
540 uint32_t expectedPixel = 0xFF0000FF | // MSB and LSB
541 ((row & 0xFF) << 8) | // vertical gradient
542 ((col & 0xFF) << 16); // horizontal gradient
543 if ((row | col) == 0) {
544 static uint32_t sFrameTicker = 0;
545 expectedPixel = (sFrameTicker) & 0xFF;
546 sFrameTicker++;
547 }
548 pixels[col] = expectedPixel;
549 }
550 // Point to the next row
551 // NOTE: stride retrieved from gralloc is in units of pixels
552 pixels = pixels + pDesc->stride;
553 }
554
555 // Release our output buffer
556 mapper.unlock(buff.buffer.nativeHandle);
557}
558
559
560void EvsCamera::fillTestFrame(const BufferDesc_1_0& buff) {
561 BufferDesc_1_1 newBufDesc = {};
562 AHardwareBuffer_Desc desc = {
563 buff.width, // width
564 buff.height, // height
565 1, // layers, always 1 for EVS
566 buff.format, // One of AHardwareBuffer_Format
567 buff.usage, // Combination of AHardwareBuffer_UsageFlags
568 buff.stride, // Row stride in pixels
569 0, // Reserved
570 0 // Reserved
571 };
572 memcpy(&desc, &newBufDesc.buffer.description, sizeof(desc));
573 newBufDesc.buffer.nativeHandle = buff.memHandle;
574 newBufDesc.pixelSize = buff.pixelSize;
575 newBufDesc.bufferId = buff.bufferId;
576
577 return fillTestFrame(newBufDesc);
578}
579
580
581void EvsCamera::returnBuffer(const uint32_t bufferId, const buffer_handle_t memHandle) {
582 std::lock_guard <std::mutex> lock(mAccessLock);
583
584 if (memHandle == nullptr) {
585 ALOGE("ignoring doneWithFrame called with null handle");
586 } else if (bufferId >= mBuffers.size()) {
587 ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)",
588 bufferId, mBuffers.size()-1);
589 } else if (!mBuffers[bufferId].inUse) {
590 ALOGE("ignoring doneWithFrame called on frame %d which is already free",
591 bufferId);
592 } else {
593 // Mark the frame as available
594 mBuffers[bufferId].inUse = false;
595 mFramesInUse--;
596
597 // If this frame's index is high in the array, try to move it down
598 // to improve locality after mFramesAllowed has been reduced.
599 if (bufferId >= mFramesAllowed) {
600 // Find an empty slot lower in the array (which should always exist in this case)
601 for (auto&& rec : mBuffers) {
602 if (rec.handle == nullptr) {
603 rec.handle = mBuffers[bufferId].handle;
604 mBuffers[bufferId].handle = nullptr;
605 break;
606 }
607 }
608 }
609 }
610}
611
612
613} // namespace implementation
614} // namespace V1_0
615} // namespace evs
616} // namespace automotive
617} // namespace hardware
618} // namespace android