From 7b82efe7a376c882f8f938e1c41b8311a8cdda4a Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Thu, 25 Jul 2013 17:12:35 -0700 Subject: Camera: Rename new API to camera2, rearrange camera service - Support API rename from photography to camera2 - Reorganize camera service files - API support files to api1/, api2/, api_pro/ - HAL device support files into device{1,2,3}/ - Common files into common/ - Camera service remains at top-level Change-Id: Ie474c12536f543832fba0a2dc936ac4fd39fe6a9 --- .../libcameraservice/common/Camera2ClientBase.cpp | 333 +++++++++++++++++++++ .../libcameraservice/common/Camera2ClientBase.h | 133 ++++++++ .../libcameraservice/common/CameraDeviceBase.cpp | 30 ++ .../libcameraservice/common/CameraDeviceBase.h | 216 +++++++++++++ .../libcameraservice/common/FrameProcessorBase.cpp | 176 +++++++++++ .../libcameraservice/common/FrameProcessorBase.h | 84 ++++++ 6 files changed, 972 insertions(+) create mode 100644 services/camera/libcameraservice/common/Camera2ClientBase.cpp create mode 100644 services/camera/libcameraservice/common/Camera2ClientBase.h create mode 100644 services/camera/libcameraservice/common/CameraDeviceBase.cpp create mode 100644 services/camera/libcameraservice/common/CameraDeviceBase.h create mode 100644 services/camera/libcameraservice/common/FrameProcessorBase.cpp create mode 100644 services/camera/libcameraservice/common/FrameProcessorBase.h (limited to 'services/camera/libcameraservice/common') diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp new file mode 100644 index 0000000..060e2a2 --- /dev/null +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -0,0 +1,333 @@ +/* + * 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 "Camera2ClientBase" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include +#include + +#include +#include +#include + +#include "common/Camera2ClientBase.h" + +#include "api2/CameraDeviceClient.h" + +#include "CameraDeviceFactory.h" + +namespace android { +using namespace camera2; + +static int getCallingPid() { + return IPCThreadState::self()->getCallingPid(); +} + +// Interface used by CameraService + +template +Camera2ClientBase::Camera2ClientBase( + const sp& cameraService, + const sp& remoteCallback, + const String16& clientPackageName, + int cameraId, + int cameraFacing, + int clientPid, + uid_t clientUid, + int servicePid): + TClientBase(cameraService, remoteCallback, clientPackageName, + cameraId, cameraFacing, clientPid, clientUid, servicePid), + mSharedCameraCallbacks(remoteCallback) +{ + ALOGI("Camera %d: Opened", cameraId); + + mDevice = CameraDeviceFactory::createDevice(cameraId); + LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here."); +} + +template +status_t Camera2ClientBase::checkPid(const char* checkLocation) + const { + + int callingPid = getCallingPid(); + if (callingPid == TClientBase::mClientPid) return NO_ERROR; + + ALOGE("%s: attempt to use a locked camera from a different process" + " (old pid %d, new pid %d)", checkLocation, TClientBase::mClientPid, callingPid); + return PERMISSION_DENIED; +} + +template +status_t Camera2ClientBase::initialize(camera_module_t *module) { + ATRACE_CALL(); + ALOGV("%s: Initializing client for camera %d", __FUNCTION__, + TClientBase::mCameraId); + status_t res; + + // Verify ops permissions + res = TClientBase::startCameraOps(); + if (res != OK) { + return res; + } + + if (mDevice == NULL) { + ALOGE("%s: Camera %d: No device connected", + __FUNCTION__, TClientBase::mCameraId); + return NO_INIT; + } + + res = mDevice->initialize(module); + if (res != OK) { + ALOGE("%s: Camera %d: unable to initialize device: %s (%d)", + __FUNCTION__, TClientBase::mCameraId, strerror(-res), res); + return NO_INIT; + } + + res = mDevice->setNotifyCallback(this); + + return OK; +} + +template +Camera2ClientBase::~Camera2ClientBase() { + ATRACE_CALL(); + + TClientBase::mDestructionStarted = true; + + TClientBase::finishCameraOps(); + + disconnect(); + + ALOGI("Closed Camera %d", TClientBase::mCameraId); +} + +template +status_t Camera2ClientBase::dump(int fd, + const Vector& args) { + String8 result; + result.appendFormat("Camera2ClientBase[%d] (%p) PID: %d, dump:\n", + TClientBase::mCameraId, + TClientBase::getRemoteCallback()->asBinder().get(), + TClientBase::mClientPid); + result.append(" State: "); + + write(fd, result.string(), result.size()); + // TODO: print dynamic/request section from most recent requests + + return dumpDevice(fd, args); +} + +template +status_t Camera2ClientBase::dumpDevice( + int fd, + const Vector& args) { + String8 result; + + result = " Device dump:\n"; + write(fd, result.string(), result.size()); + + if (!mDevice.get()) { + result = " *** Device is detached\n"; + write(fd, result.string(), result.size()); + return NO_ERROR; + } + + status_t res = mDevice->dump(fd, args); + if (res != OK) { + result = String8::format(" Error dumping device: %s (%d)", + strerror(-res), res); + write(fd, result.string(), result.size()); + } + + return NO_ERROR; +} + +// ICameraClient2BaseUser interface + + +template +void Camera2ClientBase::disconnect() { + ATRACE_CALL(); + Mutex::Autolock icl(mBinderSerializationLock); + + // Allow both client and the media server to disconnect at all times + int callingPid = getCallingPid(); + if (callingPid != TClientBase::mClientPid && + callingPid != TClientBase::mServicePid) return; + + ALOGV("Camera %d: Shutting down", TClientBase::mCameraId); + + detachDevice(); + + CameraService::BasicClient::disconnect(); + + ALOGV("Camera %d: Shut down complete complete", TClientBase::mCameraId); +} + +template +void Camera2ClientBase::detachDevice() { + if (mDevice == 0) return; + mDevice->disconnect(); + + mDevice.clear(); + + ALOGV("Camera %d: Detach complete", TClientBase::mCameraId); +} + +template +status_t Camera2ClientBase::connect( + const sp& client) { + ATRACE_CALL(); + ALOGV("%s: E", __FUNCTION__); + Mutex::Autolock icl(mBinderSerializationLock); + + if (TClientBase::mClientPid != 0 && + getCallingPid() != TClientBase::mClientPid) { + + ALOGE("%s: Camera %d: Connection attempt from pid %d; " + "current locked to pid %d", + __FUNCTION__, + TClientBase::mCameraId, + getCallingPid(), + TClientBase::mClientPid); + return BAD_VALUE; + } + + TClientBase::mClientPid = getCallingPid(); + + TClientBase::mRemoteCallback = client; + mSharedCameraCallbacks = client; + + return OK; +} + +/** Device-related methods */ + +template +void Camera2ClientBase::notifyError(int errorCode, int arg1, + int arg2) { + ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode, + arg1, arg2); +} + +template +void Camera2ClientBase::notifyShutter(int frameNumber, + nsecs_t timestamp) { + (void)frameNumber; + (void)timestamp; + + ALOGV("%s: Shutter notification for frame %d at time %lld", __FUNCTION__, + frameNumber, timestamp); +} + +template +void Camera2ClientBase::notifyAutoFocus(uint8_t newState, + int triggerId) { + (void)newState; + (void)triggerId; + + ALOGV("%s: Autofocus state now %d, last trigger %d", + __FUNCTION__, newState, triggerId); + + typename SharedCameraCallbacks::Lock l(mSharedCameraCallbacks); + if (l.mRemoteCallback != 0) { + l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS_MOVE, 1, 0); + } + if (l.mRemoteCallback != 0) { + l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS, 1, 0); + } +} + +template +void Camera2ClientBase::notifyAutoExposure(uint8_t newState, + int triggerId) { + (void)newState; + (void)triggerId; + + ALOGV("%s: Autoexposure state now %d, last trigger %d", + __FUNCTION__, newState, triggerId); +} + +template +void Camera2ClientBase::notifyAutoWhitebalance(uint8_t newState, + int triggerId) { + (void)newState; + (void)triggerId; + + ALOGV("%s: Auto-whitebalance state now %d, last trigger %d", + __FUNCTION__, newState, triggerId); +} + +template +int Camera2ClientBase::getCameraId() const { + return TClientBase::mCameraId; +} + +template +const sp& Camera2ClientBase::getCameraDevice() { + return mDevice; +} + +template +const sp& Camera2ClientBase::getCameraService() { + return TClientBase::mCameraService; +} + +template +Camera2ClientBase::SharedCameraCallbacks::Lock::Lock( + SharedCameraCallbacks &client) : + + mRemoteCallback(client.mRemoteCallback), + mSharedClient(client) { + + mSharedClient.mRemoteCallbackLock.lock(); +} + +template +Camera2ClientBase::SharedCameraCallbacks::Lock::~Lock() { + mSharedClient.mRemoteCallbackLock.unlock(); +} + +template +Camera2ClientBase::SharedCameraCallbacks::SharedCameraCallbacks( + const sp&client) : + + mRemoteCallback(client) { +} + +template +typename Camera2ClientBase::SharedCameraCallbacks& +Camera2ClientBase::SharedCameraCallbacks::operator=( + const sp&client) { + + Mutex::Autolock l(mRemoteCallbackLock); + mRemoteCallback = client; + return *this; +} + +template +void Camera2ClientBase::SharedCameraCallbacks::clear() { + Mutex::Autolock l(mRemoteCallbackLock); + mRemoteCallback.clear(); +} + +template class Camera2ClientBase; +template class Camera2ClientBase; +template class Camera2ClientBase; + +} // namespace android diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h new file mode 100644 index 0000000..d23197c --- /dev/null +++ b/services/camera/libcameraservice/common/Camera2ClientBase.h @@ -0,0 +1,133 @@ +/* + * 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_CAMERA2CLIENT_BASE_H +#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H + +#include "common/CameraDeviceBase.h" + +namespace android { + +class IMemory; + +class CameraService; + +template +class Camera2ClientBase : + public TClientBase, + public CameraDeviceBase::NotificationListener +{ +public: + typedef typename TClientBase::TCamCallbacks TCamCallbacks; + + /** + * Base binder interface (see ICamera/IProCameraUser for details) + */ + virtual status_t connect(const sp& callbacks); + virtual void disconnect(); + + /** + * Interface used by CameraService + */ + + // TODO: too many params, move into a ClientArgs + Camera2ClientBase(const sp& cameraService, + const sp& remoteCallback, + const String16& clientPackageName, + int cameraId, + int cameraFacing, + int clientPid, + uid_t clientUid, + int servicePid); + virtual ~Camera2ClientBase(); + + virtual status_t initialize(camera_module_t *module); + virtual status_t dump(int fd, const Vector& args); + + /** + * CameraDeviceBase::NotificationListener implementation + */ + + virtual void notifyError(int errorCode, int arg1, int arg2); + virtual void notifyShutter(int frameNumber, nsecs_t timestamp); + virtual void notifyAutoFocus(uint8_t newState, int triggerId); + virtual void notifyAutoExposure(uint8_t newState, int triggerId); + virtual void notifyAutoWhitebalance(uint8_t newState, + int triggerId); + + + int getCameraId() const; + const sp& + getCameraDevice(); + const sp& + getCameraService(); + + /** + * Interface used by independent components of CameraClient2Base. + */ + + // Simple class to ensure that access to TCamCallbacks is serialized + // by requiring mRemoteCallbackLock to be locked before access to + // mRemoteCallback is possible. + class SharedCameraCallbacks { + public: + class Lock { + public: + Lock(SharedCameraCallbacks &client); + ~Lock(); + sp &mRemoteCallback; + private: + SharedCameraCallbacks &mSharedClient; + }; + SharedCameraCallbacks(const sp& client); + SharedCameraCallbacks& operator=(const sp& client); + void clear(); + private: + sp mRemoteCallback; + mutable Mutex mRemoteCallbackLock; + } mSharedCameraCallbacks; + +protected: + + virtual sp asBinderWrapper() { + return IInterface::asBinder(); + } + + virtual status_t dumpDevice(int fd, const Vector& args); + + /** Binder client interface-related private members */ + + // Mutex that must be locked by methods implementing the binder client + // interface. Ensures serialization between incoming client calls. + // All methods in this class hierarchy that append 'L' to the name assume + // that mBinderSerializationLock is locked when they're called + mutable Mutex mBinderSerializationLock; + + /** CameraDeviceBase instance wrapping HAL2+ entry */ + + sp mDevice; + + /** Utility members */ + + // Verify that caller is the owner of the camera + status_t checkPid(const char *checkLocation) const; + + virtual void detachDevice(); +}; + +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.cpp b/services/camera/libcameraservice/common/CameraDeviceBase.cpp new file mode 100644 index 0000000..6c4e87f --- /dev/null +++ b/services/camera/libcameraservice/common/CameraDeviceBase.cpp @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#include "CameraDeviceBase.h" + +namespace android { + +/** + * Base class destructors + */ +CameraDeviceBase::~CameraDeviceBase() { +} + +CameraDeviceBase::NotificationListener::~NotificationListener() { +} + +} // namespace android diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h new file mode 100644 index 0000000..aa92bec --- /dev/null +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -0,0 +1,216 @@ +/* + * 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_CAMERADEVICEBASE_H +#define ANDROID_SERVERS_CAMERA_CAMERADEVICEBASE_H + +#include +#include +#include +#include +#include + +#include "hardware/camera2.h" +#include "camera/CameraMetadata.h" + +namespace android { + +/** + * Base interface for version >= 2 camera device classes, which interface to + * camera HAL device versions >= 2. + */ +class CameraDeviceBase : public virtual RefBase { + public: + virtual ~CameraDeviceBase(); + + /** + * The device's camera ID + */ + virtual int getId() const = 0; + + virtual status_t initialize(camera_module_t *module) = 0; + virtual status_t disconnect() = 0; + + virtual status_t dump(int fd, const Vector& args) = 0; + + /** + * The device's static characteristics metadata buffer + */ + virtual const CameraMetadata& info() const = 0; + + /** + * Submit request for capture. The CameraDevice takes ownership of the + * passed-in buffer. + */ + virtual status_t capture(CameraMetadata &request) = 0; + + /** + * Submit request for streaming. The CameraDevice makes a copy of the + * passed-in buffer and the caller retains ownership. + */ + virtual status_t setStreamingRequest(const CameraMetadata &request) = 0; + + /** + * Clear the streaming request slot. + */ + virtual status_t clearStreamingRequest() = 0; + + /** + * Wait until a request with the given ID has been dequeued by the + * HAL. Returns TIMED_OUT if the timeout duration is reached. Returns + * immediately if the latest request received by the HAL has this id. + */ + virtual status_t waitUntilRequestReceived(int32_t requestId, + nsecs_t timeout) = 0; + + /** + * Create an output stream of the requested size and format. + * + * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects + * an appropriate format; it can be queried with getStreamInfo. + * + * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be + * equal to the size in bytes of the buffers to allocate for the stream. For + * other formats, the size parameter is ignored. + */ + virtual status_t createStream(sp consumer, + uint32_t width, uint32_t height, int format, size_t size, + int *id) = 0; + + /** + * Create an input reprocess stream that uses buffers from an existing + * output stream. + */ + virtual status_t createReprocessStreamFromStream(int outputId, int *id) = 0; + + /** + * Get information about a given stream. + */ + virtual status_t getStreamInfo(int id, + uint32_t *width, uint32_t *height, uint32_t *format) = 0; + + /** + * Set stream gralloc buffer transform + */ + virtual status_t setStreamTransform(int id, int transform) = 0; + + /** + * Delete stream. Must not be called if there are requests in flight which + * reference that stream. + */ + virtual status_t deleteStream(int id) = 0; + + /** + * Delete reprocess stream. Must not be called if there are requests in + * flight which reference that stream. + */ + virtual status_t deleteReprocessStream(int id) = 0; + + /** + * Create a metadata buffer with fields that the HAL device believes are + * best for the given use case + */ + virtual status_t createDefaultRequest(int templateId, + CameraMetadata *request) = 0; + + /** + * Wait until all requests have been processed. Returns INVALID_OPERATION if + * the streaming slot is not empty, or TIMED_OUT if the requests haven't + * finished processing in 10 seconds. + */ + virtual status_t waitUntilDrained() = 0; + + /** + * Abstract class for HAL notification listeners + */ + class NotificationListener { + public: + // Refer to the Camera2 HAL definition for notification definitions + virtual void notifyError(int errorCode, int arg1, int arg2) = 0; + virtual void notifyShutter(int frameNumber, nsecs_t timestamp) = 0; + virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0; + virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0; + virtual void notifyAutoWhitebalance(uint8_t newState, + int triggerId) = 0; + protected: + virtual ~NotificationListener(); + }; + + /** + * Connect HAL notifications to a listener. Overwrites previous + * listener. Set to NULL to stop receiving notifications. + */ + virtual status_t setNotifyCallback(NotificationListener *listener) = 0; + + /** + * Whether the device supports calling notifyAutofocus, notifyAutoExposure, + * and notifyAutoWhitebalance; if this returns false, the client must + * synthesize these notifications from received frame metadata. + */ + virtual bool willNotify3A() = 0; + + /** + * Wait for a new frame to be produced, with timeout in nanoseconds. + * Returns TIMED_OUT when no frame produced within the specified duration + */ + virtual status_t waitForNextFrame(nsecs_t timeout) = 0; + + /** + * Get next metadata frame from the frame queue. Returns NULL if the queue + * is empty; caller takes ownership of the metadata buffer. + */ + virtual status_t getNextFrame(CameraMetadata *frame) = 0; + + /** + * Trigger auto-focus. The latest ID used in a trigger autofocus or cancel + * autofocus call will be returned by the HAL in all subsequent AF + * notifications. + */ + virtual status_t triggerAutofocus(uint32_t id) = 0; + + /** + * Cancel auto-focus. The latest ID used in a trigger autofocus/cancel + * autofocus call will be returned by the HAL in all subsequent AF + * notifications. + */ + virtual status_t triggerCancelAutofocus(uint32_t id) = 0; + + /** + * Trigger pre-capture metering. The latest ID used in a trigger pre-capture + * call will be returned by the HAL in all subsequent AE and AWB + * notifications. + */ + virtual status_t triggerPrecaptureMetering(uint32_t id) = 0; + + /** + * Abstract interface for clients that want to listen to reprocess buffer + * release events + */ + struct BufferReleasedListener : public virtual RefBase { + virtual void onBufferReleased(buffer_handle_t *handle) = 0; + }; + + /** + * Push a buffer to be reprocessed into a reprocessing stream, and + * provide a listener to call once the buffer is returned by the HAL + */ + virtual status_t pushReprocessBuffer(int reprocessStreamId, + buffer_handle_t *buffer, wp listener) = 0; +}; + +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp new file mode 100644 index 0000000..10bc6ea --- /dev/null +++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp @@ -0,0 +1,176 @@ +/* + * 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-FrameProcessorBase" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include +#include + +#include "common/FrameProcessorBase.h" +#include "common/CameraDeviceBase.h" + +namespace android { +namespace camera2 { + +FrameProcessorBase::FrameProcessorBase(wp device) : + Thread(/*canCallJava*/false), + mDevice(device) { +} + +FrameProcessorBase::~FrameProcessorBase() { + ALOGV("%s: Exit", __FUNCTION__); +} + +status_t FrameProcessorBase::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 FrameProcessorBase::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 FrameProcessorBase::dump(int fd, const Vector& /*args*/) { + String8 result(" Latest received frame:\n"); + write(fd, result.string(), result.size()); + mLastFrame.dump(fd, 2, 6); +} + +bool FrameProcessorBase::threadLoop() { + status_t res; + + sp device; + { + device = mDevice.promote(); + if (device == 0) return false; + } + + res = device->waitForNextFrame(kWaitDuration); + if (res == OK) { + processNewFrames(device); + } else if (res != TIMED_OUT) { + ALOGE("FrameProcessorBase: Error waiting for new " + "frames: %s (%d)", strerror(-res), res); + } + + return true; +} + +void FrameProcessorBase::processNewFrames(const sp &device) { + status_t res; + ATRACE_CALL(); + CameraMetadata frame; + + ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId()); + + while ( (res = device->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__, device->getId()); + break; + } + ATRACE_INT("cam2_frame", entry.data.i32[0]); + + if (!processSingleFrame(frame, device)) { + break; + } + + if (!frame.isEmpty()) { + mLastFrame.acquire(frame); + } + } + if (res != NOT_ENOUGH_DATA) { + ALOGE("%s: Camera %d: Error getting next frame: %s (%d)", + __FUNCTION__, device->getId(), strerror(-res), res); + return; + } + + return; +} + +bool FrameProcessorBase::processSingleFrame(CameraMetadata &frame, + const sp &device) { + ALOGV("%s: Camera %d: Process single frame (is empty? %d)", + __FUNCTION__, device->getId(), frame.isEmpty()); + return processListeners(frame, device) == OK; +} + +status_t FrameProcessorBase::processListeners(const CameraMetadata &frame, + const sp &device) { + 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__, device->getId()); + 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/common/FrameProcessorBase.h b/services/camera/libcameraservice/common/FrameProcessorBase.h new file mode 100644 index 0000000..1e46beb --- /dev/null +++ b/services/camera/libcameraservice/common/FrameProcessorBase.h @@ -0,0 +1,84 @@ +/* + * 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 + +namespace android { + +class CameraDeviceBase; + +namespace camera2 { + +/* Output frame metadata processing thread. This thread waits for new + * frames from the device, and analyzes them as necessary. + */ +class FrameProcessorBase: public Thread { + public: + FrameProcessorBase(wp device); + virtual ~FrameProcessorBase(); + + 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); + protected: + static const nsecs_t kWaitDuration = 10000000; // 10 ms + wp mDevice; + + virtual bool threadLoop(); + + Mutex mInputMutex; + + struct RangeListener { + int32_t minId; + int32_t maxId; + wp listener; + }; + List mRangeListeners; + + void processNewFrames(const sp &device); + + virtual bool processSingleFrame(CameraMetadata &frame, + const sp &device); + + status_t processListeners(const CameraMetadata &frame, + const sp &device); + + CameraMetadata mLastFrame; +}; + + +}; //namespace camera2 +}; //namespace android + +#endif -- cgit v1.1