From 418e493e8d67924cfda652cb64965647ce6381cb Mon Sep 17 00:00:00 2001 From: Igor Murashkin Date: Thu, 21 Feb 2013 12:02:29 -0800 Subject: Camera: ProCamera - implement onResultReceived callback for metadata callbacks Change-Id: I46775402b007244bc383d6343a620eebbd492aad --- camera/IProCameraCallbacks.cpp | 25 +++ camera/ProCamera.cpp | 18 +++ camera/tests/ProCameraTests.cpp | 128 ++++++++++++++-- include/camera/IProCameraCallbacks.h | 7 + include/camera/ProCamera.h | 17 ++- services/camera/libcameraservice/Android.mk | 3 +- .../camera/libcameraservice/ProCamera2Client.cpp | 35 +++++ .../camera/libcameraservice/ProCamera2Client.h | 12 +- .../libcameraservice/camera2/ProFrameProcessor.cpp | 168 +++++++++++++++++++++ .../libcameraservice/camera2/ProFrameProcessor.h | 81 ++++++++++ 10 files changed, 474 insertions(+), 20 deletions(-) create mode 100644 services/camera/libcameraservice/camera2/ProFrameProcessor.cpp create mode 100644 services/camera/libcameraservice/camera2/ProFrameProcessor.h diff --git a/camera/IProCameraCallbacks.cpp b/camera/IProCameraCallbacks.cpp index 756fba2..6cd36bf 100644 --- a/camera/IProCameraCallbacks.cpp +++ b/camera/IProCameraCallbacks.cpp @@ -28,6 +28,8 @@ #include +#include + namespace android { enum { @@ -35,8 +37,12 @@ enum { DATA_CALLBACK, DATA_CALLBACK_TIMESTAMP, LOCK_STATUS_CHANGED, + RESULT_RECEIVED, }; +void readMetadata(const Parcel& data, camera_metadata_t** out); +void writeMetadata(Parcel& data, camera_metadata_t* metadata); + class BpProCameraCallbacks: public BpInterface { public: @@ -96,6 +102,15 @@ public: remote()->transact(LOCK_STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY); } + + void onResultReceived(int32_t frameId, camera_metadata* result) { + ALOGV("onResultReceived"); + Parcel data, reply; + data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); + data.writeInt32(frameId); + writeMetadata(data, result); + remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY); + } }; IMPLEMENT_META_INTERFACE(ProCameraCallbacks, @@ -152,6 +167,16 @@ status_t BnProCameraCallbacks::onTransact( onLockStatusChanged(newLockStatus); return NO_ERROR; } break; + case RESULT_RECEIVED: { + ALOGV("RESULT_RECEIVED"); + CHECK_INTERFACE(IProCameraCallbacks, data, reply); + int32_t frameId = data.readInt32(); + camera_metadata_t *result = NULL; + readMetadata(data, &result); + onResultReceived(frameId, result); + return NO_ERROR; + break; + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp index 5ee0e4d..142c03b 100644 --- a/camera/ProCamera.cpp +++ b/camera/ProCamera.cpp @@ -33,6 +33,8 @@ #include #include +#include + namespace android { // client singleton for camera service binder interface @@ -198,6 +200,22 @@ void ProCamera::onLockStatusChanged( } } +void ProCamera::onResultReceived(int32_t frameId, camera_metadata* result) { + ALOGV("%s: frameId = %d, result = %p", __FUNCTION__, frameId, result); + + sp listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; + } + if (listener != NULL) { + listener->onResultReceived(frameId, result); + } else { + free_camera_metadata(result); + } + +} + status_t ProCamera::exclusiveTryLock() { sp c = mCamera; diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp index dafa995..021fbae 100644 --- a/camera/tests/ProCameraTests.cpp +++ b/camera/tests/ProCameraTests.cpp @@ -66,8 +66,13 @@ enum ProEvent { RELEASED, STOLEN, BUFFER_RECEIVED, + RESULT_RECEIVED, }; +inline int ProEvent_Mask(ProEvent e) { + return (1 << static_cast(e)); +} + typedef Vector EventList; class ProCameraTestThread : public Thread @@ -93,6 +98,12 @@ public: class ProCameraTestListener : public ProCameraListener { public: + static const int EVENT_MASK_ALL = 0xFFFFFFFF; + + ProCameraTestListener() { + mEventMask = EVENT_MASK_ALL; + } + status_t WaitForEvent() { Mutex::Autolock cal(mConditionMutex); @@ -136,15 +147,26 @@ public: return ev; } + void SetEventMask(int eventMask) { + Mutex::Autolock al(mListenerMutex); + mEventMask = eventMask; + } + private: void QueueEvent(ProEvent ev) { + bool eventAdded = false; { Mutex::Autolock al(mListenerMutex); - mProEventList.push(ev); - } + if (ProEvent_Mask(ev) & mEventMask) { + mProEventList.push(ev); + eventAdded = true; + } + } - mListenerCondition.broadcast(); + if (eventAdded) { + mListenerCondition.broadcast(); + } } protected: @@ -184,8 +206,11 @@ protected: QueueEvent(BUFFER_RECEIVED); } - virtual void onRequestReceived( - camera_metadata* request) { + virtual void onResultReceived(int32_t frameId, + camera_metadata* request) { + dout << "Result received frameId = " << frameId + << ", requestPtr = " << (void*)request << std::endl; + QueueEvent(RESULT_RECEIVED); free_camera_metadata(request); } @@ -201,6 +226,7 @@ protected: Mutex mListenerMutex; Mutex mConditionMutex; Condition mListenerCondition; + int mEventMask; }; class ProCameraTest : public ::testing::Test { @@ -309,6 +335,10 @@ TEST_F(ProCameraTest, LockingImmediate) { return; } + mListener->SetEventMask(ProEvent_Mask(ACQUIRED) | + ProEvent_Mask(STOLEN) | + ProEvent_Mask(RELEASED)); + EXPECT_FALSE(mCamera->hasExclusiveLock()); EXPECT_EQ(OK, mCamera->exclusiveTryLock()); // at this point we definitely have the lock @@ -332,13 +362,17 @@ TEST_F(ProCameraTest, LockingAsynchronous) { return; } + + mListener->SetEventMask(ProEvent_Mask(ACQUIRED) | + ProEvent_Mask(STOLEN) | + ProEvent_Mask(RELEASED)); + // TODO: Add another procamera that has a lock here. // then we can be test that the lock wont immediately be acquired EXPECT_FALSE(mCamera->hasExclusiveLock()); - EXPECT_EQ(OK, mCamera->exclusiveLock()); - // at this point we may or may not have the lock - // we cant be sure until we get an ACQUIRED event + EXPECT_EQ(OK, mCamera->exclusiveTryLock()); + // at this point we definitely have the lock EXPECT_EQ(OK, mListener->WaitForEvent()); EXPECT_EQ(ACQUIRED, mListener->ReadEvent()); @@ -353,7 +387,7 @@ TEST_F(ProCameraTest, LockingAsynchronous) { } // Stream directly to the screen. -TEST_F(ProCameraTest, StreamingImageSingle) { +TEST_F(ProCameraTest, DISABLED_StreamingImageSingle) { if (HasFatalFailure()) { return; } @@ -433,7 +467,7 @@ TEST_F(ProCameraTest, StreamingImageSingle) { } // Stream directly to the screen. -TEST_F(ProCameraTest, StreamingImageDual) { +TEST_F(ProCameraTest, DISABLED_StreamingImageDual) { if (HasFatalFailure()) { return; } @@ -523,6 +557,9 @@ TEST_F(ProCameraTest, CpuConsumerSingle) { if (HasFatalFailure()) { return; } + + mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED)); + int streamId = -1; EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240, TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &streamId)); @@ -585,6 +622,9 @@ TEST_F(ProCameraTest, CpuConsumerDual) { if (HasFatalFailure()) { return; } + + mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED)); + int streamId = -1; EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &streamId)); @@ -596,8 +636,6 @@ TEST_F(ProCameraTest, CpuConsumerDual) { EXPECT_NE(-1, depthStreamId); EXPECT_OK(mCamera->exclusiveTryLock()); - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(ACQUIRED, mListener->ReadEvent()); /* */ /* iterate in a loop submitting requests every frame. @@ -657,6 +695,72 @@ TEST_F(ProCameraTest, CpuConsumerDual) { EXPECT_OK(mCamera->exclusiveUnlock()); } +TEST_F(ProCameraTest, ResultReceiver) { + if (HasFatalFailure()) { + return; + } + + mListener->SetEventMask(ProEvent_Mask(RESULT_RECEIVED)); + //FIXME: if this is run right after the previous test we get BUFFER_RECEIVED + // need to filter out events at read time + + int streamId = -1; + EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, + TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &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. + */ + + camera_metadata_t *request = NULL; + EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, + /*out*/&request)); + EXPECT_NE((void*)NULL, request); + + /*FIXME*/ + if(request == NULL) request = allocate_camera_metadata(10, 100); + + // set the output streams to just this stream ID + + uint8_t allStreams[] = { streamId }; + size_t streamCount = 1; + 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) { + 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, &allStreams, + /*data_count*/streamCount)); + } + } else { + ASSERT_OK(update_camera_metadata_entry(request, entry.index, + &allStreams, /*data_count*/streamCount, &entry)); + } + + EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); + + // Consume a couple of results + for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) { + EXPECT_EQ(OK, mListener->WaitForEvent()); + EXPECT_EQ(RESULT_RECEIVED, mListener->ReadEvent()); + } + + // Done: clean up + free_camera_metadata(request); + EXPECT_OK(mCamera->deleteStream(streamId)); + EXPECT_OK(mCamera->exclusiveUnlock()); +} + } } } diff --git a/include/camera/IProCameraCallbacks.h b/include/camera/IProCameraCallbacks.h index e5be099..fc24026 100644 --- a/include/camera/IProCameraCallbacks.h +++ b/include/camera/IProCameraCallbacks.h @@ -24,6 +24,8 @@ #include #include +struct camera_metadata; + namespace android { class IProCameraCallbacks: public IInterface @@ -47,6 +49,11 @@ public: }; virtual void onLockStatusChanged(LockStatus newLockStatus) = 0; + + /** Missing by design: implementation is client-side in ProCamera.cpp **/ + // virtual void onBufferReceived(int streamId, + // const CpuConsumer::LockedBufer& buf); + virtual void onResultReceived(int32_t frameId, camera_metadata* result) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h index 4dda533..7cd9138 100644 --- a/include/camera/ProCamera.h +++ b/include/camera/ProCamera.h @@ -49,17 +49,19 @@ public: // 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 + // -- Use buf.timestamp to correlate with metadata's + // android.sensor.timestamp // -- 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; + /** + * A new metadata buffer has been received. + * -- Ownership of request passes on to the callee, free with + * free_camera_metadata. + */ + virtual void onResultReceived(int32_t frameId, camera_metadata* result) = 0; }; class ProCamera : public BnProCameraCallbacks, public IBinder::DeathRecipient @@ -189,6 +191,9 @@ protected: virtual void onLockStatusChanged( IProCameraCallbacks::LockStatus newLockStatus); + virtual void onResultReceived(int32_t frameId, + camera_metadata* result); + class DeathNotifier: public IBinder::DeathRecipient { public: diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index c7a8e4a..f76c861 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -20,7 +20,8 @@ LOCAL_SRC_FILES:= \ camera2/ZslProcessor.cpp \ camera2/BurstCapture.cpp \ camera2/JpegCompressor.cpp \ - camera2/CaptureSequencer.cpp + camera2/CaptureSequencer.cpp \ + camera2/ProFrameProcessor.cpp \ LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp index f850034..7611796 100644 --- a/services/camera/libcameraservice/ProCamera2Client.cpp +++ b/services/camera/libcameraservice/ProCamera2Client.cpp @@ -26,6 +26,7 @@ #include #include "camera2/Parameters.h" #include "ProCamera2Client.h" +#include "camera2/ProFrameProcessor.h" namespace android { using namespace camera2; @@ -82,6 +83,16 @@ status_t ProCamera2Client::initialize(camera_module_t *module) res = mDevice->setNotifyCallback(this); + String8 threadName; + mFrameProcessor = new ProFrameProcessor(this); + threadName = String8::format("PC2-%d-FrameProc", + mCameraId); + mFrameProcessor->run(threadName.string()); + + mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID, + FRAME_PROCESSOR_LISTENER_MAX_ID, + /*listener*/this); + return OK; } @@ -307,6 +318,7 @@ status_t ProCamera2Client::dump(int fd, const Vector& args) { result.append(" State: "); // TODO: print dynamic/request section from most recent requests + mFrameProcessor->dump(fd, args); #define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break; @@ -338,7 +350,12 @@ void ProCamera2Client::disconnect() { if (mDevice == 0) return; ALOGV("Camera %d: Shutting down", mCameraId); + mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID, + FRAME_PROCESSOR_LISTENER_MAX_ID, + /*listener*/this); + mFrameProcessor->requestExit(); ALOGV("Camera %d: Waiting for threads", mCameraId); + mFrameProcessor->join(); ALOGV("Camera %d: Disconnecting device", mCameraId); mDevice->disconnect(); @@ -446,4 +463,22 @@ void ProCamera2Client::SharedCameraCallbacks::clear() { mRemoteCallback.clear(); } +void ProCamera2Client::onFrameAvailable(int32_t frameId, + const CameraMetadata& frame) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + + Mutex::Autolock icl(mIProCameraUserLock); + SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + + if (mRemoteCallback != NULL) { + CameraMetadata tmp(frame); + camera_metadata_t* meta = tmp.release(); + ALOGV("%s: meta = %p ", __FUNCTION__, meta); + mRemoteCallback->onResultReceived(frameId, meta); + tmp.acquire(meta); + } + +} + } // namespace android diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h index b72fd63..dfea1e1 100644 --- a/services/camera/libcameraservice/ProCamera2Client.h +++ b/services/camera/libcameraservice/ProCamera2Client.h @@ -19,6 +19,7 @@ #include "Camera2Device.h" #include "CameraService.h" +#include "camera2/ProFrameProcessor.h" namespace android { @@ -29,7 +30,8 @@ class IMemory; */ class ProCamera2Client : public CameraService::ProClient, - public Camera2Device::NotificationListener + public Camera2Device::NotificationListener, + public camera2::ProFrameProcessor::FilteredListener { public: /** @@ -120,6 +122,10 @@ public: mutable Mutex mRemoteCallbackLock; } mSharedCameraCallbacks; +protected: + /** FilteredListener implementation **/ + virtual void onFrameAvailable(int32_t frameId, const CameraMetadata& frame); + private: /** IProCameraUser interface-related private members */ @@ -137,6 +143,10 @@ private: sp mPreviewSurface; /** Preview callback related members */ + sp mFrameProcessor; + static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0; + static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL; + /** Camera2Device instance wrapping HAL2 entry */ sp mDevice; diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp new file mode 100644 index 0000000..8d4933c --- /dev/null +++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Camera2-ProFrameProcessor" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include +#include + +#include "ProFrameProcessor.h" +#include "../Camera2Device.h" +#include "../ProCamera2Client.h" + +namespace android { +namespace camera2 { + +ProFrameProcessor::ProFrameProcessor(wp client): + Thread(false), mClient(client) { +} + +ProFrameProcessor::~ProFrameProcessor() { + ALOGV("%s: Exit", __FUNCTION__); +} + +status_t ProFrameProcessor::registerListener(int32_t minId, + int32_t maxId, wp listener) { + Mutex::Autolock l(mInputMutex); + ALOGV("%s: Registering listener for frame id range %d - %d", + __FUNCTION__, minId, maxId); + RangeListener rListener = { minId, maxId, listener }; + mRangeListeners.push_back(rListener); + return OK; +} + +status_t ProFrameProcessor::removeListener(int32_t minId, + int32_t maxId, wp listener) { + Mutex::Autolock l(mInputMutex); + List::iterator item = mRangeListeners.begin(); + while (item != mRangeListeners.end()) { + if (item->minId == minId && + item->maxId == maxId && + item->listener == listener) { + item = mRangeListeners.erase(item); + } else { + item++; + } + } + return OK; +} + +void ProFrameProcessor::dump(int fd, const Vector& args) { + String8 result(" Latest received frame:\n"); + write(fd, result.string(), result.size()); + mLastFrame.dump(fd, 2, 6); +} + +bool ProFrameProcessor::threadLoop() { + status_t res; + + sp device; + { + sp client = mClient.promote(); + if (client == 0) return false; + device = client->getCameraDevice(); + if (device == 0) return false; + } + + res = device->waitForNextFrame(kWaitDuration); + if (res == OK) { + sp client = mClient.promote(); + if (client == 0) return false; + processNewFrames(client); + } else if (res != TIMED_OUT) { + ALOGE("ProCamera2Client::ProFrameProcessor: Error waiting for new " + "frames: %s (%d)", strerror(-res), res); + } + + return true; +} + +void ProFrameProcessor::processNewFrames(sp &client) { + status_t res; + ATRACE_CALL(); + CameraMetadata frame; + while ( (res = client->getCameraDevice()->getNextFrame(&frame)) == OK) { + camera_metadata_entry_t entry; + + entry = frame.find(ANDROID_REQUEST_FRAME_COUNT); + if (entry.count == 0) { + ALOGE("%s: Camera %d: Error reading frame number", + __FUNCTION__, client->getCameraId()); + break; + } + ATRACE_INT("cam2_frame", entry.data.i32[0]); + + res = processListeners(frame, client); + if (res != OK) break; + + if (!frame.isEmpty()) { + mLastFrame.acquire(frame); + } + } + if (res != NOT_ENOUGH_DATA) { + ALOGE("%s: Camera %d: Error getting next frame: %s (%d)", + __FUNCTION__, client->getCameraId(), strerror(-res), res); + return; + } + + return; +} + +status_t ProFrameProcessor::processListeners(const CameraMetadata &frame, + sp &client) { + status_t res; + ATRACE_CALL(); + camera_metadata_ro_entry_t entry; + + entry = frame.find(ANDROID_REQUEST_ID); + if (entry.count == 0) { + ALOGE("%s: Camera %d: Error reading frame id", + __FUNCTION__, client->getCameraId()); + return BAD_VALUE; + } + int32_t frameId = entry.data.i32[0]; + + List > listeners; + { + Mutex::Autolock l(mInputMutex); + + List::iterator item = mRangeListeners.begin(); + while (item != mRangeListeners.end()) { + if (frameId >= item->minId && + frameId < item->maxId) { + sp listener = item->listener.promote(); + if (listener == 0) { + item = mRangeListeners.erase(item); + continue; + } else { + listeners.push_back(listener); + } + } + item++; + } + } + ALOGV("Got %d range listeners out of %d", listeners.size(), mRangeListeners.size()); + List >::iterator item = listeners.begin(); + for (; item != listeners.end(); item++) { + (*item)->onFrameAvailable(frameId, frame); + } + return OK; +} + +}; // namespace camera2 +}; // namespace android diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.h b/services/camera/libcameraservice/camera2/ProFrameProcessor.h new file mode 100644 index 0000000..e4094a6 --- /dev/null +++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_PROFRAMEPROCESSOR_H +#define ANDROID_SERVERS_CAMERA_CAMERA2_PROFRAMEPROCESSOR_H + +#include +#include +#include +#include +#include +#include + +struct camera_frame_metadata; + +namespace android { + +class ProCamera2Client; + +namespace camera2 { + +/* Output frame metadata processing thread. This thread waits for new + * frames from the device, and analyzes them as necessary. + */ +class ProFrameProcessor: public Thread { + public: + ProFrameProcessor(wp client); + ~ProFrameProcessor(); + + struct FilteredListener: virtual public RefBase { + virtual void onFrameAvailable(int32_t frameId, + const CameraMetadata &frame) = 0; + }; + + // Register a listener for a range of IDs [minId, maxId). Multiple listeners + // can be listening to the same range + status_t registerListener(int32_t minId, int32_t maxId, wp listener); + status_t removeListener(int32_t minId, int32_t maxId, wp listener); + + void dump(int fd, const Vector& args); + private: + static const nsecs_t kWaitDuration = 10000000; // 10 ms + wp mClient; + + virtual bool threadLoop(); + + Mutex mInputMutex; + + struct RangeListener { + int32_t minId; + int32_t maxId; + wp listener; + }; + List mRangeListeners; + + void processNewFrames(sp &client); + + status_t processListeners(const CameraMetadata &frame, + sp &client); + + CameraMetadata mLastFrame; +}; + + +}; //namespace camera2 +}; //namespace android + +#endif -- cgit v1.1