Home | History | Annotate | Download | only in device3
      1 /*
      2  * Copyright (C) 2013 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 "Camera3-ZslStream"
     18 #define ATRACE_TAG ATRACE_TAG_CAMERA
     19 //#define LOG_NDEBUG 0
     20 
     21 #include <inttypes.h>
     22 
     23 #include <utils/Log.h>
     24 #include <utils/Trace.h>
     25 #include "Camera3ZslStream.h"
     26 
     27 typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
     28 
     29 namespace android {
     30 
     31 namespace camera3 {
     32 
     33 namespace {
     34 struct TimestampFinder : public RingBufferConsumer::RingBufferComparator {
     35     typedef RingBufferConsumer::BufferInfo BufferInfo;
     36 
     37     enum {
     38         SELECT_I1 = -1,
     39         SELECT_I2 = 1,
     40         SELECT_NEITHER = 0,
     41     };
     42 
     43     TimestampFinder(nsecs_t timestamp) : mTimestamp(timestamp) {}
     44     ~TimestampFinder() {}
     45 
     46     template <typename T>
     47     static void swap(T& a, T& b) {
     48         T tmp = a;
     49         a = b;
     50         b = tmp;
     51     }
     52 
     53     /**
     54      * Try to find the best candidate for a ZSL buffer.
     55      * Match priority from best to worst:
     56      *  1) Timestamps match.
     57      *  2) Timestamp is closest to the needle (and lower).
     58      *  3) Timestamp is closest to the needle (and higher).
     59      *
     60      */
     61     virtual int compare(const BufferInfo *i1,
     62                         const BufferInfo *i2) const {
     63         // Try to select non-null object first.
     64         if (i1 == NULL) {
     65             return SELECT_I2;
     66         } else if (i2 == NULL) {
     67             return SELECT_I1;
     68         }
     69 
     70         // Best result: timestamp is identical
     71         if (i1->mTimestamp == mTimestamp) {
     72             return SELECT_I1;
     73         } else if (i2->mTimestamp == mTimestamp) {
     74             return SELECT_I2;
     75         }
     76 
     77         const BufferInfo* infoPtrs[2] = {
     78             i1,
     79             i2
     80         };
     81         int infoSelectors[2] = {
     82             SELECT_I1,
     83             SELECT_I2
     84         };
     85 
     86         // Order i1,i2 so that always i1.timestamp < i2.timestamp
     87         if (i1->mTimestamp > i2->mTimestamp) {
     88             swap(infoPtrs[0], infoPtrs[1]);
     89             swap(infoSelectors[0], infoSelectors[1]);
     90         }
     91 
     92         // Second best: closest (lower) timestamp
     93         if (infoPtrs[1]->mTimestamp < mTimestamp) {
     94             return infoSelectors[1];
     95         } else if (infoPtrs[0]->mTimestamp < mTimestamp) {
     96             return infoSelectors[0];
     97         }
     98 
     99         // Worst: closest (higher) timestamp
    100         return infoSelectors[0];
    101 
    102         /**
    103          * The above cases should cover all the possibilities,
    104          * and we get an 'empty' result only if the ring buffer
    105          * was empty itself
    106          */
    107     }
    108 
    109     const nsecs_t mTimestamp;
    110 }; // struct TimestampFinder
    111 } // namespace anonymous
    112 
    113 Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height,
    114         int bufferCount) :
    115         Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
    116                             width, height,
    117                             HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
    118         mDepth(bufferCount) {
    119 
    120     sp<IGraphicBufferProducer> producer;
    121     sp<IGraphicBufferConsumer> consumer;
    122     BufferQueue::createBufferQueue(&producer, &consumer);
    123     mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
    124     mConsumer = new Surface(producer);
    125 }
    126 
    127 Camera3ZslStream::~Camera3ZslStream() {
    128 }
    129 
    130 status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) {
    131     ATRACE_CALL();
    132 
    133     status_t res;
    134 
    135     // TODO: potentially register from inputBufferLocked
    136     // this should be ok, registerBuffersLocked only calls getBuffer for now
    137     // register in output mode instead of input mode for ZSL streams.
    138     if (mState == STATE_IN_CONFIG || mState == STATE_IN_RECONFIG) {
    139         ALOGE("%s: Stream %d: Buffer registration for input streams"
    140               " not implemented (state %d)",
    141               __FUNCTION__, mId, mState);
    142         return INVALID_OPERATION;
    143     }
    144 
    145     if ((res = getBufferPreconditionCheckLocked()) != OK) {
    146         return res;
    147     }
    148 
    149     ANativeWindowBuffer* anb;
    150     int fenceFd;
    151 
    152     assert(mProducer != 0);
    153 
    154     sp<PinnedBufferItem> bufferItem;
    155     {
    156         List<sp<RingBufferConsumer::PinnedBufferItem> >::iterator it, end;
    157         it = mInputBufferQueue.begin();
    158         end = mInputBufferQueue.end();
    159 
    160         // Need to call enqueueInputBufferByTimestamp as a prerequisite
    161         if (it == end) {
    162             ALOGE("%s: Stream %d: No input buffer was queued",
    163                     __FUNCTION__, mId);
    164             return INVALID_OPERATION;
    165         }
    166         bufferItem = *it;
    167         mInputBufferQueue.erase(it);
    168     }
    169 
    170     anb = bufferItem->getBufferItem().mGraphicBuffer->getNativeBuffer();
    171     assert(anb != NULL);
    172     fenceFd = bufferItem->getBufferItem().mFence->dup();
    173 
    174     /**
    175      * FenceFD now owned by HAL except in case of error,
    176      * in which case we reassign it to acquire_fence
    177      */
    178     handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
    179                          /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
    180 
    181     mBuffersInFlight.push_back(bufferItem);
    182 
    183     return OK;
    184 }
    185 
    186 status_t Camera3ZslStream::returnBufferCheckedLocked(
    187             const camera3_stream_buffer &buffer,
    188             nsecs_t timestamp,
    189             bool output,
    190             /*out*/
    191             sp<Fence> *releaseFenceOut) {
    192 
    193     if (output) {
    194         // Output stream path
    195         return Camera3OutputStream::returnBufferCheckedLocked(buffer,
    196                                                               timestamp,
    197                                                               output,
    198                                                               releaseFenceOut);
    199     }
    200 
    201     /**
    202      * Input stream path
    203      */
    204     bool bufferFound = false;
    205     sp<PinnedBufferItem> bufferItem;
    206     {
    207         // Find the buffer we are returning
    208         Vector<sp<PinnedBufferItem> >::iterator it, end;
    209         for (it = mBuffersInFlight.begin(), end = mBuffersInFlight.end();
    210              it != end;
    211              ++it) {
    212 
    213             const sp<PinnedBufferItem>& tmp = *it;
    214             ANativeWindowBuffer *anb =
    215                     tmp->getBufferItem().mGraphicBuffer->getNativeBuffer();
    216             if (anb != NULL && &(anb->handle) == buffer.buffer) {
    217                 bufferFound = true;
    218                 bufferItem = tmp;
    219                 mBuffersInFlight.erase(it);
    220                 break;
    221             }
    222         }
    223     }
    224     if (!bufferFound) {
    225         ALOGE("%s: Stream %d: Can't return buffer that wasn't sent to HAL",
    226               __FUNCTION__, mId);
    227         return INVALID_OPERATION;
    228     }
    229 
    230     int releaseFenceFd = buffer.release_fence;
    231 
    232     if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
    233         if (buffer.release_fence != -1) {
    234             ALOGE("%s: Stream %d: HAL should not set release_fence(%d) when "
    235                   "there is an error", __FUNCTION__, mId, buffer.release_fence);
    236             close(buffer.release_fence);
    237         }
    238 
    239         /**
    240          * Reassign release fence as the acquire fence incase of error
    241          */
    242         releaseFenceFd = buffer.acquire_fence;
    243     }
    244 
    245     /**
    246      * Unconditionally return buffer to the buffer queue.
    247      * - Fwk takes over the release_fence ownership
    248      */
    249     sp<Fence> releaseFence = new Fence(releaseFenceFd);
    250     bufferItem->getBufferItem().mFence = releaseFence;
    251     bufferItem.clear(); // dropping last reference unpins buffer
    252 
    253     *releaseFenceOut = releaseFence;
    254 
    255     return OK;
    256 }
    257 
    258 status_t Camera3ZslStream::returnInputBufferLocked(
    259         const camera3_stream_buffer &buffer) {
    260     ATRACE_CALL();
    261 
    262     status_t res = returnAnyBufferLocked(buffer, /*timestamp*/0,
    263                                          /*output*/false);
    264 
    265     return res;
    266 }
    267 
    268 void Camera3ZslStream::dump(int fd, const Vector<String16> &args) const {
    269     (void) args;
    270 
    271     String8 lines;
    272     lines.appendFormat("    Stream[%d]: ZSL\n", mId);
    273     write(fd, lines.string(), lines.size());
    274 
    275     Camera3IOStreamBase::dump(fd, args);
    276 
    277     lines = String8();
    278     lines.appendFormat("      Input buffers pending: %zu, in flight %zu\n",
    279             mInputBufferQueue.size(), mBuffersInFlight.size());
    280     write(fd, lines.string(), lines.size());
    281 }
    282 
    283 status_t Camera3ZslStream::enqueueInputBufferByTimestamp(
    284         nsecs_t timestamp,
    285         nsecs_t* actualTimestamp) {
    286 
    287     Mutex::Autolock l(mLock);
    288 
    289     TimestampFinder timestampFinder = TimestampFinder(timestamp);
    290 
    291     sp<RingBufferConsumer::PinnedBufferItem> pinnedBuffer =
    292             mProducer->pinSelectedBuffer(timestampFinder,
    293                                         /*waitForFence*/false);
    294 
    295     if (pinnedBuffer == 0) {
    296         ALOGE("%s: No ZSL buffers were available yet", __FUNCTION__);
    297         return NO_BUFFER_AVAILABLE;
    298     }
    299 
    300     nsecs_t actual = pinnedBuffer->getBufferItem().mTimestamp;
    301 
    302     if (actual != timestamp) {
    303         // TODO: this is problematic, we'll end up with using wrong result for this pinned buffer.
    304         ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
    305               " requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
    306               __FUNCTION__, timestamp, actual);
    307     }
    308 
    309     mInputBufferQueue.push_back(pinnedBuffer);
    310 
    311     if (actualTimestamp != NULL) {
    312         *actualTimestamp = actual;
    313     }
    314 
    315     return OK;
    316 }
    317 
    318 status_t Camera3ZslStream::clearInputRingBuffer(nsecs_t* latestTimestamp) {
    319     Mutex::Autolock l(mLock);
    320 
    321     return clearInputRingBufferLocked(latestTimestamp);
    322 }
    323 
    324 status_t Camera3ZslStream::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
    325 
    326     if (latestTimestamp) {
    327         *latestTimestamp = mProducer->getLatestTimestamp();
    328     }
    329     mInputBufferQueue.clear();
    330 
    331     return mProducer->clear();
    332 }
    333 
    334 status_t Camera3ZslStream::disconnectLocked() {
    335     clearInputRingBufferLocked(NULL);
    336 
    337     return Camera3OutputStream::disconnectLocked();
    338 }
    339 
    340 status_t Camera3ZslStream::setTransform(int /*transform*/) {
    341     ALOGV("%s: Not implemented", __FUNCTION__);
    342     return INVALID_OPERATION;
    343 }
    344 
    345 }; // namespace camera3
    346 
    347 }; // namespace android
    348