summaryrefslogtreecommitdiffstats
path: root/camera
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-02-20 13:36:17 -0800
committerIgor Murashkin <iam@google.com>2013-02-22 10:50:15 -0800
commit94a90a43b2a9f83b3a4a4a59247b74ad50336860 (patch)
tree240c0a147b8856320274dc99d8bbad2937ea7905 /camera
parent687f26c7bd7ece88cad8d51fc47be7ab1600af9d (diff)
downloadframeworks_av-94a90a43b2a9f83b3a4a4a59247b74ad50336860.zip
frameworks_av-94a90a43b2a9f83b3a4a4a59247b74ad50336860.tar.gz
frameworks_av-94a90a43b2a9f83b3a4a4a59247b74ad50336860.tar.bz2
ProCamera: Fix waitForFrameBuffer not handling multiple outstanding frames
If the CpuConsumer triggered multiple onFrameAvailable callbacks in between a single waitForFrameBuffer call, the old code would only handle 1 callback. This meant on two subsequent waitForFrameBuffer calls the second would always timeout when two buffers were already available to be unlocked. Bug: 8238112 Change-Id: Ibefca35005ac5c408e5ada97ec4a4344a9e3e497
Diffstat (limited to 'camera')
-rw-r--r--camera/ProCamera.cpp41
-rw-r--r--camera/tests/ProCameraTests.cpp57
2 files changed, 88 insertions, 10 deletions
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index d4a9556..7c66d62 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -432,20 +432,21 @@ void ProCamera::onFrameAvailable(int streamId) {
// Unblock waitForFrame(id) callers
{
Mutex::Autolock al(mWaitMutex);
- getStreamInfo(streamId).frameReady = true;
+ getStreamInfo(streamId).frameReady++;
mWaitCondition.broadcast();
}
}
-status_t ProCamera::waitForFrameBuffer(int streamId) {
+int ProCamera::waitForFrameBuffer(int streamId) {
status_t stat = BAD_VALUE;
Mutex::Autolock al(mWaitMutex);
StreamInfo& si = getStreamInfo(streamId);
- if (si.frameReady) {
- si.frameReady = false;
- return OK;
+ if (si.frameReady > 0) {
+ int numFrames = si.frameReady;
+ si.frameReady = 0;
+ return numFrames;
} else {
while (true) {
stat = mWaitCondition.waitRelative(mWaitMutex,
@@ -456,9 +457,10 @@ status_t ProCamera::waitForFrameBuffer(int streamId) {
return stat;
}
- if (si.frameReady) {
- si.frameReady = false;
- return OK;
+ if (si.frameReady > 0) {
+ int numFrames = si.frameReady;
+ si.frameReady = 0;
+ return numFrames;
}
// else it was some other stream that got unblocked
}
@@ -467,6 +469,29 @@ status_t ProCamera::waitForFrameBuffer(int streamId) {
return stat;
}
+int ProCamera::dropFrameBuffer(int streamId, int count) {
+ StreamInfo& si = getStreamInfo(streamId);
+
+ if (!si.cpuStream) {
+ return BAD_VALUE;
+ } else if (count < 0) {
+ return BAD_VALUE;
+ }
+
+ int numDropped = 0;
+ for (int i = 0; i < count; ++i) {
+ CpuConsumer::LockedBuffer buffer;
+ if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) {
+ break;
+ }
+
+ si.cpuConsumer->unlockBuffer(buffer);
+ numDropped++;
+ }
+
+ return numDropped;
+}
+
status_t ProCamera::waitForFrameMetadata() {
status_t stat = BAD_VALUE;
Mutex::Autolock al(mWaitMutex);
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 33c9179..f93e5cd 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -55,6 +55,8 @@ namespace client {
#define TEST_CPU_FRAME_COUNT 2
#define TEST_CPU_HEAP_COUNT 5
+#define TEST_FRAME_PROCESSING_DELAY_US 200000 // 200 ms
+
#if TEST_DEBUGGING
#define dout std::cerr
#else
@@ -888,7 +890,7 @@ TEST_F(ProCameraTest, WaitForSingleStreamBuffer) {
// Consume a couple of results
for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
- EXPECT_OK(mCamera->waitForFrameBuffer(streamId));
+ EXPECT_EQ(1, mCamera->waitForFrameBuffer(streamId));
CpuConsumer::LockedBuffer buf;
EXPECT_OK(consumer->lockNextBuffer(&buf));
@@ -942,7 +944,7 @@ TEST_F(ProCameraTest, WaitForDualStreamBuffer) {
// Get the buffers
- EXPECT_OK(mCamera->waitForFrameBuffer(depthStreamId));
+ EXPECT_EQ(1, mCamera->waitForFrameBuffer(depthStreamId));
/**
* Guaranteed to be able to consume the depth frame,
@@ -978,7 +980,58 @@ TEST_F(ProCameraTest, WaitForDualStreamBuffer) {
EXPECT_OK(mCamera->exclusiveUnlock());
}
+TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFrames) {
+ if (HasFatalFailure()) {
+ return;
+ }
+
+ const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT;
+
+ 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*/NUM_REQUESTS));
+
+ // Consume a couple of results
+ for (int i = 0; i < NUM_REQUESTS; ++i) {
+ // Process at 10fps, stream is at 15fps.
+ // This means we will definitely fill up the buffer queue with
+ // extra buffers and need to drop them.
+ usleep(TEST_FRAME_PROCESSING_DELAY_US);
+
+ int numFrames;
+ EXPECT_TRUE((numFrames = mCamera->waitForFrameBuffer(streamId)) > 0);
+
+ // Drop all but the newest framebuffer
+ EXPECT_EQ(numFrames-1, mCamera->dropFrameBuffer(streamId, numFrames-1));
+
+ dout << "Dropped " << (numFrames - 1) << " frames" << std::endl;
+
+ // Skip the counter ahead, don't try to consume these frames again
+ i += numFrames-1;
+
+ // "Consume" the buffer
+ 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());
+}