diff options
author | Eino-Ville Talvala <etalvala@google.com> | 2013-03-06 16:20:06 -0800 |
---|---|---|
committer | Eino-Ville Talvala <etalvala@google.com> | 2013-03-27 16:54:34 -0700 |
commit | 8be20f50711a94426f1394ec113672e41c1224e8 (patch) | |
tree | 055fb43c5e7deff31aa055cf5a74f132b7dabd2e /services | |
parent | ad065d38daace14281801127bd447114b7b4daa5 (diff) | |
download | frameworks_av-8be20f50711a94426f1394ec113672e41c1224e8.zip frameworks_av-8be20f50711a94426f1394ec113672e41c1224e8.tar.gz frameworks_av-8be20f50711a94426f1394ec113672e41c1224e8.tar.bz2 |
Camera: Add streams to camera3 HAL device
- Generic stream interface
- Functional output stream
- Skeleton input/zsl stream
Change-Id: I143794eac1a2217031d62b51912662fc6d1db900
Diffstat (limited to 'services')
9 files changed, 1363 insertions, 0 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 8600735..6847bf8 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -25,6 +25,10 @@ LOCAL_SRC_FILES:= \ camera2/JpegCompressor.cpp \ camera2/CaptureSequencer.cpp \ camera2/ProFrameProcessor.cpp \ + camera3/Camera3Stream.cpp \ + camera3/Camera3InputStream.cpp \ + camera3/Camera3OutputStream.cpp \ + camera3/Camera3ZslStream.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp new file mode 100644 index 0000000..8a48ee5 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera3-InputStream" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Trace.h> +#include "Camera3InputStream.h" + +namespace android { + +namespace camera3 { + +Camera3InputStream::Camera3InputStream(int id, + uint32_t width, uint32_t height, int format) : + Camera3Stream(id, CAMERA3_STREAM_INPUT, width, height, 0, format) { +} + +status_t Camera3InputStream::getBufferLocked(camera3_stream_buffer *buffer) { + (void) buffer; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t Camera3InputStream::returnBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp) { + (void) timestamp; + (void) buffer; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +bool Camera3InputStream::hasOutstandingBuffersLocked() const { + ALOGE("%s: Not implemented", __FUNCTION__); + return false; +} + +status_t Camera3InputStream::waitUntilIdle(nsecs_t timeout) { + (void) timeout; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t Camera3InputStream::disconnectLocked() { + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +sp<IGraphicBufferProducer> Camera3InputStream::getProducerInterface() const { + return mConsumer->getProducerInterface(); +} + +void Camera3InputStream::dump(int fd, const Vector<String16> &args) const { + (void) fd; + (void) args; + ALOGE("%s: Not implemented", __FUNCTION__); +} + +}; // namespace camera3 + +}; // namespace android diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.h b/services/camera/libcameraservice/camera3/Camera3InputStream.h new file mode 100644 index 0000000..c4b5dd9 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3InputStream.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H +#define ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H + +#include <utils/RefBase.h> +#include <gui/Surface.h> +#include <gui/BufferItemConsumer.h> + +#include "Camera3Stream.h" + +namespace android { + +namespace camera3 { + +/** + * A class for managing a single stream of input data to the camera device. + */ +class Camera3InputStream : public Camera3Stream { + public: + /** + * Set up a stream for formats that have fixed size, such as RAW and YUV. + */ + Camera3InputStream(int id, uint32_t width, uint32_t height, int format); + + virtual status_t waitUntilIdle(nsecs_t timeout); + virtual void dump(int fd, const Vector<String16> &args) const; + + /** + * Get the producer interface for this stream, to hand off to a producer. + * The producer must be connected to the provided interface before + * finishConfigure is called on this stream. + */ + sp<IGraphicBufferProducer> getProducerInterface() const; + + private: + + sp<BufferItemConsumer> mConsumer; + + /** + * Camera3Stream interface + */ + + virtual status_t getBufferLocked(camera3_stream_buffer *buffer); + virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer, + nsecs_t timestamp); + virtual bool hasOutstandingBuffersLocked() const; + virtual status_t disconnectLocked(); + +}; // class Camera3InputStream + +}; // namespace camera3 + +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp b/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp new file mode 100644 index 0000000..d07ae94 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera3-OutputStream" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +// This is needed for stdint.h to define INT64_MAX in C++ +#define __STDC_LIMIT_MACROS + +#include <utils/Log.h> +#include <utils/Trace.h> +#include "Camera3OutputStream.h" + +#ifndef container_of +#define container_of(ptr, type, member) \ + (type *)((char*)(ptr) - offsetof(type, member)) +#endif + +namespace android { + +namespace camera3 { + +Camera3OutputStream::Camera3OutputStream(int id, + sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, int format) : + Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, 0, format), + mConsumer(consumer), + mTransform(0), + mTotalBufferCount(0), + mDequeuedBufferCount(0), + mFrameCount(0), + mLastTimestamp(0) { + + mCombinedFence = new Fence(); + if (mConsumer == NULL) { + ALOGE("%s: Consumer is NULL!", __FUNCTION__); + mState = STATE_ERROR; + } +} + +Camera3OutputStream::Camera3OutputStream(int id, + sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, size_t maxSize, int format) : + Camera3Stream(id, CAMERA3_STREAM_OUTPUT, + width, height, maxSize, format), + mConsumer(consumer) { + + if (format != HAL_PIXEL_FORMAT_BLOB) { + ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__, + format); + mState = STATE_ERROR; + } + + if (mConsumer == NULL) { + ALOGE("%s: Consumer is NULL!", __FUNCTION__); + mState = STATE_ERROR; + } +} + +Camera3OutputStream::~Camera3OutputStream() { + disconnectLocked(); +} + +status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) { + ATRACE_CALL(); + status_t res; + + // Allow dequeue during IN_[RE]CONFIG for registration + if (mState != STATE_CONFIGURED && + mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) { + ALOGE("%s: Stream %d: Can't get buffers in unconfigured state %d", + __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + + // Only limit dequeue amount when fully configured + if (mState == STATE_CONFIGURED && + mDequeuedBufferCount == camera3_stream::max_buffers) { + ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous" + " buffers (%d)", __FUNCTION__, mId, + camera3_stream::max_buffers); + return INVALID_OPERATION; + } + + ANativeWindowBuffer* anb; + int fenceFd; + + res = mConsumer->dequeueBuffer(mConsumer.get(), &anb, &fenceFd); + if (res != OK) { + ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + return res; + } + + // Handing out a raw pointer to this object. Increment internal refcount. + incStrong(this); + buffer->stream = this; + buffer->buffer = &(anb->handle); + buffer->acquire_fence = fenceFd; + buffer->release_fence = -1; + buffer->status = CAMERA3_BUFFER_STATUS_OK; + + mDequeuedBufferCount++; + + return OK; +} + +status_t Camera3OutputStream::returnBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp) { + ATRACE_CALL(); + status_t res; + + // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be + // decrementing the internal refcount next. In case this is the last ref, we + // might get destructed on the decStrong(), so keep an sp around until the + // end of the call - otherwise have to sprinkle the decStrong on all exit + // points. + sp<Camera3OutputStream> keepAlive(this); + decStrong(this); + + // Allow buffers to be returned in the error state, to allow for disconnect + // and in the in-config states for registration + if (mState == STATE_CONSTRUCTED) { + ALOGE("%s: Stream %d: Can't return buffers in unconfigured state %d", + __FUNCTION__, mId, mState); + return INVALID_OPERATION; + } + if (mDequeuedBufferCount == 0) { + ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__, + mId); + return INVALID_OPERATION; + } + if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) { + res = mConsumer->cancelBuffer(mConsumer.get(), + container_of(buffer.buffer, ANativeWindowBuffer, handle), + buffer.release_fence); + if (res != OK) { + ALOGE("%s: Stream %d: Error cancelling buffer to native window:" + " %s (%d)", __FUNCTION__, mId, strerror(-res), res); + return res; + } + } else { + res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp); + if (res != OK) { + ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + return res; + } + + sp<Fence> releaseFence = new Fence(buffer.release_fence); + int anwReleaseFence = releaseFence->dup(); + + res = mConsumer->queueBuffer(mConsumer.get(), + container_of(buffer.buffer, ANativeWindowBuffer, handle), + anwReleaseFence); + if (res != OK) { + ALOGE("%s: Stream %d: Error queueing buffer to native window: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + close(anwReleaseFence); + return res; + } + + mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); + } + + mDequeuedBufferCount--; + mBufferReturnedSignal.signal(); + mLastTimestamp = timestamp; + + return OK; +} + +bool Camera3OutputStream::hasOutstandingBuffersLocked() const { + nsecs_t signalTime = mCombinedFence->getSignalTime(); + ALOGV("%s: Stream %d: Has %d outstanding buffers," + " buffer signal time is %lld", + __FUNCTION__, mId, mDequeuedBufferCount, signalTime); + if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) { + return true; + } + return false; +} + +status_t Camera3OutputStream::waitUntilIdle(nsecs_t timeout) { + status_t res; + { + Mutex::Autolock l(mLock); + while (mDequeuedBufferCount > 0) { + if (timeout != TIMEOUT_NEVER) { + nsecs_t startTime = systemTime(); + res = mBufferReturnedSignal.waitRelative(mLock, timeout); + if (res == TIMED_OUT) { + return res; + } else if (res != OK) { + ALOGE("%s: Error waiting for outstanding buffers: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + nsecs_t deltaTime = systemTime() - startTime; + if (timeout <= deltaTime) { + timeout = 0; + } else { + timeout -= deltaTime; + } + } else { + res = mBufferReturnedSignal.wait(mLock); + if (res != OK) { + ALOGE("%s: Error waiting for outstanding buffers: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + } + } + } + + // No lock + + unsigned int timeoutMs; + if (timeout == TIMEOUT_NEVER) { + timeoutMs = Fence::TIMEOUT_NEVER; + } else if (timeout == 0) { + timeoutMs = 0; + } else { + // Round up to wait at least 1 ms + timeoutMs = (timeout + 999999) / 1000000; + } + + return mCombinedFence->wait(timeoutMs); +} + +void Camera3OutputStream::dump(int fd, const Vector<String16> &args) const { + (void) args; + String8 lines; + lines.appendFormat(" Stream[%d]: Output\n", mId); + lines.appendFormat(" State: %d\n", mState); + lines.appendFormat(" Dims: %d x %d, format 0x%x\n", + camera3_stream::width, camera3_stream::height, + camera3_stream::format); + lines.appendFormat(" Max size: %d\n", mMaxSize); + lines.appendFormat(" Usage: %d, max HAL buffers: %d\n", + camera3_stream::usage, camera3_stream::max_buffers); + lines.appendFormat(" Frames produced: %d, last timestamp: %lld ns\n", + mFrameCount, mLastTimestamp); + lines.appendFormat(" Total buffers: %d, currently dequeued: %d\n", + mTotalBufferCount, mDequeuedBufferCount); + write(fd, lines.string(), lines.size()); +} + +status_t Camera3OutputStream::setTransform(int transform) { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + return setTransformLocked(transform); +} + +status_t Camera3OutputStream::setTransformLocked(int transform) { + status_t res = OK; + if (mState == STATE_ERROR) { + ALOGE("%s: Stream in error state", __FUNCTION__); + return INVALID_OPERATION; + } + + mTransform = transform; + if (mState == STATE_CONFIGURED) { + res = native_window_set_buffers_transform(mConsumer.get(), + transform); + if (res != OK) { + ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", + __FUNCTION__, transform, strerror(-res), res); + } + } + return res; +} + +status_t Camera3OutputStream::configureQueueLocked() { + status_t res; + + switch (mState) { + case STATE_IN_RECONFIG: + res = disconnect(); + if (res != OK) { + return res; + } + break; + case STATE_IN_CONFIG: + // OK + break; + default: + ALOGE("%s: Bad state: %d", __FUNCTION__, mState); + return INVALID_OPERATION; + } + + // Configure consumer-side ANativeWindow interface + res = native_window_api_connect(mConsumer.get(), + NATIVE_WINDOW_API_CAMERA); + if (res != OK) { + ALOGE("%s: Unable to connect to native window for stream %d", + __FUNCTION__, mId); + return res; + } + + res = native_window_set_usage(mConsumer.get(), camera3_stream::usage); + if (res != OK) { + ALOGE("%s: Unable to configure usage %08x for stream %d", + __FUNCTION__, camera3_stream::usage, mId); + return res; + } + + res = native_window_set_scaling_mode(mConsumer.get(), + NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (res != OK) { + ALOGE("%s: Unable to configure stream scaling: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + + res = setTransformLocked(0); + if (res != OK) { + return res; + } + + if (mMaxSize == 0) { + // For buffers of known size + res = native_window_set_buffers_geometry(mConsumer.get(), + camera3_stream::width, camera3_stream::height, + camera3_stream::format); + } else { + // For buffers with bounded size + res = native_window_set_buffers_geometry(mConsumer.get(), + mMaxSize, 1, + camera3_stream::format); + } + if (res != OK) { + ALOGE("%s: Unable to configure stream buffer geometry" + " %d x %d, format %x for stream %d", + __FUNCTION__, camera3_stream::width, camera3_stream::height, + camera3_stream::format, mId); + return res; + } + + int maxConsumerBuffers; + res = mConsumer->query(mConsumer.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; + } + + ALOGV("%s: Consumer wants %d buffers", __FUNCTION__, + maxConsumerBuffers); + + mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers; + mDequeuedBufferCount = 0; + mFrameCount = 0; + mLastTimestamp = 0; + + res = native_window_set_buffer_count(mConsumer.get(), + mTotalBufferCount); + if (res != OK) { + ALOGE("%s: Unable to set buffer count for stream %d", + __FUNCTION__, mId); + return res; + } + + res = native_window_set_buffers_transform(mConsumer.get(), + mTransform); + if (res != OK) { + ALOGE("%s: Unable to configure stream transform to %x: %s (%d)", + __FUNCTION__, mTransform, strerror(-res), res); + } + + return OK; +} + +size_t Camera3OutputStream::getBufferCountLocked() { + return mTotalBufferCount; +} + +status_t Camera3OutputStream::disconnectLocked() { + status_t res; + + switch (mState) { + case STATE_IN_RECONFIG: + case STATE_CONFIGURED: + // OK + break; + default: + // No connection, nothing to do + return OK; + } + + if (mDequeuedBufferCount > 0) { + ALOGE("%s: Can't disconnect with %d buffers still dequeued!", + __FUNCTION__, mDequeuedBufferCount); + return INVALID_OPERATION; + } + + res = native_window_api_disconnect(mConsumer.get(), NATIVE_WINDOW_API_CAMERA); + + /** + * This is not an error. if client calling process dies, the window will + * also die and all calls to it will return DEAD_OBJECT, thus it's already + * "disconnected" + */ + if (res == DEAD_OBJECT) { + ALOGW("%s: While disconnecting stream %d from native window, the" + " native window died from under us", __FUNCTION__, mId); + } + else if (res != OK) { + ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)", + __FUNCTION__, mId, res, strerror(-res)); + mState = STATE_ERROR; + return res; + } + + mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG : STATE_CONSTRUCTED; + return OK; +} + +}; // namespace camera3 + +}; // namespace android diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.h b/services/camera/libcameraservice/camera3/Camera3OutputStream.h new file mode 100644 index 0000000..d331a94 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3OutputStream.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H +#define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_H + +#include <utils/RefBase.h> +#include <gui/Surface.h> + +#include "Camera3Stream.h" + +namespace android { + +namespace camera3 { + +/** + * A class for managing a single stream of output data from the camera device. + */ +class Camera3OutputStream : public Camera3Stream { + public: + /** + * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. + */ + Camera3OutputStream(int id, sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, int format); + + /** + * Set up a stream for formats that have a variable buffer size for the same + * dimensions, such as compressed JPEG. + */ + Camera3OutputStream(int id, sp<ANativeWindow> consumer, + uint32_t width, uint32_t height, size_t maxSize, int format); + + virtual ~Camera3OutputStream(); + + /** + * Camera3Stream interface + */ + + virtual status_t waitUntilIdle(nsecs_t timeout); + virtual void dump(int fd, const Vector<String16> &args) const; + + /** + * Set the transform on the output stream; one of the + * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. + */ + status_t setTransform(int transform); + + private: + sp<ANativeWindow> mConsumer; + int mTransform; + size_t mTotalBufferCount; + size_t mDequeuedBufferCount; + Condition mBufferReturnedSignal; + uint32_t mFrameCount; + nsecs_t mLastTimestamp; + + // The merged release fence for all returned buffers + sp<Fence> mCombinedFence; + + status_t setTransformLocked(int transform); + + /** + * Internal Camera3Stream interface + */ + virtual status_t getBufferLocked(camera3_stream_buffer *buffer); + virtual status_t returnBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp); + virtual bool hasOutstandingBuffersLocked() const; + + virtual status_t configureQueueLocked(); + virtual size_t getBufferCountLocked(); + virtual status_t disconnectLocked(); + +}; // class Camera3OutputStream + +} // namespace camera3 + +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3Stream.cpp b/services/camera/libcameraservice/camera3/Camera3Stream.cpp new file mode 100644 index 0000000..cf3072b --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3Stream.cpp @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera3-Stream" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Trace.h> +#include "Camera3Stream.h" + +namespace android { + +namespace camera3 { + +Camera3Stream::~Camera3Stream() { +} + +Camera3Stream* Camera3Stream::cast(camera3_stream *stream) { + return static_cast<Camera3Stream*>(stream); +} + +const Camera3Stream* Camera3Stream::cast(const camera3_stream *stream) { + return static_cast<const Camera3Stream*>(stream); +} + +Camera3Stream::Camera3Stream(int id, + camera3_stream_type type, + uint32_t width, uint32_t height, size_t maxSize, int format) : + camera3_stream(), + mId(id), + mName(String8::format("Camera3Stream[%d]", id)), + mMaxSize(maxSize), + mState(STATE_CONSTRUCTED) { + + camera3_stream::stream_type = type; + camera3_stream::width = width; + camera3_stream::height = height; + camera3_stream::format = format; + camera3_stream::usage = 0; + camera3_stream::max_buffers = 0; + camera3_stream::priv = NULL; + + if (format == HAL_PIXEL_FORMAT_BLOB && maxSize == 0) { + ALOGE("%s: BLOB format with size == 0", __FUNCTION__); + mState = STATE_ERROR; + } +} + +int Camera3Stream::getId() const { + return mId; +} + +uint32_t Camera3Stream::getWidth() const { + return camera3_stream::width; +} + +uint32_t Camera3Stream::getHeight() const { + return camera3_stream::height; +} + +int Camera3Stream::getFormat() const { + return camera3_stream::format; +} + +camera3_stream* Camera3Stream::startConfiguration() { + Mutex::Autolock l(mLock); + + switch (mState) { + case STATE_ERROR: + ALOGE("%s: In error state", __FUNCTION__); + return NULL; + case STATE_CONSTRUCTED: + // OK + break; + case STATE_IN_CONFIG: + case STATE_IN_RECONFIG: + // Can start config again with no trouble; but don't redo + // oldUsage/oldMaxBuffers + return this; + case STATE_CONFIGURED: + if (stream_type == CAMERA3_STREAM_INPUT) { + ALOGE("%s: Cannot configure an input stream twice", + __FUNCTION__); + return NULL; + } else if (hasOutstandingBuffersLocked()) { + ALOGE("%s: Cannot configure stream; has outstanding buffers", + __FUNCTION__); + return NULL; + } + break; + default: + ALOGE("%s: Unknown state %d", __FUNCTION__, mState); + return NULL; + } + + oldUsage = usage; + oldMaxBuffers = max_buffers; + + if (mState == STATE_CONSTRUCTED) { + mState = STATE_IN_CONFIG; + } else { // mState == STATE_CONFIGURED + mState = STATE_IN_RECONFIG; + } + + return this; +} + +bool Camera3Stream::isConfiguring() const { + Mutex::Autolock l(mLock); + return (mState == STATE_IN_CONFIG) || (mState == STATE_IN_RECONFIG); +} + +status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) { + Mutex::Autolock l(mLock); + switch (mState) { + case STATE_ERROR: + ALOGE("%s: In error state", __FUNCTION__); + return INVALID_OPERATION; + case STATE_IN_CONFIG: + case STATE_IN_RECONFIG: + // OK + break; + case STATE_CONSTRUCTED: + case STATE_CONFIGURED: + ALOGE("%s: Cannot finish configuration that hasn't been started", + __FUNCTION__); + return INVALID_OPERATION; + default: + ALOGE("%s: Unknown state", __FUNCTION__); + return INVALID_OPERATION; + } + + // Check if the stream configuration is unchanged, and skip reallocation if + // so. As documented in hardware/camera3.h:configure_streams(). + if (mState == STATE_IN_RECONFIG && + oldUsage == usage && + oldMaxBuffers == max_buffers) { + mState = STATE_CONFIGURED; + return OK; + } + + status_t res; + res = configureQueueLocked(); + if (res != OK) { + ALOGE("%s: Unable to configure stream %d queue: %s (%d)", + __FUNCTION__, mId, strerror(-res), res); + mState = STATE_ERROR; + return res; + } + + res = registerBuffersLocked(hal3Device); + if (res != OK) { + ALOGE("%s: Unable to register stream buffers with HAL: %s (%d)", + __FUNCTION__, strerror(-res), res); + mState = STATE_ERROR; + return res; + } + + mState = STATE_CONFIGURED; + + return res; +} + +status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + return getBufferLocked(buffer); +} + +status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, + nsecs_t timestamp) { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + return returnBufferLocked(buffer, timestamp); +} + +bool Camera3Stream::hasOutstandingBuffers() const { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + return hasOutstandingBuffersLocked(); +} + +status_t Camera3Stream::disconnect() { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + return disconnectLocked(); +} + +status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) { + ATRACE_CALL(); + status_t res; + + size_t bufferCount = getBufferCountLocked(); + + Vector<buffer_handle_t*> buffers; + buffers.insertAt(NULL, 0, bufferCount); + + camera3_stream_buffer_set bufferSet = camera3_stream_buffer_set(); + bufferSet.stream = this; + bufferSet.num_buffers = bufferCount; + bufferSet.buffers = buffers.editArray(); + + Vector<camera3_stream_buffer_t> streamBuffers; + streamBuffers.insertAt(camera3_stream_buffer_t(), 0, bufferCount); + + // Register all buffers with the HAL. This means getting all the buffers + // from the stream, providing them to the HAL with the + // register_stream_buffers() method, and then returning them back to the + // stream in the error state, since they won't have valid data. + // + // Only registered buffers can be sent to the HAL. + + uint32_t bufferIdx = 0; + for (; bufferIdx < bufferCount; bufferIdx++) { + res = getBufferLocked( &streamBuffers.editItemAt(bufferIdx) ); + if (res != OK) { + ALOGE("%s: Unable to get buffer %d for registration with HAL", + __FUNCTION__, bufferIdx); + // Skip registering, go straight to cleanup + break; + } + + sp<Fence> fence = new Fence(streamBuffers[bufferIdx].acquire_fence); + fence->waitForever(kRegisterFenceTimeoutMs, + "Camera3Stream::registerBuffers"); + + buffers.editItemAt(bufferIdx) = streamBuffers[bufferIdx].buffer; + } + if (bufferIdx == bufferCount) { + // Got all buffers, register with HAL + ALOGV("%s: Registering %d buffers with camera HAL", + __FUNCTION__, bufferCount); + res = hal3Device->ops->register_stream_buffers(hal3Device, + &bufferSet); + } + + // Return all valid buffers to stream, in ERROR state to indicate + // they weren't filled. + for (size_t i = 0; i < bufferIdx; i++) { + streamBuffers.editItemAt(i).release_fence = -1; + streamBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR; + returnBufferLocked(streamBuffers[i], 0); + } + + return res; +} + +}; // namespace camera3 + +}; // namespace android diff --git a/services/camera/libcameraservice/camera3/Camera3Stream.h b/services/camera/libcameraservice/camera3/Camera3Stream.h new file mode 100644 index 0000000..2364cfd --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3Stream.h @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA3_STREAM_H +#define ANDROID_SERVERS_CAMERA3_STREAM_H + +#include <gui/Surface.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/String16.h> + +#include "hardware/camera3.h" + +namespace android { + +namespace camera3 { + +/** + * A class for managing a single stream of input or output data from the camera + * device. + * + * The stream has an internal state machine to track whether it's + * connected/configured/etc. + * + * States: + * + * STATE_ERROR: A serious error has occurred, stream is unusable. Outstanding + * buffers may still be returned. + * + * STATE_CONSTRUCTED: The stream is ready for configuration, but buffers cannot + * be gotten yet. Not connected to any endpoint, no buffers are registered + * with the HAL. + * + * STATE_IN_CONFIG: Configuration has started, but not yet concluded. During this + * time, the usage, max_buffers, and priv fields of camera3_stream returned by + * startConfiguration() may be modified. + * + * STATE_IN_RE_CONFIG: Configuration has started, and the stream has been + * configured before. Need to track separately from IN_CONFIG to avoid + * re-registering buffers with HAL. + * + * STATE_CONFIGURED: Stream is configured, and has registered buffers with the + * HAL. The stream's getBuffer/returnBuffer work. The priv pointer may still be + * modified. + * + * Transition table: + * + * <none> => STATE_CONSTRUCTED: + * When constructed with valid arguments + * <none> => STATE_ERROR: + * When constructed with invalid arguments + * STATE_CONSTRUCTED => STATE_IN_CONFIG: + * When startConfiguration() is called + * STATE_IN_CONFIG => STATE_CONFIGURED: + * When finishConfiguration() is called + * STATE_IN_CONFIG => STATE_ERROR: + * When finishConfiguration() fails to allocate or register buffers. + * STATE_CONFIGURED => STATE_IN_RE_CONFIG: * + * When startConfiguration() is called again, after making sure stream is + * idle with waitUntilIdle(). + * STATE_IN_RE_CONFIG => STATE_CONFIGURED: + * When finishConfiguration() is called. + * STATE_IN_RE_CONFIG => STATE_ERROR: + * When finishConfiguration() fails to allocate or register buffers. + * STATE_CONFIGURED => STATE_CONSTRUCTED: + * When disconnect() is called after making sure stream is idle with + * waitUntilIdle(). + */ +class Camera3Stream : + protected camera3_stream, + public LightRefBase<Camera3Stream> { + public: + + virtual ~Camera3Stream(); + + static Camera3Stream* cast(camera3_stream *stream); + static const Camera3Stream* cast(const camera3_stream *stream); + + /** + * Get the stream's ID + */ + int getId() const; + + /** + * Get the stream's dimensions and format + */ + uint32_t getWidth() const; + uint32_t getHeight() const; + int getFormat() const; + + /** + * Start the stream configuration process. Returns a handle to the stream's + * information to be passed into the HAL device's configure_streams call. + * + * Until finishConfiguration() is called, no other methods on the stream may be + * called. The usage and max_buffers fields of camera3_stream may be modified + * between start/finishConfiguration, but may not be changed after that. + * The priv field of camera3_stream may be modified at any time after + * startConfiguration. + * + * Returns NULL in case of error starting configuration. + */ + camera3_stream* startConfiguration(); + + /** + * Check if the stream is mid-configuration (start has been called, but not + * finish). Used for lazy completion of configuration. + */ + bool isConfiguring() const; + + /** + * Completes the stream configuration process. During this call, the stream + * may call the device's register_stream_buffers() method. The stream + * information structure returned by startConfiguration() may no longer be + * modified after this call, but can still be read until the destruction of + * the stream. + * + * Returns: + * OK on a successful configuration + * NO_INIT in case of a serious error from the HAL device + * NO_MEMORY in case of an error registering buffers + * INVALID_OPERATION in case connecting to the consumer failed + */ + status_t finishConfiguration(camera3_device *hal3Device); + + /** + * Fill in the camera3_stream_buffer with the next valid buffer for this + * stream, to hand over to the HAL. + * + * This method may only be called once finishConfiguration has been called. + * For bidirectional streams, this method applies to the output-side + * buffers. + * + */ + status_t getBuffer(camera3_stream_buffer *buffer); + + /** + * Return a buffer to the stream after use by the HAL. + * + * This method may only be called for buffers provided by getBuffer(). + * For bidirectional streams, this method applies to the output-side buffers + */ + status_t returnBuffer(const camera3_stream_buffer &buffer, + nsecs_t timestamp); + + /** + * Whether any of the stream's buffers are currently in use by the HAL, + * including buffers that have been returned but not yet had their + * release fence signaled. + */ + bool hasOutstandingBuffers() const; + + enum { + TIMEOUT_NEVER = -1 + }; + /** + * Wait until the HAL is done with all of this stream's buffers, including + * signalling all release fences. Returns TIMED_OUT if the timeout is exceeded, + * OK on success. Pass in TIMEOUT_NEVER for timeout to indicate an indefinite wait. + */ + virtual status_t waitUntilIdle(nsecs_t timeout) = 0; + + /** + * Disconnect stream from its non-HAL endpoint. After this, + * start/finishConfiguration must be called before the stream can be used + * again. This cannot be called if the stream has outstanding dequeued + * buffers. + */ + status_t disconnect(); + + /** + * Debug dump of the stream's state. + */ + virtual void dump(int fd, const Vector<String16> &args) const = 0; + + protected: + const int mId; + const String8 mName; + // Zero for formats with fixed buffer size for given dimensions. + const size_t mMaxSize; + + enum { + STATE_ERROR, + STATE_CONSTRUCTED, + STATE_IN_CONFIG, + STATE_IN_RECONFIG, + STATE_CONFIGURED + } mState; + + mutable Mutex mLock; + + Camera3Stream(int id, camera3_stream_type type, + uint32_t width, uint32_t height, size_t maxSize, int format); + + /** + * Interface to be implemented by derived classes + */ + + // getBuffer / returnBuffer implementations + + // Since camera3_stream_buffer includes a raw pointer to the stream, + // cast to camera3_stream*, implementations must increment the + // refcount of the stream manually in getBufferLocked, and decrement it in + // returnBufferLocked. + virtual status_t getBufferLocked(camera3_stream_buffer *buffer) = 0; + virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer, + nsecs_t timestamp) = 0; + virtual bool hasOutstandingBuffersLocked() const = 0; + virtual status_t disconnectLocked() = 0; + + // Configure the buffer queue interface to the other end of the stream, + // after the HAL has provided usage and max_buffers values. After this call, + // the stream must be ready to produce all buffers for registration with + // HAL. + virtual status_t configureQueueLocked() = 0; + + // Get the total number of buffers in the queue + virtual size_t getBufferCountLocked() = 0; + + private: + static const unsigned int kRegisterFenceTimeoutMs = 5000; + + uint32_t oldUsage; + uint32_t oldMaxBuffers; + + // Gets all buffers from endpoint and registers them with the HAL. + status_t registerBuffersLocked(camera3_device *hal3Device); + +}; // class Camera3Stream + +}; // namespace camera3 + +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp b/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp new file mode 100644 index 0000000..e8a5ca6 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera3-ZslStream" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Trace.h> +#include "Camera3ZslStream.h" + +namespace android { + +namespace camera3 { + +Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height, + int depth) : + Camera3Stream(id, CAMERA3_STREAM_BIDIRECTIONAL, width, height, 0, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), + mDepth(depth) { +} + +status_t Camera3ZslStream::getBufferLocked(camera3_stream_buffer *buffer) { + (void) buffer; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t Camera3ZslStream::returnBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp) { + (void) buffer; + (void) timestamp; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +bool Camera3ZslStream::hasOutstandingBuffersLocked() const { + ALOGE("%s: Not implemented", __FUNCTION__); + return false; +} + +status_t Camera3ZslStream::waitUntilIdle(nsecs_t timeout) { + (void) timeout; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t Camera3ZslStream::disconnectLocked() { + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t Camera3ZslStream::getInputBuffer(camera3_stream_buffer *buffer, + nsecs_t timestamp) { + (void) buffer; + (void) timestamp; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +status_t Camera3ZslStream::returnInputBuffer(const camera3_stream_buffer &buffer) { + (void) buffer; + ALOGE("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; +} + +void Camera3ZslStream::dump(int fd, const Vector<String16> &args) const { + (void) fd; + (void) args; + ALOGE("%s: Not implemented", __FUNCTION__); +} + +}; // namespace camera3 + +}; // namespace android diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.h b/services/camera/libcameraservice/camera3/Camera3ZslStream.h new file mode 100644 index 0000000..39d5995 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3ZslStream.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA3_ZSL_STREAM_H +#define ANDROID_SERVERS_CAMERA3_ZSL_STREAM_H + +#include <utils/RefBase.h> +#include <gui/Surface.h> + +#include "Camera3Stream.h" + +namespace android { + +namespace camera3 { + +/** + * A class for managing a single opaque ZSL stream to/from the camera device. + * This acts as a bidirectional stream at the HAL layer, caching and discarding + * most output buffers, and when directed, pushes a buffer back to the HAL for + * processing. + */ +class Camera3ZslStream: public Camera3Stream { + public: + /** + * Set up a ZSL stream of a given resolution. Depth is the number of buffers + * cached within the stream that can be retrieved for input. + */ + Camera3ZslStream(int id, uint32_t width, uint32_t height, int depth); + + virtual status_t waitUntilIdle(nsecs_t timeout); + virtual void dump(int fd, const Vector<String16> &args) const; + + /** + * Get an input buffer matching a specific timestamp. If no buffer matching + * the timestamp is available, NO_MEMORY is returned. + */ + status_t getInputBuffer(camera3_stream_buffer *buffer, nsecs_t timestamp); + + /** + * Return input buffer from HAL. The buffer is then marked as unfilled, and + * returned to the output-side stream for refilling. + */ + status_t returnInputBuffer(const camera3_stream_buffer &buffer); + + private: + + int mDepth; + + /** + * Camera3Stream interface + */ + + // getBuffer/returnBuffer operate the output stream side of the ZslStream. + virtual status_t getBufferLocked(camera3_stream_buffer *buffer); + virtual status_t returnBufferLocked(const camera3_stream_buffer &buffer, + nsecs_t timestamp); + virtual bool hasOutstandingBuffersLocked() const; + virtual status_t disconnectLocked(); + +}; // class Camera3ZslStream + +}; // namespace camera3 + +}; // namespace android + +#endif |