From 68506fd58d26748617babe94d5648503cb3690bb Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Wed, 20 Feb 2013 17:57:31 -0800 Subject: Camera: ProCamera - add createStream stub and unit test for it Change-Id: Ic05130e63f4f2c0c3278ba348b192992169f105f --- camera/ProCamera.cpp | 68 ++++++++++++++++++++++++ camera/tests/ProCameraTests.cpp | 112 +++++++++++++++++++++++++++++++++++++++- include/camera/ProCamera.h | 41 +++++++++++++++ 3 files changed, 220 insertions(+), 1 deletion(-) diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp index 8164188..26e4de9 100644 --- a/camera/ProCamera.cpp +++ b/camera/ProCamera.cpp @@ -261,4 +261,72 @@ status_t ProCamera::cancelStream(int streamId) return c->cancelStream(streamId); } +status_t ProCamera::createStream(int width, int height, int format, + const sp& window, + /*out*/ + int* streamId) +{ + *streamId = -1; + + ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height, + format); + + if (window == 0) { + return BAD_VALUE; + } + + // TODO: actually implement this in IProCamera + return INVALID_OPERATION; +} + +status_t ProCamera::createStream(int width, int height, int format, + const sp& bufferProducer, + /*out*/ + int* streamId) { + + ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height, + format); + + sp binder; + sp window; + + if (bufferProducer != 0) { + binder = bufferProducer->asBinder(); + window = new Surface(bufferProducer); + + status_t stat = createStream(width, height, format, window, streamId); + + ALOGV("%s: createStreamT END (%d), StreamID = %d", __FUNCTION__, stat, + *streamId); + } + else { + *streamId = -1; + return BAD_VALUE; + } + + return BAD_VALUE; +} + +int ProCamera::getNumberOfCameras() { + ALOGE("%s: not implemented yet", __FUNCTION__); + return 1; +} + +camera_metadata* ProCamera::getCameraInfo(int cameraId) { + ALOGE("%s: not implemented yet", __FUNCTION__); + + ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId); + return NULL; +} + +status_t ProCamera::createDefaultRequest(int templateId, + camera_metadata** request) const { + ALOGE("%s: not implemented yet", __FUNCTION__); + + ALOGV("%s: templateId = %d", __FUNCTION__, templateId); + + *request = NULL; + return INVALID_OPERATION; +} + }; // namespace android diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp index adc3c75..d632b7e 100644 --- a/camera/tests/ProCameraTests.cpp +++ b/camera/tests/ProCameraTests.cpp @@ -26,6 +26,12 @@ #include #include +#include +#include + +#include +#include // for CAMERA2_TEMPLATE_PREVIEW only + namespace android { namespace camera2 { namespace tests { @@ -34,7 +40,8 @@ namespace client { #define CAMERA_ID 0 #define TEST_DEBUGGING 0 -#define TEST_LISTENER_TIMEOUT 2000000000 // 2 second listener timeout +#define TEST_LISTENER_TIMEOUT 1000000000 // 1 second listener timeout +#define TEST_FORMAT HAL_PIXEL_FORMAT_RGBA_8888 //TODO: YUY2 instead #if TEST_DEBUGGING #define dout std::cerr @@ -206,6 +213,40 @@ protected: static sp mTestThread; + int mDisplaySecs; + sp mComposerClient; + sp mSurfaceControl; + + int getSurfaceWidth() { + return 512; + } + int getSurfaceHeight() { + return 512; + } + + void createOnScreenSurface(sp& surface) { + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + + mSurfaceControl = mComposerClient->createSurface( + String8("ProCameraTest StreamingImage Surface"), + getSurfaceWidth(), getSurfaceHeight(), + PIXEL_FORMAT_RGB_888, 0); + + ASSERT_TRUE(mSurfaceControl != NULL); + ASSERT_TRUE(mSurfaceControl->isValid()); + + SurfaceComposerClient::openGlobalTransaction(); + ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); + ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); + SurfaceComposerClient::closeGlobalTransaction(); + + sp window = mSurfaceControl->getSurface(); + surface = mSurfaceControl->getSurface(); + + ASSERT_NE((void*)NULL, surface.get()); + } + }; sp ProCameraTest::mTestThread; @@ -260,6 +301,75 @@ TEST_F(ProCameraTest, LockingAsynchronous) { EXPECT_FALSE(mCamera->hasExclusiveLock()); } +// Stream directly to the screen. +TEST_F(ProCameraTest, StreamingImage) { + if (HasFatalFailure()) { + return; + } + char* displaySecsEnv = getenv("TEST_DISPLAY_SECS"); + if (displaySecsEnv != NULL) { + mDisplaySecs = atoi(displaySecsEnv); + if (mDisplaySecs < 0) { + mDisplaySecs = 0; + } + } else { + mDisplaySecs = 0; + } + + sp surface; + sp window; + if (mDisplaySecs > 0) { + createOnScreenSurface(/*out*/surface); + window = surface; + } + int streamId = -1; + EXPECT_OK(mCamera->createStream(/*width*/640, /*height*/480, TEST_FORMAT, + window, &streamId)); + EXPECT_NE(-1, streamId); + + EXPECT_OK(mCamera->exclusiveTryLock()); + /* 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 + + // wow what a verbose API. + // i would give a loaf of bread for + // metadata->updateOrInsert(keys.request.output.streams, streamId); + camera_metadata_entry_t entry; + uint32_t tag = static_cast(ANDROID_REQUEST_OUTPUT_STREAMS); + int find = find_camera_metadata_entry(request, tag, &entry); + if (find == -ENOENT) { + ASSERT_OK(add_camera_metadata_entry(request, tag, &streamId, + /*data_count*/1)); + } else { + ASSERT_OK(update_camera_metadata_entry(request, entry.index, &streamId, + /*data_count*/1, &entry)); + } + + EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); + + sleep(mDisplaySecs); + //should the window be empty until the buffer is flipped? + // that would certainly make sense + + + free_camera_metadata(request); + EXPECT_OK(mCamera->cancelStream(streamId)); + EXPECT_OK(mCamera->exclusiveUnlock()); +} + } } } diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h index 2dd01e3..7191b07 100644 --- a/include/camera/ProCamera.h +++ b/include/camera/ProCamera.h @@ -114,8 +114,49 @@ public: * Lock free. Service maintains counter of streams. * Errors: BAD_VALUE if unknown stream ID. */ +// TODO: remove requestStream, its useless. + +// TODO: rename cancelStream to deleteStream +// can probably do it with a grep/sed + + /** + * Ask for a stream to be disabled. + * Lock free. Service maintains counter of streams. + * Errors: BAD_VALUE if unknown stream ID. + */ status_t cancelStream(int streamId); + /** + * Create a new HW stream, whose sink will be the window. + * Lock free. Service maintains counter of streams. + * Errors: -EBUSY if too many streams created + */ + status_t createStream(int width, int height, int format, + const sp& window, + /*out*/ + int* streamId); + + /** + * Create a new HW stream, whose sink will be the SurfaceTexture. + * Lock free. Service maintains counter of streams. + * Errors: -EBUSY if too many streams created + */ + status_t createStream(int width, int height, int format, + const sp& bufferProducer, + /*out*/ + int* streamId); + + // Create a request object from a template. + status_t createDefaultRequest(int templateId, + /*out*/ + camera_metadata** request) const; + + // Get number of cameras + static int getNumberOfCameras(); + + // Get static camera metadata + static camera_metadata* getCameraInfo(int cameraId); + sp remote(); protected: -- cgit v1.1