From e3a9f964d7ebb6f269e6df2ba9c24b7c8b9ccefd Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 8 May 2013 18:03:15 -0700 Subject: Camera3: Refactor stream code to be DRY Bug: 8851039 Change-Id: Iaac2926bfa25dd6e9db8b307765d4fe709b88d21 --- services/camera/libcameraservice/Android.mk | 1 + .../camera3/Camera3IOStreamBase.cpp | 273 +++++++++++++ .../libcameraservice/camera3/Camera3IOStreamBase.h | 102 +++++ .../camera3/Camera3InputStream.cpp | 193 ++------- .../libcameraservice/camera3/Camera3InputStream.h | 23 +- .../camera3/Camera3OutputStream.cpp | 242 +++-------- .../libcameraservice/camera3/Camera3OutputStream.h | 30 +- .../libcameraservice/camera3/Camera3ZslStream.cpp | 452 ++------------------- .../libcameraservice/camera3/Camera3ZslStream.h | 37 +- 9 files changed, 554 insertions(+), 799 deletions(-) create mode 100644 services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp create mode 100644 services/camera/libcameraservice/camera3/Camera3IOStreamBase.h diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index 3479553..83d9ccd 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -27,6 +27,7 @@ LOCAL_SRC_FILES:= \ camera2/ProFrameProcessor.cpp \ camera2/ZslProcessor3.cpp \ camera3/Camera3Stream.cpp \ + camera3/Camera3IOStreamBase.cpp \ camera3/Camera3InputStream.cpp \ camera3/Camera3OutputStream.cpp \ camera3/Camera3ZslStream.cpp \ diff --git a/services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp new file mode 100644 index 0000000..abc28fe --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp @@ -0,0 +1,273 @@ +/* + * 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-IOStreamBase" +#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 +#include +#include "Camera3IOStreamBase.h" + +namespace android { + +namespace camera3 { + +Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type, + uint32_t width, uint32_t height, size_t maxSize, int format) : + Camera3Stream(id, type, + width, height, maxSize, format), + mTotalBufferCount(0), + mDequeuedBufferCount(0), + mFrameCount(0), + mLastTimestamp(0) { + + mCombinedFence = new Fence(); + + if (maxSize > 0 && format != HAL_PIXEL_FORMAT_BLOB) { + ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__, + format); + mState = STATE_ERROR; + } +} + +Camera3IOStreamBase::~Camera3IOStreamBase() { + disconnectLocked(); +} + +bool Camera3IOStreamBase::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 Camera3IOStreamBase::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 Camera3IOStreamBase::dump(int fd, const Vector &args) const { + (void) args; + String8 lines; + 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 Camera3IOStreamBase::configureQueueLocked() { + status_t res; + + switch (mState) { + case STATE_IN_RECONFIG: + res = disconnectLocked(); + if (res != OK) { + return res; + } + break; + case STATE_IN_CONFIG: + // OK + break; + default: + ALOGE("%s: Bad state: %d", __FUNCTION__, mState); + return INVALID_OPERATION; + } + + return OK; +} + +size_t Camera3IOStreamBase::getBufferCountLocked() { + return mTotalBufferCount; +} + +status_t Camera3IOStreamBase::disconnectLocked() { + 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; + } + + return OK; +} + +void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer, + buffer_handle_t *handle, + int acquireFence, + int releaseFence, + camera3_buffer_status_t status) { + /** + * Note that all fences are now owned by HAL. + */ + + // Handing out a raw pointer to this object. Increment internal refcount. + incStrong(this); + buffer.stream = this; + buffer.buffer = handle; + buffer.acquire_fence = acquireFence; + buffer.release_fence = releaseFence; + buffer.status = status; + + mDequeuedBufferCount++; +} + +status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const { + // 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; + } + + return OK; +} + +status_t Camera3IOStreamBase::returnBufferPreconditionCheckLocked() const { + // 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; + } + + return OK; +} + +status_t Camera3IOStreamBase::returnAnyBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output) { + 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 keepAlive(this); + decStrong(this); + + if ((res = returnBufferPreconditionCheckLocked()) != OK) { + return res; + } + + sp releaseFence; + res = returnBufferCheckedLocked(buffer, timestamp, output, + &releaseFence); + if (res != OK) { + return res; + } + + mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); + + mDequeuedBufferCount--; + mBufferReturnedSignal.signal(); + + if (output) { + mLastTimestamp = timestamp; + } + + return OK; +} + + + +}; // namespace camera3 + +}; // namespace android diff --git a/services/camera/libcameraservice/camera3/Camera3IOStreamBase.h b/services/camera/libcameraservice/camera3/Camera3IOStreamBase.h new file mode 100644 index 0000000..74c4484 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3IOStreamBase.h @@ -0,0 +1,102 @@ +/* + * 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_IO_STREAM_BASE_H +#define ANDROID_SERVERS_CAMERA3_IO_STREAM_BASE_H + +#include +#include + +#include "Camera3Stream.h" + +namespace android { + +namespace camera3 { + +/** + * A base class for managing a single stream of I/O data from the camera device. + */ +class Camera3IOStreamBase : + public Camera3Stream { + protected: + Camera3IOStreamBase(int id, camera3_stream_type_t type, + uint32_t width, uint32_t height, size_t maxSize, int format); + + public: + + virtual ~Camera3IOStreamBase(); + + /** + * Camera3Stream interface + */ + + virtual status_t waitUntilIdle(nsecs_t timeout); + virtual void dump(int fd, const Vector &args) const; + + protected: + size_t mTotalBufferCount; + // sum of input and output buffers that are currently acquired by HAL + size_t mDequeuedBufferCount; + Condition mBufferReturnedSignal; + uint32_t mFrameCount; + // Last received output buffer's timestamp + nsecs_t mLastTimestamp; + + // The merged release fence for all returned buffers + sp mCombinedFence; + + status_t returnAnyBufferLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output); + + virtual status_t returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut) = 0; + + /** + * Internal Camera3Stream interface + */ + virtual bool hasOutstandingBuffersLocked() const; + + virtual size_t getBufferCountLocked(); + + status_t getBufferPreconditionCheckLocked() const; + status_t returnBufferPreconditionCheckLocked() const; + + // State check only + virtual status_t configureQueueLocked(); + // State checks only + virtual status_t disconnectLocked(); + + // Hand out the buffer to a native location, + // incrementing the internal refcount and dequeued buffer count + void handoutBufferLocked(camera3_stream_buffer &buffer, + buffer_handle_t *handle, + int acquire_fence, + int release_fence, + camera3_buffer_status_t status); + +}; // class Camera3IOStreamBase + +} // namespace camera3 + +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp index c7dd12a..13e9c83 100644 --- a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/camera3/Camera3InputStream.cpp @@ -18,9 +18,6 @@ #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 #include #include "Camera3InputStream.h" @@ -31,12 +28,8 @@ namespace camera3 { Camera3InputStream::Camera3InputStream(int id, uint32_t width, uint32_t height, int format) : - Camera3Stream(id, CAMERA3_STREAM_INPUT, width, height, 0, format), - mTotalBufferCount(0), - mDequeuedBufferCount(0), - mFrameCount(0), - mLastTimestamp(0) { - mCombinedFence = new Fence(); + Camera3IOStreamBase(id, CAMERA3_STREAM_INPUT, width, height, + /*maxSize*/0, format) { if (format == HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__); @@ -61,21 +54,8 @@ status_t Camera3InputStream::getInputBufferLocked( return INVALID_OPERATION; } - // Allow acquire 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 acquire amount when fully configured - if (mState == STATE_CONFIGURED && - mDequeuedBufferCount == camera3_stream::max_buffers) { - ALOGE("%s: Stream %d: Already acquired maximum number of simultaneous" - " buffers (%d)", __FUNCTION__, mId, - camera3_stream::max_buffers); - return INVALID_OPERATION; + if ((res = getBufferPreconditionCheckLocked()) != OK) { + return res; } ANativeWindowBuffer* anb; @@ -95,51 +75,30 @@ status_t Camera3InputStream::getInputBufferLocked( anb = bufferItem.mGraphicBuffer->getNativeBuffer(); assert(anb != NULL); fenceFd = bufferItem.mFence->dup(); + /** * FenceFD now owned by HAL except in case of error, * in which case we reassign it to acquire_fence */ - - // 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++; - + handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); mBuffersInFlight.push_back(bufferItem); return OK; } -status_t Camera3InputStream::returnInputBufferLocked( - const camera3_stream_buffer &buffer) { - ATRACE_CALL(); - status_t res; +status_t Camera3InputStream::returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut) { - // 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 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; - } + (void)timestamp; + (void)output; + ALOG_ASSERT(!output, "Expected output to be false"); + + status_t res; bool bufferFound = false; BufferItem bufferItem; @@ -192,91 +151,24 @@ status_t Camera3InputStream::returnInputBufferLocked( return res; } - mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); - - mBufferReturnedSignal.signal(); + *releaseFenceOut = releaseFence; return OK; - -} - -bool Camera3InputStream::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 Camera3InputStream::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); -} +status_t Camera3InputStream::returnInputBufferLocked( + const camera3_stream_buffer &buffer) { + ATRACE_CALL(); -size_t Camera3InputStream::getBufferCountLocked() { - return mTotalBufferCount; + return returnAnyBufferLocked(buffer, /*timestamp*/0, /*output*/false); } status_t Camera3InputStream::disconnectLocked() { - 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 acquired!", - __FUNCTION__, mDequeuedBufferCount); - return INVALID_OPERATION; + status_t res; + + if ((res = Camera3IOStreamBase::disconnectLocked()) != OK) { + return res; } assert(mBuffersInFlight.size() == 0); @@ -285,7 +177,8 @@ status_t Camera3InputStream::disconnectLocked() { * no-op since we can't disconnect the producer from the consumer-side */ - mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG : STATE_CONSTRUCTED; + mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG + : STATE_CONSTRUCTED; return OK; } @@ -297,36 +190,16 @@ void Camera3InputStream::dump(int fd, const Vector &args) const { (void) args; String8 lines; lines.appendFormat(" Stream[%d]: Input\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 acquired: %d\n", - mTotalBufferCount, mDequeuedBufferCount); write(fd, lines.string(), lines.size()); + + Camera3IOStreamBase::dump(fd, args); } status_t Camera3InputStream::configureQueueLocked() { status_t res; - switch (mState) { - case STATE_IN_RECONFIG: - res = disconnectLocked(); - if (res != OK) { - return res; - } - break; - case STATE_IN_CONFIG: - // OK - break; - default: - ALOGE("%s: Bad state: %d", __FUNCTION__, mState); - return INVALID_OPERATION; + if ((res = Camera3IOStreamBase::configureQueueLocked()) != OK) { + return res; } assert(mMaxSize == 0); diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.h b/services/camera/libcameraservice/camera3/Camera3InputStream.h index fd9f464..8adda88 100644 --- a/services/camera/libcameraservice/camera3/Camera3InputStream.h +++ b/services/camera/libcameraservice/camera3/Camera3InputStream.h @@ -21,7 +21,7 @@ #include #include -#include "Camera3Stream.h" +#include "Camera3IOStreamBase.h" namespace android { @@ -34,7 +34,7 @@ namespace camera3 { * buffers by feeding them into the HAL, as well as releasing the buffers back * the buffers once the HAL is done with them. */ -class Camera3InputStream : public Camera3Stream { +class Camera3InputStream : public Camera3IOStreamBase { public: /** * Set up a stream for formats that have fixed size, such as RAW and YUV. @@ -42,7 +42,6 @@ class Camera3InputStream : public Camera3Stream { Camera3InputStream(int id, uint32_t width, uint32_t height, int format); ~Camera3InputStream(); - virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector &args) const; /** @@ -58,14 +57,16 @@ class Camera3InputStream : public Camera3Stream { sp mConsumer; Vector mBuffersInFlight; - size_t mTotalBufferCount; - size_t mDequeuedBufferCount; - Condition mBufferReturnedSignal; - uint32_t mFrameCount; - nsecs_t mLastTimestamp; - // The merged release fence for all returned buffers - sp mCombinedFence; + /** + * Camera3IOStreamBase + */ + virtual status_t returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut); /** * Camera3Stream interface @@ -74,11 +75,9 @@ class Camera3InputStream : public Camera3Stream { virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer); virtual status_t returnInputBufferLocked( const camera3_stream_buffer &buffer); - virtual bool hasOutstandingBuffersLocked() const; virtual status_t disconnectLocked(); virtual status_t configureQueueLocked(); - virtual size_t getBufferCountLocked(); }; // class Camera3InputStream diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp b/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp index 9693346..bbcccaf 100644 --- a/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp @@ -18,9 +18,6 @@ #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 #include #include "Camera3OutputStream.h" @@ -37,15 +34,11 @@ namespace camera3 { Camera3OutputStream::Camera3OutputStream(int id, sp consumer, uint32_t width, uint32_t height, int format) : - Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, 0, format), + Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, + /*maxSize*/0, format), mConsumer(consumer), - mTransform(0), - mTotalBufferCount(0), - mDequeuedBufferCount(0), - mFrameCount(0), - mLastTimestamp(0) { + mTransform(0) { - mCombinedFence = new Fence(); if (mConsumer == NULL) { ALOGE("%s: Consumer is NULL!", __FUNCTION__); mState = STATE_ERROR; @@ -55,16 +48,10 @@ Camera3OutputStream::Camera3OutputStream(int id, Camera3OutputStream::Camera3OutputStream(int id, sp consumer, uint32_t width, uint32_t height, size_t maxSize, int format) : - Camera3Stream(id, CAMERA3_STREAM_OUTPUT, - width, height, maxSize, format), + Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize, + format), mConsumer(consumer), - mTransform(0), - mTotalBufferCount(0), - mDequeuedBufferCount(0), - mFrameCount(0), - mLastTimestamp(0) { - - mCombinedFence = new Fence(); + mTransform(0) { if (format != HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__, @@ -78,6 +65,18 @@ Camera3OutputStream::Camera3OutputStream(int id, } } +Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type, + uint32_t width, uint32_t height, + int format) : + Camera3IOStreamBase(id, type, width, height, + /*maxSize*/0, + format), + mTransform(0) { + + // Subclasses expected to initialize mConsumer themselves +} + + Camera3OutputStream::~Camera3OutputStream() { disconnectLocked(); } @@ -86,21 +85,8 @@ 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; + if ((res = getBufferPreconditionCheckLocked()) != OK) { + return res; } ANativeWindowBuffer* anb; @@ -113,15 +99,12 @@ status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) { 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++; + /** + * FenceFD now owned by HAL except in case of error, + * in which case we reassign it to acquire_fence + */ + handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); return OK; } @@ -130,29 +113,29 @@ 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 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; + status_t res = returnAnyBufferLocked(buffer, timestamp, /*output*/true); + + if (res != OK) { + return res; } + mLastTimestamp = timestamp; + + return OK; +} + +status_t Camera3OutputStream::returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut) { + + (void)output; + ALOG_ASSERT(output, "Expected output to be true"); + + status_t res; sp releaseFence; /** @@ -173,7 +156,7 @@ status_t Camera3OutputStream::returnBufferLocked( 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); + __FUNCTION__, mId, strerror(-res), res); return res; } @@ -192,15 +175,15 @@ status_t Camera3OutputStream::returnBufferLocked( anwReleaseFence); if (res != OK) { ALOGE("%s: Stream %d: Error cancelling buffer to native window:" - " %s (%d)", __FUNCTION__, mId, strerror(-res), res); + " %s (%d)", __FUNCTION__, mId, strerror(-res), res); } } else { 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); + ALOGE("%s: Stream %d: Error queueing buffer to native window: " + "%s (%d)", __FUNCTION__, mId, strerror(-res), res); } } @@ -209,89 +192,18 @@ status_t Camera3OutputStream::returnBufferLocked( return res; } - mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); - - mDequeuedBufferCount--; - mBufferReturnedSignal.signal(); - mLastTimestamp = timestamp; + *releaseFenceOut = releaseFence; 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 &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()); + + Camera3IOStreamBase::dump(fd, args); } status_t Camera3OutputStream::setTransform(int transform) { @@ -322,21 +234,12 @@ status_t Camera3OutputStream::setTransformLocked(int transform) { status_t Camera3OutputStream::configureQueueLocked() { status_t res; - switch (mState) { - case STATE_IN_RECONFIG: - res = disconnectLocked(); - if (res != OK) { - return res; - } - break; - case STATE_IN_CONFIG: - // OK - break; - default: - ALOGE("%s: Bad state: %d", __FUNCTION__, mState); - return INVALID_OPERATION; + if ((res = Camera3IOStreamBase::configureQueueLocked()) != OK) { + return res; } + ALOG_ASSERT(mConsumer != 0, "mConsumer should never be NULL"); + // Configure consumer-side ANativeWindow interface res = native_window_api_connect(mConsumer.get(), NATIVE_WINDOW_API_CAMERA); @@ -420,30 +323,15 @@ status_t Camera3OutputStream::configureQueueLocked() { 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; + if ((res = Camera3IOStreamBase::disconnectLocked()) != OK) { + return res; } - res = native_window_api_disconnect(mConsumer.get(), NATIVE_WINDOW_API_CAMERA); + res = native_window_api_disconnect(mConsumer.get(), + NATIVE_WINDOW_API_CAMERA); /** * This is not an error. if client calling process dies, the window will @@ -455,13 +343,15 @@ status_t Camera3OutputStream::disconnectLocked() { " 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)); + 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; + mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG + : STATE_CONSTRUCTED; return OK; } diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.h b/services/camera/libcameraservice/camera3/Camera3OutputStream.h index 2464dce..ce317f9 100644 --- a/services/camera/libcameraservice/camera3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/camera3/Camera3OutputStream.h @@ -21,6 +21,7 @@ #include #include "Camera3Stream.h" +#include "Camera3IOStreamBase.h" #include "Camera3OutputStreamInterface.h" namespace android { @@ -31,7 +32,7 @@ namespace camera3 { * A class for managing a single stream of output data from the camera device. */ class Camera3OutputStream : - public Camera3Stream, + public Camera3IOStreamBase, public Camera3OutputStreamInterface { public: /** @@ -53,7 +54,6 @@ class Camera3OutputStream : * Camera3Stream interface */ - virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector &args) const; /** @@ -62,19 +62,22 @@ class Camera3OutputStream : */ status_t setTransform(int transform); - private: + protected: + Camera3OutputStream(int id, camera3_stream_type_t type, + uint32_t width, uint32_t height, int format); + + virtual status_t returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut); + sp mConsumer; + private: 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 mCombinedFence; - - status_t setTransformLocked(int transform); + virtual status_t setTransformLocked(int transform); /** * Internal Camera3Stream interface @@ -83,12 +86,9 @@ class Camera3OutputStream : 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 diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp b/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp index 5a13dde..8790c8c 100644 --- a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp +++ b/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp @@ -18,18 +18,10 @@ #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 #include #include "Camera3ZslStream.h" -#ifndef container_of -#define container_of(ptr, type, member) \ - (type *)((char*)(ptr) - offsetof(type, member)) -#endif - typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem; namespace android { @@ -118,358 +110,24 @@ struct TimestampFinder : public RingBufferConsumer::RingBufferComparator { 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), + Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL, + width, height, + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), mDepth(depth), mProducer(new RingBufferConsumer(GRALLOC_USAGE_HW_CAMERA_ZSL, - depth)), - mConsumer(new Surface(mProducer->getProducerInterface())), - //mTransform(0), - mTotalBufferCount(0), - mDequeuedBufferCount(0), - mFrameCount(0), - mLastTimestamp(0), - mCombinedFence(new Fence()) { -} + depth)) { -Camera3ZslStream::~Camera3ZslStream() { - disconnectLocked(); + mConsumer = new Surface(mProducer->getProducerInterface()); } -status_t Camera3ZslStream::getBufferLocked(camera3_stream_buffer *buffer) { - // same as output stream code - 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; +Camera3ZslStream::~Camera3ZslStream() { } -status_t Camera3ZslStream::returnBufferLocked( - const camera3_stream_buffer &buffer, - nsecs_t timestamp) { - // same as output stream code +status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) { 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 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; - } - - sp releaseFence; - - /** - * Fence management - calculate Release Fence - */ - if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) { - if (buffer.release_fence != -1) { - ALOGE("%s: Stream %d: HAL should not set release_fence(%d) when " - "there is an error", __FUNCTION__, mId, buffer.release_fence); - close(buffer.release_fence); - } - - /** - * Reassign release fence as the acquire fence in case of error - */ - releaseFence = new Fence(buffer.acquire_fence); - } 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; - } - - releaseFence = new Fence(buffer.release_fence); - } - - int anwReleaseFence = releaseFence->dup(); - - /** - * Return buffer back to ANativeWindow - */ - if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) { - // Cancel buffer - res = mConsumer->cancelBuffer(mConsumer.get(), - container_of(buffer.buffer, ANativeWindowBuffer, handle), - anwReleaseFence); - if (res != OK) { - ALOGE("%s: Stream %d: Error cancelling buffer to native window:" - " %s (%d)", __FUNCTION__, mId, strerror(-res), res); - } - } else { - 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); - } - } - - if (res != OK) { - close(anwReleaseFence); - return res; - } - mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); - - mDequeuedBufferCount--; - mBufferReturnedSignal.signal(); - mLastTimestamp = timestamp; - - return OK; -} - -bool Camera3ZslStream::hasOutstandingBuffersLocked() const { - // same as output stream - 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 Camera3ZslStream::waitUntilIdle(nsecs_t timeout) { - // same as output stream - 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); -} -status_t Camera3ZslStream::configureQueueLocked() { status_t res; - switch (mState) { - case STATE_IN_RECONFIG: - res = disconnectLocked(); - 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; - } - - 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; - } - - return OK; -} - -size_t Camera3ZslStream::getBufferCountLocked() { - return mTotalBufferCount; -} - -status_t Camera3ZslStream::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; -} - -status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) { - ATRACE_CALL(); - // TODO: potentially register from inputBufferLocked // this should be ok, registerBuffersLocked only calls getBuffer for now // register in output mode instead of input mode for ZSL streams. @@ -480,21 +138,8 @@ status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) { return INVALID_OPERATION; } - // 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; + if ((res = getBufferPreconditionCheckLocked()) != OK) { + return res; } ANativeWindowBuffer* anb; @@ -526,47 +171,32 @@ status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) { * FenceFD now owned by HAL except in case of error, * in which case we reassign it to acquire_fence */ - - // 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++; + handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd, + /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK); mBuffersInFlight.push_back(bufferItem); return OK; } -status_t Camera3ZslStream::returnInputBufferLocked( - const camera3_stream_buffer &buffer) { - ATRACE_CALL(); +status_t Camera3ZslStream::returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut) { - // 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 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 (output) { + // Output stream path + return Camera3OutputStream::returnBufferCheckedLocked(buffer, + timestamp, + output, + releaseFenceOut); } + /** + * Input stream path + */ bool bufferFound = false; sp bufferItem; { @@ -583,7 +213,7 @@ status_t Camera3ZslStream::returnInputBufferLocked( bufferFound = true; bufferItem = tmp; mBuffersInFlight.erase(it); - mDequeuedBufferCount--; + break; } } } @@ -616,12 +246,19 @@ status_t Camera3ZslStream::returnInputBufferLocked( bufferItem->getBufferItem().mFence = releaseFence; bufferItem.clear(); // dropping last reference unpins buffer - mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); - - mBufferReturnedSignal.signal(); + *releaseFenceOut = releaseFence; return OK; +} + +status_t Camera3ZslStream::returnInputBufferLocked( + const camera3_stream_buffer &buffer) { + ATRACE_CALL(); + status_t res = returnAnyBufferLocked(buffer, /*timestamp*/0, + /*output*/false); + + return res; } void Camera3ZslStream::dump(int fd, const Vector &args) const { @@ -629,16 +266,11 @@ void Camera3ZslStream::dump(int fd, const Vector &args) const { String8 lines; lines.appendFormat(" Stream[%d]: ZSL\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(" 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()); + + Camera3IOStreamBase::dump(fd, args); + + lines = String8(); lines.appendFormat(" Input buffers pending: %d, in flight %d\n", mInputBufferQueue.size(), mBuffersInFlight.size()); write(fd, lines.string(), lines.size()); diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.h b/services/camera/libcameraservice/camera3/Camera3ZslStream.h index b863e7f..c7f4490 100644 --- a/services/camera/libcameraservice/camera3/Camera3ZslStream.h +++ b/services/camera/libcameraservice/camera3/Camera3ZslStream.h @@ -21,8 +21,7 @@ #include #include -#include "Camera3Stream.h" -#include "Camera3OutputStreamInterface.h" +#include "Camera3OutputStream.h" namespace android { @@ -35,8 +34,7 @@ namespace camera3 { * processing. */ class Camera3ZslStream : - public Camera3Stream, - public Camera3OutputStreamInterface { + public Camera3OutputStream { public: /** * Set up a ZSL stream of a given resolution. Depth is the number of buffers @@ -45,7 +43,6 @@ class Camera3ZslStream : Camera3ZslStream(int id, uint32_t width, uint32_t height, int depth); ~Camera3ZslStream(); - virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector &args) const; enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; @@ -65,6 +62,8 @@ class Camera3ZslStream : */ status_t clearInputRingBuffer(); + protected: + /** * Camera3OutputStreamInterface implementation */ @@ -76,41 +75,27 @@ class Camera3ZslStream : // Input buffers pending to be queued into HAL List > mInputBufferQueue; sp mProducer; - sp mConsumer; // Input buffers in flight to HAL Vector > mBuffersInFlight; - size_t mTotalBufferCount; - // sum of input and output buffers that are currently acquired by HAL - size_t mDequeuedBufferCount; - Condition mBufferReturnedSignal; - uint32_t mFrameCount; - // Last received output buffer's timestamp - nsecs_t mLastTimestamp; - - // The merged release fence for all returned buffers - sp mCombinedFence; /** * 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); // getInputBuffer/returnInputBuffer operate the input stream side of the // ZslStream. virtual status_t getInputBufferLocked(camera3_stream_buffer *buffer); virtual status_t returnInputBufferLocked( const camera3_stream_buffer &buffer); - virtual bool hasOutstandingBuffersLocked() const; - virtual status_t disconnectLocked(); - - virtual status_t configureQueueLocked(); - virtual size_t getBufferCountLocked(); - + // Actual body to return either input or output buffers + virtual status_t returnBufferCheckedLocked( + const camera3_stream_buffer &buffer, + nsecs_t timestamp, + bool output, + /*out*/ + sp *releaseFenceOut); }; // class Camera3ZslStream }; // namespace camera3 -- cgit v1.1