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

Commit 4865c526 authored by Eino-Ville Talvala's avatar Eino-Ville Talvala Committed by Android (Google) Code Review
Browse files

Camera2: Synchronize mode changes and triggers

Make sure that changes to various parameters have reached the HAL
before triggering asynchronous events like autofocus or precapture
metering.

Bug: 7107220
Change-Id: I3c50038de1671968eb32004ce538435121934e7e
parent 9942f62d
Loading
Loading
Loading
Loading
+57 −8
Original line number Original line Diff line number Diff line
@@ -536,7 +536,7 @@ status_t Camera2Client::setPreviewWindowL(const sp<IBinder>& binder,
            // Already running preview - need to stop and create a new stream
            // Already running preview - need to stop and create a new stream
            // TODO: Optimize this so that we don't wait for old stream to drain
            // TODO: Optimize this so that we don't wait for old stream to drain
            // before spinning up new stream
            // before spinning up new stream
            mDevice->clearStreamingRequest();
            mStreamingProcessor->stopStream();
            l.mParameters.state = Parameters::WAITING_FOR_PREVIEW_WINDOW;
            l.mParameters.state = Parameters::WAITING_FOR_PREVIEW_WINDOW;
            break;
            break;
    }
    }
@@ -719,6 +719,7 @@ void Camera2Client::stopPreview() {


void Camera2Client::stopPreviewL() {
void Camera2Client::stopPreviewL() {
    ATRACE_CALL();
    ATRACE_CALL();
    status_t res;
    Parameters::State state;
    Parameters::State state;
    {
    {
        SharedParameters::Lock l(mParameters);
        SharedParameters::Lock l(mParameters);
@@ -740,6 +741,11 @@ void Camera2Client::stopPreviewL() {
            // no break - identical to preview
            // no break - identical to preview
        case Parameters::PREVIEW:
        case Parameters::PREVIEW:
            mStreamingProcessor->stopStream();
            mStreamingProcessor->stopStream();
            res = mDevice->waitUntilDrained();
            if (res != OK) {
                ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
                        __FUNCTION__, mCameraId, strerror(-res), res);
            }
            // no break
            // no break
        case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
        case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
            SharedParameters::Lock l(mParameters);
            SharedParameters::Lock l(mParameters);
@@ -946,9 +952,14 @@ status_t Camera2Client::autoFocus() {
    int triggerId;
    int triggerId;
    {
    {
        SharedParameters::Lock l(mParameters);
        SharedParameters::Lock l(mParameters);
        if (l.mParameters.state < Parameters::PREVIEW) {
            return INVALID_OPERATION;
        }

        l.mParameters.currentAfTriggerId = ++l.mParameters.afTriggerCounter;
        l.mParameters.currentAfTriggerId = ++l.mParameters.afTriggerCounter;
        triggerId = l.mParameters.currentAfTriggerId;
        triggerId = l.mParameters.currentAfTriggerId;
    }
    }
    syncWithDevice();


    mDevice->triggerAutofocus(triggerId);
    mDevice->triggerAutofocus(triggerId);


@@ -967,6 +978,7 @@ status_t Camera2Client::cancelAutoFocus() {
        SharedParameters::Lock l(mParameters);
        SharedParameters::Lock l(mParameters);
        triggerId = ++l.mParameters.afTriggerCounter;
        triggerId = ++l.mParameters.afTriggerCounter;
    }
    }
    syncWithDevice();


    mDevice->triggerCancelAutofocus(triggerId);
    mDevice->triggerCancelAutofocus(triggerId);


@@ -1017,6 +1029,9 @@ status_t Camera2Client::takePicture(int msgType) {
        return res;
        return res;
    }
    }


    // Need HAL to have correct settings before (possibly) triggering precapture
    syncWithDevice();

    res = mCaptureSequencer->startCapture();
    res = mCaptureSequencer->startCapture();
    if (res != OK) {
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to start capture: %s (%d)",
        ALOGE("%s: Camera %d: Unable to start capture: %s (%d)",
@@ -1397,13 +1412,18 @@ int Camera2Client::getZslStreamId() const {
    return mZslProcessor->getStreamId();
    return mZslProcessor->getStreamId();
}
}


status_t Camera2Client::registerFrameListener(int32_t id,
status_t Camera2Client::registerFrameListener(int32_t minId, int32_t maxId,
        wp<camera2::FrameProcessor::FilteredListener> listener) {
        wp<camera2::FrameProcessor::FilteredListener> listener) {
    return mFrameProcessor->registerListener(id, listener);
    return mFrameProcessor->registerListener(minId, maxId, listener);
}
}


status_t Camera2Client::removeFrameListener(int32_t id) {
status_t Camera2Client::removeFrameListener(int32_t minId, int32_t maxId,
    return mFrameProcessor->removeListener(id);
        wp<camera2::FrameProcessor::FilteredListener> listener) {
    return mFrameProcessor->removeListener(minId, maxId, listener);
}

status_t Camera2Client::stopStream() {
    return mStreamingProcessor->stopStream();
}
}


Camera2Client::SharedCameraClient::Lock::Lock(SharedCameraClient &client):
Camera2Client::SharedCameraClient::Lock::Lock(SharedCameraClient &client):
@@ -1432,9 +1452,12 @@ void Camera2Client::SharedCameraClient::clear() {
    mCameraClient.clear();
    mCameraClient.clear();
}
}


const int32_t Camera2Client::kPreviewRequestId;
const int32_t Camera2Client::kPreviewRequestIdStart;
const int32_t Camera2Client::kRecordRequestId;
const int32_t Camera2Client::kPreviewRequestIdEnd;
const int32_t Camera2Client::kFirstCaptureRequestId;
const int32_t Camera2Client::kRecordingRequestIdStart;
const int32_t Camera2Client::kRecordingRequestIdEnd;
const int32_t Camera2Client::kCaptureRequestIdStart;
const int32_t Camera2Client::kCaptureRequestIdEnd;


/** Utility methods */
/** Utility methods */


@@ -1443,6 +1466,13 @@ status_t Camera2Client::updateRequests(Parameters &params) {


    ALOGV("%s: Camera %d: state = %d", __FUNCTION__, getCameraId(), params.state);
    ALOGV("%s: Camera %d: state = %d", __FUNCTION__, getCameraId(), params.state);


    res = mStreamingProcessor->incrementStreamingIds();
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to increment request IDs: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    res = mStreamingProcessor->updatePreviewRequest(params);
    res = mStreamingProcessor->updatePreviewRequest(params);
    if (res != OK) {
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
        ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
@@ -1504,4 +1534,23 @@ size_t Camera2Client::calculateBufferSize(int width, int height,
    }
    }
}
}


status_t Camera2Client::syncWithDevice() {
    ATRACE_CALL();
    const nsecs_t kMaxSyncTimeout = 100000000; // 100 ms
    status_t res;

    int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
    if (activeRequestId == 0) return OK;

    res = mDevice->waitUntilRequestReceived(activeRequestId, kMaxSyncTimeout);
    if (res == TIMED_OUT) {
        ALOGE("%s: Camera %d: Timed out waiting sync with HAL",
                __FUNCTION__, mCameraId);
    } else if (res != OK) {
        ALOGE("%s: Camera %d: Error while waiting to sync with HAL",
                __FUNCTION__, mCameraId);
    }
    return res;
}

} // namespace android
} // namespace android
+16 −5
Original line number Original line Diff line number Diff line
@@ -107,9 +107,12 @@ public:
    int getRecordingStreamId() const;
    int getRecordingStreamId() const;
    int getZslStreamId() const;
    int getZslStreamId() const;


    status_t registerFrameListener(int32_t id,
    status_t registerFrameListener(int32_t minId, int32_t maxId,
            wp<camera2::FrameProcessor::FilteredListener> listener);
            wp<camera2::FrameProcessor::FilteredListener> listener);
    status_t removeFrameListener(int32_t id);
    status_t removeFrameListener(int32_t minId, int32_t maxId,
            wp<camera2::FrameProcessor::FilteredListener> listener);

    status_t stopStream();


    // Simple class to ensure that access to ICameraClient is serialized by
    // Simple class to ensure that access to ICameraClient is serialized by
    // requiring mCameraClientLock to be locked before access to mCameraClient
    // requiring mCameraClientLock to be locked before access to mCameraClient
@@ -135,9 +138,14 @@ public:
    static size_t calculateBufferSize(int width, int height,
    static size_t calculateBufferSize(int width, int height,
            int format, int stride);
            int format, int stride);


    static const int32_t kPreviewRequestId = 1000;
    static const int32_t kPreviewRequestIdStart = 10000000;
    static const int32_t kRecordRequestId  = 2000;
    static const int32_t kPreviewRequestIdEnd   = 20000000;
    static const int32_t kFirstCaptureRequestId = 3000;

    static const int32_t kRecordingRequestIdStart  = 20000000;
    static const int32_t kRecordingRequestIdEnd    = 30000000;

    static const int32_t kCaptureRequestIdStart = 30000000;
    static const int32_t kCaptureRequestIdEnd   = 40000000;


private:
private:
    /** ICamera interface-related private members */
    /** ICamera interface-related private members */
@@ -208,6 +216,9 @@ private:


    /** Utility members */
    /** Utility members */


    // Wait until the camera device has received the latest control settings
    status_t syncWithDevice();

    // Verify that caller is the owner of the camera
    // Verify that caller is the owner of the camera
    status_t checkPid(const char *checkLocation) const;
    status_t checkPid(const char *checkLocation) const;
};
};
+33 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,7 @@


#include <utils/Log.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/Trace.h>
#include <utils/Timers.h>
#include "Camera2Device.h"
#include "Camera2Device.h"


namespace android {
namespace android {
@@ -228,6 +229,11 @@ status_t Camera2Device::clearStreamingRequest() {
    return mRequestQueue.setStreamSlot(NULL);
    return mRequestQueue.setStreamSlot(NULL);
}
}


status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
    ATRACE_CALL();
    return mRequestQueue.waitForDequeue(requestId, timeout);
}

status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
        uint32_t width, uint32_t height, int format, size_t size, int *id) {
        uint32_t width, uint32_t height, int format, size_t size, int *id) {
    ATRACE_CALL();
    ATRACE_CALL();
@@ -567,6 +573,7 @@ Camera2Device::NotificationListener::~NotificationListener() {
Camera2Device::MetadataQueue::MetadataQueue():
Camera2Device::MetadataQueue::MetadataQueue():
            mDevice(NULL),
            mDevice(NULL),
            mFrameCount(0),
            mFrameCount(0),
            mLatestRequestId(0),
            mCount(0),
            mCount(0),
            mStreamSlotCount(0),
            mStreamSlotCount(0),
            mSignalConsumer(true)
            mSignalConsumer(true)
@@ -678,6 +685,16 @@ status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
        mFrameCount++;
        mFrameCount++;
    }
    }


    // Check for request ID, and if present, signal waiters.
    camera_metadata_entry_t requestId;
    res = find_camera_metadata_entry(b,
            ANDROID_REQUEST_ID,
            &requestId);
    if (res == OK) {
        mLatestRequestId = requestId.data.i32[0];
        mNewRequestId.signal();
    }

    *buf = b;
    *buf = b;
    mCount--;
    mCount--;


@@ -695,6 +712,22 @@ status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
    return OK;
    return OK;
}
}


status_t Camera2Device::MetadataQueue::waitForDequeue(int32_t id,
        nsecs_t timeout) {
    Mutex::Autolock l(mMutex);
    status_t res;
    while (mLatestRequestId != id) {
        nsecs_t startTime = systemTime();

        res = mNewRequestId.waitRelative(mMutex, timeout);
        if (res != OK) return res;

        timeout -= (systemTime() - startTime);
    }

    return OK;
}

status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
{
{
    ATRACE_CALL();
    ATRACE_CALL();
+12 −0
Original line number Original line Diff line number Diff line
@@ -66,6 +66,13 @@ class Camera2Device : public virtual RefBase {
     */
     */
    status_t clearStreamingRequest();
    status_t clearStreamingRequest();


    /**
     * Wait until a request with the given ID has been dequeued by the
     * HAL. Returns TIMED_OUT if the timeout duration is reached. Returns
     * immediately if the latest request received by the HAL has this id.
     */
    status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);

    /**
    /**
     * Create an output stream of the requested size and format.
     * Create an output stream of the requested size and format.
     *
     *
@@ -226,6 +233,9 @@ class Camera2Device : public virtual RefBase {
        status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
        status_t dequeue(camera_metadata_t **buf, bool incrementCount = true);
        int      getBufferCount();
        int      getBufferCount();
        status_t waitForBuffer(nsecs_t timeout);
        status_t waitForBuffer(nsecs_t timeout);
        // Wait until a buffer with the given ID is dequeued. Will return
        // immediately if the latest buffer dequeued has that ID.
        status_t waitForDequeue(int32_t id, nsecs_t timeout);


        // Set repeating buffer(s); if the queue is empty on a dequeue call, the
        // Set repeating buffer(s); if the queue is empty on a dequeue call, the
        // queue copies the contents of the stream slot into the queue, and then
        // queue copies the contents of the stream slot into the queue, and then
@@ -247,6 +257,8 @@ class Camera2Device : public virtual RefBase {
        Condition notEmpty;
        Condition notEmpty;


        int mFrameCount;
        int mFrameCount;
        int32_t mLatestRequestId;
        Condition mNewRequestId;


        int mCount;
        int mCount;
        List<camera_metadata_t*> mEntries;
        List<camera_metadata_t*> mEntries;
+10 −8
Original line number Original line Diff line number Diff line
@@ -44,7 +44,7 @@ CaptureSequencer::CaptureSequencer(wp<Camera2Client> client):
        mCaptureState(IDLE),
        mCaptureState(IDLE),
        mTriggerId(0),
        mTriggerId(0),
        mTimeoutCount(0),
        mTimeoutCount(0),
        mCaptureId(Camera2Client::kFirstCaptureRequestId) {
        mCaptureId(Camera2Client::kCaptureRequestIdStart) {
    ALOGV("%s", __FUNCTION__);
    ALOGV("%s", __FUNCTION__);
}
}


@@ -84,12 +84,12 @@ void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) {
}
}


void CaptureSequencer::onFrameAvailable(int32_t frameId,
void CaptureSequencer::onFrameAvailable(int32_t frameId,
        CameraMetadata &frame) {
        const CameraMetadata &frame) {
    ALOGV("%s: Listener found new frame", __FUNCTION__);
    ALOGV("%s: Listener found new frame", __FUNCTION__);
    ATRACE_CALL();
    ATRACE_CALL();
    Mutex::Autolock l(mInputMutex);
    Mutex::Autolock l(mInputMutex);
    mNewFrameId = frameId;
    mNewFrameId = frameId;
    mNewFrame.acquire(frame);
    mNewFrame = frame;
    if (!mNewFrameReceived) {
    if (!mNewFrameReceived) {
        mNewFrameReceived = true;
        mNewFrameReceived = true;
        mNewFrameSignal.signal();
        mNewFrameSignal.signal();
@@ -203,7 +203,9 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c
    status_t res = OK;
    status_t res = OK;
    ATRACE_CALL();
    ATRACE_CALL();
    mCaptureId++;
    mCaptureId++;

    if (mCaptureId >= Camera2Client::kCaptureRequestIdEnd) {
        mCaptureId = Camera2Client::kCaptureRequestIdStart;
    }
    {
    {
        Mutex::Autolock l(mInputMutex);
        Mutex::Autolock l(mInputMutex);
        mBusy = false;
        mBusy = false;
@@ -286,7 +288,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslStart(
        return DONE;
        return DONE;
    }
    }


    client->registerFrameListener(mCaptureId,
    client->registerFrameListener(mCaptureId, mCaptureId + 1,
            this);
            this);


    // TODO: Actually select the right thing here.
    // TODO: Actually select the right thing here.
@@ -326,7 +328,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslReprocessing(
CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart(
CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart(
        sp<Camera2Client> &client) {
        sp<Camera2Client> &client) {
    ATRACE_CALL();
    ATRACE_CALL();
    client->registerFrameListener(mCaptureId,
    client->registerFrameListener(mCaptureId, mCaptureId + 1,
            this);
            this);
    {
    {
        SharedParameters::Lock l(client->getParameters());
        SharedParameters::Lock l(client->getParameters());
@@ -421,7 +423,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture(
    }
    }


    if (l.mParameters.state == Parameters::STILL_CAPTURE) {
    if (l.mParameters.state == Parameters::STILL_CAPTURE) {
        res = client->getCameraDevice()->clearStreamingRequest();
        res = client->stopStream();
        if (res != OK) {
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
            ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
                    "%s (%d)",
                    "%s (%d)",
@@ -482,7 +484,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait(
            ALOGW("Mismatched capture timestamps: Metadata frame %lld,"
            ALOGW("Mismatched capture timestamps: Metadata frame %lld,"
                    " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp);
                    " captured buffer %lld", entry.data.i64[0], mCaptureTimestamp);
        }
        }
        client->removeFrameListener(mCaptureId);
        client->removeFrameListener(mCaptureId, mCaptureId + 1, this);


        mNewFrameReceived = false;
        mNewFrameReceived = false;
        mNewCaptureReceived = false;
        mNewCaptureReceived = false;
Loading