Home | History | Annotate | Download | only in default
      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