From c3dbf1a40df85b75e5805382838a90416f69730f Mon Sep 17 00:00:00 2001 From: James Painter Date: Wed, 5 Sep 2012 18:02:32 -0700 Subject: [PATCH] Camera2: Add a burst mode skeleton. Bug: 6243944 Change-Id: I7f496ca1051571c68fdd99a6f85bf6a908a4e29a --- camera/CameraParameters.cpp | 5 + include/camera/CameraParameters.h | 14 +- services/camera/libcameraservice/Android.mk | 10 +- services/camera/libcameraservice/Camera2Client.cpp | 4 +- .../libcameraservice/camera2/BurstCapture.cpp | 112 +++++++++++ .../camera/libcameraservice/camera2/BurstCapture.h | 71 +++++++ .../libcameraservice/camera2/CaptureSequencer.cpp | 87 +++++++- .../libcameraservice/camera2/CaptureSequencer.h | 7 + .../libcameraservice/camera2/JpegCompressor.cpp | 220 +++++++++++++++++++++ .../libcameraservice/camera2/JpegCompressor.h | 107 ++++++++++ .../camera/libcameraservice/camera2/Parameters.cpp | 18 ++ .../camera/libcameraservice/camera2/Parameters.h | 7 + 12 files changed, 653 insertions(+), 9 deletions(-) create mode 100644 services/camera/libcameraservice/camera2/BurstCapture.cpp create mode 100644 services/camera/libcameraservice/camera2/BurstCapture.h create mode 100644 services/camera/libcameraservice/camera2/JpegCompressor.cpp create mode 100644 services/camera/libcameraservice/camera2/JpegCompressor.h diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index 872512a896..a657fe36f4 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -90,6 +90,7 @@ const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint"; const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported"; const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization"; const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported"; +const char CameraParameters::KEY_LIGHTFX[] = "light-fx"; const char CameraParameters::TRUE[] = "true"; const char CameraParameters::FALSE[] = "false"; @@ -166,6 +167,10 @@ const char CameraParameters::FOCUS_MODE_EDOF[] = "edof"; const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video"; const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture"; +// Values for light fx settings +const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light"; +const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range"; + CameraParameters::CameraParameters() : mMap() { diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index 4d5aa363b7..8668958a48 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -298,7 +298,7 @@ public: // Example value: "42.5". Read only. static const char KEY_VERTICAL_VIEW_ANGLE[]; // Exposure compensation index. 0 means exposure is not adjusted. - // Example value: "0" or "5". Read/write. + // Example value: "-5" or "5". Read/write. static const char KEY_EXPOSURE_COMPENSATION[]; // The maximum exposure compensation index (>=0). // Example value: "6". Read only. @@ -307,7 +307,7 @@ public: // Example value: "-6". Read only. static const char KEY_MIN_EXPOSURE_COMPENSATION[]; // The exposure compensation step. Exposure compensation index multiply by - // step eqals to EV. Ex: if exposure compensation index is 6 and step is + // step eqals to EV. Ex: if exposure compensation index is -6 and step is // 0.3333, EV is -2. // Example value: "0.333333333" or "0.5". Read only. static const char KEY_EXPOSURE_COMPENSATION_STEP[]; @@ -525,6 +525,10 @@ public: // stream and record stabilized videos. static const char KEY_VIDEO_STABILIZATION_SUPPORTED[]; + // Supported modes for special effects with light. + // Example values: "lowlight,hdr". + static const char KEY_LIGHTFX[]; + // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED. static const char TRUE[]; static const char FALSE[]; @@ -660,6 +664,12 @@ public: // other modes. static const char FOCUS_MODE_CONTINUOUS_PICTURE[]; + // Values for light special effects + // Low-light enhancement mode + static const char LIGHTFX_LOWLIGHT[]; + // High-dynamic range mode + static const char LIGHTFX_HDR[]; + private: DefaultKeyedVector mMap; }; diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index e27a065d93..c7927fe3c5 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -17,7 +17,9 @@ LOCAL_SRC_FILES:= \ camera2/JpegProcessor.cpp \ camera2/CallbackProcessor.cpp \ camera2/ZslProcessor.cpp \ - camera2/CaptureSequencer.cpp \ + camera2/BurstCapture.cpp \ + camera2/JpegCompressor.cpp \ + camera2/CaptureSequencer.cpp LOCAL_SHARED_LIBRARIES:= \ libui \ @@ -30,10 +32,12 @@ LOCAL_SHARED_LIBRARIES:= \ libgui \ libhardware \ libsync \ - libcamera_metadata + libcamera_metadata \ + libjpeg LOCAL_C_INCLUDES += \ - system/media/camera/include + system/media/camera/include \ + external/jpeg LOCAL_MODULE:= libcameraservice diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index 7abb4055ea..50812895c5 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -25,14 +25,12 @@ #include #include #include - -#include "Camera2Client.h" +#include "camera2/Parameters.h" #define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__); #define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__); namespace android { - using namespace camera2; static int getCallingPid() { diff --git a/services/camera/libcameraservice/camera2/BurstCapture.cpp b/services/camera/libcameraservice/camera2/BurstCapture.cpp new file mode 100644 index 0000000000..50208195d1 --- /dev/null +++ b/services/camera/libcameraservice/camera2/BurstCapture.cpp @@ -0,0 +1,112 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "BurstCapture" + +#include +#include + +#include "BurstCapture.h" + +#include "JpegCompressor.h" +#include "../Camera2Client.h" + +namespace android { +namespace camera2 { + +BurstCapture::BurstCapture(wp client, wp sequencer): + mCaptureStreamId(NO_STREAM), + mClient(client), + mSequencer(sequencer) +{ +} + +BurstCapture::~BurstCapture() { +} + +status_t BurstCapture::start(Vector &metadatas, int32_t firstCaptureId) { + ALOGE("Not completely implemented"); + return INVALID_OPERATION; +} + +void BurstCapture::onFrameAvailable() { + ALOGV("%s", __FUNCTION__); + Mutex::Autolock l(mInputMutex); + if(!mInputChanged) { + mInputChanged = true; + mInputSignal.signal(); + } +} + +bool BurstCapture::threadLoop() { + status_t res; + { + Mutex::Autolock l(mInputMutex); + while(!mInputChanged) { + res = mInputSignal.waitRelative(mInputMutex, kWaitDuration); + if(res == TIMED_OUT) return true; + } + mInputChanged = false; + } + + do { + sp client = mClient.promote(); + if(client == 0) return false; + ALOGV("%s: Calling processFrameAvailable()", __FUNCTION__); + res = processFrameAvailable(client); + } while(res == OK); + + return true; +} + +CpuConsumer::LockedBuffer* BurstCapture::jpegEncode( + CpuConsumer::LockedBuffer *imgBuffer, + int quality) +{ + ALOGV("%s", __FUNCTION__); + + CpuConsumer::LockedBuffer *imgEncoded = new CpuConsumer::LockedBuffer; + uint8_t *data = new uint8_t[ANDROID_JPEG_MAX_SIZE]; + imgEncoded->data = data; + imgEncoded->width = imgBuffer->width; + imgEncoded->height = imgBuffer->height; + imgEncoded->stride = imgBuffer->stride; + + Vector buffers; + buffers.push_back(imgBuffer); + buffers.push_back(imgEncoded); + + sp jpeg = new JpegCompressor(); + status_t res = jpeg->start(buffers, 1); + + bool success = jpeg->waitForDone(10 * 1e9); + if(success) { + return buffers[1]; + } + else { + ALOGE("%s: JPEG encode timed out", __FUNCTION__); + return NULL; // TODO: maybe change function return value to status_t + } +} + +status_t BurstCapture::processFrameAvailable(sp &client) { + ALOGE("Not implemented"); + return INVALID_OPERATION; +} + +} // namespace camera2 +} // namespace android diff --git a/services/camera/libcameraservice/camera2/BurstCapture.h b/services/camera/libcameraservice/camera2/BurstCapture.h new file mode 100644 index 0000000000..dfc45eb3f2 --- /dev/null +++ b/services/camera/libcameraservice/camera2/BurstCapture.h @@ -0,0 +1,71 @@ +/* + * 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_BURST_CAPTURE_H +#define ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H + +#include "camera2/CameraMetadata.h" +#include +#include +#include +#include "Camera2Device.h" + +namespace android { + +class Camera2Client; + +namespace camera2 { + +class CaptureSequencer; + +class BurstCapture : public virtual Thread, + public virtual CpuConsumer::FrameAvailableListener +{ +public: + BurstCapture(wp client, wp sequencer); + virtual ~BurstCapture(); + + virtual void onFrameAvailable(); + virtual status_t start(Vector &metadatas, int32_t firstCaptureId); + +protected: + Mutex mInputMutex; + bool mInputChanged; + Condition mInputSignal; + int mCaptureStreamId; + wp mClient; + wp mSequencer; + + // Should only be accessed by processing thread + enum { + NO_STREAM = -1 + }; + + CpuConsumer::LockedBuffer* jpegEncode( + CpuConsumer::LockedBuffer *imgBuffer, + int quality); + + virtual status_t processFrameAvailable(sp &client); + +private: + virtual bool threadLoop(); + static const nsecs_t kWaitDuration = 10000000; // 10 ms +}; + +} // namespace camera2 +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp index 1c42cbf02c..2f8b7db892 100644 --- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp @@ -23,6 +23,7 @@ #include #include "CaptureSequencer.h" +#include "BurstCapture.h" #include "../Camera2Device.h" #include "../Camera2Client.h" #include "Parameters.h" @@ -44,6 +45,7 @@ CaptureSequencer::CaptureSequencer(wp client): mTriggerId(0), mTimeoutCount(0), mCaptureId(Camera2Client::kFirstCaptureRequestId) { + ALOGV("%s", __FUNCTION__); } CaptureSequencer::~CaptureSequencer() { @@ -56,6 +58,7 @@ void CaptureSequencer::setZslProcessor(wp processor) { } status_t CaptureSequencer::startCapture() { + ALOGV("%s", __FUNCTION__); ATRACE_CALL(); Mutex::Autolock l(mInputMutex); if (mBusy) { @@ -82,6 +85,7 @@ void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) { void CaptureSequencer::onFrameAvailable(int32_t frameId, CameraMetadata &frame) { + ALOGV("%s: Listener found new frame", __FUNCTION__); ATRACE_CALL(); Mutex::Autolock l(mInputMutex); mNewFrameId = frameId; @@ -94,6 +98,7 @@ void CaptureSequencer::onFrameAvailable(int32_t frameId, void CaptureSequencer::onCaptureAvailable(nsecs_t timestamp) { ATRACE_CALL(); + ALOGV("%s", __FUNCTION__); Mutex::Autolock l(mInputMutex); mCaptureTimestamp = timestamp; if (!mNewCaptureReceived) { @@ -132,6 +137,8 @@ const char* CaptureSequencer::kStateNames[CaptureSequencer::NUM_CAPTURE_STATES+1 "STANDARD_START", "STANDARD_PRECAPTURE", "STANDARD_CAPTURING", + "BURST_CAPTURE_START", + "BURST_CAPTURE_WAIT", "DONE", "ERROR", "UNKNOWN" @@ -148,6 +155,8 @@ const CaptureSequencer::StateManager &CaptureSequencer::manageStandardPrecaptureWait, &CaptureSequencer::manageStandardCapture, &CaptureSequencer::manageStandardCaptureWait, + &CaptureSequencer::manageBurstCaptureStart, + &CaptureSequencer::manageBurstCaptureWait, &CaptureSequencer::manageDone, }; @@ -215,6 +224,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp &c CaptureSequencer::CaptureState CaptureSequencer::manageStart( sp &client) { + ALOGV("%s", __FUNCTION__); status_t res; ATRACE_CALL(); SharedParameters::Lock l(client->getParameters()); @@ -227,7 +237,11 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStart( return DONE; } - if (l.mParameters.zslMode && + if(l.mParameters.lightFx != Parameters::LIGHTFX_NONE && + l.mParameters.state == Parameters::STILL_CAPTURE) { + nextState = BURST_CAPTURE_START; + } + else if (l.mParameters.zslMode && l.mParameters.state == Parameters::STILL_CAPTURE) { nextState = ZSL_START; } else { @@ -442,6 +456,77 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait( return STANDARD_CAPTURE_WAIT; } +CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureStart( + sp &client) { + ALOGV("%s", __FUNCTION__); + status_t res; + ATRACE_CALL(); + + // check which burst mode is set, create respective burst object + { + SharedParameters::Lock l(client->getParameters()); + + res = updateCaptureRequest(l.mParameters, client); + if(res != OK) { + return DONE; + } + + // + // check for burst mode type in mParameters here + // + mBurstCapture = new BurstCapture(client, this); + } + + res = mCaptureRequest.update(ANDROID_REQUEST_ID, &mCaptureId, 1); + if (res == OK) { + res = mCaptureRequest.sort(); + } + if (res != OK) { + ALOGE("%s: Camera %d: Unable to set up still capture request: %s (%d)", + __FUNCTION__, client->getCameraId(), strerror(-res), res); + return DONE; + } + + CameraMetadata captureCopy = mCaptureRequest; + if (captureCopy.entryCount() == 0) { + ALOGE("%s: Camera %d: Unable to copy capture request for HAL device", + __FUNCTION__, client->getCameraId()); + return DONE; + } + + Vector requests; + requests.push(mCaptureRequest); + res = mBurstCapture->start(requests, mCaptureId); + mTimeoutCount = kMaxTimeoutsForCaptureEnd * 10; + return BURST_CAPTURE_WAIT; +} + +CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureWait( + sp &client) { + status_t res; + ATRACE_CALL(); + + while (!mNewCaptureReceived) { + res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration); + if (res == TIMED_OUT) { + mTimeoutCount--; + break; + } + } + + if (mTimeoutCount <= 0) { + ALOGW("Timed out waiting for burst capture to complete"); + return DONE; + } + if (mNewCaptureReceived) { + mNewCaptureReceived = false; + // TODO: update mCaptureId to last burst's capture ID + 1? + return DONE; + } + + return BURST_CAPTURE_WAIT; +} + status_t CaptureSequencer::updateCaptureRequest(const Parameters ¶ms, sp &client) { ATRACE_CALL(); diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.h b/services/camera/libcameraservice/camera2/CaptureSequencer.h index 0492a43c3b..39ae079ba1 100644 --- a/services/camera/libcameraservice/camera2/CaptureSequencer.h +++ b/services/camera/libcameraservice/camera2/CaptureSequencer.h @@ -33,6 +33,7 @@ class Camera2Client; namespace camera2 { class ZslProcessor; +class BurstCapture; /** * Manages the still image capture process for @@ -96,6 +97,7 @@ class CaptureSequencer: wp mClient; wp mZslProcessor; + sp mBurstCapture; enum CaptureState { IDLE, @@ -107,6 +109,8 @@ class CaptureSequencer: STANDARD_PRECAPTURE_WAIT, STANDARD_CAPTURE, STANDARD_CAPTURE_WAIT, + BURST_CAPTURE_START, + BURST_CAPTURE_WAIT, DONE, ERROR, NUM_CAPTURE_STATES @@ -140,6 +144,9 @@ class CaptureSequencer: CaptureState manageStandardCapture(sp &client); CaptureState manageStandardCaptureWait(sp &client); + CaptureState manageBurstCaptureStart(sp &client); + CaptureState manageBurstCaptureWait(sp &client); + CaptureState manageDone(sp &client); // Utility methods diff --git a/services/camera/libcameraservice/camera2/JpegCompressor.cpp b/services/camera/libcameraservice/camera2/JpegCompressor.cpp new file mode 100644 index 0000000000..55964b675f --- /dev/null +++ b/services/camera/libcameraservice/camera2/JpegCompressor.cpp @@ -0,0 +1,220 @@ +/* + * 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_NDEBUG 0 +#define LOG_TAG "JpegCompressor" + +#include +#include + +#include "JpegCompressor.h" + +namespace android { +namespace camera2 { + +JpegCompressor::JpegCompressor(): + Thread(false), + mIsBusy(false), + mCaptureTime(0) { +} + +JpegCompressor::~JpegCompressor() { + ALOGV("%s", __FUNCTION__); + Mutex::Autolock lock(mMutex); +} + +status_t JpegCompressor::start(Vector buffers, + nsecs_t captureTime) { + ALOGV("%s", __FUNCTION__); + Mutex::Autolock busyLock(mBusyMutex); + + if (mIsBusy) { + ALOGE("%s: Already processing a buffer!", __FUNCTION__); + return INVALID_OPERATION; + } + + mIsBusy = true; + + mBuffers = buffers; + mCaptureTime = captureTime; + + status_t res; + res = run("JpegCompressor"); + if (res != OK) { + ALOGE("%s: Unable to start up compression thread: %s (%d)", + __FUNCTION__, strerror(-res), res); + //delete mBuffers; // necessary? + } + return res; +} + +status_t JpegCompressor::cancel() { + ALOGV("%s", __FUNCTION__); + requestExitAndWait(); + return OK; +} + +status_t JpegCompressor::readyToRun() { + ALOGV("%s", __FUNCTION__); + return OK; +} + +bool JpegCompressor::threadLoop() { + ALOGV("%s", __FUNCTION__); + + mAuxBuffer = mBuffers[0]; // input + mJpegBuffer = mBuffers[1]; // output + + // Set up error management + mJpegErrorInfo = NULL; + JpegError error; + error.parent = this; + + mCInfo.err = jpeg_std_error(&error); + mCInfo.err->error_exit = jpegErrorHandler; + + jpeg_create_compress(&mCInfo); + if (checkError("Error initializing compression")) return false; + + // Route compressed data straight to output stream buffer + JpegDestination jpegDestMgr; + jpegDestMgr.parent = this; + jpegDestMgr.init_destination = jpegInitDestination; + jpegDestMgr.empty_output_buffer = jpegEmptyOutputBuffer; + jpegDestMgr.term_destination = jpegTermDestination; + + mCInfo.dest = &jpegDestMgr; + + // Set up compression parameters + mCInfo.image_width = mAuxBuffer->width; + mCInfo.image_height = mAuxBuffer->height; + mCInfo.input_components = 1; // 3; + mCInfo.in_color_space = JCS_GRAYSCALE; // JCS_RGB + + ALOGV("%s: image_width = %d, image_height = %d", __FUNCTION__, mCInfo.image_width, mCInfo.image_height); + + jpeg_set_defaults(&mCInfo); + if (checkError("Error configuring defaults")) return false; + + // Do compression + jpeg_start_compress(&mCInfo, TRUE); + if (checkError("Error starting compression")) return false; + + size_t rowStride = mAuxBuffer->stride;// * 3; + const size_t kChunkSize = 32; + while (mCInfo.next_scanline < mCInfo.image_height) { + JSAMPROW chunk[kChunkSize]; + for (size_t i = 0 ; i < kChunkSize; i++) { + chunk[i] = (JSAMPROW) + (mAuxBuffer->data + (i + mCInfo.next_scanline) * rowStride); + } + jpeg_write_scanlines(&mCInfo, chunk, kChunkSize); + if (checkError("Error while compressing")) return false; + if (exitPending()) { + ALOGV("%s: Cancel called, exiting early", __FUNCTION__); + cleanUp(); + return false; + } + } + + jpeg_finish_compress(&mCInfo); + if (checkError("Error while finishing compression")) return false; + + cleanUp(); + return false; +} + +bool JpegCompressor::isBusy() { + ALOGV("%s", __FUNCTION__); + Mutex::Autolock busyLock(mBusyMutex); + return mIsBusy; +} + +// old function -- TODO: update for new buffer type +bool JpegCompressor::isStreamInUse(uint32_t id) { + ALOGV("%s", __FUNCTION__); + Mutex::Autolock lock(mBusyMutex); + + if (mBuffers.size() && mIsBusy) { + for (size_t i = 0; i < mBuffers.size(); i++) { +// if ( mBuffers[i].streamId == (int)id ) return true; + } + } + return false; +} + +bool JpegCompressor::waitForDone(nsecs_t timeout) { + ALOGV("%s", __FUNCTION__); + Mutex::Autolock lock(mBusyMutex); + status_t res = OK; + if (mIsBusy) { + res = mDone.waitRelative(mBusyMutex, timeout); + } + return (res == OK); +} + +bool JpegCompressor::checkError(const char *msg) { + ALOGV("%s", __FUNCTION__); + if (mJpegErrorInfo) { + char errBuffer[JMSG_LENGTH_MAX]; + mJpegErrorInfo->err->format_message(mJpegErrorInfo, errBuffer); + ALOGE("%s: %s: %s", + __FUNCTION__, msg, errBuffer); + cleanUp(); + mJpegErrorInfo = NULL; + return true; + } + return false; +} + +void JpegCompressor::cleanUp() { + ALOGV("%s", __FUNCTION__); + jpeg_destroy_compress(&mCInfo); + Mutex::Autolock lock(mBusyMutex); + mIsBusy = false; + mDone.signal(); +} + +void JpegCompressor::jpegErrorHandler(j_common_ptr cinfo) { + ALOGV("%s", __FUNCTION__); + JpegError *error = static_cast(cinfo->err); + error->parent->mJpegErrorInfo = cinfo; +} + +void JpegCompressor::jpegInitDestination(j_compress_ptr cinfo) { + ALOGV("%s", __FUNCTION__); + JpegDestination *dest= static_cast(cinfo->dest); + ALOGV("%s: Setting destination to %p, size %d", + __FUNCTION__, dest->parent->mJpegBuffer->data, kMaxJpegSize); + dest->next_output_byte = (JOCTET*)(dest->parent->mJpegBuffer->data); + dest->free_in_buffer = kMaxJpegSize; +} + +boolean JpegCompressor::jpegEmptyOutputBuffer(j_compress_ptr cinfo) { + ALOGV("%s", __FUNCTION__); + ALOGE("%s: JPEG destination buffer overflow!", + __FUNCTION__); + return true; +} + +void JpegCompressor::jpegTermDestination(j_compress_ptr cinfo) { + ALOGV("%s", __FUNCTION__); + ALOGV("%s: Done writing JPEG data. %d bytes left in buffer", + __FUNCTION__, cinfo->dest->free_in_buffer); +} + +}; // namespace camera2 +}; // namespace android diff --git a/services/camera/libcameraservice/camera2/JpegCompressor.h b/services/camera/libcameraservice/camera2/JpegCompressor.h new file mode 100644 index 0000000000..945b1def28 --- /dev/null +++ b/services/camera/libcameraservice/camera2/JpegCompressor.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + + +/** + * This class simulates a hardware JPEG compressor. It receives image buffers + * in RGBA_8888 format, processes them in a worker thread, and then pushes them + * out to their destination stream. + */ + +#ifndef ANDROID_SERVERS_CAMERA_JPEGCOMPRESSOR_H +#define ANDROID_SERVERS_CAMERA_JPEGCOMPRESSOR_H + +#include "utils/Thread.h" +#include "utils/Mutex.h" +#include "utils/Timers.h" +#include "utils/Vector.h" +//#include "Base.h" +#include +#include + +extern "C" { +#include +} + + +namespace android { +namespace camera2 { + +class JpegCompressor: private Thread, public virtual RefBase { + public: + + JpegCompressor(); + ~JpegCompressor(); + + // Start compressing COMPRESSED format buffers; JpegCompressor takes + // ownership of the Buffers vector. + status_t start(Vector buffers, + nsecs_t captureTime); + + status_t cancel(); + + bool isBusy(); + bool isStreamInUse(uint32_t id); + + bool waitForDone(nsecs_t timeout); + + // TODO: Measure this + static const size_t kMaxJpegSize = 300000; + + private: + Mutex mBusyMutex; + Mutex mMutex; + bool mIsBusy; + Condition mDone; + nsecs_t mCaptureTime; + + Vector mBuffers; + CpuConsumer::LockedBuffer *mJpegBuffer; + CpuConsumer::LockedBuffer *mAuxBuffer; + bool mFoundJpeg, mFoundAux; + + jpeg_compress_struct mCInfo; + + struct JpegError : public jpeg_error_mgr { + JpegCompressor *parent; + }; + j_common_ptr mJpegErrorInfo; + + struct JpegDestination : public jpeg_destination_mgr { + JpegCompressor *parent; + }; + + static void jpegErrorHandler(j_common_ptr cinfo); + + static void jpegInitDestination(j_compress_ptr cinfo); + static boolean jpegEmptyOutputBuffer(j_compress_ptr cinfo); + static void jpegTermDestination(j_compress_ptr cinfo); + + bool checkError(const char *msg); + void cleanUp(); + + /** + * Inherited Thread virtual overrides + */ + private: + virtual status_t readyToRun(); + virtual bool threadLoop(); +}; + +}; // namespace camera2 +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp index f89d1e33f0..e5942dca93 100644 --- a/services/camera/libcameraservice/camera2/Parameters.cpp +++ b/services/camera/libcameraservice/camera2/Parameters.cpp @@ -748,6 +748,10 @@ status_t Parameters::initialize(const CameraMetadata *info) { previewCallbackFlags = 0; + zslMode = false; + + lightFx = LIGHTFX_NONE; + state = STOPPED; paramsFlattened = params.flatten(); @@ -1315,6 +1319,10 @@ status_t Parameters::set(const String8& params) { ALOGE("%s: Video stabilization not supported", __FUNCTION__); } + // LIGHTFX + validatedParams.lightFx = lightFxStringToEnum( + newParams.get(CameraParameters::KEY_LIGHTFX)); + /** Update internal parameters */ validatedParams.paramsFlattened = params; @@ -1726,6 +1734,16 @@ Parameters::Parameters::focusMode_t Parameters::focusModeStringToEnum( Parameters::FOCUS_MODE_INVALID; } +Parameters::Parameters::lightFxMode_t Parameters::lightFxStringToEnum( + const char *lightFxMode) { + return + !strcmp(lightFxMode, CameraParameters::LIGHTFX_LOWLIGHT) ? + Parameters::LIGHTFX_LOWLIGHT : + !strcmp(lightFxMode, CameraParameters::LIGHTFX_HDR) ? + Parameters::LIGHTFX_HDR : + Parameters::LIGHTFX_NONE; +} + status_t Parameters::parseAreas(const char *areasCStr, Vector *areas) { static const size_t NUM_FIELDS = 5; diff --git a/services/camera/libcameraservice/camera2/Parameters.h b/services/camera/libcameraservice/camera2/Parameters.h index 509cc85be7..f7686059fa 100644 --- a/services/camera/libcameraservice/camera2/Parameters.h +++ b/services/camera/libcameraservice/camera2/Parameters.h @@ -109,6 +109,12 @@ struct Parameters { bool recordingHint; bool videoStabilization; + enum lightFxMode_t { + LIGHTFX_NONE = 0, + LIGHTFX_LOWLIGHT, + LIGHTFX_HDR + } lightFx; + String8 paramsFlattened; // These parameters are also part of the camera API-visible state, but not @@ -198,6 +204,7 @@ struct Parameters { static int sceneModeStringToEnum(const char *sceneMode); static flashMode_t flashModeStringToEnum(const char *flashMode); static focusMode_t focusModeStringToEnum(const char *focusMode); + static lightFxMode_t lightFxStringToEnum(const char *lightFxMode); static status_t parseAreas(const char *areasCStr, Vector *areas); static status_t validateAreas(const Vector &areas, -- 2.11.0