diff options
8 files changed, 833 insertions, 423 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index eac6163..1370c62 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -13,7 +13,9 @@ LOCAL_SRC_FILES:= \ Camera2Device.cpp \ camera2/CameraMetadata.cpp \ camera2/Parameters.cpp \ - camera2/FrameProcessor.cpp + camera2/FrameProcessor.cpp \ + camera2/CaptureProcessor.cpp \ + camera2/CallbackProcessor.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 4edb49f..acd290d 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -52,11 +52,9 @@ Camera2Client::Camera2Client(const sp<CameraService>& 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 +82,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 +100,21 @@ 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()); + + mCallbackProcessor = new CallbackProcessor(this); + String8 callbackThreadName = + String8::format("Camera2Client[%d]::CallbackProcessor", mCameraId); + mCallbackProcessor->run(callbackThreadName.string()); + if (gLogLevel >= 1) { ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__, mCameraId); @@ -292,7 +300,8 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& 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,20 +366,14 @@ 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); mRecordingStreamId = NO_STREAM; } - if (mCallbackStreamId != NO_STREAM) { - mDevice->deleteStream(mCallbackStreamId); - mCallbackStreamId = NO_STREAM; - } + mCallbackProcessor->deleteStream(); mDevice.clear(); SharedParameters::Lock l(mParameters); @@ -613,7 +616,7 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { bool callbacksEnabled = params.previewCallbackFlags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK; if (callbacksEnabled) { - res = updateCallbackStream(params); + res = mCallbackProcessor->updateStream(params); if (res != OK) { ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); @@ -632,7 +635,7 @@ status_t Camera2Client::startPreviewL(Parameters ¶ms, bool restart) { if (callbacksEnabled) { uint8_t outputStreams[2] = - { mPreviewStreamId, mCallbackStreamId }; + { mPreviewStreamId, mCallbackProcessor->getStreamId() }; res = mPreviewRequest.update( ANDROID_REQUEST_OUTPUT_STREAMS, outputStreams, 2); @@ -796,7 +799,7 @@ status_t Camera2Client::startRecordingL(Parameters ¶ms, bool restart) { bool callbacksEnabled = params.previewCallbackFlags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK; if (callbacksEnabled) { - res = updateCallbackStream(params); + res = mCallbackProcessor->updateStream(params); if (res != OK) { ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); @@ -815,7 +818,8 @@ status_t Camera2Client::startRecordingL(Parameters ¶ms, bool restart) { if (callbacksEnabled) { uint8_t outputStreams[3] = - { mPreviewStreamId, mRecordingStreamId, mCallbackStreamId }; + { mPreviewStreamId, mRecordingStreamId, + mCallbackProcessor->getStreamId() }; res = mRecordingRequest.update( ANDROID_REQUEST_OUTPUT_STREAMS, outputStreams, 3); @@ -1028,7 +1032,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 +1052,47 @@ 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 }; + uint8_t streamIds[3] = { + mPreviewStreamId, + mRecordingStreamId, + captureStreamId + }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 3); break; } case 2: { // Callbacks - uint8_t streamIds[3] = { mPreviewStreamId, mCallbackStreamId, - mCaptureStreamId }; + uint8_t streamIds[3] = { + mPreviewStreamId, + mCallbackProcessor->getStreamId(), + captureStreamId + }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 3); break; } case 3: { // Both - uint8_t streamIds[4] = { mPreviewStreamId, mCallbackStreamId, - mRecordingStreamId, mCaptureStreamId }; + uint8_t streamIds[4] = { + mPreviewStreamId, + mCallbackProcessor->getStreamId(), + mRecordingStreamId, + captureStreamId + }; res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS, streamIds, 4); break; @@ -1511,6 +1530,10 @@ Camera2Client::SharedCameraClient::Lock::~Lock() { mSharedClient.mCameraClientLock.unlock(); } +Camera2Client::SharedCameraClient::SharedCameraClient(const sp<ICameraClient>&client): + mCameraClient(client) { +} + Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=( const sp<ICameraClient>&client) { Mutex::Autolock l(mCameraClientLock); @@ -1523,198 +1546,6 @@ void Camera2Client::SharedCameraClient::clear() { mCameraClient.clear(); } -void Camera2Client::onCallbackAvailable() { - ATRACE_CALL(); - status_t res; - ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, mCameraId); - - int callbackHeapId; - sp<Camera2Heap> callbackHeap; - size_t heapIdx; - - CpuConsumer::LockedBuffer imgBuffer; - ALOGV("%s: Getting buffer", __FUNCTION__); - res = mCallbackConsumer->lockNextBuffer(&imgBuffer); - if (res != OK) { - ALOGE("%s: Camera %d: Error receiving next callback buffer: " - "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); - return; - } - - { - SharedParameters::Lock l(mParameters); - - if ( l.mParameters.state != Parameters::PREVIEW - && l.mParameters.state != Parameters::RECORD - && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { - ALOGV("%s: Camera %d: No longer streaming", - __FUNCTION__, mCameraId); - mCallbackConsumer->unlockBuffer(imgBuffer); - return; - } - - if (! (l.mParameters.previewCallbackFlags & - CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) { - ALOGV("%s: No longer enabled, dropping", __FUNCTION__); - mCallbackConsumer->unlockBuffer(imgBuffer); - return; - } - if ((l.mParameters.previewCallbackFlags & - CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) && - !l.mParameters.previewCallbackOneShot) { - ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__); - mCallbackConsumer->unlockBuffer(imgBuffer); - return; - } - - if (imgBuffer.format != l.mParameters.previewFormat) { - ALOGE("%s: Camera %d: Unexpected format for callback: " - "%x, expected %x", __FUNCTION__, mCameraId, - imgBuffer.format, l.mParameters.previewFormat); - mCallbackConsumer->unlockBuffer(imgBuffer); - return; - } - - size_t bufferSize = calculateBufferSize(imgBuffer.width, imgBuffer.height, - imgBuffer.format, imgBuffer.stride); - size_t currentBufferSize = (mCallbackHeap == 0) ? - 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount); - if (bufferSize != currentBufferSize) { - mCallbackHeap.clear(); - mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount, - "Camera2Client::CallbackHeap"); - if (mCallbackHeap->mHeap->getSize() == 0) { - ALOGE("%s: Camera %d: Unable to allocate memory for callbacks", - __FUNCTION__, mCameraId); - mCallbackConsumer->unlockBuffer(imgBuffer); - return; - } - - mCallbackHeapHead = 0; - mCallbackHeapFree = kCallbackHeapCount; - mCallbackHeapId++; - } - - if (mCallbackHeapFree == 0) { - ALOGE("%s: Camera %d: No free callback buffers, dropping frame", - __FUNCTION__, mCameraId); - mCallbackConsumer->unlockBuffer(imgBuffer); - return; - } - heapIdx = mCallbackHeapHead; - callbackHeap = mCallbackHeap; - callbackHeapId = mCallbackHeapId; - - mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount; - mCallbackHeapFree--; - - // TODO: Get rid of this memcpy by passing the gralloc queue all the way - // to app - - ssize_t offset; - size_t size; - sp<IMemoryHeap> heap = - mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset, - &size); - uint8_t *data = (uint8_t*)heap->getBase() + offset; - memcpy(data, imgBuffer.data, bufferSize); - - ALOGV("%s: Freeing buffer", __FUNCTION__); - mCallbackConsumer->unlockBuffer(imgBuffer); - - // In one-shot mode, stop sending callbacks after the first one - if (l.mParameters.previewCallbackFlags & - CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { - ALOGV("%s: clearing oneshot", __FUNCTION__); - l.mParameters.previewCallbackOneShot = false; - } - } - - // Call outside parameter lock to allow re-entrancy from notification - { - SharedCameraClient::Lock l(mSharedCameraClient); - if (l.mCameraClient != 0) { - ALOGV("%s: Camera %d: Invoking client data callback", - __FUNCTION__, mCameraId); - l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, - callbackHeap->mBuffers[heapIdx], NULL); - } - } - - SharedParameters::Lock l(mParameters); - // Only increment free if we're still using the same heap - if (mCallbackHeapId == callbackHeapId) { - mCallbackHeapFree++; - } - - ALOGV("%s: exit", __FUNCTION__); -} - -void Camera2Client::onCaptureAvailable() { - ATRACE_CALL(); - status_t res; - sp<Camera2Heap> 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; @@ -1941,132 +1772,6 @@ status_t Camera2Client::updatePreviewRequest(const Parameters ¶ms) { return OK; } -status_t Camera2Client::updateCallbackStream(const Parameters ¶ms) { - status_t res; - - if (mCallbackConsumer == 0) { - // Create CPU buffer queue endpoint - mCallbackConsumer = new CpuConsumer(kCallbackHeapCount); - mCallbackWaiter = new CallbackWaiter(this); - mCallbackConsumer->setFrameAvailableListener(mCallbackWaiter); - mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer")); - mCallbackWindow = new SurfaceTextureClient( - mCallbackConsumer->getProducerInterface()); - } - - if (mCallbackStreamId != NO_STREAM) { - // Check if stream parameters have to change - uint32_t currentWidth, currentHeight, currentFormat; - res = mDevice->getStreamInfo(mCallbackStreamId, - ¤tWidth, ¤tHeight, ¤tFormat); - if (res != OK) { - ALOGE("%s: Camera %d: Error querying callback output stream info: " - "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); - return res; - } - if (currentWidth != (uint32_t)params.previewWidth || - currentHeight != (uint32_t)params.previewHeight || - currentFormat != (uint32_t)params.previewFormat) { - // Since size should only change while preview is not running, - // assuming that all existing use of old callback stream is - // completed. - res = mDevice->deleteStream(mCallbackStreamId); - if (res != OK) { - ALOGE("%s: Camera %d: Unable to delete old output stream " - "for callbacks: %s (%d)", __FUNCTION__, mCameraId, - strerror(-res), res); - return res; - } - mCallbackStreamId = NO_STREAM; - } - } - - if (mCallbackStreamId == NO_STREAM) { - ALOGV("Creating callback stream: %d %d format 0x%x", - params.previewWidth, params.previewHeight, - params.previewFormat); - res = mDevice->createStream(mCallbackWindow, - params.previewWidth, params.previewHeight, - params.previewFormat, 0, &mCallbackStreamId); - if (res != OK) { - ALOGE("%s: Camera %d: Can't create output stream for callbacks: " - "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); - return res; - } - } - - 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..b2fd636 100644 --- a/services/camera/libcameraservice/Camera2Client.h +++ b/services/camera/libcameraservice/Camera2Client.h @@ -21,6 +21,8 @@ #include "CameraService.h" #include "camera2/Parameters.h" #include "camera2/FrameProcessor.h" +#include "camera2/CaptureProcessor.h" +#include "camera2/CallbackProcessor.h" #include <binder/MemoryBase.h> #include <binder/MemoryHeapBase.h> #include <gui/CpuConsumer.h> @@ -37,7 +39,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<ICameraClient>& client); @@ -62,7 +66,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>& cameraService, const sp<ICameraClient>& cameraClient, @@ -75,7 +81,9 @@ public: virtual status_t dump(int fd, const Vector<String16>& 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 +91,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<Camera2Device>& getCameraDevice(); @@ -102,6 +112,7 @@ public: private: SharedCameraClient &mSharedClient; }; + SharedCameraClient(const sp<ICameraClient>& client); SharedCameraClient& operator=(const sp<ICameraClient>& client); void clear(); private: @@ -109,6 +120,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 +159,6 @@ private: /** Camera device-related private members */ - class Camera2Heap; - void setPreviewCallbackFlagL(Parameters ¶ms, int flag); status_t updateRequests(const Parameters ¶ms); @@ -167,50 +179,13 @@ private: /** Preview callback related members */ - int mCallbackStreamId; - static const size_t kCallbackHeapCount = 6; - sp<CpuConsumer> mCallbackConsumer; - sp<ANativeWindow> mCallbackWindow; - // Simple listener that forwards frame available notifications from - // a CPU consumer to the callback notification - class CallbackWaiter: public CpuConsumer::FrameAvailableListener { - public: - CallbackWaiter(Camera2Client *parent) : mParent(parent) {} - void onFrameAvailable() { mParent->onCallbackAvailable(); } - private: - Camera2Client *mParent; - }; - sp<CallbackWaiter> mCallbackWaiter; - sp<Camera2Heap> mCallbackHeap; - int mCallbackHeapId; - size_t mCallbackHeapHead, mCallbackHeapFree; - // Handle callback image buffers - void onCallbackAvailable(); - - status_t updateCallbackStream(const Parameters ¶ms); + sp<camera2::CallbackProcessor> mCallbackProcessor; /* Still image capture related members */ - int mCaptureStreamId; - sp<CpuConsumer> mCaptureConsumer; - sp<ANativeWindow> 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<CaptureWaiter> mCaptureWaiter; + sp<camera2::CaptureProcessor> mCaptureProcessor; CameraMetadata mCaptureRequest; - sp<Camera2Heap> mCaptureHeap; - // Handle captured image buffers - void onCaptureAvailable(); - status_t updateCaptureRequest(const Parameters ¶ms); - status_t updateCaptureStream(const Parameters ¶ms); /* Recording related members */ @@ -229,7 +204,7 @@ private: }; sp<RecordingWaiter> mRecordingWaiter; CameraMetadata mRecordingRequest; - sp<Camera2Heap> mRecordingHeap; + sp<camera2::Camera2Heap> mRecordingHeap; static const size_t kDefaultRecordingHeapCount = 8; size_t mRecordingHeapCount; @@ -254,32 +229,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<MemoryBase>[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<MemoryHeapBase> mHeap; - sp<MemoryBase> *mBuffers; - }; - // Update parameters all requests use, based on mParameters status_t updateRequestCommon(CameraMetadata *request, const Parameters ¶ms) const; @@ -291,9 +240,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/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp new file mode 100644 index 0000000..854b890 --- /dev/null +++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp @@ -0,0 +1,293 @@ +/* + * 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::CallbackProcessor" +#define ATRACE_TAG ATRACE_TAG_CAMERA +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Trace.h> + +#include "CallbackProcessor.h" +#include <gui/SurfaceTextureClient.h> +#include "../Camera2Device.h" +#include "../Camera2Client.h" + + +namespace android { +namespace camera2 { + +CallbackProcessor::CallbackProcessor(wp<Camera2Client> client): + Thread(false), + mClient(client), + mCallbackAvailable(false), + mCallbackStreamId(NO_STREAM) { +} + +CallbackProcessor::~CallbackProcessor() { + ALOGV("%s: Exit", __FUNCTION__); +} + +void CallbackProcessor::onFrameAvailable() { + Mutex::Autolock l(mInputMutex); + if (!mCallbackAvailable) { + mCallbackAvailable = true; + mCallbackAvailableSignal.signal(); + } +} + +status_t CallbackProcessor::updateStream(const Parameters ¶ms) { + ATRACE_CALL(); + status_t res; + + Mutex::Autolock l(mInputMutex); + + sp<Camera2Client> client = mClient.promote(); + if (client == 0) return OK; + sp<Camera2Device> device = client->getCameraDevice(); + + if (mCallbackConsumer == 0) { + // Create CPU buffer queue endpoint + mCallbackConsumer = new CpuConsumer(kCallbackHeapCount); + mCallbackConsumer->setFrameAvailableListener(this); + mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer")); + mCallbackWindow = new SurfaceTextureClient( + mCallbackConsumer->getProducerInterface()); + } + + if (mCallbackStreamId != NO_STREAM) { + // Check if stream parameters have to change + uint32_t currentWidth, currentHeight, currentFormat; + res = device->getStreamInfo(mCallbackStreamId, + ¤tWidth, ¤tHeight, ¤tFormat); + if (res != OK) { + ALOGE("%s: Camera %d: Error querying callback output stream info: " + "%s (%d)", __FUNCTION__, client->getCameraId(), + strerror(-res), res); + return res; + } + if (currentWidth != (uint32_t)params.previewWidth || + currentHeight != (uint32_t)params.previewHeight || + currentFormat != (uint32_t)params.previewFormat) { + // Since size should only change while preview is not running, + // assuming that all existing use of old callback stream is + // completed. + res = device->deleteStream(mCallbackStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Unable to delete old output stream " + "for callbacks: %s (%d)", __FUNCTION__, client->getCameraId(), + strerror(-res), res); + return res; + } + mCallbackStreamId = NO_STREAM; + } + } + + if (mCallbackStreamId == NO_STREAM) { + ALOGV("Creating callback stream: %d %d format 0x%x", + params.previewWidth, params.previewHeight, + params.previewFormat); + res = device->createStream(mCallbackWindow, + params.previewWidth, params.previewHeight, + params.previewFormat, 0, &mCallbackStreamId); + if (res != OK) { + ALOGE("%s: Camera %d: Can't create output stream for callbacks: " + "%s (%d)", __FUNCTION__, client->getCameraId(), + strerror(-res), res); + return res; + } + } + + return OK; +} + +status_t CallbackProcessor::deleteStream() { + ATRACE_CALL(); + status_t res; + + Mutex::Autolock l(mInputMutex); + + if (mCallbackStreamId != NO_STREAM) { + sp<Camera2Client> client = mClient.promote(); + if (client == 0) return OK; + sp<Camera2Device> device = client->getCameraDevice(); + + device->deleteStream(mCallbackStreamId); + mCallbackStreamId = NO_STREAM; + } + return OK; +} + +int CallbackProcessor::getStreamId() const { + Mutex::Autolock l(mInputMutex); + return mCallbackStreamId; +} + +void CallbackProcessor::dump(int fd, const Vector<String16>& args) { +} + +bool CallbackProcessor::threadLoop() { + status_t res; + + { + Mutex::Autolock l(mInputMutex); + while (!mCallbackAvailable) { + res = mCallbackAvailableSignal.waitRelative(mInputMutex, + kWaitDuration); + if (res == TIMED_OUT) return true; + } + mCallbackAvailable = false; + } + + do { + sp<Camera2Client> client = mClient.promote(); + if (client == 0) return false; + res = processNewCallback(client); + } while (res == OK); + + return true; +} + +status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) { + ATRACE_CALL(); + status_t res; + + int callbackHeapId; + sp<Camera2Heap> callbackHeap; + size_t heapIdx; + + CpuConsumer::LockedBuffer imgBuffer; + ALOGV("%s: Getting buffer", __FUNCTION__); + res = mCallbackConsumer->lockNextBuffer(&imgBuffer); + if (res != OK) { + if (res != BAD_VALUE) { + ALOGE("%s: Camera %d: Error receiving next callback buffer: " + "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); + } + return res; + } + ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, + client->getCameraId()); + + { + SharedParameters::Lock l(client->getParameters()); + + if ( l.mParameters.state != Parameters::PREVIEW + && l.mParameters.state != Parameters::RECORD + && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { + ALOGV("%s: Camera %d: No longer streaming", + __FUNCTION__, client->getCameraId()); + mCallbackConsumer->unlockBuffer(imgBuffer); + return OK; + } + + if (! (l.mParameters.previewCallbackFlags & + CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) { + ALOGV("%s: No longer enabled, dropping", __FUNCTION__); + mCallbackConsumer->unlockBuffer(imgBuffer); + return OK; + } + if ((l.mParameters.previewCallbackFlags & + CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) && + !l.mParameters.previewCallbackOneShot) { + ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__); + mCallbackConsumer->unlockBuffer(imgBuffer); + return OK; + } + + if (imgBuffer.format != l.mParameters.previewFormat) { + ALOGE("%s: Camera %d: Unexpected format for callback: " + "%x, expected %x", __FUNCTION__, client->getCameraId(), + imgBuffer.format, l.mParameters.previewFormat); + mCallbackConsumer->unlockBuffer(imgBuffer); + return INVALID_OPERATION; + } + + // In one-shot mode, stop sending callbacks after the first one + if (l.mParameters.previewCallbackFlags & + CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { + ALOGV("%s: clearing oneshot", __FUNCTION__); + l.mParameters.previewCallbackOneShot = false; + } + } + + size_t bufferSize = Camera2Client::calculateBufferSize( + imgBuffer.width, imgBuffer.height, + imgBuffer.format, imgBuffer.stride); + size_t currentBufferSize = (mCallbackHeap == 0) ? + 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount); + if (bufferSize != currentBufferSize) { + mCallbackHeap.clear(); + mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount, + "Camera2Client::CallbackHeap"); + if (mCallbackHeap->mHeap->getSize() == 0) { + ALOGE("%s: Camera %d: Unable to allocate memory for callbacks", + __FUNCTION__, client->getCameraId()); + mCallbackConsumer->unlockBuffer(imgBuffer); + return INVALID_OPERATION; + } + + mCallbackHeapHead = 0; + mCallbackHeapFree = kCallbackHeapCount; + } + + if (mCallbackHeapFree == 0) { + ALOGE("%s: Camera %d: No free callback buffers, dropping frame", + __FUNCTION__, client->getCameraId()); + mCallbackConsumer->unlockBuffer(imgBuffer); + return OK; + } + + heapIdx = mCallbackHeapHead; + + mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount; + mCallbackHeapFree--; + + // TODO: Get rid of this memcpy by passing the gralloc queue all the way + // to app + + ssize_t offset; + size_t size; + sp<IMemoryHeap> heap = + mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset, + &size); + uint8_t *data = (uint8_t*)heap->getBase() + offset; + memcpy(data, imgBuffer.data, bufferSize); + + ALOGV("%s: Freeing buffer", __FUNCTION__); + mCallbackConsumer->unlockBuffer(imgBuffer); + + // Call outside parameter lock to allow re-entrancy from notification + { + Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient); + if (l.mCameraClient != 0) { + ALOGV("%s: Camera %d: Invoking client data callback", + __FUNCTION__, client->getCameraId()); + l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, + mCallbackHeap->mBuffers[heapIdx], NULL); + } + } + + // Only increment free if we're still using the same heap + mCallbackHeapFree++; + + ALOGV("%s: exit", __FUNCTION__); + + return OK; +} + +}; // namespace camera2 +}; // namespace android diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.h b/services/camera/libcameraservice/camera2/CallbackProcessor.h new file mode 100644 index 0000000..36c51a3 --- /dev/null +++ b/services/camera/libcameraservice/camera2/CallbackProcessor.h @@ -0,0 +1,82 @@ +/* + * 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_CALLBACKPROCESSOR_H +#define ANDROID_SERVERS_CAMERA_CAMERA2_CALLBACKPROCESSOR_H + +#include <utils/Thread.h> +#include <utils/String16.h> +#include <utils/Vector.h> +#include <utils/Mutex.h> +#include <utils/Condition.h> +#include <gui/CpuConsumer.h> +#include "Parameters.h" +#include "CameraMetadata.h" +#include "Camera2Heap.h" + +namespace android { + +class Camera2Client; + +namespace camera2 { + +/*** + * Still image capture output image processing + */ +class CallbackProcessor: + public Thread, public CpuConsumer::FrameAvailableListener { + public: + CallbackProcessor(wp<Camera2Client> client); + ~CallbackProcessor(); + + void onFrameAvailable(); + + status_t updateStream(const Parameters ¶ms); + status_t deleteStream(); + int getStreamId() const; + + void dump(int fd, const Vector<String16>& args); + private: + static const nsecs_t kWaitDuration = 10000000; // 10 ms + wp<Camera2Client> mClient; + + mutable Mutex mInputMutex; + bool mCallbackAvailable; + Condition mCallbackAvailableSignal; + + enum { + NO_STREAM = -1 + }; + + int mCallbackStreamId; + static const size_t kCallbackHeapCount = 6; + sp<CpuConsumer> mCallbackConsumer; + sp<ANativeWindow> mCallbackWindow; + sp<Camera2Heap> mCallbackHeap; + int mCallbackHeapId; + size_t mCallbackHeapHead, mCallbackHeapFree; + + virtual bool threadLoop(); + + status_t processNewCallback(sp<Camera2Client> &client); + +}; + + +}; //namespace camera2 +}; //namespace android + +#endif 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 <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> + +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<MemoryBase>[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<MemoryHeapBase> mHeap; + sp<MemoryBase> *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 <utils/Log.h> +#include <utils/Trace.h> + +#include "CaptureProcessor.h" +#include <gui/SurfaceTextureClient.h> +#include "../Camera2Device.h" +#include "../Camera2Client.h" + + +namespace android { +namespace camera2 { + +CaptureProcessor::CaptureProcessor(wp<Camera2Client> 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<Camera2Client> client = mClient.promote(); + if (client == 0) return OK; + sp<Camera2Device> 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<Camera2Client> client = mClient.promote(); + if (client == 0) return OK; + sp<Camera2Device> 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<String16>& 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<Camera2Client> client = mClient.promote(); + if (client == 0) return false; + res = processNewCapture(client); + } while (res == OK); + + return true; +} + +status_t CaptureProcessor::processNewCapture(sp<Camera2Client> &client) { + ATRACE_CALL(); + status_t res; + sp<Camera2Heap> 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 <utils/Thread.h> +#include <utils/String16.h> +#include <utils/Vector.h> +#include <utils/Mutex.h> +#include <utils/Condition.h> +#include <gui/CpuConsumer.h> +#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<Camera2Client> client); + ~CaptureProcessor(); + + void onFrameAvailable(); + + status_t updateStream(const Parameters ¶ms); + status_t deleteStream(); + int getStreamId() const; + + void dump(int fd, const Vector<String16>& args); + private: + static const nsecs_t kWaitDuration = 10000000; // 10 ms + wp<Camera2Client> mClient; + + mutable Mutex mInputMutex; + bool mCaptureAvailable; + Condition mCaptureAvailableSignal; + + enum { + NO_STREAM = -1 + }; + + int mCaptureStreamId; + sp<CpuConsumer> mCaptureConsumer; + sp<ANativeWindow> mCaptureWindow; + sp<Camera2Heap> mCaptureHeap; + + virtual bool threadLoop(); + + status_t processNewCapture(sp<Camera2Client> &client); + +}; + + +}; //namespace camera2 +}; //namespace android + +#endif |