summaryrefslogtreecommitdiffstats
path: root/camera
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2013-02-20 19:29:53 -0800
committerIgor Murashkin <iam@google.com>2013-02-22 10:50:15 -0800
commitc0767f148e29ce821281b5965c0e25b4c143e76d (patch)
treed71e86b5d066b9a05e1732fa829c40affbb09411 /camera
parent5494cdc67b541034c963919aef8acb8b665e4dde (diff)
downloadframeworks_av-c0767f148e29ce821281b5965c0e25b4c143e76d.zip
frameworks_av-c0767f148e29ce821281b5965c0e25b4c143e76d.tar.gz
frameworks_av-c0767f148e29ce821281b5965c0e25b4c143e76d.tar.bz2
Camera: ProCamera - add createStreamCpu and unit test
Change-Id: I468172dbfdd78510b273bf9d119c950cbeda7ea3
Diffstat (limited to 'camera')
-rw-r--r--camera/ProCamera.cpp111
-rw-r--r--camera/tests/ProCameraTests.cpp175
2 files changed, 235 insertions, 51 deletions
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 8fd08f4..5ee0e4d 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -246,19 +246,16 @@ status_t ProCamera::cancelRequest(int requestId)
return c->cancelRequest(requestId);
}
-status_t ProCamera::requestStream(int streamId)
+status_t ProCamera::deleteStream(int streamId)
{
sp <IProCameraUser> c = mCamera;
if (c == 0) return NO_INIT;
- return c->requestStream(streamId);
-}
-status_t ProCamera::cancelStream(int streamId)
-{
- sp <IProCameraUser> c = mCamera;
- if (c == 0) return NO_INIT;
+ status_t s = c->cancelStream(streamId);
+
+ mStreams.removeItem(streamId);
- return c->cancelStream(streamId);
+ return s;
}
status_t ProCamera::createStream(int width, int height, int format,
@@ -275,38 +272,76 @@ status_t ProCamera::createStream(int width, int height, int format,
return BAD_VALUE;
}
- sp <IProCameraUser> c = mCamera;
- if (c == 0) return NO_INIT;
-
- return c->createStream(width, height, format, surface->getIGraphicBufferProducer(),
- streamId);
+ return createStream(width, height, format, surface->getIGraphicBufferProducer(),
+ streamId);
}
status_t ProCamera::createStream(int width, int height, int format,
const sp<IGraphicBufferProducer>& bufferProducer,
/*out*/
int* streamId) {
+ *streamId = -1;
ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
format);
- sp<IBinder> binder;
- status_t stat = INVALID_OPERATION;
+ if (bufferProducer == 0) {
+ return BAD_VALUE;
+ }
- if (bufferProducer != 0) {
- sp <IProCameraUser> c = mCamera;
- if (c == 0) return NO_INIT;
+ sp <IProCameraUser> c = mCamera;
+ status_t stat = c->createStream(width, height, format, bufferProducer,
+ streamId);
- return c->createStream(width, height, format, bufferProducer, streamId);
- }
- else {
- *streamId = -1;
- return BAD_VALUE;
+ if (stat == OK) {
+ StreamInfo s(*streamId);
+
+ mStreams.add(*streamId, s);
}
return stat;
}
+status_t ProCamera::createStreamCpu(int width, int height, int format,
+ int heapCount,
+ /*out*/
+ int* streamId)
+{
+ ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height,
+ format);
+
+ sp <IProCameraUser> c = mCamera;
+ if (c == 0) return NO_INIT;
+
+ sp<CpuConsumer> cc = new CpuConsumer(heapCount);
+ cc->setName(String8("ProCamera::mCpuConsumer"));
+
+ sp<Surface> stc = new Surface(
+ cc->getProducerInterface());
+
+ status_t s = createStream(width, height, format, stc->getIGraphicBufferProducer(),
+ streamId);
+
+ if (s != OK) {
+ ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__,
+ width, height, format);
+ return s;
+ }
+
+ sp<ProFrameListener> frameAvailableListener =
+ new ProFrameListener(this, *streamId);
+
+ getStreamInfo(*streamId).cpuStream = true;
+ getStreamInfo(*streamId).cpuConsumer = cc;
+ getStreamInfo(*streamId).stc = stc;
+ // for lifetime management
+ getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener;
+
+ cc->setFrameAvailableListener(frameAvailableListener);
+
+ return s;
+}
+
int ProCamera::getNumberOfCameras() {
ALOGE("%s: not implemented yet", __FUNCTION__);
return 1;
@@ -329,4 +364,34 @@ status_t ProCamera::createDefaultRequest(int templateId,
return c->createDefaultRequest(templateId, request);
}
+void ProCamera::onFrameAvailable(int streamId) {
+ ALOGV("%s: streamId = %d", __FUNCTION__, streamId);
+
+ sp<ProCameraListener> listener = mListener;
+ if (listener.get() != NULL) {
+ StreamInfo& stream = getStreamInfo(streamId);
+
+ CpuConsumer::LockedBuffer buf;
+
+ status_t stat = stream.cpuConsumer->lockNextBuffer(&buf);
+ if (stat != OK) {
+ ALOGE("%s: Failed to lock buffer, error code = %d", __FUNCTION__,
+ stat);
+ return;
+ }
+
+ listener->onBufferReceived(streamId, buf);
+ stat = stream.cpuConsumer->unlockBuffer(buf);
+
+ if (stat != OK) {
+ ALOGE("%s: Failed to unlock buffer, error code = %d", __FUNCTION__,
+ stat);
+ }
+ }
+}
+
+ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) {
+ return mStreams.editValueFor(streamId);
+}
+
}; // namespace android
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 230e160..f0a36e8 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -41,7 +41,12 @@ namespace client {
#define TEST_DEBUGGING 0
#define TEST_LISTENER_TIMEOUT 1000000000 // 1 second listener timeout
-#define TEST_FORMAT HAL_PIXEL_FORMAT_RGBA_8888 //TODO: YUY2 instead
+#define TEST_FORMAT HAL_PIXEL_FORMAT_Y16 //TODO: YUY2 instead
+
+#define TEST_FORMAT_DEPTH HAL_PIXEL_FORMAT_Y16
+
+#define TEST_CPU_FRAME_COUNT 2
+#define TEST_CPU_HEAP_COUNT 5
#if TEST_DEBUGGING
#define dout std::cerr
@@ -54,14 +59,15 @@ namespace client {
class ProCameraTest;
-enum LockEvent {
+enum ProEvent {
UNKNOWN,
ACQUIRED,
RELEASED,
- STOLEN
+ STOLEN,
+ BUFFER_RECEIVED,
};
-typedef Vector<LockEvent> EventList;
+typedef Vector<ProEvent> EventList;
class ProCameraTestThread : public Thread
{
@@ -92,7 +98,7 @@ public:
{
Mutex::Autolock al(mListenerMutex);
- if (mLockEventList.size() > 0) {
+ if (mProEventList.size() > 0) {
return OK;
}
}
@@ -105,35 +111,35 @@ public:
void ReadEvents(EventList& out) {
Mutex::Autolock al(mListenerMutex);
- for (size_t i = 0; i < mLockEventList.size(); ++i) {
- out.push(mLockEventList[i]);
+ for (size_t i = 0; i < mProEventList.size(); ++i) {
+ out.push(mProEventList[i]);
}
- mLockEventList.clear();
+ mProEventList.clear();
}
/**
* Dequeue 1 event from the event queue.
* Returns UNKNOWN if queue is empty
*/
- LockEvent ReadEvent() {
+ ProEvent ReadEvent() {
Mutex::Autolock al(mListenerMutex);
- if (mLockEventList.size() == 0) {
+ if (mProEventList.size() == 0) {
return UNKNOWN;
}
- LockEvent ev = mLockEventList[0];
- mLockEventList.removeAt(0);
+ ProEvent ev = mProEventList[0];
+ mProEventList.removeAt(0);
return ev;
}
private:
- void QueueEvent(LockEvent ev) {
+ void QueueEvent(ProEvent ev) {
{
Mutex::Autolock al(mListenerMutex);
- mLockEventList.push(ev);
+ mProEventList.push(ev);
}
@@ -168,6 +174,20 @@ protected:
<< " " << ext3 << std::endl;
}
+ virtual void onBufferReceived(int streamId,
+ const CpuConsumer::LockedBuffer& buf) {
+
+ dout << "Buffer received on streamId = " << streamId <<
+ ", dataPtr = " << (void*)buf.data << std::endl;
+
+ QueueEvent(BUFFER_RECEIVED);
+
+ }
+ virtual void onRequestReceived(
+ camera_metadata* request) {
+ free_camera_metadata(request);
+ }
+
// TODO: remove
virtual void notify(int32_t , int32_t , int32_t ) {}
@@ -176,7 +196,7 @@ protected:
virtual void postDataTimestamp(nsecs_t , int32_t , const sp<IMemory>& ) {}
- Vector<LockEvent> mLockEventList;
+ Vector<ProEvent> mProEventList;
Mutex mListenerMutex;
Mutex mConditionMutex;
Condition mListenerCondition;
@@ -217,6 +237,9 @@ protected:
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
+ sp<SurfaceComposerClient> mDepthComposerClient;
+ sp<SurfaceControl> mDepthSurfaceControl;
+
int getSurfaceWidth() {
return 512;
}
@@ -233,6 +256,8 @@ protected:
getSurfaceWidth(), getSurfaceHeight(),
PIXEL_FORMAT_RGB_888, 0);
+ mSurfaceControl->setPosition(640, 0);
+
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
@@ -247,6 +272,31 @@ protected:
ASSERT_NE((void*)NULL, surface.get());
}
+ void createDepthOnScreenSurface(sp<Surface>& surface) {
+ mDepthComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mDepthComposerClient->initCheck());
+
+ mDepthSurfaceControl = mDepthComposerClient->createSurface(
+ String8("ProCameraTest StreamingImage Surface"),
+ getSurfaceWidth(), getSurfaceHeight(),
+ PIXEL_FORMAT_RGB_888, 0);
+
+ mDepthSurfaceControl->setPosition(640, 0);
+
+ ASSERT_TRUE(mDepthSurfaceControl != NULL);
+ ASSERT_TRUE(mDepthSurfaceControl->isValid());
+
+ SurfaceComposerClient::openGlobalTransaction();
+ ASSERT_EQ(NO_ERROR, mDepthSurfaceControl->setLayer(0x7FFFFFFF));
+ ASSERT_EQ(NO_ERROR, mDepthSurfaceControl->show());
+ SurfaceComposerClient::closeGlobalTransaction();
+
+ sp<ANativeWindow> window = mDepthSurfaceControl->getSurface();
+ surface = mDepthSurfaceControl->getSurface();
+
+ ASSERT_NE((void*)NULL, surface.get());
+ }
+
};
sp<Thread> ProCameraTest::mTestThread;
@@ -316,14 +366,15 @@ TEST_F(ProCameraTest, StreamingImage) {
mDisplaySecs = 0;
}
- sp<Surface> surface;
+ sp<Surface> depthSurface;
if (mDisplaySecs > 0) {
- createOnScreenSurface(/*out*/surface);
+ createDepthOnScreenSurface(/*out*/depthSurface);
}
- int streamId = -1;
- EXPECT_OK(mCamera->createStream(/*width*/640, /*height*/480, TEST_FORMAT,
- surface, &streamId));
- EXPECT_NE(-1, streamId);
+
+ int depthStreamId = -1;
+ EXPECT_OK(mCamera->createStream(/*width*/320, /*height*/240,
+ TEST_FORMAT_DEPTH, depthSurface, &depthStreamId));
+ EXPECT_NE(-1, depthStreamId);
EXPECT_OK(mCamera->exclusiveTryLock());
/* iterate in a loop submitting requests every frame.
@@ -345,23 +396,26 @@ TEST_F(ProCameraTest, StreamingImage) {
// wow what a verbose API.
// i would give a loaf of bread for
// metadata->updateOrInsert(keys.request.output.streams, streamId);
+ uint8_t allStreams[] = { depthStreamId };
+ size_t streamCount = sizeof(allStreams) / sizeof(allStreams[0]);
+
camera_metadata_entry_t entry;
uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
int find = find_camera_metadata_entry(request, tag, &entry);
if (find == -ENOENT) {
- if (add_camera_metadata_entry(request, tag, &streamId, /*data_count*/1)
- != OK) {
+ if (add_camera_metadata_entry(request, tag, &allStreams,
+ /*data_count*/streamCount) != OK) {
camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000);
ASSERT_OK(append_camera_metadata(tmp, request));
free_camera_metadata(request);
request = tmp;
- ASSERT_OK(add_camera_metadata_entry(request, tag, &streamId,
- /*data_count*/1));
+ ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams,
+ /*data_count*/streamCount));
}
} else {
- ASSERT_OK(update_camera_metadata_entry(request, entry.index, &streamId,
- /*data_count*/1, &entry));
+ ASSERT_OK(update_camera_metadata_entry(request, entry.index,
+ &allStreams, /*data_count*/streamCount, &entry));
}
EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true));
@@ -370,7 +424,72 @@ TEST_F(ProCameraTest, StreamingImage) {
sleep(mDisplaySecs);
free_camera_metadata(request);
- EXPECT_OK(mCamera->cancelStream(streamId));
+
+ for (int i = 0; i < streamCount; ++i) {
+ EXPECT_OK(mCamera->deleteStream(allStreams[i]));
+ }
+ EXPECT_OK(mCamera->exclusiveUnlock());
+}
+
+TEST_F(ProCameraTest, CpuConsumer) {
+ if (HasFatalFailure()) {
+ return;
+ }
+ int streamId = -1;
+ EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240,
+ TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &streamId));
+ EXPECT_NE(-1, streamId);
+
+ EXPECT_OK(mCamera->exclusiveTryLock());
+ EXPECT_EQ(OK, mListener->WaitForEvent());
+ EXPECT_EQ(ACQUIRED, mListener->ReadEvent());
+ /* iterate in a loop submitting requests every frame.
+ * what kind of requests doesnt really matter, just whatever.
+ */
+
+ // it would probably be better to use CameraMetadata from camera service.
+ camera_metadata_t *request = NULL;
+ EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ /*out*/&request));
+ EXPECT_NE((void*)NULL, request);
+
+ /*FIXME: dont need this later, at which point the above should become an
+ ASSERT_NE*/
+ if(request == NULL) request = allocate_camera_metadata(10, 100);
+
+ // set the output streams to just this stream ID
+
+ uint8_t allStreams[] = { streamId };
+ camera_metadata_entry_t entry;
+ uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS);
+ int find = find_camera_metadata_entry(request, tag, &entry);
+ if (find == -ENOENT) {
+ if (add_camera_metadata_entry(request, tag, &allStreams,
+ /*data_count*/1) != OK) {
+ camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000);
+ ASSERT_OK(append_camera_metadata(tmp, request));
+ free_camera_metadata(request);
+ request = tmp;
+
+ ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams,
+ /*data_count*/1));
+ }
+ } else {
+ ASSERT_OK(update_camera_metadata_entry(request, entry.index,
+ &allStreams, /*data_count*/1, &entry));
+ }
+
+ EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true));
+
+ // Consume a couple of frames
+ for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) {
+ EXPECT_EQ(OK, mListener->WaitForEvent());
+ EXPECT_EQ(BUFFER_RECEIVED, mListener->ReadEvent());
+ }
+
+ // Done: clean up
+ free_camera_metadata(request);
+ EXPECT_OK(mCamera->deleteStream(streamId));
EXPECT_OK(mCamera->exclusiveUnlock());
}