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 (at) 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 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 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 // 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. 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 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 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 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 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 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 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 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 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 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. 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 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