Camera: Rework ZSL path when using API1 with HAL3
Currently this path relies entirely on the deprecated bi-directional
streams. This needs to be re-worked and the functionality should
only use input&ouput streams. In this case the dedicated
'Camera3ZslStream' module becomes mostly obsolete. Some of the logic
for buffer comparison will still be needed and can be moved to ZSL
processor entirely.
The processor module will now use two streams, one input stream and
one ZSL output stream, which will produce the queue data. Both of
them will be configured to use the supported sensor array size and
private format. Scaling from the sensor resolution to the final user
requested size will happen during the re-process pass once image
capture gets triggered.
BUG: 34131351
Test: Manual via TestingCamera, 'CameraTest' API1 test cases
Change-Id: I7c87b7e7f89815e01a7cb5ce39d9c561c58562df
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 9328d65..0401796 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -46,7 +46,6 @@
device3/Camera3IOStreamBase.cpp \
device3/Camera3InputStream.cpp \
device3/Camera3OutputStream.cpp \
- device3/Camera3ZslStream.cpp \
device3/Camera3DummyStream.cpp \
device3/Camera3SharedOutputStream.cpp \
device3/StatusTracker.cpp \
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 6efe4e3..83c84af 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -911,14 +911,26 @@
CameraParameters::FALSE);
}
+ bool isZslReprocessPresent = false;
+ camera_metadata_ro_entry_t availableCapabilities =
+ staticInfo(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ if (0 < availableCapabilities.count) {
+ const uint8_t *caps = availableCapabilities.data.u8;
+ for (size_t i = 0; i < availableCapabilities.count; i++) {
+ if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING ==
+ caps[i]) {
+ isZslReprocessPresent = true;
+ break;
+ }
+ }
+ }
+
if (slowJpegMode || property_get_bool("camera.disable_zsl_mode", false)) {
ALOGI("Camera %d: Disabling ZSL mode", cameraId);
allowZslMode = false;
} else {
- allowZslMode = true;
+ allowZslMode = isZslReprocessPresent;
}
- // TODO (b/34131351): turn ZSL back on after fixing the issue
- allowZslMode = false;
ALOGI("%s: allowZslMode: %d slowJpegMode %d", __FUNCTION__, allowZslMode, slowJpegMode);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index b127472..e03ec66 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -37,9 +37,91 @@
#include "api1/client2/ZslProcessor.h"
#include "device3/Camera3Device.h"
+typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
+
namespace android {
namespace camera2 {
+namespace {
+struct TimestampFinder : public RingBufferConsumer::RingBufferComparator {
+ typedef RingBufferConsumer::BufferInfo BufferInfo;
+
+ enum {
+ SELECT_I1 = -1,
+ SELECT_I2 = 1,
+ SELECT_NEITHER = 0,
+ };
+
+ explicit 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
+
ZslProcessor::ZslProcessor(
sp<Camera2Client> client,
wp<CaptureSequencer> sequencer):
@@ -50,8 +132,13 @@
mSequencer(sequencer),
mId(client->getCameraId()),
mZslStreamId(NO_STREAM),
+ mInputStreamId(NO_STREAM),
mFrameListHead(0),
- mHasFocuser(false) {
+ mHasFocuser(false),
+ mInputBuffer(nullptr),
+ mProducer(nullptr),
+ mInputProducer(nullptr),
+ mInputProducerSlot(-1) {
// Initialize buffer queue and frame list based on pipeline max depth.
size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
if (client != 0) {
@@ -83,7 +170,6 @@
mFrameListDepth = pipelineMaxDepth;
mBufferQueueDepth = mFrameListDepth + 1;
-
mZslQueue.insertAt(0, mBufferQueueDepth);
mFrameList.insertAt(0, mFrameListDepth);
sp<CaptureSequencer> captureSequencer = mSequencer.promote();
@@ -144,7 +230,7 @@
return INVALID_OPERATION;
}
- if (mZslStreamId != NO_STREAM) {
+ if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
// Check if stream parameters have to change
uint32_t currentWidth, currentHeight;
res = device->getStreamInfo(mZslStreamId,
@@ -157,21 +243,57 @@
}
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 == -EBUSY) {
- ALOGV("%s: Camera %d: Device is busy, call updateStream again "
- " after it becomes idle", __FUNCTION__, mId);
- return res;
- } else 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;
+ if (mZslStreamId != NO_STREAM) {
+ ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+ "dimensions changed",
+ __FUNCTION__, client->getCameraId(), mZslStreamId);
+ res = device->deleteStream(mZslStreamId);
+ if (res == -EBUSY) {
+ ALOGV("%s: Camera %d: Device is busy, call updateStream again "
+ " after it becomes idle", __FUNCTION__, mId);
+ return res;
+ } else 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;
}
- mZslStreamId = NO_STREAM;
+
+ if (mInputStreamId != NO_STREAM) {
+ ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+ "dimensions changed",
+ __FUNCTION__, client->getCameraId(), mInputStreamId);
+ res = device->deleteStream(mInputStreamId);
+ if (res == -EBUSY) {
+ ALOGV("%s: Camera %d: Device is busy, call updateStream again "
+ " after it becomes idle", __FUNCTION__, mId);
+ return res;
+ } else 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;
+ }
+ mInputStreamId = NO_STREAM;
+ }
+ if (nullptr != mInputProducer.get()) {
+ mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
+ mInputProducer.clear();
+ }
+ }
+ }
+
+ if (mInputStreamId == NO_STREAM) {
+ res = device->createInputStream(params.fastInfo.arrayWidth,
+ params.fastInfo.arrayHeight, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ &mInputStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't create input stream: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
}
}
@@ -179,21 +301,23 @@
// 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,
- mBufferQueueDepth,
- &mZslStreamId,
- &mZslStream);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL,
+ mBufferQueueDepth);
+ mProducer->setName(String8("Camera2-ZslRingBufferConsumer"));
+ sp<Surface> outSurface = new Surface(producer);
+
+ res = device->createStream(outSurface, params.fastInfo.arrayWidth,
+ params.fastInfo.arrayHeight, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+ HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create ZSL stream: "
"%s (%d)", __FUNCTION__, client->getCameraId(),
strerror(-res), res);
return res;
}
-
- // Only add the camera3 buffer listener when the stream is created.
- mZslStream->addBufferListener(this);
}
client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
@@ -207,23 +331,27 @@
status_t ZslProcessor::deleteStream() {
ATRACE_CALL();
status_t res;
+ sp<Camera3Device> device = nullptr;
+ sp<Camera2Client> client = nullptr;
Mutex::Autolock l(mInputMutex);
- if (mZslStreamId != NO_STREAM) {
- sp<Camera2Client> client = mClient.promote();
+ if ((mZslStreamId != NO_STREAM) || (mInputStreamId != NO_STREAM)) {
+ client = mClient.promote();
if (client == 0) {
ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- sp<Camera3Device> device =
+ device =
reinterpret_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) {
res = device->deleteStream(mZslStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
@@ -234,6 +362,23 @@
mZslStreamId = NO_STREAM;
}
+ if (mInputStreamId != NO_STREAM) {
+ res = device->deleteStream(mInputStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Cannot delete input stream %d: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
+ mInputStreamId, strerror(-res), res);
+ return res;
+ }
+
+ mInputStreamId = NO_STREAM;
+ }
+
+ if (nullptr != mInputProducer.get()) {
+ mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
+ mInputProducer.clear();
+ }
+
return OK;
}
@@ -282,6 +427,45 @@
return OK;
}
+void ZslProcessor::notifyInputReleased() {
+ Mutex::Autolock l(mInputMutex);
+
+ assert(nullptr != mInputBuffer.get());
+ assert(nullptr != mInputProducer.get());
+
+ sp<GraphicBuffer> gb;
+ sp<Fence> fence;
+ auto rc = mInputProducer->detachNextBuffer(&gb, &fence);
+ if (NO_ERROR != rc) {
+ ALOGE("%s: Failed to detach buffer from input producer: %d",
+ __FUNCTION__, rc);
+ return;
+ }
+
+ BufferItem &item = mInputBuffer->getBufferItem();
+ sp<GraphicBuffer> inputBuffer = item.mGraphicBuffer;
+ if (gb->handle != inputBuffer->handle) {
+ ALOGE("%s: Input mismatch, expected buffer %p received %p", __FUNCTION__,
+ inputBuffer->handle, gb->handle);
+ return;
+ }
+
+ mInputBuffer.clear();
+ ALOGV("%s: Memory optimization, clearing ZSL queue",
+ __FUNCTION__);
+ clearZslResultQueueLocked();
+
+ // Required so we accept more ZSL requests
+ mState = RUNNING;
+}
+
+void ZslProcessor::InputProducerListener::onBufferReleased() {
+ sp<ZslProcessor> parent = mParent.promote();
+ if (nullptr != parent.get()) {
+ parent->notifyInputReleased();
+ }
+}
+
status_t ZslProcessor::pushToReprocess(int32_t requestId) {
ALOGV("%s: Send in reprocess request with id %d",
__FUNCTION__, requestId);
@@ -302,15 +486,38 @@
nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
if (candidateTimestamp == -1) {
- ALOGE("%s: Could not find good candidate for ZSL reprocessing",
+ ALOGV("%s: Could not find good candidate for ZSL reprocessing",
__FUNCTION__);
return NOT_ENOUGH_DATA;
+ } else {
+ ALOGV("%s: Found good ZSL candidate idx: %u",
+ __FUNCTION__, (unsigned int) metadataIdx);
}
- res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
- /*actualTimestamp*/NULL);
+ if (nullptr == mInputProducer.get()) {
+ res = client->getCameraDevice()->getInputBufferProducer(
+ &mInputProducer);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to retrieve input producer: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
- if (res == mZslStream->NO_BUFFER_AVAILABLE) {
+ IGraphicBufferProducer::QueueBufferOutput output;
+ res = mInputProducer->connect(new InputProducerListener(this),
+ NATIVE_WINDOW_API_CPU, false, &output);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to connect to input producer: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
+ strerror(-res), res);
+ return res;
+ }
+ }
+
+ res = enqueueInputBufferByTimestamp(candidateTimestamp,
+ /*actualTimestamp*/NULL);
+ if (res == NO_BUFFER_AVAILABLE) {
ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
return NOT_ENOUGH_DATA;
} else if (res != OK) {
@@ -348,7 +555,7 @@
}
int32_t inputStreams[1] =
- { mZslStreamId };
+ { mInputStreamId };
res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
inputStreams, 1);
if (res != OK) {
@@ -428,6 +635,70 @@
return OK;
}
+status_t ZslProcessor::enqueueInputBufferByTimestamp(
+ nsecs_t timestamp,
+ nsecs_t* actualTimestamp) {
+
+ TimestampFinder timestampFinder = TimestampFinder(timestamp);
+
+ mInputBuffer = mProducer->pinSelectedBuffer(timestampFinder,
+ /*waitForFence*/false);
+
+ if (nullptr == mInputBuffer.get()) {
+ ALOGE("%s: No ZSL buffers were available yet", __FUNCTION__);
+ return NO_BUFFER_AVAILABLE;
+ }
+
+ nsecs_t actual = mInputBuffer->getBufferItem().mTimestamp;
+
+ if (actual != timestamp) {
+ // TODO: This is problematic, the metadata queue timestamp should
+ // usually have a corresponding ZSL buffer with the same timestamp.
+ // If this is not the case, then it is possible that we will use
+ // a ZSL buffer from a different request, which can result in
+ // side effects during the reprocess pass.
+ ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
+ " requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
+ __FUNCTION__, timestamp, actual);
+ }
+
+ if (nullptr != actualTimestamp) {
+ *actualTimestamp = actual;
+ }
+
+ BufferItem &item = mInputBuffer->getBufferItem();
+ auto rc = mInputProducer->attachBuffer(&mInputProducerSlot,
+ item.mGraphicBuffer);
+ if (OK != rc) {
+ ALOGE("%s: Failed to attach input ZSL buffer to producer: %d",
+ __FUNCTION__, rc);
+ return rc;
+ }
+
+ IGraphicBufferProducer::QueueBufferOutput output;
+ IGraphicBufferProducer::QueueBufferInput input(item.mTimestamp,
+ item.mIsAutoTimestamp, item.mDataSpace, item.mCrop,
+ item.mScalingMode, item.mTransform, item.mFence);
+ rc = mInputProducer->queueBuffer(mInputProducerSlot, input, &output);
+ if (OK != rc) {
+ ALOGE("%s: Failed to queue ZSL buffer to producer: %d",
+ __FUNCTION__, rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+status_t ZslProcessor::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
+
+ if (nullptr != latestTimestamp) {
+ *latestTimestamp = mProducer->getLatestTimestamp();
+ }
+ mInputBuffer.clear();
+
+ return mProducer->clear();
+}
+
status_t ZslProcessor::clearZslQueue() {
Mutex::Autolock l(mInputMutex);
// If in middle of capture, can't clear out queue
@@ -437,10 +708,10 @@
}
status_t ZslProcessor::clearZslQueueLocked() {
- if (mZslStream != 0) {
+ if (NO_STREAM != mZslStreamId) {
// clear result metadata list first.
clearZslResultQueueLocked();
- return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
+ return clearInputRingBufferLocked(&mLatestClearedBufferTimestamp);
}
return OK;
}
@@ -630,46 +901,5 @@
return minTimestamp;
}
-void ZslProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
- // Intentionally left empty
- // Although theoretically we could use this to get better dump info
-}
-
-void ZslProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
-
- // ignore output buffers
- if (bufferInfo.mOutput) {
- return;
- }
-
- // Lock mutex only once we know this is an input buffer returned to avoid
- // potential deadlock
- Mutex::Autolock l(mInputMutex);
- // 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 result
- // metadata queue on a completed capture ensures we'll only use new timestamp.
- // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
- // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
- // to hold the same lock.
- // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
- // it is safe not to do so, as back to back ZSL capture requires stop and start
- // preview, which will flush ZSL queue automatically.
- ALOGV("%s: Memory optimization, clearing ZSL queue",
- __FUNCTION__);
- clearZslResultQueueLocked();
-
- // Required so we accept more ZSL requests
- mState = RUNNING;
-}
-
}; // namespace camera2
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 86c06c6..6113d58 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -24,10 +24,11 @@
#include <utils/Condition.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
+#include <gui/RingBufferConsumer.h>
+#include <gui/IProducerListener.h>
#include <camera/CameraMetadata.h>
#include "api1/client2/FrameProcessor.h"
-#include "device3/Camera3ZslStream.h"
namespace android {
@@ -42,7 +43,6 @@
* ZSL queue processing for HALv3.0 or newer
*/
class ZslProcessor :
- public camera3::Camera3StreamBufferListener,
virtual public Thread,
virtual public FrameProcessor::FilteredListener {
public:
@@ -81,19 +81,18 @@
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:
+
+ class InputProducerListener : public BnProducerListener {
+ public:
+ InputProducerListener(wp<ZslProcessor> parent) : mParent(parent) {}
+ virtual void onBufferReleased();
+ virtual bool needsReleaseNotify() { return true; }
+
+ private:
+ wp<ZslProcessor> mParent;
+ };
+
static const nsecs_t kWaitDuration = 10000000; // 10 ms
nsecs_t mLatestClearedBufferTimestamp;
@@ -102,6 +101,8 @@
LOCKED
} mState;
+ enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+
wp<Camera2Client> mClient;
wp<CaptureSequencer> mSequencer;
@@ -114,7 +115,7 @@
};
int mZslStreamId;
- sp<camera3::Camera3ZslStream> mZslStream;
+ int mInputStreamId;
struct ZslPair {
BufferItem buffer;
@@ -135,6 +136,12 @@
bool mHasFocuser;
+ // Input buffer queued into HAL
+ sp<RingBufferConsumer::PinnedBufferItem> mInputBuffer;
+ sp<RingBufferConsumer> mProducer;
+ sp<IGraphicBufferProducer> mInputProducer;
+ int mInputProducerSlot;
+
virtual bool threadLoop();
status_t clearZslQueueLocked();
@@ -145,6 +152,11 @@
nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
+ status_t enqueueInputBufferByTimestamp( nsecs_t timestamp,
+ nsecs_t* actualTimestamp);
+ status_t clearInputRingBufferLocked(nsecs_t* latestTimestamp);
+ void notifyInputReleased();
+
bool isFixedFocusMode(uint8_t afMode) const;
// Update the post-processing metadata with the default still capture request template
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 977e7a8..9873de1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -51,7 +51,6 @@
#include "device3/Camera3Device.h"
#include "device3/Camera3OutputStream.h"
#include "device3/Camera3InputStream.h"
-#include "device3/Camera3ZslStream.h"
#include "device3/Camera3DummyStream.h"
#include "device3/Camera3SharedOutputStream.h"
#include "CameraService.h"
@@ -1209,86 +1208,6 @@
return OK;
}
-
-status_t Camera3Device::createZslStream(
- uint32_t width, uint32_t height,
- int depth,
- /*out*/
- int *id,
- sp<Camera3ZslStream>* zslStream) {
- ATRACE_CALL();
- Mutex::Autolock il(mInterfaceLock);
- Mutex::Autolock l(mLock);
- ALOGV("Camera %s: Creating ZSL stream %d: %d x %d, depth %d",
- mId.string(), mNextStreamId, width, height, depth);
-
- 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_UNCONFIGURED:
- case STATUS_CONFIGURED:
- // OK
- break;
- case STATUS_ACTIVE:
- ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
- res = internalPauseAndWaitLocked();
- if (res != OK) {
- SET_ERR_L("Can't pause captures to reconfigure streams!");
- return res;
- }
- wasActive = true;
- break;
- default:
- SET_ERR_L("Unexpected status: %d", mStatus);
- return INVALID_OPERATION;
- }
- assert(mStatus != STATUS_ACTIVE);
-
- 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);
- newStream->setStatusTracker(mStatusTracker);
-
- 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;
-
- mNeedConfig = true;
-
- *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;
- }
- internalResumeLocked();
- }
-
- ALOGV("Camera %s: Created ZSL stream", mId.string());
- return OK;
-}
-
status_t Camera3Device::createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format,
android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 91d682e..e19b62e 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -125,12 +125,6 @@
status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id) override;
- status_t createZslStream(
- uint32_t width, uint32_t height,
- int depth,
- /*out*/
- int *id,
- sp<camera3::Camera3ZslStream>* zslStream);
status_t createReprocessStreamFromStream(int outputId, int *id) override;
status_t getStreamInfo(int id,
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
deleted file mode 100644
index ea138b7..0000000
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Camera3-ZslStream"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include "Camera3ZslStream.h"
-
-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,
- };
-
- explicit 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 bufferCount) :
- Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
- width, height,
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
- HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0) {
-
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
- mProducer->setName(String8("Camera2-ZslRingBufferConsumer"));
- mConsumer = new Surface(producer);
-}
-
-Camera3ZslStream::~Camera3ZslStream() {
-}
-
-status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) {
- ATRACE_CALL();
-
- status_t res;
-
- // 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;
- }
-
- if ((res = getBufferPreconditionCheckLocked()) != OK) {
- return res;
- }
-
- 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
- */
- handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
- /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
-
- mBuffersInFlight.push_back(bufferItem);
-
- return OK;
-}
-
-status_t Camera3ZslStream::returnBufferCheckedLocked(
- const camera3_stream_buffer &buffer,
- nsecs_t timestamp,
- bool output,
- /*out*/
- sp<Fence> *releaseFenceOut) {
-
- if (output) {
- // Output stream path
- return Camera3OutputStream::returnBufferCheckedLocked(buffer,
- timestamp,
- output,
- releaseFenceOut);
- }
-
- /**
- * Input stream path
- */
- 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);
- break;
- }
- }
- }
- 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
-
- *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<String16> &args) const {
- (void) args;
-
- String8 lines;
- lines.appendFormat(" Stream[%d]: ZSL\n", mId);
- write(fd, lines.string(), lines.size());
-
- Camera3IOStreamBase::dump(fd, args);
-
- lines = String8();
- lines.appendFormat(" Input buffers pending: %zu, in flight %zu\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) {
- // TODO: this is problematic, we'll end up with using wrong result for this pinned buffer.
- ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
- " requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
- __FUNCTION__, timestamp, actual);
- }
-
- mInputBufferQueue.push_back(pinnedBuffer);
-
- if (actualTimestamp != NULL) {
- *actualTimestamp = actual;
- }
-
- return OK;
-}
-
-status_t Camera3ZslStream::clearInputRingBuffer(nsecs_t* latestTimestamp) {
- Mutex::Autolock l(mLock);
-
- return clearInputRingBufferLocked(latestTimestamp);
-}
-
-status_t Camera3ZslStream::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
-
- if (latestTimestamp) {
- *latestTimestamp = mProducer->getLatestTimestamp();
- }
- mInputBufferQueue.clear();
-
- return mProducer->clear();
-}
-
-status_t Camera3ZslStream::disconnectLocked() {
- clearInputRingBufferLocked(NULL);
-
- return Camera3OutputStream::disconnectLocked();
-}
-
-status_t Camera3ZslStream::setTransform(int /*transform*/) {
- ALOGV("%s: Not implemented", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-}; // namespace camera3
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h
deleted file mode 100644
index 12369cf..0000000
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA3_ZSL_STREAM_H
-#define ANDROID_SERVERS_CAMERA3_ZSL_STREAM_H
-
-#include <utils/RefBase.h>
-#include <gui/Surface.h>
-#include <gui/RingBufferConsumer.h>
-
-#include "Camera3OutputStream.h"
-
-namespace android {
-
-namespace camera3 {
-
-/**
- * A class for managing a single opaque ZSL stream to/from the camera device.
- * This acts as a bidirectional stream at the HAL layer, caching and discarding
- * most output buffers, and when directed, pushes a buffer back to the HAL for
- * processing.
- */
-class Camera3ZslStream :
- public Camera3OutputStream {
- public:
- /**
- * Set up a ZSL stream of a given resolution. bufferCount 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 bufferCount);
- ~Camera3ZslStream();
-
- 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);
-
- /**
- * Clears the buffers that can be used by enqueueInputBufferByTimestamp
- * latestTimestamp will be filled with the largest timestamp of buffers
- * being cleared, 0 if there is no buffer being clear.
- */
- status_t clearInputRingBuffer(nsecs_t* latestTimestamp);
-
- protected:
-
- /**
- * Camera3OutputStreamInterface implementation
- */
- status_t setTransform(int transform);
-
- private:
-
- // Input buffers pending to be queued into HAL
- List<sp<RingBufferConsumer::PinnedBufferItem> > mInputBufferQueue;
- sp<RingBufferConsumer> mProducer;
-
- // Input buffers in flight to HAL
- Vector<sp<RingBufferConsumer::PinnedBufferItem> > mBuffersInFlight;
-
- /**
- * Camera3Stream interface
- */
-
- // 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);
-
- // 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<Fence> *releaseFenceOut);
-
- // Disconnet the Camera3ZslStream specific bufferQueues.
- virtual status_t disconnectLocked();
-
- status_t clearInputRingBufferLocked(nsecs_t* latestTimestamp);
-
-}; // class Camera3ZslStream
-
-}; // namespace camera3
-
-}; // namespace android
-
-#endif