Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0776a145 authored by Igor Murashkin's avatar Igor Murashkin
Browse files

Camera3: Add input stream support

- Untested with actual CAMERA3_STREAM_INPUT streams.

Bug: 8629088

Change-Id: Ia0c21ef0a2c951e401ea8babd15d3cceb4bb25a1
parent d09801b9
Loading
Loading
Loading
Loading
+83 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <utils/Timers.h>
#include "Camera3Device.h"
#include "camera3/Camera3OutputStream.h"
#include "camera3/Camera3InputStream.h"

using namespace android::camera3;

@@ -369,6 +370,69 @@ status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t time
    return mRequestThread->waitUntilRequestProcessed(requestId, timeout);
}

status_t Camera3Device::createInputStream(
        uint32_t width, uint32_t height, int format, int *id) {
    ATRACE_CALL();
    Mutex::Autolock l(mLock);

    status_t res;
    bool wasActive = false;

    switch (mStatus) {
        case STATUS_ERROR:
            ALOGE("%s: Device has encountered a serious error", __FUNCTION__);
            return INVALID_OPERATION;
        case STATUS_UNINITIALIZED:
            ALOGE("%s: Device not initialized", __FUNCTION__);
            return INVALID_OPERATION;
        case STATUS_IDLE:
            // OK
            break;
        case STATUS_ACTIVE:
            ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
            mRequestThread->setPaused(true);
            res = waitUntilDrainedLocked();
            if (res != OK) {
                ALOGE("%s: Can't pause captures to reconfigure streams!",
                        __FUNCTION__);
                mStatus = STATUS_ERROR;
                return res;
            }
            wasActive = true;
            break;
        default:
            ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
            return INVALID_OPERATION;
    }
    assert(mStatus == STATUS_IDLE);

    if (mInputStream != 0) {
        ALOGE("%s: Cannot create more than 1 input stream", __FUNCTION__);
        return INVALID_OPERATION;
    }

    sp<Camera3InputStream> newStream = new Camera3InputStream(mNextStreamId,
                width, height, format);

    mInputStream = newStream;

    *id = mNextStreamId++;

    // Continue captures if active at start
    if (wasActive) {
        ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
        res = configureStreamsLocked();
        if (res != OK) {
            ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)",
                    __FUNCTION__, mNextStreamId, strerror(-res), res);
            return res;
        }
        mRequestThread->setPaused(false);
    }

    return OK;
}

status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
        uint32_t width, uint32_t height, int format, size_t size, int *id) {
    ATRACE_CALL();
@@ -1287,7 +1351,7 @@ bool Camera3Device::RequestThread::threadLoop() {

    if (nextRequest->mInputStream != NULL) {
        request.input_buffer = &inputBuffer;
        res = nextRequest->mInputStream->getBuffer(&inputBuffer);
        res = nextRequest->mInputStream->getInputBuffer(&inputBuffer);
        if (res != OK) {
            ALOGE("RequestThread: Can't get input buffer, skipping request:"
                    " %s (%d)", strerror(-res), res);
@@ -1358,6 +1422,23 @@ bool Camera3Device::RequestThread::threadLoop() {
        mLatestRequestSignal.signal();
    }

    // Return input buffer back to framework
    if (request.input_buffer != NULL) {
        Camera3Stream *stream =
            Camera3Stream::cast(request.input_buffer->stream);
        res = stream->returnInputBuffer(*(request.input_buffer));
        // Note: stream may be deallocated at this point, if this buffer was the
        // last reference to it.
        if (res != OK) {
            ALOGE("%s: RequestThread: Can't return input buffer for frame %d to"
                    "  its stream:%s (%d)",  __FUNCTION__,
                    request.frame_number, strerror(-res), res);
            // TODO: Report error upstream
        }
    }



    return true;
}

@@ -1371,7 +1452,7 @@ void Camera3Device::RequestThread::cleanUpFailedRequest(
    }
    if (request.input_buffer != NULL) {
        request.input_buffer->status = CAMERA3_BUFFER_STATUS_ERROR;
        nextRequest->mInputStream->returnBuffer(*(request.input_buffer), 0);
        nextRequest->mInputStream->returnInputBuffer(*(request.input_buffer));
    }
    for (size_t i = 0; i < request.num_output_buffers; i++) {
        outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
+3 −0
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ class Camera3Device :
    virtual status_t createStream(sp<ANativeWindow> consumer,
            uint32_t width, uint32_t height, int format, size_t size,
            int *id);
    virtual status_t createInputStream(
            uint32_t width, uint32_t height, int format,
            int *id);
    virtual status_t createReprocessStreamFromStream(int outputId, int *id);

    virtual status_t getStreamInfo(int id,
+309 −20
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0

// This is needed for stdint.h to define INT64_MAX in C++
#define __STDC_LIMIT_MACROS

#include <utils/Log.h>
#include <utils/Trace.h>
#include "Camera3InputStream.h"
@@ -28,48 +31,334 @@ namespace camera3 {

Camera3InputStream::Camera3InputStream(int id,
        uint32_t width, uint32_t height, int format) :
        Camera3Stream(id, CAMERA3_STREAM_INPUT, width, height, 0, format) {
        Camera3Stream(id, CAMERA3_STREAM_INPUT, width, height, 0, format),
        mTotalBufferCount(0),
        mDequeuedBufferCount(0),
        mFrameCount(0),
        mLastTimestamp(0) {
    mCombinedFence = new Fence();

    if (format == HAL_PIXEL_FORMAT_BLOB) {
        ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__);
        mState = STATE_ERROR;
    }
}

Camera3InputStream::~Camera3InputStream() {
    disconnectLocked();
}

status_t Camera3InputStream::getInputBufferLocked(
        camera3_stream_buffer *buffer) {
    ATRACE_CALL();
    status_t res;

    // FIXME: will not work in (re-)registration
    if (mState == STATE_IN_CONFIG || mState == STATE_IN_RECONFIG) {
        ALOGE("%s: Stream %d: Buffer registration for input streams"
              " not implemented (state %d)",
              __FUNCTION__, mId, mState);
        return INVALID_OPERATION;
    }

    // Allow acquire during IN_[RE]CONFIG for registration
    if (mState != STATE_CONFIGURED &&
            mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) {
        ALOGE("%s: Stream %d: Can't get buffers in unconfigured state %d",
                __FUNCTION__, mId, mState);
        return INVALID_OPERATION;
    }

    // Only limit acquire amount when fully configured
    if (mState == STATE_CONFIGURED &&
            mDequeuedBufferCount == camera3_stream::max_buffers) {
        ALOGE("%s: Stream %d: Already acquired maximum number of simultaneous"
                " buffers (%d)", __FUNCTION__, mId,
                camera3_stream::max_buffers);
        return INVALID_OPERATION;
    }

    ANativeWindowBuffer* anb;
    int fenceFd;

    assert(mConsumer != 0);

    BufferItem bufferItem;
    res = mConsumer->acquireBuffer(&bufferItem, /*waitForFence*/false);

    if (res != OK) {
        ALOGE("%s: Stream %d: Can't acquire next output buffer: %s (%d)",
                __FUNCTION__, mId, strerror(-res), res);
        return res;
    }

    anb = bufferItem.mGraphicBuffer->getNativeBuffer();
    assert(anb != NULL);
    fenceFd = bufferItem.mFence->dup();
    /**
     * FenceFD now owned by HAL except in case of error,
     * in which case we reassign it to acquire_fence
     */

    // Handing out a raw pointer to this object. Increment internal refcount.
    incStrong(this);
    buffer->stream = this;
    buffer->buffer = &(anb->handle);
    buffer->acquire_fence = fenceFd;
    buffer->release_fence = -1;
    buffer->status = CAMERA3_BUFFER_STATUS_OK;

    mDequeuedBufferCount++;

    mBuffersInFlight.push_back(bufferItem);

    return OK;
}

status_t Camera3InputStream::getBufferLocked(camera3_stream_buffer *buffer) {
    (void) buffer;
    ALOGE("%s: Not implemented", __FUNCTION__);
status_t Camera3InputStream::returnInputBufferLocked(
        const camera3_stream_buffer &buffer) {
    ATRACE_CALL();
    status_t res;

    // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be
    // decrementing the internal refcount next. In case this is the last ref, we
    // might get destructed on the decStrong(), so keep an sp around until the
    // end of the call - otherwise have to sprinkle the decStrong on all exit
    // points.
    sp<Camera3InputStream> keepAlive(this);
    decStrong(this);

    // Allow buffers to be returned in the error state, to allow for disconnect
    // and in the in-config states for registration
    if (mState == STATE_CONSTRUCTED) {
        ALOGE("%s: Stream %d: Can't return buffers in unconfigured state %d",
                __FUNCTION__, mId, mState);
        return INVALID_OPERATION;
    }
    if (mDequeuedBufferCount == 0) {
        ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__,
                mId);
        return INVALID_OPERATION;
    }

    bool bufferFound = false;
    BufferItem bufferItem;
    {
        // Find the buffer we are returning
        Vector<BufferItem>::iterator it, end;
        for (it = mBuffersInFlight.begin(), end = mBuffersInFlight.end();
             it != end;
             ++it) {

status_t Camera3InputStream::returnBufferLocked(
        const camera3_stream_buffer &buffer,
        nsecs_t timestamp) {
    (void) timestamp;
    (void) buffer;
    ALOGE("%s: Not implemented", __FUNCTION__);
            const BufferItem& tmp = *it;
            ANativeWindowBuffer *anb = tmp.mGraphicBuffer->getNativeBuffer();
            if (anb != NULL && &(anb->handle) == buffer.buffer) {
                bufferFound = true;
                bufferItem = tmp;
                mBuffersInFlight.erase(it);
                mDequeuedBufferCount--;
            }
        }
    }
    if (!bufferFound) {
        ALOGE("%s: Stream %d: Can't return buffer that wasn't sent to HAL",
              __FUNCTION__, mId);
        return INVALID_OPERATION;
    }

    if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
        if (buffer.release_fence != -1) {
            ALOGE("%s: Stream %d: HAL should not set release_fence(%d) when "
                  "there is an error", __FUNCTION__, mId, buffer.release_fence);
            close(buffer.release_fence);
        }

        /**
         * Reassign release fence as the acquire fence incase of error
         */
        const_cast<camera3_stream_buffer*>(&buffer)->release_fence =
                buffer.acquire_fence;
    }

    /**
     * Unconditionally return buffer to the buffer queue.
     * - Fwk takes over the release_fence ownership
     */
    sp<Fence> releaseFence = new Fence(buffer.release_fence);
    res = mConsumer->releaseBuffer(bufferItem, releaseFence);
    if (res != OK) {
        ALOGE("%s: Stream %d: Error releasing buffer back to buffer queue:"
                " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
        return res;
    }

    mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence);

    mBufferReturnedSignal.signal();

    return OK;

}

bool Camera3InputStream::hasOutstandingBuffersLocked() const {
    ALOGE("%s: Not implemented", __FUNCTION__);
    nsecs_t signalTime = mCombinedFence->getSignalTime();
    ALOGV("%s: Stream %d: Has %d outstanding buffers,"
            " buffer signal time is %lld",
            __FUNCTION__, mId, mDequeuedBufferCount, signalTime);
    if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) {
        return true;
    }
    return false;
}

status_t Camera3InputStream::waitUntilIdle(nsecs_t timeout) {
    (void) timeout;
    ALOGE("%s: Not implemented", __FUNCTION__);
    return INVALID_OPERATION;
    status_t res;
    {
        Mutex::Autolock l(mLock);
        while (mDequeuedBufferCount > 0) {
            if (timeout != TIMEOUT_NEVER) {
                nsecs_t startTime = systemTime();
                res = mBufferReturnedSignal.waitRelative(mLock, timeout);
                if (res == TIMED_OUT) {
                    return res;
                } else if (res != OK) {
                    ALOGE("%s: Error waiting for outstanding buffers: %s (%d)",
                            __FUNCTION__, strerror(-res), res);
                    return res;
                }
                nsecs_t deltaTime = systemTime() - startTime;
                if (timeout <= deltaTime) {
                    timeout = 0;
                } else {
                    timeout -= deltaTime;
                }
            } else {
                res = mBufferReturnedSignal.wait(mLock);
                if (res != OK) {
                    ALOGE("%s: Error waiting for outstanding buffers: %s (%d)",
                            __FUNCTION__, strerror(-res), res);
                    return res;
                }
            }
        }
    }

    // No lock

    unsigned int timeoutMs;
    if (timeout == TIMEOUT_NEVER) {
        timeoutMs = Fence::TIMEOUT_NEVER;
    } else if (timeout == 0) {
        timeoutMs = 0;
    } else {
        // Round up to wait at least 1 ms
        timeoutMs = (timeout + 999999) / 1000000;
    }

    return mCombinedFence->wait(timeoutMs);
}

size_t Camera3InputStream::getBufferCountLocked() {
    return mTotalBufferCount;
}

status_t Camera3InputStream::disconnectLocked() {
    ALOGE("%s: Not implemented", __FUNCTION__);
    switch (mState) {
        case STATE_IN_RECONFIG:
        case STATE_CONFIGURED:
            // OK
            break;
        default:
            // No connection, nothing to do
            return OK;
    }

    if (mDequeuedBufferCount > 0) {
        ALOGE("%s: Can't disconnect with %d buffers still acquired!",
                __FUNCTION__, mDequeuedBufferCount);
        return INVALID_OPERATION;
    }

    assert(mBuffersInFlight.size() == 0);

    /**
     *  no-op since we can't disconnect the producer from the consumer-side
     */

    mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG : STATE_CONSTRUCTED;
    return OK;
}

sp<IGraphicBufferProducer> Camera3InputStream::getProducerInterface() const {
    return mConsumer->getProducerInterface();
}

void Camera3InputStream::dump(int fd, const Vector<String16> &args) const {
    (void) fd;
    (void) args;
    ALOGE("%s: Not implemented", __FUNCTION__);
    String8 lines;
    lines.appendFormat("    Stream[%d]: Input\n", mId);
    lines.appendFormat("      State: %d\n", mState);
    lines.appendFormat("      Dims: %d x %d, format 0x%x\n",
            camera3_stream::width, camera3_stream::height,
            camera3_stream::format);
    lines.appendFormat("      Max size: %d\n", mMaxSize);
    lines.appendFormat("      Usage: %d, max HAL buffers: %d\n",
            camera3_stream::usage, camera3_stream::max_buffers);
    lines.appendFormat("      Frames produced: %d, last timestamp: %lld ns\n",
            mFrameCount, mLastTimestamp);
    lines.appendFormat("      Total buffers: %d, currently acquired: %d\n",
            mTotalBufferCount, mDequeuedBufferCount);
    write(fd, lines.string(), lines.size());
}

status_t Camera3InputStream::configureQueueLocked() {
    status_t res;

    switch (mState) {
        case STATE_IN_RECONFIG:
            res = disconnectLocked();
            if (res != OK) {
                return res;
            }
            break;
        case STATE_IN_CONFIG:
            // OK
            break;
        default:
            ALOGE("%s: Bad state: %d", __FUNCTION__, mState);
            return INVALID_OPERATION;
    }

    assert(mMaxSize == 0);
    assert(camera3_stream::format != HAL_PIXEL_FORMAT_BLOB);

    mTotalBufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS +
                        camera3_stream::max_buffers;
    mDequeuedBufferCount = 0;
    mFrameCount = 0;

    if (mConsumer.get() == 0) {
        mConsumer = new BufferItemConsumer(camera3_stream::usage,
                                           mTotalBufferCount,
                                           /*synchronousMode*/true);
        mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
    }

    res = mConsumer->setDefaultBufferSize(camera3_stream::width,
                                          camera3_stream::height);
    if (res != OK) {
        ALOGE("%s: Stream %d: Could not set buffer dimensions %dx%d",
              __FUNCTION__, mId, camera3_stream::width, camera3_stream::height);
        return res;
    }
    res = mConsumer->setDefaultBufferFormat(camera3_stream::format);
    if (res != OK) {
        ALOGE("%s: Stream %d: Could not set buffer format %d",
              __FUNCTION__, mId, camera3_stream::format);
        return res;
    }

    return OK;
}

}; // namespace camera3
+22 −3
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ namespace camera3 {

/**
 * A class for managing a single stream of input data to the camera device.
 *
 * This class serves as a consumer adapter for the HAL, and will consume the
 * buffers by feeding them into the HAL, as well as releasing the buffers back
 * the buffers once the HAL is done with them.
 */
class Camera3InputStream : public Camera3Stream {
  public:
@@ -36,6 +40,7 @@ class Camera3InputStream : public Camera3Stream {
     * Set up a stream for formats that have fixed size, such as RAW and YUV.
     */
    Camera3InputStream(int id, uint32_t width, uint32_t height, int format);
    ~Camera3InputStream();

    virtual status_t waitUntilIdle(nsecs_t timeout);
    virtual void     dump(int fd, const Vector<String16> &args) const;
@@ -49,18 +54,32 @@ class Camera3InputStream : public Camera3Stream {

  private:

    typedef BufferItemConsumer::BufferItem BufferItem;

    sp<BufferItemConsumer> mConsumer;
    Vector<BufferItem> mBuffersInFlight;
    size_t            mTotalBufferCount;
    size_t            mDequeuedBufferCount;
    Condition         mBufferReturnedSignal;
    uint32_t          mFrameCount;
    nsecs_t           mLastTimestamp;

    // The merged release fence for all returned buffers
    sp<Fence>         mCombinedFence;

    /**
     * Camera3Stream interface
     */

    virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
    virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer,
            nsecs_t timestamp);
    virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer);
    virtual status_t returnInputBufferLocked(
            const camera3_stream_buffer &buffer);
    virtual bool     hasOutstandingBuffersLocked() const;
    virtual status_t disconnectLocked();

    virtual status_t configureQueueLocked();
    virtual size_t   getBufferCountLocked();

}; // class Camera3InputStream

}; // namespace camera3
+1 −1
Original line number Diff line number Diff line
@@ -298,7 +298,7 @@ status_t Camera3OutputStream::configureQueueLocked() {

    switch (mState) {
        case STATE_IN_RECONFIG:
            res = disconnect();
            res = disconnectLocked();
            if (res != OK) {
                return res;
            }
Loading