summaryrefslogtreecommitdiffstats
path: root/camera
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-02-21 14:45:03 -0800
committerIgor Murashkin <iam@google.com>2013-02-22 10:50:15 -0800
commit687f26c7bd7ece88cad8d51fc47be7ab1600af9d (patch)
treebe4bc4993455225e4407cb70831979cd84a040a7 /camera
parent1d74853933937f3e3f120a6efffb1f4cec7f8ba7 (diff)
downloadframeworks_av-687f26c7bd7ece88cad8d51fc47be7ab1600af9d.zip
frameworks_av-687f26c7bd7ece88cad8d51fc47be7ab1600af9d.tar.gz
frameworks_av-687f26c7bd7ece88cad8d51fc47be7ab1600af9d.tar.bz2
ProCamera: add waitForFrameBuffer/waitForFrameResult blocking calls
Change-Id: I851d41aeecaa15245d5b9d622132e8706d6e292c
Diffstat (limited to 'camera')
-rw-r--r--camera/ProCamera.cpp110
-rw-r--r--camera/tests/ProCameraTests.cpp172
2 files changed, 260 insertions, 22 deletions
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index c95c4e0..d4a9556 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -86,12 +86,13 @@ sp<ProCamera> ProCamera::connect(int cameraId)
void ProCamera::disconnect()
{
- ALOGV("disconnect");
+ ALOGV("%s: disconnect", __FUNCTION__);
if (mCamera != 0) {
mCamera->disconnect();
mCamera->asBinder()->unlinkToDeath(this);
mCamera = 0;
}
+ ALOGV("%s: disconnect (done)", __FUNCTION__);
}
ProCamera::ProCamera()
@@ -208,6 +209,19 @@ void ProCamera::onResultReceived(int32_t frameId, camera_metadata* result) {
Mutex::Autolock _l(mLock);
listener = mListener;
}
+
+ CameraMetadata tmp(result);
+
+ // Unblock waitForFrame(id) callers
+ {
+ Mutex::Autolock al(mWaitMutex);
+ mMetadataReady = true;
+ mLatestMetadata = tmp;
+ mWaitCondition.broadcast();
+ }
+
+ result = tmp.release();
+
if (listener != NULL) {
listener->onResultReceived(frameId, result);
} else {
@@ -323,11 +337,14 @@ status_t ProCamera::createStream(int width, int height, int format,
status_t ProCamera::createStreamCpu(int width, int height, int format,
int heapCount,
/*out*/
+ sp<CpuConsumer>* cpuConsumer,
int* streamId)
{
ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
format);
+ *cpuConsumer = NULL;
+
sp <IProCameraUser> c = mCamera;
if (c == 0) return NO_INIT;
@@ -357,6 +374,8 @@ status_t ProCamera::createStreamCpu(int width, int height, int format,
cc->setFrameAvailableListener(frameAvailableListener);
+ *cpuConsumer = cc;
+
return s;
}
@@ -399,26 +418,91 @@ void ProCamera::onFrameAvailable(int streamId) {
ALOGV("%s: streamId = %d", __FUNCTION__, streamId);
sp<ProCameraListener> listener = mListener;
- if (listener.get() != NULL) {
- StreamInfo& stream = getStreamInfo(streamId);
+ StreamInfo& stream = getStreamInfo(streamId);
- CpuConsumer::LockedBuffer buf;
+ CpuConsumer::LockedBuffer buf;
- status_t stat = stream.cpuConsumer->lockNextBuffer(&buf);
- if (stat != OK) {
- ALOGE("%s: Failed to lock buffer, error code = %d", __FUNCTION__,
- stat);
+ if (listener.get() != NULL) {
+ if (listener->useOnFrameAvailable()) {
+ listener->onFrameAvailable(streamId, stream.cpuConsumer);
return;
}
+ }
+
+ // Unblock waitForFrame(id) callers
+ {
+ Mutex::Autolock al(mWaitMutex);
+ getStreamInfo(streamId).frameReady = true;
+ mWaitCondition.broadcast();
+ }
+}
+
+status_t ProCamera::waitForFrameBuffer(int streamId) {
+ status_t stat = BAD_VALUE;
+ Mutex::Autolock al(mWaitMutex);
- listener->onBufferReceived(streamId, buf);
- stat = stream.cpuConsumer->unlockBuffer(buf);
+ StreamInfo& si = getStreamInfo(streamId);
- if (stat != OK) {
- ALOGE("%s: Failed to unlock buffer, error code = %d", __FUNCTION__,
- stat);
+ if (si.frameReady) {
+ si.frameReady = false;
+ return OK;
+ } else {
+ while (true) {
+ stat = mWaitCondition.waitRelative(mWaitMutex,
+ mWaitTimeout);
+ if (stat != OK) {
+ ALOGE("%s: Error while waiting for frame buffer: %d",
+ __FUNCTION__, stat);
+ return stat;
+ }
+
+ if (si.frameReady) {
+ si.frameReady = false;
+ return OK;
+ }
+ // else it was some other stream that got unblocked
}
}
+
+ return stat;
+}
+
+status_t ProCamera::waitForFrameMetadata() {
+ status_t stat = BAD_VALUE;
+ Mutex::Autolock al(mWaitMutex);
+
+ if (mMetadataReady) {
+ return OK;
+ } else {
+ while (true) {
+ stat = mWaitCondition.waitRelative(mWaitMutex,
+ mWaitTimeout);
+
+ if (stat != OK) {
+ ALOGE("%s: Error while waiting for metadata: %d",
+ __FUNCTION__, stat);
+ return stat;
+ }
+
+ if (mMetadataReady) {
+ mMetadataReady = false;
+ return OK;
+ }
+ // else it was some other stream or metadata
+ }
+ }
+
+ return stat;
+}
+
+CameraMetadata ProCamera::consumeFrameMetadata() {
+ Mutex::Autolock al(mWaitMutex);
+
+ // Destructive: Subsequent calls return empty metadatas
+ CameraMetadata tmp = mLatestMetadata;
+ mLatestMetadata.release();
+
+ return tmp;
}
ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) {
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index f1dd48c..33c9179 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -207,7 +207,8 @@ protected:
const CpuConsumer::LockedBuffer& buf) {
dout << "Buffer received on streamId = " << streamId <<
- ", dataPtr = " << (void*)buf.data << std::endl;
+ ", dataPtr = " << (void*)buf.data <<
+ ", timestamp = " << buf.timestamp << std::endl;
QueueEvent(BUFFER_RECEIVED);
@@ -376,7 +377,7 @@ protected:
return false;
}
- for (int i = 0; i < count; ++i) {
+ for (size_t i = 0; i < count; ++i) {
if (array[i] == needle) {
return true;
}
@@ -410,10 +411,10 @@ protected:
* Creating a streaming request for these output streams from a template,
* and submit it
*/
- void createSubmitRequestForStreams(uint8_t* streamIds, size_t count) {
+ void createSubmitRequestForStreams(uint8_t* streamIds, size_t count, int requestCount=-1) {
ASSERT_NE((void*)NULL, streamIds);
- ASSERT_LT(0, count);
+ ASSERT_LT(0u, count);
camera_metadata_t *requestTmp = NULL;
EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
@@ -427,7 +428,15 @@ protected:
request.update(tag, streamIds, count);
requestTmp = request.release();
- EXPECT_OK(mCamera->submitRequest(requestTmp, /*streaming*/true));
+
+ if (requestCount < 0) {
+ EXPECT_OK(mCamera->submitRequest(requestTmp, /*streaming*/true));
+ } else {
+ for (int i = 0; i < requestCount; ++i) {
+ EXPECT_OK(mCamera->submitRequest(requestTmp,
+ /*streaming*/false));
+ }
+ }
request.acquire(requestTmp);
}
@@ -628,8 +637,9 @@ TEST_F(ProCameraTest, CpuConsumerSingle) {
mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED));
int streamId = -1;
+ sp<CpuConsumer> consumer;
EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240,
- TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &streamId));
+ TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
EXPECT_NE(-1, streamId);
EXPECT_OK(mCamera->exclusiveTryLock());
@@ -693,13 +703,14 @@ TEST_F(ProCameraTest, CpuConsumerDual) {
mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED));
int streamId = -1;
+ sp<CpuConsumer> consumer;
EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
- TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &streamId));
+ TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
EXPECT_NE(-1, streamId);
int depthStreamId = -1;
EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240,
- TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &depthStreamId));
+ TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &consumer, &depthStreamId));
EXPECT_NE(-1, depthStreamId);
EXPECT_OK(mCamera->exclusiveTryLock());
@@ -772,8 +783,9 @@ TEST_F(ProCameraTest, ResultReceiver) {
// need to filter out events at read time
int streamId = -1;
+ sp<CpuConsumer> consumer;
EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
- TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &streamId));
+ TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
EXPECT_NE(-1, streamId);
EXPECT_OK(mCamera->exclusiveTryLock());
@@ -828,6 +840,148 @@ TEST_F(ProCameraTest, ResultReceiver) {
EXPECT_OK(mCamera->exclusiveUnlock());
}
+TEST_F(ProCameraTest, WaitForResult) {
+ if (HasFatalFailure()) {
+ return;
+ }
+
+ int streamId = -1;
+ sp<CpuConsumer> consumer;
+ EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
+ TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
+ EXPECT_NE(-1, streamId);
+
+ EXPECT_OK(mCamera->exclusiveTryLock());
+
+ uint8_t streams[] = { streamId };
+ ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1));
+
+ // Consume a couple of results
+ for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
+ EXPECT_OK(mCamera->waitForFrameMetadata());
+ CameraMetadata meta = mCamera->consumeFrameMetadata();
+ EXPECT_FALSE(meta.isEmpty());
+ }
+
+ // Done: clean up
+ consumer->abandon(); // since we didn't consume any of the buffers
+ EXPECT_OK(mCamera->deleteStream(streamId));
+ EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
+TEST_F(ProCameraTest, WaitForSingleStreamBuffer) {
+ if (HasFatalFailure()) {
+ return;
+ }
+
+ int streamId = -1;
+ sp<CpuConsumer> consumer;
+ EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
+ TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
+ EXPECT_NE(-1, streamId);
+
+ EXPECT_OK(mCamera->exclusiveTryLock());
+
+ uint8_t streams[] = { streamId };
+ ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1,
+ /*requests*/TEST_CPU_FRAME_COUNT));
+
+ // Consume a couple of results
+ for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
+ EXPECT_OK(mCamera->waitForFrameBuffer(streamId));
+
+ CpuConsumer::LockedBuffer buf;
+ EXPECT_OK(consumer->lockNextBuffer(&buf));
+
+ dout << "Buffer synchronously received on streamId = " << streamId <<
+ ", dataPtr = " << (void*)buf.data <<
+ ", timestamp = " << buf.timestamp << std::endl;
+
+ EXPECT_OK(consumer->unlockBuffer(buf));
+ }
+
+ // Done: clean up
+ EXPECT_OK(mCamera->deleteStream(streamId));
+ EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
+TEST_F(ProCameraTest, WaitForDualStreamBuffer) {
+ if (HasFatalFailure()) {
+ return;
+ }
+
+ const int REQUEST_COUNT = TEST_CPU_FRAME_COUNT * 10;
+
+ // 15 fps
+ int streamId = -1;
+ sp<CpuConsumer> consumer;
+ EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960,
+ TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId));
+ EXPECT_NE(-1, streamId);
+
+ // 30 fps
+ int depthStreamId = -1;
+ sp<CpuConsumer> depthConsumer;
+ EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240,
+ TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &depthConsumer, &depthStreamId));
+ EXPECT_NE(-1, depthStreamId);
+
+ EXPECT_OK(mCamera->exclusiveTryLock());
+
+ uint8_t streams[] = { streamId, depthStreamId };
+ ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/2,
+ /*requests*/REQUEST_COUNT));
+
+ // Consume two frames simultaneously. Unsynchronized by timestamps.
+ for (int i = 0; i < REQUEST_COUNT; ++i) {
+
+ // Get the metadata
+ EXPECT_OK(mCamera->waitForFrameMetadata());
+ CameraMetadata meta = mCamera->consumeFrameMetadata();
+ EXPECT_FALSE(meta.isEmpty());
+
+ // Get the buffers
+
+ EXPECT_OK(mCamera->waitForFrameBuffer(depthStreamId));
+
+ /**
+ * Guaranteed to be able to consume the depth frame,
+ * since we waited on it.
+ */
+ CpuConsumer::LockedBuffer depthBuffer;
+ EXPECT_OK(depthConsumer->lockNextBuffer(&depthBuffer));
+
+ dout << "Depth Buffer synchronously received on streamId = " <<
+ streamId <<
+ ", dataPtr = " << (void*)depthBuffer.data <<
+ ", timestamp = " << depthBuffer.timestamp << std::endl;
+
+ EXPECT_OK(depthConsumer->unlockBuffer(depthBuffer));
+
+
+ /** Consume Greyscale frames if there are any.
+ * There may not be since it runs at half FPS */
+ CpuConsumer::LockedBuffer greyBuffer;
+ while (consumer->lockNextBuffer(&greyBuffer) == OK) {
+
+ dout << "GRAY Buffer synchronously received on streamId = " <<
+ streamId <<
+ ", dataPtr = " << (void*)greyBuffer.data <<
+ ", timestamp = " << greyBuffer.timestamp << std::endl;
+
+ EXPECT_OK(consumer->unlockBuffer(greyBuffer));
+ }
+ }
+
+ // Done: clean up
+ EXPECT_OK(mCamera->deleteStream(streamId));
+ EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
+
+
+
+
}
}
}