diff options
author | Igor Murashkin <iam@google.com> | 2013-04-22 14:03:54 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2013-04-29 10:54:49 -0700 |
commit | 2fba584544e8687b526e3388bf7160b696da1dba (patch) | |
tree | bec9fffefdccb6646bbd7d8e40b5a1d601768dbe /services/camera | |
parent | d4d5227521a53dec6f77bed33846b4ccd4a760e4 (diff) | |
download | frameworks_av-2fba584544e8687b526e3388bf7160b696da1dba.zip frameworks_av-2fba584544e8687b526e3388bf7160b696da1dba.tar.gz frameworks_av-2fba584544e8687b526e3388bf7160b696da1dba.tar.bz2 |
Camera3: Add ZSL stream support
Bug: 8563838
Change-Id: I2feda142ff5172aba17ade5c8d502f9bb5d5b766
Diffstat (limited to 'services/camera')
19 files changed, 1751 insertions, 66 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index e1c36d5..8ae414f 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES:= \ camera2/JpegCompressor.cpp \ camera2/CaptureSequencer.cpp \ camera2/ProFrameProcessor.cpp \ + camera2/ZslProcessor3.cpp \ camera3/Camera3Stream.cpp \ camera3/Camera3InputStream.cpp \ camera3/Camera3OutputStream.cpp \ diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index eae7461..48f3606 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -28,6 +28,9 @@ #include "Camera2Device.h" #include "Camera3Device.h" +#include "camera2/ZslProcessor.h" +#include "camera2/ZslProcessor3.h" + #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__); #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__); @@ -51,12 +54,13 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService, int deviceVersion): Camera2ClientBase(cameraService, cameraClient, clientPackageName, cameraId, cameraFacing, clientPid, clientUid, servicePid), - mParameters(cameraId, cameraFacing) + mParameters(cameraId, cameraFacing), + mDeviceVersion(deviceVersion) { ATRACE_CALL(); ALOGI("Camera %d: Opened", cameraId); - switch (deviceVersion) { + switch (mDeviceVersion) { case CAMERA_DEVICE_API_VERSION_2_0: mDevice = new Camera2Device(cameraId); break; @@ -65,7 +69,7 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService, break; default: ALOGE("Camera %d: Unknown HAL device version %d", - cameraId, deviceVersion); + cameraId, mDeviceVersion); mDevice = NULL; break; } @@ -114,10 +118,27 @@ status_t Camera2Client::initialize(camera_module_t *module) mCameraId); mJpegProcessor->run(threadName.string()); - mZslProcessor = new ZslProcessor(this, mCaptureSequencer); + switch (mDeviceVersion) { + case CAMERA_DEVICE_API_VERSION_2_0: { + sp<ZslProcessor> zslProc = + new ZslProcessor(this, mCaptureSequencer); + mZslProcessor = zslProc; + mZslProcessorThread = zslProc; + break; + } + case CAMERA_DEVICE_API_VERSION_3_0:{ + sp<ZslProcessor3> zslProc = + new ZslProcessor3(this, mCaptureSequencer); + mZslProcessor = zslProc; + mZslProcessorThread = zslProc; + break; + } + default: + break; + } threadName = String8::format("C2-%d-ZslProc", mCameraId); - mZslProcessor->run(threadName.string()); + mZslProcessorThread->run(threadName.string()); mCallbackProcessor = new CallbackProcessor(this); threadName = String8::format("C2-%d-CallbkProc", @@ -393,7 +414,7 @@ void Camera2Client::disconnect() { mFrameProcessor->requestExit(); mCaptureSequencer->requestExit(); mJpegProcessor->requestExit(); - mZslProcessor->requestExit(); + mZslProcessorThread->requestExit(); mCallbackProcessor->requestExit(); ALOGV("Camera %d: Waiting for threads", mCameraId); @@ -401,7 +422,7 @@ void Camera2Client::disconnect() { mFrameProcessor->join(); mCaptureSequencer->join(); mJpegProcessor->join(); - mZslProcessor->join(); + mZslProcessorThread->join(); mCallbackProcessor->join(); ALOGV("Camera %d: Disconnecting device", mCameraId); diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index 713fab3..af72ab2 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -23,7 +23,7 @@ #include "camera2/FrameProcessor.h" #include "camera2/StreamingProcessor.h" #include "camera2/JpegProcessor.h" -#include "camera2/ZslProcessor.h" +#include "camera2/ZslProcessorInterface.h" #include "camera2/CaptureSequencer.h" #include "camera2/CallbackProcessor.h" #include "Camera2ClientBase.h" @@ -154,6 +154,7 @@ private: void setPreviewCallbackFlagL(Parameters ¶ms, int flag); status_t updateRequests(Parameters ¶ms); + int mDeviceVersion; // Used with stream IDs static const int NO_STREAM = -1; @@ -173,7 +174,8 @@ private: sp<camera2::CaptureSequencer> mCaptureSequencer; sp<camera2::JpegProcessor> mJpegProcessor; - sp<camera2::ZslProcessor> mZslProcessor; + sp<camera2::ZslProcessorInterface> mZslProcessor; + sp<Thread> mZslProcessorThread; /** Notification-related members */ diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp index 3437130..748f3a7 100644 --- a/services/camera/libcameraservice/Camera3Device.cpp +++ b/services/camera/libcameraservice/Camera3Device.cpp @@ -433,6 +433,81 @@ status_t Camera3Device::createInputStream( return OK; } + +status_t Camera3Device::createZslStream( + uint32_t width, uint32_t height, + int depth, + /*out*/ + int *id, + sp<Camera3ZslStream>* zslStream) { + ATRACE_CALL(); + Mutex::Autolock l(mLock); + + status_t res; + bool wasActive = false; + + switch (mStatus) { + case STATUS_ERROR: + ALOGE("%s: Device has encountered a serious error", __FUNCTION__); + return INVALID_OPERATION; + case STATUS_UNINITIALIZED: + ALOGE("%s: Device not initialized", __FUNCTION__); + return INVALID_OPERATION; + case STATUS_IDLE: + // OK + break; + case STATUS_ACTIVE: + ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__); + mRequestThread->setPaused(true); + res = waitUntilDrainedLocked(); + if (res != OK) { + ALOGE("%s: Can't pause captures to reconfigure streams!", + __FUNCTION__); + mStatus = STATUS_ERROR; + return res; + } + wasActive = true; + break; + default: + ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus); + return INVALID_OPERATION; + } + assert(mStatus == STATUS_IDLE); + + if (mInputStream != 0) { + ALOGE("%s: Cannot create more than 1 input stream", __FUNCTION__); + return INVALID_OPERATION; + } + + sp<Camera3ZslStream> newStream = new Camera3ZslStream(mNextStreamId, + width, height, depth); + + res = mOutputStreams.add(mNextStreamId, newStream); + if (res < 0) { + ALOGE("%s: Can't add new stream to set: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + mInputStream = newStream; + + *id = mNextStreamId++; + *zslStream = newStream; + + // Continue captures if active at start + if (wasActive) { + ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__); + res = configureStreamsLocked(); + if (res != OK) { + ALOGE("%s: Can't reconfigure device for new stream %d: %s (%d)", + __FUNCTION__, mNextStreamId, strerror(-res), res); + return res; + } + mRequestThread->setPaused(false); + } + + return OK; +} + status_t Camera3Device::createStream(sp<ANativeWindow> consumer, uint32_t width, uint32_t height, int format, size_t size, int *id) { ATRACE_CALL(); @@ -588,7 +663,7 @@ status_t Camera3Device::deleteStream(int id) { return INVALID_OPERATION; } - sp<Camera3Stream> deletedStream; + sp<Camera3StreamInterface> deletedStream; if (mInputStream != NULL && id == mInputStream->getId()) { deletedStream = mInputStream; mInputStream.clear(); @@ -881,7 +956,8 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest( __FUNCTION__, streams.data.u8[i]); return NULL; } - sp<Camera3OutputStream> stream = mOutputStreams.editValueAt(idx); + sp<Camera3OutputStreamInterface> stream = + mOutputStreams.editValueAt(idx); // Lazy completion of stream configuration (allocation/registration) // on first use @@ -932,6 +1008,15 @@ status_t Camera3Device::configureStreamsLocked() { } for (size_t i = 0; i < mOutputStreams.size(); i++) { + + // Don't configure bidi streams twice, nor add them twice to the list + if (mOutputStreams[i].get() == + static_cast<Camera3StreamInterface*>(mInputStream.get())) { + + config.num_streams--; + continue; + } + camera3_stream_t *outputStream; outputStream = mOutputStreams.editValueAt(i)->startConfiguration(); if (outputStream == NULL) { diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h index 5c5faeb..9b26f06 100644 --- a/services/camera/libcameraservice/Camera3Device.h +++ b/services/camera/libcameraservice/Camera3Device.h @@ -26,6 +26,7 @@ #include "CameraDeviceBase.h" #include "camera3/Camera3Stream.h" #include "camera3/Camera3OutputStream.h" +#include "camera3/Camera3ZslStream.h" #include "hardware/camera3.h" @@ -85,6 +86,12 @@ class Camera3Device : virtual status_t createInputStream( uint32_t width, uint32_t height, int format, int *id); + virtual status_t createZslStream( + uint32_t width, uint32_t height, + int depth, + /*out*/ + int *id, + sp<camera3::Camera3ZslStream>* zslStream); virtual status_t createReprocessStreamFromStream(int outputId, int *id); virtual status_t getStreamInfo(int id, @@ -132,14 +139,15 @@ class Camera3Device : } mStatus; // Mapping of stream IDs to stream instances - typedef KeyedVector<int, sp<camera3::Camera3OutputStream> > StreamSet; + typedef KeyedVector<int, sp<camera3::Camera3OutputStreamInterface> > + StreamSet; StreamSet mOutputStreams; sp<camera3::Camera3Stream> mInputStream; int mNextStreamId; // Need to hold on to stream references until configure completes. - Vector<sp<camera3::Camera3Stream> > mDeletedStreams; + Vector<sp<camera3::Camera3StreamInterface> > mDeletedStreams; /**** End scope for mLock ****/ @@ -147,7 +155,8 @@ class Camera3Device : public: CameraMetadata mSettings; sp<camera3::Camera3Stream> mInputStream; - Vector<sp<camera3::Camera3Stream> > mOutputStreams; + Vector<sp<camera3::Camera3OutputStreamInterface> > + mOutputStreams; }; typedef List<sp<CaptureRequest> > RequestList; diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp index ee03329..266e516 100644 --- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp @@ -27,6 +27,7 @@ #include "../Camera2Device.h" #include "../Camera2Client.h" #include "Parameters.h" +#include "ZslProcessorInterface.h" namespace android { namespace camera2 { @@ -54,7 +55,7 @@ CaptureSequencer::~CaptureSequencer() { ALOGV("%s: Exit", __FUNCTION__); } -void CaptureSequencer::setZslProcessor(wp<ZslProcessor> processor) { +void CaptureSequencer::setZslProcessor(wp<ZslProcessorInterface> processor) { Mutex::Autolock l(mInputMutex); mZslProcessor = processor; } @@ -265,8 +266,10 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c res = INVALID_OPERATION; } } - sp<ZslProcessor> processor = mZslProcessor.promote(); + sp<ZslProcessorInterface> processor = mZslProcessor.promote(); if (processor != 0) { + ALOGV("%s: Memory optimization, clearing ZSL queue", + __FUNCTION__); processor->clearZslQueue(); } @@ -324,7 +327,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslStart( sp<Camera2Client> &client) { ALOGV("%s", __FUNCTION__); status_t res; - sp<ZslProcessor> processor = mZslProcessor.promote(); + sp<ZslProcessorInterface> processor = mZslProcessor.promote(); if (processor == 0) { ALOGE("%s: No ZSL queue to use!", __FUNCTION__); return DONE; diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.h b/services/camera/libcameraservice/camera2/CaptureSequencer.h index 7db8007..76750aa 100644 --- a/services/camera/libcameraservice/camera2/CaptureSequencer.h +++ b/services/camera/libcameraservice/camera2/CaptureSequencer.h @@ -33,7 +33,7 @@ class Camera2Client; namespace camera2 { -class ZslProcessor; +class ZslProcessorInterface; class BurstCapture; /** @@ -48,7 +48,7 @@ class CaptureSequencer: ~CaptureSequencer(); // Get reference to the ZslProcessor, which holds the ZSL buffers and frames - void setZslProcessor(wp<ZslProcessor> processor); + void setZslProcessor(wp<ZslProcessorInterface> processor); // Begin still image capture status_t startCapture(int msgType); @@ -105,7 +105,7 @@ class CaptureSequencer: static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec wp<Camera2Client> mClient; - wp<ZslProcessor> mZslProcessor; + wp<ZslProcessorInterface> mZslProcessor; sp<BurstCapture> mBurstCapture; enum CaptureState { diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp index 2c12fb0..94059cd 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp +++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp @@ -248,11 +248,6 @@ int ZslProcessor::getStreamId() const { return mZslStreamId; } -int ZslProcessor::getReprocessStreamId() const { - Mutex::Autolock l(mInputMutex); - return mZslReprocessStreamId; -} - status_t ZslProcessor::pushToReprocess(int32_t requestId) { ALOGV("%s: Send in reprocess request with id %d", __FUNCTION__, requestId); diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.h b/services/camera/libcameraservice/camera2/ZslProcessor.h index ee3bcd6..27b597e 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor.h +++ b/services/camera/libcameraservice/camera2/ZslProcessor.h @@ -28,6 +28,7 @@ #include "camera/CameraMetadata.h" #include "Camera2Heap.h" #include "../CameraDeviceBase.h" +#include "ZslProcessorInterface.h" namespace android { @@ -44,7 +45,8 @@ class ZslProcessor: virtual public Thread, virtual public BufferItemConsumer::FrameAvailableListener, virtual public FrameProcessor::FilteredListener, - virtual public CameraDeviceBase::BufferReleasedListener { + virtual public CameraDeviceBase::BufferReleasedListener, + public ZslProcessorInterface { public: ZslProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer); ~ZslProcessor(); @@ -56,10 +58,15 @@ class ZslProcessor: virtual void onBufferReleased(buffer_handle_t *handle); + /** + **************************************** + * ZslProcessorInterface implementation * + **************************************** + */ + status_t updateStream(const Parameters ¶ms); status_t deleteStream(); int getStreamId() const; - int getReprocessStreamId() const; status_t pushToReprocess(int32_t requestId); status_t clearZslQueue(); diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp new file mode 100644 index 0000000..88bcefb --- /dev/null +++ b/services/camera/libcameraservice/camera2/ZslProcessor3.cpp @@ -0,0 +1,442 @@ +/* + * 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 "Camera2-ZslProcessor3" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 +//#define LOG_NNDEBUG 0 + +#ifdef LOG_NNDEBUG +#define ALOGVV(...) ALOGV(__VA_ARGS__) +#else +#define ALOGVV(...) ((void)0) +#endif + +#include <utils/Log.h> +#include <utils/Trace.h> + +#include "ZslProcessor3.h" +#include <gui/Surface.h> +#include "../CameraDeviceBase.h" +#include "../Camera3Device.h" +#include "../Camera2Client.h" + + +namespace android { +namespace camera2 { + +ZslProcessor3::ZslProcessor3( + sp<Camera2Client> client, + wp<CaptureSequencer> sequencer): + Thread(false), + mState(RUNNING), + mClient(client), + mSequencer(sequencer), + mId(client->getCameraId()), + mZslStreamId(NO_STREAM), + mFrameListHead(0), + mZslQueueHead(0), + mZslQueueTail(0) { + mZslQueue.insertAt(0, kZslBufferDepth); + mFrameList.insertAt(0, kFrameListDepth); + sp<CaptureSequencer> captureSequencer = mSequencer.promote(); + if (captureSequencer != 0) captureSequencer->setZslProcessor(this); +} + +ZslProcessor3::~ZslProcessor3() { + ALOGV("%s: Exit", __FUNCTION__); + deleteStream(); +} + +void ZslProcessor3::onFrameAvailable(int32_t /*frameId*/, + const CameraMetadata &frame) { + Mutex::Autolock l(mInputMutex); + camera_metadata_ro_entry_t entry; + entry = frame.find(ANDROID_SENSOR_TIMESTAMP); + nsecs_t timestamp = entry.data.i64[0]; + (void)timestamp; + ALOGVV("Got preview metadata for timestamp %lld", timestamp); + + if (mState != RUNNING) return; + + mFrameList.editItemAt(mFrameListHead) = frame; + mFrameListHead = (mFrameListHead + 1) % kFrameListDepth; +} + +status_t ZslProcessor3::updateStream(const Parameters ¶ms) { + ATRACE_CALL(); + ALOGV("%s: Configuring ZSL streams", __FUNCTION__); + status_t res; + + Mutex::Autolock l(mInputMutex); + + sp<Camera2Client> client = mClient.promote(); + if (client == 0) { + ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + sp<Camera3Device> device = + static_cast<Camera3Device*>(client->getCameraDevice().get()); + if (device == 0) { + ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + if (mZslStreamId != NO_STREAM) { + // Check if stream parameters have to change + uint32_t currentWidth, currentHeight; + res = device->getStreamInfo(mZslStreamId, + ¤tWidth, ¤tHeight, 0); + if (res != OK) { + ALOGE("%s: Camera %d: Error querying capture output stream info: " + "%s (%d)", __FUNCTION__, + client->getCameraId(), strerror(-res), res); + return res; + } + if (currentWidth != (uint32_t)params.fastInfo.arrayWidth || + currentHeight != (uint32_t)params.fastInfo.arrayHeight) { + ALOGV("%s: Camera %d: Deleting stream %d since the buffer " + "dimensions changed", + __FUNCTION__, client->getCameraId(), mZslStreamId); + res = device->deleteStream(mZslStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to delete old output stream " + "for ZSL: %s (%d)", __FUNCTION__, + client->getCameraId(), strerror(-res), res); + return res; + } + mZslStreamId = NO_STREAM; + } + } + + if (mZslStreamId == NO_STREAM) { + // Create stream for HAL production + // TODO: Sort out better way to select resolution for ZSL + + // Note that format specified internally in Camera3ZslStream + res = device->createZslStream( + params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, + kZslBufferDepth, + &mZslStreamId, + &mZslStream); + if (res != OK) { + ALOGE("%s: Camera %d: Can't create ZSL stream: " + "%s (%d)", __FUNCTION__, client->getCameraId(), + strerror(-res), res); + return res; + } + } + client->registerFrameListener(Camera2Client::kPreviewRequestIdStart, + Camera2Client::kPreviewRequestIdEnd, + this); + + return OK; +} + +status_t ZslProcessor3::deleteStream() { + ATRACE_CALL(); + status_t res; + + Mutex::Autolock l(mInputMutex); + + if (mZslStreamId != NO_STREAM) { + sp<Camera2Client> client = mClient.promote(); + if (client == 0) { + ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + sp<Camera3Device> device = + reinterpret_cast<Camera3Device*>(client->getCameraDevice().get()); + if (device == 0) { + ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + res = device->deleteStream(mZslStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: " + "%s (%d)", __FUNCTION__, client->getCameraId(), + mZslStreamId, strerror(-res), res); + return res; + } + + mZslStreamId = NO_STREAM; + } + return OK; +} + +int ZslProcessor3::getStreamId() const { + Mutex::Autolock l(mInputMutex); + return mZslStreamId; +} + +status_t ZslProcessor3::pushToReprocess(int32_t requestId) { + ALOGV("%s: Send in reprocess request with id %d", + __FUNCTION__, requestId); + Mutex::Autolock l(mInputMutex); + status_t res; + sp<Camera2Client> client = mClient.promote(); + + if (client == 0) { + ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId); + return INVALID_OPERATION; + } + + IF_ALOGV() { + dumpZslQueue(-1); + } + + size_t metadataIdx; + nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx); + + if (candidateTimestamp == -1) { + ALOGE("%s: Could not find good candidate for ZSL reprocessing", + __FUNCTION__); + return NOT_ENOUGH_DATA; + } + + res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp, + /*actualTimestamp*/NULL); + + if (res == mZslStream->NO_BUFFER_AVAILABLE) { + ALOGV("%s: No ZSL buffers yet", __FUNCTION__); + return NOT_ENOUGH_DATA; + } else if (res != OK) { + ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)", + __FUNCTION__, strerror(-res), res); + return res; + } + + { + CameraMetadata request = mFrameList[metadataIdx]; + + // Verify that the frame is reasonable for reprocessing + + camera_metadata_entry_t entry; + entry = request.find(ANDROID_CONTROL_AE_STATE); + if (entry.count == 0) { + ALOGE("%s: ZSL queue frame has no AE state field!", + __FUNCTION__); + return BAD_VALUE; + } + if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED && + entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) { + ALOGV("%s: ZSL queue frame AE state is %d, need full capture", + __FUNCTION__, entry.data.u8[0]); + return NOT_ENOUGH_DATA; + } + + uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS; + res = request.update(ANDROID_REQUEST_TYPE, + &requestType, 1); + uint8_t inputStreams[1] = + { static_cast<uint8_t>(mZslStreamId) }; + if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS, + inputStreams, 1); + // TODO: Shouldn't we also update the latest preview frame? + uint8_t outputStreams[1] = + { static_cast<uint8_t>(client->getCaptureStreamId()) }; + if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS, + outputStreams, 1); + res = request.update(ANDROID_REQUEST_ID, + &requestId, 1); + + if (res != OK ) { + ALOGE("%s: Unable to update frame to a reprocess request", + __FUNCTION__); + return INVALID_OPERATION; + } + + res = client->stopStream(); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: " + "%s (%d)", + __FUNCTION__, client->getCameraId(), strerror(-res), res); + return INVALID_OPERATION; + } + + // Update JPEG settings + { + SharedParameters::Lock l(client->getParameters()); + res = l.mParameters.updateRequestJpeg(&request); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL " + "capture request: %s (%d)", __FUNCTION__, + client->getCameraId(), + strerror(-res), res); + return res; + } + } + + mLatestCapturedRequest = request; + res = client->getCameraDevice()->capture(request); + if (res != OK ) { + ALOGE("%s: Unable to send ZSL reprocess request to capture: %s" + " (%d)", __FUNCTION__, strerror(-res), res); + return res; + } + + mState = LOCKED; + } + + return OK; +} + +status_t ZslProcessor3::clearZslQueue() { + Mutex::Autolock l(mInputMutex); + // If in middle of capture, can't clear out queue + if (mState == LOCKED) return OK; + + return clearZslQueueLocked(); +} + +status_t ZslProcessor3::clearZslQueueLocked() { + return mZslStream->clearInputRingBuffer(); +} + +void ZslProcessor3::dump(int fd, const Vector<String16>& /*args*/) const { + Mutex::Autolock l(mInputMutex); + if (!mLatestCapturedRequest.isEmpty()) { + String8 result(" Latest ZSL capture request:\n"); + write(fd, result.string(), result.size()); + mLatestCapturedRequest.dump(fd, 2, 6); + } else { + String8 result(" Latest ZSL capture request: none yet\n"); + write(fd, result.string(), result.size()); + } + dumpZslQueue(fd); +} + +bool ZslProcessor3::threadLoop() { + // TODO: remove dependency on thread + return true; +} + +void ZslProcessor3::dumpZslQueue(int fd) const { + String8 header("ZSL queue contents:"); + String8 indent(" "); + ALOGV("%s", header.string()); + if (fd != -1) { + header = indent + header + "\n"; + write(fd, header.string(), header.size()); + } + for (size_t i = 0; i < mZslQueue.size(); i++) { + const ZslPair &queueEntry = mZslQueue[i]; + nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp; + camera_metadata_ro_entry_t entry; + nsecs_t frameTimestamp = 0; + int frameAeState = -1; + if (!queueEntry.frame.isEmpty()) { + entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP); + if (entry.count > 0) frameTimestamp = entry.data.i64[0]; + entry = queueEntry.frame.find(ANDROID_CONTROL_AE_STATE); + if (entry.count > 0) frameAeState = entry.data.u8[0]; + } + String8 result = + String8::format(" %d: b: %lld\tf: %lld, AE state: %d", i, + bufferTimestamp, frameTimestamp, frameAeState); + ALOGV("%s", result.string()); + if (fd != -1) { + result = indent + result + "\n"; + write(fd, result.string(), result.size()); + } + + } +} + +nsecs_t ZslProcessor3::getCandidateTimestampLocked(size_t* metadataIdx) const { + /** + * Find the smallest timestamp we know about so far + * - ensure that aeState is either converged or locked + */ + + size_t idx = 0; + nsecs_t minTimestamp = -1; + for (size_t j = 0; j < mFrameList.size(); j++) { + const CameraMetadata &frame = mFrameList[j]; + if (!frame.isEmpty()) { + camera_metadata_ro_entry_t entry; + entry = frame.find(ANDROID_SENSOR_TIMESTAMP); + if (entry.count == 0) { + ALOGE("%s: Can't find timestamp in frame!", + __FUNCTION__); + continue; + } + nsecs_t frameTimestamp = entry.data.i64[0]; + if (minTimestamp > frameTimestamp) { + + entry = frame.find(ANDROID_CONTROL_AE_STATE); + if (entry.count == 0) { + ALOGW("%s: ZSL queue frame has no AE state field!", + __FUNCTION__); + continue; + } + if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED && + entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) { + ALOGVV("%s: ZSL queue frame AE state is %d, need " + "full capture", __FUNCTION__, entry.data.u8[0]); + continue; + } + + minTimestamp = frameTimestamp; + idx = j; + } + } + } + + if (metadataIdx) { + *metadataIdx = idx; + } + + return minTimestamp; +} + +void ZslProcessor3::onBufferAcquired(const BufferInfo& /*bufferInfo*/) { + // Intentionally left empty + // Although theoretically we could use this to get better dump info +} + +void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) { + Mutex::Autolock l(mInputMutex); + + // ignore output buffers + if (bufferInfo.mOutput) { + return; + } + + // TODO: Verify that the buffer is in our queue by looking at timestamp + // theoretically unnecessary unless we change the following assumptions: + // -- only 1 buffer reprocessed at a time (which is the case now) + + // Erase entire ZSL queue since we've now completed the capture and preview + // is stopped. + // + // We need to guarantee that if we do two back-to-back captures, + // the second won't use a buffer that's older/the same as the first, which + // is theoretically possible if we don't clear out the queue and the + // selection criteria is something like 'newest'. Clearing out the queue + // on a completed capture ensures we'll only use new data. + ALOGV("%s: Memory optimization, clearing ZSL queue", + __FUNCTION__); + clearZslQueueLocked(); + + // Required so we accept more ZSL requests + mState = RUNNING; +} + +}; // namespace camera2 +}; // namespace android diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.h b/services/camera/libcameraservice/camera2/ZslProcessor3.h new file mode 100644 index 0000000..cb98b99 --- /dev/null +++ b/services/camera/libcameraservice/camera2/ZslProcessor3.h @@ -0,0 +1,137 @@ +/* + * 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_CAMERA_CAMERA2_ZSLPROCESSOR3_H +#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSOR3_H + +#include <utils/Thread.h> +#include <utils/String16.h> +#include <utils/Vector.h> +#include <utils/Mutex.h> +#include <utils/Condition.h> +#include <gui/BufferItemConsumer.h> +#include "Parameters.h" +#include "FrameProcessor.h" +#include "camera/CameraMetadata.h" +#include "Camera2Heap.h" +#include "../CameraDeviceBase.h" +#include "ZslProcessorInterface.h" +#include "../camera3/Camera3ZslStream.h" + +namespace android { + +class Camera2Client; + +namespace camera2 { + +class CaptureSequencer; + +/*** + * ZSL queue processing + */ +class ZslProcessor3 : + public ZslProcessorInterface, + public camera3::Camera3StreamBufferListener, + virtual public Thread, + virtual public FrameProcessor::FilteredListener { + public: + ZslProcessor3(sp<Camera2Client> client, wp<CaptureSequencer> sequencer); + ~ZslProcessor3(); + + // From FrameProcessor + virtual void onFrameAvailable(int32_t frameId, const CameraMetadata &frame); + + /** + **************************************** + * ZslProcessorInterface implementation * + **************************************** + */ + + virtual status_t updateStream(const Parameters ¶ms); + virtual status_t deleteStream(); + virtual int getStreamId() const; + + virtual status_t pushToReprocess(int32_t requestId); + virtual status_t clearZslQueue(); + + void dump(int fd, const Vector<String16>& args) const; + + protected: + /** + ********************************************** + * Camera3StreamBufferListener implementation * + ********************************************** + */ + typedef camera3::Camera3StreamBufferListener::BufferInfo BufferInfo; + // Buffer was acquired by the HAL + virtual void onBufferAcquired(const BufferInfo& bufferInfo); + // Buffer was released by the HAL + virtual void onBufferReleased(const BufferInfo& bufferInfo); + + private: + static const nsecs_t kWaitDuration = 10000000; // 10 ms + + enum { + RUNNING, + LOCKED + } mState; + + wp<Camera2Client> mClient; + wp<CaptureSequencer> mSequencer; + + const int mId; + + mutable Mutex mInputMutex; + + enum { + NO_STREAM = -1 + }; + + int mZslStreamId; + sp<camera3::Camera3ZslStream> mZslStream; + + struct ZslPair { + BufferItemConsumer::BufferItem buffer; + CameraMetadata frame; + }; + + static const size_t kZslBufferDepth = 4; + static const size_t kFrameListDepth = kZslBufferDepth * 2; + Vector<CameraMetadata> mFrameList; + size_t mFrameListHead; + + ZslPair mNextPair; + + Vector<ZslPair> mZslQueue; + size_t mZslQueueHead; + size_t mZslQueueTail; + + CameraMetadata mLatestCapturedRequest; + + virtual bool threadLoop(); + + status_t clearZslQueueLocked(); + + void dumpZslQueue(int id) const; + + nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const; +}; + + +}; //namespace camera2 +}; //namespace android + +#endif diff --git a/services/camera/libcameraservice/camera2/ZslProcessorInterface.h b/services/camera/libcameraservice/camera2/ZslProcessorInterface.h new file mode 100644 index 0000000..183c0c2 --- /dev/null +++ b/services/camera/libcameraservice/camera2/ZslProcessorInterface.h @@ -0,0 +1,59 @@ +/* + * 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_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H +#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H + +#include <utils/Errors.h> +#include <utils/RefBase.h> + +namespace android { +namespace camera2 { + +class Parameters; + +class ZslProcessorInterface : virtual public RefBase { +public: + + // Get ID for use with android.request.outputStreams / inputStreams + virtual int getStreamId() const = 0; + + // Update the streams by recreating them if the size/format has changed + virtual status_t updateStream(const Parameters& params) = 0; + + // Delete the underlying CameraDevice streams + virtual status_t deleteStream() = 0; + + /** + * Submits a ZSL capture request (id = requestId) + * + * An appropriate ZSL buffer is selected by the closest timestamp, + * then we push that buffer to be reprocessed by the HAL. + * A capture request is created and submitted on behalf of the client. + */ + virtual status_t pushToReprocess(int32_t requestId) = 0; + + // Flush the ZSL buffer queue, freeing up all the buffers + virtual status_t clearZslQueue() = 0; + + // (Debugging only) Dump the current state to the specified file descriptor + virtual void dump(int fd, const Vector<String16>& args) const = 0; +}; + +}; //namespace camera2 +}; //namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.h b/services/camera/libcameraservice/camera3/Camera3OutputStream.h index d331a94..2464dce 100644 --- a/services/camera/libcameraservice/camera3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/camera3/Camera3OutputStream.h @@ -21,6 +21,7 @@ #include <gui/Surface.h> #include "Camera3Stream.h" +#include "Camera3OutputStreamInterface.h" namespace android { @@ -29,7 +30,9 @@ namespace camera3 { /** * A class for managing a single stream of output data from the camera device. */ -class Camera3OutputStream : public Camera3Stream { +class Camera3OutputStream : + public Camera3Stream, + public Camera3OutputStreamInterface { public: /** * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/camera3/Camera3OutputStreamInterface.h new file mode 100644 index 0000000..aae72cf --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3OutputStreamInterface.h @@ -0,0 +1,43 @@ +/* + * 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_INTERFACE_H +#define ANDROID_SERVERS_CAMERA3_OUTPUT_STREAM_INTERFACE_H + +#include "Camera3StreamInterface.h" + +namespace android { + +namespace camera3 { + +/** + * An interface for managing a single stream of output data from the camera + * device. + */ +class Camera3OutputStreamInterface : public virtual Camera3StreamInterface { + public: + /** + * Set the transform on the output stream; one of the + * HAL_TRANSFORM_* / NATIVE_WINDOW_TRANSFORM_* constants. + */ + virtual status_t setTransform(int transform) = 0; +}; + +} // namespace camera3 + +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3Stream.cpp b/services/camera/libcameraservice/camera3/Camera3Stream.cpp index bc259b6..f137227 100644 --- a/services/camera/libcameraservice/camera3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/camera3/Camera3Stream.cpp @@ -178,26 +178,75 @@ status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) { status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); - return getBufferLocked(buffer); + + status_t res = getBufferLocked(buffer); + if (res == OK) { + fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true); + } + + return res; } status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer, nsecs_t timestamp) { ATRACE_CALL(); Mutex::Autolock l(mLock); - return returnBufferLocked(buffer, timestamp); + + status_t res = returnBufferLocked(buffer, timestamp); + if (res == OK) { + fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true); + } + + return res; } status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); - return getInputBufferLocked(buffer); + + status_t res = getInputBufferLocked(buffer); + if (res == OK) { + fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false); + } + + return res; } status_t Camera3Stream::returnInputBuffer(const camera3_stream_buffer &buffer) { ATRACE_CALL(); Mutex::Autolock l(mLock); - return returnInputBufferLocked(buffer); + + status_t res = returnInputBufferLocked(buffer); + if (res == OK) { + fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false); + } + return res; +} + +void Camera3Stream::fireBufferListenersLocked( + const camera3_stream_buffer& /*buffer*/, bool acquired, bool output) { + List<wp<Camera3StreamBufferListener> >::iterator it, end; + + // TODO: finish implementing + + Camera3StreamBufferListener::BufferInfo info = + Camera3StreamBufferListener::BufferInfo(); + info.mOutput = output; + // TODO: rest of fields + + for (it = mBufferListenerList.begin(), end = mBufferListenerList.end(); + it != end; + ++it) { + + sp<Camera3StreamBufferListener> listener = it->promote(); + if (listener != 0) { + if (acquired) { + listener->onBufferAcquired(info); + } else { + listener->onBufferReleased(info); + } + } + } } bool Camera3Stream::hasOutstandingBuffers() const { @@ -290,6 +339,36 @@ status_t Camera3Stream::returnInputBufferLocked( return INVALID_OPERATION; } +void Camera3Stream::addBufferListener( + wp<Camera3StreamBufferListener> listener) { + Mutex::Autolock l(mLock); + mBufferListenerList.push_back(listener); +} + +void Camera3Stream::removeBufferListener( + const sp<Camera3StreamBufferListener>& listener) { + Mutex::Autolock l(mLock); + + bool erased = true; + List<wp<Camera3StreamBufferListener> >::iterator it, end; + for (it = mBufferListenerList.begin(), end = mBufferListenerList.end(); + it != end; + ) { + + if (*it == listener) { + it = mBufferListenerList.erase(it); + erased = true; + } else { + ++it; + } + } + + if (!erased) { + ALOGW("%s: Could not find listener to remove, already removed", + __FUNCTION__); + } +} + }; // namespace camera3 }; // namespace android diff --git a/services/camera/libcameraservice/camera3/Camera3Stream.h b/services/camera/libcameraservice/camera3/Camera3Stream.h index 46a3872..d992cfe 100644 --- a/services/camera/libcameraservice/camera3/Camera3Stream.h +++ b/services/camera/libcameraservice/camera3/Camera3Stream.h @@ -21,9 +21,13 @@ #include <utils/RefBase.h> #include <utils/String8.h> #include <utils/String16.h> +#include <utils/List.h> #include "hardware/camera3.h" +#include "Camera3StreamBufferListener.h" +#include "Camera3StreamInterface.h" + namespace android { namespace camera3 { @@ -81,7 +85,8 @@ namespace camera3 { */ class Camera3Stream : protected camera3_stream, - public LightRefBase<Camera3Stream> { + public virtual Camera3StreamInterface, + public virtual RefBase { public: virtual ~Camera3Stream(); @@ -205,6 +210,11 @@ class Camera3Stream : */ virtual void dump(int fd, const Vector<String16> &args) const = 0; + void addBufferListener( + wp<Camera3StreamBufferListener> listener); + void removeBufferListener( + const sp<Camera3StreamBufferListener>& listener); + protected: const int mId; const String8 mName; @@ -261,6 +271,10 @@ class Camera3Stream : // Gets all buffers from endpoint and registers them with the HAL. status_t registerBuffersLocked(camera3_device *hal3Device); + void fireBufferListenersLocked(const camera3_stream_buffer& buffer, + bool acquired, bool output); + List<wp<Camera3StreamBufferListener> > mBufferListenerList; + }; // class Camera3Stream }; // namespace camera3 diff --git a/services/camera/libcameraservice/camera3/Camera3StreamInterface.h b/services/camera/libcameraservice/camera3/Camera3StreamInterface.h new file mode 100644 index 0000000..4768536 --- /dev/null +++ b/services/camera/libcameraservice/camera3/Camera3StreamInterface.h @@ -0,0 +1,162 @@ +/* + * 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_INTERFACE_H +#define ANDROID_SERVERS_CAMERA3_STREAM_INTERFACE_H + +#include <utils/RefBase.h> +#include "Camera3StreamBufferListener.h" + +struct camera3_stream_buffer; + +namespace android { + +namespace camera3 { + +/** + * An interface for managing a single stream of input and/or output data from + * the camera device. + */ +class Camera3StreamInterface : public virtual RefBase { + public: + /** + * Get the stream's ID + */ + virtual int getId() const = 0; + + /** + * Get the stream's dimensions and format + */ + virtual uint32_t getWidth() const = 0; + virtual uint32_t getHeight() const = 0; + virtual int getFormat() const = 0; + + /** + * 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. + */ + virtual camera3_stream* startConfiguration() = 0; + + /** + * Check if the stream is mid-configuration (start has been called, but not + * finish). Used for lazy completion of configuration. + */ + virtual bool isConfiguring() const = 0; + + /** + * 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 + */ + virtual status_t finishConfiguration(camera3_device *hal3Device) = 0; + + /** + * 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. + * + */ + virtual status_t getBuffer(camera3_stream_buffer *buffer) = 0; + + /** + * 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 + */ + virtual status_t returnBuffer(const camera3_stream_buffer &buffer, + nsecs_t timestamp) = 0; + + /** + * 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 input-side + * buffers. + * + */ + virtual status_t getInputBuffer(camera3_stream_buffer *buffer) = 0; + + /** + * 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 input-side buffers + */ + virtual status_t returnInputBuffer(const camera3_stream_buffer &buffer) = 0; + + /** + * 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. + */ + virtual bool hasOutstandingBuffers() const = 0; + + 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. + */ + virtual status_t disconnect() = 0; + + /** + * Debug dump of the stream's state. + */ + virtual void dump(int fd, const Vector<String16> &args) const = 0; + + virtual void addBufferListener( + wp<Camera3StreamBufferListener> listener) = 0; + virtual void removeBufferListener( + const sp<Camera3StreamBufferListener>& listener) = 0; +}; + +} // namespace camera3 + +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp b/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp index e8a5ca6..0345d5b 100644 --- a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp +++ b/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp @@ -18,70 +18,652 @@ #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 "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 { namespace camera3 { +namespace { +struct TimestampFinder : public RingBufferConsumer::RingBufferComparator { + typedef RingBufferConsumer::BufferInfo BufferInfo; + + enum { + SELECT_I1 = -1, + SELECT_I2 = 1, + SELECT_NEITHER = 0, + }; + + TimestampFinder(nsecs_t timestamp) : mTimestamp(timestamp) {} + ~TimestampFinder() {} + + template <typename T> + static void swap(T& a, T& b) { + T tmp = a; + a = b; + b = tmp; + } + + /** + * Try to find the best candidate for a ZSL buffer. + * Match priority from best to worst: + * 1) Timestamps match. + * 2) Timestamp is closest to the needle (and lower). + * 3) Timestamp is closest to the needle (and higher). + * + */ + virtual int compare(const BufferInfo *i1, + const BufferInfo *i2) const { + // Try to select non-null object first. + if (i1 == NULL) { + return SELECT_I2; + } else if (i2 == NULL) { + return SELECT_I1; + } + + // Best result: timestamp is identical + if (i1->mTimestamp == mTimestamp) { + return SELECT_I1; + } else if (i2->mTimestamp == mTimestamp) { + return SELECT_I2; + } + + const BufferInfo* infoPtrs[2] = { + i1, + i2 + }; + int infoSelectors[2] = { + SELECT_I1, + SELECT_I2 + }; + + // Order i1,i2 so that always i1.timestamp < i2.timestamp + if (i1->mTimestamp > i2->mTimestamp) { + swap(infoPtrs[0], infoPtrs[1]); + swap(infoSelectors[0], infoSelectors[1]); + } + + // Second best: closest (lower) timestamp + if (infoPtrs[1]->mTimestamp < mTimestamp) { + return infoSelectors[1]; + } else if (infoPtrs[0]->mTimestamp < mTimestamp) { + return infoSelectors[0]; + } + + // Worst: closest (higher) timestamp + return infoSelectors[0]; + + /** + * The above cases should cover all the possibilities, + * and we get an 'empty' result only if the ring buffer + * was empty itself + */ + } + + const nsecs_t mTimestamp; +}; // struct TimestampFinder +} // namespace anonymous + 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) { + 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()) { +} + +Camera3ZslStream::~Camera3ZslStream() { + disconnectLocked(); } status_t Camera3ZslStream::getBufferLocked(camera3_stream_buffer *buffer) { - (void) buffer; - ALOGE("%s: Not implemented", __FUNCTION__); - return INVALID_OPERATION; + // 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; } status_t Camera3ZslStream::returnBufferLocked( const camera3_stream_buffer &buffer, nsecs_t timestamp) { - (void) buffer; - (void) timestamp; - ALOGE("%s: Not implemented", __FUNCTION__); - return INVALID_OPERATION; + // same as output stream code + 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<Camera3ZslStream> 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 Camera3ZslStream::hasOutstandingBuffersLocked() const { - ALOGE("%s: Not implemented", __FUNCTION__); + // 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) { - (void) timeout; - ALOGE("%s: Not implemented", __FUNCTION__); - return INVALID_OPERATION; + // 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() { - ALOGE("%s: Not implemented", __FUNCTION__); - return INVALID_OPERATION; + 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::getInputBuffer(camera3_stream_buffer *buffer, - nsecs_t timestamp) { - (void) buffer; - (void) timestamp; - ALOGE("%s: Not implemented", __FUNCTION__); - return INVALID_OPERATION; +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. + if (mState == STATE_IN_CONFIG || mState == STATE_IN_RECONFIG) { + ALOGE("%s: Stream %d: Buffer registration for input streams" + " not implemented (state %d)", + __FUNCTION__, mId, mState); + 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; + } + + ANativeWindowBuffer* anb; + int fenceFd; + + assert(mProducer != 0); + + sp<PinnedBufferItem> bufferItem; + { + List<sp<RingBufferConsumer::PinnedBufferItem> >::iterator it, end; + it = mInputBufferQueue.begin(); + end = mInputBufferQueue.end(); + + // Need to call enqueueInputBufferByTimestamp as a prerequisite + if (it == end) { + ALOGE("%s: Stream %d: No input buffer was queued", + __FUNCTION__, mId); + return INVALID_OPERATION; + } + bufferItem = *it; + mInputBufferQueue.erase(it); + } + + anb = bufferItem->getBufferItem().mGraphicBuffer->getNativeBuffer(); + assert(anb != NULL); + fenceFd = bufferItem->getBufferItem().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++; + + mBuffersInFlight.push_back(bufferItem); + + return OK; } -status_t Camera3ZslStream::returnInputBuffer(const camera3_stream_buffer &buffer) { - (void) buffer; - ALOGE("%s: Not implemented", __FUNCTION__); - return INVALID_OPERATION; +status_t Camera3ZslStream::returnInputBufferLocked( + const camera3_stream_buffer &buffer) { + ATRACE_CALL(); + + // 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<Camera3ZslStream> 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; + } + + bool bufferFound = false; + sp<PinnedBufferItem> bufferItem; + { + // Find the buffer we are returning + Vector<sp<PinnedBufferItem> >::iterator it, end; + for (it = mBuffersInFlight.begin(), end = mBuffersInFlight.end(); + it != end; + ++it) { + + const sp<PinnedBufferItem>& tmp = *it; + ANativeWindowBuffer *anb = + tmp->getBufferItem().mGraphicBuffer->getNativeBuffer(); + if (anb != NULL && &(anb->handle) == buffer.buffer) { + bufferFound = true; + bufferItem = tmp; + mBuffersInFlight.erase(it); + mDequeuedBufferCount--; + } + } + } + if (!bufferFound) { + ALOGE("%s: Stream %d: Can't return buffer that wasn't sent to HAL", + __FUNCTION__, mId); + return INVALID_OPERATION; + } + + int releaseFenceFd = buffer.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 incase of error + */ + releaseFenceFd = buffer.acquire_fence; + } + + /** + * Unconditionally return buffer to the buffer queue. + * - Fwk takes over the release_fence ownership + */ + sp<Fence> releaseFence = new Fence(releaseFenceFd); + bufferItem->getBufferItem().mFence = releaseFence; + bufferItem.clear(); // dropping last reference unpins buffer + + mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence); + + mBufferReturnedSignal.signal(); + + return OK; + } void Camera3ZslStream::dump(int fd, const Vector<String16> &args) const { - (void) fd; (void) args; - ALOGE("%s: Not implemented", __FUNCTION__); + + 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); + lines.appendFormat(" Input buffers pending: %d, in flight %d\n", + mInputBufferQueue.size(), mBuffersInFlight.size()); + write(fd, lines.string(), lines.size()); +} + +status_t Camera3ZslStream::enqueueInputBufferByTimestamp( + nsecs_t timestamp, + nsecs_t* actualTimestamp) { + + Mutex::Autolock l(mLock); + + TimestampFinder timestampFinder = TimestampFinder(timestamp); + + sp<RingBufferConsumer::PinnedBufferItem> pinnedBuffer = + mProducer->pinSelectedBuffer(timestampFinder, + /*waitForFence*/false); + + if (pinnedBuffer == 0) { + ALOGE("%s: No ZSL buffers were available yet", __FUNCTION__); + return NO_BUFFER_AVAILABLE; + } + + nsecs_t actual = pinnedBuffer->getBufferItem().mTimestamp; + + if (actual != timestamp) { + ALOGW("%s: ZSL buffer candidate search didn't find an exact match --" + " requested timestamp = %lld, actual timestamp = %lld", + __FUNCTION__, timestamp, actual); + } + + mInputBufferQueue.push_back(pinnedBuffer); + + if (actualTimestamp != NULL) { + *actualTimestamp = actual; + } + + return OK; +} + +status_t Camera3ZslStream::clearInputRingBuffer() { + Mutex::Autolock l(mLock); + + mInputBufferQueue.clear(); + + return mProducer->clear(); +} + +status_t Camera3ZslStream::setTransform(int /*transform*/) { + ALOGV("%s: Not implemented", __FUNCTION__); + return INVALID_OPERATION; } }; // namespace camera3 diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.h b/services/camera/libcameraservice/camera3/Camera3ZslStream.h index 39d5995..b863e7f 100644 --- a/services/camera/libcameraservice/camera3/Camera3ZslStream.h +++ b/services/camera/libcameraservice/camera3/Camera3ZslStream.h @@ -19,8 +19,10 @@ #include <utils/RefBase.h> #include <gui/Surface.h> +#include <gui/RingBufferConsumer.h> #include "Camera3Stream.h" +#include "Camera3OutputStreamInterface.h" namespace android { @@ -32,32 +34,62 @@ namespace camera3 { * most output buffers, and when directed, pushes a buffer back to the HAL for * processing. */ -class Camera3ZslStream: public Camera3Stream { +class Camera3ZslStream : + public Camera3Stream, + public Camera3OutputStreamInterface { 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); + ~Camera3ZslStream(); virtual status_t waitUntilIdle(nsecs_t timeout); virtual void dump(int fd, const Vector<String16> &args) const; + enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE }; + + /** + * Locate a buffer matching this timestamp in the RingBufferConsumer, + * and mark it to be queued at the next getInputBufferLocked invocation. + * + * Errors: Returns NO_BUFFER_AVAILABLE if we could not find a match. + * + */ + status_t enqueueInputBufferByTimestamp(nsecs_t timestamp, + nsecs_t* actualTimestamp); + /** - * Get an input buffer matching a specific timestamp. If no buffer matching - * the timestamp is available, NO_MEMORY is returned. + * Clears the buffers that can be used by enqueueInputBufferByTimestamp */ - status_t getInputBuffer(camera3_stream_buffer *buffer, nsecs_t timestamp); + status_t clearInputRingBuffer(); /** - * Return input buffer from HAL. The buffer is then marked as unfilled, and - * returned to the output-side stream for refilling. + * Camera3OutputStreamInterface implementation */ - status_t returnInputBuffer(const camera3_stream_buffer &buffer); + status_t setTransform(int transform); private: int mDepth; + // Input buffers pending to be queued into HAL + List<sp<RingBufferConsumer::PinnedBufferItem> > mInputBufferQueue; + sp<RingBufferConsumer> mProducer; + sp<ANativeWindow> mConsumer; + + // Input buffers in flight to HAL + Vector<sp<RingBufferConsumer::PinnedBufferItem> > 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<Fence> mCombinedFence; /** * Camera3Stream interface @@ -67,9 +99,18 @@ class Camera3ZslStream: public Camera3Stream { 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(); + }; // class Camera3ZslStream }; // namespace camera3 |