summaryrefslogtreecommitdiffstats
path: root/services/camera/libcameraservice
diff options
context:
space:
mode:
Diffstat (limited to 'services/camera/libcameraservice')
-rw-r--r--services/camera/libcameraservice/Android.mk49
-rw-r--r--services/camera/libcameraservice/CameraDeviceFactory.cpp71
-rw-r--r--services/camera/libcameraservice/CameraDeviceFactory.h45
-rw-r--r--services/camera/libcameraservice/CameraService.cpp255
-rw-r--r--services/camera/libcameraservice/CameraService.h66
-rw-r--r--services/camera/libcameraservice/api1/Camera2Client.cpp (renamed from services/camera/libcameraservice/Camera2Client.cpp)173
-rw-r--r--services/camera/libcameraservice/api1/Camera2Client.h (renamed from services/camera/libcameraservice/Camera2Client.h)38
-rw-r--r--services/camera/libcameraservice/api1/CameraClient.cpp (renamed from services/camera/libcameraservice/CameraClient.cpp)31
-rw-r--r--services/camera/libcameraservice/api1/CameraClient.h (renamed from services/camera/libcameraservice/CameraClient.h)5
-rw-r--r--services/camera/libcameraservice/api1/client2/BurstCapture.cpp (renamed from services/camera/libcameraservice/camera2/BurstCapture.cpp)4
-rw-r--r--services/camera/libcameraservice/api1/client2/BurstCapture.h (renamed from services/camera/libcameraservice/camera2/BurstCapture.h)5
-rw-r--r--services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp (renamed from services/camera/libcameraservice/camera2/CallbackProcessor.cpp)71
-rw-r--r--services/camera/libcameraservice/api1/client2/CallbackProcessor.h (renamed from services/camera/libcameraservice/camera2/CallbackProcessor.h)12
-rw-r--r--services/camera/libcameraservice/api1/client2/Camera2Heap.h (renamed from services/camera/libcameraservice/camera2/Camera2Heap.h)0
-rw-r--r--services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp (renamed from services/camera/libcameraservice/camera2/CaptureSequencer.cpp)48
-rw-r--r--services/camera/libcameraservice/api1/client2/CaptureSequencer.h (renamed from services/camera/libcameraservice/camera2/CaptureSequencer.h)5
-rw-r--r--services/camera/libcameraservice/api1/client2/FrameProcessor.cpp (renamed from services/camera/libcameraservice/camera2/FrameProcessor.cpp)10
-rw-r--r--services/camera/libcameraservice/api1/client2/FrameProcessor.h (renamed from services/camera/libcameraservice/camera2/FrameProcessor.h)4
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegCompressor.cpp (renamed from services/camera/libcameraservice/camera2/JpegCompressor.cpp)3
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegCompressor.h (renamed from services/camera/libcameraservice/camera2/JpegCompressor.h)0
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegProcessor.cpp (renamed from services/camera/libcameraservice/camera2/JpegProcessor.cpp)15
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegProcessor.h (renamed from services/camera/libcameraservice/camera2/JpegProcessor.h)3
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp (renamed from services/camera/libcameraservice/camera2/Parameters.cpp)301
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.h (renamed from services/camera/libcameraservice/camera2/Parameters.h)22
-rw-r--r--services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp (renamed from services/camera/libcameraservice/camera2/StreamingProcessor.cpp)27
-rw-r--r--services/camera/libcameraservice/api1/client2/StreamingProcessor.h (renamed from services/camera/libcameraservice/camera2/StreamingProcessor.h)10
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.cpp (renamed from services/camera/libcameraservice/camera2/ZslProcessor.cpp)29
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.h (renamed from services/camera/libcameraservice/camera2/ZslProcessor.h)14
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp (renamed from services/camera/libcameraservice/camera2/ZslProcessor3.cpp)20
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor3.h (renamed from services/camera/libcameraservice/camera2/ZslProcessor3.h)15
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h (renamed from services/camera/libcameraservice/camera2/ZslProcessorInterface.h)0
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.cpp679
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.h154
-rw-r--r--services/camera/libcameraservice/api_pro/ProCamera2Client.cpp (renamed from services/camera/libcameraservice/ProCamera2Client.cpp)14
-rw-r--r--services/camera/libcameraservice/api_pro/ProCamera2Client.h (renamed from services/camera/libcameraservice/ProCamera2Client.h)12
-rw-r--r--services/camera/libcameraservice/common/Camera2ClientBase.cpp (renamed from services/camera/libcameraservice/Camera2ClientBase.cpp)36
-rw-r--r--services/camera/libcameraservice/common/Camera2ClientBase.h (renamed from services/camera/libcameraservice/Camera2ClientBase.h)12
-rw-r--r--services/camera/libcameraservice/common/CameraDeviceBase.cpp (renamed from services/camera/libcameraservice/CameraDeviceBase.cpp)0
-rw-r--r--services/camera/libcameraservice/common/CameraDeviceBase.h (renamed from services/camera/libcameraservice/CameraDeviceBase.h)22
-rw-r--r--services/camera/libcameraservice/common/FrameProcessorBase.cpp (renamed from services/camera/libcameraservice/camera2/ProFrameProcessor.cpp)44
-rw-r--r--services/camera/libcameraservice/common/FrameProcessorBase.h (renamed from services/camera/libcameraservice/camera2/ProFrameProcessor.h)9
-rw-r--r--services/camera/libcameraservice/device1/CameraHardwareInterface.h (renamed from services/camera/libcameraservice/CameraHardwareInterface.h)0
-rw-r--r--services/camera/libcameraservice/device2/Camera2Device.cpp (renamed from services/camera/libcameraservice/Camera2Device.cpp)34
-rw-r--r--services/camera/libcameraservice/device2/Camera2Device.h (renamed from services/camera/libcameraservice/Camera2Device.h)11
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.cpp (renamed from services/camera/libcameraservice/Camera3Device.cpp)702
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.h (renamed from services/camera/libcameraservice/Camera3Device.h)147
-rw-r--r--services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp (renamed from services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp)80
-rw-r--r--services/camera/libcameraservice/device3/Camera3IOStreamBase.h (renamed from services/camera/libcameraservice/camera3/Camera3IOStreamBase.h)3
-rw-r--r--services/camera/libcameraservice/device3/Camera3InputStream.cpp (renamed from services/camera/libcameraservice/camera3/Camera3InputStream.cpp)20
-rw-r--r--services/camera/libcameraservice/device3/Camera3InputStream.h (renamed from services/camera/libcameraservice/camera3/Camera3InputStream.h)9
-rw-r--r--services/camera/libcameraservice/device3/Camera3OutputStream.cpp (renamed from services/camera/libcameraservice/camera3/Camera3OutputStream.cpp)40
-rw-r--r--services/camera/libcameraservice/device3/Camera3OutputStream.h (renamed from services/camera/libcameraservice/camera3/Camera3OutputStream.h)3
-rw-r--r--services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h (renamed from services/camera/libcameraservice/camera3/Camera3OutputStreamInterface.h)0
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.cpp (renamed from services/camera/libcameraservice/camera3/Camera3Stream.cpp)57
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.h (renamed from services/camera/libcameraservice/camera3/Camera3Stream.h)16
-rw-r--r--services/camera/libcameraservice/device3/Camera3StreamBufferListener.h (renamed from services/camera/libcameraservice/camera3/Camera3StreamBufferListener.h)0
-rw-r--r--services/camera/libcameraservice/device3/Camera3StreamInterface.h (renamed from services/camera/libcameraservice/camera3/Camera3StreamInterface.h)10
-rw-r--r--services/camera/libcameraservice/device3/Camera3ZslStream.cpp (renamed from services/camera/libcameraservice/camera3/Camera3ZslStream.cpp)8
-rw-r--r--services/camera/libcameraservice/device3/Camera3ZslStream.h (renamed from services/camera/libcameraservice/camera3/Camera3ZslStream.h)0
-rw-r--r--services/camera/libcameraservice/device3/StatusTracker.cpp219
-rw-r--r--services/camera/libcameraservice/device3/StatusTracker.h130
-rw-r--r--services/camera/libcameraservice/gui/RingBufferConsumer.cpp33
-rw-r--r--services/camera/libcameraservice/gui/RingBufferConsumer.h4
63 files changed, 3125 insertions, 734 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 83d9ccd..d23f8b9 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -8,29 +8,32 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
CameraService.cpp \
- CameraClient.cpp \
- Camera2Client.cpp \
- ProCamera2Client.cpp \
- Camera2ClientBase.cpp \
- CameraDeviceBase.cpp \
- Camera2Device.cpp \
- Camera3Device.cpp \
- camera2/Parameters.cpp \
- camera2/FrameProcessor.cpp \
- camera2/StreamingProcessor.cpp \
- camera2/JpegProcessor.cpp \
- camera2/CallbackProcessor.cpp \
- camera2/ZslProcessor.cpp \
- camera2/BurstCapture.cpp \
- camera2/JpegCompressor.cpp \
- camera2/CaptureSequencer.cpp \
- camera2/ProFrameProcessor.cpp \
- camera2/ZslProcessor3.cpp \
- camera3/Camera3Stream.cpp \
- camera3/Camera3IOStreamBase.cpp \
- camera3/Camera3InputStream.cpp \
- camera3/Camera3OutputStream.cpp \
- camera3/Camera3ZslStream.cpp \
+ CameraDeviceFactory.cpp \
+ common/Camera2ClientBase.cpp \
+ common/CameraDeviceBase.cpp \
+ common/FrameProcessorBase.cpp \
+ api1/CameraClient.cpp \
+ api1/Camera2Client.cpp \
+ api1/client2/Parameters.cpp \
+ api1/client2/FrameProcessor.cpp \
+ api1/client2/StreamingProcessor.cpp \
+ api1/client2/JpegProcessor.cpp \
+ api1/client2/CallbackProcessor.cpp \
+ api1/client2/ZslProcessor.cpp \
+ api1/client2/BurstCapture.cpp \
+ api1/client2/JpegCompressor.cpp \
+ api1/client2/CaptureSequencer.cpp \
+ api1/client2/ZslProcessor3.cpp \
+ api2/CameraDeviceClient.cpp \
+ api_pro/ProCamera2Client.cpp \
+ device2/Camera2Device.cpp \
+ device3/Camera3Device.cpp \
+ device3/Camera3Stream.cpp \
+ device3/Camera3IOStreamBase.cpp \
+ device3/Camera3InputStream.cpp \
+ device3/Camera3OutputStream.cpp \
+ device3/Camera3ZslStream.cpp \
+ device3/StatusTracker.cpp \
gui/RingBufferConsumer.cpp \
LOCAL_SHARED_LIBRARIES:= \
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.cpp b/services/camera/libcameraservice/CameraDeviceFactory.cpp
new file mode 100644
index 0000000..7fdf304
--- /dev/null
+++ b/services/camera/libcameraservice/CameraDeviceFactory.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "CameraDeviceFactory"
+#include <utils/Log.h>
+
+#include "CameraService.h"
+#include "CameraDeviceFactory.h"
+#include "common/CameraDeviceBase.h"
+#include "device2/Camera2Device.h"
+#include "device3/Camera3Device.h"
+
+namespace android {
+
+wp<CameraService> CameraDeviceFactory::sService;
+
+sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
+
+ sp<CameraService> svc = sService.promote();
+ if (svc == 0) {
+ ALOGE("%s: No service registered", __FUNCTION__);
+ return NULL;
+ }
+
+ int deviceVersion = svc->getDeviceVersion(cameraId, /*facing*/NULL);
+
+ sp<CameraDeviceBase> device;
+
+ switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ device = new Camera2Device(cameraId);
+ break;
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ device = new Camera3Device(cameraId);
+ break;
+ default:
+ ALOGE("%s: Camera %d: Unknown HAL device version %d",
+ __FUNCTION__, cameraId, deviceVersion);
+ device = NULL;
+ break;
+ }
+
+ ALOGV_IF(device != 0, "Created a new camera device for version %d",
+ deviceVersion);
+
+ return device;
+}
+
+void CameraDeviceFactory::registerService(wp<CameraService> service) {
+ ALOGV("%s: Registered service %p", __FUNCTION__,
+ service.promote().get());
+
+ sService = service;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.h b/services/camera/libcameraservice/CameraDeviceFactory.h
new file mode 100644
index 0000000..236dc56
--- /dev/null
+++ b/services/camera/libcameraservice/CameraDeviceFactory.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
+#define ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
+
+#include <utils/RefBase.h>
+
+namespace android {
+
+class CameraDeviceBase;
+class CameraService;
+
+/**
+ * Create the right instance of Camera2Device or Camera3Device
+ * automatically based on the device version.
+ */
+class CameraDeviceFactory : public virtual RefBase {
+ public:
+ static void registerService(wp<CameraService> service);
+
+ // Prerequisite: Call registerService.
+ static sp<CameraDeviceBase> createDevice(int cameraId);
+ private:
+ CameraDeviceFactory(wp<CameraService> service);
+
+ static wp<CameraService> sService;
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 757a781..34a5b15 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -38,9 +38,11 @@
#include <utils/String16.h>
#include "CameraService.h"
-#include "CameraClient.h"
-#include "Camera2Client.h"
-#include "ProCamera2Client.h"
+#include "api1/CameraClient.h"
+#include "api1/Camera2Client.h"
+#include "api_pro/ProCamera2Client.h"
+#include "api2/CameraDeviceClient.h"
+#include "CameraDeviceFactory.h"
namespace android {
@@ -126,6 +128,8 @@ void CameraService::onFirstRef()
CAMERA_MODULE_API_VERSION_2_1) {
mModule->set_callbacks(this);
}
+
+ CameraDeviceFactory::registerService(this);
}
}
@@ -164,7 +168,7 @@ void CameraService::onDeviceStatusChanged(int cameraId,
Mutex::Autolock al(mServiceLock);
/* Find all clients that we need to disconnect */
- sp<Client> client = mClient[cameraId].promote();
+ sp<BasicClient> client = mClient[cameraId].promote();
if (client.get() != NULL) {
clientsToDisconnect.push_back(client);
}
@@ -207,7 +211,7 @@ int32_t CameraService::getNumberOfCameras() {
status_t CameraService::getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo) {
if (!mModule) {
- return NO_INIT;
+ return -ENODEV;
}
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
@@ -221,6 +225,49 @@ status_t CameraService::getCameraInfo(int cameraId,
return rc;
}
+status_t CameraService::getCameraCharacteristics(int cameraId,
+ CameraMetadata* cameraInfo) {
+ if (!cameraInfo) {
+ ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (!mModule) {
+ ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0) {
+ // TODO: Remove this check once HAL1 shim is in place.
+ ALOGE("%s: Only HAL module version V2 or higher supports static metadata", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (cameraId < 0 || cameraId >= mNumberOfCameras) {
+ ALOGE("%s: Invalid camera id: %d", __FUNCTION__, cameraId);
+ return BAD_VALUE;
+ }
+
+ int facing;
+ if (getDeviceVersion(cameraId, &facing) == CAMERA_DEVICE_API_VERSION_1_0) {
+ // TODO: Remove this check once HAL1 shim is in place.
+ ALOGE("%s: HAL1 doesn't support static metadata yet", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1) {
+ // Disable HAL2.x support for camera2 API for now.
+ ALOGW("%s: HAL2.x doesn't support getCameraCharacteristics for now", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ struct camera_info info;
+ status_t ret = mModule->get_camera_info(cameraId, &info);
+ *cameraInfo = info.static_camera_characteristics;
+
+ return ret;
+}
+
int CameraService::getDeviceVersion(int cameraId, int* facing) {
struct camera_info info;
if (mModule->get_camera_info(cameraId, &info) != OK) {
@@ -258,7 +305,7 @@ bool CameraService::isValidCameraId(int cameraId) {
return false;
}
-bool CameraService::validateConnect(int cameraId,
+status_t CameraService::validateConnect(int cameraId,
/*inout*/
int& clientUid) const {
@@ -271,19 +318,19 @@ bool CameraService::validateConnect(int cameraId,
if (callingPid != getpid()) {
ALOGE("CameraService::connect X (pid %d) rejected (don't trust clientUid)",
callingPid);
- return false;
+ return PERMISSION_DENIED;
}
}
if (!mModule) {
ALOGE("Camera HAL module not loaded");
- return false;
+ return -ENODEV;
}
if (cameraId < 0 || cameraId >= mNumberOfCameras) {
ALOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
callingPid, cameraId);
- return false;
+ return -ENODEV;
}
char value[PROPERTY_VALUE_MAX];
@@ -291,36 +338,36 @@ bool CameraService::validateConnect(int cameraId,
if (strcmp(value, "1") == 0) {
// Camera is disabled by DevicePolicyManager.
ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
- return false;
+ return -EACCES;
}
ICameraServiceListener::Status currentStatus = getStatus(cameraId);
if (currentStatus == ICameraServiceListener::STATUS_NOT_PRESENT) {
ALOGI("Camera is not plugged in,"
" connect X (pid %d) rejected", callingPid);
- return false;
+ return -ENODEV;
} else if (currentStatus == ICameraServiceListener::STATUS_ENUMERATING) {
ALOGI("Camera is enumerating,"
" connect X (pid %d) rejected", callingPid);
- return false;
+ return -EBUSY;
}
// Else don't check for STATUS_NOT_AVAILABLE.
// -- It's done implicitly in canConnectUnsafe /w the mBusy array
- return true;
+ return OK;
}
bool CameraService::canConnectUnsafe(int cameraId,
const String16& clientPackageName,
const sp<IBinder>& remoteCallback,
- sp<Client> &client) {
+ sp<BasicClient> &client) {
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
if (mClient[cameraId] != 0) {
client = mClient[cameraId].promote();
if (client != 0) {
- if (remoteCallback == client->getRemoteCallback()->asBinder()) {
+ if (remoteCallback == client->getRemote()) {
LOG1("CameraService::connect X (pid %d) (the same client)",
callingPid);
return true;
@@ -354,11 +401,13 @@ bool CameraService::canConnectUnsafe(int cameraId,
return true;
}
-sp<ICamera> CameraService::connect(
+status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
- int clientUid) {
+ int clientUid,
+ /*out*/
+ sp<ICamera>& device) {
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
@@ -366,20 +415,23 @@ sp<ICamera> CameraService::connect(
LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
clientName8.string(), cameraId);
- if (!validateConnect(cameraId, /*inout*/clientUid)) {
- return NULL;
+ status_t status = validateConnect(cameraId, /*inout*/clientUid);
+ if (status != OK) {
+ return status;
}
- sp<Client> client;
+ sp<Client> client;
{
Mutex::Autolock lock(mServiceLock);
+ sp<BasicClient> clientTmp;
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
- /*out*/client)) {
- return NULL;
+ /*out*/clientTmp)) {
+ return -EBUSY;
} else if (client.get() != NULL) {
- return client;
+ device = static_cast<Client*>(clientTmp.get());
+ return OK;
}
int facing = -1;
@@ -409,18 +461,18 @@ sp<ICamera> CameraService::connect(
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
- return NULL;
+ return BAD_VALUE;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
- return NULL;
+ return INVALID_OPERATION;
}
- if (!connectFinishUnsafe(client, client->asBinder())) {
+ status_t status = connectFinishUnsafe(client, client->getRemote());
+ if (status != OK) {
// this is probably not recoverable.. maybe the client can try again
// OK: we can only get here if we were originally in PRESENT state
updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
-
- return NULL;
+ return status;
}
mClient[cameraId] = client;
@@ -430,45 +482,49 @@ sp<ICamera> CameraService::connect(
// important: release the mutex here so the client can call back
// into the service from its destructor (can be at the end of the call)
- return client;
+ device = client;
+ return OK;
}
-bool CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
- const sp<IBinder>& clientBinder) {
- if (client->initialize(mModule) != OK) {
- return false;
+status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
+ const sp<IBinder>& remoteCallback) {
+ status_t status = client->initialize(mModule);
+ if (status != OK) {
+ return status;
}
- clientBinder->linkToDeath(this);
+ remoteCallback->linkToDeath(this);
- return true;
+ return OK;
}
-sp<IProCameraUser> CameraService::connect(
+status_t CameraService::connectPro(
const sp<IProCameraCallbacks>& cameraCb,
int cameraId,
const String16& clientPackageName,
- int clientUid)
+ int clientUid,
+ /*out*/
+ sp<IProCameraUser>& device)
{
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
LOG1("CameraService::connectPro E (pid %d \"%s\", id %d)", callingPid,
clientName8.string(), cameraId);
-
- if (!validateConnect(cameraId, /*inout*/clientUid)) {
- return NULL;
+ status_t status = validateConnect(cameraId, /*inout*/clientUid);
+ if (status != OK) {
+ return status;
}
sp<ProClient> client;
{
Mutex::Autolock lock(mServiceLock);
{
- sp<Client> client;
+ sp<BasicClient> client;
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraCb->asBinder(),
/*out*/client)) {
- return NULL;
+ return -EBUSY;
}
}
@@ -479,23 +535,25 @@ sp<IProCameraUser> CameraService::connect(
case CAMERA_DEVICE_API_VERSION_1_0:
ALOGE("Camera id %d uses HALv1, doesn't support ProCamera",
cameraId);
- return NULL;
+ return -EOPNOTSUPP;
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
client = new ProCamera2Client(this, cameraCb, String16(),
cameraId, facing, callingPid, USE_CALLING_UID, getpid());
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
- return NULL;
+ return BAD_VALUE;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
- return NULL;
+ return INVALID_OPERATION;
}
- if (!connectFinishUnsafe(client, client->asBinder())) {
- return NULL;
+ status_t status = connectFinishUnsafe(client, client->getRemote());
+ if (status != OK) {
+ return status;
}
mProClientList[cameraId].push(client);
@@ -505,10 +563,93 @@ sp<IProCameraUser> CameraService::connect(
}
// important: release the mutex here so the client can call back
// into the service from its destructor (can be at the end of the call)
+ device = client;
+ return OK;
+}
- return client;
+status_t CameraService::connectDevice(
+ const sp<ICameraDeviceCallbacks>& cameraCb,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ /*out*/
+ sp<ICameraDeviceUser>& device)
+{
+
+ String8 clientName8(clientPackageName);
+ int callingPid = getCallingPid();
+
+ LOG1("CameraService::connectDevice E (pid %d \"%s\", id %d)", callingPid,
+ clientName8.string(), cameraId);
+
+ status_t status = validateConnect(cameraId, /*inout*/clientUid);
+ if (status != OK) {
+ return status;
+ }
+
+ sp<CameraDeviceClient> client;
+ {
+ Mutex::Autolock lock(mServiceLock);
+ {
+ sp<BasicClient> client;
+ if (!canConnectUnsafe(cameraId, clientPackageName,
+ cameraCb->asBinder(),
+ /*out*/client)) {
+ return -EBUSY;
+ }
+ }
+
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ // If there are other non-exclusive users of the camera,
+ // this will tear them down before we can reuse the camera
+ if (isValidCameraId(cameraId)) {
+ // transition from PRESENT -> NOT_AVAILABLE
+ updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+ cameraId);
+ }
+
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ ALOGW("Camera using old HAL version: %d", deviceVersion);
+ return -EOPNOTSUPP;
+ // TODO: don't allow 2.0 Only allow 2.1 and higher
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ client = new CameraDeviceClient(this, cameraCb, String16(),
+ cameraId, facing, callingPid, USE_CALLING_UID, getpid());
+ break;
+ case -1:
+ ALOGE("Invalid camera id %d", cameraId);
+ return BAD_VALUE;
+ default:
+ ALOGE("Unknown camera device HAL version: %d", deviceVersion);
+ return INVALID_OPERATION;
+ }
+
+ status_t status = connectFinishUnsafe(client, client->getRemote());
+ if (status != OK) {
+ // this is probably not recoverable.. maybe the client can try again
+ // OK: we can only get here if we were originally in PRESENT state
+ updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
+ return status;
+ }
+
+ LOG1("CameraService::connectDevice X (id %d, this pid is %d)", cameraId,
+ getpid());
+
+ mClient[cameraId] = client;
+ }
+ // important: release the mutex here so the client can call back
+ // into the service from its destructor (can be at the end of the call)
+
+ device = client;
+ return OK;
}
+
status_t CameraService::addListener(
const sp<ICameraServiceListener>& listener) {
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -566,14 +707,14 @@ void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
Mutex::Autolock lock(mServiceLock);
int outIndex;
- sp<Client> client = findClientUnsafe(remoteBinder, outIndex);
+ sp<BasicClient> client = findClientUnsafe(remoteBinder, outIndex);
if (client != 0) {
// Found our camera, clear and leave.
LOG1("removeClient: clear camera %d", outIndex);
mClient[outIndex].clear();
- client->unlinkToDeath(this);
+ client->getRemote()->unlinkToDeath(this);
} else {
sp<ProClient> clientPro = findProClientUnsafe(remoteBinder);
@@ -620,9 +761,9 @@ sp<CameraService::ProClient> CameraService::findProClientUnsafe(
return clientPro;
}
-sp<CameraService::Client> CameraService::findClientUnsafe(
+sp<CameraService::BasicClient> CameraService::findClientUnsafe(
const wp<IBinder>& cameraClient, int& outIndex) {
- sp<Client> client;
+ sp<BasicClient> client;
for (int i = 0; i < mNumberOfCameras; i++) {
@@ -640,7 +781,7 @@ sp<CameraService::Client> CameraService::findClientUnsafe(
continue;
}
- if (cameraClient == client->getRemoteCallback()->asBinder()) {
+ if (cameraClient == client->getRemote()) {
// Found our camera
outIndex = i;
return client;
@@ -651,7 +792,7 @@ sp<CameraService::Client> CameraService::findClientUnsafe(
return NULL;
}
-CameraService::Client* CameraService::getClientByIdUnsafe(int cameraId) {
+CameraService::BasicClient* CameraService::getClientByIdUnsafe(int cameraId) {
if (cameraId < 0 || cameraId >= mNumberOfCameras) return NULL;
return mClient[cameraId].unsafe_get();
}
@@ -906,7 +1047,9 @@ Mutex* CameraService::Client::getClientLockFromCookie(void* user) {
// Provide client pointer for callbacks. Client lock returned from getClientLockFromCookie should
// be acquired for this to be safe
CameraService::Client* CameraService::Client::getClientFromCookie(void* user) {
- Client* client = gCameraService->getClientByIdUnsafe((int) user);
+ BasicClient *basicClient = gCameraService->getClientByIdUnsafe((int) user);
+ // OK: only CameraClient calls this, and they already cast anyway.
+ Client* client = static_cast<Client*>(basicClient);
// This could happen if the Client is in the process of shutting down (the
// last strong reference is gone, but the destructor hasn't finished
@@ -1058,7 +1201,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
}
}
- sp<Client> client = mClient[i].promote();
+ sp<BasicClient> client = mClient[i].promote();
if (client == 0) {
result = String8::format(" Device is closed, no client instance\n");
write(fd, result.string(), result.size());
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 710f164..ad6a582 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -29,6 +29,8 @@
#include <camera/ICameraClient.h>
#include <camera/IProCameraUser.h>
#include <camera/IProCameraCallbacks.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
#include <camera/ICameraServiceListener.h>
@@ -69,11 +71,26 @@ public:
virtual int32_t getNumberOfCameras();
virtual status_t getCameraInfo(int cameraId,
struct CameraInfo* cameraInfo);
-
- virtual sp<ICamera> connect(const sp<ICameraClient>& cameraClient, int cameraId,
- const String16& clientPackageName, int clientUid);
- virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
- int cameraId, const String16& clientPackageName, int clientUid);
+ virtual status_t getCameraCharacteristics(int cameraId,
+ CameraMetadata* cameraInfo);
+
+ virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
+ const String16& clientPackageName, int clientUid,
+ /*out*/
+ sp<ICamera>& device);
+
+ virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb,
+ int cameraId, const String16& clientPackageName, int clientUid,
+ /*out*/
+ sp<IProCameraUser>& device);
+
+ virtual status_t connectDevice(
+ const sp<ICameraDeviceCallbacks>& cameraCb,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ /*out*/
+ sp<ICameraDeviceUser>& device);
virtual status_t addListener(const sp<ICameraServiceListener>& listener);
virtual status_t removeListener(
@@ -99,13 +116,17 @@ public:
void playSound(sound_kind kind);
void releaseSound();
+ /////////////////////////////////////////////////////////////////////
+ // CameraDeviceFactory functionality
+ int getDeviceVersion(int cameraId, int* facing = NULL);
+
/////////////////////////////////////////////////////////////////////
// CameraClient functionality
// returns plain pointer of client. Note that mClientLock should be acquired to
// prevent the client from destruction. The result can be NULL.
- virtual Client* getClientByIdUnsafe(int cameraId);
+ virtual BasicClient* getClientByIdUnsafe(int cameraId);
virtual Mutex* getClientLockById(int cameraId);
class BasicClient : public virtual RefBase {
@@ -114,11 +135,17 @@ public:
virtual void disconnect() = 0;
+ // because we can't virtually inherit IInterface, which breaks
+ // virtual inheritance
+ virtual sp<IBinder> asBinderWrapper() = 0;
+
// Return the remote callback binder object (e.g. IProCameraCallbacks)
- wp<IBinder> getRemote() {
+ sp<IBinder> getRemote() {
return mRemoteBinder;
}
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
protected:
BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
@@ -147,7 +174,7 @@ public:
pid_t mServicePid; // immutable after constructor
// - The app-side Binder interface to receive callbacks from us
- wp<IBinder> mRemoteBinder; // immutable after constructor
+ sp<IBinder> mRemoteBinder; // immutable after constructor
// permissions management
status_t startCameraOps();
@@ -187,9 +214,10 @@ public:
virtual status_t connect(const sp<ICameraClient>& client) = 0;
virtual status_t lock() = 0;
virtual status_t unlock() = 0;
- virtual status_t setPreviewDisplay(const sp<Surface>& surface) = 0;
- virtual status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer)=0;
+ virtual status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer)=0;
virtual void setPreviewCallbackFlag(int flag) = 0;
+ virtual status_t setPreviewCallbackTarget(
+ const sp<IGraphicBufferProducer>& callbackProducer) = 0;
virtual status_t startPreview() = 0;
virtual void stopPreview() = 0;
virtual bool previewEnabled() = 0;
@@ -221,6 +249,10 @@ public:
return mRemoteCallback;
}
+ virtual sp<IBinder> asBinderWrapper() {
+ return asBinder();
+ }
+
protected:
static Mutex* getClientLockFromCookie(void* user);
// convert client from cookie. Client lock should be acquired before getting Client.
@@ -285,7 +317,7 @@ private:
virtual void onFirstRef();
// Step 1. Check if we can connect, before we acquire the service lock.
- bool validateConnect(int cameraId,
+ status_t validateConnect(int cameraId,
/*inout*/
int& clientUid) const;
@@ -294,16 +326,17 @@ private:
const String16& clientPackageName,
const sp<IBinder>& remoteCallback,
/*out*/
- sp<Client> &client);
+ sp<BasicClient> &client);
// When connection is successful, initialize client and track its death
- bool connectFinishUnsafe(const sp<BasicClient>& client,
- const sp<IBinder>& clientBinder);
+ status_t connectFinishUnsafe(const sp<BasicClient>& client,
+ const sp<IBinder>& remoteCallback);
virtual sp<BasicClient> getClientByRemote(const wp<IBinder>& cameraClient);
Mutex mServiceLock;
- wp<Client> mClient[MAX_CAMERAS]; // protected by mServiceLock
+ // either a Client or CameraDeviceClient
+ wp<BasicClient> mClient[MAX_CAMERAS]; // protected by mServiceLock
Mutex mClientLock[MAX_CAMERAS]; // prevent Client destruction inside callbacks
int mNumberOfCameras;
@@ -311,7 +344,7 @@ private:
Vector<weak_pro_client_ptr> mProClientList[MAX_CAMERAS];
// needs to be called with mServiceLock held
- sp<Client> findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
+ sp<BasicClient> findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
sp<ProClient> findProClientUnsafe(
const wp<IBinder>& cameraCallbacksRemote);
@@ -352,7 +385,6 @@ private:
virtual void binderDied(const wp<IBinder> &who);
// Helpers
- int getDeviceVersion(int cameraId, int* facing);
bool isValidCameraId(int cameraId);
};
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 6942006..df3b162 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "Camera2"
+#define LOG_TAG "Camera2Client"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
@@ -23,13 +23,15 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
-#include "camera2/Parameters.h"
-#include "Camera2Client.h"
-#include "Camera2Device.h"
-#include "Camera3Device.h"
-#include "camera2/ZslProcessor.h"
-#include "camera2/ZslProcessor3.h"
+#include "api1/Camera2Client.h"
+
+#include "api1/client2/StreamingProcessor.h"
+#include "api1/client2/JpegProcessor.h"
+#include "api1/client2/CaptureSequencer.h"
+#include "api1/client2/CallbackProcessor.h"
+#include "api1/client2/ZslProcessor.h"
+#include "api1/client2/ZslProcessor3.h"
#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -58,22 +60,6 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
mDeviceVersion(deviceVersion)
{
ATRACE_CALL();
- ALOGI("Camera %d: Opened", cameraId);
-
- switch (mDeviceVersion) {
- case CAMERA_DEVICE_API_VERSION_2_0:
- mDevice = new Camera2Device(cameraId);
- break;
- case CAMERA_DEVICE_API_VERSION_3_0:
- mDevice = new Camera3Device(cameraId);
- break;
- default:
- ALOGE("Camera %d: Unknown HAL device version %d",
- cameraId, mDeviceVersion);
- mDevice = NULL;
- break;
- }
-
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
@@ -297,6 +283,7 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_INACTIVE)
CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN)
CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)
+ CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED)
CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN)
CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED)
CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED)
@@ -340,6 +327,10 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
result.appendFormat(" Video stabilization is %s\n",
p.videoStabilization ? "enabled" : "disabled");
+ result.appendFormat(" Selected still capture FPS range: %d - %d\n",
+ p.fastInfo.bestStillCaptureFpsRange[0],
+ p.fastInfo.bestStillCaptureFpsRange[1]);
+
result.append(" Current streams:\n");
result.appendFormat(" Preview stream ID: %d\n",
getPreviewStreamId());
@@ -505,25 +496,7 @@ status_t Camera2Client::unlock() {
return EBUSY;
}
-status_t Camera2Client::setPreviewDisplay(
- const sp<Surface>& surface) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- Mutex::Autolock icl(mBinderSerializationLock);
- status_t res;
- if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
-
- sp<IBinder> binder;
- sp<ANativeWindow> window;
- if (surface != 0) {
- binder = surface->getIGraphicBufferProducer()->asBinder();
- window = surface;
- }
-
- return setPreviewWindowL(binder,window);
-}
-
-status_t Camera2Client::setPreviewTexture(
+status_t Camera2Client::setPreviewTarget(
const sp<IGraphicBufferProducer>& bufferProducer) {
ATRACE_CALL();
ALOGV("%s: E", __FUNCTION__);
@@ -535,7 +508,10 @@ status_t Camera2Client::setPreviewTexture(
sp<ANativeWindow> window;
if (bufferProducer != 0) {
binder = bufferProducer->asBinder();
- window = new Surface(bufferProducer);
+ // Using controlledByApp flag to ensure that the buffer queue remains in
+ // async mode for the old camera API, where many applications depend
+ // on that behavior.
+ window = new Surface(bufferProducer, /*controlledByApp*/ true);
}
return setPreviewWindowL(binder, window);
}
@@ -632,6 +608,19 @@ void Camera2Client::setPreviewCallbackFlagL(Parameters &params, int flag) {
params.previewCallbackOneShot = true;
}
if (params.previewCallbackFlags != (uint32_t)flag) {
+
+ if (params.previewCallbackSurface && flag != CAMERA_FRAME_CALLBACK_FLAG_NOOP) {
+ // Disable any existing preview callback window when enabling
+ // preview callback flags
+ res = mCallbackProcessor->setCallbackWindow(NULL);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to clear preview callback surface:"
+ " %s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
+ return;
+ }
+ params.previewCallbackSurface = false;
+ }
+
params.previewCallbackFlags = flag;
if (params.state == Parameters::PREVIEW) {
@@ -643,9 +632,61 @@ void Camera2Client::setPreviewCallbackFlagL(Parameters &params, int flag) {
}
}
}
+}
+status_t Camera2Client::setPreviewCallbackTarget(
+ const sp<IGraphicBufferProducer>& callbackProducer) {
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+ Mutex::Autolock icl(mBinderSerializationLock);
+ status_t res;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ sp<ANativeWindow> window;
+ if (callbackProducer != 0) {
+ window = new Surface(callbackProducer);
+ }
+
+ res = mCallbackProcessor->setCallbackWindow(window);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to set preview callback surface: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
+
+ SharedParameters::Lock l(mParameters);
+
+ if (window != NULL) {
+ // Disable traditional callbacks when a valid callback target is given
+ l.mParameters.previewCallbackFlags = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
+ l.mParameters.previewCallbackOneShot = false;
+ l.mParameters.previewCallbackSurface = true;
+ } else {
+ // Disable callback target if given a NULL interface.
+ l.mParameters.previewCallbackSurface = false;
+ }
+
+ switch(l.mParameters.state) {
+ case Parameters::PREVIEW:
+ res = startPreviewL(l.mParameters, true);
+ break;
+ case Parameters::RECORD:
+ case Parameters::VIDEO_SNAPSHOT:
+ res = startRecordingL(l.mParameters, true);
+ break;
+ default:
+ break;
+ }
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to refresh request in state %s",
+ __FUNCTION__, mCameraId,
+ Parameters::getStateName(l.mParameters.state));
+ }
+
+ return OK;
}
+
status_t Camera2Client::startPreview() {
ATRACE_CALL();
ALOGV("%s: E", __FUNCTION__);
@@ -707,9 +748,11 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
return res;
}
- Vector<uint8_t> outputStreams;
- bool callbacksEnabled = params.previewCallbackFlags &
- CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK;
+ Vector<int32_t> outputStreams;
+ bool callbacksEnabled = (params.previewCallbackFlags &
+ CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ||
+ params.previewCallbackSurface;
+
if (callbacksEnabled) {
// Can't have recording stream hanging around when enabling callbacks,
// since it exceeds the max stream count on some devices.
@@ -816,6 +859,7 @@ void Camera2Client::stopPreviewL() {
// no break
case Parameters::RECORD:
case Parameters::PREVIEW:
+ syncWithDevice();
res = stopStream();
if (res != OK) {
ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
@@ -960,7 +1004,7 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
return res;
}
- Vector<uint8_t> outputStreams;
+ Vector<int32_t> outputStreams;
outputStreams.push(getPreviewStreamId());
outputStreams.push(getRecordingStreamId());
@@ -1105,6 +1149,8 @@ status_t Camera2Client::autoFocus() {
l.mParameters.currentAfTriggerId = ++l.mParameters.afTriggerCounter;
triggerId = l.mParameters.currentAfTriggerId;
}
+ ATRACE_ASYNC_BEGIN(kAutofocusLabel, triggerId);
+
syncWithDevice();
mDevice->triggerAutofocus(triggerId);
@@ -1127,6 +1173,12 @@ status_t Camera2Client::cancelAutoFocus() {
l.mParameters.focusMode == Parameters::FOCUS_MODE_INFINITY) {
return OK;
}
+
+ // An active AF trigger is canceled
+ if (l.mParameters.afTriggerCounter == l.mParameters.currentAfTriggerId) {
+ ATRACE_ASYNC_END(kAutofocusLabel, l.mParameters.currentAfTriggerId);
+ }
+
triggerId = ++l.mParameters.afTriggerCounter;
// When using triggerAfWithAuto quirk, may need to reset focus mode to
@@ -1155,6 +1207,7 @@ status_t Camera2Client::takePicture(int msgType) {
status_t res;
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+ int takePictureCounter;
{
SharedParameters::Lock l(mParameters);
switch (l.mParameters.state) {
@@ -1193,8 +1246,11 @@ status_t Camera2Client::takePicture(int msgType) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ takePictureCounter = ++l.mParameters.takePictureCounter;
}
+ ATRACE_ASYNC_BEGIN(kTakepictureLabel, takePictureCounter);
+
// Need HAL to have correct settings before (possibly) triggering precapture
syncWithDevice();
@@ -1422,7 +1478,24 @@ void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
bool afInMotion = false;
{
SharedParameters::Lock l(mParameters);
+ // Trace end of AF state
+ char tmp[32];
+ if (l.mParameters.afStateCounter > 0) {
+ camera_metadata_enum_snprint(
+ ANDROID_CONTROL_AF_STATE, l.mParameters.focusState, tmp, sizeof(tmp));
+ ATRACE_ASYNC_END(tmp, l.mParameters.afStateCounter);
+ }
+
+ // Update state
l.mParameters.focusState = newState;
+ l.mParameters.afStateCounter++;
+
+ // Trace start of AF state
+
+ camera_metadata_enum_snprint(
+ ANDROID_CONTROL_AF_STATE, l.mParameters.focusState, tmp, sizeof(tmp));
+ ATRACE_ASYNC_BEGIN(tmp, l.mParameters.afStateCounter);
+
switch (l.mParameters.focusMode) {
case Parameters::FOCUS_MODE_AUTO:
case Parameters::FOCUS_MODE_MACRO:
@@ -1444,6 +1517,7 @@ void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
case ANDROID_CONTROL_AF_STATE_INACTIVE:
case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
+ case ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
default:
// Unexpected in AUTO/MACRO mode
ALOGE("%s: Unexpected AF state transition in AUTO/MACRO mode: %d",
@@ -1486,6 +1560,7 @@ void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
afInMotion = true;
// no break
case ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED:
+ case ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
// Stop passive scan, inform upstream
if (l.mParameters.enableFocusMoveMessages) {
sendMovingMessage = true;
@@ -1514,6 +1589,7 @@ void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
}
}
if (sendCompletedMessage) {
+ ATRACE_ASYNC_END(kAutofocusLabel, triggerId);
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
if (l.mRemoteCallback != 0) {
l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS,
@@ -1723,4 +1799,7 @@ status_t Camera2Client::updateProcessorStream(sp<ProcessorT> processor,
return res;
}
+const char* Camera2Client::kAutofocusLabel = "autofocus";
+const char* Camera2Client::kTakepictureLabel = "take_picture";
+
} // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 8ab46b1..fe0bf74 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -17,19 +17,29 @@
#ifndef ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_H
-#include "CameraDeviceBase.h"
#include "CameraService.h"
-#include "camera2/Parameters.h"
-#include "camera2/FrameProcessor.h"
-#include "camera2/StreamingProcessor.h"
-#include "camera2/JpegProcessor.h"
-#include "camera2/ZslProcessorInterface.h"
-#include "camera2/CaptureSequencer.h"
-#include "camera2/CallbackProcessor.h"
-#include "Camera2ClientBase.h"
+#include "common/CameraDeviceBase.h"
+#include "common/Camera2ClientBase.h"
+#include "api1/client2/Parameters.h"
+#include "api1/client2/FrameProcessor.h"
+//#include "api1/client2/StreamingProcessor.h"
+//#include "api1/client2/JpegProcessor.h"
+//#include "api1/client2/ZslProcessorInterface.h"
+//#include "api1/client2/CaptureSequencer.h"
+//#include "api1/client2/CallbackProcessor.h"
namespace android {
+namespace camera2 {
+
+class StreamingProcessor;
+class JpegProcessor;
+class ZslProcessorInterface;
+class CaptureSequencer;
+class CallbackProcessor;
+
+}
+
class IMemory;
/**
* Interface between android.hardware.Camera API and Camera HAL device for versions
@@ -47,10 +57,12 @@ public:
virtual status_t connect(const sp<ICameraClient>& client);
virtual status_t lock();
virtual status_t unlock();
- virtual status_t setPreviewDisplay(const sp<Surface>& surface);
- virtual status_t setPreviewTexture(
+ virtual status_t setPreviewTarget(
const sp<IGraphicBufferProducer>& bufferProducer);
virtual void setPreviewCallbackFlag(int flag);
+ virtual status_t setPreviewCallbackTarget(
+ const sp<IGraphicBufferProducer>& callbackProducer);
+
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
@@ -124,6 +136,10 @@ public:
static const int32_t kCaptureRequestIdStart = 30000000;
static const int32_t kCaptureRequestIdEnd = 40000000;
+ // Constant strings for ATRACE logging
+ static const char* kAutofocusLabel;
+ static const char* kTakepictureLabel;
+
private:
/** ICamera interface-related private members */
typedef camera2::Parameters Parameters;
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index e577fa3..bd6805d 100644
--- a/services/camera/libcameraservice/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -20,8 +20,8 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
-#include "CameraClient.h"
-#include "CameraHardwareInterface.h"
+#include "api1/CameraClient.h"
+#include "device1/CameraHardwareInterface.h"
#include "CameraService.h"
namespace android {
@@ -308,26 +308,20 @@ status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,
return result;
}
-// set the Surface that the preview will use
-status_t CameraClient::setPreviewDisplay(const sp<Surface>& surface) {
- LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());
-
- sp<IBinder> binder(surface != 0 ? surface->getIGraphicBufferProducer()->asBinder() : 0);
- sp<ANativeWindow> window(surface);
- return setPreviewWindow(binder, window);
-}
-
-// set the SurfaceTextureClient that the preview will use
-status_t CameraClient::setPreviewTexture(
+// set the buffer consumer that the preview will use
+status_t CameraClient::setPreviewTarget(
const sp<IGraphicBufferProducer>& bufferProducer) {
- LOG1("setPreviewTexture(%p) (pid %d)", bufferProducer.get(),
+ LOG1("setPreviewTarget(%p) (pid %d)", bufferProducer.get(),
getCallingPid());
sp<IBinder> binder;
sp<ANativeWindow> window;
if (bufferProducer != 0) {
binder = bufferProducer->asBinder();
- window = new Surface(bufferProducer);
+ // Using controlledByApp flag to ensure that the buffer queue remains in
+ // async mode for the old camera API, where many applications depend
+ // on that behavior.
+ window = new Surface(bufferProducer, /*controlledByApp*/ true);
}
return setPreviewWindow(binder, window);
}
@@ -347,6 +341,13 @@ void CameraClient::setPreviewCallbackFlag(int callback_flag) {
}
}
+status_t CameraClient::setPreviewCallbackTarget(
+ const sp<IGraphicBufferProducer>& callbackProducer) {
+ (void)callbackProducer;
+ ALOGE("%s: Unimplemented!", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+
// start preview mode
status_t CameraClient::startPreview() {
LOG1("startPreview (pid %d)", getCallingPid());
diff --git a/services/camera/libcameraservice/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 7f0cb29..4b89564 100644
--- a/services/camera/libcameraservice/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -37,9 +37,10 @@ public:
virtual status_t connect(const sp<ICameraClient>& client);
virtual status_t lock();
virtual status_t unlock();
- virtual status_t setPreviewDisplay(const sp<Surface>& surface);
- virtual status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer);
+ virtual status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer);
virtual void setPreviewCallbackFlag(int flag);
+ virtual status_t setPreviewCallbackTarget(
+ const sp<IGraphicBufferProducer>& callbackProducer);
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
diff --git a/services/camera/libcameraservice/camera2/BurstCapture.cpp b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
index 192d419..0bfdfd4 100644
--- a/services/camera/libcameraservice/camera2/BurstCapture.cpp
+++ b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
@@ -22,8 +22,8 @@
#include "BurstCapture.h"
-#include "../Camera2Client.h"
-#include "JpegCompressor.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/JpegCompressor.h"
namespace android {
namespace camera2 {
diff --git a/services/camera/libcameraservice/camera2/BurstCapture.h b/services/camera/libcameraservice/api1/client2/BurstCapture.h
index a2cc893..ea321fd 100644
--- a/services/camera/libcameraservice/camera2/BurstCapture.h
+++ b/services/camera/libcameraservice/api1/client2/BurstCapture.h
@@ -17,11 +17,12 @@
#ifndef ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H
#define ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H
-#include "camera/CameraMetadata.h"
+#include <camera/CameraMetadata.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <gui/CpuConsumer.h>
-#include "Camera2Device.h"
+
+#include "device2/Camera2Device.h"
namespace android {
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index 522f49a..d2ac79c 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -20,11 +20,11 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-
-#include "CallbackProcessor.h"
#include <gui/Surface.h>
-#include "../CameraDeviceBase.h"
-#include "../Camera2Client.h"
+
+#include "common/CameraDeviceBase.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/CallbackProcessor.h"
#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
@@ -37,6 +37,7 @@ CallbackProcessor::CallbackProcessor(sp<Camera2Client> client):
mDevice(client->getCameraDevice()),
mId(client->getCameraId()),
mCallbackAvailable(false),
+ mCallbackToApp(false),
mCallbackStreamId(NO_STREAM) {
}
@@ -53,6 +54,35 @@ void CallbackProcessor::onFrameAvailable() {
}
}
+status_t CallbackProcessor::setCallbackWindow(
+ sp<ANativeWindow> callbackWindow) {
+ ATRACE_CALL();
+ status_t res;
+
+ Mutex::Autolock l(mInputMutex);
+
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) return OK;
+ sp<CameraDeviceBase> device = client->getCameraDevice();
+
+ // If the window is changing, clear out stream if it already exists
+ if (mCallbackWindow != callbackWindow && mCallbackStreamId != NO_STREAM) {
+ res = device->deleteStream(mCallbackStreamId);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete old stream "
+ "for callbacks: %s (%d)", __FUNCTION__,
+ client->getCameraId(), strerror(-res), res);
+ return res;
+ }
+ mCallbackStreamId = NO_STREAM;
+ mCallbackConsumer.clear();
+ }
+ mCallbackWindow = callbackWindow;
+ mCallbackToApp = (mCallbackWindow != NULL);
+
+ return OK;
+}
+
status_t CallbackProcessor::updateStream(const Parameters &params) {
ATRACE_CALL();
status_t res;
@@ -67,21 +97,24 @@ status_t CallbackProcessor::updateStream(const Parameters &params) {
// If possible, use the flexible YUV format
int32_t callbackFormat = params.previewFormat;
- if (params.fastInfo.useFlexibleYuv &&
+ if (mCallbackToApp) {
+ // TODO: etalvala: This should use the flexible YUV format as well, but
+ // need to reconcile HAL2/HAL3 requirements.
+ callbackFormat = HAL_PIXEL_FORMAT_YV12;
+ } else if(params.fastInfo.useFlexibleYuv &&
(params.previewFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
params.previewFormat == HAL_PIXEL_FORMAT_YV12) ) {
callbackFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
}
- if (mCallbackConsumer == 0) {
- // Create CPU buffer queue endpoint. Make it async to avoid disconnect
- // deadlocks.
- mCallbackConsumer = new CpuConsumer(kCallbackHeapCount,
- /*synchronized*/ false);
+ if (!mCallbackToApp && mCallbackConsumer == 0) {
+ // Create CPU buffer queue endpoint, since app hasn't given us one
+ // Make it async to avoid disconnect deadlocks
+ sp<BufferQueue> bq = new BufferQueue();
+ mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount);
mCallbackConsumer->setFrameAvailableListener(this);
mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
- mCallbackWindow = new Surface(
- mCallbackConsumer->getProducerInterface());
+ mCallbackWindow = new Surface(bq);
}
if (mCallbackStreamId != NO_STREAM) {
@@ -106,8 +139,8 @@ status_t CallbackProcessor::updateStream(const Parameters &params) {
res = device->deleteStream(mCallbackStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to delete old output stream "
- "for callbacks: %s (%d)", __FUNCTION__, mId,
- strerror(-res), res);
+ "for callbacks: %s (%d)", __FUNCTION__,
+ mId, strerror(-res), res);
return res;
}
mCallbackStreamId = NO_STREAM;
@@ -279,6 +312,16 @@ status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) {
return OK;
}
+ if (imgBuffer.width != static_cast<uint32_t>(l.mParameters.previewWidth) ||
+ imgBuffer.height != static_cast<uint32_t>(l.mParameters.previewHeight)) {
+ ALOGW("%s: The preview size has changed to %d x %d from %d x %d, this buffer is"
+ " no longer valid, dropping",__FUNCTION__,
+ l.mParameters.previewWidth, l.mParameters.previewHeight,
+ imgBuffer.width, imgBuffer.height);
+ mCallbackConsumer->unlockBuffer(imgBuffer);
+ return OK;
+ }
+
previewFormat = l.mParameters.previewFormat;
useFlexibleYuv = l.mParameters.fastInfo.useFlexibleYuv &&
(previewFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP ||
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.h b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
index d851a84..613f5be 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
@@ -23,9 +23,8 @@
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include <gui/CpuConsumer.h>
-#include "Parameters.h"
-#include "camera/CameraMetadata.h"
-#include "Camera2Heap.h"
+
+#include "api1/client2/Camera2Heap.h"
namespace android {
@@ -34,6 +33,8 @@ class CameraDeviceBase;
namespace camera2 {
+class Parameters;
+
/***
* Still image capture output image processing
*/
@@ -45,6 +46,8 @@ class CallbackProcessor:
void onFrameAvailable();
+ // Set to NULL to disable the direct-to-app callback window
+ status_t setCallbackWindow(sp<ANativeWindow> callbackWindow);
status_t updateStream(const Parameters &params);
status_t deleteStream();
int getStreamId() const;
@@ -64,6 +67,9 @@ class CallbackProcessor:
NO_STREAM = -1
};
+ // True if mCallbackWindow is a remote consumer, false if just the local
+ // mCallbackConsumer
+ bool mCallbackToApp;
int mCallbackStreamId;
static const size_t kCallbackHeapCount = 6;
sp<CpuConsumer> mCallbackConsumer;
diff --git a/services/camera/libcameraservice/camera2/Camera2Heap.h b/services/camera/libcameraservice/api1/client2/Camera2Heap.h
index 9c72d76..9c72d76 100644
--- a/services/camera/libcameraservice/camera2/Camera2Heap.h
+++ b/services/camera/libcameraservice/api1/client2/Camera2Heap.h
diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index e5a011c..8a4ce4e 100644
--- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -22,12 +22,11 @@
#include <utils/Trace.h>
#include <utils/Vector.h>
-#include "CaptureSequencer.h"
-#include "BurstCapture.h"
-#include "../Camera2Device.h"
-#include "../Camera2Client.h"
-#include "Parameters.h"
-#include "ZslProcessorInterface.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/CaptureSequencer.h"
+#include "api1/client2/BurstCapture.h"
+#include "api1/client2/Parameters.h"
+#include "api1/client2/ZslProcessorInterface.h"
namespace android {
namespace camera2 {
@@ -44,6 +43,7 @@ CaptureSequencer::CaptureSequencer(wp<Camera2Client> client):
mShutterNotified(false),
mClient(client),
mCaptureState(IDLE),
+ mStateTransitionCount(0),
mTriggerId(0),
mTimeoutCount(0),
mCaptureId(Camera2Client::kCaptureRequestIdStart),
@@ -104,12 +104,12 @@ void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) {
}
}
-void CaptureSequencer::onFrameAvailable(int32_t frameId,
+void CaptureSequencer::onFrameAvailable(int32_t requestId,
const CameraMetadata &frame) {
ALOGV("%s: Listener found new frame", __FUNCTION__);
ATRACE_CALL();
Mutex::Autolock l(mInputMutex);
- mNewFrameId = frameId;
+ mNewFrameId = requestId;
mNewFrame = frame;
if (!mNewFrameReceived) {
mNewFrameReceived = true;
@@ -199,8 +199,14 @@ bool CaptureSequencer::threadLoop() {
Mutex::Autolock l(mStateMutex);
if (currentState != mCaptureState) {
+ if (mCaptureState != IDLE) {
+ ATRACE_ASYNC_END(kStateNames[mCaptureState], mStateTransitionCount);
+ }
mCaptureState = currentState;
- ATRACE_INT("cam2_capt_state", mCaptureState);
+ mStateTransitionCount++;
+ if (mCaptureState != IDLE) {
+ ATRACE_ASYNC_BEGIN(kStateNames[mCaptureState], mStateTransitionCount);
+ }
ALOGV("Camera %d: New capture state %s",
client->getCameraId(), kStateNames[mCaptureState]);
mStateChanged.signal();
@@ -244,6 +250,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c
mBusy = false;
}
+ int takePictureCounter = 0;
{
SharedParameters::Lock l(client->getParameters());
switch (l.mParameters.state) {
@@ -271,6 +278,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c
Parameters::getStateName(l.mParameters.state));
res = INVALID_OPERATION;
}
+ takePictureCounter = l.mParameters.takePictureCounter;
}
sp<ZslProcessorInterface> processor = mZslProcessor.promote();
if (processor != 0) {
@@ -283,6 +291,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageDone(sp<Camera2Client> &c
* Fire the jpegCallback in Camera#takePicture(..., jpegCallback)
*/
if (mCaptureBuffer != 0 && res == OK) {
+ ATRACE_ASYNC_END(Camera2Client::kTakepictureLabel, takePictureCounter);
+
Camera2Client::SharedCameraCallbacks::Lock
l(client->mSharedCameraCallbacks);
ALOGV("%s: Sending still image to client", __FUNCTION__);
@@ -380,11 +390,23 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart(
sp<Camera2Client> &client) {
ATRACE_CALL();
+ bool isAeConverged = false;
// Get the onFrameAvailable callback when the requestID == mCaptureId
client->registerFrameListener(mCaptureId, mCaptureId + 1,
this);
+
+ {
+ Mutex::Autolock l(mInputMutex);
+ isAeConverged = (mAEState == ANDROID_CONTROL_AE_STATE_CONVERGED);
+ }
+
{
SharedParameters::Lock l(client->getParameters());
+ // Skip AE precapture when it is already converged and not in force flash mode.
+ if (l.mParameters.flashMode != Parameters::FLASH_MODE_ON && isAeConverged) {
+ return STANDARD_CAPTURE;
+ }
+
mTriggerId = l.mParameters.precaptureTriggerCounter++;
}
client->getCameraDevice()->triggerPrecaptureMetering(mTriggerId);
@@ -438,7 +460,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture(
status_t res;
ATRACE_CALL();
SharedParameters::Lock l(client->getParameters());
- Vector<uint8_t> outputStreams;
+ Vector<int32_t> outputStreams;
+ uint8_t captureIntent = static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
/**
* Set up output streams in the request
@@ -457,6 +480,7 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture(
if (l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
outputStreams.push(client->getRecordingStreamId());
+ captureIntent = static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
}
res = mCaptureRequest.update(ANDROID_REQUEST_OUTPUT_STREAMS,
@@ -466,6 +490,10 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture(
&mCaptureId, 1);
}
if (res == OK) {
+ res = mCaptureRequest.update(ANDROID_CONTROL_CAPTURE_INTENT,
+ &captureIntent, 1);
+ }
+ if (res == OK) {
res = mCaptureRequest.sort();
}
diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 76750aa..9fb4ee7 100644
--- a/services/camera/libcameraservice/camera2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -62,7 +62,7 @@ class CaptureSequencer:
void notifyAutoExposure(uint8_t newState, int triggerId);
// Notifications from the frame processor
- virtual void onFrameAvailable(int32_t frameId, const CameraMetadata &frame);
+ virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame);
// Notifications from the JPEG processor
void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer);
@@ -100,7 +100,7 @@ class CaptureSequencer:
* Internal to CaptureSequencer
*/
static const nsecs_t kWaitDuration = 100000000; // 100 ms
- static const int kMaxTimeoutsForPrecaptureStart = 2; // 200 ms
+ static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
@@ -125,6 +125,7 @@ class CaptureSequencer:
NUM_CAPTURE_STATES
} mCaptureState;
static const char* kStateNames[];
+ int mStateTransitionCount;
Mutex mStateMutex; // Guards mCaptureState
Condition mStateChanged;
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 114a7a8..c34cb12 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -21,16 +21,16 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-#include "FrameProcessor.h"
-#include "../CameraDeviceBase.h"
-#include "../Camera2Client.h"
+#include "common/CameraDeviceBase.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/FrameProcessor.h"
namespace android {
namespace camera2 {
FrameProcessor::FrameProcessor(wp<CameraDeviceBase> device,
wp<Camera2Client> client) :
- ProFrameProcessor(device),
+ FrameProcessorBase(device),
mClient(client),
mLastFrameNumberOfFaces(0) {
@@ -58,7 +58,7 @@ bool FrameProcessor::processSingleFrame(CameraMetadata &frame,
process3aState(frame, client);
}
- if (!ProFrameProcessor::processSingleFrame(frame, device)) {
+ if (!FrameProcessorBase::processSingleFrame(frame, device)) {
return false;
}
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
index f480c55..2a17d45 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
@@ -24,7 +24,7 @@
#include <utils/List.h>
#include <camera/CameraMetadata.h>
-#include "ProFrameProcessor.h"
+#include "common/FrameProcessorBase.h"
struct camera_frame_metadata;
@@ -37,7 +37,7 @@ namespace camera2 {
/* Output frame metadata processing thread. This thread waits for new
* frames from the device, and analyzes them as necessary.
*/
-class FrameProcessor : public ProFrameProcessor {
+class FrameProcessor : public FrameProcessorBase {
public:
FrameProcessor(wp<CameraDeviceBase> device, wp<Camera2Client> client);
~FrameProcessor();
diff --git a/services/camera/libcameraservice/camera2/JpegCompressor.cpp b/services/camera/libcameraservice/api1/client2/JpegCompressor.cpp
index c9af71e..2f0c67d 100644
--- a/services/camera/libcameraservice/camera2/JpegCompressor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegCompressor.cpp
@@ -210,7 +210,8 @@ boolean JpegCompressor::jpegEmptyOutputBuffer(j_compress_ptr /*cinfo*/) {
return true;
}
-void JpegCompressor::jpegTermDestination(j_compress_ptr /*cinfo*/) {
+void JpegCompressor::jpegTermDestination(j_compress_ptr cinfo) {
+ (void) cinfo; // TODO: clean up
ALOGV("%s", __FUNCTION__);
ALOGV("%s: Done writing JPEG data. %d bytes left in buffer",
__FUNCTION__, cinfo->dest->free_in_buffer);
diff --git a/services/camera/libcameraservice/camera2/JpegCompressor.h b/services/camera/libcameraservice/api1/client2/JpegCompressor.h
index 945b1de..945b1de 100644
--- a/services/camera/libcameraservice/camera2/JpegCompressor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegCompressor.h
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index f0a13ca..77d5c8a 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -24,12 +24,13 @@
#include <binder/MemoryHeapBase.h>
#include <utils/Log.h>
#include <utils/Trace.h>
-
-#include "JpegProcessor.h"
#include <gui/Surface.h>
-#include "../CameraDeviceBase.h"
-#include "../Camera2Client.h"
+#include "common/CameraDeviceBase.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/Camera2Heap.h"
+#include "api1/client2/CaptureSequencer.h"
+#include "api1/client2/JpegProcessor.h"
namespace android {
namespace camera2 {
@@ -82,11 +83,11 @@ status_t JpegProcessor::updateStream(const Parameters &params) {
if (mCaptureConsumer == 0) {
// Create CPU buffer queue endpoint
- mCaptureConsumer = new CpuConsumer(1);
+ sp<BufferQueue> bq = new BufferQueue();
+ mCaptureConsumer = new CpuConsumer(bq, 1);
mCaptureConsumer->setFrameAvailableListener(this);
mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
- mCaptureWindow = new Surface(
- mCaptureConsumer->getProducerInterface());
+ mCaptureWindow = new Surface(bq);
// Create memory for API consumption
mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0,
"Camera2Client::CaptureHeap");
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index a38611c..b2c05df 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -23,7 +23,7 @@
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include <gui/CpuConsumer.h>
-#include "Parameters.h"
+
#include "camera/CameraMetadata.h"
namespace android {
@@ -35,6 +35,7 @@ class MemoryHeapBase;
namespace camera2 {
class CaptureSequencer;
+class Parameters;
/***
* Still image capture output image processing
diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index a248b76..8a4e75c 100644
--- a/services/camera/libcameraservice/camera2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -58,13 +58,13 @@ status_t Parameters::initialize(const CameraMetadata *info) {
res = buildQuirks();
if (res != OK) return res;
- camera_metadata_ro_entry_t availableProcessedSizes =
- staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, 2);
- if (!availableProcessedSizes.count) return NO_INIT;
+ const Size MAX_PREVIEW_SIZE = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
+ res = getFilteredPreviewSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes);
+ if (res != OK) return res;
// TODO: Pick more intelligently
- previewWidth = availableProcessedSizes.data.i32[0];
- previewHeight = availableProcessedSizes.data.i32[1];
+ previewWidth = availablePreviewSizes[0].width;
+ previewHeight = availablePreviewSizes[0].height;
videoWidth = previewWidth;
videoHeight = previewHeight;
@@ -75,12 +75,13 @@ status_t Parameters::initialize(const CameraMetadata *info) {
previewWidth, previewHeight));
{
String8 supportedPreviewSizes;
- for (size_t i=0; i < availableProcessedSizes.count; i += 2) {
+ for (size_t i = 0; i < availablePreviewSizes.size(); i++) {
if (i != 0) supportedPreviewSizes += ",";
supportedPreviewSizes += String8::format("%dx%d",
- availableProcessedSizes.data.i32[i],
- availableProcessedSizes.data.i32[i+1]);
+ availablePreviewSizes[i].width,
+ availablePreviewSizes[i].height);
}
+ ALOGV("Supported preview sizes are: %s", supportedPreviewSizes.string());
params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
supportedPreviewSizes);
params.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
@@ -183,6 +184,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
// NOTE: Not scaled like FPS range values are.
previewFps = fpsFromRange(previewFpsRange[0], previewFpsRange[1]);
+ lastSetPreviewFps = previewFps;
params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
previewFps);
@@ -248,9 +250,17 @@ status_t Parameters::initialize(const CameraMetadata *info) {
staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, 4);
if (!availableJpegThumbnailSizes.count) return NO_INIT;
- // TODO: Pick default thumbnail size sensibly
- jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0];
- jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1];
+ // Pick the largest thumbnail size that matches still image aspect ratio.
+ ALOG_ASSERT(pictureWidth > 0 && pictureHeight > 0,
+ "Invalid picture size, %d x %d", pictureWidth, pictureHeight);
+ float picAspectRatio = static_cast<float>(pictureWidth) / pictureHeight;
+ Size thumbnailSize =
+ getMaxSizeForRatio(
+ picAspectRatio,
+ &availableJpegThumbnailSizes.data.i32[0],
+ availableJpegThumbnailSizes.count);
+ jpegThumbSize[0] = thumbnailSize.width;
+ jpegThumbSize[1] = thumbnailSize.height;
params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
jpegThumbSize[0]);
@@ -292,8 +302,11 @@ status_t Parameters::initialize(const CameraMetadata *info) {
CameraParameters::WHITE_BALANCE_AUTO);
camera_metadata_ro_entry_t availableWhiteBalanceModes =
- staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
- {
+ staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES, 0, 0, false);
+ if (!availableWhiteBalanceModes.count) {
+ params.set(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE,
+ CameraParameters::WHITE_BALANCE_AUTO);
+ } else {
String8 supportedWhiteBalance;
bool addComma = false;
for (size_t i=0; i < availableWhiteBalanceModes.count; i++) {
@@ -353,9 +366,11 @@ status_t Parameters::initialize(const CameraMetadata *info) {
CameraParameters::EFFECT_NONE);
camera_metadata_ro_entry_t availableEffects =
- staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
- if (!availableEffects.count) return NO_INIT;
- {
+ staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS, 0, 0, false);
+ if (!availableEffects.count) {
+ params.set(CameraParameters::KEY_SUPPORTED_EFFECTS,
+ CameraParameters::EFFECT_NONE);
+ } else {
String8 supportedEffects;
bool addComma = false;
for (size_t i=0; i < availableEffects.count; i++) {
@@ -413,9 +428,11 @@ status_t Parameters::initialize(const CameraMetadata *info) {
CameraParameters::ANTIBANDING_AUTO);
camera_metadata_ro_entry_t availableAntibandingModes =
- staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
- if (!availableAntibandingModes.count) return NO_INIT;
- {
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, 0, 0, false);
+ if (!availableAntibandingModes.count) {
+ params.set(CameraParameters::KEY_SUPPORTED_ANTIBANDING,
+ CameraParameters::ANTIBANDING_OFF);
+ } else {
String8 supportedAntibanding;
bool addComma = false;
for (size_t i=0; i < availableAntibandingModes.count; i++) {
@@ -455,9 +472,10 @@ status_t Parameters::initialize(const CameraMetadata *info) {
CameraParameters::SCENE_MODE_AUTO);
camera_metadata_ro_entry_t availableSceneModes =
- staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
- if (!availableSceneModes.count) return NO_INIT;
- {
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, 0, 0, false);
+ if (!availableSceneModes.count) {
+ params.remove(CameraParameters::KEY_SCENE_MODE);
+ } else {
String8 supportedSceneModes(CameraParameters::SCENE_MODE_AUTO);
bool addComma = true;
bool noSceneModes = false;
@@ -548,15 +566,17 @@ status_t Parameters::initialize(const CameraMetadata *info) {
}
}
+ bool isFlashAvailable = false;
camera_metadata_ro_entry_t flashAvailable =
- staticInfo(ANDROID_FLASH_INFO_AVAILABLE, 1, 1);
- if (!flashAvailable.count) return NO_INIT;
+ staticInfo(ANDROID_FLASH_INFO_AVAILABLE, 0, 1, false);
+ if (flashAvailable.count) {
+ isFlashAvailable = flashAvailable.data.u8[0];
+ }
camera_metadata_ro_entry_t availableAeModes =
- staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES);
- if (!availableAeModes.count) return NO_INIT;
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES, 0, 0, false);
- if (flashAvailable.data.u8[0]) {
+ if (isFlashAvailable) {
flashMode = Parameters::FLASH_MODE_OFF;
params.set(CameraParameters::KEY_FLASH_MODE,
CameraParameters::FLASH_MODE_OFF);
@@ -585,14 +605,12 @@ status_t Parameters::initialize(const CameraMetadata *info) {
}
camera_metadata_ro_entry_t minFocusDistance =
- staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 1, 1);
- if (!minFocusDistance.count) return NO_INIT;
+ staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0, 1, false);
camera_metadata_ro_entry_t availableAfModes =
- staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES);
- if (!availableAfModes.count) return NO_INIT;
+ staticInfo(ANDROID_CONTROL_AF_AVAILABLE_MODES, 0, 0, false);
- if (minFocusDistance.data.f[0] == 0) {
+ if (!minFocusDistance.count || minFocusDistance.data.f[0] == 0) {
// Fixed-focus lens
focusMode = Parameters::FOCUS_MODE_FIXED;
params.set(CameraParameters::KEY_FOCUS_MODE,
@@ -662,7 +680,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
focusingAreas.add(Parameters::Area(0,0,0,0,0));
camera_metadata_ro_entry_t availableFocalLengths =
- staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
+ staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, 0, 0, false);
if (!availableFocalLengths.count) return NO_INIT;
float minFocalLength = availableFocalLengths.data.f[0];
@@ -768,8 +786,8 @@ status_t Parameters::initialize(const CameraMetadata *info) {
CameraParameters::FALSE);
camera_metadata_ro_entry_t availableVideoStabilizationModes =
- staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
- if (!availableVideoStabilizationModes.count) return NO_INIT;
+ staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, 0, 0,
+ false);
if (availableVideoStabilizationModes.count > 1) {
params.set(CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED,
@@ -787,29 +805,25 @@ status_t Parameters::initialize(const CameraMetadata *info) {
enableFocusMoveMessages = false;
afTriggerCounter = 1;
+ afStateCounter = 0;
currentAfTriggerId = -1;
afInMotion = false;
precaptureTriggerCounter = 1;
+ takePictureCounter = 0;
+
previewCallbackFlags = 0;
previewCallbackOneShot = false;
+ previewCallbackSurface = false;
- camera_metadata_ro_entry_t supportedHardwareLevel =
- staticInfo(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
- if (!supportedHardwareLevel.count || (supportedHardwareLevel.data.u8[0] ==
- ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)) {
- ALOGI("Camera %d: ZSL mode disabled for limited mode HALs", cameraId);
+ char value[PROPERTY_VALUE_MAX];
+ property_get("camera.disable_zsl_mode", value, "0");
+ if (!strcmp(value,"1")) {
+ ALOGI("Camera %d: Disabling ZSL mode", cameraId);
zslMode = false;
} else {
- char value[PROPERTY_VALUE_MAX];
- property_get("camera.disable_zsl_mode", value, "0");
- if (!strcmp(value,"1")) {
- ALOGI("Camera %d: Disabling ZSL mode", cameraId);
- zslMode = false;
- } else {
- zslMode = true;
- }
+ zslMode = true;
}
lightFx = LIGHTFX_NONE;
@@ -828,14 +842,50 @@ String8 Parameters::get() const {
status_t Parameters::buildFastInfo() {
camera_metadata_ro_entry_t activeArraySize =
- staticInfo(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, 2, 2);
+ staticInfo(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, 2, 4);
if (!activeArraySize.count) return NO_INIT;
- int32_t arrayWidth = activeArraySize.data.i32[0];
- int32_t arrayHeight = activeArraySize.data.i32[1];
+ int32_t arrayWidth;
+ int32_t arrayHeight;
+ if (activeArraySize.count == 2) {
+ ALOGW("%s: Camera %d: activeArraySize is missing xmin/ymin!",
+ __FUNCTION__, cameraId);
+ arrayWidth = activeArraySize.data.i32[0];
+ arrayHeight = activeArraySize.data.i32[1];
+ } else if (activeArraySize.count == 4) {
+ arrayWidth = activeArraySize.data.i32[2];
+ arrayHeight = activeArraySize.data.i32[3];
+ } else return NO_INIT;
+
+ // We'll set the target FPS range for still captures to be as wide
+ // as possible to give the HAL maximum latitude for exposure selection
+ camera_metadata_ro_entry_t availableFpsRanges =
+ staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
+ if (availableFpsRanges.count < 2 || availableFpsRanges.count % 2 != 0) {
+ return NO_INIT;
+ }
+
+ int32_t bestStillCaptureFpsRange[2] = {
+ availableFpsRanges.data.i32[0], availableFpsRanges.data.i32[1]
+ };
+ int32_t curRange =
+ bestStillCaptureFpsRange[1] - bestStillCaptureFpsRange[0];
+ for (size_t i = 2; i < availableFpsRanges.count; i += 2) {
+ int32_t nextRange =
+ availableFpsRanges.data.i32[i + 1] -
+ availableFpsRanges.data.i32[i];
+ if ( (nextRange > curRange) || // Maximize size of FPS range first
+ (nextRange == curRange && // Then minimize low-end FPS
+ bestStillCaptureFpsRange[0] > availableFpsRanges.data.i32[i])) {
+
+ bestStillCaptureFpsRange[0] = availableFpsRanges.data.i32[i];
+ bestStillCaptureFpsRange[1] = availableFpsRanges.data.i32[i + 1];
+ curRange = nextRange;
+ }
+ }
camera_metadata_ro_entry_t availableFaceDetectModes =
- staticInfo(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);
- if (!availableFaceDetectModes.count) return NO_INIT;
+ staticInfo(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, 0, 0,
+ false);
uint8_t bestFaceDetectMode =
ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
@@ -862,19 +912,21 @@ status_t Parameters::buildFastInfo() {
}
}
+ int32_t maxFaces = 0;
camera_metadata_ro_entry_t maxFacesDetected =
- staticInfo(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, 1, 1);
- if (!maxFacesDetected.count) return NO_INIT;
-
- int32_t maxFaces = maxFacesDetected.data.i32[0];
+ staticInfo(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, 0, 1, false);
+ if (maxFacesDetected.count) {
+ maxFaces = maxFacesDetected.data.i32[0];
+ }
camera_metadata_ro_entry_t availableSceneModes =
- staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, 0, 0, false);
camera_metadata_ro_entry_t sceneModeOverrides =
- staticInfo(ANDROID_CONTROL_SCENE_MODE_OVERRIDES);
+ staticInfo(ANDROID_CONTROL_SCENE_MODE_OVERRIDES, 0, 0, false);
camera_metadata_ro_entry_t minFocusDistance =
- staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
- bool fixedLens = (minFocusDistance.data.f[0] == 0);
+ staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0, 0, false);
+ bool fixedLens = minFocusDistance.count == 0 ||
+ minFocusDistance.data.f[0] == 0;
camera_metadata_ro_entry_t availableFocalLengths =
staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
@@ -950,6 +1002,8 @@ status_t Parameters::buildFastInfo() {
fastInfo.arrayWidth = arrayWidth;
fastInfo.arrayHeight = arrayHeight;
+ fastInfo.bestStillCaptureFpsRange[0] = bestStillCaptureFpsRange[0];
+ fastInfo.bestStillCaptureFpsRange[1] = bestStillCaptureFpsRange[1];
fastInfo.bestFaceDetectMode = bestFaceDetectMode;
fastInfo.maxFaces = maxFaces;
@@ -1052,15 +1106,13 @@ status_t Parameters::set(const String8& paramString) {
validatedParams.previewWidth, validatedParams.previewHeight);
return BAD_VALUE;
}
- camera_metadata_ro_entry_t availablePreviewSizes =
- staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
- for (i = 0; i < availablePreviewSizes.count; i += 2 ) {
- if ((availablePreviewSizes.data.i32[i] ==
+ for (i = 0; i < availablePreviewSizes.size(); i++) {
+ if ((availablePreviewSizes[i].width ==
validatedParams.previewWidth) &&
- (availablePreviewSizes.data.i32[i+1] ==
+ (availablePreviewSizes[i].height ==
validatedParams.previewHeight)) break;
}
- if (i == availablePreviewSizes.count) {
+ if (i == availablePreviewSizes.size()) {
ALOGE("%s: Requested preview size %d x %d is not supported",
__FUNCTION__, validatedParams.previewWidth,
validatedParams.previewHeight);
@@ -1104,6 +1156,12 @@ status_t Parameters::set(const String8& paramString) {
validatedParams.previewFps =
fpsFromRange(validatedParams.previewFpsRange[0],
validatedParams.previewFpsRange[1]);
+
+ // Update our last-seen single preview FPS, needed for disambiguating
+ // when the application is intending to use the deprecated single-FPS
+ // setting vs. the range FPS setting
+ validatedParams.lastSetPreviewFps = newParams.getPreviewFrameRate();
+
newParams.setPreviewFrameRate(validatedParams.previewFps);
}
@@ -1139,12 +1197,15 @@ status_t Parameters::set(const String8& paramString) {
}
}
- // PREVIEW_FRAME_RATE
- // Deprecated, only use if the preview fps range is unchanged this time.
- // The single-value FPS is the same as the minimum of the range.
+ // PREVIEW_FRAME_RATE Deprecated, only use if the preview fps range is
+ // unchanged this time. The single-value FPS is the same as the minimum of
+ // the range. To detect whether the application has changed the value of
+ // previewFps, compare against their last-set preview FPS instead of the
+ // single FPS we may have synthesized from a range FPS set.
if (!fpsRangeChanged) {
validatedParams.previewFps = newParams.getPreviewFrameRate();
- if (validatedParams.previewFps != previewFps || recordingHintChanged) {
+ if (validatedParams.previewFps != lastSetPreviewFps ||
+ recordingHintChanged) {
camera_metadata_ro_entry_t availableFrameRates =
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
/**
@@ -1215,7 +1276,10 @@ status_t Parameters::set(const String8& paramString) {
String8::format("%d,%d",
validatedParams.previewFpsRange[0] * kFpsToApiScale,
validatedParams.previewFpsRange[1] * kFpsToApiScale));
-
+ // Update our last-seen single preview FPS, needed for disambiguating
+ // when the application is intending to use the deprecated single-FPS
+ // setting vs. the range FPS setting
+ validatedParams.lastSetPreviewFps = validatedParams.previewFps;
}
// PICTURE_SIZE
@@ -1465,7 +1529,7 @@ status_t Parameters::set(const String8& paramString) {
}
if (validatedParams.wbMode != wbMode) {
camera_metadata_ro_entry_t availableWbModes =
- staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+ staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES, 0, 0, false);
for (i = 0; i < availableWbModes.count; i++) {
if (validatedParams.wbMode == availableWbModes.data.u8[i]) break;
}
@@ -1496,8 +1560,9 @@ status_t Parameters::set(const String8& paramString) {
validatedParams.currentAfTriggerId = -1;
if (validatedParams.focusMode != Parameters::FOCUS_MODE_FIXED) {
camera_metadata_ro_entry_t minFocusDistance =
- staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
- if (minFocusDistance.data.f[0] == 0) {
+ staticInfo(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0, 0,
+ false);
+ if (minFocusDistance.count && minFocusDistance.data.f[0] == 0) {
ALOGE("%s: Requested focus mode \"%s\" is not available: "
"fixed focus lens",
__FUNCTION__,
@@ -1597,15 +1662,13 @@ status_t Parameters::set(const String8& paramString) {
__FUNCTION__);
return BAD_VALUE;
}
- camera_metadata_ro_entry_t availableVideoSizes =
- staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
- for (i = 0; i < availableVideoSizes.count; i += 2 ) {
- if ((availableVideoSizes.data.i32[i] ==
+ for (i = 0; i < availablePreviewSizes.size(); i++) {
+ if ((availablePreviewSizes[i].width ==
validatedParams.videoWidth) &&
- (availableVideoSizes.data.i32[i+1] ==
+ (availablePreviewSizes[i].height ==
validatedParams.videoHeight)) break;
}
- if (i == availableVideoSizes.count) {
+ if (i == availablePreviewSizes.size()) {
ALOGE("%s: Requested video size %d x %d is not supported",
__FUNCTION__, validatedParams.videoWidth,
validatedParams.videoHeight);
@@ -1617,7 +1680,8 @@ status_t Parameters::set(const String8& paramString) {
validatedParams.videoStabilization = boolFromString(
newParams.get(CameraParameters::KEY_VIDEO_STABILIZATION) );
camera_metadata_ro_entry_t availableVideoStabilizationModes =
- staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
+ staticInfo(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, 0, 0,
+ false);
if (validatedParams.videoStabilization &&
availableVideoStabilizationModes.count == 1) {
ALOGE("%s: Video stabilization not supported", __FUNCTION__);
@@ -1690,8 +1754,15 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
&metadataMode, 1);
if (res != OK) return res;
- res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
- previewFpsRange, 2);
+ camera_metadata_entry_t intent =
+ request->find(ANDROID_CONTROL_CAPTURE_INTENT);
+ if (intent.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE) {
+ res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ fastInfo.bestStillCaptureFpsRange, 2);
+ } else {
+ res = request->update(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+ previewFpsRange, 2);
+ }
if (res != OK) return res;
uint8_t reqWbLock = autoWhiteBalanceLock ?
@@ -2425,6 +2496,64 @@ int Parameters::normalizedYToArray(int y) const {
return cropYToArray(normalizedYToCrop(y));
}
+status_t Parameters::getFilteredPreviewSizes(Size limit, Vector<Size> *sizes) {
+ if (info == NULL) {
+ ALOGE("%s: Static metadata is not initialized", __FUNCTION__);
+ return NO_INIT;
+ }
+ if (sizes == NULL) {
+ ALOGE("%s: Input size is null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ const size_t SIZE_COUNT = sizeof(Size) / sizeof(int);
+ camera_metadata_ro_entry_t availableProcessedSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES, SIZE_COUNT);
+ if (availableProcessedSizes.count < SIZE_COUNT) return BAD_VALUE;
+
+ Size previewSize;
+ for (size_t i = 0; i < availableProcessedSizes.count; i += SIZE_COUNT) {
+ previewSize.width = availableProcessedSizes.data.i32[i];
+ previewSize.height = availableProcessedSizes.data.i32[i+1];
+ // Need skip the preview sizes that are too large.
+ if (previewSize.width <= limit.width &&
+ previewSize.height <= limit.height) {
+ sizes->push(previewSize);
+ }
+ }
+ if (sizes->isEmpty()) {
+ ALOGE("generated preview size list is empty!!");
+ return BAD_VALUE;
+ }
+ return OK;
+}
+
+Parameters::Size Parameters::getMaxSizeForRatio(
+ float ratio, const int32_t* sizeArray, size_t count) {
+ ALOG_ASSERT(sizeArray != NULL, "size array shouldn't be NULL");
+ ALOG_ASSERT(count >= 2 && count % 2 == 0, "count must be a positive even number");
+
+ Size maxSize = {0, 0};
+ for (size_t i = 0; i < count; i += 2) {
+ if (sizeArray[i] > 0 && sizeArray[i+1] > 0) {
+ float curRatio = static_cast<float>(sizeArray[i]) / sizeArray[i+1];
+ if (fabs(curRatio - ratio) < ASPECT_RATIO_TOLERANCE && maxSize.width < sizeArray[i]) {
+ maxSize.width = sizeArray[i];
+ maxSize.height = sizeArray[i+1];
+ }
+ }
+ }
+
+ if (maxSize.width == 0 || maxSize.height == 0) {
+ maxSize.width = sizeArray[0];
+ maxSize.height = sizeArray[1];
+ ALOGW("Unable to find the size to match the given aspect ratio %f."
+ "Fall back to %d x %d", ratio, maxSize.width, maxSize.height);
+ }
+
+ return maxSize;
+}
+
Parameters::CropRegion Parameters::calculateCropRegion(
Parameters::CropRegion::Outputs outputs) const {
@@ -2544,10 +2673,6 @@ status_t Parameters::calculatePictureFovs(float *horizFov, float *vertFov)
staticInfo(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, 2, 2);
if (!sensorSize.count) return NO_INIT;
- camera_metadata_ro_entry_t availableFocalLengths =
- staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
- if (!availableFocalLengths.count) return NO_INIT;
-
float arrayAspect = static_cast<float>(fastInfo.arrayWidth) /
fastInfo.arrayHeight;
float stillAspect = static_cast<float>(pictureWidth) / pictureHeight;
diff --git a/services/camera/libcameraservice/camera2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index be05b54..bcbdb99 100644
--- a/services/camera/libcameraservice/camera2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -46,6 +46,7 @@ struct Parameters {
int previewWidth, previewHeight;
int32_t previewFpsRange[2];
+ int lastSetPreviewFps; // the last single FPS value seen in a set call
int previewFps; // deprecated, here only for tracking changes
int previewFormat;
@@ -105,6 +106,11 @@ struct Parameters {
};
Vector<Area> focusingAreas;
+ struct Size {
+ int32_t width;
+ int32_t height;
+ };
+
int32_t exposureCompensation;
bool autoExposureLock;
bool autoWhiteBalanceLock;
@@ -135,13 +141,17 @@ struct Parameters {
bool enableFocusMoveMessages;
int afTriggerCounter;
+ int afStateCounter;
int currentAfTriggerId;
bool afInMotion;
int precaptureTriggerCounter;
+ int takePictureCounter;
+
uint32_t previewCallbackFlags;
bool previewCallbackOneShot;
+ bool previewCallbackSurface;
bool zslMode;
@@ -158,6 +168,11 @@ struct Parameters {
// Number of zoom steps to simulate
static const unsigned int NUM_ZOOM_STEPS = 100;
+ // Max preview size allowed
+ static const unsigned int MAX_PREVIEW_WIDTH = 1920;
+ static const unsigned int MAX_PREVIEW_HEIGHT = 1080;
+ // Aspect ratio tolerance
+ static const float ASPECT_RATIO_TOLERANCE = 0.001;
// Full static camera info, object owned by someone else, such as
// Camera2Device.
@@ -170,6 +185,7 @@ struct Parameters {
struct DeviceInfo {
int32_t arrayWidth;
int32_t arrayHeight;
+ int32_t bestStillCaptureFpsRange[2];
uint8_t bestFaceDetectMode;
int32_t maxFaces;
struct OverrideModes {
@@ -316,6 +332,12 @@ private:
int cropYToNormalized(int y) const;
int normalizedXToCrop(int x) const;
int normalizedYToCrop(int y) const;
+
+ Vector<Size> availablePreviewSizes;
+ // Get size list (that are no larger than limit) from static metadata.
+ status_t getFilteredPreviewSizes(Size limit, Vector<Size> *sizes);
+ // Get max size (from the size array) that matches the given aspect ratio.
+ Size getMaxSizeForRatio(float ratio, const int32_t* sizeArray, size_t count);
};
// This class encapsulates the Parameters class so that it can only be accessed
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index f7a6be7..6076dae 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -30,10 +30,10 @@
#include <gui/Surface.h>
#include <media/hardware/MetadataBufferType.h>
-#include "StreamingProcessor.h"
-#include "Camera2Heap.h"
-#include "../Camera2Client.h"
-#include "../CameraDeviceBase.h"
+#include "common/CameraDeviceBase.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/StreamingProcessor.h"
+#include "api1/client2/Camera2Heap.h"
namespace android {
namespace camera2 {
@@ -319,14 +319,13 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters &params) {
// Create CPU buffer queue endpoint. We need one more buffer here so that we can
// always acquire and free a buffer when the heap is full; otherwise the consumer
// will have buffers in flight we'll never clear out.
- mRecordingConsumer = new BufferItemConsumer(
+ sp<BufferQueue> bq = new BufferQueue();
+ mRecordingConsumer = new BufferItemConsumer(bq,
GRALLOC_USAGE_HW_VIDEO_ENCODER,
- mRecordingHeapCount + 1,
- true);
+ mRecordingHeapCount + 1);
mRecordingConsumer->setFrameAvailableListener(this);
mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
- mRecordingWindow = new Surface(
- mRecordingConsumer->getProducerInterface());
+ mRecordingWindow = new Surface(bq);
newConsumer = true;
// Allocate memory later, since we don't know buffer size until receipt
}
@@ -413,7 +412,7 @@ int StreamingProcessor::getRecordingStreamId() const {
}
status_t StreamingProcessor::startStream(StreamType type,
- const Vector<uint8_t> &outputStreams) {
+ const Vector<int32_t> &outputStreams) {
ATRACE_CALL();
status_t res;
@@ -617,7 +616,7 @@ status_t StreamingProcessor::processRecordingFrame() {
if (client == 0) {
// Discard frames during shutdown
BufferItemConsumer::BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer);
+ res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
if (res != OK) {
if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
@@ -635,7 +634,7 @@ status_t StreamingProcessor::processRecordingFrame() {
SharedParameters::Lock l(client->getParameters());
Mutex::Autolock m(mMutex);
BufferItemConsumer::BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer);
+ res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
if (res != OK) {
if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
@@ -831,8 +830,8 @@ void StreamingProcessor::releaseAllRecordingFramesLocked() {
mRecordingHeapFree = mRecordingHeapCount;
}
-bool StreamingProcessor::isStreamActive(const Vector<uint8_t> &streams,
- uint8_t recordingStreamId) {
+bool StreamingProcessor::isStreamActive(const Vector<int32_t> &streams,
+ int32_t recordingStreamId) {
for (size_t i = 0; i < streams.size(); i++) {
if (streams[i] == recordingStreamId) {
return true;
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index 3ec2df7..833bb8f 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -21,7 +21,6 @@
#include <utils/String16.h>
#include <gui/BufferItemConsumer.h>
-#include "Parameters.h"
#include "camera/CameraMetadata.h"
namespace android {
@@ -32,6 +31,7 @@ class IMemory;
namespace camera2 {
+class Parameters;
class Camera2Heap;
/**
@@ -64,7 +64,7 @@ class StreamingProcessor:
RECORD
};
status_t startStream(StreamType type,
- const Vector<uint8_t> &outputStreams);
+ const Vector<int32_t> &outputStreams);
// Toggle between paused and unpaused. Stream must be started first.
status_t togglePauseStream(bool pause);
@@ -97,7 +97,7 @@ class StreamingProcessor:
StreamType mActiveRequest;
bool mPaused;
- Vector<uint8_t> mActiveStreamIds;
+ Vector<int32_t> mActiveStreamIds;
// Preview-related members
int32_t mPreviewRequestId;
@@ -132,8 +132,8 @@ class StreamingProcessor:
void releaseAllRecordingFramesLocked();
// Determine if the specified stream is currently in use
- static bool isStreamActive(const Vector<uint8_t> &streams,
- uint8_t recordingStreamId);
+ static bool isStreamActive(const Vector<int32_t> &streams,
+ int32_t recordingStreamId);
};
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 94059cd..4207ba9 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -27,12 +27,12 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-
-#include "ZslProcessor.h"
#include <gui/Surface.h>
-#include "../CameraDeviceBase.h"
-#include "../Camera2Client.h"
+#include "common/CameraDeviceBase.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/CaptureSequencer.h"
+#include "api1/client2/ZslProcessor.h"
namespace android {
namespace camera2 {
@@ -71,7 +71,7 @@ void ZslProcessor::onFrameAvailable() {
}
}
-void ZslProcessor::onFrameAvailable(int32_t /*frameId*/,
+void ZslProcessor::onFrameAvailable(int32_t /*requestId*/,
const CameraMetadata &frame) {
Mutex::Autolock l(mInputMutex);
camera_metadata_ro_entry_t entry;
@@ -128,14 +128,13 @@ status_t ZslProcessor::updateStream(const Parameters &params) {
if (mZslConsumer == 0) {
// Create CPU buffer queue endpoint
- mZslConsumer = new BufferItemConsumer(
+ sp<BufferQueue> bq = new BufferQueue();
+ mZslConsumer = new BufferItemConsumer(bq,
GRALLOC_USAGE_HW_CAMERA_ZSL,
- kZslBufferDepth,
- true);
+ kZslBufferDepth);
mZslConsumer->setFrameAvailableListener(this);
mZslConsumer->setName(String8("Camera2Client::ZslConsumer"));
- mZslWindow = new Surface(
- mZslConsumer->getProducerInterface());
+ mZslWindow = new Surface(bq);
}
if (mZslStreamId != NO_STREAM) {
@@ -301,12 +300,12 @@ status_t ZslProcessor::pushToReprocess(int32_t requestId) {
uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
res = request.update(ANDROID_REQUEST_TYPE,
&requestType, 1);
- uint8_t inputStreams[1] =
- { static_cast<uint8_t>(mZslReprocessStreamId) };
+ int32_t inputStreams[1] =
+ { mZslReprocessStreamId };
if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
inputStreams, 1);
- uint8_t outputStreams[1] =
- { static_cast<uint8_t>(client->getCaptureStreamId()) };
+ int32_t outputStreams[1] =
+ { client->getCaptureStreamId() };
if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreams, 1);
res = request.update(ANDROID_REQUEST_ID,
@@ -426,7 +425,7 @@ status_t ZslProcessor::processNewZslBuffer() {
}
ALOGVV("Trying to get next buffer");
BufferItemConsumer::BufferItem item;
- res = zslConsumer->acquireBuffer(&item);
+ res = zslConsumer->acquireBuffer(&item, 0);
if (res != OK) {
if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
ALOGE("%s: Camera %d: Error receiving ZSL image buffer: "
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 27b597e..6d3cb85 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -23,12 +23,11 @@
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include <gui/BufferItemConsumer.h>
-#include "Parameters.h"
-#include "FrameProcessor.h"
-#include "camera/CameraMetadata.h"
-#include "Camera2Heap.h"
-#include "../CameraDeviceBase.h"
-#include "ZslProcessorInterface.h"
+#include <camera/CameraMetadata.h>
+
+#include "common/CameraDeviceBase.h"
+#include "api1/client2/ZslProcessorInterface.h"
+#include "api1/client2/FrameProcessor.h"
namespace android {
@@ -37,6 +36,7 @@ class Camera2Client;
namespace camera2 {
class CaptureSequencer;
+class Parameters;
/***
* ZSL queue processing
@@ -54,7 +54,7 @@ class ZslProcessor:
// From mZslConsumer
virtual void onFrameAvailable();
// From FrameProcessor
- virtual void onFrameAvailable(int32_t frameId, const CameraMetadata &frame);
+ virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame);
virtual void onBufferReleased(buffer_handle_t *handle);
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index 40c77df..776ebe2 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -27,13 +27,13 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-
-#include "ZslProcessor3.h"
#include <gui/Surface.h>
-#include "../CameraDeviceBase.h"
-#include "../Camera3Device.h"
-#include "../Camera2Client.h"
+#include "common/CameraDeviceBase.h"
+#include "api1/Camera2Client.h"
+#include "api1/client2/CaptureSequencer.h"
+#include "api1/client2/ZslProcessor3.h"
+#include "device3/Camera3Device.h"
namespace android {
namespace camera2 {
@@ -61,7 +61,7 @@ ZslProcessor3::~ZslProcessor3() {
deleteStream();
}
-void ZslProcessor3::onFrameAvailable(int32_t /*frameId*/,
+void ZslProcessor3::onFrameAvailable(int32_t /*requestId*/,
const CameraMetadata &frame) {
Mutex::Autolock l(mInputMutex);
camera_metadata_ro_entry_t entry;
@@ -247,13 +247,13 @@ status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
res = request.update(ANDROID_REQUEST_TYPE,
&requestType, 1);
- uint8_t inputStreams[1] =
- { static_cast<uint8_t>(mZslStreamId) };
+ int32_t inputStreams[1] =
+ { mZslStreamId };
if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
inputStreams, 1);
// TODO: Shouldn't we also update the latest preview frame?
- uint8_t outputStreams[1] =
- { static_cast<uint8_t>(client->getCaptureStreamId()) };
+ int32_t outputStreams[1] =
+ { client->getCaptureStreamId() };
if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreams, 1);
res = request.update(ANDROID_REQUEST_ID,
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
index cb98b99..d2f8322 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor3.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
@@ -23,13 +23,11 @@
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include <gui/BufferItemConsumer.h>
-#include "Parameters.h"
-#include "FrameProcessor.h"
-#include "camera/CameraMetadata.h"
-#include "Camera2Heap.h"
-#include "../CameraDeviceBase.h"
-#include "ZslProcessorInterface.h"
-#include "../camera3/Camera3ZslStream.h"
+#include <camera/CameraMetadata.h>
+
+#include "api1/client2/FrameProcessor.h"
+#include "api1/client2/ZslProcessorInterface.h"
+#include "device3/Camera3ZslStream.h"
namespace android {
@@ -38,6 +36,7 @@ class Camera2Client;
namespace camera2 {
class CaptureSequencer;
+class Parameters;
/***
* ZSL queue processing
@@ -52,7 +51,7 @@ class ZslProcessor3 :
~ZslProcessor3();
// From FrameProcessor
- virtual void onFrameAvailable(int32_t frameId, const CameraMetadata &frame);
+ virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame);
/**
****************************************
diff --git a/services/camera/libcameraservice/camera2/ZslProcessorInterface.h b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
index 183c0c2..183c0c2 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessorInterface.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
new file mode 100644
index 0000000..72126c1
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CameraDeviceClient"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+// #define LOG_NDEBUG 0
+
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <gui/Surface.h>
+#include <camera/camera2/CaptureRequest.h>
+
+#include "common/CameraDeviceBase.h"
+#include "api2/CameraDeviceClient.h"
+
+
+
+namespace android {
+using namespace camera2;
+
+CameraDeviceClientBase::CameraDeviceClientBase(
+ const sp<CameraService>& cameraService,
+ const sp<ICameraDeviceCallbacks>& remoteCallback,
+ const String16& clientPackageName,
+ int cameraId,
+ int cameraFacing,
+ int clientPid,
+ uid_t clientUid,
+ int servicePid) :
+ BasicClient(cameraService, remoteCallback->asBinder(), clientPackageName,
+ cameraId, cameraFacing, clientPid, clientUid, servicePid),
+ mRemoteCallback(remoteCallback) {
+}
+
+// Interface used by CameraService
+
+CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
+ const sp<ICameraDeviceCallbacks>& remoteCallback,
+ const String16& clientPackageName,
+ int cameraId,
+ int cameraFacing,
+ int clientPid,
+ uid_t clientUid,
+ int servicePid) :
+ Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
+ cameraId, cameraFacing, clientPid, clientUid, servicePid),
+ mRequestIdCounter(0) {
+
+ ATRACE_CALL();
+ ALOGI("CameraDeviceClient %d: Opened", cameraId);
+}
+
+status_t CameraDeviceClient::initialize(camera_module_t *module)
+{
+ ATRACE_CALL();
+ status_t res;
+
+ res = Camera2ClientBase::initialize(module);
+ if (res != OK) {
+ return res;
+ }
+
+ String8 threadName;
+ mFrameProcessor = new FrameProcessorBase(mDevice);
+ threadName = String8::format("CDU-%d-FrameProc", mCameraId);
+ mFrameProcessor->run(threadName.string());
+
+ mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+ FRAME_PROCESSOR_LISTENER_MAX_ID,
+ /*listener*/this);
+
+ return OK;
+}
+
+CameraDeviceClient::~CameraDeviceClient() {
+}
+
+status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
+ bool streaming) {
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res;
+
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ if (request == 0) {
+ ALOGE("%s: Camera %d: Sent null request. Rejecting request.",
+ __FUNCTION__, mCameraId);
+ return BAD_VALUE;
+ }
+
+ CameraMetadata metadata(request->mMetadata);
+
+ if (metadata.isEmpty()) {
+ ALOGE("%s: Camera %d: Sent empty metadata packet. Rejecting request.",
+ __FUNCTION__, mCameraId);
+ return BAD_VALUE;
+ } else if (request->mSurfaceList.size() == 0) {
+ ALOGE("%s: Camera %d: Requests must have at least one surface target. "
+ "Rejecting request.", __FUNCTION__, mCameraId);
+ return BAD_VALUE;
+ }
+
+ if (!enforceRequestPermissions(metadata)) {
+ // Callee logs
+ return PERMISSION_DENIED;
+ }
+
+ /**
+ * Write in the output stream IDs which we calculate from
+ * the capture request's list of surface targets
+ */
+ Vector<int32_t> outputStreamIds;
+ outputStreamIds.setCapacity(request->mSurfaceList.size());
+ for (size_t i = 0; i < request->mSurfaceList.size(); ++i) {
+ sp<Surface> surface = request->mSurfaceList[i];
+
+ if (surface == 0) continue;
+
+ sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
+ int idx = mStreamMap.indexOfKey(gbp->asBinder());
+
+ // Trying to submit request with surface that wasn't created
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: Camera %d: Tried to submit a request with a surface that"
+ " we have not called createStream on",
+ __FUNCTION__, mCameraId);
+ return BAD_VALUE;
+ }
+
+ int streamId = mStreamMap.valueAt(idx);
+ outputStreamIds.push_back(streamId);
+ ALOGV("%s: Camera %d: Appending output stream %d to request",
+ __FUNCTION__, mCameraId, streamId);
+ }
+
+ metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
+ outputStreamIds.size());
+
+ int32_t requestId = mRequestIdCounter++;
+ metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
+ ALOGV("%s: Camera %d: Submitting request with ID %d",
+ __FUNCTION__, mCameraId, requestId);
+
+ if (streaming) {
+ res = mDevice->setStreamingRequest(metadata);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Got error %d after trying to set streaming "
+ "request", __FUNCTION__, mCameraId, res);
+ } else {
+ mStreamingRequestList.push_back(requestId);
+ }
+ } else {
+ res = mDevice->capture(metadata);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Got error %d after trying to set capture",
+ __FUNCTION__, mCameraId, res);
+ }
+ }
+
+ ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId);
+ if (res == OK) {
+ return requestId;
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClient::cancelRequest(int requestId) {
+ ATRACE_CALL();
+ ALOGV("%s, requestId = %d", __FUNCTION__, requestId);
+
+ status_t res;
+
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ Vector<int>::iterator it, end;
+ for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
+ it != end; ++it) {
+ if (*it == requestId) {
+ break;
+ }
+ }
+
+ if (it == end) {
+ ALOGE("%s: Camera%d: Did not find request id %d in list of streaming "
+ "requests", __FUNCTION__, mCameraId, requestId);
+ return BAD_VALUE;
+ }
+
+ res = mDevice->clearStreamingRequest();
+
+ if (res == OK) {
+ ALOGV("%s: Camera %d: Successfully cleared streaming request",
+ __FUNCTION__, mCameraId);
+ mStreamingRequestList.erase(it);
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClient::deleteStream(int streamId) {
+ ATRACE_CALL();
+ ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
+
+ status_t res;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ // Guard against trying to delete non-created streams
+ ssize_t index = NAME_NOT_FOUND;
+ for (size_t i = 0; i < mStreamMap.size(); ++i) {
+ if (streamId == mStreamMap.valueAt(i)) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == NAME_NOT_FOUND) {
+ ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream "
+ "created yet", __FUNCTION__, mCameraId, streamId);
+ return BAD_VALUE;
+ }
+
+ // Also returns BAD_VALUE if stream ID was not valid
+ res = mDevice->deleteStream(streamId);
+
+ if (res == BAD_VALUE) {
+ ALOGE("%s: Camera %d: Unexpected BAD_VALUE when deleting stream, but we"
+ " already checked and the stream ID (%d) should be valid.",
+ __FUNCTION__, mCameraId, streamId);
+ } else if (res == OK) {
+ mStreamMap.removeItemsAt(index);
+
+ ALOGV("%s: Camera %d: Successfully deleted stream ID (%d)",
+ __FUNCTION__, mCameraId, streamId);
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClient::createStream(int width, int height, int format,
+ const sp<IGraphicBufferProducer>& bufferProducer)
+{
+ 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);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ // Don't create multiple streams for the same target surface
+ {
+ ssize_t index = mStreamMap.indexOfKey(bufferProducer->asBinder());
+ if (index != NAME_NOT_FOUND) {
+ ALOGW("%s: Camera %d: Buffer producer already has a stream for it "
+ "(ID %d)",
+ __FUNCTION__, mCameraId, index);
+ return ALREADY_EXISTS;
+ }
+ }
+
+ // HACK b/10949105
+ // Query consumer usage bits to set async operation mode for
+ // GLConsumer using controlledByApp parameter.
+ bool useAsync = false;
+ int32_t consumerUsage;
+ if ((res = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
+ &consumerUsage)) != OK) {
+ ALOGE("%s: Camera %d: Failed to query consumer usage", __FUNCTION__,
+ mCameraId);
+ return res;
+ }
+ if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
+ ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
+ __FUNCTION__, mCameraId);
+ useAsync = true;
+ }
+
+ sp<IBinder> binder;
+ sp<ANativeWindow> anw;
+ if (bufferProducer != 0) {
+ binder = bufferProducer->asBinder();
+ anw = new Surface(bufferProducer, useAsync);
+ }
+
+ // TODO: remove w,h,f since we are ignoring them
+
+ if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
+ ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__,
+ mCameraId);
+ return res;
+ }
+ if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
+ ALOGE("%s: Camera %d: Failed to query Surface height", __FUNCTION__,
+ mCameraId);
+ return res;
+ }
+ if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &format)) != OK) {
+ ALOGE("%s: Camera %d: Failed to query Surface format", __FUNCTION__,
+ mCameraId);
+ return res;
+ }
+
+ // FIXME: remove this override since the default format should be
+ // IMPLEMENTATION_DEFINED. b/9487482
+ if (format >= HAL_PIXEL_FORMAT_RGBA_8888 &&
+ format <= HAL_PIXEL_FORMAT_BGRA_8888) {
+ ALOGW("%s: Camera %d: Overriding format 0x%x to IMPLEMENTATION_DEFINED",
+ __FUNCTION__, mCameraId, format);
+ format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ }
+
+ // TODO: add startConfigure/stopConfigure call to CameraDeviceBase
+ // this will make it so Camera3Device doesn't call configure_streams
+ // after each call, but only once we are done with all.
+
+ int streamId = -1;
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ // JPEG buffers need to be sized for maximum possible compressed size
+ CameraMetadata staticInfo = mDevice->info();
+ camera_metadata_entry_t entry = staticInfo.find(ANDROID_JPEG_MAX_SIZE);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: Can't find maximum JPEG size in "
+ "static metadata!", __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+ int32_t maxJpegSize = entry.data.i32[0];
+ res = mDevice->createStream(anw, width, height, format, maxJpegSize,
+ &streamId);
+ } else {
+ // All other streams are a known size
+ res = mDevice->createStream(anw, width, height, format, /*size*/0,
+ &streamId);
+ }
+
+ if (res == OK) {
+ mStreamMap.add(bufferProducer->asBinder(), streamId);
+
+ ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
+ __FUNCTION__, mCameraId, streamId);
+
+ /**
+ * Set the stream transform flags to automatically
+ * rotate the camera stream for preview use cases.
+ */
+ int32_t transform = 0;
+ res = getRotationTransformLocked(&transform);
+
+ if (res != OK) {
+ // Error logged by getRotationTransformLocked.
+ return res;
+ }
+
+ res = mDevice->setStreamTransform(streamId, transform);
+ if (res != OK) {
+ ALOGE("%s: Failed to set stream transform (stream id %d)",
+ __FUNCTION__, streamId);
+ return res;
+ }
+
+ return streamId;
+ }
+
+ return res;
+}
+
+// Create a request object from a template.
+status_t CameraDeviceClient::createDefaultRequest(int templateId,
+ /*out*/
+ CameraMetadata* request)
+{
+ ATRACE_CALL();
+ ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId);
+
+ status_t res;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ CameraMetadata metadata;
+ if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK &&
+ request != NULL) {
+
+ request->swap(metadata);
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClient::getCameraInfo(/*out*/CameraMetadata* info)
+{
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res = OK;
+
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ if (info != NULL) {
+ *info = mDevice->info(); // static camera metadata
+ // TODO: merge with device-specific camera metadata
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClient::waitUntilIdle()
+{
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res = OK;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ // FIXME: Also need check repeating burst.
+ if (!mStreamingRequestList.isEmpty()) {
+ ALOGE("%s: Camera %d: Try to waitUntilIdle when there are active streaming requests",
+ __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+ res = mDevice->waitUntilDrained();
+ ALOGV("%s Done", __FUNCTION__);
+
+ return res;
+}
+
+status_t CameraDeviceClient::flush() {
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ status_t res = OK;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ return mDevice->flush();
+}
+
+status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
+ String8 result;
+ result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
+ mCameraId,
+ getRemoteCallback()->asBinder().get(),
+ mClientPid);
+ result.append(" State: ");
+
+ // TODO: print dynamic/request section from most recent requests
+ mFrameProcessor->dump(fd, args);
+
+ return dumpDevice(fd, args);
+}
+
+
+void CameraDeviceClient::notifyError() {
+ // Thread safe. Don't bother locking.
+ sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+
+ if (remoteCb != 0) {
+ remoteCb->onDeviceError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE);
+ }
+}
+
+void CameraDeviceClient::notifyIdle() {
+ // Thread safe. Don't bother locking.
+ sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+
+ if (remoteCb != 0) {
+ remoteCb->onDeviceIdle();
+ }
+}
+
+void CameraDeviceClient::notifyShutter(int requestId,
+ nsecs_t timestamp) {
+ // Thread safe. Don't bother locking.
+ sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+ if (remoteCb != 0) {
+ remoteCb->onCaptureStarted(requestId, timestamp);
+ }
+}
+
+// TODO: refactor the code below this with IProCameraUser.
+// it's 100% copy-pasted, so lets not change it right now to make it easier.
+
+void CameraDeviceClient::detachDevice() {
+ if (mDevice == 0) return;
+
+ ALOGV("Camera %d: Stopping processors", mCameraId);
+
+ mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+ FRAME_PROCESSOR_LISTENER_MAX_ID,
+ /*listener*/this);
+ mFrameProcessor->requestExit();
+ ALOGV("Camera %d: Waiting for threads", mCameraId);
+ mFrameProcessor->join();
+ ALOGV("Camera %d: Disconnecting device", mCameraId);
+
+ // WORKAROUND: HAL refuses to disconnect while there's streams in flight
+ {
+ mDevice->clearStreamingRequest();
+
+ status_t code;
+ if ((code = mDevice->waitUntilDrained()) != OK) {
+ ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
+ code);
+ }
+ }
+
+ Camera2ClientBase::detachDevice();
+}
+
+/** Device-related methods */
+void CameraDeviceClient::onFrameAvailable(int32_t requestId,
+ const CameraMetadata& frame) {
+ ATRACE_CALL();
+ ALOGV("%s", __FUNCTION__);
+
+ // Thread-safe. No lock necessary.
+ sp<ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
+ if (remoteCb != NULL) {
+ ALOGV("%s: frame = %p ", __FUNCTION__, &frame);
+ remoteCb->onResultReceived(requestId, frame);
+ }
+}
+
+// TODO: move to Camera2ClientBase
+bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
+
+ const int pid = IPCThreadState::self()->getCallingPid();
+ const int selfPid = getpid();
+ camera_metadata_entry_t entry;
+
+ /**
+ * Mixin default important security values
+ * - android.led.transmit = defaulted ON
+ */
+ CameraMetadata staticInfo = mDevice->info();
+ entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS);
+ for(size_t i = 0; i < entry.count; ++i) {
+ uint8_t led = entry.data.u8[i];
+
+ switch(led) {
+ case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
+ uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
+ if (!metadata.exists(ANDROID_LED_TRANSMIT)) {
+ metadata.update(ANDROID_LED_TRANSMIT,
+ &transmitDefault, 1);
+ }
+ break;
+ }
+ }
+ }
+
+ // We can do anything!
+ if (pid == selfPid) {
+ return true;
+ }
+
+ /**
+ * Permission check special fields in the request
+ * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT
+ */
+ entry = metadata.find(ANDROID_LED_TRANSMIT);
+ if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) {
+ String16 permissionString =
+ String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
+ if (!checkCallingPermission(permissionString)) {
+ const int uid = IPCThreadState::self()->getCallingUid();
+ ALOGE("Permission Denial: "
+ "can't disable transmit LED pid=%d, uid=%d", pid, uid);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+status_t CameraDeviceClient::getRotationTransformLocked(int32_t* transform) {
+ ALOGV("%s: begin", __FUNCTION__);
+
+ if (transform == NULL) {
+ ALOGW("%s: null transform", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ *transform = 0;
+
+ const CameraMetadata& staticInfo = mDevice->info();
+ camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_SENSOR_ORIENTATION);
+ if (entry.count == 0) {
+ ALOGE("%s: Camera %d: Can't find android.sensor.orientation in "
+ "static metadata!", __FUNCTION__, mCameraId);
+ return INVALID_OPERATION;
+ }
+
+ int32_t& flags = *transform;
+
+ int orientation = entry.data.i32[0];
+ switch (orientation) {
+ case 0:
+ flags = 0;
+ break;
+ case 90:
+ flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
+ break;
+ case 180:
+ flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
+ break;
+ case 270:
+ flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
+ break;
+ default:
+ ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
+ __FUNCTION__, orientation);
+ return INVALID_OPERATION;
+ }
+
+ /**
+ * This magic flag makes surfaceflinger un-rotate the buffers
+ * to counter the extra global device UI rotation whenever the user
+ * physically rotates the device.
+ *
+ * By doing this, the camera buffer always ends up aligned
+ * with the physical camera for a "see through" effect.
+ *
+ * In essence, the buffer only gets rotated during preview use-cases.
+ * The user is still responsible to re-create streams of the proper
+ * aspect ratio, or the preview will end up looking non-uniformly
+ * stretched.
+ */
+ flags |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+
+ ALOGV("%s: final transform = 0x%x", __FUNCTION__, flags);
+
+ return OK;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
new file mode 100644
index 0000000..b9c16aa
--- /dev/null
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERADEVICECLIENT_H
+#define ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERADEVICECLIENT_H
+
+#include <camera/camera2/ICameraDeviceUser.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+
+#include "CameraService.h"
+#include "common/FrameProcessorBase.h"
+#include "common/Camera2ClientBase.h"
+
+namespace android {
+
+struct CameraDeviceClientBase :
+ public CameraService::BasicClient, public BnCameraDeviceUser
+{
+ typedef ICameraDeviceCallbacks TCamCallbacks;
+
+ const sp<ICameraDeviceCallbacks>& getRemoteCallback() {
+ return mRemoteCallback;
+ }
+
+protected:
+ CameraDeviceClientBase(const sp<CameraService>& cameraService,
+ const sp<ICameraDeviceCallbacks>& remoteCallback,
+ const String16& clientPackageName,
+ int cameraId,
+ int cameraFacing,
+ int clientPid,
+ uid_t clientUid,
+ int servicePid);
+
+ sp<ICameraDeviceCallbacks> mRemoteCallback;
+};
+
+/**
+ * Implements the binder ICameraDeviceUser API,
+ * meant for HAL3-public implementation of
+ * android.hardware.photography.CameraDevice
+ */
+class CameraDeviceClient :
+ public Camera2ClientBase<CameraDeviceClientBase>,
+ public camera2::FrameProcessorBase::FilteredListener
+{
+public:
+ /**
+ * ICameraDeviceUser interface (see ICameraDeviceUser for details)
+ */
+
+ // Note that the callee gets a copy of the metadata.
+ virtual int submitRequest(sp<CaptureRequest> request,
+ bool streaming = false);
+ virtual status_t cancelRequest(int requestId);
+
+ // 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);
+
+ // Create a request object from a template.
+ virtual status_t createDefaultRequest(int templateId,
+ /*out*/
+ CameraMetadata* request);
+
+ // Get the static metadata for the camera
+ // -- Caller owns the newly allocated metadata
+ virtual status_t getCameraInfo(/*out*/CameraMetadata* info);
+
+ // Wait until all the submitted requests have finished processing
+ virtual status_t waitUntilIdle();
+
+ // Flush all active and pending requests as fast as possible
+ virtual status_t flush();
+
+ /**
+ * Interface used by CameraService
+ */
+
+ CameraDeviceClient(const sp<CameraService>& cameraService,
+ const sp<ICameraDeviceCallbacks>& remoteCallback,
+ const String16& clientPackageName,
+ int cameraId,
+ int cameraFacing,
+ int clientPid,
+ uid_t clientUid,
+ int servicePid);
+ virtual ~CameraDeviceClient();
+
+ virtual status_t initialize(camera_module_t *module);
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ /**
+ * Device listener interface
+ */
+
+ virtual void notifyIdle();
+ virtual void notifyError();
+ virtual void notifyShutter(int requestId, nsecs_t timestamp);
+
+ /**
+ * Interface used by independent components of CameraDeviceClient.
+ */
+protected:
+ /** FilteredListener implementation **/
+ virtual void onFrameAvailable(int32_t requestId,
+ const CameraMetadata& frame);
+ virtual void detachDevice();
+
+ // Calculate the ANativeWindow transform from android.sensor.orientation
+ status_t getRotationTransformLocked(/*out*/int32_t* transform);
+
+private:
+ /** ICameraDeviceUser interface-related private members */
+
+ /** Preview callback related members */
+ sp<camera2::FrameProcessorBase> mFrameProcessor;
+ static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
+ static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
+
+ /** Utility members */
+ bool enforceRequestPermissions(CameraMetadata& metadata);
+
+ // IGraphicsBufferProducer binder -> Stream ID
+ KeyedVector<sp<IBinder>, int> mStreamMap;
+
+ // Stream ID
+ Vector<int> mStreamingRequestList;
+
+ int32_t mRequestIdCounter;
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
index 251fdab..1a7a7a7 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
@@ -24,10 +24,9 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <gui/Surface.h>
-#include "camera2/Parameters.h"
-#include "ProCamera2Client.h"
-#include "camera2/ProFrameProcessor.h"
-#include "CameraDeviceBase.h"
+
+#include "api_pro/ProCamera2Client.h"
+#include "common/CameraDeviceBase.h"
namespace android {
using namespace camera2;
@@ -62,7 +61,7 @@ status_t ProCamera2Client::initialize(camera_module_t *module)
}
String8 threadName;
- mFrameProcessor = new ProFrameProcessor(mDevice);
+ mFrameProcessor = new FrameProcessorBase(mDevice);
threadName = String8::format("PC2-%d-FrameProc", mCameraId);
mFrameProcessor->run(threadName.string());
@@ -218,6 +217,7 @@ status_t ProCamera2Client::submitRequest(camera_metadata_t* request,
}
status_t ProCamera2Client::cancelRequest(int requestId) {
+ (void)requestId;
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
@@ -374,7 +374,7 @@ void ProCamera2Client::detachDevice() {
}
/** Device-related methods */
-void ProCamera2Client::onFrameAvailable(int32_t frameId,
+void ProCamera2Client::onFrameAvailable(int32_t requestId,
const CameraMetadata& frame) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
@@ -386,7 +386,7 @@ void ProCamera2Client::onFrameAvailable(int32_t frameId,
CameraMetadata tmp(frame);
camera_metadata_t* meta = tmp.release();
ALOGV("%s: meta = %p ", __FUNCTION__, meta);
- mRemoteCallback->onResultReceived(frameId, meta);
+ mRemoteCallback->onResultReceived(requestId, meta);
tmp.acquire(meta);
}
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/api_pro/ProCamera2Client.h
index faee9f9..8a0f547 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.h
@@ -17,10 +17,10 @@
#ifndef ANDROID_SERVERS_CAMERA_PROCAMERA2CLIENT_H
#define ANDROID_SERVERS_CAMERA_PROCAMERA2CLIENT_H
-#include "Camera2Device.h"
#include "CameraService.h"
-#include "camera2/ProFrameProcessor.h"
-#include "Camera2ClientBase.h"
+#include "common/FrameProcessorBase.h"
+#include "common/Camera2ClientBase.h"
+#include "device2/Camera2Device.h"
namespace android {
@@ -31,7 +31,7 @@ class IMemory;
*/
class ProCamera2Client :
public Camera2ClientBase<CameraService::ProClient>,
- public camera2::ProFrameProcessor::FilteredListener
+ public camera2::FrameProcessorBase::FilteredListener
{
public:
/**
@@ -97,7 +97,7 @@ public:
protected:
/** FilteredListener implementation **/
- virtual void onFrameAvailable(int32_t frameId,
+ virtual void onFrameAvailable(int32_t requestId,
const CameraMetadata& frame);
virtual void detachDevice();
@@ -105,7 +105,7 @@ private:
/** IProCameraUser interface-related private members */
/** Preview callback related members */
- sp<camera2::ProFrameProcessor> mFrameProcessor;
+ sp<camera2::FrameProcessorBase> mFrameProcessor;
static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
diff --git a/services/camera/libcameraservice/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 0623b89..2d1253f 100644
--- a/services/camera/libcameraservice/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -24,11 +24,12 @@
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <gui/Surface.h>
-#include "camera2/Parameters.h"
-#include "Camera2ClientBase.h"
-#include "camera2/ProFrameProcessor.h"
-#include "Camera2Device.h"
+#include "common/Camera2ClientBase.h"
+
+#include "api2/CameraDeviceClient.h"
+
+#include "CameraDeviceFactory.h"
namespace android {
using namespace camera2;
@@ -54,7 +55,9 @@ Camera2ClientBase<TClientBase>::Camera2ClientBase(
mSharedCameraCallbacks(remoteCallback)
{
ALOGI("Camera %d: Opened", cameraId);
- mDevice = new Camera2Device(cameraId);
+
+ mDevice = CameraDeviceFactory::createDevice(cameraId);
+ LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
template <typename TClientBase>
@@ -92,7 +95,7 @@ status_t Camera2ClientBase<TClientBase>::initialize(camera_module_t *module) {
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, TClientBase::mCameraId, strerror(-res), res);
- return NO_INIT;
+ return res;
}
res = mDevice->setNotifyCallback(this);
@@ -223,13 +226,18 @@ void Camera2ClientBase<TClientBase>::notifyError(int errorCode, int arg1,
}
template <typename TClientBase>
-void Camera2ClientBase<TClientBase>::notifyShutter(int frameNumber,
+void Camera2ClientBase<TClientBase>::notifyIdle() {
+ ALOGV("Camera device is now idle");
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyShutter(int requestId,
nsecs_t timestamp) {
- (void)frameNumber;
+ (void)requestId;
(void)timestamp;
- ALOGV("%s: Shutter notification for frame %d at time %lld", __FUNCTION__,
- frameNumber, timestamp);
+ ALOGV("%s: Shutter notification for request id %d at time %lld",
+ __FUNCTION__, requestId, timestamp);
}
template <typename TClientBase>
@@ -241,13 +249,6 @@ void Camera2ClientBase<TClientBase>::notifyAutoFocus(uint8_t newState,
ALOGV("%s: Autofocus state now %d, last trigger %d",
__FUNCTION__, newState, triggerId);
- typename SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
- if (l.mRemoteCallback != 0) {
- l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS_MOVE, 1, 0);
- }
- if (l.mRemoteCallback != 0) {
- l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS, 1, 0);
- }
}
template <typename TClientBase>
@@ -325,5 +326,6 @@ void Camera2ClientBase<TClientBase>::SharedCameraCallbacks::clear() {
template class Camera2ClientBase<CameraService::ProClient>;
template class Camera2ClientBase<CameraService::Client>;
+template class Camera2ClientBase<CameraDeviceClientBase>;
} // namespace android
diff --git a/services/camera/libcameraservice/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 9001efb..61e44f0 100644
--- a/services/camera/libcameraservice/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
-#include "CameraDeviceBase.h"
-#include "CameraService.h"
+#include "common/CameraDeviceBase.h"
namespace android {
class IMemory;
+class CameraService;
+
template <typename TClientBase>
class Camera2ClientBase :
public TClientBase,
@@ -61,7 +62,8 @@ public:
*/
virtual void notifyError(int errorCode, int arg1, int arg2);
- virtual void notifyShutter(int frameNumber, nsecs_t timestamp);
+ virtual void notifyIdle();
+ virtual void notifyShutter(int requestId, nsecs_t timestamp);
virtual void notifyAutoFocus(uint8_t newState, int triggerId);
virtual void notifyAutoExposure(uint8_t newState, int triggerId);
virtual void notifyAutoWhitebalance(uint8_t newState,
@@ -101,6 +103,10 @@ public:
protected:
+ virtual sp<IBinder> asBinderWrapper() {
+ return IInterface::asBinder();
+ }
+
virtual status_t dumpDevice(int fd, const Vector<String16>& args);
/** Binder client interface-related private members */
diff --git a/services/camera/libcameraservice/CameraDeviceBase.cpp b/services/camera/libcameraservice/common/CameraDeviceBase.cpp
index 6c4e87f..6c4e87f 100644
--- a/services/camera/libcameraservice/CameraDeviceBase.cpp
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.cpp
diff --git a/services/camera/libcameraservice/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index aa92bec..e80abf1 100644
--- a/services/camera/libcameraservice/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -138,9 +138,18 @@ class CameraDeviceBase : public virtual RefBase {
*/
class NotificationListener {
public:
- // Refer to the Camera2 HAL definition for notification definitions
+ // The set of notifications is a merge of the notifications required for
+ // API1 and API2.
+
+ // Required for API 1 and 2
virtual void notifyError(int errorCode, int arg1, int arg2) = 0;
- virtual void notifyShutter(int frameNumber, nsecs_t timestamp) = 0;
+
+ // Required only for API2
+ virtual void notifyIdle() = 0;
+ virtual void notifyShutter(int requestId,
+ nsecs_t timestamp) = 0;
+
+ // Required only for API1
virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoExposure(uint8_t newState, int triggerId) = 0;
virtual void notifyAutoWhitebalance(uint8_t newState,
@@ -165,12 +174,14 @@ class CameraDeviceBase : public virtual RefBase {
/**
* Wait for a new frame to be produced, with timeout in nanoseconds.
* Returns TIMED_OUT when no frame produced within the specified duration
+ * May be called concurrently to most methods, except for getNextFrame
*/
virtual status_t waitForNextFrame(nsecs_t timeout) = 0;
/**
* Get next metadata frame from the frame queue. Returns NULL if the queue
* is empty; caller takes ownership of the metadata buffer.
+ * May be called concurrently to most methods, except for waitForNextFrame
*/
virtual status_t getNextFrame(CameraMetadata *frame) = 0;
@@ -209,6 +220,13 @@ class CameraDeviceBase : public virtual RefBase {
*/
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener) = 0;
+
+ /**
+ * Flush all pending and in-flight requests. Blocks until flush is
+ * complete.
+ */
+ virtual status_t flush() = 0;
+
};
}; // namespace android
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 4012fc5..52906ee 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -14,29 +14,29 @@
* limitations under the License.
*/
-#define LOG_TAG "Camera2-ProFrameProcessor"
+#define LOG_TAG "Camera2-FrameProcessorBase"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <utils/Trace.h>
-#include "ProFrameProcessor.h"
-#include "../CameraDeviceBase.h"
+#include "common/FrameProcessorBase.h"
+#include "common/CameraDeviceBase.h"
namespace android {
namespace camera2 {
-ProFrameProcessor::ProFrameProcessor(wp<CameraDeviceBase> device) :
+FrameProcessorBase::FrameProcessorBase(wp<CameraDeviceBase> device) :
Thread(/*canCallJava*/false),
mDevice(device) {
}
-ProFrameProcessor::~ProFrameProcessor() {
+FrameProcessorBase::~FrameProcessorBase() {
ALOGV("%s: Exit", __FUNCTION__);
}
-status_t ProFrameProcessor::registerListener(int32_t minId,
+status_t FrameProcessorBase::registerListener(int32_t minId,
int32_t maxId, wp<FilteredListener> listener) {
Mutex::Autolock l(mInputMutex);
ALOGV("%s: Registering listener for frame id range %d - %d",
@@ -46,7 +46,7 @@ status_t ProFrameProcessor::registerListener(int32_t minId,
return OK;
}
-status_t ProFrameProcessor::removeListener(int32_t minId,
+status_t FrameProcessorBase::removeListener(int32_t minId,
int32_t maxId,
wp<FilteredListener> listener) {
Mutex::Autolock l(mInputMutex);
@@ -63,13 +63,20 @@ status_t ProFrameProcessor::removeListener(int32_t minId,
return OK;
}
-void ProFrameProcessor::dump(int fd, const Vector<String16>& /*args*/) {
+void FrameProcessorBase::dump(int fd, const Vector<String16>& /*args*/) {
String8 result(" Latest received frame:\n");
write(fd, result.string(), result.size());
- mLastFrame.dump(fd, 2, 6);
+
+ CameraMetadata lastFrame;
+ {
+ // Don't race while dumping metadata
+ Mutex::Autolock al(mLastFrameMutex);
+ lastFrame = CameraMetadata(mLastFrame);
+ }
+ lastFrame.dump(fd, 2, 6);
}
-bool ProFrameProcessor::threadLoop() {
+bool FrameProcessorBase::threadLoop() {
status_t res;
sp<CameraDeviceBase> device;
@@ -82,14 +89,14 @@ bool ProFrameProcessor::threadLoop() {
if (res == OK) {
processNewFrames(device);
} else if (res != TIMED_OUT) {
- ALOGE("ProFrameProcessor: Error waiting for new "
+ ALOGE("FrameProcessorBase: Error waiting for new "
"frames: %s (%d)", strerror(-res), res);
}
return true;
}
-void ProFrameProcessor::processNewFrames(const sp<CameraDeviceBase> &device) {
+void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) {
status_t res;
ATRACE_CALL();
CameraMetadata frame;
@@ -113,6 +120,7 @@ void ProFrameProcessor::processNewFrames(const sp<CameraDeviceBase> &device) {
}
if (!frame.isEmpty()) {
+ Mutex::Autolock al(mLastFrameMutex);
mLastFrame.acquire(frame);
}
}
@@ -125,14 +133,14 @@ void ProFrameProcessor::processNewFrames(const sp<CameraDeviceBase> &device) {
return;
}
-bool ProFrameProcessor::processSingleFrame(CameraMetadata &frame,
+bool FrameProcessorBase::processSingleFrame(CameraMetadata &frame,
const sp<CameraDeviceBase> &device) {
ALOGV("%s: Camera %d: Process single frame (is empty? %d)",
__FUNCTION__, device->getId(), frame.isEmpty());
return processListeners(frame, device) == OK;
}
-status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
+status_t FrameProcessorBase::processListeners(const CameraMetadata &frame,
const sp<CameraDeviceBase> &device) {
ATRACE_CALL();
camera_metadata_ro_entry_t entry;
@@ -143,7 +151,7 @@ status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
__FUNCTION__, device->getId());
return BAD_VALUE;
}
- int32_t frameId = entry.data.i32[0];
+ int32_t requestId = entry.data.i32[0];
List<sp<FilteredListener> > listeners;
{
@@ -151,8 +159,8 @@ status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
List<RangeListener>::iterator item = mRangeListeners.begin();
while (item != mRangeListeners.end()) {
- if (frameId >= item->minId &&
- frameId < item->maxId) {
+ if (requestId >= item->minId &&
+ requestId < item->maxId) {
sp<FilteredListener> listener = item->listener.promote();
if (listener == 0) {
item = mRangeListeners.erase(item);
@@ -167,7 +175,7 @@ status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
ALOGV("Got %d range listeners out of %d", listeners.size(), mRangeListeners.size());
List<sp<FilteredListener> >::iterator item = listeners.begin();
for (; item != listeners.end(); item++) {
- (*item)->onFrameAvailable(frameId, frame);
+ (*item)->onFrameAvailable(requestId, frame);
}
return OK;
}
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.h b/services/camera/libcameraservice/common/FrameProcessorBase.h
index b82942c..4d80ebf 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.h
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.h
@@ -33,13 +33,13 @@ namespace camera2 {
/* Output frame metadata processing thread. This thread waits for new
* frames from the device, and analyzes them as necessary.
*/
-class ProFrameProcessor: public Thread {
+class FrameProcessorBase: public Thread {
public:
- ProFrameProcessor(wp<CameraDeviceBase> device);
- virtual ~ProFrameProcessor();
+ FrameProcessorBase(wp<CameraDeviceBase> device);
+ virtual ~FrameProcessorBase();
struct FilteredListener: virtual public RefBase {
- virtual void onFrameAvailable(int32_t frameId,
+ virtual void onFrameAvailable(int32_t requestId,
const CameraMetadata &frame) = 0;
};
@@ -58,6 +58,7 @@ class ProFrameProcessor: public Thread {
virtual bool threadLoop();
Mutex mInputMutex;
+ Mutex mLastFrameMutex;
struct RangeListener {
int32_t minId;
diff --git a/services/camera/libcameraservice/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 87b2807..87b2807 100644
--- a/services/camera/libcameraservice/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index 710d0e9..2bc1a8a 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -464,8 +464,10 @@ void Camera2Device::notificationCallback(int32_t msg_type,
listener->notifyError(ext1, ext2, ext3);
break;
case CAMERA2_MSG_SHUTTER: {
- nsecs_t timestamp = (nsecs_t)ext2 | ((nsecs_t)(ext3) << 32 );
- listener->notifyShutter(ext1, timestamp);
+ // TODO: Only needed for camera2 API, which is unsupported
+ // by HAL2 directly.
+ // nsecs_t timestamp = (nsecs_t)ext2 | ((nsecs_t)(ext3) << 32 );
+ // listener->notifyShutter(requestId, timestamp);
break;
}
case CAMERA2_MSG_AUTOFOCUS:
@@ -567,6 +569,13 @@ status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId,
return res;
}
+status_t Camera2Device::flush() {
+ ATRACE_CALL();
+
+ mRequestQueue.clear();
+ return waitUntilDrained();
+}
+
/**
* Camera2Device::MetadataQueue
*/
@@ -591,9 +600,7 @@ Camera2Device::MetadataQueue::MetadataQueue():
Camera2Device::MetadataQueue::~MetadataQueue() {
ATRACE_CALL();
- Mutex::Autolock l(mMutex);
- freeBuffers(mEntries.begin(), mEntries.end());
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+ clear();
}
// Connect to camera2 HAL as consumer (input requests/reprocessing)
@@ -784,6 +791,23 @@ status_t Camera2Device::MetadataQueue::setStreamSlot(
return signalConsumerLocked();
}
+status_t Camera2Device::MetadataQueue::clear()
+{
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+
+ Mutex::Autolock l(mMutex);
+
+ // Clear streaming slot
+ freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
+ mStreamSlotCount = 0;
+
+ // Clear request queue
+ freeBuffers(mEntries.begin(), mEntries.end());
+ mCount = 0;
+ return OK;
+}
+
status_t Camera2Device::MetadataQueue::dump(int fd,
const Vector<String16>& /*args*/) {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 372ce9f..1f53c56 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -22,12 +22,16 @@
#include <utils/List.h>
#include <utils/Mutex.h>
-#include "CameraDeviceBase.h"
+#include "common/CameraDeviceBase.h"
namespace android {
/**
* CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_2_0
+ *
+ * TODO for camera2 API implementation:
+ * Does not produce notifyShutter / notifyIdle callbacks to NotificationListener
+ * Use waitUntilDrained for idle.
*/
class Camera2Device: public CameraDeviceBase {
public:
@@ -67,6 +71,8 @@ class Camera2Device: public CameraDeviceBase {
virtual status_t triggerPrecaptureMetering(uint32_t id);
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
+ // Flush implemented as just a wait
+ virtual status_t flush();
private:
const int mId;
camera2_device_t *mHal2Device;
@@ -113,6 +119,9 @@ class Camera2Device: public CameraDeviceBase {
status_t setStreamSlot(camera_metadata_t *buf);
status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
+ // Clear the request queue and the streaming slot
+ status_t clear();
+
status_t dump(int fd, const Vector<String16>& args);
private:
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 353fe74..6f2dc85 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -40,9 +40,11 @@
#include <utils/Log.h>
#include <utils/Trace.h>
#include <utils/Timers.h>
-#include "Camera3Device.h"
-#include "camera3/Camera3OutputStream.h"
-#include "camera3/Camera3InputStream.h"
+
+#include "device3/Camera3Device.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3ZslStream.h"
using namespace android::camera3;
@@ -80,6 +82,7 @@ int Camera3Device::getId() const {
status_t Camera3Device::initialize(camera_module_t *module)
{
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
@@ -128,7 +131,10 @@ status_t Camera3Device::initialize(camera_module_t *module)
/** Initialize device with callback functions */
+ ATRACE_BEGIN("camera3->initialize");
res = device->ops->initialize(device, this);
+ ATRACE_END();
+
if (res != OK) {
SET_ERR_L("Unable to initialize HAL device: %s (%d)",
strerror(-res), res);
@@ -140,7 +146,9 @@ status_t Camera3Device::initialize(camera_module_t *module)
mVendorTagOps.get_camera_vendor_section_name = NULL;
+ ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
+ ATRACE_END();
if (mVendorTagOps.get_camera_vendor_section_name != NULL) {
res = set_camera_metadata_vendor_tag_ops(&mVendorTagOps);
@@ -152,9 +160,20 @@ status_t Camera3Device::initialize(camera_module_t *module)
}
}
+ /** Start up status tracker thread */
+ mStatusTracker = new StatusTracker(this);
+ res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());
+ if (res != OK) {
+ SET_ERR_L("Unable to start status tracking thread: %s (%d)",
+ strerror(-res), res);
+ device->common.close(&device->common);
+ mStatusTracker.clear();
+ return res;
+ }
+
/** Start up request queue thread */
- mRequestThread = new RequestThread(this, device);
+ mRequestThread = new RequestThread(this, mStatusTracker, device);
res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());
if (res != OK) {
SET_ERR_L("Unable to start request queue thread: %s (%d)",
@@ -168,81 +187,130 @@ status_t Camera3Device::initialize(camera_module_t *module)
mDeviceInfo = info.static_camera_characteristics;
mHal3Device = device;
- mStatus = STATUS_IDLE;
+ mStatus = STATUS_UNCONFIGURED;
mNextStreamId = 0;
mNeedConfig = true;
+ mPauseStateNotify = false;
return OK;
}
status_t Camera3Device::disconnect() {
ATRACE_CALL();
- Mutex::Autolock l(mLock);
+ Mutex::Autolock il(mInterfaceLock);
ALOGV("%s: E", __FUNCTION__);
status_t res = OK;
- if (mStatus == STATUS_UNINITIALIZED) return res;
- if (mStatus == STATUS_ACTIVE ||
- (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
- res = mRequestThread->clearRepeatingRequests();
- if (res != OK) {
- SET_ERR_L("Can't stop streaming");
- // Continue to close device even in case of error
- } else {
- res = waitUntilDrainedLocked();
+ {
+ Mutex::Autolock l(mLock);
+ if (mStatus == STATUS_UNINITIALIZED) return res;
+
+ if (mStatus == STATUS_ACTIVE ||
+ (mStatus == STATUS_ERROR && mRequestThread != NULL)) {
+ res = mRequestThread->clearRepeatingRequests();
if (res != OK) {
- SET_ERR_L("Timeout waiting for HAL to drain");
+ SET_ERR_L("Can't stop streaming");
// Continue to close device even in case of error
+ } else {
+ res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+ if (res != OK) {
+ SET_ERR_L("Timeout waiting for HAL to drain");
+ // Continue to close device even in case of error
+ }
}
}
+
+ if (mStatus == STATUS_ERROR) {
+ CLOGE("Shutting down in an error state");
+ }
+
+ if (mStatusTracker != NULL) {
+ mStatusTracker->requestExit();
+ }
+
+ if (mRequestThread != NULL) {
+ mRequestThread->requestExit();
+ }
+
+ mOutputStreams.clear();
+ mInputStream.clear();
}
- assert(mStatus == STATUS_IDLE || mStatus == STATUS_ERROR);
- if (mStatus == STATUS_ERROR) {
- CLOGE("Shutting down in an error state");
+ // Joining done without holding mLock, otherwise deadlocks may ensue
+ // as the threads try to access parent state
+ if (mRequestThread != NULL && mStatus != STATUS_ERROR) {
+ // HAL may be in a bad state, so waiting for request thread
+ // (which may be stuck in the HAL processCaptureRequest call)
+ // could be dangerous.
+ mRequestThread->join();
}
- if (mRequestThread != NULL) {
- mRequestThread->requestExit();
+ if (mStatusTracker != NULL) {
+ mStatusTracker->join();
}
- mOutputStreams.clear();
- mInputStream.clear();
+ {
+ Mutex::Autolock l(mLock);
- if (mRequestThread != NULL) {
- if (mStatus != STATUS_ERROR) {
- // HAL may be in a bad state, so waiting for request thread
- // (which may be stuck in the HAL processCaptureRequest call)
- // could be dangerous.
- mRequestThread->join();
- }
mRequestThread.clear();
- }
+ mStatusTracker.clear();
- if (mHal3Device != NULL) {
- mHal3Device->common.close(&mHal3Device->common);
- mHal3Device = NULL;
- }
+ if (mHal3Device != NULL) {
+ mHal3Device->common.close(&mHal3Device->common);
+ mHal3Device = NULL;
+ }
- mStatus = STATUS_UNINITIALIZED;
+ mStatus = STATUS_UNINITIALIZED;
+ }
ALOGV("%s: X", __FUNCTION__);
return res;
}
+// For dumping/debugging only -
+// try to acquire a lock a few times, eventually give up to proceed with
+// debug/dump operations
+bool Camera3Device::tryLockSpinRightRound(Mutex& lock) {
+ bool gotLock = false;
+ for (size_t i = 0; i < kDumpLockAttempts; ++i) {
+ if (lock.tryLock() == NO_ERROR) {
+ gotLock = true;
+ break;
+ } else {
+ usleep(kDumpSleepDuration);
+ }
+ }
+ return gotLock;
+}
+
status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
ATRACE_CALL();
(void)args;
+
+ // Try to lock, but continue in case of failure (to avoid blocking in
+ // deadlocks)
+ bool gotInterfaceLock = tryLockSpinRightRound(mInterfaceLock);
+ bool gotLock = tryLockSpinRightRound(mLock);
+
+ ALOGW_IF(!gotInterfaceLock,
+ "Camera %d: %s: Unable to lock interface lock, proceeding anyway",
+ mId, __FUNCTION__);
+ ALOGW_IF(!gotLock,
+ "Camera %d: %s: Unable to lock main lock, proceeding anyway",
+ mId, __FUNCTION__);
+
String8 lines;
const char *status =
mStatus == STATUS_ERROR ? "ERROR" :
mStatus == STATUS_UNINITIALIZED ? "UNINITIALIZED" :
- mStatus == STATUS_IDLE ? "IDLE" :
+ mStatus == STATUS_UNCONFIGURED ? "UNCONFIGURED" :
+ mStatus == STATUS_CONFIGURED ? "CONFIGURED" :
mStatus == STATUS_ACTIVE ? "ACTIVE" :
"Unknown";
+
lines.appendFormat(" Device status: %s\n", status);
if (mStatus == STATUS_ERROR) {
lines.appendFormat(" Error cause: %s\n", mErrorCause.string());
@@ -274,12 +342,23 @@ status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
}
write(fd, lines.string(), lines.size());
+ {
+ lines = String8(" Last request sent:\n");
+ write(fd, lines.string(), lines.size());
+
+ CameraMetadata lastRequest = getLatestRequestLocked();
+ lastRequest.dump(fd, /*verbosity*/2, /*indentation*/6);
+ }
+
if (mHal3Device != NULL) {
lines = String8(" HAL device dump:\n");
write(fd, lines.string(), lines.size());
mHal3Device->ops->dump(mHal3Device, fd);
}
+ if (gotLock) mLock.unlock();
+ if (gotInterfaceLock) mInterfaceLock.unlock();
+
return OK;
}
@@ -296,6 +375,8 @@ const CameraMetadata& Camera3Device::info() const {
status_t Camera3Device::capture(CameraMetadata &request) {
ATRACE_CALL();
+ status_t res;
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
// TODO: take ownership of the request
@@ -307,7 +388,9 @@ status_t Camera3Device::capture(CameraMetadata &request) {
case STATUS_UNINITIALIZED:
CLOGE("Device not initialized");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ // May be lazily configuring streams, will check during setup
+ case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
break;
@@ -322,12 +405,23 @@ status_t Camera3Device::capture(CameraMetadata &request) {
return BAD_VALUE;
}
- return mRequestThread->queueRequest(newRequest);
+ res = mRequestThread->queueRequest(newRequest);
+ if (res == OK) {
+ waitUntilStateThenRelock(/*active*/ true, kActiveTimeout);
+ if (res != OK) {
+ SET_ERR_L("Can't transition to active in %f seconds!",
+ kActiveTimeout/1e9);
+ }
+ ALOGV("Camera %d: Capture request enqueued", mId);
+ }
+ return res;
}
status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
ATRACE_CALL();
+ status_t res;
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
switch (mStatus) {
@@ -337,7 +431,9 @@ status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
case STATUS_UNINITIALIZED:
CLOGE("Device not initialized");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ // May be lazily configuring streams, will check during setup
+ case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
break;
@@ -355,7 +451,16 @@ status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
RequestList newRepeatingRequests;
newRepeatingRequests.push_back(newRepeatingRequest);
- return mRequestThread->setRepeatingRequests(newRepeatingRequests);
+ res = mRequestThread->setRepeatingRequests(newRepeatingRequests);
+ if (res == OK) {
+ waitUntilStateThenRelock(/*active*/ true, kActiveTimeout);
+ if (res != OK) {
+ SET_ERR_L("Can't transition to active in %f seconds!",
+ kActiveTimeout/1e9);
+ }
+ ALOGV("Camera %d: Repeating request set", mId);
+ }
+ return res;
}
@@ -363,12 +468,16 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
const CameraMetadata &request) {
status_t res;
- if (mStatus == STATUS_IDLE) {
+ if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) {
res = configureStreamsLocked();
if (res != OK) {
SET_ERR_L("Can't set up streams: %s (%d)", strerror(-res), res);
return NULL;
}
+ if (mStatus == STATUS_UNCONFIGURED) {
+ CLOGE("No streams configured");
+ return NULL;
+ }
}
sp<CaptureRequest> newRequest = createCaptureRequest(request);
@@ -377,6 +486,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
status_t Camera3Device::clearStreamingRequest() {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
switch (mStatus) {
@@ -386,7 +496,8 @@ status_t Camera3Device::clearStreamingRequest() {
case STATUS_UNINITIALIZED:
CLOGE("Device not initialized");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
break;
@@ -394,12 +505,13 @@ status_t Camera3Device::clearStreamingRequest() {
SET_ERR_L("Unexpected status: %d", mStatus);
return INVALID_OPERATION;
}
-
+ ALOGV("Camera %d: Clearing repeating request", mId);
return mRequestThread->clearRepeatingRequests();
}
status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
return mRequestThread->waitUntilRequestProcessed(requestId, timeout);
}
@@ -407,7 +519,10 @@ status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t time
status_t Camera3Device::createInputStream(
uint32_t width, uint32_t height, int format, int *id) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
+ ALOGV("Camera %d: Creating new input stream %d: %d x %d, format %d",
+ mId, mNextStreamId, width, height, format);
status_t res;
bool wasActive = false;
@@ -419,26 +534,24 @@ status_t Camera3Device::createInputStream(
case STATUS_UNINITIALIZED:
ALOGE("%s: Device not initialized", __FUNCTION__);
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
// OK
break;
case STATUS_ACTIVE:
ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
- mRequestThread->setPaused(true);
- res = waitUntilDrainedLocked();
+ res = internalPauseAndWaitLocked();
if (res != OK) {
- ALOGE("%s: Can't pause captures to reconfigure streams!",
- __FUNCTION__);
- mStatus = STATUS_ERROR;
+ SET_ERR_L("Can't pause captures to reconfigure streams!");
return res;
}
wasActive = true;
break;
default:
- ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ SET_ERR_L("%s: Unexpected status: %d", mStatus);
return INVALID_OPERATION;
}
- assert(mStatus == STATUS_IDLE);
+ assert(mStatus != STATUS_ACTIVE);
if (mInputStream != 0) {
ALOGE("%s: Cannot create more than 1 input stream", __FUNCTION__);
@@ -447,6 +560,7 @@ status_t Camera3Device::createInputStream(
sp<Camera3InputStream> newStream = new Camera3InputStream(mNextStreamId,
width, height, format);
+ newStream->setStatusTracker(mStatusTracker);
mInputStream = newStream;
@@ -461,9 +575,10 @@ status_t Camera3Device::createInputStream(
__FUNCTION__, mNextStreamId, strerror(-res), res);
return res;
}
- mRequestThread->setPaused(false);
+ internalResumeLocked();
}
+ ALOGV("Camera %d: Created input stream", mId);
return OK;
}
@@ -475,7 +590,10 @@ status_t Camera3Device::createZslStream(
int *id,
sp<Camera3ZslStream>* zslStream) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
+ ALOGV("Camera %d: Creating ZSL stream %d: %d x %d, depth %d",
+ mId, mNextStreamId, width, height, depth);
status_t res;
bool wasActive = false;
@@ -487,26 +605,24 @@ status_t Camera3Device::createZslStream(
case STATUS_UNINITIALIZED:
ALOGE("%s: Device not initialized", __FUNCTION__);
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
// OK
break;
case STATUS_ACTIVE:
ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
- mRequestThread->setPaused(true);
- res = waitUntilDrainedLocked();
+ res = internalPauseAndWaitLocked();
if (res != OK) {
- ALOGE("%s: Can't pause captures to reconfigure streams!",
- __FUNCTION__);
- mStatus = STATUS_ERROR;
+ SET_ERR_L("Can't pause captures to reconfigure streams!");
return res;
}
wasActive = true;
break;
default:
- ALOGE("%s: Unexpected status: %d", __FUNCTION__, mStatus);
+ SET_ERR_L("Unexpected status: %d", mStatus);
return INVALID_OPERATION;
}
- assert(mStatus == STATUS_IDLE);
+ assert(mStatus != STATUS_ACTIVE);
if (mInputStream != 0) {
ALOGE("%s: Cannot create more than 1 input stream", __FUNCTION__);
@@ -515,6 +631,7 @@ status_t Camera3Device::createZslStream(
sp<Camera3ZslStream> newStream = new Camera3ZslStream(mNextStreamId,
width, height, depth);
+ newStream->setStatusTracker(mStatusTracker);
res = mOutputStreams.add(mNextStreamId, newStream);
if (res < 0) {
@@ -536,16 +653,20 @@ status_t Camera3Device::createZslStream(
__FUNCTION__, mNextStreamId, strerror(-res), res);
return res;
}
- mRequestThread->setPaused(false);
+ internalResumeLocked();
}
+ ALOGV("Camera %d: Created ZSL stream", mId);
return OK;
}
status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
uint32_t width, uint32_t height, int format, size_t size, int *id) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
+ ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, size %d",
+ mId, mNextStreamId, width, height, format, size);
status_t res;
bool wasActive = false;
@@ -557,16 +678,15 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
case STATUS_UNINITIALIZED:
CLOGE("Device not initialized");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
// OK
break;
case STATUS_ACTIVE:
ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
- mRequestThread->setPaused(true);
- res = waitUntilDrainedLocked();
+ res = internalPauseAndWaitLocked();
if (res != OK) {
- ALOGE("%s: Can't pause captures to reconfigure streams!",
- __FUNCTION__);
+ SET_ERR_L("Can't pause captures to reconfigure streams!");
return res;
}
wasActive = true;
@@ -575,7 +695,7 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
SET_ERR_L("Unexpected status: %d", mStatus);
return INVALID_OPERATION;
}
- assert(mStatus == STATUS_IDLE);
+ assert(mStatus != STATUS_ACTIVE);
sp<Camera3OutputStream> newStream;
if (format == HAL_PIXEL_FORMAT_BLOB) {
@@ -585,6 +705,7 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, format);
}
+ newStream->setStatusTracker(mStatusTracker);
res = mOutputStreams.add(mNextStreamId, newStream);
if (res < 0) {
@@ -604,9 +725,9 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
mNextStreamId, strerror(-res), res);
return res;
}
- mRequestThread->setPaused(false);
+ internalResumeLocked();
}
-
+ ALOGV("Camera %d: Created new stream", mId);
return OK;
}
@@ -622,6 +743,7 @@ status_t Camera3Device::createReprocessStreamFromStream(int outputId, int *id) {
status_t Camera3Device::getStreamInfo(int id,
uint32_t *width, uint32_t *height, uint32_t *format) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
switch (mStatus) {
@@ -631,7 +753,8 @@ status_t Camera3Device::getStreamInfo(int id,
case STATUS_UNINITIALIZED:
CLOGE("Device not initialized!");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
break;
@@ -656,6 +779,7 @@ status_t Camera3Device::getStreamInfo(int id,
status_t Camera3Device::setStreamTransform(int id,
int transform) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
switch (mStatus) {
@@ -665,7 +789,8 @@ status_t Camera3Device::setStreamTransform(int id,
case STATUS_UNINITIALIZED:
CLOGE("Device not initialized");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
break;
@@ -686,6 +811,7 @@ status_t Camera3Device::setStreamTransform(int id,
status_t Camera3Device::deleteStream(int id) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
status_t res;
@@ -693,7 +819,7 @@ status_t Camera3Device::deleteStream(int id) {
// CameraDevice semantics require device to already be idle before
// deleteStream is called, unlike for createStream.
- if (mStatus != STATUS_IDLE) {
+ if (mStatus == STATUS_ACTIVE) {
ALOGV("%s: Camera %d: Device not idle", __FUNCTION__, mId);
return -EBUSY;
}
@@ -736,7 +862,8 @@ status_t Camera3Device::deleteReprocessStream(int id) {
status_t Camera3Device::createDefaultRequest(int templateId,
CameraMetadata *request) {
ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
+ ALOGV("%s: for template %d", __FUNCTION__, templateId);
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
switch (mStatus) {
@@ -746,7 +873,8 @@ status_t Camera3Device::createDefaultRequest(int templateId,
case STATUS_UNINITIALIZED:
CLOGE("Device is not initialized!");
return INVALID_OPERATION;
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
+ case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
break;
@@ -756,8 +884,10 @@ status_t Camera3Device::createDefaultRequest(int templateId,
}
const camera_metadata_t *rawRequest;
+ ATRACE_BEGIN("camera3->construct_default_request_settings");
rawRequest = mHal3Device->ops->construct_default_request_settings(
mHal3Device, templateId);
+ ATRACE_END();
if (rawRequest == NULL) {
SET_ERR_L("HAL is unable to construct default settings for template %d",
templateId);
@@ -770,61 +900,88 @@ status_t Camera3Device::createDefaultRequest(int templateId,
status_t Camera3Device::waitUntilDrained() {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
- return waitUntilDrainedLocked();
-}
-
-status_t Camera3Device::waitUntilDrainedLocked() {
- ATRACE_CALL();
- status_t res;
-
switch (mStatus) {
case STATUS_UNINITIALIZED:
- case STATUS_IDLE:
+ case STATUS_UNCONFIGURED:
ALOGV("%s: Already idle", __FUNCTION__);
return OK;
+ case STATUS_CONFIGURED:
+ // To avoid race conditions, check with tracker to be sure
case STATUS_ERROR:
case STATUS_ACTIVE:
- // Need to shut down
+ // Need to verify shut down
break;
default:
SET_ERR_L("Unexpected status: %d",mStatus);
return INVALID_OPERATION;
}
- if (mRequestThread != NULL) {
- res = mRequestThread->waitUntilPaused(kShutdownTimeout);
- if (res != OK) {
- SET_ERR_L("Can't stop request thread in %f seconds!",
- kShutdownTimeout/1e9);
- return res;
- }
- }
- if (mInputStream != NULL) {
- res = mInputStream->waitUntilIdle(kShutdownTimeout);
- if (res != OK) {
- SET_ERR_L("Can't idle input stream %d in %f seconds!",
- mInputStream->getId(), kShutdownTimeout/1e9);
- return res;
- }
+ ALOGV("%s: Camera %d: Waiting until idle", __FUNCTION__, mId);
+ status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+ return res;
+}
+
+// Pause to reconfigure
+status_t Camera3Device::internalPauseAndWaitLocked() {
+ mRequestThread->setPaused(true);
+ mPauseStateNotify = true;
+
+ ALOGV("%s: Camera %d: Internal wait until idle", __FUNCTION__, mId);
+ status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+ if (res != OK) {
+ SET_ERR_L("Can't idle device in %f seconds!",
+ kShutdownTimeout/1e9);
}
- for (size_t i = 0; i < mOutputStreams.size(); i++) {
- res = mOutputStreams.editValueAt(i)->waitUntilIdle(kShutdownTimeout);
- if (res != OK) {
- SET_ERR_L("Can't idle output stream %d in %f seconds!",
- mOutputStreams.keyAt(i), kShutdownTimeout/1e9);
- return res;
- }
+
+ return res;
+}
+
+// Resume after internalPauseAndWaitLocked
+status_t Camera3Device::internalResumeLocked() {
+ status_t res;
+
+ mRequestThread->setPaused(false);
+
+ res = waitUntilStateThenRelock(/*active*/ true, kActiveTimeout);
+ if (res != OK) {
+ SET_ERR_L("Can't transition to active in %f seconds!",
+ kActiveTimeout/1e9);
}
+ mPauseStateNotify = false;
+ return OK;
+}
- if (mStatus != STATUS_ERROR) {
- mStatus = STATUS_IDLE;
+status_t Camera3Device::waitUntilStateThenRelock(bool active,
+ nsecs_t timeout) {
+ status_t res = OK;
+ if (active == (mStatus == STATUS_ACTIVE)) {
+ // Desired state already reached
+ return res;
}
- return OK;
+ bool stateSeen = false;
+ do {
+ mRecentStatusUpdates.clear();
+
+ res = mStatusChanged.waitRelative(mLock, timeout);
+ if (res != OK) break;
+
+ // Check state change history during wait
+ for (size_t i = 0; i < mRecentStatusUpdates.size(); i++) {
+ if (active == (mRecentStatusUpdates[i] == STATUS_ACTIVE) ) {
+ stateSeen = true;
+ break;
+ }
+ }
+ } while (!stateSeen);
+
+ return res;
}
+
status_t Camera3Device::setNotifyCallback(NotificationListener *listener) {
ATRACE_CALL();
Mutex::Autolock l(mOutputLock);
@@ -842,7 +999,6 @@ bool Camera3Device::willNotify3A() {
}
status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
- ATRACE_CALL();
status_t res;
Mutex::Autolock l(mOutputLock);
@@ -876,6 +1032,7 @@ status_t Camera3Device::getNextFrame(CameraMetadata *frame) {
status_t Camera3Device::triggerAutofocus(uint32_t id) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
// Mix-in this trigger into the next request and only the next request.
@@ -896,6 +1053,7 @@ status_t Camera3Device::triggerAutofocus(uint32_t id) {
status_t Camera3Device::triggerCancelAutofocus(uint32_t id) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
ALOGV("%s: Triggering cancel autofocus, id %d", __FUNCTION__, id);
// Mix-in this trigger into the next request and only the next request.
@@ -916,6 +1074,7 @@ status_t Camera3Device::triggerCancelAutofocus(uint32_t id) {
status_t Camera3Device::triggerPrecaptureMetering(uint32_t id) {
ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id);
// Mix-in this trigger into the next request and only the next request.
@@ -943,6 +1102,51 @@ status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId,
return INVALID_OPERATION;
}
+status_t Camera3Device::flush() {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: Flushing all requests", __FUNCTION__, mId);
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ mRequestThread->clear();
+ return mHal3Device->ops->flush(mHal3Device);
+}
+
+/**
+ * Methods called by subclasses
+ */
+
+void Camera3Device::notifyStatus(bool idle) {
+ {
+ // Need mLock to safely update state and synchronize to current
+ // state of methods in flight.
+ Mutex::Autolock l(mLock);
+ // We can get various system-idle notices from the status tracker
+ // while starting up. Only care about them if we've actually sent
+ // in some requests recently.
+ if (mStatus != STATUS_ACTIVE && mStatus != STATUS_CONFIGURED) {
+ return;
+ }
+ ALOGV("%s: Camera %d: Now %s", __FUNCTION__, mId,
+ idle ? "idle" : "active");
+ mStatus = idle ? STATUS_CONFIGURED : STATUS_ACTIVE;
+ mRecentStatusUpdates.add(mStatus);
+ mStatusChanged.signal();
+
+ // Skip notifying listener if we're doing some user-transparent
+ // state changes
+ if (mPauseStateNotify) return;
+ }
+ NotificationListener *listener;
+ {
+ Mutex::Autolock l(mOutputLock);
+ listener = mListener;
+ }
+ if (idle && listener != NULL) {
+ listener->notifyIdle();
+ }
+}
+
/**
* Camera3Device private methods
*/
@@ -959,7 +1163,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest(
newRequest->mSettings.find(ANDROID_REQUEST_INPUT_STREAMS);
if (inputStreams.count > 0) {
if (mInputStream == NULL ||
- mInputStream->getId() != inputStreams.data.u8[0]) {
+ mInputStream->getId() != inputStreams.data.i32[0]) {
CLOGE("Request references unknown input stream %d",
inputStreams.data.u8[0]);
return NULL;
@@ -988,7 +1192,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::createCaptureRequest(
}
for (size_t i = 0; i < streams.count; i++) {
- int idx = mOutputStreams.indexOfKey(streams.data.u8[i]);
+ int idx = mOutputStreams.indexOfKey(streams.data.i32[i]);
if (idx == NAME_NOT_FOUND) {
CLOGE("Request references unknown stream %d",
streams.data.u8[i]);
@@ -1019,18 +1223,18 @@ status_t Camera3Device::configureStreamsLocked() {
ATRACE_CALL();
status_t res;
- if (mStatus != STATUS_IDLE) {
+ if (mStatus != STATUS_UNCONFIGURED && mStatus != STATUS_CONFIGURED) {
CLOGE("Not idle");
return INVALID_OPERATION;
}
if (!mNeedConfig) {
ALOGV("%s: Skipping config, no stream changes", __FUNCTION__);
- mStatus = STATUS_ACTIVE;
return OK;
}
// Start configuring the streams
+ ALOGV("%s: Camera %d: Starting stream configuration", __FUNCTION__, mId);
camera3_stream_configuration config;
@@ -1072,8 +1276,9 @@ status_t Camera3Device::configureStreamsLocked() {
// Do the HAL configuration; will potentially touch stream
// max_buffers, usage, priv fields.
-
+ ATRACE_BEGIN("camera3->configure_streams");
res = mHal3Device->ops->configure_streams(mHal3Device, &config);
+ ATRACE_END();
if (res != OK) {
SET_ERR_L("Unable to configure streams with HAL: %s (%d)",
@@ -1111,11 +1316,18 @@ status_t Camera3Device::configureStreamsLocked() {
// across configure_streams() calls
mRequestThread->configurationComplete();
- // Finish configuring the streams lazily on first reference
+ // Update device state
- mStatus = STATUS_ACTIVE;
mNeedConfig = false;
+ if (config.num_streams > 0) {
+ mStatus = STATUS_CONFIGURED;
+ } else {
+ mStatus = STATUS_UNCONFIGURED;
+ }
+
+ ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);
+
return OK;
}
@@ -1162,12 +1374,12 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) {
*/
status_t Camera3Device::registerInFlight(int32_t frameNumber,
- int32_t numBuffers) {
+ int32_t requestId, int32_t numBuffers) {
ATRACE_CALL();
Mutex::Autolock l(mInFlightLock);
ssize_t res;
- res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers));
+ res = mInFlightMap.add(frameNumber, InFlightRequest(requestId, numBuffers));
if (res < 0) return res;
return OK;
@@ -1204,7 +1416,12 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
InFlightRequest &request = mInFlightMap.editValueAt(idx);
timestamp = request.captureTimestamp;
- if (timestamp == 0) {
+ /**
+ * One of the following must happen before it's legal to call process_capture_result:
+ * - CAMERA3_MSG_SHUTTER (expected during normal operation)
+ * - CAMERA3_MSG_ERROR (expected during flush)
+ */
+ if (request.requestStatus == OK && timestamp == 0) {
SET_ERR("Called before shutter notify for frame %d",
frameNumber);
return;
@@ -1228,6 +1445,7 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
if (request.haveResultMetadata && request.numBuffersLeft == 0) {
+ ATRACE_ASYNC_END("frame capture", frameNumber);
mInFlightMap.removeItemsAt(idx, 1);
}
@@ -1271,8 +1489,7 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
if (entry.count == 0) {
SET_ERR("No timestamp provided by HAL for frame %d!",
frameNumber);
- }
- if (timestamp != entry.data.i64[0]) {
+ } else if (timestamp != entry.data.i64[0]) {
SET_ERR("Timestamp mismatch between shutter notify and result"
" metadata for frame %d (%lld vs %lld respectively)",
frameNumber, timestamp, entry.data.i64[0]);
@@ -1288,7 +1505,7 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
// Note: stream may be deallocated at this point, if this buffer was the
// last reference to it.
if (res != OK) {
- SET_ERR("Can't return buffer %d for frame %d to its stream: "
+ ALOGE("Can't return buffer %d for frame %d to its stream: "
" %s (%d)", i, frameNumber, strerror(-res), res);
}
}
@@ -1304,6 +1521,7 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
void Camera3Device::notify(const camera3_notify_msg *msg) {
+ ATRACE_CALL();
NotificationListener *listener;
{
Mutex::Autolock l(mOutputLock);
@@ -1324,6 +1542,19 @@ void Camera3Device::notify(const camera3_notify_msg *msg) {
msg->message.error.error_stream);
streamId = stream->getId();
}
+ ALOGV("Camera %d: %s: HAL error, frame %d, stream %d: %d",
+ mId, __FUNCTION__, msg->message.error.frame_number,
+ streamId, msg->message.error.error_code);
+
+ // Set request error status for the request in the in-flight tracking
+ {
+ Mutex::Autolock l(mInFlightLock);
+ ssize_t idx = mInFlightMap.indexOfKey(msg->message.error.frame_number);
+ if (idx >= 0) {
+ mInFlightMap.editValueAt(idx).requestStatus = msg->message.error.error_code;
+ }
+ }
+
if (listener != NULL) {
listener->notifyError(msg->message.error.error_code,
msg->message.error.frame_number, streamId);
@@ -1346,12 +1577,17 @@ void Camera3Device::notify(const camera3_notify_msg *msg) {
mNextShutterFrameNumber++;
}
+ int32_t requestId = -1;
+
// Set timestamp for the request in the in-flight tracking
+ // and get the request ID to send upstream
{
Mutex::Autolock l(mInFlightLock);
idx = mInFlightMap.indexOfKey(frameNumber);
if (idx >= 0) {
- mInFlightMap.editValueAt(idx).captureTimestamp = timestamp;
+ InFlightRequest &r = mInFlightMap.editValueAt(idx);
+ r.captureTimestamp = timestamp;
+ requestId = r.requestId;
}
}
if (idx < 0) {
@@ -1359,10 +1595,11 @@ void Camera3Device::notify(const camera3_notify_msg *msg) {
frameNumber);
break;
}
-
+ ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %lld",
+ mId, __FUNCTION__, frameNumber, requestId, timestamp);
// Call listener, if any
if (listener != NULL) {
- listener->notifyShutter(frameNumber, timestamp);
+ listener->notifyShutter(requestId, timestamp);
}
break;
}
@@ -1372,14 +1609,28 @@ void Camera3Device::notify(const camera3_notify_msg *msg) {
}
}
+CameraMetadata Camera3Device::getLatestRequestLocked() {
+ ALOGV("%s", __FUNCTION__);
+
+ CameraMetadata retVal;
+
+ if (mRequestThread != NULL) {
+ retVal = mRequestThread->getLatestRequest();
+ }
+
+ return retVal;
+}
+
/**
* RequestThread inner class methods
*/
Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
+ sp<StatusTracker> statusTracker,
camera3_device_t *hal3Device) :
Thread(false),
mParent(parent),
+ mStatusTracker(statusTracker),
mHal3Device(hal3Device),
mId(getId(parent)),
mReconfigured(false),
@@ -1387,6 +1638,7 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
mPaused(true),
mFrameNumber(0),
mLatestRequestId(NAME_NOT_FOUND) {
+ mStatusId = statusTracker->addComponent();
}
void Camera3Device::RequestThread::configurationComplete() {
@@ -1399,6 +1651,8 @@ status_t Camera3Device::RequestThread::queueRequest(
Mutex::Autolock l(mRequestLock);
mRequestQueue.push_back(request);
+ unpauseForNewRequests();
+
return OK;
}
@@ -1464,6 +1718,9 @@ status_t Camera3Device::RequestThread::setRepeatingRequests(
mRepeatingRequests.clear();
mRepeatingRequests.insert(mRepeatingRequests.begin(),
requests.begin(), requests.end());
+
+ unpauseForNewRequests();
+
return OK;
}
@@ -1473,24 +1730,20 @@ status_t Camera3Device::RequestThread::clearRepeatingRequests() {
return OK;
}
+status_t Camera3Device::RequestThread::clear() {
+ Mutex::Autolock l(mRequestLock);
+ mRepeatingRequests.clear();
+ mRequestQueue.clear();
+ mTriggerMap.clear();
+ return OK;
+}
+
void Camera3Device::RequestThread::setPaused(bool paused) {
Mutex::Autolock l(mPauseLock);
mDoPause = paused;
mDoPauseSignal.signal();
}
-status_t Camera3Device::RequestThread::waitUntilPaused(nsecs_t timeout) {
- status_t res;
- Mutex::Autolock l(mPauseLock);
- while (!mPaused) {
- res = mPausedSignal.waitRelative(mPauseLock, timeout);
- if (res == TIMED_OUT) {
- return res;
- }
- }
- return OK;
-}
-
status_t Camera3Device::RequestThread::waitUntilRequestProcessed(
int32_t requestId, nsecs_t timeout) {
Mutex::Autolock l(mLatestRequestMutex);
@@ -1507,7 +1760,13 @@ status_t Camera3Device::RequestThread::waitUntilRequestProcessed(
return OK;
}
-
+void Camera3Device::RequestThread::requestExit() {
+ // Call parent to set up shutdown
+ Thread::requestExit();
+ // The exit from any possible waits
+ mDoPauseSignal.signal();
+ mRequestSignal.signal();
+}
bool Camera3Device::RequestThread::threadLoop() {
@@ -1529,6 +1788,18 @@ bool Camera3Device::RequestThread::threadLoop() {
camera3_capture_request_t request = camera3_capture_request_t();
Vector<camera3_stream_buffer_t> outputBuffers;
+ // Get the request ID, if any
+ int requestId;
+ camera_metadata_entry_t requestIdEntry =
+ nextRequest->mSettings.find(ANDROID_REQUEST_ID);
+ if (requestIdEntry.count > 0) {
+ requestId = requestIdEntry.data.i32[0];
+ } else {
+ ALOGW("%s: Did not have android.request.id set in the request",
+ __FUNCTION__);
+ requestId = NAME_NOT_FOUND;
+ }
+
// Insert any queued triggers (before metadata is locked)
int32_t triggerCount;
res = insertTriggers(nextRequest);
@@ -1546,6 +1817,19 @@ bool Camera3Device::RequestThread::threadLoop() {
// If the request is the same as last, or we had triggers last time
if (mPrevRequest != nextRequest || triggersMixedIn) {
/**
+ * HAL workaround:
+ * Insert a dummy trigger ID if a trigger is set but no trigger ID is
+ */
+ res = addDummyTriggerIds(nextRequest);
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
+ "(capture request %d, HAL device: %s (%d)",
+ (mFrameNumber+1), strerror(-res), res);
+ cleanUpFailedRequest(request, nextRequest, outputBuffers);
+ return false;
+ }
+
+ /**
* The request should be presorted so accesses in HAL
* are O(logn). Sidenote, sorting a sorted metadata is nop.
*/
@@ -1582,7 +1866,7 @@ bool Camera3Device::RequestThread::threadLoop() {
request.input_buffer = &inputBuffer;
res = nextRequest->mInputStream->getInputBuffer(&inputBuffer);
if (res != OK) {
- SET_ERR("RequestThread: Can't get input buffer, skipping request:"
+ ALOGE("RequestThread: Can't get input buffer, skipping request:"
" %s (%d)", strerror(-res), res);
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return true;
@@ -1598,8 +1882,8 @@ bool Camera3Device::RequestThread::threadLoop() {
res = nextRequest->mOutputStreams.editItemAt(i)->
getBuffer(&outputBuffers.editItemAt(i));
if (res != OK) {
- SET_ERR("RequestThread: Can't get output buffer, skipping request:"
- "%s (%d)", strerror(-res), res);
+ ALOGE("RequestThread: Can't get output buffer, skipping request:"
+ " %s (%d)", strerror(-res), res);
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return true;
}
@@ -1616,7 +1900,7 @@ bool Camera3Device::RequestThread::threadLoop() {
return false;
}
- res = parent->registerInFlight(request.frame_number,
+ res = parent->registerInFlight(request.frame_number, requestId,
request.num_output_buffers);
if (res != OK) {
SET_ERR("RequestThread: Unable to register new in-flight request:"
@@ -1625,9 +1909,20 @@ bool Camera3Device::RequestThread::threadLoop() {
return false;
}
- // Submit request and block until ready for next one
+ // Inform waitUntilRequestProcessed thread of a new request ID
+ {
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ mLatestRequestId = requestId;
+ mLatestRequestSignal.signal();
+ }
+ // Submit request and block until ready for next one
+ ATRACE_ASYNC_BEGIN("frame capture", request.frame_number);
+ ATRACE_BEGIN("camera3->process_capture_request");
res = mHal3Device->ops->process_capture_request(mHal3Device, &request);
+ ATRACE_END();
+
if (res != OK) {
SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
" device: %s (%d)", request.frame_number, strerror(-res), res);
@@ -1635,6 +1930,14 @@ bool Camera3Device::RequestThread::threadLoop() {
return false;
}
+ // Update the latest request sent to HAL
+ if (request.settings != NULL) { // Don't update them if they were unchanged
+ Mutex::Autolock al(mLatestRequestMutex);
+
+ camera_metadata_t* cloned = clone_camera_metadata(request.settings);
+ mLatestRequest.acquire(cloned);
+ }
+
if (request.settings != NULL) {
nextRequest->mSettings.unlock(request.settings);
}
@@ -1649,24 +1952,6 @@ bool Camera3Device::RequestThread::threadLoop() {
}
mPrevTriggers = triggerCount;
- // Read android.request.id from the request settings metadata
- // - inform waitUntilRequestProcessed thread of a new request ID
- {
- Mutex::Autolock al(mLatestRequestMutex);
-
- camera_metadata_entry_t requestIdEntry =
- nextRequest->mSettings.find(ANDROID_REQUEST_ID);
- if (requestIdEntry.count > 0) {
- mLatestRequestId = requestIdEntry.data.i32[0];
- } else {
- ALOGW("%s: Did not have android.request.id set in the request",
- __FUNCTION__);
- mLatestRequestId = NAME_NOT_FOUND;
- }
-
- mLatestRequestSignal.signal();
- }
-
// Return input buffer back to framework
if (request.input_buffer != NULL) {
Camera3Stream *stream =
@@ -1682,9 +1967,15 @@ bool Camera3Device::RequestThread::threadLoop() {
}
}
+ return true;
+}
+CameraMetadata Camera3Device::RequestThread::getLatestRequest() const {
+ Mutex::Autolock al(mLatestRequestMutex);
- return true;
+ ALOGV("RequestThread::%s", __FUNCTION__);
+
+ return mLatestRequest;
}
void Camera3Device::RequestThread::cleanUpFailedRequest(
@@ -1733,12 +2024,17 @@ sp<Camera3Device::CaptureRequest>
res = mRequestSignal.waitRelative(mRequestLock, kRequestTimeout);
- if (res == TIMED_OUT) {
- // Signal that we're paused by starvation
+ if ((mRequestQueue.empty() && mRepeatingRequests.empty()) ||
+ exitPending()) {
Mutex::Autolock pl(mPauseLock);
if (mPaused == false) {
+ ALOGV("%s: RequestThread: Going idle", __FUNCTION__);
mPaused = true;
- mPausedSignal.signal();
+ // Let the tracker know
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
+ }
}
// Stop waiting for now and let thread management happen
return NULL;
@@ -1754,8 +2050,17 @@ sp<Camera3Device::CaptureRequest>
mRequestQueue.erase(firstRequest);
}
- // Not paused
+ // In case we've been unpaused by setPaused clearing mDoPause, need to
+ // update internal pause state (capture/setRepeatingRequest unpause
+ // directly).
Mutex::Autolock pl(mPauseLock);
+ if (mPaused) {
+ ALOGV("%s: RequestThread: Unpaused", __FUNCTION__);
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->markComponentActive(mStatusId);
+ }
+ }
mPaused = false;
// Check if we've reconfigured since last time, and reset the preview
@@ -1772,13 +2077,18 @@ bool Camera3Device::RequestThread::waitIfPaused() {
status_t res;
Mutex::Autolock l(mPauseLock);
while (mDoPause) {
- // Signal that we're paused by request
if (mPaused == false) {
mPaused = true;
- mPausedSignal.signal();
+ ALOGV("%s: RequestThread: Paused", __FUNCTION__);
+ // Let the tracker know
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);
+ }
}
+
res = mDoPauseSignal.waitRelative(mPauseLock, kRequestTimeout);
- if (res == TIMED_OUT) {
+ if (res == TIMED_OUT || exitPending()) {
return true;
}
}
@@ -1787,6 +2097,24 @@ bool Camera3Device::RequestThread::waitIfPaused() {
return false;
}
+void Camera3Device::RequestThread::unpauseForNewRequests() {
+ // With work to do, mark thread as unpaused.
+ // If paused by request (setPaused), don't resume, to avoid
+ // extra signaling/waiting overhead to waitUntilPaused
+ mRequestSignal.signal();
+ Mutex::Autolock p(mPauseLock);
+ if (!mDoPause) {
+ ALOGV("%s: RequestThread: Going active", __FUNCTION__);
+ if (mPaused) {
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->markComponentActive(mStatusId);
+ }
+ }
+ mPaused = false;
+ }
+}
+
void Camera3Device::RequestThread::setErrorState(const char *fmt, ...) {
sp<Camera3Device> parent = mParent.promote();
if (parent != NULL) {
@@ -1932,6 +2260,40 @@ status_t Camera3Device::RequestThread::removeTriggers(
return OK;
}
+status_t Camera3Device::RequestThread::addDummyTriggerIds(
+ const sp<CaptureRequest> &request) {
+ // Trigger ID 0 has special meaning in the HAL2 spec, so avoid it here
+ static const int32_t dummyTriggerId = 1;
+ status_t res;
+
+ CameraMetadata &metadata = request->mSettings;
+
+ // If AF trigger is active, insert a dummy AF trigger ID if none already
+ // exists
+ camera_metadata_entry afTrigger = metadata.find(ANDROID_CONTROL_AF_TRIGGER);
+ camera_metadata_entry afId = metadata.find(ANDROID_CONTROL_AF_TRIGGER_ID);
+ if (afTrigger.count > 0 &&
+ afTrigger.data.u8[0] != ANDROID_CONTROL_AF_TRIGGER_IDLE &&
+ afId.count == 0) {
+ res = metadata.update(ANDROID_CONTROL_AF_TRIGGER_ID, &dummyTriggerId, 1);
+ if (res != OK) return res;
+ }
+
+ // If AE precapture trigger is active, insert a dummy precapture trigger ID
+ // if none already exists
+ camera_metadata_entry pcTrigger =
+ metadata.find(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER);
+ camera_metadata_entry pcId = metadata.find(ANDROID_CONTROL_AE_PRECAPTURE_ID);
+ if (pcTrigger.count > 0 &&
+ pcTrigger.data.u8[0] != ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE &&
+ pcId.count == 0) {
+ res = metadata.update(ANDROID_CONTROL_AE_PRECAPTURE_ID,
+ &dummyTriggerId, 1);
+ if (res != OK) return res;
+ }
+
+ return OK;
+}
/**
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2328f89..12252c8 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -22,13 +22,11 @@
#include <utils/List.h>
#include <utils/Mutex.h>
#include <utils/Thread.h>
+#include <utils/KeyedVector.h>
+#include <hardware/camera3.h>
-#include "CameraDeviceBase.h"
-#include "camera3/Camera3Stream.h"
-#include "camera3/Camera3OutputStream.h"
-#include "camera3/Camera3ZslStream.h"
-
-#include "hardware/camera3.h"
+#include "common/CameraDeviceBase.h"
+#include "device3/StatusTracker.h"
/**
* Function pointer types with C calling convention to
@@ -46,6 +44,15 @@ extern "C" {
namespace android {
+namespace camera3 {
+
+class Camera3Stream;
+class Camera3ZslStream;
+class Camera3OutputStreamInterface;
+class Camera3StreamInterface;
+
+}
+
/**
* CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0
*/
@@ -118,27 +125,49 @@ class Camera3Device :
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
+ virtual status_t flush();
+
+ // Methods called by subclasses
+ void notifyStatus(bool idle); // updates from StatusTracker
+
private:
+ static const size_t kDumpLockAttempts = 10;
+ static const size_t kDumpSleepDuration = 100000; // 0.10 sec
static const size_t kInFlightWarnLimit = 20;
static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec
+ static const nsecs_t kActiveTimeout = 500000000; // 500 ms
struct RequestTrigger;
+ // A lock to enforce serialization on the input/configure side
+ // of the public interface.
+ // Only locked by public methods inherited from CameraDeviceBase.
+ // Not locked by methods guarded by mOutputLock, since they may act
+ // concurrently to the input/configure side of the interface.
+ // Must be locked before mLock if both will be locked by a method
+ Mutex mInterfaceLock;
+
+ // The main lock on internal state
Mutex mLock;
+ // Camera device ID
+ const int mId;
+
/**** Scope for mLock ****/
- const int mId;
camera3_device_t *mHal3Device;
CameraMetadata mDeviceInfo;
vendor_tag_query_ops_t mVendorTagOps;
- enum {
+ enum Status {
STATUS_ERROR,
STATUS_UNINITIALIZED,
- STATUS_IDLE,
+ STATUS_UNCONFIGURED,
+ STATUS_CONFIGURED,
STATUS_ACTIVE
} mStatus;
+ Vector<Status> mRecentStatusUpdates;
+ Condition mStatusChanged;
// Tracking cause of fatal errors when in STATUS_ERROR
String8 mErrorCause;
@@ -152,6 +181,10 @@ class Camera3Device :
int mNextStreamId;
bool mNeedConfig;
+ // Whether to send state updates upstream
+ // Pause when doing transparent reconfiguration
+ bool mPauseStateNotify;
+
// Need to hold on to stream references until configure completes.
Vector<sp<camera3::Camera3StreamInterface> > mDeletedStreams;
@@ -167,10 +200,38 @@ class Camera3Device :
typedef List<sp<CaptureRequest> > RequestList;
/**
- * Lock-held version of waitUntilDrained. Will transition to IDLE on
- * success.
+ * Get the last request submitted to the hal by the request thread.
+ *
+ * Takes mLock.
+ */
+ virtual CameraMetadata getLatestRequestLocked();
+
+ /**
+ * Pause processing and flush everything, but don't tell the clients.
+ * This is for reconfiguring outputs transparently when according to the
+ * CameraDeviceBase interface we shouldn't need to.
+ * Must be called with mLock and mInterfaceLock both held.
+ */
+ status_t internalPauseAndWaitLocked();
+
+ /**
+ * Resume work after internalPauseAndWaitLocked()
+ * Must be called with mLock and mInterfaceLock both held.
+ */
+ status_t internalResumeLocked();
+
+ /**
+ * Wait until status tracker tells us we've transitioned to the target state
+ * set, which is either ACTIVE when active==true or IDLE (which is any
+ * non-ACTIVE state) when active==false.
+ *
+ * Needs to be called with mLock and mInterfaceLock held. This means there
+ * can ever only be one waiter at most.
+ *
+ * During the wait mLock is released.
+ *
*/
- status_t waitUntilDrainedLocked();
+ status_t waitUntilStateThenRelock(bool active, nsecs_t timeout);
/**
* Do common work for setting up a streaming or single capture request.
@@ -200,6 +261,12 @@ class Camera3Device :
void setErrorStateLocked(const char *fmt, ...);
void setErrorStateLockedV(const char *fmt, va_list args);
+ /**
+ * Debugging trylock/spin method
+ * Try to acquire a lock a few times with sleeps between before giving up.
+ */
+ bool tryLockSpinRightRound(Mutex& lock);
+
struct RequestTrigger {
// Metadata tag number, e.g. android.control.aePrecaptureTrigger
uint32_t metadataTag;
@@ -225,6 +292,7 @@ class Camera3Device :
public:
RequestThread(wp<Camera3Device> parent,
+ sp<camera3::StatusTracker> statusTracker,
camera3_device_t *hal3Device);
/**
@@ -243,6 +311,11 @@ class Camera3Device :
status_t queueRequest(sp<CaptureRequest> request);
/**
+ * Remove all queued and repeating requests, and pending triggers
+ */
+ status_t clear();
+
+ /**
* Queue a trigger to be dispatched with the next outgoing
* process_capture_request. The settings for that request only
* will be temporarily rewritten to add the trigger tag/value.
@@ -257,13 +330,6 @@ class Camera3Device :
void setPaused(bool paused);
/**
- * Wait until thread is paused, either due to setPaused(true)
- * or due to lack of input requests. Returns TIMED_OUT in case
- * the thread does not pause within the timeout.
- */
- status_t waitUntilPaused(nsecs_t timeout);
-
- /**
* Wait until thread processes the capture request with settings'
* android.request.id == requestId.
*
@@ -272,6 +338,18 @@ class Camera3Device :
*/
status_t waitUntilRequestProcessed(int32_t requestId, nsecs_t timeout);
+ /**
+ * Shut down the thread. Shutdown is asynchronous, so thread may
+ * still be running once this method returns.
+ */
+ virtual void requestExit();
+
+ /**
+ * Get the latest request that was sent to the HAL
+ * with process_capture_request.
+ */
+ CameraMetadata getLatestRequest() const;
+
protected:
virtual bool threadLoop();
@@ -286,6 +364,10 @@ class Camera3Device :
// restoring the old field values for those tags.
status_t removeTriggers(const sp<CaptureRequest> &request);
+ // HAL workaround: Make sure a trigger ID always exists if
+ // a trigger does
+ status_t addDummyTriggerIds(const sp<CaptureRequest> &request);
+
static const nsecs_t kRequestTimeout = 50e6; // 50 ms
// Waits for a request, or returns NULL if times out.
@@ -301,14 +383,18 @@ class Camera3Device :
// Pause handling
bool waitIfPaused();
+ void unpauseForNewRequests();
// Relay error to parent device object setErrorState
void setErrorState(const char *fmt, ...);
wp<Camera3Device> mParent;
+ wp<camera3::StatusTracker> mStatusTracker;
camera3_device_t *mHal3Device;
- const int mId;
+ const int mId; // The camera ID
+ int mStatusId; // The RequestThread's component ID for
+ // status tracking
Mutex mRequestLock;
Condition mRequestSignal;
@@ -329,10 +415,11 @@ class Camera3Device :
uint32_t mFrameNumber;
- Mutex mLatestRequestMutex;
+ mutable Mutex mLatestRequestMutex;
Condition mLatestRequestSignal;
// android.request.id for latest process_capture_request
int32_t mLatestRequestId;
+ CameraMetadata mLatestRequest;
typedef KeyedVector<uint32_t/*tag*/, RequestTrigger> TriggerMap;
Mutex mTriggerMutex;
@@ -347,22 +434,30 @@ class Camera3Device :
*/
struct InFlightRequest {
+ // android.request.id for the request
+ int requestId;
// Set by notify() SHUTTER call.
nsecs_t captureTimestamp;
+ int requestStatus;
// Set by process_capture_result call with valid metadata
bool haveResultMetadata;
// Decremented by calls to process_capture_result with valid output
// buffers
int numBuffersLeft;
+ // Default constructor needed by KeyedVector
InFlightRequest() :
+ requestId(0),
captureTimestamp(0),
+ requestStatus(OK),
haveResultMetadata(false),
numBuffersLeft(0) {
}
- explicit InFlightRequest(int numBuffers) :
+ InFlightRequest(int id, int numBuffers) :
+ requestId(id),
captureTimestamp(0),
+ requestStatus(OK),
haveResultMetadata(false),
numBuffersLeft(numBuffers) {
}
@@ -373,7 +468,13 @@ class Camera3Device :
Mutex mInFlightLock; // Protects mInFlightMap
InFlightMap mInFlightMap;
- status_t registerInFlight(int32_t frameNumber, int32_t numBuffers);
+ status_t registerInFlight(int32_t frameNumber, int32_t requestId,
+ int32_t numBuffers);
+
+ /**
+ * Tracking for idle detection
+ */
+ sp<camera3::StatusTracker> mStatusTracker;
/**
* Output result queue and current HAL device 3A state
diff --git a/services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 0850566..da51228 100644
--- a/services/camera/libcameraservice/camera3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -23,7 +23,8 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-#include "Camera3IOStreamBase.h"
+#include "device3/Camera3IOStreamBase.h"
+#include "device3/StatusTracker.h"
namespace android {
@@ -62,53 +63,6 @@ bool Camera3IOStreamBase::hasOutstandingBuffersLocked() const {
return false;
}
-status_t Camera3IOStreamBase::waitUntilIdle(nsecs_t timeout) {
- status_t res;
- {
- Mutex::Autolock l(mLock);
- while (mDequeuedBufferCount > 0) {
- if (timeout != TIMEOUT_NEVER) {
- nsecs_t startTime = systemTime();
- res = mBufferReturnedSignal.waitRelative(mLock, timeout);
- if (res == TIMED_OUT) {
- return res;
- } else if (res != OK) {
- ALOGE("%s: Error waiting for outstanding buffers: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- nsecs_t deltaTime = systemTime() - startTime;
- if (timeout <= deltaTime) {
- timeout = 0;
- } else {
- timeout -= deltaTime;
- }
- } else {
- res = mBufferReturnedSignal.wait(mLock);
- if (res != OK) {
- ALOGE("%s: Error waiting for outstanding buffers: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
- }
- }
- }
-
- // No lock
-
- unsigned int timeoutMs;
- if (timeout == TIMEOUT_NEVER) {
- timeoutMs = Fence::TIMEOUT_NEVER;
- } else if (timeout == 0) {
- timeoutMs = 0;
- } else {
- // Round up to wait at least 1 ms
- timeoutMs = (timeout + 999999) / 1000000;
- }
-
- return mCombinedFence->wait(timeoutMs);
-}
-
void Camera3IOStreamBase::dump(int fd, const Vector<String16> &args) const {
(void) args;
String8 lines;
@@ -190,6 +144,14 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer,
buffer.release_fence = releaseFence;
buffer.status = status;
+ // Inform tracker about becoming busy
+ if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG &&
+ mState != STATE_IN_RECONFIG) {
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->markComponentActive(mStatusId);
+ }
+ }
mDequeuedBufferCount++;
}
@@ -252,20 +214,32 @@ status_t Camera3IOStreamBase::returnAnyBufferLocked(
sp<Fence> releaseFence;
res = returnBufferCheckedLocked(buffer, timestamp, output,
&releaseFence);
- if (res != OK) {
- return res;
- }
+ // Res may be an error, but we still want to decrement our owned count
+ // to enable clean shutdown. So we'll just return the error but otherwise
+ // carry on
- mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence);
+ if (releaseFence != 0) {
+ mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence);
+ }
mDequeuedBufferCount--;
+ if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG &&
+ mState != STATE_IN_RECONFIG) {
+ ALOGV("%s: Stream %d: All buffers returned; now idle", __FUNCTION__,
+ mId);
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->markComponentIdle(mStatusId, mCombinedFence);
+ }
+ }
+
mBufferReturnedSignal.signal();
if (output) {
mLastTimestamp = timestamp;
}
- return OK;
+ return res;
}
diff --git a/services/camera/libcameraservice/camera3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index 74c4484..fcb9d04 100644
--- a/services/camera/libcameraservice/camera3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -43,7 +43,6 @@ class Camera3IOStreamBase :
* Camera3Stream interface
*/
- virtual status_t waitUntilIdle(nsecs_t timeout);
virtual void dump(int fd, const Vector<String16> &args) const;
protected:
@@ -77,6 +76,8 @@ class Camera3IOStreamBase :
virtual size_t getBufferCountLocked();
+ virtual status_t getEndpointUsage(uint32_t *usage) = 0;
+
status_t getBufferPreconditionCheckLocked() const;
status_t returnBufferPreconditionCheckLocked() const;
diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 13e9c83..5aa9a3e 100644
--- a/services/camera/libcameraservice/camera3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -115,7 +115,6 @@ status_t Camera3InputStream::returnBufferCheckedLocked(
bufferFound = true;
bufferItem = tmp;
mBuffersInFlight.erase(it);
- mDequeuedBufferCount--;
}
}
}
@@ -148,12 +147,11 @@ status_t Camera3InputStream::returnBufferCheckedLocked(
if (res != OK) {
ALOGE("%s: Stream %d: Error releasing buffer back to buffer queue:"
" %s (%d)", __FUNCTION__, mId, strerror(-res), res);
- return res;
}
*releaseFenceOut = releaseFence;
- return OK;
+ return res;
}
status_t Camera3InputStream::returnInputBufferLocked(
@@ -182,10 +180,6 @@ status_t Camera3InputStream::disconnectLocked() {
return OK;
}
-sp<IGraphicBufferProducer> Camera3InputStream::getProducerInterface() const {
- return mConsumer->getProducerInterface();
-}
-
void Camera3InputStream::dump(int fd, const Vector<String16> &args) const {
(void) args;
String8 lines;
@@ -211,9 +205,9 @@ status_t Camera3InputStream::configureQueueLocked() {
mFrameCount = 0;
if (mConsumer.get() == 0) {
- mConsumer = new BufferItemConsumer(camera3_stream::usage,
- mTotalBufferCount,
- /*synchronousMode*/true);
+ sp<BufferQueue> bq = new BufferQueue();
+ mConsumer = new BufferItemConsumer(bq, camera3_stream::usage,
+ mTotalBufferCount);
mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
}
@@ -234,6 +228,12 @@ status_t Camera3InputStream::configureQueueLocked() {
return OK;
}
+status_t Camera3InputStream::getEndpointUsage(uint32_t *usage) {
+ // Per HAL3 spec, input streams have 0 for their initial usage field.
+ *usage = 0;
+ return OK;
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/camera3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 8adda88..681d684 100644
--- a/services/camera/libcameraservice/camera3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -44,13 +44,6 @@ class Camera3InputStream : public Camera3IOStreamBase {
virtual void dump(int fd, const Vector<String16> &args) const;
- /**
- * Get the producer interface for this stream, to hand off to a producer.
- * The producer must be connected to the provided interface before
- * finishConfigure is called on this stream.
- */
- sp<IGraphicBufferProducer> getProducerInterface() const;
-
private:
typedef BufferItemConsumer::BufferItem BufferItem;
@@ -79,6 +72,8 @@ class Camera3InputStream : public Camera3IOStreamBase {
virtual status_t configureQueueLocked();
+ virtual status_t getEndpointUsage(uint32_t *usage);
+
}; // class Camera3InputStream
}; // namespace camera3
diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 2efeede..682755d 100644
--- a/services/camera/libcameraservice/camera3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -92,7 +92,22 @@ status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
ANativeWindowBuffer* anb;
int fenceFd;
- res = mConsumer->dequeueBuffer(mConsumer.get(), &anb, &fenceFd);
+ /**
+ * Release the lock briefly to avoid deadlock for below scenario:
+ * Thread 1: StreamingProcessor::startStream -> Camera3Stream::isConfiguring().
+ * This thread acquired StreamingProcessor lock and try to lock Camera3Stream lock.
+ * Thread 2: Camera3Stream::returnBuffer->StreamingProcessor::onFrameAvailable().
+ * This thread acquired Camera3Stream lock and bufferQueue lock, and try to lock
+ * StreamingProcessor lock.
+ * Thread 3: Camera3Stream::getBuffer(). This thread acquired Camera3Stream lock
+ * and try to lock bufferQueue lock.
+ * Then there is circular locking dependency.
+ */
+ sp<ANativeWindow> currentConsumer = mConsumer;
+ mLock.unlock();
+
+ res = currentConsumer->dequeueBuffer(currentConsumer.get(), &anb, &fenceFd);
+ mLock.lock();
if (res != OK) {
ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -198,12 +213,11 @@ status_t Camera3OutputStream::returnBufferCheckedLocked(
mLock.lock();
if (res != OK) {
close(anwReleaseFence);
- return res;
}
*releaseFenceOut = releaseFence;
- return OK;
+ return res;
}
void Camera3OutputStream::dump(int fd, const Vector<String16> &args) const {
@@ -301,8 +315,13 @@ status_t Camera3OutputStream::configureQueueLocked() {
return res;
}
- ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
- maxConsumerBuffers);
+ ALOGV("%s: Consumer wants %d buffers, HAL wants %d", __FUNCTION__,
+ maxConsumerBuffers, camera3_stream::max_buffers);
+ if (camera3_stream::max_buffers == 0) {
+ ALOGE("%s: Camera HAL requested max_buffer count: %d, requires at least 1",
+ __FUNCTION__, camera3_stream::max_buffers);
+ return INVALID_OPERATION;
+ }
mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers;
mDequeuedBufferCount = 0;
@@ -359,6 +378,17 @@ status_t Camera3OutputStream::disconnectLocked() {
return OK;
}
+status_t Camera3OutputStream::getEndpointUsage(uint32_t *usage) {
+
+ status_t res;
+ int32_t u = 0;
+ res = mConsumer->query(mConsumer.get(),
+ NATIVE_WINDOW_CONSUMER_USAGE_BITS, &u);
+ *usage = u;
+
+ return res;
+}
+
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 774fbdd..6cbb9f4 100644
--- a/services/camera/libcameraservice/camera3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -92,6 +92,9 @@ class Camera3OutputStream :
virtual status_t configureQueueLocked();
virtual status_t disconnectLocked();
+
+ virtual status_t getEndpointUsage(uint32_t *usage);
+
}; // class Camera3OutputStream
} // namespace camera3
diff --git a/services/camera/libcameraservice/camera3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index aae72cf..aae72cf 100644
--- a/services/camera/libcameraservice/camera3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
diff --git a/services/camera/libcameraservice/camera3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index f05658a..6d2cf94 100644
--- a/services/camera/libcameraservice/camera3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -20,13 +20,18 @@
#include <utils/Log.h>
#include <utils/Trace.h>
-#include "Camera3Stream.h"
+#include "device3/Camera3Stream.h"
+#include "device3/StatusTracker.h"
namespace android {
namespace camera3 {
Camera3Stream::~Camera3Stream() {
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0 && mStatusId != StatusTracker::NO_STATUS_ID) {
+ statusTracker->removeComponent(mStatusId);
+ }
}
Camera3Stream* Camera3Stream::cast(camera3_stream *stream) {
@@ -44,7 +49,8 @@ Camera3Stream::Camera3Stream(int id,
mId(id),
mName(String8::format("Camera3Stream[%d]", id)),
mMaxSize(maxSize),
- mState(STATE_CONSTRUCTED) {
+ mState(STATE_CONSTRUCTED),
+ mStatusId(StatusTracker::NO_STATUS_ID) {
camera3_stream::stream_type = type;
camera3_stream::width = width;
@@ -77,7 +83,9 @@ int Camera3Stream::getFormat() const {
}
camera3_stream* Camera3Stream::startConfiguration() {
+ ATRACE_CALL();
Mutex::Autolock l(mLock);
+ status_t res;
switch (mState) {
case STATE_ERROR:
@@ -107,8 +115,24 @@ camera3_stream* Camera3Stream::startConfiguration() {
return NULL;
}
- oldUsage = usage;
- oldMaxBuffers = max_buffers;
+ oldUsage = camera3_stream::usage;
+ oldMaxBuffers = camera3_stream::max_buffers;
+
+ res = getEndpointUsage(&(camera3_stream::usage));
+ if (res != OK) {
+ ALOGE("%s: Cannot query consumer endpoint usage!",
+ __FUNCTION__);
+ return NULL;
+ }
+
+ // Stop tracking if currently doing so
+ if (mStatusId != StatusTracker::NO_STATUS_ID) {
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ statusTracker->removeComponent(mStatusId);
+ }
+ mStatusId = StatusTracker::NO_STATUS_ID;
+ }
if (mState == STATE_CONSTRUCTED) {
mState = STATE_IN_CONFIG;
@@ -125,6 +149,7 @@ bool Camera3Stream::isConfiguring() const {
}
status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) {
+ ATRACE_CALL();
Mutex::Autolock l(mLock);
switch (mState) {
case STATE_ERROR:
@@ -144,11 +169,17 @@ status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) {
return INVALID_OPERATION;
}
+ // Register for idle tracking
+ sp<StatusTracker> statusTracker = mStatusTracker.promote();
+ if (statusTracker != 0) {
+ mStatusId = statusTracker->addComponent();
+ }
+
// Check if the stream configuration is unchanged, and skip reallocation if
// so. As documented in hardware/camera3.h:configure_streams().
if (mState == STATE_IN_RECONFIG &&
- oldUsage == usage &&
- oldMaxBuffers == max_buffers) {
+ oldUsage == camera3_stream::usage &&
+ oldMaxBuffers == camera3_stream::max_buffers) {
mState = STATE_CONFIGURED;
return OK;
}
@@ -255,6 +286,18 @@ bool Camera3Stream::hasOutstandingBuffers() const {
return hasOutstandingBuffersLocked();
}
+status_t Camera3Stream::setStatusTracker(sp<StatusTracker> statusTracker) {
+ Mutex::Autolock l(mLock);
+ sp<StatusTracker> oldTracker = mStatusTracker.promote();
+ if (oldTracker != 0 && mStatusId != StatusTracker::NO_STATUS_ID) {
+ oldTracker->removeComponent(mStatusId);
+ }
+ mStatusId = StatusTracker::NO_STATUS_ID;
+ mStatusTracker = statusTracker;
+
+ return OK;
+}
+
status_t Camera3Stream::disconnect() {
ATRACE_CALL();
Mutex::Autolock l(mLock);
@@ -312,8 +355,10 @@ status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) {
// Got all buffers, register with HAL
ALOGV("%s: Registering %d buffers with camera HAL",
__FUNCTION__, bufferCount);
+ ATRACE_BEGIN("camera3->register_stream_buffers");
res = hal3Device->ops->register_stream_buffers(hal3Device,
&bufferSet);
+ ATRACE_END();
}
// Return all valid buffers to stream, in ERROR state to indicate
diff --git a/services/camera/libcameraservice/camera3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 69d81e4..6eeb721 100644
--- a/services/camera/libcameraservice/camera3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -190,12 +190,11 @@ class Camera3Stream :
enum {
TIMEOUT_NEVER = -1
};
+
/**
- * Wait until the HAL is done with all of this stream's buffers, including
- * signalling all release fences. Returns TIMED_OUT if the timeout is exceeded,
- * OK on success. Pass in TIMEOUT_NEVER for timeout to indicate an indefinite wait.
+ * Set the status tracker to notify about idle transitions
*/
- virtual status_t waitUntilIdle(nsecs_t timeout) = 0;
+ virtual status_t setStatusTracker(sp<StatusTracker> statusTracker);
/**
* Disconnect stream from its non-HAL endpoint. After this,
@@ -263,6 +262,15 @@ class Camera3Stream :
// Get the total number of buffers in the queue
virtual size_t getBufferCountLocked() = 0;
+ // Get the usage flags for the other endpoint, or return
+ // INVALID_OPERATION if they cannot be obtained.
+ virtual status_t getEndpointUsage(uint32_t *usage) = 0;
+
+ // Tracking for idle state
+ wp<StatusTracker> mStatusTracker;
+ // Status tracker component ID
+ int mStatusId;
+
private:
uint32_t oldUsage;
uint32_t oldMaxBuffers;
diff --git a/services/camera/libcameraservice/camera3/Camera3StreamBufferListener.h b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
index 62ea6c0..62ea6c0 100644
--- a/services/camera/libcameraservice/camera3/Camera3StreamBufferListener.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamBufferListener.h
diff --git a/services/camera/libcameraservice/camera3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 4768536..c93ae15 100644
--- a/services/camera/libcameraservice/camera3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -26,6 +26,8 @@ namespace android {
namespace camera3 {
+class StatusTracker;
+
/**
* An interface for managing a single stream of input and/or output data from
* the camera device.
@@ -128,13 +130,11 @@ class Camera3StreamInterface : public virtual RefBase {
enum {
TIMEOUT_NEVER = -1
};
+
/**
- * Wait until the HAL is done with all of this stream's buffers, including
- * signalling all release fences. Returns TIMED_OUT if the timeout is
- * exceeded, OK on success. Pass in TIMEOUT_NEVER for timeout to indicate
- * an indefinite wait.
+ * Set the state tracker to use for signaling idle transitions.
*/
- virtual status_t waitUntilIdle(nsecs_t timeout) = 0;
+ virtual status_t setStatusTracker(sp<StatusTracker> statusTracker) = 0;
/**
* Disconnect stream from its non-HAL endpoint. After this,
diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index 8790c8c..04f5dc5 100644
--- a/services/camera/libcameraservice/camera3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -113,11 +113,11 @@ Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height,
Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
width, height,
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mDepth(depth),
- mProducer(new RingBufferConsumer(GRALLOC_USAGE_HW_CAMERA_ZSL,
- depth)) {
+ mDepth(depth) {
- mConsumer = new Surface(mProducer->getProducerInterface());
+ sp<BufferQueue> bq = new BufferQueue();
+ mProducer = new RingBufferConsumer(bq, GRALLOC_USAGE_HW_CAMERA_ZSL, depth);
+ mConsumer = new Surface(bq);
}
Camera3ZslStream::~Camera3ZslStream() {
diff --git a/services/camera/libcameraservice/camera3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h
index c7f4490..c7f4490 100644
--- a/services/camera/libcameraservice/camera3/Camera3ZslStream.h
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.h
diff --git a/services/camera/libcameraservice/device3/StatusTracker.cpp b/services/camera/libcameraservice/device3/StatusTracker.cpp
new file mode 100644
index 0000000..ab5419f
--- /dev/null
+++ b/services/camera/libcameraservice/device3/StatusTracker.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera3-Status"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+// This is needed for stdint.h to define INT64_MAX in C++
+#define __STDC_LIMIT_MACROS
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <ui/Fence.h>
+
+#include "device3/StatusTracker.h"
+#include "device3/Camera3Device.h"
+
+namespace android {
+
+namespace camera3 {
+
+StatusTracker::StatusTracker(wp<Camera3Device> parent) :
+ mComponentsChanged(false),
+ mParent(parent),
+ mNextComponentId(0),
+ mIdleFence(new Fence()),
+ mDeviceState(IDLE) {
+}
+
+StatusTracker::~StatusTracker() {
+}
+
+int StatusTracker::addComponent() {
+ int id;
+ ssize_t err;
+ {
+ Mutex::Autolock l(mLock);
+ id = mNextComponentId++;
+ ALOGV("%s: Adding new component %d", __FUNCTION__, id);
+
+ err = mStates.add(id, IDLE);
+ ALOGE_IF(err < 0, "%s: Can't add new component %d: %s (%d)",
+ __FUNCTION__, id, strerror(-err), err);
+ }
+
+ if (err >= 0) {
+ Mutex::Autolock pl(mPendingLock);
+ mComponentsChanged = true;
+ mPendingChangeSignal.signal();
+ }
+
+ return err < 0 ? err : id;
+}
+
+void StatusTracker::removeComponent(int id) {
+ ssize_t idx;
+ {
+ Mutex::Autolock l(mLock);
+ ALOGV("%s: Removing component %d", __FUNCTION__, id);
+ idx = mStates.removeItem(id);
+ }
+
+ if (idx >= 0) {
+ Mutex::Autolock pl(mPendingLock);
+ mComponentsChanged = true;
+ mPendingChangeSignal.signal();
+ }
+
+ return;
+}
+
+
+void StatusTracker::markComponentIdle(int id, const sp<Fence>& componentFence) {
+ markComponent(id, IDLE, componentFence);
+}
+
+void StatusTracker::markComponentActive(int id) {
+ markComponent(id, ACTIVE, Fence::NO_FENCE);
+}
+
+void StatusTracker::markComponent(int id, ComponentState state,
+ const sp<Fence>& componentFence) {
+ ALOGV("%s: Component %d is now %s", __FUNCTION__, id,
+ state == IDLE ? "idle" : "active");
+ Mutex::Autolock l(mPendingLock);
+
+ StateChange newState = {
+ id,
+ state,
+ componentFence
+ };
+
+ mPendingChangeQueue.add(newState);
+ mPendingChangeSignal.signal();
+}
+
+void StatusTracker::requestExit() {
+ // First mark thread dead
+ Thread::requestExit();
+ // Then exit any waits
+ mPendingChangeSignal.signal();
+}
+
+StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() {
+ for (size_t i = 0; i < mStates.size(); i++) {
+ if (mStates.valueAt(i) == ACTIVE) {
+ ALOGV("%s: Component %d not idle", __FUNCTION__,
+ mStates.keyAt(i));
+ return ACTIVE;
+ }
+ }
+ // - If not yet signaled, getSignalTime returns INT64_MAX
+ // - If invalid fence or error, returns -1
+ // - Otherwise returns time of signalling.
+ // Treat -1 as 'signalled', since HAL may not be using fences, and want
+ // to be able to idle in case of errors.
+ nsecs_t signalTime = mIdleFence->getSignalTime();
+ bool fencesDone = signalTime != INT64_MAX;
+
+ ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__);
+
+ return fencesDone ? IDLE : ACTIVE;
+}
+
+bool StatusTracker::threadLoop() {
+ status_t res;
+
+ // Wait for state updates
+ {
+ Mutex::Autolock pl(mPendingLock);
+ while (mPendingChangeQueue.size() == 0 && !mComponentsChanged) {
+ res = mPendingChangeSignal.waitRelative(mPendingLock,
+ kWaitDuration);
+ if (exitPending()) return false;
+ if (res != OK) {
+ if (res != TIMED_OUT) {
+ ALOGE("%s: Error waiting on state changes: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ // TIMED_OUT is expected
+ break;
+ }
+ }
+ }
+
+ // After new pending states appear, or timeout, check if we're idle. Even
+ // with timeout, need to check to account for fences that may still be
+ // clearing out
+ sp<Camera3Device> parent;
+ {
+ Mutex::Autolock pl(mPendingLock);
+ Mutex::Autolock l(mLock);
+
+ // Collect all pending state updates and see if the device
+ // collectively transitions between idle and active for each one
+
+ // First pass for changed components or fence completions
+ ComponentState prevState = getDeviceStateLocked();
+ if (prevState != mDeviceState) {
+ // Only collect changes to overall device state
+ mStateTransitions.add(prevState);
+ }
+ // For each pending component state update, check if we've transitioned
+ // to a new overall device state
+ for (size_t i = 0; i < mPendingChangeQueue.size(); i++) {
+ const StateChange &newState = mPendingChangeQueue[i];
+ ssize_t idx = mStates.indexOfKey(newState.id);
+ // Ignore notices for unknown components
+ if (idx >= 0) {
+ // Update single component state
+ mStates.replaceValueAt(idx, newState.state);
+ mIdleFence = Fence::merge(String8("idleFence"),
+ mIdleFence, newState.fence);
+ // .. and see if overall device state has changed
+ ComponentState newState = getDeviceStateLocked();
+ if (newState != prevState) {
+ mStateTransitions.add(newState);
+ }
+ prevState = newState;
+ }
+ }
+ mPendingChangeQueue.clear();
+ mComponentsChanged = false;
+
+ // Store final state after all pending state changes are done with
+
+ mDeviceState = prevState;
+ parent = mParent.promote();
+ }
+
+ // Notify parent for all intermediate transitions
+ if (mStateTransitions.size() > 0 && parent.get()) {
+ for (size_t i = 0; i < mStateTransitions.size(); i++) {
+ bool idle = (mStateTransitions[i] == IDLE);
+ ALOGV("Camera device is now %s", idle ? "idle" : "active");
+ parent->notifyStatus(idle);
+ }
+ }
+ mStateTransitions.clear();
+
+ return true;
+}
+
+} // namespace android
+
+} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/StatusTracker.h b/services/camera/libcameraservice/device3/StatusTracker.h
new file mode 100644
index 0000000..49cecb3
--- /dev/null
+++ b/services/camera/libcameraservice/device3/StatusTracker.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA3_STATUSTRACKER_H
+#define ANDROID_SERVERS_CAMERA3_STATUSTRACKER_H
+
+#include <utils/Condition.h>
+#include <utils/Errors.h>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <utils/KeyedVector.h>
+#include <hardware/camera3.h>
+
+#include "common/CameraDeviceBase.h"
+
+namespace android {
+
+class Camera3Device;
+class Fence;
+
+namespace camera3 {
+
+/**
+ * State tracking for idle and other collective state transitions.
+ * Collects idle notifications from different sources and calls the
+ * parent when all of them become idle.
+ *
+ * The parent is responsible for synchronizing the status updates with its
+ * internal state correctly, which means the notifyStatus call to the parent may
+ * block for a while.
+ */
+class StatusTracker: public Thread {
+ public:
+ StatusTracker(wp<Camera3Device> parent);
+ ~StatusTracker();
+
+ // An always-invalid component ID
+ static const int NO_STATUS_ID = -1;
+
+ // Add a component to track; returns non-negative unique ID for the new
+ // component on success, negative error code on failure.
+ // New components start in the idle state.
+ int addComponent();
+
+ // Remove existing component from idle tracking. Ignores unknown IDs
+ void removeComponent(int id);
+
+ // Set the state of a tracked component to be idle. Ignores unknown IDs; can
+ // accept a fence to wait on to complete idle. The fence is merged with any
+ // previous fences given, which means they all must signal before the
+ // component is considered idle.
+ void markComponentIdle(int id, const sp<Fence>& componentFence);
+
+ // Set the state of a tracked component to be active. Ignores unknown IDs.
+ void markComponentActive(int id);
+
+ virtual void requestExit();
+ protected:
+
+ virtual bool threadLoop();
+
+ private:
+ enum ComponentState {
+ IDLE,
+ ACTIVE
+ };
+
+ void markComponent(int id, ComponentState state,
+ const sp<Fence>& componentFence);
+
+ // Guards mPendingChange, mPendingStates, mComponentsChanged
+ Mutex mPendingLock;
+
+ Condition mPendingChangeSignal;
+
+ struct StateChange {
+ int id;
+ ComponentState state;
+ sp<Fence> fence;
+ };
+ // A queue of yet-to-be-processed state changes to components
+ Vector<StateChange> mPendingChangeQueue;
+ bool mComponentsChanged;
+
+ wp<Camera3Device> mParent;
+
+ // Guards rest of internals. Must be locked after mPendingLock if both used.
+ Mutex mLock;
+
+ int mNextComponentId;
+
+ // Current component states
+ KeyedVector<int, ComponentState> mStates;
+ // Merged fence for all processed state changes
+ sp<Fence> mIdleFence;
+ // Current overall device state
+ ComponentState mDeviceState;
+
+ // Private to threadLoop
+
+ // Determine current overall device state
+ // We're IDLE iff
+ // - All components are currently IDLE
+ // - The merged fence for all component updates has signalled
+ ComponentState getDeviceStateLocked();
+
+ Vector<ComponentState> mStateTransitions;
+
+ static const nsecs_t kWaitDuration = 250000000LL; // 250 ms
+};
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index cd39bad..ebc7ea7 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -34,14 +34,14 @@ typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
namespace android {
-RingBufferConsumer::RingBufferConsumer(uint32_t consumerUsage,
+RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer,
+ uint32_t consumerUsage,
int bufferCount) :
- ConsumerBase(new BufferQueue(true)),
+ ConsumerBase(consumer),
mBufferCount(bufferCount)
{
- mBufferQueue->setConsumerUsageBits(consumerUsage);
- mBufferQueue->setSynchronousMode(true);
- mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
+ mConsumer->setConsumerUsageBits(consumerUsage);
+ mConsumer->setMaxAcquiredBufferCount(bufferCount);
assert(bufferCount > 0);
}
@@ -52,7 +52,7 @@ RingBufferConsumer::~RingBufferConsumer() {
void RingBufferConsumer::setName(const String8& name) {
Mutex::Autolock _l(mMutex);
mName = name;
- mBufferQueue->setConsumerName(name);
+ mConsumer->setConsumerName(name);
}
sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer(
@@ -214,7 +214,11 @@ status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
// In case the object was never pinned, pass the acquire fence
// back to the release fence. If the fence was already waited on,
// it'll just be a no-op to wait on it again.
- err = addReleaseFenceLocked(item.mBuf, item.mFence);
+
+ // item.mGraphicBuffer was populated with the proper graphic-buffer
+ // at acquire even if it was previously acquired
+ err = addReleaseFenceLocked(item.mBuf,
+ item.mGraphicBuffer, item.mFence);
if (err != OK) {
BI_LOGE("Failed to add release fence to buffer "
@@ -226,7 +230,9 @@ status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld",
item.mTimestamp, item.mFrameNumber);
- err = releaseBufferLocked(item.mBuf,
+ // item.mGraphicBuffer was populated with the proper graphic-buffer
+ // at acquire even if it was previously acquired
+ err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR);
if (err != OK) {
@@ -278,7 +284,7 @@ void RingBufferConsumer::onFrameAvailable() {
/**
* Acquire new frame
*/
- err = acquireBufferLocked(&item);
+ err = acquireBufferLocked(&item, 0);
if (err != OK) {
if (err != NO_BUFFER_AVAILABLE) {
BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
@@ -310,7 +316,8 @@ void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
RingBufferItem& find = *it;
if (item.mGraphicBuffer == find.mGraphicBuffer) {
- status_t res = addReleaseFenceLocked(item.mBuf, item.mFence);
+ status_t res = addReleaseFenceLocked(item.mBuf,
+ item.mGraphicBuffer, item.mFence);
if (res != OK) {
BI_LOGE("Failed to add release fence to buffer "
@@ -336,17 +343,17 @@ void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
Mutex::Autolock _l(mMutex);
- return mBufferQueue->setDefaultBufferSize(w, h);
+ return mConsumer->setDefaultBufferSize(w, h);
}
status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
Mutex::Autolock _l(mMutex);
- return mBufferQueue->setDefaultBufferFormat(defaultFormat);
+ return mConsumer->setDefaultBufferFormat(defaultFormat);
}
status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) {
Mutex::Autolock _l(mMutex);
- return mBufferQueue->setConsumerUsageBits(usage);
+ return mConsumer->setConsumerUsageBits(usage);
}
} // namespace android
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 454fbae..b4ad824 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -63,7 +63,7 @@ class RingBufferConsumer : public ConsumerBase,
// the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be pinned for user
// access at the same time.
- RingBufferConsumer(uint32_t consumerUsage,
+ RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS);
virtual ~RingBufferConsumer();
@@ -72,8 +72,6 @@ class RingBufferConsumer : public ConsumerBase,
// log messages.
void setName(const String8& name);
- sp<IGraphicBufferProducer> getProducerInterface() const { return getBufferQueue(); }
-
// setDefaultBufferSize is used to set the size of buffers returned by
// requestBuffers when a with and height of zero is requested.
status_t setDefaultBufferSize(uint32_t w, uint32_t h);