diff options
49 files changed, 2035 insertions, 181 deletions
diff --git a/camera/Android.mk b/camera/Android.mk index da5ac59..df7279f 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -35,6 +35,7 @@ LOCAL_SRC_FILES:= \ camera2/ICameraDeviceUser.cpp \ camera2/ICameraDeviceCallbacks.cpp \ camera2/CaptureRequest.cpp \ + camera2/OutputConfiguration.cpp \ ProCamera.cpp \ CameraBase.cpp \ CameraUtils.cpp \ diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index e5e4e90..3dbf75e 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -526,7 +526,7 @@ int CameraParameters::previewFormatToEnum(const char* format) { !strcmp(format, PIXEL_FORMAT_RGBA8888) ? HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888 !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ? - HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data + HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data -1; } diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 5485205..e3f9931 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -209,6 +209,20 @@ public: return status; } + virtual status_t setTorchMode(const String16& cameraId, bool enabled, + const sp<IBinder>& clientBinder) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + data.writeString16(cameraId); + data.writeInt32(enabled ? 1 : 0); + data.writeStrongBinder(clientBinder); + remote()->transact(BnCameraService::SET_TORCH_MODE, data, &reply); + + if (readExceptionCode(reply)) return -EPROTO; + return reply.readInt32(); + } + // connect to camera service (pro client) virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId, const String16 &clientPackageName, int clientUid, @@ -490,6 +504,16 @@ status_t BnCameraService::onTransact( } return NO_ERROR; } break; + case SET_TORCH_MODE: { + CHECK_INTERFACE(ICameraService, data, reply); + String16 cameraId = data.readString16(); + bool enabled = data.readInt32() != 0 ? true : false; + const sp<IBinder> clientBinder = data.readStrongBinder(); + status_t status = setTorchMode(cameraId, enabled, clientBinder); + reply->writeNoException(); + reply->writeInt32(status); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp index b2f1729..90a8bc2 100644 --- a/camera/ICameraServiceListener.cpp +++ b/camera/ICameraServiceListener.cpp @@ -29,6 +29,7 @@ namespace android { namespace { enum { STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION, + TORCH_STATUS_CHANGED, }; }; // namespace anonymous @@ -54,8 +55,21 @@ public: data, &reply, IBinder::FLAG_ONEWAY); + } - reply.readExceptionCode(); + virtual void onTorchStatusChanged(TorchStatus status, const String16 &cameraId) + { + Parcel data, reply; + data.writeInterfaceToken( + ICameraServiceListener::getInterfaceDescriptor()); + + data.writeInt32(static_cast<int32_t>(status)); + data.writeString16(cameraId); + + remote()->transact(TORCH_STATUS_CHANGED, + data, + &reply, + IBinder::FLAG_ONEWAY); } }; @@ -75,7 +89,16 @@ status_t BnCameraServiceListener::onTransact( int32_t cameraId = data.readInt32(); onStatusChanged(status, cameraId); - reply->writeNoException(); + + return NO_ERROR; + } break; + case TORCH_STATUS_CHANGED: { + CHECK_INTERFACE(ICameraServiceListener, data, reply); + + TorchStatus status = static_cast<TorchStatus>(data.readInt32()); + String16 cameraId = data.readString16(); + + onTorchStatusChanged(status, cameraId); return NO_ERROR; } break; diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index ff4a0c2..16018dc 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -26,6 +26,7 @@ #include <gui/Surface.h> #include <camera/CameraMetadata.h> #include <camera/camera2/CaptureRequest.h> +#include <camera/camera2/OutputConfiguration.h> namespace android { @@ -107,7 +108,7 @@ public: } } - if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) { res = FAILED_TRANSACTION; } return res; @@ -147,7 +148,7 @@ public: resFrameNumber = reply.readInt64(lastFrameNumber); } } - if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { + if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) { res = FAILED_TRANSACTION; } return res; @@ -167,7 +168,7 @@ public: status_t resFrameNumber = BAD_VALUE; if (reply.readInt32() != 0) { if (lastFrameNumber != NULL) { - res = reply.readInt64(lastFrameNumber); + resFrameNumber = reply.readInt64(lastFrameNumber); } } if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { @@ -208,20 +209,17 @@ public: return reply.readInt32(); } - virtual status_t createStream(int width, int height, int format, - const sp<IGraphicBufferProducer>& bufferProducer) + virtual status_t createStream(const OutputConfiguration& outputConfiguration) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); - data.writeInt32(width); - data.writeInt32(height); - data.writeInt32(format); - - data.writeInt32(1); // marker that bufferProducer is not null - data.writeString16(String16("unknown_name")); // name of surface - sp<IBinder> b(bufferProducer->asBinder()); - data.writeStrongBinder(b); + if (outputConfiguration.getGraphicBufferProducer() != NULL) { + data.writeInt32(1); // marker that OutputConfiguration is not null. Mimic aidl behavior + outputConfiguration.writeToParcel(data); + } else { + data.writeInt32(0); + } remote()->transact(CREATE_STREAM, data, &reply); reply.readExceptionCode(); @@ -296,7 +294,7 @@ public: status_t resFrameNumber = BAD_VALUE; if (reply.readInt32() != 0) { if (lastFrameNumber != NULL) { - res = reply.readInt64(lastFrameNumber); + resFrameNumber = reply.readInt64(lastFrameNumber); } } if ((res != NO_ERROR) || (resFrameNumber != NO_ERROR)) { @@ -396,31 +394,15 @@ status_t BnCameraDeviceUser::onTransact( } break; case CREATE_STREAM: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); - int width, height, format; - - width = data.readInt32(); - ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width); - height = data.readInt32(); - ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height); - format = data.readInt32(); - ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format); - sp<IGraphicBufferProducer> bp; + status_t ret = BAD_VALUE; if (data.readInt32() != 0) { - String16 name = readMaybeEmptyString16(data); - bp = interface_cast<IGraphicBufferProducer>( - data.readStrongBinder()); - - ALOGV("%s: CREATE_STREAM: bp = %p, name = %s", __FUNCTION__, - bp.get(), String8(name).string()); + OutputConfiguration outputConfiguration(data); + ret = createStream(outputConfiguration); } else { - ALOGV("%s: CREATE_STREAM: bp = unset, name = unset", - __FUNCTION__); + ALOGE("%s: cannot take an empty OutputConfiguration", __FUNCTION__); } - status_t ret; - ret = createStream(width, height, format, bp); - reply->writeNoException(); ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__); reply->writeInt32(ret); diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp new file mode 100644 index 0000000..dab6a00 --- /dev/null +++ b/camera/camera2/OutputConfiguration.cpp @@ -0,0 +1,79 @@ +/* +** +** Copyright 2015, 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 "OutputConfiguration" +#include <utils/Log.h> + +#include <camera/camera2/OutputConfiguration.h> +#include <binder/Parcel.h> + +namespace android { + + +const int OutputConfiguration::INVALID_ROTATION = -1; + +// Read empty strings without printing a false error message. +String16 OutputConfiguration::readMaybeEmptyString16(const Parcel& parcel) { + size_t len; + const char16_t* str = parcel.readString16Inplace(&len); + if (str != NULL) { + return String16(str, len); + } else { + return String16(); + } +} + +sp<IGraphicBufferProducer> OutputConfiguration::getGraphicBufferProducer() const { + return mGbp; +} + +int OutputConfiguration::getRotation() const { + return mRotation; +} + +OutputConfiguration::OutputConfiguration(const Parcel& parcel) { + status_t err; + int rotation = 0; + if ((err = parcel.readInt32(&rotation)) != OK) { + ALOGE("%s: Failed to read rotation from parcel", __FUNCTION__); + mGbp = NULL; + mRotation = INVALID_ROTATION; + return; + } + + String16 name = readMaybeEmptyString16(parcel); + const sp<IGraphicBufferProducer>& gbp = + interface_cast<IGraphicBufferProducer>(parcel.readStrongBinder()); + mGbp = gbp; + mRotation = rotation; + + ALOGV("%s: OutputConfiguration: bp = %p, name = %s", __FUNCTION__, + gbp.get(), String8(name).string()); +} + +status_t OutputConfiguration::writeToParcel(Parcel& parcel) const { + + parcel.writeInt32(mRotation); + parcel.writeString16(String16("unknown_name")); // name of surface + sp<IBinder> b(mGbp->asBinder()); + parcel.writeStrongBinder(b); + + return OK; +} + +}; // namespace android + diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp index 1f5867a..24b2327 100644 --- a/camera/tests/ProCameraTests.cpp +++ b/camera/tests/ProCameraTests.cpp @@ -89,6 +89,12 @@ struct ServiceListener : public BnCameraServiceListener { mCondition.broadcast(); } + void onTorchStatusChanged(TorchStatus status, const String16& cameraId) { + dout << "On torch status changed: 0x" << std::hex + << (unsigned int) status << " cameraId " << cameraId.string() + << std::endl; + } + status_t waitForStatusChange(Status& newStatus) { Mutex::Autolock al(mMutex); @@ -469,7 +475,7 @@ protected: CMP_STR(NV16, YCbCr_422_SP); CMP_STR(NV21, YCrCb_420_SP); CMP_STR(YUY2, YCbCr_422_I); - CMP_STR(RAW, RAW_SENSOR); + CMP_STR(RAW, RAW16); CMP_STR(RGBA, RGBA_8888); std::cerr << "Unknown format string " << str << std::endl; diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h index f7f06bb..194a646 100644 --- a/include/camera/ICameraService.h +++ b/include/camera/ICameraService.h @@ -53,6 +53,7 @@ public: GET_LEGACY_PARAMETERS, SUPPORTS_CAMERA_API, CONNECT_LEGACY, + SET_TORCH_MODE, }; enum { @@ -142,6 +143,21 @@ public: int clientUid, /*out*/ sp<ICamera>& device) = 0; + + /** + * Turn on or off a camera's torch mode. Torch mode will be turned off by + * camera service if the lastest client binder that turns it on dies. + * + * return values: + * 0: on a successful operation. + * -ENOSYS: the camera device doesn't support this operation. It it returned + * if and only if android.flash.into.available is false. + * -EBUSY: the camera device is opened. + * -EINVAL: camera_id is invalid or clientBinder is NULL when enabling a + * torch mode. + */ + virtual status_t setTorchMode(const String16& cameraId, bool enabled, + const sp<IBinder>& clientBinder) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h index 0a0e43a..709ff31 100644 --- a/include/camera/ICameraServiceListener.h +++ b/include/camera/ICameraServiceListener.h @@ -66,9 +66,35 @@ public: STATUS_UNKNOWN = 0xFFFFFFFF, }; + /** + * The torch mode status of a camera. + * + * Initial status will be transmitted with onTorchStatusChanged immediately + * after this listener is added to the service listener list. + * + * The enums should be set to values matching + * include/hardware/camera_common.h + */ + enum TorchStatus { + // The camera's torch mode has become not available to use via + // setTorchMode(). + TORCH_STATUS_NOT_AVAILABLE = TORCH_MODE_STATUS_NOT_AVAILABLE, + // The camera's torch mode is off and available to be turned on via + // setTorchMode(). + TORCH_STATUS_AVAILABLE_OFF = TORCH_MODE_STATUS_AVAILABLE_OFF, + // The camera's torch mode is on and available to be turned off via + // setTorchMode(). + TORCH_STATUS_AVAILABLE_ON = TORCH_MODE_STATUS_AVAILABLE_ON, + + // Use to initialize variables only + TORCH_STATUS_UNKNOWN = 0xFFFFFFFF, + }; + DECLARE_META_INTERFACE(CameraServiceListener); virtual void onStatusChanged(Status status, int32_t cameraId) = 0; + + virtual void onTorchStatusChanged(TorchStatus status, const String16& cameraId) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/camera/camera2/ICameraDeviceUser.h b/include/camera/camera2/ICameraDeviceUser.h index 35488bb..e9f1f5a 100644 --- a/include/camera/camera2/ICameraDeviceUser.h +++ b/include/camera/camera2/ICameraDeviceUser.h @@ -27,9 +27,9 @@ namespace android { class ICameraDeviceUserClient; class IGraphicBufferProducer; -class Surface; class CaptureRequest; class CameraMetadata; +class OutputConfiguration; enum { NO_IN_FLIGHT_REPEATING_FRAMES = -1, @@ -100,9 +100,8 @@ public: virtual status_t endConfigure() = 0; virtual status_t deleteStream(int streamId) = 0; - virtual status_t createStream( - int width, int height, int format, - const sp<IGraphicBufferProducer>& bufferProducer) = 0; + + virtual status_t createStream(const OutputConfiguration& outputConfiguration) = 0; // Create a request object from a template. virtual status_t createDefaultRequest(int templateId, diff --git a/include/camera/camera2/OutputConfiguration.h b/include/camera/camera2/OutputConfiguration.h new file mode 100644 index 0000000..e6b679f --- /dev/null +++ b/include/camera/camera2/OutputConfiguration.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 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_HARDWARE_CAMERA2_OUTPUTCONFIGURATION_H +#define ANDROID_HARDWARE_CAMERA2_OUTPUTCONFIGURATION_H + +#include <utils/RefBase.h> +#include <gui/IGraphicBufferProducer.h> + +namespace android { + +class Surface; + +class OutputConfiguration : public virtual RefBase { +public: + + static const int INVALID_ROTATION; + sp<IGraphicBufferProducer> getGraphicBufferProducer() const; + int getRotation() const; + + /** + * Keep impl up-to-date with OutputConfiguration.java in frameworks/base + */ + status_t writeToParcel(Parcel& parcel) const; + // getGraphicBufferProducer will be NULL if error occurred + // getRotation will be INVALID_ROTATION if error occurred + OutputConfiguration(const Parcel& parcel); + +private: + sp<IGraphicBufferProducer> mGbp; + int mRotation; + + // helper function + static String16 readMaybeEmptyString16(const Parcel& parcel); +}; +}; // namespace android + +#endif diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk index e184d97..5d6423a 100644 --- a/services/camera/libcameraservice/Android.mk +++ b/services/camera/libcameraservice/Android.mk @@ -23,8 +23,10 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ CameraService.cpp \ CameraDeviceFactory.cpp \ + CameraFlashlight.cpp \ common/Camera2ClientBase.cpp \ common/CameraDeviceBase.cpp \ + common/CameraModule.cpp \ common/FrameProcessorBase.cpp \ api1/CameraClient.cpp \ api1/Camera2Client.cpp \ diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp new file mode 100644 index 0000000..b3449e2 --- /dev/null +++ b/services/camera/libcameraservice/CameraFlashlight.cpp @@ -0,0 +1,875 @@ +/* + * Copyright (C) 2015 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 "CameraFlashlight" +#define ATRACE_TAG ATRACE_TAG_CAMERA +// #define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Trace.h> +#include <cutils/properties.h> + +#include "camera/CameraMetadata.h" +#include "CameraFlashlight.h" +#include "gui/IGraphicBufferConsumer.h" +#include "gui/BufferQueue.h" +#include "camera/camera2/CaptureRequest.h" +#include "CameraDeviceFactory.h" + + +namespace android { + +///////////////////////////////////////////////////////////////////// +// CameraFlashlight implementation begins +// used by camera service to control flashflight. +///////////////////////////////////////////////////////////////////// +CameraFlashlight::CameraFlashlight(CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks) : + mCameraModule(&cameraModule), + mCallbacks(&callbacks), + mFlashlightMapInitialized(false) { +} + +CameraFlashlight::~CameraFlashlight() { +} + +status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) { + ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__, + cameraId.string()); + if (mFlashControl != NULL) { + return INVALID_OPERATION; + } + + status_t res = OK; + + if (mCameraModule->getRawModule()->module_api_version >= + CAMERA_MODULE_API_VERSION_2_4) { + mFlashControl = new ModuleFlashControl(*mCameraModule, *mCallbacks); + if (mFlashControl == NULL) { + ALOGV("%s: cannot create flash control for module api v2.4+", + __FUNCTION__); + return NO_MEMORY; + } + } else { + uint32_t deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; + + if (mCameraModule->getRawModule()->module_api_version >= + CAMERA_MODULE_API_VERSION_2_0) { + camera_info info; + res = mCameraModule->getCameraInfo( + atoi(String8(cameraId).string()), &info); + if (res) { + ALOGE("%s: failed to get camera info for camera %s", + __FUNCTION__, cameraId.string()); + return res; + } + deviceVersion = info.device_version; + } + + if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) { + CameraDeviceClientFlashControl *flashControl = + new CameraDeviceClientFlashControl(*mCameraModule, + *mCallbacks); + if (!flashControl) { + return NO_MEMORY; + } + + mFlashControl = flashControl; + } else { + mFlashControl = + new CameraHardwareInterfaceFlashControl(*mCameraModule, + *mCallbacks); + } + } + + return OK; +} + +status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) { + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return NO_INIT; + } + + ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__, + cameraId.string(), enabled); + + status_t res = OK; + Mutex::Autolock l(mLock); + + if (mFlashControl == NULL) { + if (enabled == false) { + return OK; + } + + res = createFlashlightControl(cameraId); + if (res) { + return res; + } + res = mFlashControl->setTorchMode(cameraId, enabled); + return res; + } + + // if flash control already exists, turning on torch mode may fail if it's + // tied to another camera device for module v2.3 and below. + res = mFlashControl->setTorchMode(cameraId, enabled); + if (res == BAD_INDEX) { + // flash control is tied to another camera device, need to close it and + // try again. + mFlashControl.clear(); + res = createFlashlightControl(cameraId); + if (res) { + return res; + } + res = mFlashControl->setTorchMode(cameraId, enabled); + } + + return res; +} + +status_t CameraFlashlight::findFlashUnits() { + Mutex::Autolock l(mLock); + status_t res; + int32_t numCameras = mCameraModule->getNumberOfCameras(); + + mHasFlashlightMap.clear(); + mFlashlightMapInitialized = false; + + for (int32_t i = 0; i < numCameras; i++) { + bool hasFlash = false; + String8 id = String8::format("%d", i); + + res = createFlashlightControl(id); + if (res) { + ALOGE("%s: failed to create flash control for %s", __FUNCTION__, + id.string()); + } else { + res = mFlashControl->hasFlashUnit(id, &hasFlash); + if (res == -EUSERS || res == -EBUSY) { + ALOGE("%s: failed to check if camera %s has a flash unit. Some " + "camera devices may be opened", __FUNCTION__, + id.string()); + return res; + } else if (res) { + ALOGE("%s: failed to check if camera %s has a flash unit. %s" + " (%d)", __FUNCTION__, id.string(), strerror(-res), + res); + } + + mFlashControl.clear(); + } + mHasFlashlightMap.add(id, hasFlash); + } + + mFlashlightMapInitialized = true; + return OK; +} + +bool CameraFlashlight::hasFlashUnit(const String8& cameraId) { + status_t res; + + Mutex::Autolock l(mLock); + return hasFlashUnitLocked(cameraId); +} + +bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) { + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return false; + } + + ssize_t index = mHasFlashlightMap.indexOfKey(cameraId); + if (index == NAME_NOT_FOUND) { + ALOGE("%s: camera %s not present when findFlashUnits() was called", + __FUNCTION__, cameraId.string()); + return false; + } + + return mHasFlashlightMap.valueAt(index); +} + +status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) { + ALOGV("%s: prepare for device open", __FUNCTION__); + + Mutex::Autolock l(mLock); + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return NO_INIT; + } + + if (mCameraModule->getRawModule()->module_api_version < + CAMERA_MODULE_API_VERSION_2_4) { + // framework is going to open a camera device, all flash light control + // should be closed for backward compatible support. + mFlashControl.clear(); + + if (mOpenedCameraIds.size() == 0) { + // notify torch unavailable for all cameras with a flash + int numCameras = mCameraModule->getNumberOfCameras(); + for (int i = 0; i < numCameras; i++) { + if (hasFlashUnitLocked(String8::format("%d", i))) { + mCallbacks->torch_mode_status_change(mCallbacks, + String8::format("%d", i).string(), + TORCH_MODE_STATUS_NOT_AVAILABLE); + } + } + } + + // close flash control that may be opened by calling hasFlashUnitLocked. + mFlashControl.clear(); + } + + if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) { + mOpenedCameraIds.add(cameraId); + } + + return OK; +} + +status_t CameraFlashlight::deviceClosed(const String8& cameraId) { + ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string()); + + Mutex::Autolock l(mLock); + if (!mFlashlightMapInitialized) { + ALOGE("%s: findFlashUnits() must be called before this method."); + return NO_INIT; + } + + ssize_t index = mOpenedCameraIds.indexOf(cameraId); + if (index == NAME_NOT_FOUND) { + ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__, + cameraId.string()); + } else { + mOpenedCameraIds.removeAt(index); + } + + // Cannot do anything until all cameras are closed. + if (mOpenedCameraIds.size() != 0) + return OK; + + if (mCameraModule->getRawModule()->module_api_version < + CAMERA_MODULE_API_VERSION_2_4) { + // notify torch available for all cameras with a flash + int numCameras = mCameraModule->getNumberOfCameras(); + for (int i = 0; i < numCameras; i++) { + if (hasFlashUnitLocked(String8::format("%d", i))) { + mCallbacks->torch_mode_status_change(mCallbacks, + String8::format("%d", i).string(), + TORCH_MODE_STATUS_AVAILABLE_OFF); + } + } + } + + return OK; +} +// CameraFlashlight implementation ends + + +FlashControlBase::~FlashControlBase() { +} + +///////////////////////////////////////////////////////////////////// +// ModuleFlashControl implementation begins +// Flash control for camera module v2.4 and above. +///////////////////////////////////////////////////////////////////// +ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks) : + mCameraModule(&cameraModule) { +} + +ModuleFlashControl::~ModuleFlashControl() { +} + +status_t ModuleFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) { + if (!hasFlash) { + return BAD_VALUE; + } + + *hasFlash = false; + Mutex::Autolock l(mLock); + + camera_info info; + status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), + &info); + if (res != 0) { + return res; + } + + CameraMetadata metadata; + metadata = info.static_camera_characteristics; + camera_metadata_entry flashAvailable = + metadata.find(ANDROID_FLASH_INFO_AVAILABLE); + if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) { + *hasFlash = true; + } + + return OK; +} + +status_t ModuleFlashControl::setTorchMode(const String8& cameraId, bool enabled) { + ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__, + cameraId.string(), enabled); + + Mutex::Autolock l(mLock); + return mCameraModule->setTorchMode(cameraId.string(), enabled); +} +// ModuleFlashControl implementation ends + +///////////////////////////////////////////////////////////////////// +// CameraDeviceClientFlashControl implementation begins +// Flash control for camera module <= v2.3 and camera HAL v2-v3 +///////////////////////////////////////////////////////////////////// +CameraDeviceClientFlashControl::CameraDeviceClientFlashControl( + CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks) : + mCameraModule(&cameraModule), + mCallbacks(&callbacks), + mTorchEnabled(false), + mMetadata(NULL), + mStreaming(false) { +} + +CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() { + disconnectCameraDevice(); + if (mMetadata) { + delete mMetadata; + } + + mAnw.clear(); + mSurfaceTexture.clear(); + mProducer.clear(); + mConsumer.clear(); + + if (mTorchEnabled) { + if (mCallbacks) { + ALOGV("%s: notify the framework that torch was turned off", + __FUNCTION__); + mCallbacks->torch_mode_status_change(mCallbacks, + mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF); + } + } +} + +status_t CameraDeviceClientFlashControl::initializeSurface( + sp<CameraDeviceBase> &device, int32_t width, int32_t height) { + status_t res; + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + + mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL, + true, true); + if (mSurfaceTexture == NULL) { + return NO_MEMORY; + } + + int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + res = mSurfaceTexture->setDefaultBufferSize(width, height); + if (res) { + return res; + } + res = mSurfaceTexture->setDefaultBufferFormat(format); + if (res) { + return res; + } + + mAnw = new Surface(mProducer, /*useAsync*/ true); + if (mAnw == NULL) { + return NO_MEMORY; + } + res = device->createStream(mAnw, width, height, format, + HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mStreamId); + if (res) { + return res; + } + + res = device->configureStreams(); + if (res) { + return res; + } + + return res; +} + +status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize( + const camera_info& info, int32_t *width, int32_t *height) { + if (!width || !height) { + return BAD_VALUE; + } + + int32_t w = INT32_MAX; + int32_t h = 1; + + CameraMetadata metadata; + metadata = info.static_camera_characteristics; + camera_metadata_entry streamConfigs = + metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); + for (size_t i = 0; i < streamConfigs.count; i += 4) { + int32_t fmt = streamConfigs.data.i32[i]; + if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED) { + int32_t ww = streamConfigs.data.i32[i + 1]; + int32_t hh = streamConfigs.data.i32[i + 2]; + + if (w * h > ww * hh) { + w = ww; + h = hh; + } + } + } + + // if stream configuration is not found, try available processed sizes. + if (streamConfigs.count == 0) { + camera_metadata_entry availableProcessedSizes = + metadata.find(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES); + for (size_t i = 0; i < availableProcessedSizes.count; i += 2) { + int32_t ww = availableProcessedSizes.data.i32[i]; + int32_t hh = availableProcessedSizes.data.i32[i + 1]; + if (w * h > ww * hh) { + w = ww; + h = hh; + } + } + } + + if (w == INT32_MAX) { + return NAME_NOT_FOUND; + } + + *width = w; + *height = h; + + return OK; +} + +status_t CameraDeviceClientFlashControl::connectCameraDevice( + const String8& cameraId) { + camera_info info; + status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info); + if (res != 0) { + ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__, + cameraId.string()); + return res; + } + + sp<CameraDeviceBase> device = + CameraDeviceFactory::createDevice(atoi(cameraId.string())); + if (device == NULL) { + return NO_MEMORY; + } + + res = device->initialize(mCameraModule); + if (res) { + return res; + } + + int32_t width, height; + res = getSmallestSurfaceSize(info, &width, &height); + if (res) { + return res; + } + res = initializeSurface(device, width, height); + if (res) { + return res; + } + + mCameraId = cameraId; + mStreaming = (info.device_version <= CAMERA_DEVICE_API_VERSION_3_1); + mDevice = device; + + return OK; +} + +status_t CameraDeviceClientFlashControl::disconnectCameraDevice() { + if (mDevice != NULL) { + mDevice->disconnect(); + mDevice.clear(); + } + + return OK; +} + + + +status_t CameraDeviceClientFlashControl::hasFlashUnit(const String8& cameraId, + bool *hasFlash) { + ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__, + cameraId.string()); + + Mutex::Autolock l(mLock); + return hasFlashUnitLocked(cameraId, hasFlash); + +} + +status_t CameraDeviceClientFlashControl::hasFlashUnitLocked( + const String8& cameraId, bool *hasFlash) { + if (!hasFlash) { + return BAD_VALUE; + } + + camera_info info; + status_t res = mCameraModule->getCameraInfo( + atoi(cameraId.string()), &info); + if (res != 0) { + ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__, + cameraId.string()); + return res; + } + + CameraMetadata metadata; + metadata = info.static_camera_characteristics; + camera_metadata_entry flashAvailable = + metadata.find(ANDROID_FLASH_INFO_AVAILABLE); + if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) { + *hasFlash = true; + } + + return OK; +} + +status_t CameraDeviceClientFlashControl::submitTorchEnabledRequest() { + status_t res; + + if (mMetadata == NULL) { + mMetadata = new CameraMetadata(); + if (mMetadata == NULL) { + return NO_MEMORY; + } + res = mDevice->createDefaultRequest( + CAMERA3_TEMPLATE_PREVIEW, mMetadata); + if (res) { + return res; + } + } + + uint8_t torchOn = ANDROID_FLASH_MODE_TORCH; + mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1); + mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1); + + uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON; + mMetadata->update(ANDROID_CONTROL_AE_MODE, &aeMode, 1); + + int32_t requestId = 0; + mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1); + + if (mStreaming) { + res = mDevice->setStreamingRequest(*mMetadata); + } else { + res = mDevice->capture(*mMetadata); + } + return res; +} + + + + +status_t CameraDeviceClientFlashControl::setTorchMode( + const String8& cameraId, bool enabled) { + bool hasFlash = false; + + Mutex::Autolock l(mLock); + status_t res = hasFlashUnitLocked(cameraId, &hasFlash); + + // pre-check + if (enabled) { + // invalid camera? + if (res) { + return -EINVAL; + } + // no flash unit? + if (!hasFlash) { + return -ENOSYS; + } + // already opened for a different device? + if (mDevice != NULL && cameraId != mCameraId) { + return BAD_INDEX; + } + } else if (mDevice == NULL || cameraId != mCameraId) { + // disabling the torch mode of an un-opened or different device. + return OK; + } else { + // disabling the torch mode of currently opened device + disconnectCameraDevice(); + mTorchEnabled = false; + mCallbacks->torch_mode_status_change(mCallbacks, + cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF); + return OK; + } + + if (mDevice == NULL) { + res = connectCameraDevice(cameraId); + if (res) { + return res; + } + } + + res = submitTorchEnabledRequest(); + if (res) { + return res; + } + + mTorchEnabled = true; + mCallbacks->torch_mode_status_change(mCallbacks, + cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON); + return OK; +} +// CameraDeviceClientFlashControl implementation ends + + +///////////////////////////////////////////////////////////////////// +// CameraHardwareInterfaceFlashControl implementation begins +// Flash control for camera module <= v2.3 and camera HAL v1 +///////////////////////////////////////////////////////////////////// +CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl( + CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks) : + mCameraModule(&cameraModule), + mCallbacks(&callbacks), + mTorchEnabled(false) { + +} + +CameraHardwareInterfaceFlashControl::~CameraHardwareInterfaceFlashControl() { + disconnectCameraDevice(); + + mAnw.clear(); + mSurfaceTexture.clear(); + mProducer.clear(); + mConsumer.clear(); + + if (mTorchEnabled) { + if (mCallbacks) { + ALOGV("%s: notify the framework that torch was turned off", + __FUNCTION__); + mCallbacks->torch_mode_status_change(mCallbacks, + mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF); + } + } +} + +status_t CameraHardwareInterfaceFlashControl::setTorchMode( + const String8& cameraId, bool enabled) { + Mutex::Autolock l(mLock); + + // pre-check + status_t res; + if (enabled) { + bool hasFlash = false; + res = hasFlashUnitLocked(cameraId, &hasFlash); + // invalid camera? + if (res) { + // hasFlashUnitLocked() returns BAD_INDEX if mDevice is connected to + // another camera device. + return res == BAD_INDEX ? BAD_INDEX : -EINVAL; + } + // no flash unit? + if (!hasFlash) { + return -ENOSYS; + } + } else if (mDevice == NULL || cameraId != mCameraId) { + // disabling the torch mode of an un-opened or different device. + return OK; + } else { + // disabling the torch mode of currently opened device + disconnectCameraDevice(); + mTorchEnabled = false; + mCallbacks->torch_mode_status_change(mCallbacks, + cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF); + return OK; + } + + res = startPreviewAndTorch(); + if (res) { + return res; + } + + mTorchEnabled = true; + mCallbacks->torch_mode_status_change(mCallbacks, + cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON); + return OK; +} + +status_t CameraHardwareInterfaceFlashControl::hasFlashUnit( + const String8& cameraId, bool *hasFlash) { + Mutex::Autolock l(mLock); + return hasFlashUnitLocked(cameraId, hasFlash); +} + +status_t CameraHardwareInterfaceFlashControl::hasFlashUnitLocked( + const String8& cameraId, bool *hasFlash) { + if (!hasFlash) { + return BAD_VALUE; + } + + status_t res; + if (mDevice == NULL) { + res = connectCameraDevice(cameraId); + if (res) { + return res; + } + } + + if (cameraId != mCameraId) { + return BAD_INDEX; + } + + const char *flashMode = + mParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES); + if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) { + *hasFlash = true; + } else { + *hasFlash = false; + } + + return OK; +} + +status_t CameraHardwareInterfaceFlashControl::startPreviewAndTorch() { + status_t res = OK; + res = mDevice->startPreview(); + if (res) { + ALOGE("%s: start preview failed. %s (%d)", __FUNCTION__, + strerror(-res), res); + return res; + } + + mParameters.set(CameraParameters::KEY_FLASH_MODE, + CameraParameters::FLASH_MODE_TORCH); + + return mDevice->setParameters(mParameters); +} + +status_t CameraHardwareInterfaceFlashControl::getSmallestSurfaceSize( + int32_t *width, int32_t *height) { + if (!width || !height) { + return BAD_VALUE; + } + + int32_t w = INT32_MAX; + int32_t h = 1; + Vector<Size> sizes; + + mParameters.getSupportedPreviewSizes(sizes); + for (size_t i = 0; i < sizes.size(); i++) { + Size s = sizes[i]; + if (w * h > s.width * s.height) { + w = s.width; + h = s.height; + } + } + + if (w == INT32_MAX) { + return NAME_NOT_FOUND; + } + + *width = w; + *height = h; + + return OK; +} + +status_t CameraHardwareInterfaceFlashControl::initializePreviewWindow( + sp<CameraHardwareInterface> device, int32_t width, int32_t height) { + status_t res; + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + + mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL, + true, true); + if (mSurfaceTexture == NULL) { + return NO_MEMORY; + } + + int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + res = mSurfaceTexture->setDefaultBufferSize(width, height); + if (res) { + return res; + } + res = mSurfaceTexture->setDefaultBufferFormat(format); + if (res) { + return res; + } + + mAnw = new Surface(mProducer, /*useAsync*/ true); + if (mAnw == NULL) { + return NO_MEMORY; + } + + res = native_window_api_connect(mAnw.get(), NATIVE_WINDOW_API_CAMERA); + if (res) { + ALOGE("%s: Unable to connect to native window", __FUNCTION__); + return res; + } + + return device->setPreviewWindow(mAnw); +} + +status_t CameraHardwareInterfaceFlashControl::connectCameraDevice( + const String8& cameraId) { + sp<CameraHardwareInterface> device = + new CameraHardwareInterface(cameraId.string()); + + status_t res = device->initialize(mCameraModule); + if (res) { + ALOGE("%s: initializing camera %s failed", __FUNCTION__, + cameraId.string()); + return res; + } + + // need to set __get_memory in set_callbacks(). + device->setCallbacks(NULL, NULL, NULL, NULL); + + mParameters = device->getParameters(); + + int32_t width, height; + res = getSmallestSurfaceSize(&width, &height); + if (res) { + ALOGE("%s: failed to get smallest surface size for camera %s", + __FUNCTION__, cameraId.string()); + return res; + } + + res = initializePreviewWindow(device, width, height); + if (res) { + ALOGE("%s: failed to initialize preview window for camera %s", + __FUNCTION__, cameraId.string()); + return res; + } + + mCameraId = cameraId; + mDevice = device; + return OK; +} + +status_t CameraHardwareInterfaceFlashControl::disconnectCameraDevice() { + if (mDevice == NULL) { + return OK; + } + + mParameters.set(CameraParameters::KEY_FLASH_MODE, + CameraParameters::FLASH_MODE_OFF); + mDevice->setParameters(mParameters); + mDevice->stopPreview(); + status_t res = native_window_api_disconnect(mAnw.get(), + NATIVE_WINDOW_API_CAMERA); + if (res) { + ALOGW("%s: native_window_api_disconnect failed: %s (%d)", + __FUNCTION__, strerror(-res), res); + } + mDevice->setPreviewWindow(NULL); + mDevice->release(); + + return OK; +} +// CameraHardwareInterfaceFlashControl implementation ends + +} diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h new file mode 100644 index 0000000..30f01f0 --- /dev/null +++ b/services/camera/libcameraservice/CameraFlashlight.h @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2015 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_CAMERAFLASHLIGHT_H +#define ANDROID_SERVERS_CAMERA_CAMERAFLASHLIGHT_H + +#include "hardware/camera_common.h" +#include "utils/KeyedVector.h" +#include "utils/SortedVector.h" +#include "gui/GLConsumer.h" +#include "gui/Surface.h" +#include "common/CameraDeviceBase.h" +#include "device1/CameraHardwareInterface.h" + +namespace android { + +/** + * FlashControlBase is a base class for flash control. It defines the functions + * that a flash control for each camera module/device version should implement. + */ +class FlashControlBase : public virtual VirtualLightRefBase { + public: + virtual ~FlashControlBase(); + + // Whether a camera device has a flash unit. Calling this function may + // cause the torch mode to be turned off in HAL v1 devices. If + // previously-on torch mode is turned off, + // callbacks.torch_mode_status_change() should be invoked. + virtual status_t hasFlashUnit(const String8& cameraId, + bool *hasFlash) = 0; + + // set the torch mode to on or off. + virtual status_t setTorchMode(const String8& cameraId, + bool enabled) = 0; +}; + +/** + * CameraFlashlight can be used by camera service to control flashflight. + */ +class CameraFlashlight : public virtual VirtualLightRefBase { + public: + CameraFlashlight(CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks); + virtual ~CameraFlashlight(); + + // Find all flash units. This must be called before other methods. All + // camera devices must be closed when it's called because HAL v1 devices + // need to be opened to query available flash modes. + status_t findFlashUnits(); + + // Whether a camera device has a flash unit. Before findFlashUnits() is + // called, this function always returns false. + bool hasFlashUnit(const String8& cameraId); + + // set the torch mode to on or off. + status_t setTorchMode(const String8& cameraId, bool enabled); + + // Notify CameraFlashlight that camera service is going to open a camera + // device. CameraFlashlight will free the resources that may cause the + // camera open to fail. Camera service must call this function before + // opening a camera device. + status_t prepareDeviceOpen(const String8& cameraId); + + // Notify CameraFlashlight that camera service has closed a camera + // device. CameraFlashlight may invoke callbacks for torch mode + // available depending on the implementation. + status_t deviceClosed(const String8& cameraId); + + private: + // create flashlight control based on camera module API and camera + // device API versions. + status_t createFlashlightControl(const String8& cameraId); + + // mLock should be locked. + bool hasFlashUnitLocked(const String8& cameraId); + + sp<FlashControlBase> mFlashControl; + CameraModule *mCameraModule; + const camera_module_callbacks_t *mCallbacks; + SortedVector<String8> mOpenedCameraIds; + + // camera id -> if it has a flash unit + KeyedVector<String8, bool> mHasFlashlightMap; + bool mFlashlightMapInitialized; + + Mutex mLock; // protect CameraFlashlight API +}; + +/** + * Flash control for camera module v2.4 and above. + */ +class ModuleFlashControl : public FlashControlBase { + public: + ModuleFlashControl(CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks); + virtual ~ModuleFlashControl(); + + // FlashControlBase + status_t hasFlashUnit(const String8& cameraId, bool *hasFlash); + status_t setTorchMode(const String8& cameraId, bool enabled); + + private: + CameraModule *mCameraModule; + + Mutex mLock; +}; + +/** + * Flash control for camera module <= v2.3 and camera HAL v2-v3 + */ +class CameraDeviceClientFlashControl : public FlashControlBase { + public: + CameraDeviceClientFlashControl(CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks); + virtual ~CameraDeviceClientFlashControl(); + + // FlashControlBase + status_t setTorchMode(const String8& cameraId, bool enabled); + status_t hasFlashUnit(const String8& cameraId, bool *hasFlash); + + private: + // connect to a camera device + status_t connectCameraDevice(const String8& cameraId); + // disconnect and free mDevice + status_t disconnectCameraDevice(); + + // initialize a surface + status_t initializeSurface(sp<CameraDeviceBase>& device, int32_t width, + int32_t height); + + // submit a request to enable the torch mode + status_t submitTorchEnabledRequest(); + + // get the smallest surface size of IMPLEMENTATION_DEFINED + status_t getSmallestSurfaceSize(const camera_info& info, int32_t *width, + int32_t *height); + + // protected by mLock + status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash); + + CameraModule *mCameraModule; + const camera_module_callbacks_t *mCallbacks; + String8 mCameraId; + bool mTorchEnabled; + CameraMetadata *mMetadata; + // WORKAROUND: will be set to true for HAL v2 devices where + // setStreamingRequest() needs to be call for torch mode settings to + // take effect. + bool mStreaming; + + sp<CameraDeviceBase> mDevice; + + sp<IGraphicBufferProducer> mProducer; + sp<IGraphicBufferConsumer> mConsumer; + sp<GLConsumer> mSurfaceTexture; + sp<ANativeWindow> mAnw; + int32_t mStreamId; + + Mutex mLock; +}; + +/** + * Flash control for camera module <= v2.3 and camera HAL v1 + */ +class CameraHardwareInterfaceFlashControl : public FlashControlBase { + public: + CameraHardwareInterfaceFlashControl(CameraModule& cameraModule, + const camera_module_callbacks_t& callbacks); + virtual ~CameraHardwareInterfaceFlashControl(); + + // FlashControlBase + status_t setTorchMode(const String8& cameraId, bool enabled); + status_t hasFlashUnit(const String8& cameraId, bool *hasFlash); + + private: + // connect to a camera device + status_t connectCameraDevice(const String8& cameraId); + + // disconnect and free mDevice + status_t disconnectCameraDevice(); + + // initialize the preview window + status_t initializePreviewWindow(sp<CameraHardwareInterface> device, + int32_t width, int32_t height); + + // start preview and enable torch + status_t startPreviewAndTorch(); + + // get the smallest surface + status_t getSmallestSurfaceSize(int32_t *width, int32_t *height); + + // protected by mLock + status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash); + + CameraModule *mCameraModule; + const camera_module_callbacks_t *mCallbacks; + sp<CameraHardwareInterface> mDevice; + String8 mCameraId; + CameraParameters mParameters; + bool mTorchEnabled; + + sp<IGraphicBufferProducer> mProducer; + sp<IGraphicBufferConsumer> mConsumer; + sp<GLConsumer> mSurfaceTexture; + sp<ANativeWindow> mAnw; + + Mutex mLock; +}; + +} // namespace android + +#endif diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 76428da..5ba3a5c 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -29,6 +29,7 @@ #include <binder/MemoryHeapBase.h> #include <cutils/atomic.h> #include <cutils/properties.h> +#include <cutils/multiuser.h> #include <gui/Surface.h> #include <hardware/hardware.h> #include <media/AudioSystem.h> @@ -86,6 +87,38 @@ static void camera_device_status_change( camera_id, new_status); } + +static void torch_mode_status_change( + const struct camera_module_callbacks* callbacks, + const char* camera_id, + int new_status) { + if (!callbacks || !camera_id) { + ALOGE("%s invalid parameters. callbacks %p, camera_id %p", __FUNCTION__, + callbacks, camera_id); + } + sp<CameraService> cs = const_cast<CameraService*>( + static_cast<const CameraService*>(callbacks)); + + ICameraServiceListener::TorchStatus status; + switch (new_status) { + case TORCH_MODE_STATUS_NOT_AVAILABLE: + status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE; + break; + case TORCH_MODE_STATUS_AVAILABLE_OFF: + status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF; + break; + case TORCH_MODE_STATUS_AVAILABLE_ON: + status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON; + break; + default: + ALOGE("Unknown torch status %d", new_status); + return; + } + + cs->onTorchStatusChanged( + String8(camera_id), + status); +} } // extern "C" // ---------------------------------------------------------------------------- @@ -95,7 +128,7 @@ static void camera_device_status_change( static CameraService *gCameraService; CameraService::CameraService() - :mSoundRef(0), mModule(0) + :mSoundRef(0), mModule(0), mFlashlight(0) { ALOGI("CameraService started (pid=%d)", getpid()); gCameraService = this; @@ -105,6 +138,8 @@ CameraService::CameraService() } this->camera_device_status_change = android::camera_device_status_change; + this->torch_mode_status_change = android::torch_mode_status_change; + } void CameraService::onFirstRef() @@ -113,31 +148,47 @@ void CameraService::onFirstRef() BnCameraService::onFirstRef(); + camera_module_t *rawModule; if (hw_get_module(CAMERA_HARDWARE_MODULE_ID, - (const hw_module_t **)&mModule) < 0) { + (const hw_module_t **)&rawModule) < 0) { ALOGE("Could not load camera HAL module"); mNumberOfCameras = 0; } else { - ALOGI("Loaded \"%s\" camera module", mModule->common.name); - mNumberOfCameras = mModule->get_number_of_cameras(); + mModule = new CameraModule(rawModule); + const hw_module_t *common = mModule->getRawModule(); + ALOGI("Loaded \"%s\" cameraCa module", common->name); + mNumberOfCameras = mModule->getNumberOfCameras(); if (mNumberOfCameras > MAX_CAMERAS) { ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).", mNumberOfCameras, MAX_CAMERAS); mNumberOfCameras = MAX_CAMERAS; } + + mFlashlight = new CameraFlashlight(*mModule, *this); + status_t res = mFlashlight->findFlashUnits(); + if (res) { + // impossible because we haven't open any camera devices. + ALOGE("failed to find flash units."); + } + for (int i = 0; i < mNumberOfCameras; i++) { setCameraFree(i); + + String8 cameraName = String8::format("%d", i); + if (mFlashlight->hasFlashUnit(cameraName)) { + mTorchStatusMap.add(cameraName, + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); + } } - if (mModule->common.module_api_version >= - CAMERA_MODULE_API_VERSION_2_1) { - mModule->set_callbacks(this); + if (common->module_api_version >= CAMERA_MODULE_API_VERSION_2_1) { + mModule->setCallbacks(this); } VendorTagDescriptor::clearGlobalVendorTagDescriptor(); - if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) { + if (common->module_api_version >= CAMERA_MODULE_API_VERSION_2_2) { setUpVendorTags(); } @@ -152,6 +203,9 @@ CameraService::~CameraService() { } } + if (mModule) { + delete mModule; + } VendorTagDescriptor::clearGlobalVendorTagDescriptor(); gCameraService = NULL; } @@ -159,7 +213,7 @@ CameraService::~CameraService() { void CameraService::onDeviceStatusChanged(int cameraId, int newStatus) { - ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__, + ALOGV("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__, cameraId, newStatus); if (cameraId < 0 || cameraId >= MAX_CAMERAS) { @@ -220,6 +274,43 @@ void CameraService::onDeviceStatusChanged(int cameraId, } +void CameraService::onTorchStatusChanged(const String8& cameraId, + ICameraServiceListener::TorchStatus newStatus) { + Mutex::Autolock al(mTorchStatusMutex); + onTorchStatusChangedLocked(cameraId, newStatus); +} + +void CameraService::onTorchStatusChangedLocked(const String8& cameraId, + ICameraServiceListener::TorchStatus newStatus) { + ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d", + __FUNCTION__, cameraId.string(), newStatus); + + ICameraServiceListener::TorchStatus status; + status_t res = getTorchStatusLocked(cameraId, &status); + if (res) { + ALOGE("%s: cannot get torch status of camera %s", cameraId.string()); + return; + } + if (status == newStatus) { + ALOGE("%s: Torch state transition to the same status 0x%x not allowed", + __FUNCTION__, (uint32_t)newStatus); + return; + } + + res = setTorchStatusLocked(cameraId, newStatus); + if (res) { + ALOGE("%s: Failed to set the torch status", __FUNCTION__, + (uint32_t)newStatus); + return; + } + + Vector<sp<ICameraServiceListener> >::const_iterator it; + for (it = mListenerList.begin(); it != mListenerList.end(); ++it) { + (*it)->onTorchStatusChanged(newStatus, String16(cameraId.string())); + } +} + + int32_t CameraService::getNumberOfCameras() { return mNumberOfCameras; } @@ -236,7 +327,7 @@ status_t CameraService::getCameraInfo(int cameraId, struct camera_info info; status_t rc = filterGetInfoErrorCode( - mModule->get_camera_info(cameraId, &info)); + mModule->getCameraInfo(cameraId, &info)); cameraInfo->facing = info.facing; cameraInfo->orientation = info.orientation; return rc; @@ -347,7 +438,7 @@ status_t CameraService::getCameraCharacteristics(int cameraId, int facing; status_t ret = OK; - if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0 || + if (mModule->getRawModule()->module_api_version < CAMERA_MODULE_API_VERSION_2_0 || getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) { /** * Backwards compatibility mode for old HALs: @@ -368,7 +459,7 @@ status_t CameraService::getCameraCharacteristics(int cameraId, * Normal HAL 2.1+ codepath. */ struct camera_info info; - ret = filterGetInfoErrorCode(mModule->get_camera_info(cameraId, &info)); + ret = filterGetInfoErrorCode(mModule->getCameraInfo(cameraId, &info)); *cameraInfo = info.static_camera_characteristics; } @@ -387,12 +478,12 @@ status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescript int CameraService::getDeviceVersion(int cameraId, int* facing) { struct camera_info info; - if (mModule->get_camera_info(cameraId, &info) != OK) { + if (mModule->getCameraInfo(cameraId, &info) != OK) { return -1; } int deviceVersion; - if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_0) { + if (mModule->getRawModule()->module_api_version >= CAMERA_MODULE_API_VERSION_2_0) { deviceVersion = info.device_version; } else { deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; @@ -405,19 +496,6 @@ int CameraService::getDeviceVersion(int cameraId, int* facing) { return deviceVersion; } -status_t CameraService::filterOpenErrorCode(status_t err) { - switch(err) { - case NO_ERROR: - case -EBUSY: - case -EINVAL: - case -EUSERS: - return err; - default: - break; - } - return -ENODEV; -} - status_t CameraService::filterGetInfoErrorCode(status_t err) { switch(err) { case NO_ERROR: @@ -433,13 +511,13 @@ bool CameraService::setUpVendorTags() { vendor_tag_ops_t vOps = vendor_tag_ops_t(); // Check if vendor operations have been implemented - if (mModule->get_vendor_tag_ops == NULL) { + if (!mModule->isVendorTagDefined()) { ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__); return false; } ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops"); - mModule->get_vendor_tag_ops(&vOps); + mModule->getVendorTagOps(&vOps); ATRACE_END(); // Ensure all vendor operations are present @@ -592,7 +670,10 @@ status_t CameraService::validateConnect(int cameraId, } char value[PROPERTY_VALUE_MAX]; - property_get("sys.secpolicy.camera.disabled", value, "0"); + char key[PROPERTY_KEY_MAX]; + int clientUserId = multiuser_get_user_id(clientUid); + snprintf(key, PROPERTY_KEY_MAX, "sys.secpolicy.camera.off_%d", clientUserId); + property_get(key, value, "0"); if (strcmp(value, "1") == 0) { // Camera is disabled by DevicePolicyManager. ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid); @@ -671,6 +752,9 @@ status_t CameraService::connectHelperLocked( int halVersion, bool legacyMode) { + // give flashlight a chance to close devices if necessary. + mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId)); + int facing = -1; int deviceVersion = getDeviceVersion(cameraId, &facing); @@ -789,8 +873,9 @@ status_t CameraService::connectLegacy( /*out*/ sp<ICamera>& device) { + int apiVersion = mModule->getRawModule()->module_api_version; if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED && - mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_3) { + apiVersion < CAMERA_MODULE_API_VERSION_2_3) { /* * Either the HAL version is unspecified in which case this just creates * a camera client selected by the latest device version, or @@ -798,7 +883,7 @@ status_t CameraService::connectLegacy( * the open_legacy call */ ALOGE("%s: camera HAL module version %x doesn't support connecting to legacy HAL devices!", - __FUNCTION__, mModule->common.module_api_version); + __FUNCTION__, apiVersion); return INVALID_OPERATION; } @@ -846,6 +931,97 @@ status_t CameraService::connectLegacy( return OK; } +bool CameraService::validCameraIdForSetTorchMode(const String8& cameraId) { + // invalid string for int + if (cameraId.string() == NULL) { + return false; + } + errno = 0; + char *endptr; + long id = strtol(cameraId.string(), &endptr, 10); // base 10 + if (errno || id > INT_MAX || id < INT_MIN || *endptr != 0) { + return false; + } + + // id matches one of the plugged-in devices? + ICameraServiceListener::Status deviceStatus = getStatus(id); + if (deviceStatus != ICameraServiceListener::STATUS_PRESENT && + deviceStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) { + return false; + } + + return true; +} + +status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, + const sp<IBinder>& clientBinder) { + if (enabled && clientBinder == NULL) { + ALOGE("%s: torch client binder is NULL", __FUNCTION__); + return -EINVAL; + } + + String8 id = String8(cameraId.string()); + + // verify id is valid. + if (validCameraIdForSetTorchMode(id) == false) { + ALOGE("%s: camera id is invalid %s", id.string()); + return -EINVAL; + } + + { + Mutex::Autolock al(mTorchStatusMutex); + ICameraServiceListener::TorchStatus status; + status_t res = getTorchStatusLocked(id, &status); + if (res) { + ALOGE("%s: getting current torch status failed for camera %s", + __FUNCTION__, id.string()); + return -EINVAL; + } + + if (status == ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE) { + if (getStatus(atoi(id.string())) == + ICameraServiceListener::STATUS_NOT_AVAILABLE) { + ALOGE("%s: torch mode of camera %s is not available because " + "camera is in use", __FUNCTION__, id.string()); + return -EBUSY; + } else { + ALOGE("%s: torch mode of camera %s is not available due to " + "insufficient resources", __FUNCTION__, id.string()); + return -EUSERS; + } + } + } + + status_t res = mFlashlight->setTorchMode(id, enabled); + if (res) { + ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)", + __FUNCTION__, id.string(), enabled, strerror(-res), res); + return res; + } + + { + // update the link to client's death + Mutex::Autolock al(mTorchClientMapMutex); + ssize_t index = mTorchClientMap.indexOfKey(id); + if (enabled) { + if (index == NAME_NOT_FOUND) { + mTorchClientMap.add(id, clientBinder); + } else { + const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); + oldBinder->unlinkToDeath(this); + + mTorchClientMap.replaceValueAt(index, clientBinder); + } + clientBinder->linkToDeath(this); + } else if (index != NAME_NOT_FOUND) { + sp<IBinder> oldBinder = mTorchClientMap.valueAt(index); + oldBinder->unlinkToDeath(this); + } + } + + return OK; +} + status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client, const sp<IBinder>& remoteCallback) { status_t status = client->initialize(mModule); @@ -971,6 +1147,9 @@ status_t CameraService::connectDevice( int facing = -1; int deviceVersion = getDeviceVersion(cameraId, &facing); + // give flashlight a chance to close devices if necessary. + mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId)); + switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: ALOGW("Camera using old HAL version: %d", deviceVersion); @@ -1042,6 +1221,16 @@ status_t CameraService::addListener( } } + /* Immediately signal current torch status to this listener only */ + { + Mutex::Autolock al(mTorchStatusMutex); + for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) { + String16 id = String16(mTorchStatusMap.keyAt(i).string()); + listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), id); + } + + } + return OK; } status_t CameraService::removeListener( @@ -1475,6 +1664,9 @@ status_t CameraService::BasicClient::finishCameraOps() { mCameraId, &rejectSourceStates); + // Notify flashlight that a camera device is closed. + mCameraService->mFlashlight->deviceClosed( + String8::format("%d", mCameraId)); } // Always stop watching, even if no camera op is active mAppOpsManager.stopWatchingMode(mOpsCallback); @@ -1630,14 +1822,11 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { return NO_ERROR; } - result = String8::format("Camera module HAL API version: 0x%x\n", - mModule->common.hal_api_version); - result.appendFormat("Camera module API version: 0x%x\n", - mModule->common.module_api_version); - result.appendFormat("Camera module name: %s\n", - mModule->common.name); - result.appendFormat("Camera module author: %s\n", - mModule->common.author); + const hw_module_t* common = mModule->getRawModule(); + result = String8::format("Camera module HAL API version: 0x%x\n", common->hal_api_version); + result.appendFormat("Camera module API version: 0x%x\n", common->module_api_version); + result.appendFormat("Camera module name: %s\n", common->name); + result.appendFormat("Camera module author: %s\n", common->author); result.appendFormat("Number of camera devices: %d\n\n", mNumberOfCameras); sp<VendorTagDescriptor> desc = VendorTagDescriptor::getGlobalVendorTagDescriptor(); @@ -1657,7 +1846,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { result = String8::format("Camera %d static information:\n", i); camera_info info; - status_t rc = mModule->get_camera_info(i, &info); + status_t rc = mModule->getCameraInfo(i, &info); if (rc != OK) { result.appendFormat(" Error reading static information!\n"); write(fd, result.string(), result.size()); @@ -1666,8 +1855,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT"); result.appendFormat(" Orientation: %d\n", info.orientation); int deviceVersion; - if (mModule->common.module_api_version < - CAMERA_MODULE_API_VERSION_2_0) { + if (common->module_api_version < CAMERA_MODULE_API_VERSION_2_0) { deviceVersion = CAMERA_DEVICE_API_VERSION_1_0; } else { deviceVersion = info.device_version; @@ -1722,6 +1910,24 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { return NO_ERROR; } +void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) { + Mutex::Autolock al(mTorchClientMapMutex); + for (size_t i = 0; i < mTorchClientMap.size(); i++) { + if (mTorchClientMap[i] == who) { + // turn off the torch mode that was turned on by dead client + String8 cameraId = mTorchClientMap.keyAt(i); + status_t res = mFlashlight->setTorchMode(cameraId, false); + if (res) { + ALOGE("%s: torch client died but couldn't turn off torch: " + "%s (%d)", __FUNCTION__, strerror(-res), res); + return; + } + mTorchClientMap.removeItemsAt(i); + break; + } + } +} + /*virtual*/void CameraService::binderDied( const wp<IBinder> &who) { @@ -1732,6 +1938,10 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { ALOGV("java clients' binder died"); + // check torch client + handleTorchClientBinderDied(who); + + // check camera device client sp<BasicClient> cameraClient = getClientByRemote(who); if (cameraClient == 0) { @@ -1808,6 +2018,19 @@ void CameraService::updateStatus(ICameraServiceListener::Status status, } } + if (status == ICameraServiceListener::STATUS_NOT_PRESENT || + status == ICameraServiceListener::STATUS_NOT_AVAILABLE) { + // update torch status to not available when the camera device + // becomes not present or not available. + onTorchStatusChanged(String8::format("%d", cameraId), + ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE); + } else if (status == ICameraServiceListener::STATUS_PRESENT) { + // update torch status to available when the camera device becomes + // present or available + onTorchStatusChanged(String8::format("%d", cameraId), + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF); + } + Vector<sp<ICameraServiceListener> >::const_iterator it; for (it = mListenerList.begin(); it != mListenerList.end(); ++it) { (*it)->onStatusChanged(status, cameraId); @@ -1825,4 +2048,33 @@ ICameraServiceListener::Status CameraService::getStatus(int cameraId) const { return mStatusList[cameraId]; } +status_t CameraService::getTorchStatusLocked( + const String8& cameraId, + ICameraServiceListener::TorchStatus *status) const { + if (!status) { + return BAD_VALUE; + } + ssize_t index = mTorchStatusMap.indexOfKey(cameraId); + if (index == NAME_NOT_FOUND) { + // invalid camera ID or the camera doesn't have a flash unit + return NAME_NOT_FOUND; + } + + *status = mTorchStatusMap.valueAt(index); + return OK; +} + +status_t CameraService::setTorchStatusLocked(const String8& cameraId, + ICameraServiceListener::TorchStatus status) { + ssize_t index = mTorchStatusMap.indexOfKey(cameraId); + if (index == NAME_NOT_FOUND) { + return BAD_VALUE; + } + ICameraServiceListener::TorchStatus& item = + mTorchStatusMap.editValueAt(index); + item = status; + + return OK; +} + }; // namespace android diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index a7328cf..5e2817d 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -36,6 +36,10 @@ #include <camera/CameraParameters.h> #include <camera/ICameraServiceListener.h> +#include "CameraFlashlight.h" + + +#include "common/CameraModule.h" /* This needs to be increased if we can have more cameras */ #define MAX_CAMERAS 2 @@ -68,6 +72,9 @@ public: // HAL Callbacks virtual void onDeviceStatusChanged(int cameraId, int newStatus); + virtual void onTorchStatusChanged(const String8& cameraId, + ICameraServiceListener::TorchStatus + newStatus); ///////////////////////////////////////////////////////////////////// // ICameraService @@ -110,6 +117,9 @@ public: /*out*/ String16* parameters); + virtual status_t setTorchMode(const String16& cameraId, bool enabled, + const sp<IBinder>& clientBinder); + // OK = supports api of that version, -EOPNOTSUPP = does not support virtual status_t supportsCameraApi( int cameraId, int apiVersion); @@ -140,7 +150,6 @@ public: ///////////////////////////////////////////////////////////////////// // Shared utilities - static status_t filterOpenErrorCode(status_t err); static status_t filterGetInfoErrorCode(status_t err); ///////////////////////////////////////////////////////////////////// @@ -153,7 +162,7 @@ public: class BasicClient : public virtual RefBase { public: - virtual status_t initialize(camera_module_t *module) = 0; + virtual status_t initialize(CameraModule *module) = 0; virtual void disconnect(); // because we can't virtually inherit IInterface, which breaks @@ -385,7 +394,7 @@ private: sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS]; int mSoundRef; // reference count (release all MediaPlayer when 0) - camera_module_t *mModule; + CameraModule* mModule; Vector<sp<ICameraServiceListener> > mListenerList; @@ -406,6 +415,37 @@ private: int32_t cameraId, const StatusVector *rejectSourceStates = NULL); + // flashlight control + sp<CameraFlashlight> mFlashlight; + // guard mTorchStatusMap + Mutex mTorchStatusMutex; + // guard mTorchClientMap + Mutex mTorchClientMapMutex; + // camera id -> torch status + KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap; + // camera id -> torch client binder + // only store the last client that turns on each camera's torch mode + KeyedVector<String8, sp<IBinder> > mTorchClientMap; + + // check and handle if torch client's process has died + void handleTorchClientBinderDied(const wp<IBinder> &who); + + // handle torch mode status change and invoke callbacks. mTorchStatusMutex + // should be locked. + void onTorchStatusChangedLocked(const String8& cameraId, + ICameraServiceListener::TorchStatus newStatus); + + // validate the camera id for use of setting a torch mode. + bool validCameraIdForSetTorchMode(const String8& cameraId); + + // get a camera's torch status. mTorchStatusMutex should be locked. + status_t getTorchStatusLocked(const String8 &cameraId, + ICameraServiceListener::TorchStatus *status) const; + + // set a camera's torch status. mTorchStatusMutex should be locked. + status_t setTorchStatusLocked(const String8 &cameraId, + ICameraServiceListener::TorchStatus status); + // IBinder::DeathRecipient implementation virtual void binderDied(const wp<IBinder> &who); diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index dcab4ad..5c631b1 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -67,7 +67,7 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService, mLegacyMode = legacyMode; } -status_t Camera2Client::initialize(camera_module_t *module) +status_t Camera2Client::initialize(CameraModule *module) { ATRACE_CALL(); ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId); @@ -1958,7 +1958,7 @@ size_t Camera2Client::calculateBufferSize(int width, int height, return width * height * 2; case HAL_PIXEL_FORMAT_RGBA_8888: return width * height * 4; - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: return width * height * 2; default: ALOGE("%s: Unknown preview format: %x", diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h index d68bb29..5a8241f 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.h +++ b/services/camera/libcameraservice/api1/Camera2Client.h @@ -94,7 +94,7 @@ public: virtual ~Camera2Client(); - status_t initialize(camera_module_t *module); + status_t initialize(CameraModule *module); virtual status_t dump(int fd, const Vector<String16>& args); diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp index 1a4d9a6..5bdce9b 100644 --- a/services/camera/libcameraservice/api1/CameraClient.cpp +++ b/services/camera/libcameraservice/api1/CameraClient.cpp @@ -59,7 +59,7 @@ CameraClient::CameraClient(const sp<CameraService>& cameraService, LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId); } -status_t CameraClient::initialize(camera_module_t *module) { +status_t CameraClient::initialize(CameraModule *module) { int callingPid = getCallingPid(); status_t res; @@ -75,7 +75,7 @@ status_t CameraClient::initialize(camera_module_t *module) { snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId); mHardware = new CameraHardwareInterface(camera_device_name); - res = mHardware->initialize(&module->common); + res = mHardware->initialize(module); if (res != OK) { ALOGE("%s: Camera %d: unable to initialize device: %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res); diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h index 63a9d0f..95616b2 100644 --- a/services/camera/libcameraservice/api1/CameraClient.h +++ b/services/camera/libcameraservice/api1/CameraClient.h @@ -68,7 +68,7 @@ public: bool legacyMode = false); ~CameraClient(); - status_t initialize(camera_module_t *module); + status_t initialize(CameraModule *module); status_t dump(int fd, const Vector<String16>& args); diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp index eadaa00..5c8f750 100644 --- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp @@ -154,8 +154,8 @@ status_t CallbackProcessor::updateStream(const Parameters ¶ms) { params.previewWidth, params.previewHeight, callbackFormat, params.previewFormat); res = device->createStream(mCallbackWindow, - params.previewWidth, params.previewHeight, - callbackFormat, &mCallbackStreamId); + params.previewWidth, params.previewHeight, callbackFormat, + HAL_DATASPACE_JFIF, CAMERA3_STREAM_ROTATION_0, &mCallbackStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for callbacks: " "%s (%d)", __FUNCTION__, mId, diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp index 2772267..34798bf 100644 --- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp @@ -145,7 +145,8 @@ status_t JpegProcessor::updateStream(const Parameters ¶ms) { // Create stream for HAL production res = device->createStream(mCaptureWindow, params.pictureWidth, params.pictureHeight, - HAL_PIXEL_FORMAT_BLOB, &mCaptureStreamId); + HAL_PIXEL_FORMAT_BLOB, HAL_DATASPACE_JFIF, + CAMERA3_STREAM_ROTATION_0, &mCaptureStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for capture: " "%s (%d)", __FUNCTION__, mId, diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 4f4cfb0..87e0132 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -182,9 +182,9 @@ status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) { supportedPreviewFormats += CameraParameters::PIXEL_FORMAT_YUV420SP; break; - // Not advertizing JPEG, RAW_SENSOR, etc, for preview formats + // Not advertizing JPEG, RAW16, etc, for preview formats case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: case HAL_PIXEL_FORMAT_BLOB: addComma = false; break; @@ -2253,7 +2253,7 @@ const char* Parameters::formatEnumToString(int format) { case HAL_PIXEL_FORMAT_RGBA_8888: // RGBA8888 fmt = CameraParameters::PIXEL_FORMAT_RGBA8888; break; - case HAL_PIXEL_FORMAT_RAW_SENSOR: + case HAL_PIXEL_FORMAT_RAW16: ALOGW("Raw sensor preview format requested."); fmt = CameraParameters::PIXEL_FORMAT_BAYER_RGGB; break; diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp index 470624b..423659c 100644 --- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp @@ -181,7 +181,8 @@ status_t StreamingProcessor::updatePreviewStream(const Parameters ¶ms) { if (mPreviewStreamId == NO_STREAM) { res = device->createStream(mPreviewWindow, params.previewWidth, params.previewHeight, - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId); + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN, + CAMERA3_STREAM_ROTATION_0, &mPreviewStreamId); if (res != OK) { ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)", __FUNCTION__, mId, strerror(-res), res); @@ -420,9 +421,12 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters ¶ms) { if (mRecordingStreamId == NO_STREAM) { mRecordingFrameCount = 0; + // Selecting BT.709 colorspace by default + // TODO: Wire this in from encoder side res = device->createStream(mRecordingWindow, params.videoWidth, params.videoHeight, - CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mRecordingStreamId); + CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_BT709, + CAMERA3_STREAM_ROTATION_0, &mRecordingStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for recording: " "%s (%d)", __FUNCTION__, mId, diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp index 8b7e4b4..2e41db5 100644 --- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp +++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp @@ -185,8 +185,8 @@ status_t ZslProcessor::updateStream(const Parameters ¶ms) { (int)CAMERA2_HAL_PIXEL_FORMAT_ZSL : (int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; res = device->createStream(mZslWindow, - params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, - streamType, &mZslStreamId); + params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, streamType, + HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId); if (res != OK) { ALOGE("%s: Camera %d: Can't create output stream for ZSL: " "%s (%d)", __FUNCTION__, mId, diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index e6865bb..d25344e 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -65,7 +65,7 @@ CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService, ALOGI("CameraDeviceClient %d: Opened", cameraId); } -status_t CameraDeviceClient::initialize(camera_module_t *module) +status_t CameraDeviceClient::initialize(CameraModule *module) { ATRACE_CALL(); status_t res; @@ -308,17 +308,17 @@ status_t CameraDeviceClient::deleteStream(int streamId) { return res; } -status_t CameraDeviceClient::createStream(int width, int height, int format, - const sp<IGraphicBufferProducer>& bufferProducer) +status_t CameraDeviceClient::createStream(const OutputConfiguration &outputConfiguration) { ATRACE_CALL(); - ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; Mutex::Autolock icl(mBinderSerializationLock); + + sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer(); if (bufferProducer == NULL) { ALOGE("%s: bufferProducer must not be null", __FUNCTION__); return BAD_VALUE; @@ -368,7 +368,8 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, anw = new Surface(bufferProducer, useAsync); } - // TODO: remove w,h,f since we are ignoring them + int width, height, format; + android_dataspace dataSpace; if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) { ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__, @@ -385,6 +386,12 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, mCameraId); return res; } + if ((res = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, + reinterpret_cast<int*>(&dataSpace))) != OK) { + ALOGE("%s: Camera %d: Failed to query Surface dataSpace", __FUNCTION__, + mCameraId); + return res; + } // FIXME: remove this override since the default format should be // IMPLEMENTATION_DEFINED. b/9487482 @@ -397,14 +404,17 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, // Round dimensions to the nearest dimensions available for this format if (flexibleConsumer && !CameraDeviceClient::roundBufferDimensionNearest(width, height, - format, mDevice->info(), /*out*/&width, /*out*/&height)) { + format, dataSpace, mDevice->info(), /*out*/&width, /*out*/&height)) { ALOGE("%s: No stream configurations with the format %#x defined, failed to create stream.", __FUNCTION__, format); return BAD_VALUE; } int streamId = -1; - res = mDevice->createStream(anw, width, height, format, &streamId); + res = mDevice->createStream(anw, width, height, format, dataSpace, + static_cast<camera3_stream_rotation_t> + (outputConfiguration.getRotation()), + &streamId); if (res == OK) { mStreamMap.add(bufferProducer->asBinder(), streamId); @@ -439,10 +449,12 @@ status_t CameraDeviceClient::createStream(int width, int height, int format, bool CameraDeviceClient::roundBufferDimensionNearest(int32_t width, int32_t height, - int32_t format, const CameraMetadata& info, + int32_t format, android_dataspace dataSpace, const CameraMetadata& info, /*out*/int32_t* outWidth, /*out*/int32_t* outHeight) { camera_metadata_ro_entry streamConfigs = + (dataSpace == HAL_DATASPACE_DEPTH) ? + info.find(ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS) : info.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS); int32_t bestWidth = -1; diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index 84e46b7..a3dbb90 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -19,6 +19,7 @@ #include <camera/camera2/ICameraDeviceUser.h> #include <camera/camera2/ICameraDeviceCallbacks.h> +#include <camera/camera2/OutputConfiguration.h> #include "CameraService.h" #include "common/FrameProcessorBase.h" @@ -83,11 +84,7 @@ public: // Returns -EBUSY if device is not idle virtual status_t deleteStream(int streamId); - virtual status_t createStream( - int width, - int height, - int format, - const sp<IGraphicBufferProducer>& bufferProducer); + virtual status_t createStream(const OutputConfiguration &outputConfiguration); // Create a request object from a template. virtual status_t createDefaultRequest(int templateId, @@ -119,7 +116,7 @@ public: int servicePid); virtual ~CameraDeviceClient(); - virtual status_t initialize(camera_module_t *module); + virtual status_t initialize(CameraModule *module); virtual status_t dump(int fd, const Vector<String16>& args); @@ -161,7 +158,8 @@ private: // a width <= ROUNDING_WIDTH_CAP static const int32_t ROUNDING_WIDTH_CAP = 1080; static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format, - const CameraMetadata& info, /*out*/int32_t* outWidth, /*out*/int32_t* outHeight); + android_dataspace dataSpace, const CameraMetadata& info, + /*out*/int32_t* outWidth, /*out*/int32_t* outHeight); // IGraphicsBufferProducer binder -> Stream ID KeyedVector<sp<IBinder>, int> mStreamMap; diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp index 2ea460f..8999ee4 100644 --- a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp @@ -50,7 +50,7 @@ ProCamera2Client::ProCamera2Client(const sp<CameraService>& cameraService, mExclusiveLock = false; } -status_t ProCamera2Client::initialize(camera_module_t *module) +status_t ProCamera2Client::initialize(CameraModule *module) { ATRACE_CALL(); status_t res; @@ -281,6 +281,7 @@ status_t ProCamera2Client::createStream(int width, int height, int format, } return mDevice->createStream(window, width, height, format, + HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, streamId); } diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.h b/services/camera/libcameraservice/api_pro/ProCamera2Client.h index 9d83122..7f5f6ac 100644 --- a/services/camera/libcameraservice/api_pro/ProCamera2Client.h +++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.h @@ -85,7 +85,7 @@ public: int servicePid); virtual ~ProCamera2Client(); - virtual status_t initialize(camera_module_t *module); + virtual status_t initialize(CameraModule *module); virtual status_t dump(int fd, const Vector<String16>& args); diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp index d6db151..053d6e3 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp +++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp @@ -78,7 +78,7 @@ status_t Camera2ClientBase<TClientBase>::checkPid(const char* checkLocation) } template <typename TClientBase> -status_t Camera2ClientBase<TClientBase>::initialize(camera_module_t *module) { +status_t Camera2ClientBase<TClientBase>::initialize(CameraModule *module) { ATRACE_CALL(); ALOGV("%s: Initializing client for camera %d", __FUNCTION__, TClientBase::mCameraId); diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h index d198e4e..ca2b74b 100644 --- a/services/camera/libcameraservice/common/Camera2ClientBase.h +++ b/services/camera/libcameraservice/common/Camera2ClientBase.h @@ -18,6 +18,7 @@ #define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H #include "common/CameraDeviceBase.h" +#include "common/CameraModule.h" #include "camera/CaptureResult.h" namespace android { @@ -55,7 +56,7 @@ public: int servicePid); virtual ~Camera2ClientBase(); - virtual status_t initialize(camera_module_t *module); + virtual status_t initialize(CameraModule *module); virtual status_t dump(int fd, const Vector<String16>& args); /** diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h index d26e20c..fe55b9e 100644 --- a/services/camera/libcameraservice/common/CameraDeviceBase.h +++ b/services/camera/libcameraservice/common/CameraDeviceBase.h @@ -29,6 +29,7 @@ #include "hardware/camera3.h" #include "camera/CameraMetadata.h" #include "camera/CaptureResult.h" +#include "common/CameraModule.h" namespace android { @@ -45,7 +46,7 @@ class CameraDeviceBase : public virtual RefBase { */ virtual int getId() const = 0; - virtual status_t initialize(camera_module_t *module) = 0; + virtual status_t initialize(CameraModule *module) = 0; virtual status_t disconnect() = 0; virtual status_t dump(int fd, const Vector<String16> &args) = 0; @@ -99,17 +100,14 @@ class CameraDeviceBase : public virtual RefBase { nsecs_t timeout) = 0; /** - * Create an output stream of the requested size and format. + * Create an output stream of the requested size, format, rotation and dataspace * - * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device selects - * an appropriate format; it can be queried with getStreamInfo. - * - * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must be - * equal to the size in bytes of the buffers to allocate for the stream. For - * other formats, the size parameter is ignored. + * For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the + * logical dimensions of the buffer, not the number of bytes. */ virtual status_t createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id) = 0; + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id) = 0; /** * Create an input reprocess stream that uses buffers from an existing diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp new file mode 100644 index 0000000..5f767ad --- /dev/null +++ b/services/camera/libcameraservice/common/CameraModule.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2015 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 "CameraModule" +//#define LOG_NDEBUG 0 + +#include "CameraModule.h" + +namespace android { + +void CameraModule::deriveCameraCharacteristicsKeys( + uint32_t deviceVersion, CameraMetadata &chars) { + // HAL1 devices should not reach here + if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) { + ALOGV("%s: Cannot derive keys for HAL version < 2.0"); + return; + } + + // Keys added in HAL3.3 + if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) { + Vector<uint8_t> controlModes; + uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE; + chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1); + data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE; + chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1); + controlModes.push(ANDROID_CONTROL_MODE_OFF); + controlModes.push(ANDROID_CONTROL_MODE_AUTO); + camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES); + if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) { + controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE); + } + chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes); + } + return; +} + +CameraModule::CameraModule(camera_module_t *module) { + if (module == NULL) { + ALOGE("%s: camera hardware module must not be null", __FUNCTION__); + assert(0); + } + + mModule = module; + for (int i = 0; i < MAX_CAMERAS_PER_MODULE; i++) { + mCameraInfoCached[i] = false; + } +} + +int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) { + Mutex::Autolock lock(mCameraInfoLock); + if (cameraId < 0 || cameraId >= MAX_CAMERAS_PER_MODULE) { + ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId); + return -EINVAL; + } + + // Only override static_camera_characteristics for API2 devices + int apiVersion = mModule->common.module_api_version; + if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) { + return mModule->get_camera_info(cameraId, info); + } + + camera_info &wrappedInfo = mCameraInfo[cameraId]; + if (!mCameraInfoCached[cameraId]) { + camera_info rawInfo; + int ret = mModule->get_camera_info(cameraId, &rawInfo); + if (ret != 0) { + return ret; + } + CameraMetadata &m = mCameraCharacteristics[cameraId]; + m = rawInfo.static_camera_characteristics; + deriveCameraCharacteristicsKeys(rawInfo.device_version, m); + wrappedInfo = rawInfo; + wrappedInfo.static_camera_characteristics = m.getAndLock(); + mCameraInfoCached[cameraId] = true; + } + *info = wrappedInfo; + return 0; +} + +int CameraModule::open(const char* id, struct hw_device_t** device) { + return filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device)); +} + +int CameraModule::openLegacy( + const char* id, uint32_t halVersion, struct hw_device_t** device) { + return mModule->open_legacy(&mModule->common, id, halVersion, device); +} + +const hw_module_t* CameraModule::getRawModule() { + return &mModule->common; +} + +int CameraModule::getNumberOfCameras() { + return mModule->get_number_of_cameras(); +} + +int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) { + return mModule->set_callbacks(callbacks); +} + +bool CameraModule::isVendorTagDefined() { + return mModule->get_vendor_tag_ops != NULL; +} + +void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) { + if (mModule->get_vendor_tag_ops) { + mModule->get_vendor_tag_ops(ops); + } +} + +int CameraModule::setTorchMode(const char* camera_id, bool enable) { + return mModule->set_torch_mode(camera_id, enable); +} + + +status_t CameraModule::filterOpenErrorCode(status_t err) { + switch(err) { + case NO_ERROR: + case -EBUSY: + case -EINVAL: + case -EUSERS: + return err; + default: + break; + } + return -ENODEV; +} + + +}; // namespace android + diff --git a/services/camera/libcameraservice/common/CameraModule.h b/services/camera/libcameraservice/common/CameraModule.h new file mode 100644 index 0000000..16207aa --- /dev/null +++ b/services/camera/libcameraservice/common/CameraModule.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 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_CAMERAMODULE_H +#define ANDROID_SERVERS_CAMERA_CAMERAMODULE_H + +#include <hardware/camera.h> +#include <camera/CameraMetadata.h> +#include <utils/Mutex.h> + +/* This needs to be increased if we can have more cameras */ +#define MAX_CAMERAS_PER_MODULE 2 + + +namespace android { +/** + * A wrapper class for HAL camera module. + * + * This class wraps camera_module_t returned from HAL to provide a wrapped + * get_camera_info implementation which CameraService generates some + * camera characteristics keys defined in newer HAL version on an older HAL. + */ +class CameraModule { +public: + CameraModule(camera_module_t *module); + + const hw_module_t* getRawModule(); + int getCameraInfo(int cameraId, struct camera_info *info); + int getNumberOfCameras(void); + int open(const char* id, struct hw_device_t** device); + int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device); + int setCallbacks(const camera_module_callbacks_t *callbacks); + bool isVendorTagDefined(); + void getVendorTagOps(vendor_tag_ops_t* ops); + int setTorchMode(const char* camera_id, bool enable); + +private: + // Derive camera characteristics keys defined after HAL device version + static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars); + status_t filterOpenErrorCode(status_t err); + + camera_module_t *mModule; + CameraMetadata mCameraCharacteristics[MAX_CAMERAS_PER_MODULE]; + camera_info mCameraInfo[MAX_CAMERAS_PER_MODULE]; + bool mCameraInfoCached[MAX_CAMERAS_PER_MODULE]; + Mutex mCameraInfoLock; +}; + +} // namespace android + +#endif + diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h index 6386838..c79fa59 100644 --- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h +++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h @@ -89,24 +89,22 @@ public: } } - status_t initialize(hw_module_t *module) + status_t initialize(CameraModule *module) { ALOGI("Opening camera %s", mName.string()); - camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module); camera_info info; - status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info); + status_t res = module->getCameraInfo(atoi(mName.string()), &info); if (res != OK) return res; int rc = OK; - if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 && + if (module->getRawModule()->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 && info.device_version > CAMERA_DEVICE_API_VERSION_1_0) { // Open higher version camera device as HAL1.0 device. - rc = cameraModule->open_legacy(module, mName.string(), - CAMERA_DEVICE_API_VERSION_1_0, - (hw_device_t **)&mDevice); + rc = module->openLegacy(mName.string(), + CAMERA_DEVICE_API_VERSION_1_0, + (hw_device_t **)&mDevice); } else { - rc = CameraService::filterOpenErrorCode(module->methods->open( - module, mName.string(), (hw_device_t **)&mDevice)); + rc = module->open(mName.string(), (hw_device_t **)&mDevice); } if (rc != OK) { ALOGE("Could not open camera %s: %d", mName.string(), rc); diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp index d1158d6..878986b 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.cpp +++ b/services/camera/libcameraservice/device2/Camera2Device.cpp @@ -53,7 +53,7 @@ int Camera2Device::getId() const { return mId; } -status_t Camera2Device::initialize(camera_module_t *module) +status_t Camera2Device::initialize(CameraModule *module) { ATRACE_CALL(); ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId); @@ -68,8 +68,7 @@ status_t Camera2Device::initialize(camera_module_t *module) camera2_device_t *device; - res = CameraService::filterOpenErrorCode(module->common.methods->open( - &module->common, name, reinterpret_cast<hw_device_t**>(&device))); + res = module->open(name, reinterpret_cast<hw_device_t**>(&device)); if (res != OK) { ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__, @@ -87,7 +86,7 @@ status_t Camera2Device::initialize(camera_module_t *module) } camera_info info; - res = module->get_camera_info(mId, &info); + res = module->getCameraInfo(mId, &info); if (res != OK ) return res; if (info.device_version != device->common.version) { @@ -242,7 +241,8 @@ status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t time } status_t Camera2Device::createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id) { + uint32_t width, uint32_t height, int format, + android_dataspace /*dataSpace*/, camera3_stream_rotation_t rotation, int *id) { ATRACE_CALL(); status_t res; ALOGV("%s: E", __FUNCTION__); diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h index 4def8ae..9b32fa6 100644 --- a/services/camera/libcameraservice/device2/Camera2Device.h +++ b/services/camera/libcameraservice/device2/Camera2Device.h @@ -43,7 +43,7 @@ class Camera2Device: public CameraDeviceBase { * CameraDevice interface */ virtual int getId() const; - virtual status_t initialize(camera_module_t *module); + virtual status_t initialize(CameraModule *module); virtual status_t disconnect(); virtual status_t dump(int fd, const Vector<String16>& args); virtual const CameraMetadata& info() const; @@ -57,7 +57,8 @@ class Camera2Device: public CameraDeviceBase { virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL); virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout); virtual status_t createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id); virtual status_t createReprocessStreamFromStream(int outputId, int *id); virtual status_t getStreamInfo(int id, uint32_t *width, uint32_t *height, uint32_t *format); diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index 53e6fa9..8236788 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -86,7 +86,7 @@ int Camera3Device::getId() const { * CameraDeviceBase interface */ -status_t Camera3Device::initialize(camera_module_t *module) +status_t Camera3Device::initialize(CameraModule *module) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); @@ -106,9 +106,8 @@ status_t Camera3Device::initialize(camera_module_t *module) camera3_device_t *device; ATRACE_BEGIN("camera3->open"); - res = CameraService::filterOpenErrorCode(module->common.methods->open( - &module->common, deviceName.string(), - reinterpret_cast<hw_device_t**>(&device))); + res = module->open(deviceName.string(), + reinterpret_cast<hw_device_t**>(&device)); ATRACE_END(); if (res != OK) { @@ -127,7 +126,7 @@ status_t Camera3Device::initialize(camera_module_t *module) } camera_info info; - res = CameraService::filterGetInfoErrorCode(module->get_camera_info( + res = CameraService::filterGetInfoErrorCode(module->getCameraInfo( mId, &info)); if (res != OK) return res; @@ -802,12 +801,13 @@ status_t Camera3Device::createZslStream( } status_t Camera3Device::createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id) { + uint32_t width, uint32_t height, int format, android_dataspace dataSpace, + camera3_stream_rotation_t rotation, int *id) { ATRACE_CALL(); Mutex::Autolock il(mInterfaceLock); Mutex::Autolock l(mLock); - ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d", - mId, mNextStreamId, width, height, format); + ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d", + mId, mNextStreamId, width, height, format, dataSpace, rotation); status_t res; bool wasActive = false; @@ -847,10 +847,10 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer, } newStream = new Camera3OutputStream(mNextStreamId, consumer, - width, height, jpegBufferSize, format); + width, height, jpegBufferSize, format, dataSpace, rotation); } else { newStream = new Camera3OutputStream(mNextStreamId, consumer, - width, height, format); + width, height, format, dataSpace, rotation); } newStream->setStatusTracker(mStatusTracker); diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h index ec8dc10..a77548d 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.h +++ b/services/camera/libcameraservice/device3/Camera3Device.h @@ -73,7 +73,7 @@ class Camera3Device : virtual int getId() const; // Transitions to idle state on success. - virtual status_t initialize(camera_module_t *module); + virtual status_t initialize(CameraModule *module); virtual status_t disconnect(); virtual status_t dump(int fd, const Vector<String16> &args); virtual const CameraMetadata& info() const; @@ -95,7 +95,8 @@ class Camera3Device : // If adding streams while actively capturing, will pause device before adding // stream, reconfiguring device, and unpausing. virtual status_t createStream(sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format, int *id); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id); virtual status_t createInputStream( uint32_t width, uint32_t height, int format, int *id); diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp index 6656b09..01edfff 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp @@ -28,7 +28,7 @@ namespace camera3 { Camera3DummyStream::Camera3DummyStream(int id) : Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, DUMMY_WIDTH, DUMMY_HEIGHT, - /*maxSize*/0, DUMMY_FORMAT) { + /*maxSize*/0, DUMMY_FORMAT, DUMMY_DATASPACE, DUMMY_ROTATION) { } diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h index 3e42623..d023c57 100644 --- a/services/camera/libcameraservice/device3/Camera3DummyStream.h +++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h @@ -75,6 +75,8 @@ class Camera3DummyStream : static const int DUMMY_WIDTH = 320; static const int DUMMY_HEIGHT = 240; static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; + static const android_dataspace DUMMY_DATASPACE = HAL_DATASPACE_UNKNOWN; + static const camera3_stream_rotation_t DUMMY_ROTATION = CAMERA3_STREAM_ROTATION_0; static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER; /** diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp index cc66459..8696413 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp @@ -30,9 +30,10 @@ namespace android { namespace camera3 { Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type, - uint32_t width, uint32_t height, size_t maxSize, int format) : + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation) : Camera3Stream(id, type, - width, height, maxSize, format), + width, height, maxSize, format, dataSpace, rotation), mTotalBufferCount(0), mHandoutTotalBufferCount(0), mHandoutOutputBufferCount(0), diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h index a35c290..abcf2b1 100644 --- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h +++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h @@ -33,7 +33,8 @@ class Camera3IOStreamBase : public Camera3Stream { protected: Camera3IOStreamBase(int id, camera3_stream_type_t type, - uint32_t width, uint32_t height, size_t maxSize, int format); + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation); public: diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp index 319be1d..2f0c8be 100644 --- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp @@ -28,8 +28,8 @@ namespace camera3 { Camera3InputStream::Camera3InputStream(int id, uint32_t width, uint32_t height, int format) : - Camera3IOStreamBase(id, CAMERA3_STREAM_INPUT, width, height, - /*maxSize*/0, format) { + Camera3IOStreamBase(id, CAMERA3_STREAM_INPUT, width, height, /*maxSize*/0, + format, HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0) { if (format == HAL_PIXEL_FORMAT_BLOB) { ALOGE("%s: Bad format, BLOB not supported", __FUNCTION__); diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp index 77ad503..96bed0d 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp @@ -33,9 +33,10 @@ namespace camera3 { Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format) : + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation) : Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, - /*maxSize*/0, format), + /*maxSize*/0, format, dataSpace, rotation), mConsumer(consumer), mTransform(0), mTraceFirstBuffer(true) { @@ -48,9 +49,10 @@ Camera3OutputStream::Camera3OutputStream(int id, Camera3OutputStream::Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, size_t maxSize, int format) : + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation) : Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize, - format), + format, dataSpace, rotation), mConsumer(consumer), mTransform(0), mTraceFirstBuffer(true) { @@ -69,10 +71,12 @@ Camera3OutputStream::Camera3OutputStream(int id, Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type, uint32_t width, uint32_t height, - int format) : + int format, + android_dataspace dataSpace, + camera3_stream_rotation_t rotation) : Camera3IOStreamBase(id, type, width, height, /*maxSize*/0, - format), + format, dataSpace, rotation), mTransform(0) { // Subclasses expected to initialize mConsumer themselves @@ -323,6 +327,14 @@ status_t Camera3OutputStream::configureQueueLocked() { return res; } + res = native_window_set_buffers_data_space(mConsumer.get(), + camera3_stream::data_space); + if (res != OK) { + ALOGE("%s: Unable to configure stream dataspace %#x for stream %d", + __FUNCTION__, camera3_stream::data_space, mId); + return res; + } + int maxConsumerBuffers; res = mConsumer->query(mConsumer.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers); diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h index be278c5..12b2ebb 100644 --- a/services/camera/libcameraservice/device3/Camera3OutputStream.h +++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h @@ -39,14 +39,16 @@ class Camera3OutputStream : * Set up a stream for formats that have 2 dimensions, such as RAW and YUV. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, int format); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation); /** * Set up a stream for formats that have a variable buffer size for the same * dimensions, such as compressed JPEG. */ Camera3OutputStream(int id, sp<ANativeWindow> consumer, - uint32_t width, uint32_t height, size_t maxSize, int format); + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation); virtual ~Camera3OutputStream(); @@ -64,7 +66,8 @@ class Camera3OutputStream : protected: Camera3OutputStream(int id, camera3_stream_type_t type, - uint32_t width, uint32_t height, int format); + uint32_t width, uint32_t height, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation); /** * Note that we release the lock briefly in this function diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp index 3c0e908..4acbce3 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.cpp +++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp @@ -46,7 +46,8 @@ const Camera3Stream* Camera3Stream::cast(const camera3_stream *stream) { Camera3Stream::Camera3Stream(int id, camera3_stream_type type, - uint32_t width, uint32_t height, size_t maxSize, int format) : + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation) : camera3_stream(), mId(id), mName(String8::format("Camera3Stream[%d]", id)), @@ -58,6 +59,8 @@ Camera3Stream::Camera3Stream(int id, camera3_stream::width = width; camera3_stream::height = height; camera3_stream::format = format; + camera3_stream::data_space = dataSpace; + camera3_stream::rotation = rotation; camera3_stream::usage = 0; camera3_stream::max_buffers = 0; camera3_stream::priv = NULL; @@ -84,6 +87,10 @@ int Camera3Stream::getFormat() const { return camera3_stream::format; } +android_dataspace Camera3Stream::getDataSpace() const { + return camera3_stream::data_space; +} + camera3_stream* Camera3Stream::startConfiguration() { ATRACE_CALL(); Mutex::Autolock l(mLock); diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h index d0e1337..aba27fe 100644 --- a/services/camera/libcameraservice/device3/Camera3Stream.h +++ b/services/camera/libcameraservice/device3/Camera3Stream.h @@ -119,9 +119,10 @@ class Camera3Stream : /** * Get the stream's dimensions and format */ - uint32_t getWidth() const; - uint32_t getHeight() const; - int getFormat() const; + uint32_t getWidth() const; + uint32_t getHeight() const; + int getFormat() const; + android_dataspace getDataSpace() const; /** * Start the stream configuration process. Returns a handle to the stream's @@ -264,7 +265,8 @@ class Camera3Stream : mutable Mutex mLock; Camera3Stream(int id, camera3_stream_type type, - uint32_t width, uint32_t height, size_t maxSize, int format); + uint32_t width, uint32_t height, size_t maxSize, int format, + android_dataspace dataSpace, camera3_stream_rotation_t rotation); /** * Interface to be implemented by derived classes diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp index 81330ea..10d7f2e 100644 --- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp +++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp @@ -114,7 +114,8 @@ Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height, int bufferCount) : Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL, width, height, - HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED), + HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, + HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0), mDepth(bufferCount) { sp<IGraphicBufferProducer> producer; |