summaryrefslogtreecommitdiffstats
path: root/services/camera
diff options
context:
space:
mode:
authorEino-Ville Talvala <etalvala@google.com>2012-06-07 17:12:38 -0700
committerEino-Ville Talvala <etalvala@google.com>2012-06-13 12:03:28 -0700
commitd4bcfde6bf3e7b28e36f6ec66e6d9e5adebfa949 (patch)
tree9a7809d649c25ee5bb30bd7dd46da7753b59fa1a /services/camera
parenta9300fd3d84cc07bbfa702e2fad3b32a5ebfd337 (diff)
downloadframeworks_av-d4bcfde6bf3e7b28e36f6ec66e6d9e5adebfa949.zip
frameworks_av-d4bcfde6bf3e7b28e36f6ec66e6d9e5adebfa949.tar.gz
frameworks_av-d4bcfde6bf3e7b28e36f6ec66e6d9e5adebfa949.tar.bz2
Camera2: Still image support
- Add stream / request creation for still image capture - Add takePicture call - Add callback handler - Fix shutdown bugs (wait until requests have drained) Bug: 6243944 Change-Id: Id73eb7090e61b40b90348d1eb262f641ea5f3229
Diffstat (limited to 'services/camera')
-rw-r--r--services/camera/libcameraservice/Camera2Client.cpp297
-rw-r--r--services/camera/libcameraservice/Camera2Client.h41
-rw-r--r--services/camera/libcameraservice/Camera2Device.cpp99
-rw-r--r--services/camera/libcameraservice/Camera2Device.h66
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,
+ &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) ?
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;