diff options
Diffstat (limited to 'camera/ProCamera.cpp')
-rw-r--r-- | camera/ProCamera.cpp | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp new file mode 100644 index 0000000..ba5a48c --- /dev/null +++ b/camera/ProCamera.cpp @@ -0,0 +1,433 @@ +/* +** +** 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_NDEBUG 0 +#define LOG_TAG "ProCamera" +#include <utils/Log.h> +#include <utils/threads.h> +#include <utils/Mutex.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/IMemory.h> + +#include <camera/ProCamera.h> +#include <camera/IProCameraUser.h> +#include <camera/IProCameraCallbacks.h> + +#include <gui/IGraphicBufferProducer.h> + +#include <system/camera_metadata.h> + +namespace android { + +sp<ProCamera> ProCamera::connect(int cameraId) +{ + return CameraBaseT::connect(cameraId, String16(), + ICameraService::USE_CALLING_UID); +} + +ProCamera::ProCamera(int cameraId) + : CameraBase(cameraId) +{ +} + +CameraTraits<ProCamera>::TCamConnectService CameraTraits<ProCamera>::fnConnectService = + &ICameraService::connectPro; + +ProCamera::~ProCamera() +{ + +} + +/* IProCameraUser's implementation */ + +// callback from camera service +void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) +{ + return CameraBaseT::notifyCallback(msgType, ext1, ext2); +} + +void ProCamera::onLockStatusChanged( + IProCameraCallbacks::LockStatus newLockStatus) +{ + ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus); + + sp<ProCameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; + } + if (listener != NULL) { + switch (newLockStatus) { + case IProCameraCallbacks::LOCK_ACQUIRED: + listener->onLockAcquired(); + break; + case IProCameraCallbacks::LOCK_RELEASED: + listener->onLockReleased(); + break; + case IProCameraCallbacks::LOCK_STOLEN: + listener->onLockStolen(); + break; + default: + ALOGE("%s: Unknown lock status: %d", + __FUNCTION__, newLockStatus); + } + } +} + +void ProCamera::onResultReceived(int32_t requestId, camera_metadata* result) { + ALOGV("%s: requestId = %d, result = %p", __FUNCTION__, requestId, result); + + sp<ProCameraListener> listener; + { + Mutex::Autolock _l(mLock); + listener = mListener; + } + + CameraMetadata tmp(result); + + // Unblock waitForFrame(id) callers + { + Mutex::Autolock al(mWaitMutex); + mMetadataReady = true; + mLatestMetadata = tmp; // make copy + mWaitCondition.broadcast(); + } + + result = tmp.release(); + + if (listener != NULL) { + listener->onResultReceived(requestId, result); + } else { + free_camera_metadata(result); + } + +} + +status_t ProCamera::exclusiveTryLock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->exclusiveTryLock(); +} +status_t ProCamera::exclusiveLock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->exclusiveLock(); +} +status_t ProCamera::exclusiveUnlock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->exclusiveUnlock(); +} +bool ProCamera::hasExclusiveLock() +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->hasExclusiveLock(); +} + +// Note that the callee gets a copy of the metadata. +int ProCamera::submitRequest(const struct camera_metadata* metadata, + bool streaming) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->submitRequest(const_cast<struct camera_metadata*>(metadata), + streaming); +} + +status_t ProCamera::cancelRequest(int requestId) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->cancelRequest(requestId); +} + +status_t ProCamera::deleteStream(int streamId) +{ + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + status_t s = c->deleteStream(streamId); + + mStreams.removeItem(streamId); + + return s; +} + +status_t ProCamera::createStream(int width, int height, int format, + const sp<Surface>& surface, + /*out*/ + int* streamId) +{ + *streamId = -1; + + ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height, + format); + + if (surface == 0) { + return BAD_VALUE; + } + + return createStream(width, height, format, + surface->getIGraphicBufferProducer(), + streamId); +} + +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); + + if (bufferProducer == 0) { + return BAD_VALUE; + } + + sp <IProCameraUser> c = mCamera; + status_t stat = c->createStream(width, height, format, bufferProducer, + streamId); + + 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*/ + sp<CpuConsumer>* cpuConsumer, + int* streamId) { + return createStreamCpu(width, height, format, heapCount, + /*synchronousMode*/true, + cpuConsumer, streamId); +} + +status_t ProCamera::createStreamCpu(int width, int height, int format, + int heapCount, + bool synchronousMode, + /*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; + + sp<BufferQueue> bq = new BufferQueue(); + sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/); + cc->setName(String8("ProCamera::mCpuConsumer")); + + sp<Surface> stc = new Surface(bq); + + 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).synchronousMode = synchronousMode; + getStreamInfo(*streamId).stc = stc; + // for lifetime management + getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener; + + cc->setFrameAvailableListener(frameAvailableListener); + + *cpuConsumer = cc; + + return s; +} + +camera_metadata* ProCamera::getCameraInfo(int cameraId) { + ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId); + + sp <IProCameraUser> c = mCamera; + if (c == 0) return NULL; + + camera_metadata* ptr = NULL; + status_t status = c->getCameraInfo(cameraId, &ptr); + + if (status != OK) { + ALOGE("%s: Failed to get camera info, error = %d", __FUNCTION__, status); + } + + return ptr; +} + +status_t ProCamera::createDefaultRequest(int templateId, + camera_metadata** request) const { + ALOGV("%s: templateId = %d", __FUNCTION__, templateId); + + sp <IProCameraUser> c = mCamera; + if (c == 0) return NO_INIT; + + return c->createDefaultRequest(templateId, request); +} + +void ProCamera::onFrameAvailable(int streamId) { + ALOGV("%s: streamId = %d", __FUNCTION__, streamId); + + sp<ProCameraListener> listener = mListener; + StreamInfo& stream = getStreamInfo(streamId); + + if (listener.get() != NULL) { + listener->onFrameAvailable(streamId, stream.cpuConsumer); + } + + // Unblock waitForFrame(id) callers + { + Mutex::Autolock al(mWaitMutex); + getStreamInfo(streamId).frameReady++; + mWaitCondition.broadcast(); + } +} + +int ProCamera::waitForFrameBuffer(int streamId) { + status_t stat = BAD_VALUE; + Mutex::Autolock al(mWaitMutex); + + StreamInfo& si = getStreamInfo(streamId); + + if (si.frameReady > 0) { + int numFrames = si.frameReady; + si.frameReady = 0; + return numFrames; + } 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 > 0) { + int numFrames = si.frameReady; + si.frameReady = 0; + return numFrames; + } + // else it was some other stream that got unblocked + } + } + + return stat; +} + +int ProCamera::dropFrameBuffer(int streamId, int count) { + StreamInfo& si = getStreamInfo(streamId); + + if (!si.cpuStream) { + return BAD_VALUE; + } else if (count < 0) { + return BAD_VALUE; + } + + if (!si.synchronousMode) { + ALOGW("%s: No need to drop frames on asynchronous streams," + " as asynchronous mode only keeps 1 latest frame around.", + __FUNCTION__); + return BAD_VALUE; + } + + int numDropped = 0; + for (int i = 0; i < count; ++i) { + CpuConsumer::LockedBuffer buffer; + if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) { + break; + } + + si.cpuConsumer->unlockBuffer(buffer); + numDropped++; + } + + return numDropped; +} + +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: 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.clear(); + + return tmp; +} + +ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) { + return mStreams.editValueFor(streamId); +} + +}; // namespace android |