Camera service: Minimally functional preview for camera 2 devices.
- Camera app starts up
- Basic preview operation with defaults
- Shutdown sequence is very minimal
Bug: 6243944
Change-Id: I67673b7c1fc08956d218d99f9171e74a7a82bf07
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index d0a84a5..9825af7 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -57,7 +57,10 @@
int clientPid):
Client(cameraService, cameraClient,
cameraId, cameraFacing, clientPid),
- mParams(NULL)
+ mState(NOT_INITIALIZED),
+ mParams(NULL),
+ mPreviewStreamId(NO_PREVIEW_STREAM),
+ mPreviewRequest(NULL)
{
ALOG1_ENTRY;
@@ -90,6 +93,8 @@
mParams->dump();
}
+ mState = STOPPED;
+
ALOG1_EXIT;
return OK;
}
@@ -118,7 +123,12 @@
if (mDevice == 0) return;
- mDevice->setStreamingRequest(NULL);
+ stopPreview();
+
+ if (mPreviewStreamId != NO_PREVIEW_STREAM) {
+ mDevice->deleteStream(mPreviewStreamId);
+ mPreviewStreamId = NO_PREVIEW_STREAM;
+ }
CameraService::Client::disconnect();
}
@@ -135,12 +145,67 @@
return BAD_VALUE;
}
-status_t Camera2Client::setPreviewDisplay(const sp<Surface>& surface) {
- return BAD_VALUE;
+status_t Camera2Client::setPreviewDisplay(
+ const sp<Surface>& surface) {
+ ALOG1_ENTRY;
+ if (mState == PREVIEW) return INVALID_OPERATION;
+
+ sp<IBinder> binder;
+ sp<ANativeWindow> window;
+ if (surface != 0) {
+ binder = surface->asBinder();
+ window = surface;
+ }
+
+ return setPreviewWindow(binder,window);
}
-status_t Camera2Client::setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture) {
- return BAD_VALUE;
+status_t Camera2Client::setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture) {
+ ALOG1_ENTRY;
+ if (mState == PREVIEW) return INVALID_OPERATION;
+
+ sp<IBinder> binder;
+ sp<ANativeWindow> window;
+ if (surfaceTexture != 0) {
+ binder = surfaceTexture->asBinder();
+ window = new SurfaceTextureClient(surfaceTexture);
+ }
+ return setPreviewWindow(binder, window);
+}
+
+status_t Camera2Client::setPreviewWindow(const sp<IBinder>& binder,
+ const sp<ANativeWindow>& window) {
+ ALOG1_ENTRY;
+ status_t res;
+
+ if (binder == mPreviewSurface) {
+ return NO_ERROR;
+ }
+
+ if (mPreviewStreamId != NO_PREVIEW_STREAM) {
+ res = mDevice->deleteStream(mPreviewStreamId);
+ if (res != OK) {
+ return res;
+ }
+ }
+
+ int previewWidth, previewHeight;
+ mParams->getPreviewSize(&previewWidth, &previewHeight);
+
+ res = mDevice->createStream(window,
+ previewWidth, previewHeight, CAMERA2_HAL_PIXEL_FORMAT_OPAQUE,
+ &mPreviewStreamId);
+ if (res != OK) {
+ return res;
+ }
+
+ if (mState == WAITING_FOR_PREVIEW_WINDOW) {
+ return startPreview();
+ }
+
+ ALOG1_EXIT;
+ return OK;
}
void Camera2Client::setPreviewCallbackFlag(int flag) {
@@ -148,15 +213,63 @@
}
status_t Camera2Client::startPreview() {
- return BAD_VALUE;
+ ALOG1_ENTRY;
+ status_t res;
+ if (mState == PREVIEW) return INVALID_OPERATION;
+
+ if (mPreviewStreamId == NO_PREVIEW_STREAM) {
+ mState = WAITING_FOR_PREVIEW_WINDOW;
+ return OK;
+ }
+
+ if (mPreviewRequest == NULL) {
+ updatePreviewRequest();
+ }
+
+ uint8_t outputStream = mPreviewStreamId;
+
+ camera_metadata_entry_t outputStreams;
+ res = find_camera_metadata_entry(mPreviewRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ &outputStreams);
+ if (res == NAME_NOT_FOUND) {
+ res = add_camera_metadata_entry(mPreviewRequest,
+ ANDROID_REQUEST_OUTPUT_STREAMS,
+ &outputStream, 1);
+ } else if (res == OK) {
+ res = update_camera_metadata_entry(mPreviewRequest,
+ outputStreams.index, &outputStream, 1, NULL);
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ mState = STOPPED;
+ return res;
+ }
+
+ res = mDevice->setStreamingRequest(mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set preview request to start preview: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ mState = STOPPED;
+ return res;
+ }
+ mState = PREVIEW;
+
+ return OK;
}
void Camera2Client::stopPreview() {
+ ALOG1_ENTRY;
+ if (mState != PREVIEW) return;
+ mDevice->setStreamingRequest(NULL);
+ mState = STOPPED;
}
bool Camera2Client::previewEnabled() {
- return false;
+ return mState == PREVIEW;
}
status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
@@ -179,11 +292,11 @@
}
status_t Camera2Client::autoFocus() {
- return BAD_VALUE;
+ return OK;
}
status_t Camera2Client::cancelAutoFocus() {
- return BAD_VALUE;
+ return OK;
}
status_t Camera2Client::takePicture(int msgType) {
@@ -191,7 +304,7 @@
}
status_t Camera2Client::setParameters(const String8& params) {
- return BAD_VALUE;
+ return OK;
}
String8 Camera2Client::getParameters() const {
@@ -199,7 +312,7 @@
}
status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
- return BAD_VALUE;
+ return OK;
}
// private methods
@@ -781,7 +894,7 @@
"(0,0,0,0,0)");
mParams->set(CameraParameters::KEY_ZOOM, 0);
- mParams->set(CameraParameters::KEY_MAX_ZOOM, kNumZoomSteps - 1);
+ mParams->set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
camera_metadata_entry_t maxDigitalZoom;
res = find_camera_metadata_entry(mDevice->info(),
@@ -792,9 +905,9 @@
String8 zoomRatios;
float zoom = 1.f;
float zoomIncrement = (maxDigitalZoom.data.f[0] - zoom) /
- (kNumZoomSteps-1);
+ (NUM_ZOOM_STEPS-1);
bool addComma = false;
- for (size_t i=0; i < kNumZoomSteps; i++) {
+ for (size_t i=0; i < NUM_ZOOM_STEPS; i++) {
if (addComma) zoomRatios += ",";
addComma = true;
zoomRatios += String8::format("%d", static_cast<int>(zoom * 100));
@@ -846,4 +959,21 @@
return OK;
}
+status_t Camera2Client::updatePreviewRequest() {
+ ALOG1_ENTRY
+ status_t res;
+ if (mPreviewRequest == NULL) {
+ res = mDevice->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &mPreviewRequest);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create default preview request: "
+ "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+ }
+ // TODO: Adjust for mParams changes
+ ALOG1_EXIT
+ return OK;
+}
+
} // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 4f0fcf0..fb701ab 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -36,7 +36,8 @@
virtual status_t lock();
virtual status_t unlock();
virtual status_t setPreviewDisplay(const sp<Surface>& surface);
- virtual status_t setPreviewTexture(const sp<ISurfaceTexture>& surfaceTexture);
+ virtual status_t setPreviewTexture(
+ const sp<ISurfaceTexture>& surfaceTexture);
virtual void setPreviewCallbackFlag(int flag);
virtual status_t startPreview();
virtual void stopPreview();
@@ -66,15 +67,35 @@
virtual status_t dump(int fd, const Vector<String16>& args);
private:
- CameraParameters *mParams;
+ // Number of zoom steps to simulate
+ static const unsigned int NUM_ZOOM_STEPS = 10;
+ // Used with mPreviewStreamId
+ static const int NO_PREVIEW_STREAM = -1;
+
+ enum {
+ NOT_INITIALIZED,
+ STOPPED,
+ WAITING_FOR_PREVIEW_WINDOW,
+ PREVIEW
+ } mState;
+
sp<Camera2Device> mDevice;
+ CameraParameters *mParams;
+
+ sp<IBinder> mPreviewSurface;
+ int mPreviewStreamId;
+ camera_metadata_t *mPreviewRequest;
+
+ status_t setPreviewWindow(const sp<IBinder>& binder,
+ const sp<ANativeWindow>& window);
+
// Convert static camera info from a camera2 device to the
// old API parameter map.
status_t buildDefaultParameters();
- // Free parameters for mapping from new to old HAL
- static const unsigned int kNumZoomSteps = 10;
+ // Update preview request based on mParams
+ status_t updatePreviewRequest();
};
}; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 4b0cfc4..bd62fa1 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -26,11 +26,12 @@
mId(id),
mDevice(NULL)
{
-
+ ALOGV("%s: E", __FUNCTION__);
}
Camera2Device::~Camera2Device()
{
+ ALOGV("%s: E", __FUNCTION__);
if (mDevice) {
status_t res;
res = mDevice->common.close(&mDevice->common);
@@ -45,6 +46,8 @@
status_t Camera2Device::initialize(camera_module_t *module)
{
+ ALOGV("%s: E", __FUNCTION__);
+
status_t res;
char name[10];
snprintf(name, sizeof(name), "%d", mId);
@@ -79,26 +82,90 @@
mDeviceInfo = info.static_camera_characteristics;
- res = mDevice->ops->set_request_queue_src_ops(mDevice,
- mRequestQueue.getToConsumerInterface());
- if (res != OK) return res;
-
- res = mDevice->ops->set_frame_queue_dst_ops(mDevice,
- mFrameQueue.getToProducerInterface());
- if (res != OK) return res;
+ res = mRequestQueue.setConsumerDevice(mDevice);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
+ res = mFrameQueue.setProducerDevice(mDevice);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
res = mDevice->ops->get_metadata_vendor_tag_ops(mDevice, &mVendorTagOps);
- if (res != OK ) return res;
+ if (res != OK ) {
+ ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ return res;
+ }
return OK;
}
+camera_metadata_t *Camera2Device::info() {
+ ALOGV("%s: E", __FUNCTION__);
+
+ return mDeviceInfo;
+}
+
status_t Camera2Device::setStreamingRequest(camera_metadata_t* request)
{
+ ALOGV("%s: E", __FUNCTION__);
+
mRequestQueue.setStreamSlot(request);
return OK;
}
+status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format, int *id) {
+ status_t res;
+ ALOGV("%s: E", __FUNCTION__);
+
+ sp<StreamAdapter> stream = new StreamAdapter(mDevice);
+
+ res = stream->connectToDevice(consumer, width, height, format);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
+ "%s (%d)",
+ __FUNCTION__, mId, width, height, format, strerror(-res), res);
+ return res;
+ }
+
+ *id = stream->getId();
+
+ mStreams.push_back(stream);
+ return OK;
+}
+
+status_t Camera2Device::deleteStream(int id) {
+ ALOGV("%s: E", __FUNCTION__);
+
+ bool found = false;
+ for (StreamList::iterator streamI = mStreams.begin();
+ streamI != mStreams.end(); streamI++) {
+ if ((*streamI)->getId() == id) {
+ mStreams.erase(streamI);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("%s: Camera %d: Unable to find stream %d to delete",
+ __FUNCTION__, mId, id);
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+status_t Camera2Device::createDefaultRequest(int templateId,
+ camera_metadata_t **request) {
+ ALOGV("%s: E", __FUNCTION__);
+ return mDevice->ops->construct_default_request(mDevice, templateId, request);
+}
+
/**
* Camera2Device::MetadataQueue
*/
@@ -125,39 +192,32 @@
freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
}
-// Interface to camera2 HAL as consumer (input requests/reprocessing)
-const camera2_request_queue_src_ops_t*
-Camera2Device::MetadataQueue::getToConsumerInterface() {
- return static_cast<camera2_request_queue_src_ops_t*>(this);
-}
-
-void Camera2Device::MetadataQueue::setFromConsumerInterface(camera2_device_t *d) {
- Mutex::Autolock l(mMutex);
+// Connect to camera2 HAL as consumer (input requests/reprocessing)
+status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
+ status_t res;
+ res = d->ops->set_request_queue_src_ops(d,
+ this);
+ if (res != OK) return res;
mDevice = d;
+ return OK;
}
-const camera2_frame_queue_dst_ops_t*
-Camera2Device::MetadataQueue::getToProducerInterface() {
- return static_cast<camera2_frame_queue_dst_ops_t*>(this);
+status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
+ status_t res;
+ res = d->ops->set_frame_queue_dst_ops(d,
+ this);
+ return res;
}
// Real interfaces
status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
+ ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock l(mMutex);
mCount++;
mEntries.push_back(buf);
- notEmpty.signal();
- if (mSignalConsumer && mDevice != NULL) {
- mSignalConsumer = false;
-
- mMutex.unlock();
- ALOGV("%s: Signaling consumer", __FUNCTION__);
- mDevice->ops->notify_request_queue_not_empty(mDevice);
- mMutex.lock();
- }
- return OK;
+ return signalConsumerLocked();
}
int Camera2Device::MetadataQueue::getBufferCount() {
@@ -171,6 +231,8 @@
status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
bool incrementCount)
{
+ ALOGV("%s: E", __FUNCTION__);
+ status_t res;
Mutex::Autolock l(mMutex);
if (mCount == 0) {
@@ -201,9 +263,16 @@
mEntries.erase(mEntries.begin());
if (incrementCount) {
- add_camera_metadata_entry(b,
+ camera_metadata_entry_t frameCount;
+ res = find_camera_metadata_entry(b,
ANDROID_REQUEST_FRAME_COUNT,
- (void**)&mFrameCount, 1);
+ &frameCount);
+ if (res != OK) {
+ ALOGE("%s: Unable to add frame count: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ } else {
+ *frameCount.data.i32 = mFrameCount;
+ }
mFrameCount++;
}
@@ -226,6 +295,7 @@
status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
{
+ ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock l(mMutex);
if (buf == NULL) {
freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
@@ -244,20 +314,34 @@
mStreamSlot.push_front(buf);
mStreamSlotCount = 1;
}
- return OK;
+ return signalConsumerLocked();
}
status_t Camera2Device::MetadataQueue::setStreamSlot(
const List<camera_metadata_t*> &bufs)
{
+ ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock l(mMutex);
if (mStreamSlotCount > 0) {
freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
}
mStreamSlot = bufs;
mStreamSlotCount = mStreamSlot.size();
+ return signalConsumerLocked();
+}
- return OK;
+status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
+ status_t res = OK;
+ notEmpty.signal();
+ if (mSignalConsumer && mDevice != NULL) {
+ mSignalConsumer = false;
+
+ mMutex.unlock();
+ ALOGV("%s: Signaling consumer", __FUNCTION__);
+ res = mDevice->ops->notify_request_queue_not_empty(mDevice);
+ mMutex.lock();
+ }
+ return res;
}
status_t Camera2Device::MetadataQueue::freeBuffers(
@@ -337,5 +421,268 @@
return queue->enqueue(filled_buffer);
}
+/**
+ * Camera2Device::StreamAdapter
+ */
+
+#ifndef container_of
+#define container_of(ptr, type, member) \
+ (type *)((char*)(ptr) - offsetof(type, member))
+#endif
+
+Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
+ mState(DISCONNECTED),
+ mDevice(d),
+ mId(-1),
+ mWidth(0), mHeight(0), mFormatRequested(0)
+{
+ camera2_stream_ops::dequeue_buffer = dequeue_buffer;
+ camera2_stream_ops::enqueue_buffer = enqueue_buffer;
+ camera2_stream_ops::cancel_buffer = cancel_buffer;
+ camera2_stream_ops::set_crop = set_crop;
+}
+
+Camera2Device::StreamAdapter::~StreamAdapter() {
+ disconnect();
+}
+
+status_t Camera2Device::StreamAdapter::connectToDevice(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format) {
+ status_t res;
+
+ if (mState != DISCONNECTED) return INVALID_OPERATION;
+ if (consumer == NULL) {
+ ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ mConsumerInterface = consumer;
+ mWidth = width;
+ mHeight = height;
+ mFormatRequested = format;
+
+ // Allocate device-side stream interface
+
+ uint32_t id;
+ uint32_t formatActual;
+ uint32_t usage;
+ uint32_t maxBuffers = 2;
+ res = mDevice->ops->allocate_stream(mDevice,
+ mWidth, mHeight, mFormatRequested, getStreamOps(),
+ &id, &formatActual, &usage, &maxBuffers);
+ if (res != OK) {
+ ALOGE("%s: Device stream allocation failed: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ mId = id;
+ mFormat = formatActual;
+ mUsage = usage;
+ mMaxProducerBuffers = maxBuffers;
+
+ mState = ALLOCATED;
+
+ // Configure consumer-side ANativeWindow interface
+ res = native_window_api_connect(mConsumerInterface.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (res != OK) {
+ ALOGE("%s: Unable to connect to native window for stream %d",
+ __FUNCTION__, mId);
+
+ return res;
+ }
+
+ mState = CONNECTED;
+
+ res = native_window_set_usage(mConsumerInterface.get(), mUsage);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure usage %08x for stream %d",
+ __FUNCTION__, mUsage, mId);
+ return res;
+ }
+
+ res = native_window_set_buffers_geometry(mConsumerInterface.get(),
+ mWidth, mHeight, mFormat);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure buffer geometry"
+ " %d x %d, format 0x%x for stream %d",
+ __FUNCTION__, mWidth, mHeight, mFormat, mId);
+ return res;
+ }
+
+ int maxConsumerBuffers;
+ res = mConsumerInterface->query(mConsumerInterface.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
+ if (res != OK) {
+ ALOGE("%s: Unable to query consumer undequeued"
+ " buffer count for stream %d", __FUNCTION__, mId);
+ return res;
+ }
+ mMaxConsumerBuffers = maxConsumerBuffers;
+
+ ALOGV("%s: Producer wants %d buffers, consumer wants %d", __FUNCTION__,
+ mMaxProducerBuffers, mMaxConsumerBuffers);
+
+ int totalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
+
+ res = native_window_set_buffer_count(mConsumerInterface.get(),
+ totalBuffers);
+ if (res != OK) {
+ ALOGE("%s: Unable to set buffer count for stream %d",
+ __FUNCTION__, mId);
+ return res;
+ }
+
+ // Register allocated buffers with HAL device
+ buffer_handle_t *buffers = new buffer_handle_t[totalBuffers];
+ ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[totalBuffers];
+ int bufferIdx = 0;
+ for (; bufferIdx < totalBuffers; bufferIdx++) {
+ res = mConsumerInterface->dequeueBuffer(mConsumerInterface.get(),
+ &anwBuffers[bufferIdx]);
+ if (res != OK) {
+ ALOGE("%s: Unable to dequeue buffer %d for initial registration for"
+ "stream %d", __FUNCTION__, bufferIdx, mId);
+ goto cleanUpBuffers;
+ }
+
+ res = mConsumerInterface->lockBuffer(mConsumerInterface.get(),
+ anwBuffers[bufferIdx]);
+ if (res != OK) {
+ ALOGE("%s: Unable to lock buffer %d for initial registration for"
+ "stream %d", __FUNCTION__, bufferIdx, mId);
+ bufferIdx++;
+ goto cleanUpBuffers;
+ }
+
+ buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
+ }
+
+ res = mDevice->ops->register_stream_buffers(mDevice,
+ mId,
+ totalBuffers,
+ buffers);
+ if (res != OK) {
+ ALOGE("%s: Unable to register buffers with HAL device for stream %d",
+ __FUNCTION__, mId);
+ } else {
+ mState = ACTIVE;
+ }
+
+cleanUpBuffers:
+ for (int i = 0; i < bufferIdx; i++) {
+ res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
+ anwBuffers[i]);
+ if (res != OK) {
+ ALOGE("%s: Unable to cancel buffer %d after registration",
+ __FUNCTION__, i);
+ }
+ }
+ delete anwBuffers;
+ delete buffers;
+
+ return res;
+}
+
+status_t Camera2Device::StreamAdapter::disconnect() {
+ status_t res;
+ if (mState >= ALLOCATED) {
+ res = mDevice->ops->release_stream(mDevice, mId);
+ if (res != OK) {
+ ALOGE("%s: Unable to release stream %d",
+ __FUNCTION__, mId);
+ return res;
+ }
+ }
+ if (mState >= CONNECTED) {
+ res = native_window_api_disconnect(mConsumerInterface.get(),
+ NATIVE_WINDOW_API_CAMERA);
+ if (res != OK) {
+ ALOGE("%s: Unable to disconnect stream %d from native window",
+ __FUNCTION__, mId);
+ return res;
+ }
+ }
+ mId = -1;
+ mState = DISCONNECTED;
+ return OK;
+}
+
+int Camera2Device::StreamAdapter::getId() {
+ return mId;
+}
+
+const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
+ return static_cast<camera2_stream_ops *>(this);
+}
+
+ANativeWindow* Camera2Device::StreamAdapter::toANW(
+ const camera2_stream_ops_t *w) {
+ return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
+}
+
+int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
+ buffer_handle_t** buffer) {
+ int res;
+ int state = static_cast<const StreamAdapter*>(w)->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+
+ ANativeWindow *a = toANW(w);
+ ANativeWindowBuffer* anb;
+ res = a->dequeueBuffer(a, &anb);
+ if (res != OK) return res;
+ res = a->lockBuffer(a, anb);
+ if (res != OK) return res;
+
+ *buffer = &(anb->handle);
+ ALOGV("%s: Buffer %p", __FUNCTION__, *buffer);
+ return res;
+}
+
+int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
+ int64_t timestamp,
+ buffer_handle_t* buffer) {
+ ALOGV("%s: Buffer %p captured at %lld ns", __FUNCTION__, buffer, timestamp);
+ int state = static_cast<const StreamAdapter*>(w)->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+ ANativeWindow *a = toANW(w);
+ status_t err;
+ err = native_window_set_buffers_timestamp(a, timestamp);
+ if (err != OK) return err;
+ return a->queueBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle));
+}
+
+int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
+ buffer_handle_t* buffer) {
+ int state = static_cast<const StreamAdapter*>(w)->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+ ANativeWindow *a = toANW(w);
+ return a->cancelBuffer(a,
+ container_of(buffer, ANativeWindowBuffer, handle));
+}
+
+int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
+ int left, int top, int right, int bottom) {
+ int state = static_cast<const StreamAdapter*>(w)->mState;
+ if (state != ACTIVE) {
+ ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
+ return INVALID_OPERATION;
+ }
+ ANativeWindow *a = toANW(w);
+ android_native_rect_t crop = { left, top, right, bottom };
+ return native_window_set_crop(a, &crop);
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 07c5ff7..e8a68d3 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -19,6 +19,7 @@
#include <utils/RefBase.h>
#include <utils/List.h>
+#include <utils/Vector.h>
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include <utils/Errors.h>
@@ -34,11 +35,18 @@
status_t initialize(camera_module_t *module);
+ camera_metadata_t* info();
+
status_t setStreamingRequest(camera_metadata_t* request);
- camera_metadata_t* info() {
- return mDeviceInfo;
- }
+ status_t createStream(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format,
+ int *id);
+
+ status_t deleteStream(int id);
+
+ status_t createDefaultRequest(int templateId,
+ camera_metadata_t **request);
private:
@@ -63,6 +71,11 @@
const camera2_request_queue_src_ops_t* getToConsumerInterface();
void setFromConsumerInterface(camera2_device_t *d);
+ // Connect queue consumer endpoint to a camera2 device
+ status_t setConsumerDevice(camera2_device_t *d);
+ // Connect queue producer endpoint to a camera2 device
+ status_t setProducerDevice(camera2_device_t *d);
+
const camera2_frame_queue_dst_ops_t* getToProducerInterface();
// Real interfaces. On enqueue, queue takes ownership of buffer pointer
@@ -79,6 +92,7 @@
status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
private:
+ status_t signalConsumerLocked();
status_t freeBuffers(List<camera_metadata_t*>::iterator start,
List<camera_metadata_t*>::iterator end);
@@ -125,6 +139,67 @@
MetadataQueue mRequestQueue;
MetadataQueue mFrameQueue;
+ /**
+ * Adapter from an ANativeWindow interface to camera2 device stream ops.
+ * Also takes care of allocating/deallocating stream in device interface
+ */
+ class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
+ public:
+ StreamAdapter(camera2_device_t *d);
+
+ ~StreamAdapter();
+
+ status_t connectToDevice(sp<ANativeWindow> consumer,
+ uint32_t width, uint32_t height, int format);
+
+ status_t disconnect();
+
+ // Get stream ID. Only valid after a successful connectToDevice call.
+ int getId();
+
+ private:
+ enum {
+ ERROR = -1,
+ DISCONNECTED = 0,
+ ALLOCATED,
+ CONNECTED,
+ ACTIVE
+ } mState;
+
+ sp<ANativeWindow> mConsumerInterface;
+ camera2_device_t *mDevice;
+
+ uint32_t mId;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ uint32_t mFormat;
+ uint32_t mUsage;
+ uint32_t mMaxProducerBuffers;
+ uint32_t mMaxConsumerBuffers;
+
+ int mFormatRequested;
+
+ const camera2_stream_ops *getStreamOps();
+
+ static ANativeWindow* toANW(const camera2_stream_ops_t *w);
+
+ static int dequeue_buffer(const camera2_stream_ops_t *w,
+ buffer_handle_t** buffer);
+
+ static int enqueue_buffer(const camera2_stream_ops_t* w,
+ int64_t timestamp,
+ buffer_handle_t* buffer);
+
+ static int cancel_buffer(const camera2_stream_ops_t* w,
+ buffer_handle_t* buffer);
+
+ static int set_crop(const camera2_stream_ops_t* w,
+ int left, int top, int right, int bottom);
+ }; // class StreamAdapter
+
+ typedef List<sp<StreamAdapter> > StreamList;
+ StreamList mStreams;
+
}; // class Camera2Device
}; // namespace android