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

Commit ea0d51b5 authored by Eino-Ville Talvala's avatar Eino-Ville Talvala
Browse files

Camera2: Move still capture processing to separate thread.

To avoid stalling HAL when it queues up new buffers for still capture,
process still captures in a separate thread. Also move Camera2Heap to
its own class so it can be used by the CaptureProcessor.

Bug: 6243944
Change-Id: Id38e2a52367c0985812fcd4fd9af3ef90beef43f
parent 6524b7e1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -13,7 +13,8 @@ LOCAL_SRC_FILES:= \
    Camera2Device.cpp \
    camera2/CameraMetadata.cpp \
    camera2/Parameters.cpp \
    camera2/FrameProcessor.cpp
    camera2/FrameProcessor.cpp \
    camera2/CaptureProcessor.cpp

LOCAL_SHARED_LIBRARIES:= \
    libui \
+25 −150
Original line number Diff line number Diff line
@@ -52,11 +52,11 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
        int clientPid):
        Client(cameraService, cameraClient,
                cameraId, cameraFacing, clientPid),
        mSharedCameraClient(cameraClient),
        mParameters(cameraId, cameraFacing),
        mPreviewStreamId(NO_STREAM),
        mCallbackStreamId(NO_STREAM),
        mCallbackHeapId(0),
        mCaptureStreamId(NO_STREAM),
        mRecordingStreamId(NO_STREAM),
        mRecordingHeapCount(kDefaultRecordingHeapCount)
{
@@ -84,11 +84,6 @@ status_t Camera2Client::initialize(camera_module_t *module)
    ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
    status_t res;

    mFrameProcessor = new FrameProcessor(this);
    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
            mCameraId);
    mFrameProcessor->run(frameThreadName.string());

    res = mDevice->initialize(module);
    if (res != OK) {
        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
@@ -107,6 +102,16 @@ status_t Camera2Client::initialize(camera_module_t *module)
        return NO_INIT;
    }

    mFrameProcessor = new FrameProcessor(this);
    String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor",
            mCameraId);
    mFrameProcessor->run(frameThreadName.string());

    mCaptureProcessor = new CaptureProcessor(this);
    String8 captureThreadName =
            String8::format("Camera2Client[%d]::CaptureProcessor", mCameraId);
    mCaptureProcessor->run(captureThreadName.string());

    if (gLogLevel >= 1) {
        ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
              mCameraId);
@@ -292,7 +297,8 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& args) {

    result.append("  Current streams:\n");
    result.appendFormat("    Preview stream ID: %d\n", mPreviewStreamId);
    result.appendFormat("    Capture stream ID: %d\n", mCaptureStreamId);
    result.appendFormat("    Capture stream ID: %d\n",
            mCaptureProcessor->getStreamId());
    result.appendFormat("    Recording stream ID: %d\n", mRecordingStreamId);

    result.append("  Current requests:\n");
@@ -357,10 +363,7 @@ void Camera2Client::disconnect() {
        mPreviewStreamId = NO_STREAM;
    }

    if (mCaptureStreamId != NO_STREAM) {
        mDevice->deleteStream(mCaptureStreamId);
        mCaptureStreamId = NO_STREAM;
    }
    mCaptureProcessor->deleteStream();

    if (mRecordingStreamId != NO_STREAM) {
        mDevice->deleteStream(mRecordingStreamId);
@@ -1028,7 +1031,7 @@ status_t Camera2Client::takePicture(int msgType) {

    ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);

    res = updateCaptureStream(l.mParameters);
    res = mCaptureProcessor->updateStream(l.mParameters);
    if (res != OK) {
        ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
@@ -1048,32 +1051,34 @@ status_t Camera2Client::takePicture(int msgType) {
            CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
    bool recordingEnabled = (l.mParameters.state == Parameters::RECORD);

    int captureStreamId = mCaptureProcessor->getStreamId();

    int streamSwitch = (callbacksEnabled ? 0x2 : 0x0) +
            (recordingEnabled ? 0x1 : 0x0);
    switch ( streamSwitch ) {
        case 0: { // No recording, callbacks
            uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
            uint8_t streamIds[2] = { mPreviewStreamId, captureStreamId };
            res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                    streamIds, 2);
            break;
        }
        case 1: { // Recording
            uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId,
                                     mCaptureStreamId };
                                     captureStreamId };
            res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                    streamIds, 3);
            break;
        }
        case 2: { // Callbacks
            uint8_t streamIds[3] = { mPreviewStreamId, mCallbackStreamId,
                                     mCaptureStreamId };
                                     captureStreamId };
            res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                    streamIds, 3);
            break;
        }
        case 3: { // Both
            uint8_t streamIds[4] = { mPreviewStreamId, mCallbackStreamId,
                                     mRecordingStreamId, mCaptureStreamId };
                                     mRecordingStreamId, captureStreamId };
            res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
                    streamIds, 4);
            break;
@@ -1511,6 +1516,10 @@ Camera2Client::SharedCameraClient::Lock::~Lock() {
    mSharedClient.mCameraClientLock.unlock();
}

Camera2Client::SharedCameraClient::SharedCameraClient(const sp<ICameraClient>&client):
        mCameraClient(client) {
}

Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=(
        const sp<ICameraClient>&client) {
    Mutex::Autolock l(mCameraClientLock);
@@ -1650,71 +1659,6 @@ void Camera2Client::onCallbackAvailable() {
    ALOGV("%s: exit", __FUNCTION__);
}

void Camera2Client::onCaptureAvailable() {
    ATRACE_CALL();
    status_t res;
    sp<Camera2Heap> captureHeap;
    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId);

    {
        SharedParameters::Lock l(mParameters);
        CpuConsumer::LockedBuffer imgBuffer;

        res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return;
        }

        // TODO: Signal errors here upstream
        if (l.mParameters.state != Parameters::STILL_CAPTURE &&
                l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
            ALOGE("%s: Camera %d: Still image produced unexpectedly!",
                    __FUNCTION__, mCameraId);
            mCaptureConsumer->unlockBuffer(imgBuffer);
            return;
        }

        if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
            ALOGE("%s: Camera %d: Unexpected format for still image: "
                    "%x, expected %x", __FUNCTION__, mCameraId,
                    imgBuffer.format,
                    HAL_PIXEL_FORMAT_BLOB);
            mCaptureConsumer->unlockBuffer(imgBuffer);
            return;
        }

        // TODO: Optimize this to avoid memcopy
        void* captureMemory = mCaptureHeap->mHeap->getBase();
        size_t size = mCaptureHeap->mHeap->getSize();
        memcpy(captureMemory, imgBuffer.data, size);

        mCaptureConsumer->unlockBuffer(imgBuffer);

        switch (l.mParameters.state) {
            case Parameters::STILL_CAPTURE:
                l.mParameters.state = Parameters::STOPPED;
                break;
            case Parameters::VIDEO_SNAPSHOT:
                l.mParameters.state = Parameters::RECORD;
                break;
            default:
                ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
                        mCameraId, l.mParameters.state);
                break;
        }

        captureHeap = mCaptureHeap;
    }
    // Call outside parameter locks to allow re-entrancy from notification
    SharedCameraClient::Lock l(mSharedCameraClient);
    if (l.mCameraClient != 0) {
        l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
                captureHeap->mBuffers[0], NULL);
    }
}

void Camera2Client::onRecordingFrameAvailable() {
    ATRACE_CALL();
    status_t res;
@@ -1998,75 +1942,6 @@ status_t Camera2Client::updateCallbackStream(const Parameters &params) {
    return OK;
}


status_t Camera2Client::updateCaptureStream(const Parameters &params) {
    ATRACE_CALL();
    status_t res;
    // Find out buffer size for JPEG
    camera_metadata_ro_entry_t maxJpegSize =
            mParameters.staticInfo(ANDROID_JPEG_MAX_SIZE);
    if (maxJpegSize.count == 0) {
        ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
                __FUNCTION__, mCameraId);
        return INVALID_OPERATION;
    }

    if (mCaptureConsumer == 0) {
        // Create CPU buffer queue endpoint
        mCaptureConsumer = new CpuConsumer(1);
        mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this));
        mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
        mCaptureWindow = new SurfaceTextureClient(
            mCaptureConsumer->getProducerInterface());
        // Create memory for API consumption
        mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
                                       "Camera2Client::CaptureHeap");
        if (mCaptureHeap->mHeap->getSize() == 0) {
            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
                    __FUNCTION__, mCameraId);
            return NO_MEMORY;
        }
    }

    if (mCaptureStreamId != NO_STREAM) {
        // Check if stream parameters have to change
        uint32_t currentWidth, currentHeight;
        res = mDevice->getStreamInfo(mCaptureStreamId,
                &currentWidth, &currentHeight, 0);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error querying capture output stream info: "
                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
        if (currentWidth != (uint32_t)params.pictureWidth ||
                currentHeight != (uint32_t)params.pictureHeight) {
            res = mDevice->deleteStream(mCaptureStreamId);
            if (res != OK) {
                ALOGE("%s: Camera %d: Unable to delete old output stream "
                        "for capture: %s (%d)", __FUNCTION__, mCameraId,
                        strerror(-res), res);
                return res;
            }
            mCaptureStreamId = NO_STREAM;
        }
    }

    if (mCaptureStreamId == NO_STREAM) {
        // Create stream for HAL production
        res = mDevice->createStream(mCaptureWindow,
                params.pictureWidth, params.pictureHeight,
                HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
                &mCaptureStreamId);
        if (res != OK) {
            ALOGE("%s: Camera %d: Can't create output stream for capture: "
                    "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }

    }
    return OK;
}

status_t Camera2Client::updateCaptureRequest(const Parameters &params) {
    ATRACE_CALL();
    status_t res;
+20 −55
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "CameraService.h"
#include "camera2/Parameters.h"
#include "camera2/FrameProcessor.h"
#include "camera2/CaptureProcessor.h"
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <gui/CpuConsumer.h>
@@ -37,7 +38,9 @@ class Camera2Client :
        public Camera2Device::NotificationListener
{
public:
    // ICamera interface (see ICamera for details)
    /**
     * ICamera interface (see ICamera for details)
     */

    virtual void            disconnect();
    virtual status_t        connect(const sp<ICameraClient>& client);
@@ -62,7 +65,9 @@ public:
    virtual String8         getParameters() const;
    virtual status_t        sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);

    // Interface used by CameraService
    /**
     * Interface used by CameraService
     */

    Camera2Client(const sp<CameraService>& cameraService,
            const sp<ICameraClient>& cameraClient,
@@ -75,7 +80,9 @@ public:

    virtual status_t dump(int fd, const Vector<String16>& args);

    // Interface used by CameraDevice
    /**
     * Interface used by Camera2Device
     */

    virtual void notifyError(int errorCode, int arg1, int arg2);
    virtual void notifyShutter(int frameNumber, nsecs_t timestamp);
@@ -83,7 +90,9 @@ public:
    virtual void notifyAutoExposure(uint8_t newState, int triggerId);
    virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);

    // Interface used by independent components of Camera2Client.
    /**
     * Interface used by independent components of Camera2Client.
     */

    int getCameraId();
    const sp<Camera2Device>& getCameraDevice();
@@ -102,6 +111,7 @@ public:
          private:
            SharedCameraClient &mSharedClient;
        };
        SharedCameraClient(const sp<ICameraClient>& client);
        SharedCameraClient& operator=(const sp<ICameraClient>& client);
        void clear();
      private:
@@ -109,6 +119,9 @@ public:
        mutable Mutex mCameraClientLock;
    } mSharedCameraClient;

    static size_t calculateBufferSize(int width, int height,
            int format, int stride);

private:
    /** ICamera interface-related private members */

@@ -145,8 +158,6 @@ private:

    /** Camera device-related private members */

    class Camera2Heap;

    void     setPreviewCallbackFlagL(Parameters &params, int flag);
    status_t updateRequests(const Parameters &params);

@@ -181,7 +192,7 @@ private:
        Camera2Client *mParent;
    };
    sp<CallbackWaiter>  mCallbackWaiter;
    sp<Camera2Heap>     mCallbackHeap;
    sp<camera2::Camera2Heap>     mCallbackHeap;
    int mCallbackHeapId;
    size_t mCallbackHeapHead, mCallbackHeapFree;
    // Handle callback image buffers
@@ -191,26 +202,9 @@ private:

    /* Still image capture related members */

    int mCaptureStreamId;
    sp<CpuConsumer>    mCaptureConsumer;
    sp<ANativeWindow>  mCaptureWindow;
    // Simple listener that forwards frame available notifications from
    // a CPU consumer to the capture notification
    class CaptureWaiter: public CpuConsumer::FrameAvailableListener {
      public:
        CaptureWaiter(Camera2Client *parent) : mParent(parent) {}
        void onFrameAvailable() { mParent->onCaptureAvailable(); }
      private:
        Camera2Client *mParent;
    };
    sp<CaptureWaiter>  mCaptureWaiter;
    sp<camera2::CaptureProcessor> mCaptureProcessor;
    CameraMetadata mCaptureRequest;
    sp<Camera2Heap>    mCaptureHeap;
    // Handle captured image buffers
    void onCaptureAvailable();

    status_t updateCaptureRequest(const Parameters &params);
    status_t updateCaptureStream(const Parameters &params);

    /* Recording related members */

@@ -229,7 +223,7 @@ private:
    };
    sp<RecordingWaiter>  mRecordingWaiter;
    CameraMetadata mRecordingRequest;
    sp<Camera2Heap> mRecordingHeap;
    sp<camera2::Camera2Heap> mRecordingHeap;

    static const size_t kDefaultRecordingHeapCount = 8;
    size_t mRecordingHeapCount;
@@ -254,32 +248,6 @@ private:
    // Verify that caller is the owner of the camera
    status_t checkPid(const char *checkLocation) const;

    // Utility class for managing a set of IMemory blocks
    class Camera2Heap : public RefBase {
    public:
        Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
                const char *name = NULL) :
                         mBufSize(buf_size),
                         mNumBufs(num_buffers) {
            mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name);
            mBuffers = new sp<MemoryBase>[mNumBufs];
            for (uint_t i = 0; i < mNumBufs; i++)
                mBuffers[i] = new MemoryBase(mHeap,
                                             i * mBufSize,
                                             mBufSize);
        }

        virtual ~Camera2Heap()
        {
            delete [] mBuffers;
        }

        size_t mBufSize;
        uint_t mNumBufs;
        sp<MemoryHeapBase> mHeap;
        sp<MemoryBase> *mBuffers;
    };

    // Update parameters all requests use, based on mParameters
    status_t updateRequestCommon(CameraMetadata *request, const Parameters &params) const;

@@ -291,9 +259,6 @@ private:
    int arrayXToNormalized(int width) const;
    int arrayYToNormalized(int height) const;


    static size_t calculateBufferSize(int width, int height,
            int format, int stride);
};

}; // namespace android
+55 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROiD_SERVERS_CAMERA_CAMERA2HEAP_H
#define ANDROiD_SERVERS_CAMERA_CAMERA2HEAP_H

#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>

namespace android {
namespace camera2 {

// Utility class for managing a set of IMemory blocks
class Camera2Heap : public RefBase {
  public:
    Camera2Heap(size_t buf_size, uint_t num_buffers = 1,
            const char *name = NULL) :
            mBufSize(buf_size),
            mNumBufs(num_buffers) {
        mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name);
        mBuffers = new sp<MemoryBase>[mNumBufs];
        for (uint_t i = 0; i < mNumBufs; i++)
            mBuffers[i] = new MemoryBase(mHeap,
                    i * mBufSize,
                    mBufSize);
    }

    virtual ~Camera2Heap()
    {
        delete [] mBuffers;
    }

    size_t mBufSize;
    uint_t mNumBufs;
    sp<MemoryHeapBase> mHeap;
    sp<MemoryBase> *mBuffers;
};

}; // namespace camera2
}; // namespace android

#endif
+248 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "Camera2Client::CaptureProcessor"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0

#include <utils/Log.h>
#include <utils/Trace.h>

#include "CaptureProcessor.h"
#include <gui/SurfaceTextureClient.h>
#include "../Camera2Device.h"
#include "../Camera2Client.h"


namespace android {
namespace camera2 {

CaptureProcessor::CaptureProcessor(wp<Camera2Client> client):
        Thread(false),
        mClient(client),
        mCaptureAvailable(false),
        mCaptureStreamId(NO_STREAM) {
}

CaptureProcessor::~CaptureProcessor() {
    ALOGV("%s: Exit", __FUNCTION__);
}

void CaptureProcessor::onFrameAvailable() {
    Mutex::Autolock l(mInputMutex);
    if (!mCaptureAvailable) {
        mCaptureAvailable = true;
        mCaptureAvailableSignal.signal();
    }
}

status_t CaptureProcessor::updateStream(const Parameters &params) {
    ATRACE_CALL();
    ALOGV("%s", __FUNCTION__);
    status_t res;

    Mutex::Autolock l(mInputMutex);

    sp<Camera2Client> client = mClient.promote();
    if (client == 0) return OK;
    sp<Camera2Device> device = client->getCameraDevice();

    // Find out buffer size for JPEG
    camera_metadata_ro_entry_t maxJpegSize =
            params.staticInfo(ANDROID_JPEG_MAX_SIZE);
    if (maxJpegSize.count == 0) {
        ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
                __FUNCTION__, client->getCameraId());
        return INVALID_OPERATION;
    }

    if (mCaptureConsumer == 0) {
        // Create CPU buffer queue endpoint
        mCaptureConsumer = new CpuConsumer(1);
        mCaptureConsumer->setFrameAvailableListener(this);
        mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
        mCaptureWindow = new SurfaceTextureClient(
            mCaptureConsumer->getProducerInterface());
        // Create memory for API consumption
        mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
                                       "Camera2Client::CaptureHeap");
        if (mCaptureHeap->mHeap->getSize() == 0) {
            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
                    __FUNCTION__, client->getCameraId());
            return NO_MEMORY;
        }
    }

    if (mCaptureStreamId != NO_STREAM) {
        // Check if stream parameters have to change
        uint32_t currentWidth, currentHeight;
        res = device->getStreamInfo(mCaptureStreamId,
                &currentWidth, &currentHeight, 0);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error querying capture output stream info: "
                    "%s (%d)", __FUNCTION__,
                    client->getCameraId(), strerror(-res), res);
            return res;
        }
        if (currentWidth != (uint32_t)params.pictureWidth ||
                currentHeight != (uint32_t)params.pictureHeight) {
            res = device->deleteStream(mCaptureStreamId);
            if (res != OK) {
                ALOGE("%s: Camera %d: Unable to delete old output stream "
                        "for capture: %s (%d)", __FUNCTION__,
                        client->getCameraId(), strerror(-res), res);
                return res;
            }
            mCaptureStreamId = NO_STREAM;
        }
    }

    if (mCaptureStreamId == NO_STREAM) {
        // Create stream for HAL production
        res = device->createStream(mCaptureWindow,
                params.pictureWidth, params.pictureHeight,
                HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
                &mCaptureStreamId);
        if (res != OK) {
            ALOGE("%s: Camera %d: Can't create output stream for capture: "
                    "%s (%d)", __FUNCTION__, client->getCameraId(),
                    strerror(-res), res);
            return res;
        }

    }
    return OK;
}

status_t CaptureProcessor::deleteStream() {
    ATRACE_CALL();
    status_t res;

    Mutex::Autolock l(mInputMutex);

    if (mCaptureStreamId != NO_STREAM) {
        sp<Camera2Client> client = mClient.promote();
        if (client == 0) return OK;
        sp<Camera2Device> device = client->getCameraDevice();

        device->deleteStream(mCaptureStreamId);
        mCaptureStreamId = NO_STREAM;
    }
    return OK;
}

int CaptureProcessor::getStreamId() const {
    Mutex::Autolock l(mInputMutex);
    return mCaptureStreamId;
}

void CaptureProcessor::dump(int fd, const Vector<String16>& args) {
}

bool CaptureProcessor::threadLoop() {
    status_t res;

    {
        Mutex::Autolock l(mInputMutex);
        while (!mCaptureAvailable) {
            res = mCaptureAvailableSignal.waitRelative(mInputMutex,
                    kWaitDuration);
            if (res == TIMED_OUT) return true;
        }
        mCaptureAvailable = false;
    }

    do {
        sp<Camera2Client> client = mClient.promote();
        if (client == 0) return false;
        res = processNewCapture(client);
    } while (res == OK);

    return true;
}

status_t CaptureProcessor::processNewCapture(sp<Camera2Client> &client) {
    ATRACE_CALL();
    status_t res;
    sp<Camera2Heap> captureHeap;

    CpuConsumer::LockedBuffer imgBuffer;

    res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
    if (res != OK) {
        if (res != BAD_VALUE) {
            ALOGE("%s: Camera %d: Error receiving still image buffer: "
                    "%s (%d)", __FUNCTION__,
                    client->getCameraId(), strerror(-res), res);
        }
        return res;
    }

    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__,
            client->getCameraId());

    // TODO: Signal errors here upstream
    {
        SharedParameters::Lock l(client->getParameters());

        switch (l.mParameters.state) {
            case Parameters::STILL_CAPTURE:
                l.mParameters.state = Parameters::STOPPED;
                break;
            case Parameters::VIDEO_SNAPSHOT:
                l.mParameters.state = Parameters::RECORD;
                break;
            default:
                ALOGE("%s: Camera %d: Still image produced unexpectedly "
                        "in state %s!",
                        __FUNCTION__, client->getCameraId(),
                        Parameters::getStateName(l.mParameters.state));
                mCaptureConsumer->unlockBuffer(imgBuffer);
                return BAD_VALUE;
        }
    }

    if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
        ALOGE("%s: Camera %d: Unexpected format for still image: "
                "%x, expected %x", __FUNCTION__, client->getCameraId(),
                imgBuffer.format,
                HAL_PIXEL_FORMAT_BLOB);
        mCaptureConsumer->unlockBuffer(imgBuffer);
        return OK;
    }

    // TODO: Optimize this to avoid memcopy
    void* captureMemory = mCaptureHeap->mHeap->getBase();
    size_t size = mCaptureHeap->mHeap->getSize();
    memcpy(captureMemory, imgBuffer.data, size);

    mCaptureConsumer->unlockBuffer(imgBuffer);

    captureHeap = mCaptureHeap;

    Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
    ALOGV("%s: Sending still image to client", __FUNCTION__);
    if (l.mCameraClient != 0) {
        l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
                captureHeap->mBuffers[0], NULL);
    } else {
        ALOGV("%s: No client!", __FUNCTION__);
    }
    return OK;
}

}; // namespace camera2
}; // namespace android
Loading