Loading camera/ProCamera.cpp +88 −23 Original line number Diff line number Diff line Loading @@ -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); return c->cancelStream(streamId); mStreams.removeItem(streamId); return s; } status_t ProCamera::createStream(int width, int height, int format, Loading @@ -275,10 +272,7 @@ 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(), return createStream(width, height, format, surface->getIGraphicBufferProducer(), streamId); } Loading @@ -286,27 +280,68 @@ 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; 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; Loading @@ -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 camera/tests/ProCameraTests.cpp +147 −28 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 { Loading Loading @@ -92,7 +98,7 @@ public: { Mutex::Autolock al(mListenerMutex); if (mLockEventList.size() > 0) { if (mProEventList.size() > 0) { return OK; } } Loading @@ -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); } Loading Loading @@ -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 ) {} Loading @@ -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; Loading Loading @@ -217,6 +237,9 @@ protected: sp<SurfaceComposerClient> mComposerClient; sp<SurfaceControl> mSurfaceControl; sp<SurfaceComposerClient> mDepthComposerClient; sp<SurfaceControl> mDepthSurfaceControl; int getSurfaceWidth() { return 512; } Loading @@ -233,6 +256,8 @@ protected: getSurfaceWidth(), getSurfaceHeight(), PIXEL_FORMAT_RGB_888, 0); mSurfaceControl->setPosition(640, 0); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); Loading @@ -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; Loading Loading @@ -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. Loading @@ -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)); Loading @@ -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()); } Loading include/camera/ProCamera.h +74 −12 Original line number Diff line number Diff line Loading @@ -18,17 +18,20 @@ #define ANDROID_HARDWARE_PRO_CAMERA_H #include <utils/Timers.h> #include <utils/KeyedVector.h> #include <gui/IGraphicBufferProducer.h> #include <system/camera.h> #include <camera/IProCameraCallbacks.h> #include <camera/IProCameraUser.h> #include <camera/Camera.h> #include <gui/CpuConsumer.h> struct camera_metadata; namespace android { // ref-counted object for callbacks // All callbacks on this class are concurrent // (they come from separate threads) class ProCameraListener : public CameraListener { public: Loading @@ -42,6 +45,21 @@ public: // Lock free. virtual void onTriggerNotify(int32_t msgType, int32_t ext1, int32_t ext2) = 0; // OnBufferReceived and OnRequestReceived can come in with any order, // use android.sensor.timestamp and LockedBuffer.timestamp to correlate them // TODO: implement in IProCameraCallbacks, ProCamera2Client // A new frame buffer has been received for this stream. // -- This callback only fires for createStreamCpu streams // -- The buffer must not be accessed after this function call completes virtual void onBufferReceived(int streamId, const CpuConsumer::LockedBuffer& buf) = 0; // A new metadata buffer has been received. // -- Ownership of request passes on to the callee, // free with free_camera_metadata. virtual void onRequestReceived(camera_metadata* request) = 0; }; class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient Loading Loading @@ -109,22 +127,15 @@ public: * Lock free. Service maintains counter of streams. */ status_t requestStream(int streamId); /** * Ask for a stream to be disabled. * 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. * Delete a stream. * Lock free. * Errors: BAD_VALUE if unknown stream ID. * PERMISSION_DENIED if the stream wasn't yours */ status_t cancelStream(int streamId); status_t deleteStream(int streamId); /** * Create a new HW stream, whose sink will be the window. Loading @@ -145,6 +156,10 @@ public: const sp<IGraphicBufferProducer>& bufferProducer, /*out*/ int* streamId); status_t createStreamCpu(int width, int height, int format, int heapCount, /*out*/ int* streamId); // Create a request object from a template. status_t createDefaultRequest(int templateId, Loading Loading @@ -203,6 +218,53 @@ private: static Mutex mLock; static sp<ICameraService> mCameraService; class ProFrameListener : public CpuConsumer::FrameAvailableListener { public: ProFrameListener(wp<ProCamera> camera, int streamID) { mCamera = camera; mStreamId = streamID; } protected: virtual void onFrameAvailable() { sp<ProCamera> c = mCamera.promote(); if (c.get() != NULL) { c->onFrameAvailable(mStreamId); } } private: wp<ProCamera> mCamera; int mStreamId; }; friend class ProFrameListener; struct StreamInfo { StreamInfo(int streamId) { this->streamID = streamId; cpuStream = false; } StreamInfo() { streamID = -1; cpuStream = false; } int streamID; bool cpuStream; sp<CpuConsumer> cpuConsumer; sp<ProFrameListener> frameAvailableListener; sp<Surface> stc; }; KeyedVector<int, StreamInfo> mStreams; void onFrameAvailable(int streamId); StreamInfo& getStreamInfo(int streamId); }; Loading services/camera/libcameraservice/ProCamera2Client.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -234,6 +234,13 @@ status_t ProCamera2Client::cancelStream(int streamId) { Mutex::Autolock icl(mIProCameraUserLock); mDevice->clearStreamingRequest(); status_t code; if ((code = mDevice->waitUntilDrained()) != OK) { ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, code); } return mDevice->deleteStream(streamId); } Loading Loading
camera/ProCamera.cpp +88 −23 Original line number Diff line number Diff line Loading @@ -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); return c->cancelStream(streamId); mStreams.removeItem(streamId); return s; } status_t ProCamera::createStream(int width, int height, int format, Loading @@ -275,10 +272,7 @@ 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(), return createStream(width, height, format, surface->getIGraphicBufferProducer(), streamId); } Loading @@ -286,27 +280,68 @@ 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; 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; Loading @@ -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
camera/tests/ProCameraTests.cpp +147 −28 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 { Loading Loading @@ -92,7 +98,7 @@ public: { Mutex::Autolock al(mListenerMutex); if (mLockEventList.size() > 0) { if (mProEventList.size() > 0) { return OK; } } Loading @@ -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); } Loading Loading @@ -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 ) {} Loading @@ -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; Loading Loading @@ -217,6 +237,9 @@ protected: sp<SurfaceComposerClient> mComposerClient; sp<SurfaceControl> mSurfaceControl; sp<SurfaceComposerClient> mDepthComposerClient; sp<SurfaceControl> mDepthSurfaceControl; int getSurfaceWidth() { return 512; } Loading @@ -233,6 +256,8 @@ protected: getSurfaceWidth(), getSurfaceHeight(), PIXEL_FORMAT_RGB_888, 0); mSurfaceControl->setPosition(640, 0); ASSERT_TRUE(mSurfaceControl != NULL); ASSERT_TRUE(mSurfaceControl->isValid()); Loading @@ -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; Loading Loading @@ -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. Loading @@ -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)); Loading @@ -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()); } Loading
include/camera/ProCamera.h +74 −12 Original line number Diff line number Diff line Loading @@ -18,17 +18,20 @@ #define ANDROID_HARDWARE_PRO_CAMERA_H #include <utils/Timers.h> #include <utils/KeyedVector.h> #include <gui/IGraphicBufferProducer.h> #include <system/camera.h> #include <camera/IProCameraCallbacks.h> #include <camera/IProCameraUser.h> #include <camera/Camera.h> #include <gui/CpuConsumer.h> struct camera_metadata; namespace android { // ref-counted object for callbacks // All callbacks on this class are concurrent // (they come from separate threads) class ProCameraListener : public CameraListener { public: Loading @@ -42,6 +45,21 @@ public: // Lock free. virtual void onTriggerNotify(int32_t msgType, int32_t ext1, int32_t ext2) = 0; // OnBufferReceived and OnRequestReceived can come in with any order, // use android.sensor.timestamp and LockedBuffer.timestamp to correlate them // TODO: implement in IProCameraCallbacks, ProCamera2Client // A new frame buffer has been received for this stream. // -- This callback only fires for createStreamCpu streams // -- The buffer must not be accessed after this function call completes virtual void onBufferReceived(int streamId, const CpuConsumer::LockedBuffer& buf) = 0; // A new metadata buffer has been received. // -- Ownership of request passes on to the callee, // free with free_camera_metadata. virtual void onRequestReceived(camera_metadata* request) = 0; }; class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient Loading Loading @@ -109,22 +127,15 @@ public: * Lock free. Service maintains counter of streams. */ status_t requestStream(int streamId); /** * Ask for a stream to be disabled. * 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. * Delete a stream. * Lock free. * Errors: BAD_VALUE if unknown stream ID. * PERMISSION_DENIED if the stream wasn't yours */ status_t cancelStream(int streamId); status_t deleteStream(int streamId); /** * Create a new HW stream, whose sink will be the window. Loading @@ -145,6 +156,10 @@ public: const sp<IGraphicBufferProducer>& bufferProducer, /*out*/ int* streamId); status_t createStreamCpu(int width, int height, int format, int heapCount, /*out*/ int* streamId); // Create a request object from a template. status_t createDefaultRequest(int templateId, Loading Loading @@ -203,6 +218,53 @@ private: static Mutex mLock; static sp<ICameraService> mCameraService; class ProFrameListener : public CpuConsumer::FrameAvailableListener { public: ProFrameListener(wp<ProCamera> camera, int streamID) { mCamera = camera; mStreamId = streamID; } protected: virtual void onFrameAvailable() { sp<ProCamera> c = mCamera.promote(); if (c.get() != NULL) { c->onFrameAvailable(mStreamId); } } private: wp<ProCamera> mCamera; int mStreamId; }; friend class ProFrameListener; struct StreamInfo { StreamInfo(int streamId) { this->streamID = streamId; cpuStream = false; } StreamInfo() { streamID = -1; cpuStream = false; } int streamID; bool cpuStream; sp<CpuConsumer> cpuConsumer; sp<ProFrameListener> frameAvailableListener; sp<Surface> stc; }; KeyedVector<int, StreamInfo> mStreams; void onFrameAvailable(int streamId); StreamInfo& getStreamInfo(int streamId); }; Loading
services/camera/libcameraservice/ProCamera2Client.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -234,6 +234,13 @@ status_t ProCamera2Client::cancelStream(int streamId) { Mutex::Autolock icl(mIProCameraUserLock); mDevice->clearStreamingRequest(); status_t code; if ((code = mDevice->waitUntilDrained()) != OK) { ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__, code); } return mDevice->deleteStream(streamId); } Loading