Loading camera/ProCamera.cpp +97 −13 Original line number Diff line number Diff line Loading @@ -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() Loading Loading @@ -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 { Loading Loading @@ -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; Loading Loading @@ -357,6 +374,8 @@ status_t ProCamera::createStreamCpu(int width, int height, int format, cc->setFrameAvailableListener(frameAvailableListener); *cpuConsumer = cc; return s; } Loading Loading @@ -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); 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); StreamInfo& si = getStreamInfo(streamId); 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 } } listener->onBufferReceived(streamId, buf); stat = stream.cpuConsumer->unlockBuffer(buf); 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: Failed to unlock buffer, error code = %d", __FUNCTION__, stat); 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) { Loading camera/tests/ProCameraTests.cpp +163 −9 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading Loading @@ -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, Loading @@ -427,7 +428,15 @@ protected: request.update(tag, streamIds, count); requestTmp = request.release(); 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); } Loading Loading @@ -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()); Loading Loading @@ -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()); Loading Loading @@ -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()); Loading Loading @@ -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()); } } } } Loading include/camera/ProCamera.h +44 −1 Original line number Diff line number Diff line Loading @@ -24,8 +24,12 @@ #include <camera/IProCameraCallbacks.h> #include <camera/IProCameraUser.h> #include <camera/Camera.h> #include <camera/CameraMetadata.h> #include <gui/CpuConsumer.h> #include <utils/Condition.h> #include <utils/Mutex.h> struct camera_metadata; namespace android { Loading Loading @@ -62,6 +66,20 @@ public: * free_camera_metadata. */ virtual void onResultReceived(int32_t frameId, camera_metadata* result) = 0; // A new frame buffer has been received for this stream. // -- This callback only fires for createStreamCpu streams // -- Use buf.timestamp to correlate with metadata's android.sensor.timestamp // -- The buffer should be accessed with CpuConsumer::lockNextBuffer // and CpuConsumer::unlockBuffer virtual void onFrameAvailable(int streamId, const sp<CpuConsumer>& cpuConsumer) { } virtual bool useOnFrameAvailable() { return false; } }; class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient Loading Loading @@ -161,6 +179,7 @@ public: status_t createStreamCpu(int width, int height, int format, int heapCount, /*out*/ sp<CpuConsumer>* cpuConsumer, int* streamId); // Create a request object from a template. Loading @@ -174,6 +193,24 @@ public: // Get static camera metadata camera_metadata* getCameraInfo(int cameraId); // Blocks until a frame is available (CPU streams only) // - Obtain the frame data by calling CpuConsumer::lockNextBuffer // - Release the frame data after use with CpuConsumer::unlockBuffer // Error codes: // -ETIMEDOUT if it took too long to get a frame status_t waitForFrameBuffer(int streamId); // Blocks until a metadata result is available // - Obtain the metadata by calling consumeFrameMetadata() // Error codes: // -ETIMEDOUT if it took too long to get a frame status_t waitForFrameMetadata(); // Get the latest metadata. This is destructive. // - Calling this repeatedly will produce empty metadata objects. // - Use waitForFrameMetadata to sync until new data is available. CameraMetadata consumeFrameMetadata(); sp<IProCameraUser> remote(); protected: Loading Loading @@ -249,6 +286,7 @@ private: StreamInfo(int streamId) { this->streamID = streamId; cpuStream = false; frameReady = false; } StreamInfo() { Loading @@ -261,10 +299,15 @@ private: sp<CpuConsumer> cpuConsumer; sp<ProFrameListener> frameAvailableListener; sp<Surface> stc; bool frameReady; }; Condition mWaitCondition; Mutex mWaitMutex; static const nsecs_t mWaitTimeout = 1000000000; // 1sec KeyedVector<int, StreamInfo> mStreams; bool mMetadataReady; CameraMetadata mLatestMetadata; void onFrameAvailable(int streamId); Loading Loading
camera/ProCamera.cpp +97 −13 Original line number Diff line number Diff line Loading @@ -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() Loading Loading @@ -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 { Loading Loading @@ -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; Loading Loading @@ -357,6 +374,8 @@ status_t ProCamera::createStreamCpu(int width, int height, int format, cc->setFrameAvailableListener(frameAvailableListener); *cpuConsumer = cc; return s; } Loading Loading @@ -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); 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); StreamInfo& si = getStreamInfo(streamId); 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 } } listener->onBufferReceived(streamId, buf); stat = stream.cpuConsumer->unlockBuffer(buf); 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: Failed to unlock buffer, error code = %d", __FUNCTION__, stat); 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) { Loading
camera/tests/ProCameraTests.cpp +163 −9 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading Loading @@ -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, Loading @@ -427,7 +428,15 @@ protected: request.update(tag, streamIds, count); requestTmp = request.release(); 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); } Loading Loading @@ -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()); Loading Loading @@ -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()); Loading Loading @@ -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()); Loading Loading @@ -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()); } } } } Loading
include/camera/ProCamera.h +44 −1 Original line number Diff line number Diff line Loading @@ -24,8 +24,12 @@ #include <camera/IProCameraCallbacks.h> #include <camera/IProCameraUser.h> #include <camera/Camera.h> #include <camera/CameraMetadata.h> #include <gui/CpuConsumer.h> #include <utils/Condition.h> #include <utils/Mutex.h> struct camera_metadata; namespace android { Loading Loading @@ -62,6 +66,20 @@ public: * free_camera_metadata. */ virtual void onResultReceived(int32_t frameId, camera_metadata* result) = 0; // A new frame buffer has been received for this stream. // -- This callback only fires for createStreamCpu streams // -- Use buf.timestamp to correlate with metadata's android.sensor.timestamp // -- The buffer should be accessed with CpuConsumer::lockNextBuffer // and CpuConsumer::unlockBuffer virtual void onFrameAvailable(int streamId, const sp<CpuConsumer>& cpuConsumer) { } virtual bool useOnFrameAvailable() { return false; } }; class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient Loading Loading @@ -161,6 +179,7 @@ public: status_t createStreamCpu(int width, int height, int format, int heapCount, /*out*/ sp<CpuConsumer>* cpuConsumer, int* streamId); // Create a request object from a template. Loading @@ -174,6 +193,24 @@ public: // Get static camera metadata camera_metadata* getCameraInfo(int cameraId); // Blocks until a frame is available (CPU streams only) // - Obtain the frame data by calling CpuConsumer::lockNextBuffer // - Release the frame data after use with CpuConsumer::unlockBuffer // Error codes: // -ETIMEDOUT if it took too long to get a frame status_t waitForFrameBuffer(int streamId); // Blocks until a metadata result is available // - Obtain the metadata by calling consumeFrameMetadata() // Error codes: // -ETIMEDOUT if it took too long to get a frame status_t waitForFrameMetadata(); // Get the latest metadata. This is destructive. // - Calling this repeatedly will produce empty metadata objects. // - Use waitForFrameMetadata to sync until new data is available. CameraMetadata consumeFrameMetadata(); sp<IProCameraUser> remote(); protected: Loading Loading @@ -249,6 +286,7 @@ private: StreamInfo(int streamId) { this->streamID = streamId; cpuStream = false; frameReady = false; } StreamInfo() { Loading @@ -261,10 +299,15 @@ private: sp<CpuConsumer> cpuConsumer; sp<ProFrameListener> frameAvailableListener; sp<Surface> stc; bool frameReady; }; Condition mWaitCondition; Mutex mWaitMutex; static const nsecs_t mWaitTimeout = 1000000000; // 1sec KeyedVector<int, StreamInfo> mStreams; bool mMetadataReady; CameraMetadata mLatestMetadata; void onFrameAvailable(int streamId); Loading