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

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

Merge "Camera2: Still image support"

parents b5a64065 d4bcfde6
Loading
Loading
Loading
Loading
+280 −17
Original line number Diff line number Diff line
@@ -52,8 +52,10 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
        Client(cameraService, cameraClient,
                cameraId, cameraFacing, clientPid),
        mState(NOT_INITIALIZED),
        mPreviewStreamId(NO_PREVIEW_STREAM),
        mPreviewRequest(NULL)
        mPreviewStreamId(NO_STREAM),
        mPreviewRequest(NULL),
        mCaptureStreamId(NO_STREAM),
        mCaptureRequest(NULL)
{
    ATRACE_CALL();

@@ -280,9 +282,16 @@ void Camera2Client::disconnect() {

    stopPreviewLocked();

    if (mPreviewStreamId != NO_PREVIEW_STREAM) {
    mDevice->waitUntilDrained();

    if (mPreviewStreamId != NO_STREAM) {
        mDevice->deleteStream(mPreviewStreamId);
        mPreviewStreamId = NO_PREVIEW_STREAM;
        mPreviewStreamId = NO_STREAM;
    }

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

    CameraService::Client::disconnect();
@@ -323,7 +332,7 @@ status_t Camera2Client::setPreviewDisplay(
        window = surface;
    }

    return setPreviewWindow(binder,window);
    return setPreviewWindowLocked(binder,window);
}

status_t Camera2Client::setPreviewTexture(
@@ -339,10 +348,10 @@ status_t Camera2Client::setPreviewTexture(
        binder = surfaceTexture->asBinder();
        window = new SurfaceTextureClient(surfaceTexture);
    }
    return setPreviewWindow(binder, window);
    return setPreviewWindowLocked(binder, window);
}

status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder,
status_t Camera2Client::setPreviewWindowLocked(const sp<IBinder>& binder,
        const sp<ANativeWindow>& window) {
    ATRACE_CALL();
    status_t res;
@@ -351,7 +360,9 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder,
        return NO_ERROR;
    }

    if (mPreviewStreamId != NO_PREVIEW_STREAM) {
    // TODO: Should wait until HAL has no remaining requests

    if (mPreviewStreamId != NO_STREAM) {
        res = mDevice->deleteStream(mPreviewStreamId);
        if (res != OK) {
            return res;
@@ -359,7 +370,7 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder,
    }
    res = mDevice->createStream(window,
            mParameters.previewWidth, mParameters.previewHeight,
            CAMERA2_HAL_PIXEL_FORMAT_OPAQUE,
            CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
            &mPreviewStreamId);
    if (res != OK) {
        return res;
@@ -368,7 +379,7 @@ status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder,
    mPreviewSurface = binder;

    if (mState == WAITING_FOR_PREVIEW_WINDOW) {
        return startPreview();
        return startPreviewLocked();
    }

    return OK;
@@ -382,11 +393,15 @@ void Camera2Client::setPreviewCallbackFlag(int flag) {
status_t Camera2Client::startPreview() {
    ATRACE_CALL();
    Mutex::Autolock icl(mICameraLock);
    return startPreviewLocked();
}

status_t Camera2Client::startPreviewLocked() {
    ATRACE_CALL();
    status_t res;
    if (mState == PREVIEW) return INVALID_OPERATION;
    if (mState >= PREVIEW) return INVALID_OPERATION;

    if (mPreviewStreamId == NO_PREVIEW_STREAM) {
    if (mPreviewStreamId == NO_STREAM) {
        mState = WAITING_FOR_PREVIEW_WINDOW;
        return OK;
    }
@@ -438,10 +453,28 @@ void Camera2Client::stopPreview() {

void Camera2Client::stopPreviewLocked() {
    ATRACE_CALL();
    if (mState != PREVIEW) return;

    switch (mState) {
        case NOT_INITIALIZED:
            ALOGE("%s: Camera %d: Call before initialized",
                    __FUNCTION__, mCameraId);
            break;
        case STOPPED:
            break;
        case STILL_CAPTURE:
            ALOGE("%s: Camera %d: Cannot stop preview during still capture.",
                    __FUNCTION__, mCameraId);
            break;
        case RECORD:
            // TODO: Handle record stop here
        case PREVIEW:
            mDevice->setStreamingRequest(NULL);
        case WAITING_FOR_PREVIEW_WINDOW:
            mState = STOPPED;
            break;
        default:
            ALOGE("%s: Camera %d: Unknown state %d", __FUNCTION__, mCameraId,
                    mState);
    }
}

bool Camera2Client::previewEnabled() {
@@ -493,7 +526,95 @@ status_t Camera2Client::cancelAutoFocus() {
status_t Camera2Client::takePicture(int msgType) {
    ATRACE_CALL();
    Mutex::Autolock icl(mICameraLock);
    return BAD_VALUE;
    status_t res;

    switch (mState) {
        case NOT_INITIALIZED:
        case STOPPED:
        case WAITING_FOR_PREVIEW_WINDOW:
            ALOGE("%s: Camera %d: Cannot take picture without preview enabled",
                    __FUNCTION__, mCameraId);
            return INVALID_OPERATION;
        case PREVIEW:
        case RECORD:
            // Good to go for takePicture
            break;
        case STILL_CAPTURE:
        case VIDEO_SNAPSHOT:
            ALOGE("%s: Camera %d: Already taking a picture",
                    __FUNCTION__, mCameraId);
            return INVALID_OPERATION;
    }

    Mutex::Autolock pl(mParamsLock);

    res = updateCaptureStream();

    if (mCaptureRequest == NULL) {
        updateCaptureRequest();
    }

    // TODO: For video snapshot, need 3 streams here
    camera_metadata_entry_t outputStreams;
    uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId };
    res = find_camera_metadata_entry(mCaptureRequest,
            ANDROID_REQUEST_OUTPUT_STREAMS,
            &outputStreams);
    if (res == NAME_NOT_FOUND) {
        res = add_camera_metadata_entry(mCaptureRequest,
                ANDROID_REQUEST_OUTPUT_STREAMS,
                streamIds, 2);
    } else if (res == OK) {
        res = update_camera_metadata_entry(mCaptureRequest,
                outputStreams.index, streamIds, 2, NULL);
    }

    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to set up still image capture request: "
                "%s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    camera_metadata_t *captureCopy = clone_camera_metadata(mCaptureRequest);
    if (captureCopy == NULL) {
        ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
                __FUNCTION__, mCameraId);
        return NO_MEMORY;
    }

    if (mState == PREVIEW) {
        res = mDevice->setStreamingRequest(NULL);
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to stop preview for still capture: "
                    "%s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    }

    res = mDevice->capture(captureCopy);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to submit still image capture request: "
                "%s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    switch (mState) {
        case PREVIEW:
            mState = STILL_CAPTURE;
            break;
        case RECORD:
            mState = VIDEO_SNAPSHOT;
            break;
        default:
            ALOGE("%s: Camera %d: Unknown state for still capture!",
                    __FUNCTION__, mCameraId);
            return INVALID_OPERATION;
    }

    return OK;
}

status_t Camera2Client::setParameters(const String8& params) {
@@ -991,6 +1112,7 @@ status_t Camera2Client::setParameters(const String8& params) {
    mParameters.videoStabilization = videoStabilization;

    updatePreviewRequest();
    updateCaptureRequest();

    return OK;
}
@@ -1013,6 +1135,65 @@ status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {

/** Device-related methods */

void Camera2Client::onCaptureAvailable() {
    ATRACE_CALL();
    status_t res;
    sp<ICameraClient> currentClient;
    CpuConsumer::LockedBuffer imgBuffer;
    {
        Mutex::Autolock icl(mICameraLock);

        // TODO: Signal errors here upstream
        if (mState != STILL_CAPTURE && mState != VIDEO_SNAPSHOT) {
            ALOGE("%s: Camera %d: Still image produced unexpectedly!",
                    __FUNCTION__, mCameraId);
            return;
        }

        res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            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->getBase();
        size_t size = mCaptureHeap->getSize();
        memcpy(captureMemory, imgBuffer.data, size);

        mCaptureConsumer->unlockBuffer(imgBuffer);

        currentClient = mCameraClient;
        switch (mState) {
            case STILL_CAPTURE:
                mState = STOPPED;
                break;
            case VIDEO_SNAPSHOT:
                mState = RECORD;
                break;
            default:
                ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__,
                        mCameraId, mState);
                break;
        }
    }
    // Call outside mICameraLock to allow re-entrancy from notification
    if (currentClient != 0) {
        currentClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
                mCaptureMemory, NULL);
    }
}

camera_metadata_entry_t Camera2Client::staticInfo(uint32_t tag,
        size_t minCount, size_t maxCount) {
    status_t res;
@@ -1752,6 +1933,88 @@ status_t Camera2Client::updatePreviewRequest() {
    return OK;
}

status_t Camera2Client::updateCaptureStream() {
    status_t res;
    // Find out buffer size for JPEG
    camera_metadata_entry_t maxJpegSize =
            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 MemoryHeapBase(maxJpegSize.data.i32[0], 0,
                "Camera2Client::CaptureHeap");
        if (mCaptureHeap->getSize() == 0) {
            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
                    __FUNCTION__, mCameraId);
            return NO_MEMORY;
        }
        mCaptureMemory = new MemoryBase(mCaptureHeap,
                0, maxJpegSize.data.i32[0]);
    }
    if (mCaptureStreamId == NO_STREAM) {
        // Create stream for HAL production
        res = mDevice->createStream(mCaptureWindow,
                mParameters.pictureWidth, mParameters.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;
        }

    } else {
        // 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)mParameters.pictureWidth ||
                currentHeight != (uint32_t)mParameters.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;
            return updateCaptureStream();
        }
    }
    return OK;
}
status_t Camera2Client::updateCaptureRequest() {
    ATRACE_CALL();
    status_t res;
    if (mCaptureRequest == NULL) {
        res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_STILL_CAPTURE,
                &mCaptureRequest);
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to create default still image request:"
                    " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    }
    // TODO: Adjust for params changes
    return OK;
}

int Camera2Client::formatStringToEnum(const char *format) {
    return
        !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
+36 −5
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@
#include "Camera2Device.h"
#include "CameraService.h"
#include "camera/CameraParameters.h"
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <gui/CpuConsumer.h>

namespace android {

@@ -73,7 +76,8 @@ private:
        WAITING_FOR_PREVIEW_WINDOW,
        PREVIEW,
        RECORD,
        STILL_CAPTURE
        STILL_CAPTURE,
        VIDEO_SNAPSHOT
    } mState;

    /** ICamera interface-related private members */
@@ -82,11 +86,15 @@ private:
    // Ensures serialization between incoming ICamera calls
    mutable Mutex mICameraLock;

    status_t setPreviewWindow(const sp<IBinder>& binder,
    // The following must be called with mICamaeraLock already locked

    status_t setPreviewWindowLocked(const sp<IBinder>& binder,
            const sp<ANativeWindow>& window);

    void stopPreviewLocked();
    status_t startPreviewLocked();

    // Mutex that must be locked before accessing mParams, mParamsFlattened
    // Mutex that must be locked before accessing mParameters, mParamsFlattened
    mutable Mutex mParamsLock;
    String8 mParamsFlattened;
    // Current camera state; this is the contents of the CameraParameters object
@@ -164,16 +172,34 @@ private:

    /** Camera device-related private members */

    // 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;
    };

    void onCaptureAvailable();

    // Number of zoom steps to simulate
    static const unsigned int NUM_ZOOM_STEPS = 10;
    // Used with mPreviewStreamId
    static const int NO_PREVIEW_STREAM = -1;
    // Used with mPreviewStreamId, mCaptureStreamId
    static const int NO_STREAM = -1;

    sp<IBinder> mPreviewSurface;
    int mPreviewStreamId;
    camera_metadata_t *mPreviewRequest;

    int mCaptureStreamId;
    sp<CpuConsumer>    mCaptureConsumer;
    sp<ANativeWindow>  mCaptureWindow;
    sp<CaptureWaiter>  mCaptureWaiter;
    camera_metadata_t *mCaptureRequest;
    sp<MemoryHeapBase> mCaptureHeap;
    sp<MemoryBase>     mCaptureMemory;

    sp<Camera2Device> mDevice;

@@ -194,6 +220,11 @@ private:
    // Update preview request based on mParams
    status_t updatePreviewRequest();

    // Update capture request based on mParams
    status_t updateCaptureRequest();
    // Update capture stream based on mParams
    status_t updateCaptureStream();

    // Convert camera1 preview format string to camera2 enum
    static int formatStringToEnum(const char *format);
    static const char *formatEnumToString(int format);
+81 −18
Original line number Diff line number Diff line
@@ -111,8 +111,15 @@ camera_metadata_t *Camera2Device::info() {
    return mDeviceInfo;
}

status_t Camera2Device::setStreamingRequest(camera_metadata_t* request)
{
status_t Camera2Device::capture(camera_metadata_t* request) {
    ALOGV("%s: E", __FUNCTION__);

    mRequestQueue.enqueue(request);
    return OK;
}


status_t Camera2Device::setStreamingRequest(camera_metadata_t* request) {
    ALOGV("%s: E", __FUNCTION__);

    mRequestQueue.setStreamSlot(request);
@@ -120,13 +127,13 @@ status_t Camera2Device::setStreamingRequest(camera_metadata_t* request)
}

status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
        uint32_t width, uint32_t height, int format, int *id) {
        uint32_t width, uint32_t height, int format, size_t size, int *id) {
    status_t res;
    ALOGV("%s: E", __FUNCTION__);

    sp<StreamAdapter> stream = new StreamAdapter(mDevice);

    res = stream->connectToDevice(consumer, width, height, format);
    res = stream->connectToDevice(consumer, width, height, format, size);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
                "%s (%d)",
@@ -140,6 +147,31 @@ status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
    return OK;
}

status_t Camera2Device::getStreamInfo(int id,
        uint32_t *width, uint32_t *height, uint32_t *format) {
    ALOGV("%s: E", __FUNCTION__);
    bool found = false;
    StreamList::iterator streamI;
    for (streamI = mStreams.begin();
         streamI != mStreams.end(); streamI++) {
        if ((*streamI)->getId() == id) {
            found = true;
            break;
        }
    }
    if (!found) {
        ALOGE("%s: Camera %d: Stream %d does not exist",
                __FUNCTION__, mId, id);
        return BAD_VALUE;
    }

    if (width) *width = (*streamI)->getWidth();
    if (height) *height = (*streamI)->getHeight();
    if (format) *format = (*streamI)->getFormat();

    return OK;
}

status_t Camera2Device::deleteStream(int id) {
    ALOGV("%s: E", __FUNCTION__);

@@ -163,7 +195,29 @@ status_t Camera2Device::deleteStream(int id) {
status_t Camera2Device::createDefaultRequest(int templateId,
        camera_metadata_t **request) {
    ALOGV("%s: E", __FUNCTION__);
    return mDevice->ops->construct_default_request(mDevice, templateId, request);
    return mDevice->ops->construct_default_request(
        mDevice, templateId, request);
}

status_t Camera2Device::waitUntilDrained() {
    static const uint32_t kSleepTime = 50000; // 50 ms
    static const uint32_t kMaxSleepTime = 10000000; // 10 s

    if (mRequestQueue.getBufferCount() ==
            CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;

    // TODO: Set up notifications from HAL, instead of sleeping here
    uint32_t totalTime = 0;
    while (mDevice->ops->get_in_progress_count(mDevice) > 0) {
        usleep(kSleepTime);
        totalTime += kSleepTime;
        if (totalTime > kMaxSleepTime) {
            ALOGE("%s: Waited %d us, requests still in flight", __FUNCTION__,
                    totalTime);
            return TIMED_OUT;
        }
    }
    return OK;
}

/**
@@ -463,8 +517,9 @@ Camera2Device::StreamAdapter::~StreamAdapter() {
    disconnect();
}

status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consumer,
        uint32_t width, uint32_t height, int format) {
status_t Camera2Device::StreamAdapter::connectToDevice(
        sp<ANativeWindow> consumer,
        uint32_t width, uint32_t height, int format, size_t size) {
    status_t res;

    if (mState != DISCONNECTED) return INVALID_OPERATION;
@@ -476,6 +531,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume
    mConsumerInterface = consumer;
    mWidth = width;
    mHeight = height;
    mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0;
    mFormatRequested = format;

    // Allocate device-side stream interface
@@ -534,6 +590,16 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume
        return res;
    }

    if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
        res = native_window_set_buffers_geometry(mConsumerInterface.get(),
                mSize, 1, mFormat);
        if (res != OK) {
            ALOGE("%s: Unable to configure compressed stream buffer geometry"
                    " %d x %d, size %d for stream %d",
                    __FUNCTION__, mWidth, mHeight, mSize, mId);
            return res;
        }
    } else {
        res = native_window_set_buffers_geometry(mConsumerInterface.get(),
                mWidth, mHeight, mFormat);
        if (res != OK) {
@@ -542,6 +608,7 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume
                    __FUNCTION__, mWidth, mHeight, mFormat, mId);
            return res;
        }
    }

    int maxConsumerBuffers;
    res = mConsumerInterface->query(mConsumerInterface.get(),
@@ -641,10 +708,6 @@ status_t Camera2Device::StreamAdapter::disconnect() {
    return OK;
}

int Camera2Device::StreamAdapter::getId() {
    return mId;
}

const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
    return static_cast<camera2_stream_ops *>(this);
}
+61 −5
Original line number Diff line number Diff line
@@ -37,17 +37,58 @@ class Camera2Device : public virtual RefBase {

    camera_metadata_t* info();

    /**
     * Submit request for capture. The Camera2Device takes ownership of the
     * passed-in buffer.
     */
    status_t capture(camera_metadata_t *request);

    /**
     * Submit request for streaming. The Camera2Device makes a copy of the
     * passed-in buffer and the caller retains ownership.
     */
    status_t setStreamingRequest(camera_metadata_t *request);

    /**
     * Create an output stream of the requested size and format.
     *
     * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects
     * an appropriate format; it can be queried with getStreamInfo.
     *
     * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be
     * equal to the size in bytes of the buffers to allocate for the stream. For
     * other formats, the size parameter is ignored.
     */
    status_t createStream(sp<ANativeWindow> consumer,
            uint32_t width, uint32_t height, int format,
            uint32_t width, uint32_t height, int format, size_t size,
            int *id);

    /**
     * Get information about a given stream.
     */
    status_t getStreamInfo(int id,
            uint32_t *width, uint32_t *height, uint32_t *format);

    /**
     * Delete stream. Must not be called if there are requests in flight which
     * reference that stream.
     */
    status_t deleteStream(int id);

    /**
     * Create a metadata buffer with fields that the HAL device believes are
     * best for the given use case
     */
    status_t createDefaultRequest(int templateId,
            camera_metadata_t **request);

    /**
     * Wait until all requests have been processed. Returns INVALID_OPERATION if
     * the streaming slot is not empty, or TIMED_OUT if the requests haven't
     * finished processing in 10 seconds.
     */
    status_t waitUntilDrained();

  private:

    const int mId;
@@ -150,13 +191,27 @@ class Camera2Device : public virtual RefBase {

        ~StreamAdapter();

        /**
         * Create a HAL device stream of the requested size and format.
         *
         * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device
         * selects an appropriate format; it can be queried with getFormat.
         *
         * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must
         * be equal to the size in bytes of the buffers to allocate for the
         * stream. For other formats, the size parameter is ignored.
         */
        status_t connectToDevice(sp<ANativeWindow> consumer,
                uint32_t width, uint32_t height, int format);
                uint32_t width, uint32_t height, int format, size_t size);

        status_t disconnect();

        // Get stream ID. Only valid after a successful connectToDevice call.
        int      getId();
        // Get stream parameters.
        // Only valid after a successful connectToDevice call.
        int      getId() const     { return mId; }
        uint32_t getWidth() const  { return mWidth; }
        uint32_t getHeight() const { return mHeight; }
        uint32_t getFormat() const { return mFormat; }

      private:
        enum {
@@ -174,6 +229,7 @@ class Camera2Device : public virtual RefBase {
        uint32_t mWidth;
        uint32_t mHeight;
        uint32_t mFormat;
        size_t   mSize;
        uint32_t mUsage;
        uint32_t mMaxProducerBuffers;
        uint32_t mMaxConsumerBuffers;