From ea0d51b5ed0b474433b02414f9133b835f972569 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 28 Aug 2012 01:25:43 -0700 Subject: Camera2: Move still capture processing to separate thread. To avoid stalling HAL when it queues up new buffers for still capture, process still captures in a separate thread. Also move Camera2Heap to its own class so it can be used by the CaptureProcessor. Bug: 6243944 Change-Id: Id38e2a52367c0985812fcd4fd9af3ef90beef43f --- services/camera/libcameraservice/Android.mk | 3 +- services/camera/libcameraservice/Camera2Client.cpp | 175 +++------------ services/camera/libcameraservice/Camera2Client.h | 75 ++----- .../camera/libcameraservice/camera2/Camera2Heap.h | 55 +++++ .../libcameraservice/camera2/CaptureProcessor.cpp | 248 +++++++++++++++++++++ .../libcameraservice/camera2/CaptureProcessor.h | 79 +++++++ 6 files changed, 429 insertions(+), 206 deletions(-) create mode 100644 services/camera/libcameraservice/camera2/Camera2Heap.h create mode 100644 services/camera/libcameraservice/camera2/CaptureProcessor.cpp create mode 100644 services/camera/libcameraservice/camera2/CaptureProcessor.h (limited to 'services') diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index eac6163..9898a70 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -13,7 +13,8 @@ LOCAL_SRC_FILES:= \ Camera2Device.cpp \ camera2/CameraMetadata.cpp \ camera2/Parameters.cpp \ - camera2/FrameProcessor.cpp + camera2/FrameProcessor.cpp \ + camera2/CaptureProcessor.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 4edb49f..d296445 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -52,11 +52,11 @@ Camera2Client::Camera2Client(const sp& cameraService, int clientPid): Client(cameraService, cameraClient, cameraId, cameraFacing, clientPid), + mSharedCameraClient(cameraClient), mParameters(cameraId, cameraFacing), mPreviewStreamId(NO_STREAM), mCallbackStreamId(NO_STREAM), mCallbackHeapId(0), - mCaptureStreamId(NO_STREAM), mRecordingStreamId(NO_STREAM), mRecordingHeapCount(kDefaultRecordingHeapCount) { @@ -84,11 +84,6 @@ status_t Camera2Client::initialize(camera_module_t *module) ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId); status_t res; - mFrameProcessor = new FrameProcessor(this); - String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor", - mCameraId); - mFrameProcessor->run(frameThreadName.string()); - res = mDevice->initialize(module); if (res != OK) { ALOGE("%s: Camera %d: unable to initialize device: %s (%d)", @@ -107,6 +102,16 @@ status_t Camera2Client::initialize(camera_module_t *module) return NO_INIT; } + mFrameProcessor = new FrameProcessor(this); + String8 frameThreadName = String8::format("Camera2Client[%d]::FrameProcessor", + mCameraId); + mFrameProcessor->run(frameThreadName.string()); + + mCaptureProcessor = new CaptureProcessor(this); + String8 captureThreadName = + String8::format("Camera2Client[%d]::CaptureProcessor", mCameraId); + mCaptureProcessor->run(captureThreadName.string()); + if (gLogLevel >= 1) { ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__, mCameraId); @@ -292,7 +297,8 @@ status_t Camera2Client::dump(int fd, const Vector& args) { result.append(" Current streams:\n"); result.appendFormat(" Preview stream ID: %d\n", mPreviewStreamId); - result.appendFormat(" Capture stream ID: %d\n", mCaptureStreamId); + result.appendFormat(" Capture stream ID: %d\n", + mCaptureProcessor->getStreamId()); result.appendFormat(" Recording stream ID: %d\n", mRecordingStreamId); result.append(" Current requests:\n"); @@ -357,10 +363,7 @@ void Camera2Client::disconnect() { mPreviewStreamId = NO_STREAM; } - if (mCaptureStreamId != NO_STREAM) { - mDevice->deleteStream(mCaptureStreamId); - mCaptureStreamId = NO_STREAM; - } + mCaptureProcessor->deleteStream(); if (mRecordingStreamId != NO_STREAM) { mDevice->deleteStream(mRecordingStreamId); @@ -1028,7 +1031,7 @@ status_t Camera2Client::takePicture(int msgType) { ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId); - res = updateCaptureStream(l.mParameters); + res = mCaptureProcessor->updateStream(l.mParameters); if (res != OK) { ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); @@ -1048,32 +1051,34 @@ status_t Camera2Client::takePicture(int msgType) { CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK; bool recordingEnabled = (l.mParameters.state == Parameters::RECORD); + int captureStreamId = mCaptureProcessor->getStreamId(); + int streamSwitch = (callbacksEnabled ? 0x2 : 0x0) + (recordingEnabled ? 0x1 : 0x0); switch ( streamSwitch ) { case 0: { // No recording, callbacks - uint8_t streamIds[2] = { mPreviewStreamId, mCaptureStreamId }; + uint8_t streamIds[2] = { mPreviewStreamId, captureStreamId }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 2); break; } case 1: { // Recording uint8_t streamIds[3] = { mPreviewStreamId, mRecordingStreamId, - mCaptureStreamId }; + captureStreamId }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 3); break; } case 2: { // Callbacks uint8_t streamIds[3] = { mPreviewStreamId, mCallbackStreamId, - mCaptureStreamId }; + captureStreamId }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 3); break; } case 3: { // Both uint8_t streamIds[4] = { mPreviewStreamId, mCallbackStreamId, - mRecordingStreamId, mCaptureStreamId }; + mRecordingStreamId, captureStreamId }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 4); break; @@ -1511,6 +1516,10 @@ Camera2Client::SharedCameraClient::Lock::~Lock() { mSharedClient.mCameraClientLock.unlock(); } +Camera2Client::SharedCameraClient::SharedCameraClient(const sp&client): + mCameraClient(client) { +} + Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=( const sp&client) { Mutex::Autolock l(mCameraClientLock); @@ -1650,71 +1659,6 @@ void Camera2Client::onCallbackAvailable() { ALOGV("%s: exit", __FUNCTION__); } -void Camera2Client::onCaptureAvailable() { - ATRACE_CALL(); - status_t res; - sp captureHeap; - ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, mCameraId); - - { - SharedParameters::Lock l(mParameters); - CpuConsumer::LockedBuffer imgBuffer; - - res = mCaptureConsumer->lockNextBuffer(&imgBuffer); - if (res != OK) { - ALOGE("%s: Camera %d: Error receiving still image buffer: %s (%d)", - __FUNCTION__, mCameraId, strerror(-res), res); - return; - } - - // TODO: Signal errors here upstream - if (l.mParameters.state != Parameters::STILL_CAPTURE && - l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { - ALOGE("%s: Camera %d: Still image produced unexpectedly!", - __FUNCTION__, mCameraId); - mCaptureConsumer->unlockBuffer(imgBuffer); - return; - } - - if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) { - ALOGE("%s: Camera %d: Unexpected format for still image: " - "%x, expected %x", __FUNCTION__, mCameraId, - imgBuffer.format, - HAL_PIXEL_FORMAT_BLOB); - mCaptureConsumer->unlockBuffer(imgBuffer); - return; - } - - // TODO: Optimize this to avoid memcopy - void* captureMemory = mCaptureHeap->mHeap->getBase(); - size_t size = mCaptureHeap->mHeap->getSize(); - memcpy(captureMemory, imgBuffer.data, size); - - mCaptureConsumer->unlockBuffer(imgBuffer); - - switch (l.mParameters.state) { - case Parameters::STILL_CAPTURE: - l.mParameters.state = Parameters::STOPPED; - break; - case Parameters::VIDEO_SNAPSHOT: - l.mParameters.state = Parameters::RECORD; - break; - default: - ALOGE("%s: Camera %d: Unexpected state %d", __FUNCTION__, - mCameraId, l.mParameters.state); - break; - } - - captureHeap = mCaptureHeap; - } - // Call outside parameter locks to allow re-entrancy from notification - SharedCameraClient::Lock l(mSharedCameraClient); - if (l.mCameraClient != 0) { - l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, - captureHeap->mBuffers[0], NULL); - } -} - void Camera2Client::onRecordingFrameAvailable() { ATRACE_CALL(); status_t res; @@ -1998,75 +1942,6 @@ status_t Camera2Client::updateCallbackStream(const Parameters ¶ms) { return OK; } - -status_t Camera2Client::updateCaptureStream(const Parameters ¶ms) { - ATRACE_CALL(); - status_t res; - // Find out buffer size for JPEG - camera_metadata_ro_entry_t maxJpegSize = - mParameters.staticInfo(ANDROID_JPEG_MAX_SIZE); - if (maxJpegSize.count == 0) { - ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!", - __FUNCTION__, mCameraId); - return INVALID_OPERATION; - } - - if (mCaptureConsumer == 0) { - // Create CPU buffer queue endpoint - mCaptureConsumer = new CpuConsumer(1); - mCaptureConsumer->setFrameAvailableListener(new CaptureWaiter(this)); - mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer")); - mCaptureWindow = new SurfaceTextureClient( - mCaptureConsumer->getProducerInterface()); - // Create memory for API consumption - mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1, - "Camera2Client::CaptureHeap"); - if (mCaptureHeap->mHeap->getSize() == 0) { - ALOGE("%s: Camera %d: Unable to allocate memory for capture", - __FUNCTION__, mCameraId); - return NO_MEMORY; - } - } - - if (mCaptureStreamId != NO_STREAM) { - // Check if stream parameters have to change - uint32_t currentWidth, currentHeight; - res = mDevice->getStreamInfo(mCaptureStreamId, - ¤tWidth, ¤tHeight, 0); - if (res != OK) { - ALOGE("%s: Camera %d: Error querying capture output stream info: " - "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); - return res; - } - if (currentWidth != (uint32_t)params.pictureWidth || - currentHeight != (uint32_t)params.pictureHeight) { - res = mDevice->deleteStream(mCaptureStreamId); - if (res != OK) { - ALOGE("%s: Camera %d: Unable to delete old output stream " - "for capture: %s (%d)", __FUNCTION__, mCameraId, - strerror(-res), res); - return res; - } - mCaptureStreamId = NO_STREAM; - } - } - - if (mCaptureStreamId == NO_STREAM) { - // Create stream for HAL production - res = mDevice->createStream(mCaptureWindow, - params.pictureWidth, params.pictureHeight, - HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0], - &mCaptureStreamId); - if (res != OK) { - ALOGE("%s: Camera %d: Can't create output stream for capture: " - "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); - return res; - } - - } - return OK; -} - status_t Camera2Client::updateCaptureRequest(const Parameters ¶ms) { ATRACE_CALL(); status_t res; diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h index 3195f94..2695108 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -21,6 +21,7 @@ #include "CameraService.h" #include "camera2/Parameters.h" #include "camera2/FrameProcessor.h" +#include "camera2/CaptureProcessor.h" #include #include #include @@ -37,7 +38,9 @@ class Camera2Client : public Camera2Device::NotificationListener { public: - // ICamera interface (see ICamera for details) + /** + * ICamera interface (see ICamera for details) + */ virtual void disconnect(); virtual status_t connect(const sp& client); @@ -62,7 +65,9 @@ public: virtual String8 getParameters() const; virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); - // Interface used by CameraService + /** + * Interface used by CameraService + */ Camera2Client(const sp& cameraService, const sp& cameraClient, @@ -75,7 +80,9 @@ public: virtual status_t dump(int fd, const Vector& args); - // Interface used by CameraDevice + /** + * Interface used by Camera2Device + */ virtual void notifyError(int errorCode, int arg1, int arg2); virtual void notifyShutter(int frameNumber, nsecs_t timestamp); @@ -83,7 +90,9 @@ public: virtual void notifyAutoExposure(uint8_t newState, int triggerId); virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId); - // Interface used by independent components of Camera2Client. + /** + * Interface used by independent components of Camera2Client. + */ int getCameraId(); const sp& getCameraDevice(); @@ -102,6 +111,7 @@ public: private: SharedCameraClient &mSharedClient; }; + SharedCameraClient(const sp& client); SharedCameraClient& operator=(const sp& client); void clear(); private: @@ -109,6 +119,9 @@ public: mutable Mutex mCameraClientLock; } mSharedCameraClient; + static size_t calculateBufferSize(int width, int height, + int format, int stride); + private: /** ICamera interface-related private members */ @@ -145,8 +158,6 @@ private: /** Camera device-related private members */ - class Camera2Heap; - void setPreviewCallbackFlagL(Parameters ¶ms, int flag); status_t updateRequests(const Parameters ¶ms); @@ -181,7 +192,7 @@ private: Camera2Client *mParent; }; sp mCallbackWaiter; - sp mCallbackHeap; + sp mCallbackHeap; int mCallbackHeapId; size_t mCallbackHeapHead, mCallbackHeapFree; // Handle callback image buffers @@ -191,26 +202,9 @@ private: /* Still image capture related members */ - int mCaptureStreamId; - sp mCaptureConsumer; - sp mCaptureWindow; - // Simple listener that forwards frame available notifications from - // a CPU consumer to the capture notification - class CaptureWaiter: public CpuConsumer::FrameAvailableListener { - public: - CaptureWaiter(Camera2Client *parent) : mParent(parent) {} - void onFrameAvailable() { mParent->onCaptureAvailable(); } - private: - Camera2Client *mParent; - }; - sp mCaptureWaiter; + sp mCaptureProcessor; CameraMetadata mCaptureRequest; - sp mCaptureHeap; - // Handle captured image buffers - void onCaptureAvailable(); - status_t updateCaptureRequest(const Parameters ¶ms); - status_t updateCaptureStream(const Parameters ¶ms); /* Recording related members */ @@ -229,7 +223,7 @@ private: }; sp mRecordingWaiter; CameraMetadata mRecordingRequest; - sp mRecordingHeap; + sp mRecordingHeap; static const size_t kDefaultRecordingHeapCount = 8; size_t mRecordingHeapCount; @@ -254,32 +248,6 @@ private: // Verify that caller is the owner of the camera status_t checkPid(const char *checkLocation) const; - // Utility class for managing a set of IMemory blocks - class Camera2Heap : public RefBase { - public: - Camera2Heap(size_t buf_size, uint_t num_buffers = 1, - const char *name = NULL) : - mBufSize(buf_size), - mNumBufs(num_buffers) { - mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name); - mBuffers = new sp[mNumBufs]; - for (uint_t i = 0; i < mNumBufs; i++) - mBuffers[i] = new MemoryBase(mHeap, - i * mBufSize, - mBufSize); - } - - virtual ~Camera2Heap() - { - delete [] mBuffers; - } - - size_t mBufSize; - uint_t mNumBufs; - sp mHeap; - sp *mBuffers; - }; - // Update parameters all requests use, based on mParameters status_t updateRequestCommon(CameraMetadata *request, const Parameters ¶ms) const; @@ -291,9 +259,6 @@ private: int arrayXToNormalized(int width) const; int arrayYToNormalized(int height) const; - - static size_t calculateBufferSize(int width, int height, - int format, int stride); }; }; // namespace android diff --git a/services/camera/libcameraservice/camera2/Camera2Heap.h b/services/camera/libcameraservice/camera2/Camera2Heap.h new file mode 100644 index 0000000..9c72d76 --- /dev/null +++ b/services/camera/libcameraservice/camera2/Camera2Heap.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 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_CAMERA2HEAP_H +#define ANDROiD_SERVERS_CAMERA_CAMERA2HEAP_H + +#include +#include + +namespace android { +namespace camera2 { + +// Utility class for managing a set of IMemory blocks +class Camera2Heap : public RefBase { + public: + Camera2Heap(size_t buf_size, uint_t num_buffers = 1, + const char *name = NULL) : + mBufSize(buf_size), + mNumBufs(num_buffers) { + mHeap = new MemoryHeapBase(buf_size * num_buffers, 0, name); + mBuffers = new sp[mNumBufs]; + for (uint_t i = 0; i < mNumBufs; i++) + mBuffers[i] = new MemoryBase(mHeap, + i * mBufSize, + mBufSize); + } + + virtual ~Camera2Heap() + { + delete [] mBuffers; + } + + size_t mBufSize; + uint_t mNumBufs; + sp mHeap; + sp *mBuffers; +}; + +}; // namespace camera2 +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera2/CaptureProcessor.cpp b/services/camera/libcameraservice/camera2/CaptureProcessor.cpp new file mode 100644 index 0000000..b17f9d2 --- /dev/null +++ b/services/camera/libcameraservice/camera2/CaptureProcessor.cpp @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2012 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 "Camera2Client::CaptureProcessor" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include +#include + +#include "CaptureProcessor.h" +#include +#include "../Camera2Device.h" +#include "../Camera2Client.h" + + +namespace android { +namespace camera2 { + +CaptureProcessor::CaptureProcessor(wp client): + Thread(false), + mClient(client), + mCaptureAvailable(false), + mCaptureStreamId(NO_STREAM) { +} + +CaptureProcessor::~CaptureProcessor() { + ALOGV("%s: Exit", __FUNCTION__); +} + +void CaptureProcessor::onFrameAvailable() { + Mutex::Autolock l(mInputMutex); + if (!mCaptureAvailable) { + mCaptureAvailable = true; + mCaptureAvailableSignal.signal(); + } +} + +status_t CaptureProcessor::updateStream(const Parameters ¶ms) { + ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); + status_t res; + + Mutex::Autolock l(mInputMutex); + + sp client = mClient.promote(); + if (client == 0) return OK; + sp device = client->getCameraDevice(); + + // Find out buffer size for JPEG + camera_metadata_ro_entry_t maxJpegSize = + params.staticInfo(ANDROID_JPEG_MAX_SIZE); + if (maxJpegSize.count == 0) { + ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!", + __FUNCTION__, client->getCameraId()); + return INVALID_OPERATION; + } + + if (mCaptureConsumer == 0) { + // Create CPU buffer queue endpoint + mCaptureConsumer = new CpuConsumer(1); + mCaptureConsumer->setFrameAvailableListener(this); + mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer")); + mCaptureWindow = new SurfaceTextureClient( + mCaptureConsumer->getProducerInterface()); + // Create memory for API consumption + mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1, + "Camera2Client::CaptureHeap"); + if (mCaptureHeap->mHeap->getSize() == 0) { + ALOGE("%s: Camera %d: Unable to allocate memory for capture", + __FUNCTION__, client->getCameraId()); + return NO_MEMORY; + } + } + + if (mCaptureStreamId != NO_STREAM) { + // Check if stream parameters have to change + uint32_t currentWidth, currentHeight; + res = device->getStreamInfo(mCaptureStreamId, + ¤tWidth, ¤tHeight, 0); + if (res != OK) { + ALOGE("%s: Camera %d: Error querying capture output stream info: " + "%s (%d)", __FUNCTION__, + client->getCameraId(), strerror(-res), res); + return res; + } + if (currentWidth != (uint32_t)params.pictureWidth || + currentHeight != (uint32_t)params.pictureHeight) { + res = device->deleteStream(mCaptureStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to delete old output stream " + "for capture: %s (%d)", __FUNCTION__, + client->getCameraId(), strerror(-res), res); + return res; + } + mCaptureStreamId = NO_STREAM; + } + } + + if (mCaptureStreamId == NO_STREAM) { + // Create stream for HAL production + res = device->createStream(mCaptureWindow, + params.pictureWidth, params.pictureHeight, + HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0], + &mCaptureStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Can't create output stream for capture: " + "%s (%d)", __FUNCTION__, client->getCameraId(), + strerror(-res), res); + return res; + } + + } + return OK; +} + +status_t CaptureProcessor::deleteStream() { + ATRACE_CALL(); + status_t res; + + Mutex::Autolock l(mInputMutex); + + if (mCaptureStreamId != NO_STREAM) { + sp client = mClient.promote(); + if (client == 0) return OK; + sp device = client->getCameraDevice(); + + device->deleteStream(mCaptureStreamId); + mCaptureStreamId = NO_STREAM; + } + return OK; +} + +int CaptureProcessor::getStreamId() const { + Mutex::Autolock l(mInputMutex); + return mCaptureStreamId; +} + +void CaptureProcessor::dump(int fd, const Vector& args) { +} + +bool CaptureProcessor::threadLoop() { + status_t res; + + { + Mutex::Autolock l(mInputMutex); + while (!mCaptureAvailable) { + res = mCaptureAvailableSignal.waitRelative(mInputMutex, + kWaitDuration); + if (res == TIMED_OUT) return true; + } + mCaptureAvailable = false; + } + + do { + sp client = mClient.promote(); + if (client == 0) return false; + res = processNewCapture(client); + } while (res == OK); + + return true; +} + +status_t CaptureProcessor::processNewCapture(sp &client) { + ATRACE_CALL(); + status_t res; + sp captureHeap; + + CpuConsumer::LockedBuffer imgBuffer; + + res = mCaptureConsumer->lockNextBuffer(&imgBuffer); + if (res != OK) { + if (res != BAD_VALUE) { + ALOGE("%s: Camera %d: Error receiving still image buffer: " + "%s (%d)", __FUNCTION__, + client->getCameraId(), strerror(-res), res); + } + return res; + } + + ALOGV("%s: Camera %d: Still capture available", __FUNCTION__, + client->getCameraId()); + + // TODO: Signal errors here upstream + { + SharedParameters::Lock l(client->getParameters()); + + switch (l.mParameters.state) { + case Parameters::STILL_CAPTURE: + l.mParameters.state = Parameters::STOPPED; + break; + case Parameters::VIDEO_SNAPSHOT: + l.mParameters.state = Parameters::RECORD; + break; + default: + ALOGE("%s: Camera %d: Still image produced unexpectedly " + "in state %s!", + __FUNCTION__, client->getCameraId(), + Parameters::getStateName(l.mParameters.state)); + mCaptureConsumer->unlockBuffer(imgBuffer); + return BAD_VALUE; + } + } + + if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) { + ALOGE("%s: Camera %d: Unexpected format for still image: " + "%x, expected %x", __FUNCTION__, client->getCameraId(), + imgBuffer.format, + HAL_PIXEL_FORMAT_BLOB); + mCaptureConsumer->unlockBuffer(imgBuffer); + return OK; + } + + // TODO: Optimize this to avoid memcopy + void* captureMemory = mCaptureHeap->mHeap->getBase(); + size_t size = mCaptureHeap->mHeap->getSize(); + memcpy(captureMemory, imgBuffer.data, size); + + mCaptureConsumer->unlockBuffer(imgBuffer); + + captureHeap = mCaptureHeap; + + Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient); + ALOGV("%s: Sending still image to client", __FUNCTION__); + if (l.mCameraClient != 0) { + l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, + captureHeap->mBuffers[0], NULL); + } else { + ALOGV("%s: No client!", __FUNCTION__); + } + return OK; +} + +}; // namespace camera2 +}; // namespace android diff --git a/services/camera/libcameraservice/camera2/CaptureProcessor.h b/services/camera/libcameraservice/camera2/CaptureProcessor.h new file mode 100644 index 0000000..8e35739 --- /dev/null +++ b/services/camera/libcameraservice/camera2/CaptureProcessor.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 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_CAPTUREPROCESSOR_H +#define ANDROID_SERVERS_CAMERA_CAMERA2_CAPTUREPROCESSOR_H + +#include +#include +#include +#include +#include +#include +#include "Parameters.h" +#include "CameraMetadata.h" +#include "Camera2Heap.h" + +namespace android { + +class Camera2Client; + +namespace camera2 { + +/*** + * Still image capture output image processing + */ +class CaptureProcessor: + public Thread, public CpuConsumer::FrameAvailableListener { + public: + CaptureProcessor(wp client); + ~CaptureProcessor(); + + void onFrameAvailable(); + + status_t updateStream(const Parameters ¶ms); + status_t deleteStream(); + int getStreamId() const; + + void dump(int fd, const Vector& args); + private: + static const nsecs_t kWaitDuration = 10000000; // 10 ms + wp mClient; + + mutable Mutex mInputMutex; + bool mCaptureAvailable; + Condition mCaptureAvailableSignal; + + enum { + NO_STREAM = -1 + }; + + int mCaptureStreamId; + sp mCaptureConsumer; + sp mCaptureWindow; + sp mCaptureHeap; + + virtual bool threadLoop(); + + status_t processNewCapture(sp &client); + +}; + + +}; //namespace camera2 +}; //namespace android + +#endif -- cgit v1.1