diff options
Diffstat (limited to 'services/camera')
-rw-r--r-- | services/camera/libcameraservice/Camera2Client.cpp | 297 | ||||
-rw-r--r-- | services/camera/libcameraservice/Camera2Client.h | 41 | ||||
-rw-r--r-- | services/camera/libcameraservice/Camera2Device.cpp | 99 | ||||
-rw-r--r-- | services/camera/libcameraservice/Camera2Device.h | 66 |
4 files changed, 458 insertions, 45 deletions
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 1cea906..05a54b7 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -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; - - mDevice->setStreamingRequest(NULL); - mState = STOPPED; + 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, + ¤tWidth, ¤tHeight, 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) ? diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index e2a0086..5457343 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -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); diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp index b81d54c..8cb872a 100644 --- a/services/camera/libcameraservice/Camera2Device.cpp +++ b/services/camera/libcameraservice/Camera2Device.cpp @@ -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,13 +590,24 @@ status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consume return res; } - res = native_window_set_buffers_geometry(mConsumerInterface.get(), - mWidth, mHeight, mFormat); - if (res != OK) { - ALOGE("%s: Unable to configure stream buffer geometry" - " %d x %d, format 0x%x for stream %d", - __FUNCTION__, mWidth, mHeight, mFormat, mId); - 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) { + ALOGE("%s: Unable to configure stream buffer geometry" + " %d x %d, format 0x%x for stream %d", + __FUNCTION__, mWidth, mHeight, mFormat, mId); + return res; + } } int maxConsumerBuffers; @@ -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); } diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h index 2da3ade..7071561 100644 --- a/services/camera/libcameraservice/Camera2Device.h +++ b/services/camera/libcameraservice/Camera2Device.h @@ -37,17 +37,58 @@ class Camera2Device : public virtual RefBase { camera_metadata_t* info(); - status_t setStreamingRequest(camera_metadata_t* request); + /** + * 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; |