summaryrefslogtreecommitdiffstats
path: root/services/camera
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2014-11-06 17:49:48 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2014-11-06 17:49:48 -0800
commite1a2df553a6d151807a5da738a3cd853bef908d9 (patch)
tree9015c1c9ad9ec69f1962657f70fe3df386fbb05a /services/camera
parentbcf093bfef277a8ec0119da9e84e5abac58ad0b1 (diff)
parent841daebc75fbf5e7fb4dd71cab559b8f4d7150ae (diff)
downloadframeworks_av-e1a2df553a6d151807a5da738a3cd853bef908d9.zip
frameworks_av-e1a2df553a6d151807a5da738a3cd853bef908d9.tar.gz
frameworks_av-e1a2df553a6d151807a5da738a3cd853bef908d9.tar.bz2
Resolve conflict
Diffstat (limited to 'services/camera')
-rw-r--r--services/camera/libcameraservice/Android.mk17
-rw-r--r--services/camera/libcameraservice/CameraDeviceFactory.cpp2
-rw-r--r--services/camera/libcameraservice/CameraService.cpp699
-rw-r--r--services/camera/libcameraservice/CameraService.h122
-rw-r--r--services/camera/libcameraservice/api1/Camera2Client.cpp207
-rw-r--r--services/camera/libcameraservice/api1/Camera2Client.h10
-rw-r--r--services/camera/libcameraservice/api1/CameraClient.cpp41
-rw-r--r--services/camera/libcameraservice/api1/CameraClient.h7
-rw-r--r--services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp10
-rw-r--r--services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp53
-rw-r--r--services/camera/libcameraservice/api1/client2/CaptureSequencer.h5
-rw-r--r--services/camera/libcameraservice/api1/client2/FrameProcessor.cpp57
-rw-r--r--services/camera/libcameraservice/api1/client2/FrameProcessor.h8
-rw-r--r--services/camera/libcameraservice/api1/client2/JpegProcessor.cpp36
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp440
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.h53
-rw-r--r--services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp84
-rw-r--r--services/camera/libcameraservice/api1/client2/StreamingProcessor.h3
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.cpp36
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor.h6
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp233
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessor3.h19
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp28
-rw-r--r--services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h5
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.cpp274
-rw-r--r--services/camera/libcameraservice/api2/CameraDeviceClient.h30
-rw-r--r--services/camera/libcameraservice/api_pro/ProCamera2Client.cpp15
-rw-r--r--services/camera/libcameraservice/api_pro/ProCamera2Client.h5
-rw-r--r--services/camera/libcameraservice/common/Camera2ClientBase.cpp36
-rw-r--r--services/camera/libcameraservice/common/Camera2ClientBase.h12
-rw-r--r--services/camera/libcameraservice/common/CameraDeviceBase.h72
-rw-r--r--services/camera/libcameraservice/common/FrameProcessorBase.cpp94
-rw-r--r--services/camera/libcameraservice/common/FrameProcessorBase.h20
-rw-r--r--services/camera/libcameraservice/device1/CameraHardwareInterface.h27
-rw-r--r--services/camera/libcameraservice/device2/Camera2Device.cpp122
-rw-r--r--services/camera/libcameraservice/device2/Camera2Device.h26
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.cpp1116
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.h180
-rw-r--r--services/camera/libcameraservice/device3/Camera3DummyStream.cpp97
-rw-r--r--services/camera/libcameraservice/device3/Camera3DummyStream.h98
-rw-r--r--services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp65
-rw-r--r--services/camera/libcameraservice/device3/Camera3IOStreamBase.h12
-rw-r--r--services/camera/libcameraservice/device3/Camera3InputStream.cpp34
-rw-r--r--services/camera/libcameraservice/device3/Camera3InputStream.h2
-rw-r--r--services/camera/libcameraservice/device3/Camera3OutputStream.cpp43
-rw-r--r--services/camera/libcameraservice/device3/Camera3OutputStream.h5
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.cpp128
-rw-r--r--services/camera/libcameraservice/device3/Camera3Stream.h42
-rw-r--r--services/camera/libcameraservice/device3/Camera3StreamInterface.h7
-rw-r--r--services/camera/libcameraservice/device3/Camera3ZslStream.cpp31
-rw-r--r--services/camera/libcameraservice/device3/Camera3ZslStream.h14
-rw-r--r--services/camera/libcameraservice/gui/RingBufferConsumer.cpp18
-rw-r--r--services/camera/libcameraservice/gui/RingBufferConsumer.h8
53 files changed, 3768 insertions, 1046 deletions
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 51ba698..e184d97 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -1,3 +1,17 @@
+# Copyright 2010 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.
+
LOCAL_PATH:= $(call my-dir)
#
@@ -20,6 +34,7 @@ LOCAL_SRC_FILES:= \
api1/client2/JpegProcessor.cpp \
api1/client2/CallbackProcessor.cpp \
api1/client2/ZslProcessor.cpp \
+ api1/client2/ZslProcessorInterface.cpp \
api1/client2/BurstCapture.cpp \
api1/client2/JpegCompressor.cpp \
api1/client2/CaptureSequencer.cpp \
@@ -33,6 +48,7 @@ LOCAL_SRC_FILES:= \
device3/Camera3InputStream.cpp \
device3/Camera3OutputStream.cpp \
device3/Camera3ZslStream.cpp \
+ device3/Camera3DummyStream.cpp \
device3/StatusTracker.cpp \
gui/RingBufferConsumer.cpp \
utils/CameraTraces.cpp \
@@ -53,6 +69,7 @@ LOCAL_SHARED_LIBRARIES:= \
LOCAL_C_INCLUDES += \
system/media/camera/include \
+ system/media/private/camera/include \
external/jpeg
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.cpp b/services/camera/libcameraservice/CameraDeviceFactory.cpp
index 7fdf304..bfef50e 100644
--- a/services/camera/libcameraservice/CameraDeviceFactory.cpp
+++ b/services/camera/libcameraservice/CameraDeviceFactory.cpp
@@ -46,6 +46,8 @@ sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
device = new Camera2Device(cameraId);
break;
case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
device = new Camera3Device(cameraId);
break;
default:
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 9ce7daf..fd5a426 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1,24 +1,24 @@
/*
-**
-** Copyright (C) 2008, 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.
-*/
+ * Copyright (C) 2008 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 "CameraService"
//#define LOG_NDEBUG 0
#include <stdio.h>
+#include <string.h>
#include <sys/types.h>
#include <pthread.h>
@@ -32,10 +32,15 @@
#include <gui/Surface.h>
#include <hardware/hardware.h>
#include <media/AudioSystem.h>
+#include <media/IMediaHTTPService.h>
#include <media/mediaplayer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h>
+#include <utils/Trace.h>
+#include <system/camera_vendor_tags.h>
+#include <system/camera_metadata.h>
+#include <system/camera.h>
#include "CameraService.h"
#include "api1/CameraClient.h"
@@ -130,6 +135,12 @@ void CameraService::onFirstRef()
mModule->set_callbacks(this);
}
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+
+ if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {
+ setUpVendorTags();
+ }
+
CameraDeviceFactory::registerService(this);
}
}
@@ -141,6 +152,7 @@ CameraService::~CameraService() {
}
}
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
gCameraService = NULL;
}
@@ -168,6 +180,9 @@ void CameraService::onDeviceStatusChanged(int cameraId,
{
Mutex::Autolock al(mServiceLock);
+ /* Remove cached parameters from shim cache */
+ mShimParams.removeItem(cameraId);
+
/* Find all clients that we need to disconnect */
sp<BasicClient> client = mClient[cameraId].promote();
if (client.get() != NULL) {
@@ -220,12 +235,99 @@ status_t CameraService::getCameraInfo(int cameraId,
}
struct camera_info info;
- status_t rc = mModule->get_camera_info(cameraId, &info);
+ status_t rc = filterGetInfoErrorCode(
+ mModule->get_camera_info(cameraId, &info));
cameraInfo->facing = info.facing;
cameraInfo->orientation = info.orientation;
return rc;
}
+
+status_t CameraService::generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo) {
+ status_t ret = OK;
+ struct CameraInfo info;
+ if ((ret = getCameraInfo(cameraId, &info)) != OK) {
+ return ret;
+ }
+
+ CameraMetadata shimInfo;
+ int32_t orientation = static_cast<int32_t>(info.orientation);
+ if ((ret = shimInfo.update(ANDROID_SENSOR_ORIENTATION, &orientation, 1)) != OK) {
+ return ret;
+ }
+
+ uint8_t facing = (info.facing == CAMERA_FACING_FRONT) ?
+ ANDROID_LENS_FACING_FRONT : ANDROID_LENS_FACING_BACK;
+ if ((ret = shimInfo.update(ANDROID_LENS_FACING, &facing, 1)) != OK) {
+ return ret;
+ }
+
+ CameraParameters shimParams;
+ if ((ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)) != OK) {
+ // Error logged by callee
+ return ret;
+ }
+
+ Vector<Size> sizes;
+ Vector<Size> jpegSizes;
+ Vector<int32_t> formats;
+ const char* supportedPreviewFormats;
+ {
+ shimParams.getSupportedPreviewSizes(/*out*/sizes);
+ shimParams.getSupportedPreviewFormats(/*out*/formats);
+ shimParams.getSupportedPictureSizes(/*out*/jpegSizes);
+ }
+
+ // Always include IMPLEMENTATION_DEFINED
+ formats.add(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
+
+ const size_t INTS_PER_CONFIG = 4;
+
+ // Build available stream configurations metadata
+ size_t streamConfigSize = (sizes.size() * formats.size() + jpegSizes.size()) * INTS_PER_CONFIG;
+
+ Vector<int32_t> streamConfigs;
+ streamConfigs.setCapacity(streamConfigSize);
+
+ for (size_t i = 0; i < formats.size(); ++i) {
+ for (size_t j = 0; j < sizes.size(); ++j) {
+ streamConfigs.add(formats[i]);
+ streamConfigs.add(sizes[j].width);
+ streamConfigs.add(sizes[j].height);
+ streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+ }
+ }
+
+ for (size_t i = 0; i < jpegSizes.size(); ++i) {
+ streamConfigs.add(HAL_PIXEL_FORMAT_BLOB);
+ streamConfigs.add(jpegSizes[i].width);
+ streamConfigs.add(jpegSizes[i].height);
+ streamConfigs.add(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+ }
+
+ if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ streamConfigs.array(), streamConfigSize)) != OK) {
+ return ret;
+ }
+
+ int64_t fakeMinFrames[0];
+ // TODO: Fixme, don't fake min frame durations.
+ if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+ fakeMinFrames, 0)) != OK) {
+ return ret;
+ }
+
+ int64_t fakeStalls[0];
+ // TODO: Fixme, don't fake stall durations.
+ if ((ret = shimInfo.update(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
+ fakeStalls, 0)) != OK) {
+ return ret;
+ }
+
+ *cameraInfo = shimInfo;
+ return OK;
+}
+
status_t CameraService::getCameraCharacteristics(int cameraId,
CameraMetadata* cameraInfo) {
if (!cameraInfo) {
@@ -238,37 +340,51 @@ status_t CameraService::getCameraCharacteristics(int cameraId,
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;
- }
+ status_t ret = OK;
+ if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0 ||
+ getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) {
+ /**
+ * Backwards compatibility mode for old HALs:
+ * - Convert CameraInfo into static CameraMetadata properties.
+ * - Retrieve cached CameraParameters for this camera. If none exist,
+ * attempt to open CameraClient and retrieve the CameraParameters.
+ * - Convert cached CameraParameters into static CameraMetadata
+ * properties.
+ */
+ ALOGI("%s: Switching to HAL1 shim implementation...", __FUNCTION__);
+
+ if ((ret = generateShimMetadata(cameraId, cameraInfo)) != OK) {
+ return ret;
+ }
- 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;
+ } else {
+ /**
+ * Normal HAL 2.1+ codepath.
+ */
+ struct camera_info info;
+ ret = filterGetInfoErrorCode(mModule->get_camera_info(cameraId, &info));
+ *cameraInfo = info.static_camera_characteristics;
}
- struct camera_info info;
- status_t ret = mModule->get_camera_info(cameraId, &info);
- *cameraInfo = info.static_camera_characteristics;
-
return ret;
}
+status_t CameraService::getCameraVendorTagDescriptor(/*out*/sp<VendorTagDescriptor>& desc) {
+ if (!mModule) {
+ ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+ return OK;
+}
+
int CameraService::getDeviceVersion(int cameraId, int* facing) {
struct camera_info info;
if (mModule->get_camera_info(cameraId, &info) != OK) {
@@ -289,21 +405,162 @@ int CameraService::getDeviceVersion(int cameraId, int* facing) {
return deviceVersion;
}
-bool CameraService::isValidCameraId(int cameraId) {
- int facing;
- int deviceVersion = getDeviceVersion(cameraId, &facing);
+status_t CameraService::filterOpenErrorCode(status_t err) {
+ switch(err) {
+ case NO_ERROR:
+ case -EBUSY:
+ case -EINVAL:
+ case -EUSERS:
+ return err;
+ default:
+ break;
+ }
+ return -ENODEV;
+}
- switch(deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_1_0:
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
- case CAMERA_DEVICE_API_VERSION_3_0:
- return true;
- default:
+status_t CameraService::filterGetInfoErrorCode(status_t err) {
+ switch(err) {
+ case NO_ERROR:
+ case -EINVAL:
+ return err;
+ default:
+ break;
+ }
+ return -ENODEV;
+}
+
+bool CameraService::setUpVendorTags() {
+ vendor_tag_ops_t vOps = vendor_tag_ops_t();
+
+ // Check if vendor operations have been implemented
+ if (mModule->get_vendor_tag_ops == NULL) {
+ ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
return false;
}
- return false;
+ ATRACE_BEGIN("camera3->get_metadata_vendor_tag_ops");
+ mModule->get_vendor_tag_ops(&vOps);
+ ATRACE_END();
+
+ // Ensure all vendor operations are present
+ if (vOps.get_tag_count == NULL || vOps.get_all_tags == NULL ||
+ vOps.get_section_name == NULL || vOps.get_tag_name == NULL ||
+ vOps.get_tag_type == NULL) {
+ ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions."
+ , __FUNCTION__);
+ return false;
+ }
+
+ // Read all vendor tag definitions into a descriptor
+ sp<VendorTagDescriptor> desc;
+ status_t res;
+ if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc))
+ != OK) {
+ ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+ "received error %s (%d). Camera clients will not be able to use"
+ "vendor tags", __FUNCTION__, strerror(res), res);
+ return false;
+ }
+
+ // Set the global descriptor to use with camera metadata
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+ return true;
+}
+
+status_t CameraService::initializeShimMetadata(int cameraId) {
+ int pid = getCallingPid();
+ int uid = getCallingUid();
+ status_t ret = validateConnect(cameraId, uid);
+ if (ret != OK) {
+ // Error already logged by callee
+ return ret;
+ }
+
+ bool needsNewClient = false;
+ sp<Client> client;
+
+ String16 internalPackageName("media");
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ if (mClient[cameraId] != NULL) {
+ client = static_cast<Client*>(mClient[cameraId].promote().get());
+ }
+ if (client == NULL) {
+ needsNewClient = true;
+ ret = connectHelperLocked(/*out*/client,
+ /*cameraClient*/NULL, // Empty binder callbacks
+ cameraId,
+ internalPackageName,
+ uid,
+ pid);
+
+ if (ret != OK) {
+ // Error already logged by callee
+ return ret;
+ }
+ }
+
+ if (client == NULL) {
+ ALOGE("%s: Could not connect to client camera device.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ String8 rawParams = client->getParameters();
+ CameraParameters params(rawParams);
+ mShimParams.add(cameraId, params);
+ }
+
+ // Close client if one was opened solely for this call
+ if (needsNewClient) {
+ client->disconnect();
+ }
+ return OK;
+}
+
+status_t CameraService::getLegacyParametersLazy(int cameraId,
+ /*out*/
+ CameraParameters* parameters) {
+
+ ALOGV("%s: for cameraId: %d", __FUNCTION__, cameraId);
+
+ status_t ret = 0;
+
+ if (parameters == NULL) {
+ ALOGE("%s: parameters must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ ssize_t index = -1;
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ index = mShimParams.indexOfKey(cameraId);
+ // Release service lock so initializeShimMetadata can be called correctly.
+
+ if (index >= 0) {
+ *parameters = mShimParams[index];
+ }
+ }
+
+ if (index < 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ ret = initializeShimMetadata(cameraId);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ if (ret != OK) {
+ // Error already logged by callee
+ return ret;
+ }
+
+ { // Scope for service lock
+ Mutex::Autolock lock(mServiceLock);
+ index = mShimParams.indexOfKey(cameraId);
+
+ LOG_ALWAYS_FATAL_IF(index < 0, "index should have been initialized");
+
+ *parameters = mShimParams[index];
+ }
+ }
+
+ return OK;
}
status_t CameraService::validateConnect(int cameraId,
@@ -402,6 +659,77 @@ bool CameraService::canConnectUnsafe(int cameraId,
return true;
}
+status_t CameraService::connectHelperLocked(
+ /*out*/
+ sp<Client>& client,
+ /*in*/
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ int callingPid,
+ int halVersion,
+ bool legacyMode) {
+
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ if (halVersion < 0 || halVersion == deviceVersion) {
+ // Default path: HAL version is unspecified by caller, create CameraClient
+ // based on device version reported by the HAL.
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ client = new CameraClient(this, cameraClient,
+ clientPackageName, cameraId,
+ facing, callingPid, clientUid, getpid(), legacyMode);
+ break;
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ client = new Camera2Client(this, cameraClient,
+ clientPackageName, cameraId,
+ facing, callingPid, clientUid, getpid(), legacyMode);
+ break;
+ case -1:
+ ALOGE("Invalid camera id %d", cameraId);
+ return BAD_VALUE;
+ default:
+ ALOGE("Unknown camera device HAL version: %d", deviceVersion);
+ return INVALID_OPERATION;
+ }
+ } else {
+ // A particular HAL version is requested by caller. Create CameraClient
+ // based on the requested HAL version.
+ if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
+ halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+ // Only support higher HAL version device opened as HAL1.0 device.
+ client = new CameraClient(this, cameraClient,
+ clientPackageName, cameraId,
+ facing, callingPid, clientUid, getpid(), legacyMode);
+ } else {
+ // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
+ ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
+ " opened as HAL %x device", halVersion, deviceVersion,
+ CAMERA_DEVICE_API_VERSION_1_0);
+ return INVALID_OPERATION;
+ }
+ }
+
+ status_t status = connectFinishUnsafe(client, client->getRemote());
+ if (status != OK) {
+ // this is probably not recoverable.. maybe the client can try again
+ return status;
+ }
+
+ mClient[cameraId] = client;
+ LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
+ getpid());
+
+ return OK;
+}
+
status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
@@ -435,50 +763,81 @@ status_t CameraService::connect(
return OK;
}
- 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);
+ status = connectHelperLocked(/*out*/client,
+ cameraClient,
+ cameraId,
+ clientPackageName,
+ clientUid,
+ callingPid);
+ if (status != OK) {
+ return status;
}
- switch(deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_1_0:
- client = new CameraClient(this, cameraClient,
- clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid());
- break;
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
- case CAMERA_DEVICE_API_VERSION_3_0:
- client = new Camera2Client(this, cameraClient,
- clientPackageName, cameraId,
- facing, callingPid, clientUid, getpid(),
- deviceVersion);
- break;
- case -1:
- ALOGE("Invalid camera id %d", cameraId);
- return BAD_VALUE;
- default:
- ALOGE("Unknown camera device HAL version: %d", deviceVersion);
- return INVALID_OPERATION;
+ }
+ // 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::connectLegacy(
+ const sp<ICameraClient>& cameraClient,
+ int cameraId, int halVersion,
+ const String16& clientPackageName,
+ int clientUid,
+ /*out*/
+ sp<ICamera>& device) {
+
+ if (halVersion != CAMERA_HAL_API_VERSION_UNSPECIFIED &&
+ mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_3) {
+ /*
+ * Either the HAL version is unspecified in which case this just creates
+ * a camera client selected by the latest device version, or
+ * it's a particular version in which case the HAL must supported
+ * the open_legacy call
+ */
+ ALOGE("%s: camera HAL module version %x doesn't support connecting to legacy HAL devices!",
+ __FUNCTION__, mModule->common.module_api_version);
+ return INVALID_OPERATION;
+ }
+
+ String8 clientName8(clientPackageName);
+ int callingPid = getCallingPid();
+
+ LOG1("CameraService::connect legacy E (pid %d \"%s\", id %d)", callingPid,
+ clientName8.string(), cameraId);
+
+ status_t status = validateConnect(cameraId, /*inout*/clientUid);
+ if (status != OK) {
+ return status;
+ }
+
+ sp<Client> client;
+ {
+ Mutex::Autolock lock(mServiceLock);
+ sp<BasicClient> clientTmp;
+ if (!canConnectUnsafe(cameraId, clientPackageName,
+ cameraClient->asBinder(),
+ /*out*/clientTmp)) {
+ return -EBUSY;
+ } else if (client.get() != NULL) {
+ device = static_cast<Client*>(clientTmp.get());
+ return OK;
}
- status_t status = connectFinishUnsafe(client, client->getRemote());
+ status = connectHelperLocked(/*out*/client,
+ cameraClient,
+ cameraId,
+ clientPackageName,
+ clientUid,
+ callingPid,
+ halVersion,
+ /*legacyMode*/true);
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;
}
- mClient[cameraId] = client;
- LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
- getpid());
}
// 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)
@@ -493,8 +852,9 @@ status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
if (status != OK) {
return status;
}
-
- remoteCallback->linkToDeath(this);
+ if (remoteCallback != NULL) {
+ remoteCallback->linkToDeath(this);
+ }
return OK;
}
@@ -507,6 +867,11 @@ status_t CameraService::connectPro(
/*out*/
sp<IProCameraUser>& device)
{
+ if (cameraCb == 0) {
+ ALOGE("%s: Callback must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
@@ -541,8 +906,10 @@ status_t CameraService::connectPro(
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());
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ client = new ProCamera2Client(this, cameraCb, clientPackageName,
+ cameraId, facing, callingPid, clientUid, getpid());
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
@@ -603,14 +970,6 @@ status_t CameraService::connectDevice(
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);
@@ -619,8 +978,10 @@ status_t CameraService::connectDevice(
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());
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ client = new CameraDeviceClient(this, cameraCb, clientPackageName,
+ cameraId, facing, callingPid, clientUid, getpid());
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
@@ -633,8 +994,6 @@ status_t CameraService::connectDevice(
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;
}
@@ -709,6 +1068,78 @@ status_t CameraService::removeListener(
return BAD_VALUE;
}
+status_t CameraService::getLegacyParameters(
+ int cameraId,
+ /*out*/
+ String16* parameters) {
+ ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
+
+ if (parameters == NULL) {
+ ALOGE("%s: parameters must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ status_t ret = 0;
+
+ CameraParameters shimParams;
+ if ((ret = getLegacyParametersLazy(cameraId, /*out*/&shimParams)) != OK) {
+ // Error logged by caller
+ return ret;
+ }
+
+ String8 shimParamsString8 = shimParams.flatten();
+ String16 shimParamsString16 = String16(shimParamsString8);
+
+ *parameters = shimParamsString16;
+
+ return OK;
+}
+
+status_t CameraService::supportsCameraApi(int cameraId, int apiVersion) {
+ ALOGV("%s: for camera ID = %d", __FUNCTION__, cameraId);
+
+ switch (apiVersion) {
+ case API_VERSION_1:
+ case API_VERSION_2:
+ break;
+ default:
+ ALOGE("%s: Bad API version %d", __FUNCTION__, apiVersion);
+ return BAD_VALUE;
+ }
+
+ int facing = -1;
+ int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+ switch(deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ if (apiVersion == API_VERSION_2) {
+ ALOGV("%s: Camera id %d uses HAL prior to HAL3.2, doesn't support api2 without shim",
+ __FUNCTION__, cameraId);
+ return -EOPNOTSUPP;
+ } else { // if (apiVersion == API_VERSION_1) {
+ ALOGV("%s: Camera id %d uses older HAL before 3.2, but api1 is always supported",
+ __FUNCTION__, cameraId);
+ return OK;
+ }
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ ALOGV("%s: Camera id %d uses HAL3.2 or newer, supports api1/api2 directly",
+ __FUNCTION__, cameraId);
+ return OK;
+ case -1:
+ ALOGE("%s: Invalid camera id %d", __FUNCTION__, cameraId);
+ return BAD_VALUE;
+ default:
+ ALOGE("%s: Unknown camera device HAL version: %d", __FUNCTION__, deviceVersion);
+ return INVALID_OPERATION;
+ }
+
+ return OK;
+}
+
void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
int callingPid = getCallingPid();
LOG1("CameraService::removeClientByRemote E (pid %d)", callingPid);
@@ -723,9 +1154,13 @@ void CameraService::removeClientByRemote(const wp<IBinder>& remoteBinder) {
if (client != 0) {
// Found our camera, clear and leave.
LOG1("removeClient: clear camera %d", outIndex);
- mClient[outIndex].clear();
- client->getRemote()->unlinkToDeath(this);
+ sp<IBinder> remote = client->getRemote();
+ if (remote != NULL) {
+ remote->unlinkToDeath(this);
+ }
+
+ mClient[outIndex].clear();
} else {
sp<ProClient> clientPro = findProClientUnsafe(remoteBinder);
@@ -834,6 +1269,8 @@ status_t CameraService::onTransact(
switch (code) {
case BnCameraService::CONNECT:
case BnCameraService::CONNECT_PRO:
+ case BnCameraService::CONNECT_DEVICE:
+ case BnCameraService::CONNECT_LEGACY:
const int pid = getCallingPid();
const int self_pid = getpid();
if (pid != self_pid) {
@@ -876,7 +1313,7 @@ void CameraService::setCameraFree(int cameraId) {
MediaPlayer* CameraService::newMediaPlayer(const char *file) {
MediaPlayer* mp = new MediaPlayer();
- if (mp->setDataSource(file, NULL) == NO_ERROR) {
+ if (mp->setDataSource(NULL /* httpService */, file, NULL) == NO_ERROR) {
mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
mp->prepare();
} else {
@@ -980,13 +1417,15 @@ CameraService::BasicClient::~BasicClient() {
void CameraService::BasicClient::disconnect() {
ALOGV("BasicClient::disconnect");
mCameraService->removeClientByRemote(mRemoteBinder);
+
+ finishCameraOps();
// client shouldn't be able to call into us anymore
mClientPid = 0;
}
status_t CameraService::BasicClient::startCameraOps() {
int32_t res;
-
+ // Notify app ops that the camera is not available
mOpsCallback = new OpsCallback(this);
{
@@ -1004,16 +1443,39 @@ status_t CameraService::BasicClient::startCameraOps() {
mCameraId, String8(mClientPackageName).string());
return PERMISSION_DENIED;
}
+
mOpsActive = true;
+
+ // Transition device availability listeners from PRESENT -> NOT_AVAILABLE
+ mCameraService->updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+ mCameraId);
+
return OK;
}
status_t CameraService::BasicClient::finishCameraOps() {
+ // Check if startCameraOps succeeded, and if so, finish the camera op
if (mOpsActive) {
+ // Notify app ops that the camera is available again
mAppOpsManager.finishOp(AppOpsManager::OP_CAMERA, mClientUid,
mClientPackageName);
mOpsActive = false;
+
+ // Notify device availability listeners that this camera is available
+ // again
+
+ StatusVector rejectSourceStates;
+ rejectSourceStates.push_back(ICameraServiceListener::STATUS_NOT_PRESENT);
+ rejectSourceStates.push_back(ICameraServiceListener::STATUS_ENUMERATING);
+
+ // Transition to PRESENT if the camera is not in either of above 2
+ // states
+ mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
+ mCameraId,
+ &rejectSourceStates);
+
}
+ // Always stop watching, even if no camera op is active
mAppOpsManager.stopWatchingMode(mOpsCallback);
mOpsCallback.clear();
@@ -1044,7 +1506,8 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16& packageNa
// Reset the client PID to allow server-initiated disconnect,
// and to prevent further calls by client.
mClientPid = getCallingPid();
- notifyError();
+ CaptureResultExtras resultExtras; // a dummy result (invalid)
+ notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE, resultExtras);
disconnect();
}
}
@@ -1073,7 +1536,8 @@ CameraService::Client* CameraService::Client::getClientFromCookie(void* user) {
return client;
}
-void CameraService::Client::notifyError() {
+void CameraService::Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
}
@@ -1082,15 +1546,6 @@ void CameraService::Client::disconnect() {
ALOGV("Client::disconnect");
BasicClient::disconnect();
mCameraService->setCameraFree(mCameraId);
-
- StatusVector rejectSourceStates;
- rejectSourceStates.push_back(ICameraServiceListener::STATUS_NOT_PRESENT);
- rejectSourceStates.push_back(ICameraServiceListener::STATUS_ENUMERATING);
-
- // Transition to PRESENT if the camera is not in either of above 2 states
- mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
- mCameraId,
- &rejectSourceStates);
}
CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
@@ -1127,7 +1582,8 @@ CameraService::ProClient::ProClient(const sp<CameraService>& cameraService,
CameraService::ProClient::~ProClient() {
}
-void CameraService::ProClient::notifyError() {
+void CameraService::ProClient::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
}
@@ -1182,7 +1638,20 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
result.appendFormat("Camera module author: %s\n",
mModule->common.author);
result.appendFormat("Number of camera devices: %d\n\n", mNumberOfCameras);
+
+ sp<VendorTagDescriptor> desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
+ if (desc == NULL) {
+ result.appendFormat("Vendor tags left unimplemented.\n");
+ } else {
+ result.appendFormat("Vendor tag definitions:\n");
+ }
+
write(fd, result.string(), result.size());
+
+ if (desc != NULL) {
+ desc->dump(fd, /*verbosity*/2, /*indentation*/4);
+ }
+
for (int i = 0; i < mNumberOfCameras; i++) {
result = String8::format("Camera %d static information:\n", i);
camera_info info;
@@ -1207,7 +1676,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
result.appendFormat(" Device static metadata:\n");
write(fd, result.string(), result.size());
dump_indented_camera_metadata(info.static_camera_characteristics,
- fd, 2, 4);
+ fd, /*verbosity*/2, /*indentation*/4);
} else {
write(fd, result.string(), result.size());
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ad6a582..a7328cf 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -1,24 +1,24 @@
/*
-**
-** Copyright (C) 2008, 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.
-*/
+ * Copyright (C) 2008 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_CAMERASERVICE_H
#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H
#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IAppOpsCallback.h>
@@ -31,6 +31,9 @@
#include <camera/IProCameraCallbacks.h>
#include <camera/camera2/ICameraDeviceUser.h>
#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/VendorTagDescriptor.h>
+#include <camera/CaptureResult.h>
+#include <camera/CameraParameters.h>
#include <camera/ICameraServiceListener.h>
@@ -73,12 +76,18 @@ public:
struct CameraInfo* cameraInfo);
virtual status_t getCameraCharacteristics(int cameraId,
CameraMetadata* cameraInfo);
+ virtual status_t getCameraVendorTagDescriptor(/*out*/ sp<VendorTagDescriptor>& desc);
virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
const String16& clientPackageName, int clientUid,
/*out*/
sp<ICamera>& device);
+ virtual status_t connectLegacy(const sp<ICameraClient>& cameraClient, int cameraId,
+ int halVersion, 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*/
@@ -96,6 +105,15 @@ public:
virtual status_t removeListener(
const sp<ICameraServiceListener>& listener);
+ virtual status_t getLegacyParameters(
+ int cameraId,
+ /*out*/
+ String16* parameters);
+
+ // OK = supports api of that version, -EOPNOTSUPP = does not support
+ virtual status_t supportsCameraApi(
+ int cameraId, int apiVersion);
+
// Extra permissions checks
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -120,6 +138,10 @@ public:
// CameraDeviceFactory functionality
int getDeviceVersion(int cameraId, int* facing = NULL);
+ /////////////////////////////////////////////////////////////////////
+ // Shared utilities
+ static status_t filterOpenErrorCode(status_t err);
+ static status_t filterGetInfoErrorCode(status_t err);
/////////////////////////////////////////////////////////////////////
// CameraClient functionality
@@ -131,20 +153,19 @@ public:
class BasicClient : public virtual RefBase {
public:
- virtual status_t initialize(camera_module_t *module) = 0;
-
- virtual void disconnect() = 0;
+ virtual status_t initialize(camera_module_t *module) = 0;
+ virtual void disconnect();
// 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)
- sp<IBinder> getRemote() {
+ sp<IBinder> getRemote() {
return mRemoteBinder;
}
- virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+ virtual status_t dump(int fd, const Vector<String16>& args) = 0;
protected:
BasicClient(const sp<CameraService>& cameraService,
@@ -181,7 +202,9 @@ public:
status_t finishCameraOps();
// Notify client about a fatal error
- virtual void notifyError() = 0;
+ virtual void notifyError(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) = 0;
private:
AppOpsManager mAppOpsManager;
@@ -258,7 +281,8 @@ public:
// convert client from cookie. Client lock should be acquired before getting Client.
static Client* getClientFromCookie(void* user);
- virtual void notifyError();
+ virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
// Initialized in constructor
@@ -306,7 +330,8 @@ public:
virtual void onExclusiveLockStolen() = 0;
protected:
- virtual void notifyError();
+ virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
sp<IProCameraCallbacks> mRemoteCallback;
}; // class ProClient
@@ -387,6 +412,57 @@ private:
// Helpers
bool isValidCameraId(int cameraId);
+
+ bool setUpVendorTags();
+
+ /**
+ * A mapping of camera ids to CameraParameters returned by that camera device.
+ *
+ * This cache is used to generate CameraCharacteristic metadata when using
+ * the HAL1 shim.
+ */
+ KeyedVector<int, CameraParameters> mShimParams;
+
+ /**
+ * Initialize and cache the metadata used by the HAL1 shim for a given cameraId.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t initializeShimMetadata(int cameraId);
+
+ /**
+ * Get the cached CameraParameters for the camera. If they haven't been
+ * cached yet, then initialize them for the first time.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t getLegacyParametersLazy(int cameraId, /*out*/CameraParameters* parameters);
+
+ /**
+ * Generate the CameraCharacteristics metadata required by the Camera2 API
+ * from the available HAL1 CameraParameters and CameraInfo.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t generateShimMetadata(int cameraId, /*out*/CameraMetadata* cameraInfo);
+
+ /**
+ * Connect a new camera client. This should only be used while holding the
+ * mutex for mServiceLock.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t connectHelperLocked(
+ /*out*/
+ sp<Client>& client,
+ /*in*/
+ const sp<ICameraClient>& cameraClient,
+ int cameraId,
+ const String16& clientPackageName,
+ int clientUid,
+ int callingPid,
+ int halVersion = CAMERA_HAL_API_VERSION_UNSPECIFIED,
+ bool legacyMode = false);
};
} // namespace android
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index af23557..2a6aa7b 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -54,16 +54,17 @@ Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
int clientPid,
uid_t clientUid,
int servicePid,
- int deviceVersion):
+ bool legacyMode):
Camera2ClientBase(cameraService, cameraClient, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
- mParameters(cameraId, cameraFacing),
- mDeviceVersion(deviceVersion)
+ mParameters(cameraId, cameraFacing)
{
ATRACE_CALL();
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
+
+ mLegacyMode = legacyMode;
}
status_t Camera2Client::initialize(camera_module_t *module)
@@ -80,7 +81,7 @@ status_t Camera2Client::initialize(camera_module_t *module)
{
SharedParameters::Lock l(mParameters);
- res = l.mParameters.initialize(&(mDevice->info()));
+ res = l.mParameters.initialize(&(mDevice->info()), mDeviceVersion);
if (res != OK) {
ALOGE("%s: Camera %d: unable to build defaults: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -118,7 +119,9 @@ status_t Camera2Client::initialize(camera_module_t *module)
mZslProcessorThread = zslProc;
break;
}
- case CAMERA_DEVICE_API_VERSION_3_0:{
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2: {
sp<ZslProcessor3> zslProc =
new ZslProcessor3(this, mCaptureSequencer);
mZslProcessor = zslProc;
@@ -238,7 +241,7 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
result.append(" Scene mode: ");
switch (p.sceneMode) {
- case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+ case ANDROID_CONTROL_SCENE_MODE_DISABLED:
result.append("AUTO\n"); break;
CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PORTRAIT)
@@ -431,6 +434,9 @@ void Camera2Client::disconnect() {
mCallbackProcessor->deleteStream();
mZslProcessor->deleteStream();
+ // Remove all ZSL stream state before disconnect; needed to work around b/15408128.
+ mZslProcessor->disconnect();
+
ALOGV("Camera %d: Disconnecting device", mCameraId);
mDevice->disconnect();
@@ -753,6 +759,7 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
// ever take a picture.
// TODO: Find a better compromise, though this likely would involve HAL
// changes.
+ int lastJpegStreamId = mJpegProcessor->getStreamId();
res = updateProcessorStream(mJpegProcessor, params);
if (res != OK) {
ALOGE("%s: Camera %d: Can't pre-configure still image "
@@ -760,6 +767,7 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+ bool jpegStreamChanged = mJpegProcessor->getStreamId() != lastJpegStreamId;
Vector<int32_t> outputStreams;
bool callbacksEnabled = (params.previewCallbackFlags &
@@ -808,14 +816,24 @@ status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
return res;
}
}
- if (params.zslMode && !params.recordingHint) {
+
+ if (params.zslMode && !params.recordingHint &&
+ getRecordingStreamId() == NO_STREAM) {
res = updateProcessorStream(mZslProcessor, params);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update ZSL stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
+
+ if (jpegStreamChanged) {
+ ALOGV("%s: Camera %d: Clear ZSL buffer queue when Jpeg size is changed",
+ __FUNCTION__, mCameraId);
+ mZslProcessor->clearZslQueue();
+ }
outputStreams.push(getZslStreamId());
+ } else {
+ mZslProcessor->deleteStream();
}
outputStreams.push(getPreviewStreamId());
@@ -896,6 +914,20 @@ void Camera2Client::stopPreviewL() {
ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
}
+ // Clean up recording stream
+ res = mStreamingProcessor->deleteRecordingStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete recording stream before "
+ "stop preview: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ {
+ // Ideally we should recover the override after recording stopped, but
+ // right now recording stream will live until here, so we are forced to
+ // recover here. TODO: find a better way to handle that (b/17495165)
+ SharedParameters::Lock l(mParameters);
+ l.mParameters.recoverOverriddenJpegSize();
+ }
// no break
case Parameters::WAITING_FOR_PREVIEW_WINDOW: {
SharedParameters::Lock l(mParameters);
@@ -963,6 +995,10 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
case Parameters::STOPPED:
res = startPreviewL(params, false);
if (res != OK) return res;
+ // Make sure first preview request is submitted to the HAL device to avoid
+ // two consecutive set of configure_streams being called into the HAL.
+ // TODO: Refactor this to avoid initial preview configuration.
+ syncWithDevice();
break;
case Parameters::PREVIEW:
// Ready to go
@@ -1016,18 +1052,95 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
return res;
}
}
+
+ // On current HALs, clean up ZSL before transitioning into recording
+ if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
+ if (mZslProcessor->getStreamId() != NO_STREAM) {
+ ALOGV("%s: Camera %d: Clearing out zsl stream before "
+ "creating recording stream", __FUNCTION__, mCameraId);
+ res = mStreamingProcessor->stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ res = mZslProcessor->clearZslQueue();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't clear zsl queue",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mZslProcessor->deleteStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete zsl stream before "
+ "record: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ }
+ }
+
// Disable callbacks if they're enabled; can't record and use callbacks,
// and we can't fail record start without stagefright asserting.
params.previewCallbackFlags = 0;
- res = updateProcessorStream<
- StreamingProcessor,
- &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
- params);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- return res;
+ if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
+ // For newer devices, may need to reconfigure video snapshot JPEG sizes
+ // during recording startup, so need a more complex sequence here to
+ // ensure an early stream reconfiguration doesn't happen
+ bool recordingStreamNeedsUpdate;
+ res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't query recording stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+
+ if (recordingStreamNeedsUpdate) {
+ // Need to stop stream here so updateProcessorStream won't trigger configureStream
+ // Right now camera device cannot handle configureStream failure gracefully
+ // when device is streaming
+ res = mStreamingProcessor->stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming to update record "
+ "stream", __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ }
+
+ res = updateProcessorStream<
+ StreamingProcessor,
+ &StreamingProcessor::updateRecordingStream>(
+ mStreamingProcessor,
+ params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording stream: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
+ }
+ }
+ } else {
+ // Maintain call sequencing for HALv2 devices.
+ res = updateProcessorStream<
+ StreamingProcessor,
+ &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
+ params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ return res;
+ }
}
Vector<int32_t> outputStreams;
@@ -1036,6 +1149,16 @@ status_t Camera2Client::startRecordingL(Parameters &params, bool restart) {
res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
outputStreams);
+
+ // startStream might trigger a configureStream call and device might fail
+ // configureStream due to jpeg size > video size. Try again with jpeg size overridden
+ // to video size.
+ if (res == BAD_VALUE) {
+ overrideVideoSnapshotSize(params);
+ res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
+ outputStreams);
+ }
+
if (res != OK) {
ALOGE("%s: Camera %d: Unable to start recording stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -1120,6 +1243,8 @@ status_t Camera2Client::autoFocus() {
{
SharedParameters::Lock l(mParameters);
if (l.mParameters.state < Parameters::PREVIEW) {
+ ALOGE("%s: Camera %d: Call autoFocus when preview is inactive (state = %d).",
+ __FUNCTION__, mCameraId, l.mParameters.state);
return INVALID_OPERATION;
}
@@ -1162,7 +1287,7 @@ status_t Camera2Client::autoFocus() {
* Handle quirk mode for AF in scene modes
*/
if (l.mParameters.quirks.triggerAfWithAuto &&
- l.mParameters.sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED &&
+ l.mParameters.sceneMode != ANDROID_CONTROL_SCENE_MODE_DISABLED &&
l.mParameters.focusMode != Parameters::FOCUS_MODE_AUTO &&
!l.mParameters.focusingAreas[0].isEmpty()) {
ALOGV("%s: Quirk: Switching from focusMode %d to AUTO",
@@ -1219,6 +1344,9 @@ status_t Camera2Client::cancelAutoFocus() {
return OK;
}
+ if (l.mParameters.zslMode) {
+ mZslProcessor->clearZslQueue();
+ }
}
syncWithDevice();
@@ -1266,13 +1394,28 @@ status_t Camera2Client::takePicture(int msgType) {
ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);
+ int lastJpegStreamId = mJpegProcessor->getStreamId();
res = updateProcessorStream(mJpegProcessor, l.mParameters);
+ // If video snapshot fail to configureStream, try override video snapshot size to
+ // video size
+ if (res == BAD_VALUE && l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
+ overrideVideoSnapshotSize(l.mParameters);
+ res = updateProcessorStream(mJpegProcessor, l.mParameters);
+ }
if (res != OK) {
ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
return res;
}
takePictureCounter = ++l.mParameters.takePictureCounter;
+
+ // Clear ZSL buffer queue when Jpeg size is changed.
+ bool jpegStreamChanged = mJpegProcessor->getStreamId() != lastJpegStreamId;
+ if (l.mParameters.zslMode && jpegStreamChanged) {
+ ALOGV("%s: Camera %d: Clear ZSL buffer queue when Jpeg size is changed",
+ __FUNCTION__, mCameraId);
+ mZslProcessor->clearZslQueue();
+ }
}
ATRACE_ASYNC_BEGIN(kTakepictureLabel, takePictureCounter);
@@ -1298,8 +1441,14 @@ status_t Camera2Client::setParameters(const String8& params) {
SharedParameters::Lock l(mParameters);
+ Parameters::focusMode_t focusModeBefore = l.mParameters.focusMode;
res = l.mParameters.set(params);
if (res != OK) return res;
+ Parameters::focusMode_t focusModeAfter = l.mParameters.focusMode;
+
+ if (l.mParameters.zslMode && focusModeAfter != focusModeBefore) {
+ mZslProcessor->clearZslQueue();
+ }
res = updateRequests(l.mParameters);
@@ -1310,7 +1459,8 @@ String8 Camera2Client::getParameters() const {
ATRACE_CALL();
ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
Mutex::Autolock icl(mBinderSerializationLock);
- if ( checkPid(__FUNCTION__) != OK) return String8();
+ // The camera service can unconditionally get the parameters at all times
+ if (getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
SharedParameters::ReadLock l(mParameters);
@@ -1390,6 +1540,13 @@ status_t Camera2Client::commandEnableShutterSoundL(bool enable) {
return OK;
}
+ // the camera2 api legacy mode can unconditionally disable the shutter sound
+ if (mLegacyMode) {
+ ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
+ l.mParameters.playShutterSound = false;
+ return OK;
+ }
+
// Disabling shutter sound may not be allowed. In that case only
// allow the mediaserver process to disable the sound.
char value[PROPERTY_VALUE_MAX];
@@ -1655,8 +1812,8 @@ int Camera2Client::getZslStreamId() const {
}
status_t Camera2Client::registerFrameListener(int32_t minId, int32_t maxId,
- wp<camera2::FrameProcessor::FilteredListener> listener) {
- return mFrameProcessor->registerListener(minId, maxId, listener);
+ wp<camera2::FrameProcessor::FilteredListener> listener, bool sendPartials) {
+ return mFrameProcessor->registerListener(minId, maxId, listener, sendPartials);
}
status_t Camera2Client::removeFrameListener(int32_t minId, int32_t maxId,
@@ -1825,6 +1982,18 @@ status_t Camera2Client::updateProcessorStream(sp<ProcessorT> processor,
return res;
}
+status_t Camera2Client::overrideVideoSnapshotSize(Parameters &params) {
+ ALOGV("%s: Camera %d: configure still size to video size before recording"
+ , __FUNCTION__, mCameraId);
+ params.overrideJpegSizeByVideoSize();
+ status_t res = updateProcessorStream(mJpegProcessor, params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't override video snapshot size to video size: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ return res;
+}
+
const char* Camera2Client::kAutofocusLabel = "autofocus";
const char* Camera2Client::kTakepictureLabel = "take_picture";
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index fe0bf74..d68bb29 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -90,7 +90,7 @@ public:
int clientPid,
uid_t clientUid,
int servicePid,
- int deviceVersion);
+ bool legacyMode);
virtual ~Camera2Client();
@@ -118,7 +118,8 @@ public:
int getZslStreamId() const;
status_t registerFrameListener(int32_t minId, int32_t maxId,
- wp<camera2::FrameProcessor::FilteredListener> listener);
+ wp<camera2::FrameProcessor::FilteredListener> listener,
+ bool sendPartials = true);
status_t removeFrameListener(int32_t minId, int32_t maxId,
wp<camera2::FrameProcessor::FilteredListener> listener);
@@ -170,7 +171,6 @@ private:
void setPreviewCallbackFlagL(Parameters &params, int flag);
status_t updateRequests(Parameters &params);
- int mDeviceVersion;
// Used with stream IDs
static const int NO_STREAM = -1;
@@ -204,9 +204,13 @@ private:
bool mAfInMotion;
/** Utility members */
+ bool mLegacyMode;
// Wait until the camera device has received the latest control settings
status_t syncWithDevice();
+
+ // Video snapshot jpeg size overriding helper function
+ status_t overrideVideoSnapshotSize(Parameters &params);
};
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 30b7bb8..1a4d9a6 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -38,7 +38,7 @@ CameraClient::CameraClient(const sp<CameraService>& cameraService,
const String16& clientPackageName,
int cameraId, int cameraFacing,
int clientPid, int clientUid,
- int servicePid):
+ int servicePid, bool legacyMode):
Client(cameraService, cameraClient, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid)
{
@@ -54,6 +54,7 @@ CameraClient::CameraClient(const sp<CameraService>& cameraService,
// Callback is disabled by default
mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
+ mLegacyMode = legacyMode;
mPlayShutterSound = true;
LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
}
@@ -79,7 +80,7 @@ status_t CameraClient::initialize(camera_module_t *module) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
- return NO_INIT;
+ return res;
}
mHardware->setCallbacks(notifyCallback,
@@ -121,6 +122,16 @@ status_t CameraClient::dump(int fd, const Vector<String16>& args) {
mClientPid);
len = (len > SIZE - 1) ? SIZE - 1 : len;
write(fd, buffer, len);
+
+ len = snprintf(buffer, SIZE, "Latest set parameters:\n");
+ len = (len > SIZE - 1) ? SIZE - 1 : len;
+ write(fd, buffer, len);
+
+ mLatestSetParameters.dump(fd, args);
+
+ const char *enddump = "\n\n";
+ write(fd, enddump, strlen(enddump));
+
return mHardware->dump(fd, args);
}
@@ -549,6 +560,7 @@ status_t CameraClient::setParameters(const String8& params) {
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
+ mLatestSetParameters = CameraParameters(params);
CameraParameters p(params);
return mHardware->setParameters(p);
}
@@ -556,7 +568,8 @@ status_t CameraClient::setParameters(const String8& params) {
// get preview/capture parameters - key/value pairs
String8 CameraClient::getParameters() const {
Mutex::Autolock lock(mLock);
- if (checkPidAndHardware() != NO_ERROR) return String8();
+ // The camera service can unconditionally get the parameters at all times
+ if (getCallingPid() != mServicePid && checkPidAndHardware() != NO_ERROR) return String8();
String8 params(mHardware->getParameters().flatten());
LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
@@ -575,6 +588,13 @@ status_t CameraClient::enableShutterSound(bool enable) {
return OK;
}
+ // the camera2 api legacy mode can unconditionally disable the shutter sound
+ if (mLegacyMode) {
+ ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
+ mPlayShutterSound = false;
+ return OK;
+ }
+
// Disabling shutter sound may not be allowed. In that case only
// allow the mediaserver process to disable the sound.
char value[PROPERTY_VALUE_MAX];
@@ -929,7 +949,20 @@ void CameraClient::copyFrameAndPostCopiedFrame(
}
previewBuffer = mPreviewBuffer;
- memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
+ void* previewBufferBase = previewBuffer->base();
+ void* heapBase = heap->base();
+
+ if (heapBase == MAP_FAILED) {
+ ALOGE("%s: Failed to mmap heap for preview frame.", __FUNCTION__);
+ mLock.unlock();
+ return;
+ } else if (previewBufferBase == MAP_FAILED) {
+ ALOGE("%s: Failed to mmap preview buffer for preview frame.", __FUNCTION__);
+ mLock.unlock();
+ return;
+ }
+
+ memcpy(previewBufferBase, (uint8_t *) heapBase + offset, size);
sp<MemoryBase> frame = new MemoryBase(previewBuffer, 0, size);
if (frame == 0) {
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 4b89564..63a9d0f 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -64,7 +64,8 @@ public:
int cameraFacing,
int clientPid,
int clientUid,
- int servicePid);
+ int servicePid,
+ bool legacyMode = false);
~CameraClient();
status_t initialize(camera_module_t *module);
@@ -129,6 +130,7 @@ private:
int mPreviewCallbackFlag;
int mOrientation; // Current display orientation
bool mPlayShutterSound;
+ bool mLegacyMode; // camera2 api legacy mode?
// Ensures atomicity among the public methods
mutable Mutex mLock;
@@ -140,6 +142,9 @@ private:
// of the original one), we allocate mPreviewBuffer and reuse it if possible.
sp<MemoryHeapBase> mPreviewBuffer;
+ // Debugging information
+ CameraParameters mLatestSetParameters;
+
// We need to avoid the deadlock when the incoming command thread and
// the CameraHardwareInterface callback thread both want to grab mLock.
// An extra flag is used to tell the callback thread that it should stop
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index d2ac79c..bf3318e 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -110,11 +110,13 @@ status_t CallbackProcessor::updateStream(const Parameters &params) {
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);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mCallbackConsumer = new CpuConsumer(consumer, kCallbackHeapCount);
mCallbackConsumer->setFrameAvailableListener(this);
mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
- mCallbackWindow = new Surface(bq);
+ mCallbackWindow = new Surface(producer);
}
if (mCallbackStreamId != NO_STREAM) {
@@ -153,7 +155,7 @@ status_t CallbackProcessor::updateStream(const Parameters &params) {
callbackFormat, params.previewFormat);
res = device->createStream(mCallbackWindow,
params.previewWidth, params.previewHeight,
- callbackFormat, 0, &mCallbackStreamId);
+ callbackFormat, &mCallbackStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index f5c28ed..9849f4d 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -106,13 +106,12 @@ void CaptureSequencer::notifyAutoExposure(uint8_t newState, int triggerId) {
}
}
-void CaptureSequencer::onFrameAvailable(int32_t requestId,
- const CameraMetadata &frame) {
- ALOGV("%s: Listener found new frame", __FUNCTION__);
+void CaptureSequencer::onResultAvailable(const CaptureResult &result) {
ATRACE_CALL();
+ ALOGV("%s: New result available.", __FUNCTION__);
Mutex::Autolock l(mInputMutex);
- mNewFrameId = requestId;
- mNewFrame = frame;
+ mNewFrameId = result.mResultExtras.requestId;
+ mNewFrame = result.mMetadata;
if (!mNewFrameReceived) {
mNewFrameReceived = true;
mNewFrameSignal.signal();
@@ -351,8 +350,10 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslStart(
return DONE;
}
+ // We don't want to get partial results for ZSL capture.
client->registerFrameListener(mCaptureId, mCaptureId + 1,
- this);
+ this,
+ /*sendPartials*/false);
// TODO: Actually select the right thing here.
res = processor->pushToReprocess(mCaptureId);
@@ -394,8 +395,14 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardStart(
bool isAeConverged = false;
// Get the onFrameAvailable callback when the requestID == mCaptureId
+ // We don't want to get partial results for normal capture, as we need
+ // Get ANDROID_SENSOR_TIMESTAMP from the capture result, but partial
+ // result doesn't have to have this metadata available.
+ // TODO: Update to use the HALv3 shutter notification for remove the
+ // need for this listener and make it faster. see bug 12530628.
client->registerFrameListener(mCaptureId, mCaptureId + 1,
- this);
+ this,
+ /*sendPartials*/false);
{
Mutex::Autolock l(mInputMutex);
@@ -438,11 +445,18 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardPrecaptureWait(
if (mNewAEState) {
if (!mAeInPrecapture) {
// Waiting to see PRECAPTURE state
- if (mAETriggerId == mTriggerId &&
- mAEState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
- ALOGV("%s: Got precapture start", __FUNCTION__);
- mAeInPrecapture = true;
- mTimeoutCount = kMaxTimeoutsForPrecaptureEnd;
+ if (mAETriggerId == mTriggerId) {
+ if (mAEState == ANDROID_CONTROL_AE_STATE_PRECAPTURE) {
+ ALOGV("%s: Got precapture start", __FUNCTION__);
+ mAeInPrecapture = true;
+ mTimeoutCount = kMaxTimeoutsForPrecaptureEnd;
+ } else if (mAEState == ANDROID_CONTROL_AE_STATE_CONVERGED ||
+ mAEState == ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED) {
+ // It is legal to transit to CONVERGED or FLASH_REQUIRED
+ // directly after a trigger.
+ ALOGV("%s: AE is already in good state, start capture", __FUNCTION__);
+ return STANDARD_CAPTURE;
+ }
}
} else {
// Waiting to see PRECAPTURE state end
@@ -585,12 +599,15 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCaptureWait(
entry = mNewFrame.find(ANDROID_SENSOR_TIMESTAMP);
if (entry.count == 0) {
ALOGE("No timestamp field in capture frame!");
- }
- if (entry.data.i64[0] != mCaptureTimestamp) {
- ALOGW("Mismatched capture timestamps: Metadata frame %" PRId64 ","
- " captured buffer %" PRId64,
- entry.data.i64[0],
- mCaptureTimestamp);
+ } else if (entry.count == 1) {
+ if (entry.data.i64[0] != mCaptureTimestamp) {
+ ALOGW("Mismatched capture timestamps: Metadata frame %" PRId64 ","
+ " captured buffer %" PRId64,
+ entry.data.i64[0],
+ mCaptureTimestamp);
+ }
+ } else {
+ ALOGE("Timestamp metadata is malformed!");
}
client->removeFrameListener(mCaptureId, mCaptureId + 1, this);
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 9fb4ee7..d42ab13 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -24,6 +24,7 @@
#include <utils/Mutex.h>
#include <utils/Condition.h>
#include "camera/CameraMetadata.h"
+#include "camera/CaptureResult.h"
#include "Parameters.h"
#include "FrameProcessor.h"
@@ -61,8 +62,8 @@ class CaptureSequencer:
// Notifications about AE state changes
void notifyAutoExposure(uint8_t newState, int triggerId);
- // Notifications from the frame processor
- virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame);
+ // Notification from the frame processor
+ virtual void onResultAvailable(const CaptureResult &result);
// Notifications from the JPEG processor
void onCaptureAvailable(nsecs_t timestamp, sp<MemoryBase> captureBuffer);
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index dd5b27c..312a78c 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -40,7 +40,12 @@ FrameProcessor::FrameProcessor(wp<CameraDeviceBase> device,
{
SharedParameters::Lock l(client->getParameters());
- mUsePartialQuirk = l.mParameters.quirks.partialResults;
+
+ if (client->getCameraDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
+ mUsePartialResult = (mNumPartialResults > 1);
+ } else {
+ mUsePartialResult = l.mParameters.quirks.partialResults;
+ }
// Initialize starting 3A state
m3aState.afTriggerId = l.mParameters.afTriggerCounter;
@@ -55,7 +60,7 @@ FrameProcessor::FrameProcessor(wp<CameraDeviceBase> device,
FrameProcessor::~FrameProcessor() {
}
-bool FrameProcessor::processSingleFrame(CameraMetadata &frame,
+bool FrameProcessor::processSingleFrame(CaptureResult &frame,
const sp<CameraDeviceBase> &device) {
sp<Camera2Client> client = mClient.promote();
@@ -63,17 +68,21 @@ bool FrameProcessor::processSingleFrame(CameraMetadata &frame,
return false;
}
- bool partialResult = false;
- if (mUsePartialQuirk) {
- camera_metadata_entry_t entry;
- entry = frame.find(ANDROID_QUIRKS_PARTIAL_RESULT);
- if (entry.count > 0 &&
- entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
- partialResult = true;
+ bool isPartialResult = false;
+ if (mUsePartialResult) {
+ if (client->getCameraDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
+ isPartialResult = frame.mResultExtras.partialResultCount < mNumPartialResults;
+ } else {
+ camera_metadata_entry_t entry;
+ entry = frame.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT);
+ if (entry.count > 0 &&
+ entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
+ isPartialResult = true;
+ }
}
}
- if (!partialResult && processFaceDetect(frame, client) != OK) {
+ if (!isPartialResult && processFaceDetect(frame.mMetadata, client) != OK) {
return false;
}
@@ -212,14 +221,15 @@ status_t FrameProcessor::processFaceDetect(const CameraMetadata &frame,
return OK;
}
-status_t FrameProcessor::process3aState(const CameraMetadata &frame,
+status_t FrameProcessor::process3aState(const CaptureResult &frame,
const sp<Camera2Client> &client) {
ATRACE_CALL();
+ const CameraMetadata &metadata = frame.mMetadata;
camera_metadata_ro_entry_t entry;
int cameraId = client->getCameraId();
- entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
+ entry = metadata.find(ANDROID_REQUEST_FRAME_COUNT);
int32_t frameNumber = entry.data.i32[0];
// Don't send 3A notifications for the same frame number twice
@@ -238,26 +248,31 @@ status_t FrameProcessor::process3aState(const CameraMetadata &frame,
// TODO: Also use AE mode, AE trigger ID
- gotAllStates &= get3aResult<uint8_t>(frame, ANDROID_CONTROL_AF_MODE,
+ gotAllStates &= get3aResult<uint8_t>(metadata, ANDROID_CONTROL_AF_MODE,
&new3aState.afMode, frameNumber, cameraId);
- gotAllStates &= get3aResult<uint8_t>(frame, ANDROID_CONTROL_AWB_MODE,
+ gotAllStates &= get3aResult<uint8_t>(metadata, ANDROID_CONTROL_AWB_MODE,
&new3aState.awbMode, frameNumber, cameraId);
- gotAllStates &= get3aResult<uint8_t>(frame, ANDROID_CONTROL_AE_STATE,
+ gotAllStates &= get3aResult<uint8_t>(metadata, ANDROID_CONTROL_AE_STATE,
&new3aState.aeState, frameNumber, cameraId);
- gotAllStates &= get3aResult<uint8_t>(frame, ANDROID_CONTROL_AF_STATE,
+ gotAllStates &= get3aResult<uint8_t>(metadata, ANDROID_CONTROL_AF_STATE,
&new3aState.afState, frameNumber, cameraId);
- gotAllStates &= get3aResult<uint8_t>(frame, ANDROID_CONTROL_AWB_STATE,
+ gotAllStates &= get3aResult<uint8_t>(metadata, ANDROID_CONTROL_AWB_STATE,
&new3aState.awbState, frameNumber, cameraId);
- gotAllStates &= get3aResult<int32_t>(frame, ANDROID_CONTROL_AF_TRIGGER_ID,
- &new3aState.afTriggerId, frameNumber, cameraId);
+ if (client->getCameraDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
+ new3aState.afTriggerId = frame.mResultExtras.afTriggerId;
+ new3aState.aeTriggerId = frame.mResultExtras.precaptureTriggerId;
+ } else {
+ gotAllStates &= get3aResult<int32_t>(metadata, ANDROID_CONTROL_AF_TRIGGER_ID,
+ &new3aState.afTriggerId, frameNumber, cameraId);
- gotAllStates &= get3aResult<int32_t>(frame, ANDROID_CONTROL_AE_PRECAPTURE_ID,
- &new3aState.aeTriggerId, frameNumber, cameraId);
+ gotAllStates &= get3aResult<int32_t>(metadata, ANDROID_CONTROL_AE_PRECAPTURE_ID,
+ &new3aState.aeTriggerId, frameNumber, cameraId);
+ }
if (!gotAllStates) return BAD_VALUE;
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.h b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
index 856ad32..68cf55b 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.h
@@ -51,14 +51,14 @@ class FrameProcessor : public FrameProcessorBase {
void processNewFrames(const sp<Camera2Client> &client);
- virtual bool processSingleFrame(CameraMetadata &frame,
+ virtual bool processSingleFrame(CaptureResult &frame,
const sp<CameraDeviceBase> &device);
status_t processFaceDetect(const CameraMetadata &frame,
const sp<Camera2Client> &client);
// Send 3A state change notifications to client based on frame metadata
- status_t process3aState(const CameraMetadata &frame,
+ status_t process3aState(const CaptureResult &frame,
const sp<Camera2Client> &client);
// Helper for process3aState
@@ -91,8 +91,8 @@ class FrameProcessor : public FrameProcessorBase {
}
} m3aState;
- // Whether the partial result quirk is enabled for this device
- bool mUsePartialQuirk;
+ // Whether the partial result is enabled for this device
+ bool mUsePartialResult;
// Track most recent frame number for which 3A notifications were sent for.
// Used to filter against sending 3A notifications for the same frame
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index 2de7a2b..b433781 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -73,30 +73,43 @@ status_t JpegProcessor::updateStream(const Parameters &params) {
}
// Find out buffer size for JPEG
- camera_metadata_ro_entry_t maxJpegSize =
- params.staticInfo(ANDROID_JPEG_MAX_SIZE);
- if (maxJpegSize.count == 0) {
- ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
- __FUNCTION__, mId);
+ ssize_t maxJpegSize = device->getJpegBufferSize(params.pictureWidth, params.pictureHeight);
+ if (maxJpegSize <= 0) {
+ ALOGE("%s: Camera %d: Jpeg buffer size (%zu) is invalid ",
+ __FUNCTION__, mId, maxJpegSize);
return INVALID_OPERATION;
}
if (mCaptureConsumer == 0) {
// Create CPU buffer queue endpoint
- sp<BufferQueue> bq = new BufferQueue();
- mCaptureConsumer = new CpuConsumer(bq, 1);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mCaptureConsumer = new CpuConsumer(consumer, 1);
mCaptureConsumer->setFrameAvailableListener(this);
mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
- mCaptureWindow = new Surface(bq);
+ mCaptureWindow = new Surface(producer);
+ }
+
+ // Since ashmem heaps are rounded up to page size, don't reallocate if
+ // the capture heap isn't exactly the same size as the required JPEG buffer
+ const size_t HEAP_SLACK_FACTOR = 2;
+ if (mCaptureHeap == 0 ||
+ (mCaptureHeap->getSize() < static_cast<size_t>(maxJpegSize)) ||
+ (mCaptureHeap->getSize() >
+ static_cast<size_t>(maxJpegSize) * HEAP_SLACK_FACTOR) ) {
// Create memory for API consumption
- mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0,
- "Camera2Client::CaptureHeap");
+ mCaptureHeap.clear();
+ mCaptureHeap =
+ new MemoryHeapBase(maxJpegSize, 0, "Camera2Client::CaptureHeap");
if (mCaptureHeap->getSize() == 0) {
ALOGE("%s: Camera %d: Unable to allocate memory for capture",
__FUNCTION__, mId);
return NO_MEMORY;
}
}
+ ALOGV("%s: Camera %d: JPEG capture heap now %d bytes; requested %d bytes",
+ __FUNCTION__, mId, mCaptureHeap->getSize(), maxJpegSize);
if (mCaptureStreamId != NO_STREAM) {
// Check if stream parameters have to change
@@ -132,8 +145,7 @@ status_t JpegProcessor::updateStream(const Parameters &params) {
// Create stream for HAL production
res = device->createStream(mCaptureWindow,
params.pictureWidth, params.pictureHeight,
- HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
- &mCaptureStreamId);
+ HAL_PIXEL_FORMAT_BLOB, &mCaptureStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for capture: "
"%s (%d)", __FUNCTION__, mId,
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 081a6e6..7b90d28 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -29,6 +29,9 @@
#include "Parameters.h"
#include "system/camera.h"
+#include "hardware/camera_common.h"
+#include <media/MediaProfiles.h>
+#include <media/mediarecorder.h>
namespace android {
namespace camera2 {
@@ -43,7 +46,7 @@ Parameters::Parameters(int cameraId,
Parameters::~Parameters() {
}
-status_t Parameters::initialize(const CameraMetadata *info) {
+status_t Parameters::initialize(const CameraMetadata *info, int deviceVersion) {
status_t res;
if (info->entryCount() == 0) {
@@ -51,6 +54,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
return BAD_VALUE;
}
Parameters::info = info;
+ mDeviceVersion = deviceVersion;
res = buildFastInfo();
if (res != OK) return res;
@@ -59,12 +63,42 @@ status_t Parameters::initialize(const CameraMetadata *info) {
if (res != OK) return res;
const Size MAX_PREVIEW_SIZE = { MAX_PREVIEW_WIDTH, MAX_PREVIEW_HEIGHT };
- res = getFilteredPreviewSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes);
+ // Treat the H.264 max size as the max supported video size.
+ MediaProfiles *videoEncoderProfiles = MediaProfiles::getInstance();
+ int32_t maxVideoWidth = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.width.max", VIDEO_ENCODER_H264);
+ int32_t maxVideoHeight = videoEncoderProfiles->getVideoEncoderParamByName(
+ "enc.vid.height.max", VIDEO_ENCODER_H264);
+ const Size MAX_VIDEO_SIZE = {maxVideoWidth, maxVideoHeight};
+
+ res = getFilteredSizes(MAX_PREVIEW_SIZE, &availablePreviewSizes);
+ if (res != OK) return res;
+ res = getFilteredSizes(MAX_VIDEO_SIZE, &availableVideoSizes);
if (res != OK) return res;
- // TODO: Pick more intelligently
- previewWidth = availablePreviewSizes[0].width;
- previewHeight = availablePreviewSizes[0].height;
+ // Select initial preview and video size that's under the initial bound and
+ // on the list of both preview and recording sizes
+ previewWidth = 0;
+ previewHeight = 0;
+ for (size_t i = 0 ; i < availablePreviewSizes.size(); i++) {
+ int newWidth = availablePreviewSizes[i].width;
+ int newHeight = availablePreviewSizes[i].height;
+ if (newWidth >= previewWidth && newHeight >= previewHeight &&
+ newWidth <= MAX_INITIAL_PREVIEW_WIDTH &&
+ newHeight <= MAX_INITIAL_PREVIEW_HEIGHT) {
+ for (size_t j = 0; j < availableVideoSizes.size(); j++) {
+ if (availableVideoSizes[j].width == newWidth &&
+ availableVideoSizes[j].height == newHeight) {
+ previewWidth = newWidth;
+ previewHeight = newHeight;
+ }
+ }
+ }
+ }
+ if (previewWidth == 0) {
+ ALOGE("%s: No initial preview size can be found!", __FUNCTION__);
+ return BAD_VALUE;
+ }
videoWidth = previewWidth;
videoHeight = previewHeight;
@@ -84,8 +118,17 @@ status_t Parameters::initialize(const CameraMetadata *info) {
ALOGV("Supported preview sizes are: %s", supportedPreviewSizes.string());
params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES,
supportedPreviewSizes);
+
+ String8 supportedVideoSizes;
+ for (size_t i = 0; i < availableVideoSizes.size(); i++) {
+ if (i != 0) supportedVideoSizes += ",";
+ supportedVideoSizes += String8::format("%dx%d",
+ availableVideoSizes[i].width,
+ availableVideoSizes[i].height);
+ }
+ ALOGV("Supported video sizes are: %s", supportedVideoSizes.string());
params.set(CameraParameters::KEY_SUPPORTED_VIDEO_SIZES,
- supportedPreviewSizes);
+ supportedVideoSizes);
}
camera_metadata_ro_entry_t availableFpsRanges =
@@ -99,16 +142,14 @@ status_t Parameters::initialize(const CameraMetadata *info) {
previewTransform = degToTransform(0,
cameraFacing == CAMERA_FACING_FRONT);
- camera_metadata_ro_entry_t availableFormats =
- staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
-
{
String8 supportedPreviewFormats;
+ SortedVector<int32_t> outputFormats = getAvailableOutputFormats();
bool addComma = false;
- for (size_t i=0; i < availableFormats.count; i++) {
+ for (size_t i=0; i < outputFormats.size(); i++) {
if (addComma) supportedPreviewFormats += ",";
addComma = true;
- switch (availableFormats.data.i32[i]) {
+ switch (outputFormats[i]) {
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
supportedPreviewFormats +=
CameraParameters::PIXEL_FORMAT_YUV422SP;
@@ -150,7 +191,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
default:
ALOGW("%s: Camera %d: Unknown preview format: %x",
- __FUNCTION__, cameraId, availableFormats.data.i32[i]);
+ __FUNCTION__, cameraId, outputFormats[i]);
addComma = false;
break;
}
@@ -222,24 +263,26 @@ status_t Parameters::initialize(const CameraMetadata *info) {
supportedPreviewFrameRates);
}
- camera_metadata_ro_entry_t availableJpegSizes =
- staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES, 2);
- if (!availableJpegSizes.count) return NO_INIT;
+ Vector<Size> availableJpegSizes = getAvailableJpegSizes();
+ if (!availableJpegSizes.size()) return NO_INIT;
// TODO: Pick maximum
- pictureWidth = availableJpegSizes.data.i32[0];
- pictureHeight = availableJpegSizes.data.i32[1];
+ pictureWidth = availableJpegSizes[0].width;
+ pictureHeight = availableJpegSizes[0].height;
+ pictureWidthLastSet = pictureWidth;
+ pictureHeightLastSet = pictureHeight;
+ pictureSizeOverriden = false;
params.setPictureSize(pictureWidth,
pictureHeight);
{
String8 supportedPictureSizes;
- for (size_t i=0; i < availableJpegSizes.count; i += 2) {
+ for (size_t i=0; i < availableJpegSizes.size(); i++) {
if (i != 0) supportedPictureSizes += ",";
supportedPictureSizes += String8::format("%dx%d",
- availableJpegSizes.data.i32[i],
- availableJpegSizes.data.i32[i+1]);
+ availableJpegSizes[i].width,
+ availableJpegSizes[i].height);
}
params.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES,
supportedPictureSizes);
@@ -470,7 +513,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
supportedAntibanding);
}
- sceneMode = ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ sceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
params.set(CameraParameters::KEY_SCENE_MODE,
CameraParameters::SCENE_MODE_AUTO);
@@ -486,7 +529,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
if (addComma) supportedSceneModes += ",";
addComma = true;
switch (availableSceneModes.data.u8[i]) {
- case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
+ case ANDROID_CONTROL_SCENE_MODE_DISABLED:
noSceneModes = true;
break;
case ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY:
@@ -579,8 +622,8 @@ status_t Parameters::initialize(const CameraMetadata *info) {
camera_metadata_ro_entry_t availableAeModes =
staticInfo(ANDROID_CONTROL_AE_AVAILABLE_MODES, 0, 0, false);
+ flashMode = Parameters::FLASH_MODE_OFF;
if (isFlashAvailable) {
- flashMode = Parameters::FLASH_MODE_OFF;
params.set(CameraParameters::KEY_FLASH_MODE,
CameraParameters::FLASH_MODE_OFF);
@@ -600,11 +643,10 @@ status_t Parameters::initialize(const CameraMetadata *info) {
params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
supportedFlashModes);
} else {
- flashMode = Parameters::FLASH_MODE_OFF;
- params.set(CameraParameters::KEY_FLASH_MODE,
- CameraParameters::FLASH_MODE_OFF);
- params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
- CameraParameters::FLASH_MODE_OFF);
+ // No flash means null flash mode and supported flash modes keys, so
+ // remove them just to be safe
+ params.remove(CameraParameters::KEY_FLASH_MODE);
+ params.remove(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
}
camera_metadata_ro_entry_t minFocusDistance =
@@ -624,8 +666,17 @@ status_t Parameters::initialize(const CameraMetadata *info) {
focusMode = Parameters::FOCUS_MODE_AUTO;
params.set(CameraParameters::KEY_FOCUS_MODE,
CameraParameters::FOCUS_MODE_AUTO);
- String8 supportedFocusModes(CameraParameters::FOCUS_MODE_INFINITY);
- bool addComma = true;
+ String8 supportedFocusModes;
+ bool addComma = false;
+ camera_metadata_ro_entry_t focusDistanceCalibration =
+ staticInfo(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, 0, 0, false);
+
+ if (focusDistanceCalibration.count &&
+ focusDistanceCalibration.data.u8[0] !=
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED) {
+ supportedFocusModes += CameraParameters::FOCUS_MODE_INFINITY;
+ addComma = true;
+ }
for (size_t i=0; i < availableAfModes.count; i++) {
if (addComma) supportedFocusModes += ",";
@@ -668,13 +719,13 @@ status_t Parameters::initialize(const CameraMetadata *info) {
focusState = ANDROID_CONTROL_AF_STATE_INACTIVE;
shadowFocusMode = FOCUS_MODE_INVALID;
- camera_metadata_ro_entry_t max3aRegions =
- staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1);
- if (!max3aRegions.count) return NO_INIT;
+ camera_metadata_ro_entry_t max3aRegions = staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+ Parameters::NUM_REGION, Parameters::NUM_REGION);
+ if (max3aRegions.count != Parameters::NUM_REGION) return NO_INIT;
int32_t maxNumFocusAreas = 0;
if (focusMode != Parameters::FOCUS_MODE_FIXED) {
- maxNumFocusAreas = max3aRegions.data.i32[0];
+ maxNumFocusAreas = max3aRegions.data.i32[Parameters::REGION_AF];
}
params.set(CameraParameters::KEY_MAX_NUM_FOCUS_AREAS, maxNumFocusAreas);
params.set(CameraParameters::KEY_FOCUS_AREAS,
@@ -734,7 +785,7 @@ status_t Parameters::initialize(const CameraMetadata *info) {
meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
- max3aRegions.data.i32[0]);
+ max3aRegions.data.i32[Parameters::REGION_AE]);
params.set(CameraParameters::KEY_METERING_AREAS,
"(0,0,0,0,0)");
@@ -931,13 +982,19 @@ status_t Parameters::buildFastInfo() {
bool fixedLens = minFocusDistance.count == 0 ||
minFocusDistance.data.f[0] == 0;
+ camera_metadata_ro_entry_t focusDistanceCalibration =
+ staticInfo(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, 0, 0,
+ false);
+ bool canFocusInfinity = (focusDistanceCalibration.count &&
+ focusDistanceCalibration.data.u8[0] !=
+ ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED);
+
camera_metadata_ro_entry_t availableFocalLengths =
staticInfo(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
if (!availableFocalLengths.count) return NO_INIT;
- camera_metadata_ro_entry_t availableFormats =
- staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
- if (!availableFormats.count) return NO_INIT;
+ SortedVector<int32_t> availableFormats = getAvailableOutputFormats();
+ if (!availableFormats.size()) return NO_INIT;
if (sceneModeOverrides.count > 0) {
@@ -982,6 +1039,13 @@ status_t Parameters::buildFastInfo() {
sceneModeOverrides.data.u8[i * kModesPerSceneMode + 2];
switch(afMode) {
case ANDROID_CONTROL_AF_MODE_OFF:
+ if (!fixedLens && !canFocusInfinity) {
+ ALOGE("%s: Camera %d: Scene mode override lists asks for"
+ " fixed focus on a device with focuser but not"
+ " calibrated for infinity focus", __FUNCTION__,
+ cameraId);
+ return NO_INIT;
+ }
modes.focusMode = fixedLens ?
FOCUS_MODE_FIXED : FOCUS_MODE_INFINITY;
break;
@@ -1021,8 +1085,8 @@ status_t Parameters::buildFastInfo() {
// Check if the HAL supports HAL_PIXEL_FORMAT_YCbCr_420_888
fastInfo.useFlexibleYuv = false;
- for (size_t i = 0; i < availableFormats.count; i++) {
- if (availableFormats.data.i32[i] == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ for (size_t i = 0; i < availableFormats.size(); i++) {
+ if (availableFormats[i] == HAL_PIXEL_FORMAT_YCbCr_420_888) {
fastInfo.useFlexibleYuv = true;
break;
}
@@ -1225,8 +1289,7 @@ status_t Parameters::set(const String8& paramString) {
"is active!", __FUNCTION__);
return BAD_VALUE;
}
- camera_metadata_ro_entry_t availableFormats =
- staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+ SortedVector<int32_t> availableFormats = getAvailableOutputFormats();
// If using flexible YUV, always support NV21/YV12. Otherwise, check
// HAL's list.
if (! (fastInfo.useFlexibleYuv &&
@@ -1235,11 +1298,10 @@ status_t Parameters::set(const String8& paramString) {
validatedParams.previewFormat ==
HAL_PIXEL_FORMAT_YV12) ) ) {
// Not using flexible YUV format, so check explicitly
- for (i = 0; i < availableFormats.count; i++) {
- if (availableFormats.data.i32[i] ==
- validatedParams.previewFormat) break;
+ for (i = 0; i < availableFormats.size(); i++) {
+ if (availableFormats[i] == validatedParams.previewFormat) break;
}
- if (i == availableFormats.count) {
+ if (i == availableFormats.size()) {
ALOGE("%s: Requested preview format %s (0x%x) is not supported",
__FUNCTION__, newParams.getPreviewFormat(),
validatedParams.previewFormat);
@@ -1355,17 +1417,16 @@ status_t Parameters::set(const String8& paramString) {
// PICTURE_SIZE
newParams.getPictureSize(&validatedParams.pictureWidth,
&validatedParams.pictureHeight);
- if (validatedParams.pictureWidth == pictureWidth ||
- validatedParams.pictureHeight == pictureHeight) {
- camera_metadata_ro_entry_t availablePictureSizes =
- staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
- for (i = 0; i < availablePictureSizes.count; i+=2) {
- if ((availablePictureSizes.data.i32[i] ==
+ if (validatedParams.pictureWidth != pictureWidth ||
+ validatedParams.pictureHeight != pictureHeight) {
+ Vector<Size> availablePictureSizes = getAvailableJpegSizes();
+ for (i = 0; i < availablePictureSizes.size(); i++) {
+ if ((availablePictureSizes[i].width ==
validatedParams.pictureWidth) &&
- (availablePictureSizes.data.i32[i+1] ==
+ (availablePictureSizes[i].height ==
validatedParams.pictureHeight)) break;
}
- if (i == availablePictureSizes.count) {
+ if (i == availablePictureSizes.size()) {
ALOGE("%s: Requested picture size %d x %d is not supported",
__FUNCTION__, validatedParams.pictureWidth,
validatedParams.pictureHeight);
@@ -1522,7 +1583,7 @@ status_t Parameters::set(const String8& paramString) {
newParams.get(CameraParameters::KEY_SCENE_MODE) );
if (validatedParams.sceneMode != sceneMode &&
validatedParams.sceneMode !=
- ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) {
+ ANDROID_CONTROL_SCENE_MODE_DISABLED) {
camera_metadata_ro_entry_t availableSceneModes =
staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
for (i = 0; i < availableSceneModes.count; i++) {
@@ -1537,7 +1598,7 @@ status_t Parameters::set(const String8& paramString) {
}
}
bool sceneModeSet =
- validatedParams.sceneMode != ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ validatedParams.sceneMode != ANDROID_CONTROL_SCENE_MODE_DISABLED;
// FLASH_MODE
if (sceneModeSet) {
@@ -1555,7 +1616,9 @@ status_t Parameters::set(const String8& paramString) {
if (validatedParams.flashMode != flashMode) {
camera_metadata_ro_entry_t flashAvailable =
staticInfo(ANDROID_FLASH_INFO_AVAILABLE, 1, 1);
- if (!flashAvailable.data.u8[0] &&
+ bool isFlashAvailable =
+ flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE;
+ if (!isFlashAvailable &&
validatedParams.flashMode != Parameters::FLASH_MODE_OFF) {
ALOGE("%s: Requested flash mode \"%s\" is not supported: "
"No flash on device", __FUNCTION__,
@@ -1580,9 +1643,11 @@ status_t Parameters::set(const String8& paramString) {
newParams.get(CameraParameters::KEY_FLASH_MODE));
return BAD_VALUE;
}
- // Update in case of override
- newParams.set(CameraParameters::KEY_FLASH_MODE,
- flashModeEnumToString(validatedParams.flashMode));
+ // Update in case of override, but only if flash is supported
+ if (isFlashAvailable) {
+ newParams.set(CameraParameters::KEY_FLASH_MODE,
+ flashModeEnumToString(validatedParams.flashMode));
+ }
}
// WHITE_BALANCE
@@ -1667,10 +1732,11 @@ status_t Parameters::set(const String8& paramString) {
// FOCUS_AREAS
res = parseAreas(newParams.get(CameraParameters::KEY_FOCUS_AREAS),
&validatedParams.focusingAreas);
- size_t max3aRegions =
- (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS, 1, 1).data.i32[0];
+ size_t maxAfRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+ Parameters::NUM_REGION, Parameters::NUM_REGION).
+ data.i32[Parameters::REGION_AF];
if (res == OK) res = validateAreas(validatedParams.focusingAreas,
- max3aRegions, AREA_KIND_FOCUS);
+ maxAfRegions, AREA_KIND_FOCUS);
if (res != OK) {
ALOGE("%s: Requested focus areas are malformed: %s",
__FUNCTION__, newParams.get(CameraParameters::KEY_FOCUS_AREAS));
@@ -1700,10 +1766,13 @@ status_t Parameters::set(const String8& paramString) {
newParams.get(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK));
// METERING_AREAS
+ size_t maxAeRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+ Parameters::NUM_REGION, Parameters::NUM_REGION).
+ data.i32[Parameters::REGION_AE];
res = parseAreas(newParams.get(CameraParameters::KEY_METERING_AREAS),
&validatedParams.meteringAreas);
if (res == OK) {
- res = validateAreas(validatedParams.meteringAreas, max3aRegions,
+ res = validateAreas(validatedParams.meteringAreas, maxAeRegions,
AREA_KIND_METERING);
}
if (res != OK) {
@@ -1728,21 +1797,26 @@ status_t Parameters::set(const String8& paramString) {
if (validatedParams.videoWidth != videoWidth ||
validatedParams.videoHeight != videoHeight) {
if (state == RECORD) {
- ALOGE("%s: Video size cannot be updated when recording is active!",
- __FUNCTION__);
- return BAD_VALUE;
- }
- for (i = 0; i < availablePreviewSizes.size(); i++) {
- if ((availablePreviewSizes[i].width ==
- validatedParams.videoWidth) &&
- (availablePreviewSizes[i].height ==
- validatedParams.videoHeight)) break;
- }
- if (i == availablePreviewSizes.size()) {
- ALOGE("%s: Requested video size %d x %d is not supported",
- __FUNCTION__, validatedParams.videoWidth,
+ ALOGW("%s: Video size cannot be updated (from %d x %d to %d x %d)"
+ " when recording is active! Ignore the size update!",
+ __FUNCTION__, videoWidth, videoHeight, validatedParams.videoWidth,
validatedParams.videoHeight);
- return BAD_VALUE;
+ validatedParams.videoWidth = videoWidth;
+ validatedParams.videoHeight = videoHeight;
+ newParams.setVideoSize(videoWidth, videoHeight);
+ } else {
+ for (i = 0; i < availableVideoSizes.size(); i++) {
+ if ((availableVideoSizes[i].width ==
+ validatedParams.videoWidth) &&
+ (availableVideoSizes[i].height ==
+ validatedParams.videoHeight)) break;
+ }
+ if (i == availableVideoSizes.size()) {
+ ALOGE("%s: Requested video size %d x %d is not supported",
+ __FUNCTION__, validatedParams.videoWidth,
+ validatedParams.videoHeight);
+ return BAD_VALUE;
+ }
}
}
@@ -1764,6 +1838,7 @@ status_t Parameters::set(const String8& paramString) {
/** Update internal parameters */
*this = validatedParams;
+ updateOverriddenJpegSize();
/** Update external parameters calculated from the internal ones */
@@ -1855,7 +1930,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
// (face detection statistics and face priority scene mode). Map from other
// to the other.
bool sceneModeActive =
- sceneMode != (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ sceneMode != (uint8_t)ANDROID_CONTROL_SCENE_MODE_DISABLED;
uint8_t reqControlMode = ANDROID_CONTROL_MODE_AUTO;
if (enableFaceDetect || sceneModeActive) {
reqControlMode = ANDROID_CONTROL_MODE_USE_SCENE_MODE;
@@ -1867,7 +1942,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
uint8_t reqSceneMode =
sceneModeActive ? sceneMode :
enableFaceDetect ? (uint8_t)ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY :
- (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED;
+ (uint8_t)ANDROID_CONTROL_SCENE_MODE_DISABLED;
res = request->update(ANDROID_CONTROL_SCENE_MODE,
&reqSceneMode, 1);
if (res != OK) return res;
@@ -1988,6 +2063,23 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
reqMeteringAreas, reqMeteringAreasSize);
if (res != OK) return res;
+ // Set awb regions to be the same as the metering regions if allowed
+ size_t maxAwbRegions = (size_t)staticInfo(ANDROID_CONTROL_MAX_REGIONS,
+ Parameters::NUM_REGION, Parameters::NUM_REGION).
+ data.i32[Parameters::REGION_AWB];
+ if (maxAwbRegions > 0) {
+ if (maxAwbRegions >= meteringAreas.size()) {
+ res = request->update(ANDROID_CONTROL_AWB_REGIONS,
+ reqMeteringAreas, reqMeteringAreasSize);
+ } else {
+ // Ensure the awb regions are zeroed if the region count is too high.
+ int32_t zeroedAwbAreas[5] = {0, 0, 0, 0, 0};
+ res = request->update(ANDROID_CONTROL_AWB_REGIONS,
+ zeroedAwbAreas, sizeof(zeroedAwbAreas)/sizeof(int32_t));
+ }
+ if (res != OK) return res;
+ }
+
delete[] reqMeteringAreas;
/* don't include jpeg thumbnail size - it's valid for
@@ -2064,6 +2156,52 @@ status_t Parameters::updateRequestJpeg(CameraMetadata *request) const {
return OK;
}
+status_t Parameters::overrideJpegSizeByVideoSize() {
+ if (pictureSizeOverriden) {
+ ALOGV("Picture size has been overridden. Skip overriding");
+ return OK;
+ }
+
+ pictureSizeOverriden = true;
+ pictureWidthLastSet = pictureWidth;
+ pictureHeightLastSet = pictureHeight;
+ pictureWidth = videoWidth;
+ pictureHeight = videoHeight;
+ // This change of picture size is invisible to app layer.
+ // Do not update app visible params
+ return OK;
+}
+
+status_t Parameters::updateOverriddenJpegSize() {
+ if (!pictureSizeOverriden) {
+ ALOGV("Picture size has not been overridden. Skip checking");
+ return OK;
+ }
+
+ pictureWidthLastSet = pictureWidth;
+ pictureHeightLastSet = pictureHeight;
+
+ if (pictureWidth <= videoWidth && pictureHeight <= videoHeight) {
+ // Picture size is now smaller than video size. No need to override anymore
+ return recoverOverriddenJpegSize();
+ }
+
+ pictureWidth = videoWidth;
+ pictureHeight = videoHeight;
+
+ return OK;
+}
+
+status_t Parameters::recoverOverriddenJpegSize() {
+ if (!pictureSizeOverriden) {
+ ALOGV("Picture size has not been overridden. Skip recovering");
+ return OK;
+ }
+ pictureSizeOverriden = false;
+ pictureWidth = pictureWidthLastSet;
+ pictureHeight = pictureHeightLastSet;
+ return OK;
+}
const char* Parameters::getStateName(State state) {
#define CASE_ENUM_TO_CHAR(x) case x: return(#x); break;
@@ -2083,24 +2221,7 @@ const char* Parameters::getStateName(State state) {
}
int Parameters::formatStringToEnum(const char *format) {
- return
- !format ?
- HAL_PIXEL_FORMAT_YCrCb_420_SP :
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
- HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420SP) ?
- HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422I) ?
- HAL_PIXEL_FORMAT_YCbCr_422_I : // YUY2
- !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV420P) ?
- HAL_PIXEL_FORMAT_YV12 : // YV12
- !strcmp(format, CameraParameters::PIXEL_FORMAT_RGB565) ?
- HAL_PIXEL_FORMAT_RGB_565 : // RGB565
- !strcmp(format, CameraParameters::PIXEL_FORMAT_RGBA8888) ?
- HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888
- !strcmp(format, CameraParameters::PIXEL_FORMAT_BAYER_RGGB) ?
- HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data
- -1;
+ return CameraParameters::previewFormatToEnum(format);
}
const char* Parameters::formatEnumToString(int format) {
@@ -2228,9 +2349,9 @@ int Parameters::abModeStringToEnum(const char *abMode) {
int Parameters::sceneModeStringToEnum(const char *sceneMode) {
return
!sceneMode ?
- ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+ ANDROID_CONTROL_SCENE_MODE_DISABLED :
!strcmp(sceneMode, CameraParameters::SCENE_MODE_AUTO) ?
- ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED :
+ ANDROID_CONTROL_SCENE_MODE_DISABLED :
!strcmp(sceneMode, CameraParameters::SCENE_MODE_ACTION) ?
ANDROID_CONTROL_SCENE_MODE_ACTION :
!strcmp(sceneMode, CameraParameters::SCENE_MODE_PORTRAIT) ?
@@ -2268,7 +2389,7 @@ Parameters::Parameters::flashMode_t Parameters::flashModeStringToEnum(
const char *flashMode) {
return
!flashMode ?
- Parameters::FLASH_MODE_INVALID :
+ Parameters::FLASH_MODE_OFF :
!strcmp(flashMode, CameraParameters::FLASH_MODE_OFF) ?
Parameters::FLASH_MODE_OFF :
!strcmp(flashMode, CameraParameters::FLASH_MODE_AUTO) ?
@@ -2569,7 +2690,7 @@ int Parameters::normalizedYToArray(int y) const {
return cropYToArray(normalizedYToCrop(y));
}
-status_t Parameters::getFilteredPreviewSizes(Size limit, Vector<Size> *sizes) {
+status_t Parameters::getFilteredSizes(Size limit, Vector<Size> *sizes) {
if (info == NULL) {
ALOGE("%s: Static metadata is not initialized", __FUNCTION__);
return NO_INIT;
@@ -2578,22 +2699,37 @@ status_t Parameters::getFilteredPreviewSizes(Size limit, Vector<Size> *sizes) {
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);
+ sizes->clear();
+
+ if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ Vector<StreamConfiguration> scs = getStreamConfigurations();
+ for (size_t i=0; i < scs.size(); i++) {
+ const StreamConfiguration &sc = scs[i];
+ if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ sc.format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
+ sc.width <= limit.width && sc.height <= limit.height) {
+ Size sz = {sc.width, sc.height};
+ sizes->push(sz);
}
+ }
+ } else {
+ 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 filteredSize;
+ for (size_t i = 0; i < availableProcessedSizes.count; i += SIZE_COUNT) {
+ filteredSize.width = availableProcessedSizes.data.i32[i];
+ filteredSize.height = availableProcessedSizes.data.i32[i+1];
+ // Need skip the preview sizes that are too large.
+ if (filteredSize.width <= limit.width &&
+ filteredSize.height <= limit.height) {
+ sizes->push(filteredSize);
+ }
+ }
}
+
if (sizes->isEmpty()) {
ALOGE("generated preview size list is empty!!");
return BAD_VALUE;
@@ -2627,6 +2763,78 @@ Parameters::Size Parameters::getMaxSizeForRatio(
return maxSize;
}
+Vector<Parameters::StreamConfiguration> Parameters::getStreamConfigurations() {
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ Vector<StreamConfiguration> scs;
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("StreamConfiguration is only valid after device HAL 3.2!");
+ return scs;
+ }
+
+ camera_metadata_ro_entry_t availableStreamConfigs =
+ staticInfo(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ for (size_t i=0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {
+ int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ StreamConfiguration sc = {format, width, height, isInput};
+ scs.add(sc);
+ }
+ return scs;
+}
+
+SortedVector<int32_t> Parameters::getAvailableOutputFormats() {
+ SortedVector<int32_t> outputFormats; // Non-duplicated output formats
+ if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ Vector<StreamConfiguration> scs = getStreamConfigurations();
+ for (size_t i=0; i < scs.size(); i++) {
+ const StreamConfiguration &sc = scs[i];
+ if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) {
+ outputFormats.add(sc.format);
+ }
+ }
+ } else {
+ camera_metadata_ro_entry_t availableFormats = staticInfo(ANDROID_SCALER_AVAILABLE_FORMATS);
+ for (size_t i=0; i < availableFormats.count; i++) {
+ outputFormats.add(availableFormats.data.i32[i]);
+ }
+ }
+ return outputFormats;
+}
+
+Vector<Parameters::Size> Parameters::getAvailableJpegSizes() {
+ Vector<Parameters::Size> jpegSizes;
+ if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ Vector<StreamConfiguration> scs = getStreamConfigurations();
+ for (size_t i=0; i < scs.size(); i++) {
+ const StreamConfiguration &sc = scs[i];
+ if (sc.isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ sc.format == HAL_PIXEL_FORMAT_BLOB) {
+ Size sz = {sc.width, sc.height};
+ jpegSizes.add(sz);
+ }
+ }
+ } else {
+ const int JPEG_SIZE_ENTRY_COUNT = 2;
+ const int WIDTH_OFFSET = 0;
+ const int HEIGHT_OFFSET = 1;
+ camera_metadata_ro_entry_t availableJpegSizes =
+ staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+ for (size_t i=0; i < availableJpegSizes.count; i+= JPEG_SIZE_ENTRY_COUNT) {
+ int width = availableJpegSizes.data.i32[i + WIDTH_OFFSET];
+ int height = availableJpegSizes.data.i32[i + HEIGHT_OFFSET];
+ Size sz = {width, height};
+ jpegSizes.add(sz);
+ }
+ }
+ return jpegSizes;
+}
+
Parameters::CropRegion Parameters::calculateCropRegion(
Parameters::CropRegion::Outputs outputs) const {
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index da07ccf..815cc55 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -52,6 +52,9 @@ struct Parameters {
int previewTransform; // set by CAMERA_CMD_SET_DISPLAY_ORIENTATION
int pictureWidth, pictureHeight;
+ // Store the picture size before they are overriden by video snapshot
+ int pictureWidthLastSet, pictureHeightLastSet;
+ bool pictureSizeOverriden;
int32_t jpegThumbSize[2];
uint8_t jpegQuality, jpegThumbQuality;
@@ -114,6 +117,14 @@ struct Parameters {
bool autoExposureLock;
bool autoWhiteBalanceLock;
+ // 3A region types, for use with ANDROID_CONTROL_MAX_REGIONS
+ enum region_t {
+ REGION_AE = 0,
+ REGION_AWB,
+ REGION_AF,
+ NUM_REGION // Number of region types
+ } region;
+
Vector<Area> meteringAreas;
int zoom;
@@ -168,8 +179,13 @@ struct Parameters {
// Number of zoom steps to simulate
static const unsigned int NUM_ZOOM_STEPS = 100;
// Max preview size allowed
+ // This is set to a 1:1 value to allow for any aspect ratio that has
+ // a max long side of 1920 pixels
static const unsigned int MAX_PREVIEW_WIDTH = 1920;
- static const unsigned int MAX_PREVIEW_HEIGHT = 1080;
+ static const unsigned int MAX_PREVIEW_HEIGHT = 1920;
+ // Initial max preview/recording size bound
+ static const int MAX_INITIAL_PREVIEW_WIDTH = 1920;
+ static const int MAX_INITIAL_PREVIEW_HEIGHT = 1080;
// Aspect ratio tolerance
static const float ASPECT_RATIO_TOLERANCE = 0.001;
@@ -219,7 +235,7 @@ struct Parameters {
~Parameters();
// Sets up default parameters
- status_t initialize(const CameraMetadata *info);
+ status_t initialize(const CameraMetadata *info, int deviceVersion);
// Build fast-access device static info from static info
status_t buildFastInfo();
@@ -245,6 +261,12 @@ struct Parameters {
// Add/update JPEG entries in metadata
status_t updateRequestJpeg(CameraMetadata *request) const;
+ /* Helper functions to override jpeg size for video snapshot */
+ // Override jpeg size by video size. Called during startRecording.
+ status_t overrideJpegSizeByVideoSize();
+ // Recover overridden jpeg size. Called during stopRecording.
+ status_t recoverOverriddenJpegSize();
+
// Calculate the crop region rectangle based on current stream sizes
struct CropRegion {
float left;
@@ -334,10 +356,35 @@ private:
int normalizedYToCrop(int y) const;
Vector<Size> availablePreviewSizes;
+ Vector<Size> availableVideoSizes;
// Get size list (that are no larger than limit) from static metadata.
- status_t getFilteredPreviewSizes(Size limit, Vector<Size> *sizes);
+ status_t getFilteredSizes(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);
+
+ // Helper function for overriding jpeg size for video snapshot
+ // Check if overridden jpeg size needs to be updated after Parameters::set.
+ // The behavior of this function is tailored to the implementation of Parameters::set.
+ // Do not use this function for other purpose.
+ status_t updateOverriddenJpegSize();
+
+ struct StreamConfiguration {
+ int32_t format;
+ int32_t width;
+ int32_t height;
+ int32_t isInput;
+ };
+ // Helper function extract available stream configuration
+ // Only valid since device HAL version 3.2
+ // returns an empty Vector if device HAL version does support it
+ Vector<StreamConfiguration> getStreamConfigurations();
+
+ // Helper function to get non-duplicated available output formats
+ SortedVector<int32_t> getAvailableOutputFormats();
+ // Helper function to get available output jpeg sizes
+ Vector<Size> getAvailableJpegSizes();
+
+ int mDeviceVersion;
};
// This class encapsulates the Parameters class so that it can only be accessed
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 77ae7ec..9e7fff8 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -89,8 +89,26 @@ status_t StreamingProcessor::updatePreviewRequest(const Parameters &params) {
Mutex::Autolock m(mMutex);
if (mPreviewRequest.entryCount() == 0) {
- res = device->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
- &mPreviewRequest);
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) {
+ ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ // Use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG for ZSL streaming case.
+ if (client->getCameraDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_0) {
+ if (params.zslMode && !params.recordingHint) {
+ res = device->createDefaultRequest(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG,
+ &mPreviewRequest);
+ } else {
+ res = device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW,
+ &mPreviewRequest);
+ }
+ } else {
+ res = device->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+ &mPreviewRequest);
+ }
+
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create default preview request: "
"%s (%d)", __FUNCTION__, mId, strerror(-res), res);
@@ -163,8 +181,7 @@ status_t StreamingProcessor::updatePreviewStream(const Parameters &params) {
if (mPreviewStreamId == NO_STREAM) {
res = device->createStream(mPreviewWindow,
params.previewWidth, params.previewHeight,
- CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
- &mPreviewStreamId);
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
@@ -301,6 +318,44 @@ status_t StreamingProcessor::updateRecordingRequest(const Parameters &params) {
return OK;
}
+status_t StreamingProcessor::recordingStreamNeedsUpdate(
+ const Parameters &params, bool *needsUpdate) {
+ status_t res;
+
+ if (needsUpdate == 0) {
+ ALOGE("%s: Camera %d: invalid argument", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ if (mRecordingStreamId == NO_STREAM) {
+ *needsUpdate = true;
+ return OK;
+ }
+
+ sp<CameraDeviceBase> device = mDevice.promote();
+ if (device == 0) {
+ ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ uint32_t currentWidth, currentHeight;
+ res = device->getStreamInfo(mRecordingStreamId,
+ &currentWidth, &currentHeight, 0);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Error querying recording output stream info: "
+ "%s (%d)", __FUNCTION__, mId,
+ strerror(-res), res);
+ return res;
+ }
+
+ if (mRecordingConsumer == 0 || currentWidth != (uint32_t)params.videoWidth ||
+ currentHeight != (uint32_t)params.videoHeight) {
+ *needsUpdate = true;
+ }
+ *needsUpdate = false;
+ return res;
+}
+
status_t StreamingProcessor::updateRecordingStream(const Parameters &params) {
ATRACE_CALL();
status_t res;
@@ -319,13 +374,15 @@ 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.
- sp<BufferQueue> bq = new BufferQueue();
- mRecordingConsumer = new BufferItemConsumer(bq,
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mRecordingConsumer = new BufferItemConsumer(consumer,
GRALLOC_USAGE_HW_VIDEO_ENCODER,
mRecordingHeapCount + 1);
mRecordingConsumer->setFrameAvailableListener(this);
mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
- mRecordingWindow = new Surface(bq);
+ mRecordingWindow = new Surface(producer);
newConsumer = true;
// Allocate memory later, since we don't know buffer size until receipt
}
@@ -365,7 +422,7 @@ status_t StreamingProcessor::updateRecordingStream(const Parameters &params) {
mRecordingFrameCount = 0;
res = device->createStream(mRecordingWindow,
params.videoWidth, params.videoHeight,
- CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
+ CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mRecordingStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for recording: "
"%s (%d)", __FUNCTION__, mId,
@@ -428,10 +485,13 @@ status_t StreamingProcessor::startStream(StreamType type,
Mutex::Autolock m(mMutex);
- // If a recording stream is being started up, free up any
- // outstanding buffers left from the previous recording session.
- // There should never be any, so if there are, warn about it.
- if (isStreamActive(outputStreams, mRecordingStreamId)) {
+ // If a recording stream is being started up and no recording
+ // stream is active yet, free up any outstanding buffers left
+ // from the previous recording session. There should never be
+ // any, so if there are, warn about it.
+ bool isRecordingStreamIdle = !isStreamActive(mActiveStreamIds, mRecordingStreamId);
+ bool startRecordingStream = isStreamActive(outputStreams, mRecordingStreamId);
+ if (startRecordingStream && isRecordingStreamIdle) {
releaseAllRecordingFramesLocked();
}
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index 833bb8f..8466af4 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -54,6 +54,9 @@ class StreamingProcessor:
status_t setRecordingBufferCount(size_t count);
status_t updateRecordingRequest(const Parameters &params);
+ // If needsUpdate is set to true, a updateRecordingStream call with params will recreate
+ // recording stream
+ status_t recordingStreamNeedsUpdate(const Parameters &params, bool *needsUpdate);
status_t updateRecordingStream(const Parameters &params);
status_t deleteRecordingStream();
int getRecordingStreamId() const;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 130f81a..8f78103 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -48,6 +48,7 @@ ZslProcessor::ZslProcessor(
mDevice(client->getCameraDevice()),
mSequencer(sequencer),
mId(client->getCameraId()),
+ mDeleted(false),
mZslBufferAvailable(false),
mZslStreamId(NO_STREAM),
mZslReprocessStreamId(NO_STREAM),
@@ -62,7 +63,7 @@ ZslProcessor::ZslProcessor(
ZslProcessor::~ZslProcessor() {
ALOGV("%s: Exit", __FUNCTION__);
- deleteStream();
+ disconnect();
}
void ZslProcessor::onFrameAvailable() {
@@ -73,18 +74,19 @@ void ZslProcessor::onFrameAvailable() {
}
}
-void ZslProcessor::onFrameAvailable(int32_t /*requestId*/,
- const CameraMetadata &frame) {
+void ZslProcessor::onResultAvailable(const CaptureResult &result) {
+ ATRACE_CALL();
+ ALOGV("%s:", __FUNCTION__);
Mutex::Autolock l(mInputMutex);
camera_metadata_ro_entry_t entry;
- entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
+ entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
nsecs_t timestamp = entry.data.i64[0];
(void)timestamp;
ALOGVV("Got preview frame for timestamp %" PRId64, timestamp);
if (mState != RUNNING) return;
- mFrameList.editItemAt(mFrameListHead) = frame;
+ mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
mFrameListHead = (mFrameListHead + 1) % kFrameListDepth;
findMatchesLocked();
@@ -130,13 +132,15 @@ status_t ZslProcessor::updateStream(const Parameters &params) {
if (mZslConsumer == 0) {
// Create CPU buffer queue endpoint
- sp<BufferQueue> bq = new BufferQueue();
- mZslConsumer = new BufferItemConsumer(bq,
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mZslConsumer = new BufferItemConsumer(consumer,
GRALLOC_USAGE_HW_CAMERA_ZSL,
kZslBufferDepth);
mZslConsumer->setFrameAvailableListener(this);
mZslConsumer->setName(String8("Camera2Client::ZslConsumer"));
- mZslWindow = new Surface(bq);
+ mZslWindow = new Surface(producer);
}
if (mZslStreamId != NO_STREAM) {
@@ -172,6 +176,8 @@ status_t ZslProcessor::updateStream(const Parameters &params) {
}
}
+ mDeleted = false;
+
if (mZslStreamId == NO_STREAM) {
// Create stream for HAL production
// TODO: Sort out better way to select resolution for ZSL
@@ -180,8 +186,7 @@ status_t ZslProcessor::updateStream(const Parameters &params) {
(int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
res = device->createStream(mZslWindow,
params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
- streamType, 0,
- &mZslStreamId);
+ streamType, &mZslStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
"%s (%d)", __FUNCTION__, mId,
@@ -199,13 +204,22 @@ status_t ZslProcessor::updateStream(const Parameters &params) {
}
client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
Camera2Client::kPreviewRequestIdEnd,
- this);
+ this,
+ /*sendPartials*/false);
return OK;
}
status_t ZslProcessor::deleteStream() {
ATRACE_CALL();
+ Mutex::Autolock l(mInputMutex);
+ // WAR(b/15408128): do not delete stream unless client is being disconnected.
+ mDeleted = true;
+ return OK;
+}
+
+status_t ZslProcessor::disconnect() {
+ ATRACE_CALL();
status_t res;
Mutex::Autolock l(mInputMutex);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 6d3cb85..b6533cf 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -24,6 +24,7 @@
#include <utils/Condition.h>
#include <gui/BufferItemConsumer.h>
#include <camera/CameraMetadata.h>
+#include <camera/CaptureResult.h>
#include "common/CameraDeviceBase.h"
#include "api1/client2/ZslProcessorInterface.h"
@@ -54,7 +55,7 @@ class ZslProcessor:
// From mZslConsumer
virtual void onFrameAvailable();
// From FrameProcessor
- virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame);
+ virtual void onResultAvailable(const CaptureResult &result);
virtual void onBufferReleased(buffer_handle_t *handle);
@@ -66,6 +67,7 @@ class ZslProcessor:
status_t updateStream(const Parameters &params);
status_t deleteStream();
+ status_t disconnect();
int getStreamId() const;
status_t pushToReprocess(int32_t requestId);
@@ -85,6 +87,8 @@ class ZslProcessor:
wp<CaptureSequencer> mSequencer;
int mId;
+ bool mDeleted;
+
mutable Mutex mInputMutex;
bool mZslBufferAvailable;
Condition mZslBufferAvailableSignal;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
index 2fce2b6..f110b66 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
@@ -44,6 +44,7 @@ ZslProcessor3::ZslProcessor3(
sp<Camera2Client> client,
wp<CaptureSequencer> sequencer):
Thread(false),
+ mLatestClearedBufferTimestamp(0),
mState(RUNNING),
mClient(client),
mSequencer(sequencer),
@@ -51,9 +52,42 @@ ZslProcessor3::ZslProcessor3(
mZslStreamId(NO_STREAM),
mFrameListHead(0),
mZslQueueHead(0),
- mZslQueueTail(0) {
- mZslQueue.insertAt(0, kZslBufferDepth);
- mFrameList.insertAt(0, kFrameListDepth);
+ mZslQueueTail(0),
+ mHasFocuser(false) {
+ // Initialize buffer queue and frame list based on pipeline max depth.
+ size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
+ if (client != 0) {
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
+ if (device != 0) {
+ camera_metadata_ro_entry_t entry =
+ device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
+ if (entry.count == 1) {
+ pipelineMaxDepth = entry.data.u8[0];
+ } else {
+ ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
+ " use default pipeline max depth %zu", __FUNCTION__,
+ kDefaultMaxPipelineDepth);
+ }
+
+ entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ if (entry.count > 0 && entry.data.f[0] != 0.) {
+ mHasFocuser = true;
+ }
+ }
+ }
+
+ ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%d)",
+ __FUNCTION__, pipelineMaxDepth);
+ // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
+ // earlier than metadata which causes the buffer corresponding to oldest metadata being
+ // removed.
+ mFrameListDepth = pipelineMaxDepth;
+ mBufferQueueDepth = mFrameListDepth + 1;
+
+
+ mZslQueue.insertAt(0, mBufferQueueDepth);
+ mFrameList.insertAt(0, mFrameListDepth);
sp<CaptureSequencer> captureSequencer = mSequencer.promote();
if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
}
@@ -63,19 +97,34 @@ ZslProcessor3::~ZslProcessor3() {
deleteStream();
}
-void ZslProcessor3::onFrameAvailable(int32_t /*requestId*/,
- const CameraMetadata &frame) {
+void ZslProcessor3::onResultAvailable(const CaptureResult &result) {
+ ATRACE_CALL();
+ ALOGV("%s:", __FUNCTION__);
Mutex::Autolock l(mInputMutex);
camera_metadata_ro_entry_t entry;
- entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
+ entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
nsecs_t timestamp = entry.data.i64[0];
- (void)timestamp;
- ALOGVV("Got preview metadata for timestamp %" PRId64, timestamp);
+ if (entry.count == 0) {
+ ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
+ return;
+ }
+
+ entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
+ if (entry.count == 0) {
+ ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
+ return;
+ }
+ int32_t frameNumber = entry.data.i32[0];
+
+ ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
if (mState != RUNNING) return;
- mFrameList.editItemAt(mFrameListHead) = frame;
- mFrameListHead = (mFrameListHead + 1) % kFrameListDepth;
+ // Corresponding buffer has been cleared. No need to push into mFrameList
+ if (timestamp <= mLatestClearedBufferTimestamp) return;
+
+ mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
+ mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
}
status_t ZslProcessor3::updateStream(const Parameters &params) {
@@ -135,7 +184,7 @@ status_t ZslProcessor3::updateStream(const Parameters &params) {
// Note that format specified internally in Camera3ZslStream
res = device->createZslStream(
params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
- kZslBufferDepth,
+ mBufferQueueDepth,
&mZslStreamId,
&mZslStream);
if (res != OK) {
@@ -144,10 +193,15 @@ status_t ZslProcessor3::updateStream(const Parameters &params) {
strerror(-res), res);
return res;
}
+
+ // Only add the camera3 buffer listener when the stream is created.
+ mZslStream->addBufferListener(this);
}
+
client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
Camera2Client::kPreviewRequestIdEnd,
- this);
+ this,
+ /*sendPartials*/false);
return OK;
}
@@ -190,6 +244,46 @@ int ZslProcessor3::getStreamId() const {
return mZslStreamId;
}
+status_t ZslProcessor3::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) {
+ ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
+ if (device == 0) {
+ ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ CameraMetadata stillTemplate;
+ device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+
+ // Find some of the post-processing tags, and assign the value from template to the request.
+ // Only check the aberration mode and noise reduction mode for now, as they are very important
+ // for image quality.
+ uint32_t postProcessingTags[] = {
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_TONEMAP_MODE,
+ ANDROID_SHADING_MODE,
+ ANDROID_HOT_PIXEL_MODE,
+ ANDROID_EDGE_MODE
+ };
+
+ camera_metadata_entry_t entry;
+ for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
+ entry = stillTemplate.find(postProcessingTags[i]);
+ if (entry.count > 0) {
+ request.update(postProcessingTags[i], entry.data.u8, 1);
+ }
+ }
+
+ return OK;
+}
+
status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
ALOGV("%s: Send in reprocess request with id %d",
__FUNCTION__, requestId);
@@ -249,18 +343,45 @@ status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
res = request.update(ANDROID_REQUEST_TYPE,
&requestType, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request type",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
int32_t inputStreams[1] =
{ mZslStreamId };
- if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
+ res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
inputStreams, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request input streams",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ uint8_t captureIntent =
+ static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+ res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
+ &captureIntent, 1);
+ if (res != OK ) {
+ ALOGE("%s: Unable to update request capture intent",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
// TODO: Shouldn't we also update the latest preview frame?
int32_t outputStreams[1] =
{ client->getCaptureStreamId() };
- if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+ res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreams, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request output streams",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
res = request.update(ANDROID_REQUEST_ID,
&requestId, 1);
-
if (res != OK ) {
ALOGE("%s: Unable to update frame to a reprocess request",
__FUNCTION__);
@@ -288,6 +409,13 @@ status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
}
}
+ // Update post-processing settings
+ res = updateRequestWithDefaultStillRequest(request);
+ if (res != OK) {
+ ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
+ "may be compromised", __FUNCTION__);
+ }
+
mLatestCapturedRequest = request;
res = client->getCameraDevice()->capture(request);
if (res != OK ) {
@@ -312,11 +440,19 @@ status_t ZslProcessor3::clearZslQueue() {
status_t ZslProcessor3::clearZslQueueLocked() {
if (mZslStream != 0) {
- return mZslStream->clearInputRingBuffer();
+ // clear result metadata list first.
+ clearZslResultQueueLocked();
+ return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
}
return OK;
}
+void ZslProcessor3::clearZslResultQueueLocked() {
+ mFrameList.clear();
+ mFrameListHead = 0;
+ mFrameList.insertAt(0, mFrameListDepth);
+}
+
void ZslProcessor3::dump(int fd, const Vector<String16>& /*args*/) const {
Mutex::Autolock l(mInputMutex);
if (!mLatestCapturedRequest.isEmpty()) {
@@ -368,6 +504,23 @@ void ZslProcessor3::dumpZslQueue(int fd) const {
}
}
+bool ZslProcessor3::isFixedFocusMode(uint8_t afMode) const {
+ switch (afMode) {
+ case ANDROID_CONTROL_AF_MODE_AUTO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ case ANDROID_CONTROL_AF_MODE_MACRO:
+ return false;
+ break;
+ case ANDROID_CONTROL_AF_MODE_OFF:
+ case ANDROID_CONTROL_AF_MODE_EDOF:
+ return true;
+ default:
+ ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
+ return false;
+ }
+}
+
nsecs_t ZslProcessor3::getCandidateTimestampLocked(size_t* metadataIdx) const {
/**
* Find the smallest timestamp we know about so far
@@ -413,6 +566,38 @@ nsecs_t ZslProcessor3::getCandidateTimestampLocked(size_t* metadataIdx) const {
continue;
}
+ entry = frame.find(ANDROID_CONTROL_AF_MODE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF mode field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afMode = entry.data.u8[0];
+ if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
+ // Skip all the ZSL buffer for manual AF mode, as we don't really
+ // know the af state.
+ continue;
+ }
+
+ // Check AF state if device has focuser and focus mode isn't fixed
+ if (mHasFocuser && !isFixedFocusMode(afMode)) {
+ // Make sure the candidate frame has good focus.
+ entry = frame.find(ANDROID_CONTROL_AF_STATE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF state field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afState = entry.data.u8[0];
+ if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
+ afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
+ afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+ ALOGW("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
+ __FUNCTION__, afState);
+ continue;
+ }
+ }
+
minTimestamp = frameTimestamp;
idx = j;
}
@@ -453,13 +638,15 @@ void ZslProcessor3::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
}
void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) {
- Mutex::Autolock l(mInputMutex);
// ignore output buffers
if (bufferInfo.mOutput) {
return;
}
+ // Lock mutex only once we know this is an input buffer returned to avoid
+ // potential deadlock
+ Mutex::Autolock l(mInputMutex);
// TODO: Verify that the buffer is in our queue by looking at timestamp
// theoretically unnecessary unless we change the following assumptions:
// -- only 1 buffer reprocessed at a time (which is the case now)
@@ -470,11 +657,17 @@ void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) {
// We need to guarantee that if we do two back-to-back captures,
// the second won't use a buffer that's older/the same as the first, which
// is theoretically possible if we don't clear out the queue and the
- // selection criteria is something like 'newest'. Clearing out the queue
- // on a completed capture ensures we'll only use new data.
+ // selection criteria is something like 'newest'. Clearing out the result
+ // metadata queue on a completed capture ensures we'll only use new timestamp.
+ // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
+ // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
+ // to hold the same lock.
+ // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
+ // it is safe not to do so, as back to back ZSL capture requires stop and start
+ // preview, which will flush ZSL queue automatically.
ALOGV("%s: Memory optimization, clearing ZSL queue",
__FUNCTION__);
- clearZslQueueLocked();
+ clearZslResultQueueLocked();
// Required so we accept more ZSL requests
mState = RUNNING;
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
index d2f8322..fc9f70c 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
@@ -50,8 +50,8 @@ class ZslProcessor3 :
ZslProcessor3(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
~ZslProcessor3();
- // From FrameProcessor
- virtual void onFrameAvailable(int32_t requestId, const CameraMetadata &frame);
+ // From FrameProcessor::FilteredListener
+ virtual void onResultAvailable(const CaptureResult &result);
/**
****************************************
@@ -82,6 +82,7 @@ class ZslProcessor3 :
private:
static const nsecs_t kWaitDuration = 10000000; // 10 ms
+ nsecs_t mLatestClearedBufferTimestamp;
enum {
RUNNING,
@@ -107,8 +108,9 @@ class ZslProcessor3 :
CameraMetadata frame;
};
- static const size_t kZslBufferDepth = 4;
- static const size_t kFrameListDepth = kZslBufferDepth * 2;
+ static const int32_t kDefaultMaxPipelineDepth = 4;
+ size_t mBufferQueueDepth;
+ size_t mFrameListDepth;
Vector<CameraMetadata> mFrameList;
size_t mFrameListHead;
@@ -120,13 +122,22 @@ class ZslProcessor3 :
CameraMetadata mLatestCapturedRequest;
+ bool mHasFocuser;
+
virtual bool threadLoop();
status_t clearZslQueueLocked();
+ void clearZslResultQueueLocked();
+
void dumpZslQueue(int id) const;
nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
+
+ bool isFixedFocusMode(uint8_t afMode) const;
+
+ // Update the post-processing metadata with the default still capture request template
+ status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
};
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
new file mode 100644
index 0000000..9efeaba
--- /dev/null
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "ZslProcessorInterface.h"
+
+namespace android {
+namespace camera2 {
+
+status_t ZslProcessorInterface::disconnect() {
+ return OK;
+}
+
+}; //namespace camera2
+}; //namespace android
+
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
index 183c0c2..9e266e7 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
@@ -19,6 +19,8 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
namespace android {
namespace camera2 {
@@ -37,6 +39,9 @@ public:
// Delete the underlying CameraDevice streams
virtual status_t deleteStream() = 0;
+ // Clear any additional state necessary before the CameraDevice is disconnected
+ virtual status_t disconnect();
+
/**
* Submits a ZSL capture request (id = requestId)
*
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 142da9e..e3301aa 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -16,13 +16,14 @@
#define LOG_TAG "CameraDeviceClient"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-// #define LOG_NDEBUG 0
+//#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 <camera/CameraUtils.h>
#include "common/CameraDeviceBase.h"
#include "api2/CameraDeviceClient.h"
@@ -82,7 +83,7 @@ status_t CameraDeviceClient::initialize(camera_module_t *module)
mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
FRAME_PROCESSOR_LISTENER_MAX_ID,
/*listener*/this,
- /*quirkSendPartials*/true);
+ /*sendPartials*/true);
return OK;
}
@@ -91,79 +92,101 @@ CameraDeviceClient::~CameraDeviceClient() {
}
status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
- bool streaming) {
+ bool streaming,
+ /*out*/
+ int64_t* lastFrameNumber) {
+ List<sp<CaptureRequest> > requestList;
+ requestList.push_back(request);
+ return submitRequestList(requestList, streaming, lastFrameNumber);
+}
+
+status_t CameraDeviceClient::submitRequestList(List<sp<CaptureRequest> > requests,
+ bool streaming, int64_t* lastFrameNumber) {
ATRACE_CALL();
- ALOGV("%s", __FUNCTION__);
+ ALOGV("%s-start of function. Request list size %zu", __FUNCTION__, requests.size());
status_t res;
-
if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
Mutex::Autolock icl(mBinderSerializationLock);
if (!mDevice.get()) return DEAD_OBJECT;
- if (request == 0) {
+ if (requests.empty()) {
ALOGE("%s: Camera %d: Sent null request. Rejecting request.",
__FUNCTION__, mCameraId);
return BAD_VALUE;
}
- CameraMetadata metadata(request->mMetadata);
+ List<const CameraMetadata> metadataRequestList;
+ int32_t requestId = mRequestIdCounter;
+ uint32_t loopCounter = 0;
- 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;
- }
+ for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end(); ++it) {
+ sp<CaptureRequest> request = *it;
+ if (request == 0) {
+ ALOGE("%s: Camera %d: Sent null request.",
+ __FUNCTION__, mCameraId);
+ return BAD_VALUE;
+ }
- /**
- * 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];
+ 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.isEmpty()) {
+ ALOGE("%s: Camera %d: Requests must have at least one surface target. "
+ "Rejecting request.", __FUNCTION__, mCameraId);
+ return BAD_VALUE;
+ }
- if (surface == 0) continue;
+ if (!enforceRequestPermissions(metadata)) {
+ // Callee logs
+ return PERMISSION_DENIED;
+ }
- sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
- int idx = mStreamMap.indexOfKey(gbp->asBinder());
+ /**
+ * 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;
+ }
- // 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);
}
- 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());
- metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
- outputStreamIds.size());
+ metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
+ loopCounter++; // loopCounter starts from 1
+ ALOGV("%s: Camera %d: Creating request with ID %d (%d of %zu)",
+ __FUNCTION__, mCameraId, requestId, loopCounter, requests.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);
+ metadataRequestList.push_back(metadata);
+ }
+ mRequestIdCounter++;
if (streaming) {
- res = mDevice->setStreamingRequest(metadata);
+ res = mDevice->setStreamingRequestList(metadataRequestList, lastFrameNumber);
if (res != OK) {
ALOGE("%s: Camera %d: Got error %d after trying to set streaming "
"request", __FUNCTION__, mCameraId, res);
@@ -171,11 +194,12 @@ status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
mStreamingRequestList.push_back(requestId);
}
} else {
- res = mDevice->capture(metadata);
+ res = mDevice->captureList(metadataRequestList, lastFrameNumber);
if (res != OK) {
ALOGE("%s: Camera %d: Got error %d after trying to set capture",
- __FUNCTION__, mCameraId, res);
+ __FUNCTION__, mCameraId, res);
}
+ ALOGV("%s: requestId = %d ", __FUNCTION__, requestId);
}
ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId);
@@ -186,7 +210,7 @@ status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
return res;
}
-status_t CameraDeviceClient::cancelRequest(int requestId) {
+status_t CameraDeviceClient::cancelRequest(int requestId, int64_t* lastFrameNumber) {
ATRACE_CALL();
ALOGV("%s, requestId = %d", __FUNCTION__, requestId);
@@ -212,7 +236,7 @@ status_t CameraDeviceClient::cancelRequest(int requestId) {
return BAD_VALUE;
}
- res = mDevice->clearStreamingRequest();
+ res = mDevice->clearStreamingRequest(lastFrameNumber);
if (res == OK) {
ALOGV("%s: Camera %d: Successfully cleared streaming request",
@@ -223,6 +247,26 @@ status_t CameraDeviceClient::cancelRequest(int requestId) {
return res;
}
+status_t CameraDeviceClient::beginConfigure() {
+ // TODO: Implement this.
+ ALOGE("%s: Not implemented yet.", __FUNCTION__);
+ return OK;
+}
+
+status_t CameraDeviceClient::endConfigure() {
+ ALOGV("%s: ending configure (%zu streams)",
+ __FUNCTION__, mStreamMap.size());
+
+ status_t res;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) return DEAD_OBJECT;
+
+ return mDevice->configureStreams();
+}
+
status_t CameraDeviceClient::deleteStream(int streamId) {
ATRACE_CALL();
ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
@@ -259,8 +303,6 @@ status_t CameraDeviceClient::deleteStream(int streamId) {
} else if (res == OK) {
mStreamMap.removeItemsAt(index);
- ALOGV("%s: Camera %d: Successfully deleted stream ID (%d)",
- __FUNCTION__, mCameraId, streamId);
}
return res;
@@ -277,6 +319,10 @@ status_t CameraDeviceClient::createStream(int width, int height, int format,
Mutex::Autolock icl(mBinderSerializationLock);
+ if (bufferProducer == NULL) {
+ ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
+ return BAD_VALUE;
+ }
if (!mDevice.get()) return DEAD_OBJECT;
// Don't create multiple streams for the same target surface
@@ -346,23 +392,7 @@ status_t CameraDeviceClient::createStream(int width, int height, int format,
// 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);
- }
+ res = mDevice->createStream(anw, width, height, format, &streamId);
if (res == OK) {
mStreamMap.add(bufferProducer->asBinder(), streamId);
@@ -465,7 +495,7 @@ status_t CameraDeviceClient::waitUntilIdle()
return res;
}
-status_t CameraDeviceClient::flush() {
+status_t CameraDeviceClient::flush(int64_t* lastFrameNumber) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
@@ -476,30 +506,43 @@ status_t CameraDeviceClient::flush() {
if (!mDevice.get()) return DEAD_OBJECT;
- return mDevice->flush();
+ mStreamingRequestList.clear();
+ return mDevice->flush(lastFrameNumber);
}
status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
String8 result;
- result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
+ result.appendFormat("CameraDeviceClient[%d] (%p) dump:\n",
mCameraId,
- getRemoteCallback()->asBinder().get(),
- mClientPid);
- result.append(" State: ");
-
+ getRemoteCallback()->asBinder().get());
+ result.appendFormat(" Current client: %s (PID %d, UID %u)\n",
+ String8(mClientPackageName).string(),
+ mClientPid, mClientUid);
+
+ result.append(" State:\n");
+ result.appendFormat(" Request ID counter: %d\n", mRequestIdCounter);
+ if (!mStreamMap.isEmpty()) {
+ result.append(" Current stream IDs:\n");
+ for (size_t i = 0; i < mStreamMap.size(); i++) {
+ result.appendFormat(" Stream %d\n", mStreamMap.valueAt(i));
+ }
+ } else {
+ result.append(" No streams configured.\n");
+ }
+ write(fd, result.string(), result.size());
// TODO: print dynamic/request section from most recent requests
mFrameProcessor->dump(fd, args);
return dumpDevice(fd, args);
}
-
-void CameraDeviceClient::notifyError() {
+void CameraDeviceClient::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
// Thread safe. Don't bother locking.
sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
if (remoteCb != 0) {
- remoteCb->onDeviceError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE);
+ remoteCb->onDeviceError(errorCode, resultExtras);
}
}
@@ -512,12 +555,12 @@ void CameraDeviceClient::notifyIdle() {
}
}
-void CameraDeviceClient::notifyShutter(int requestId,
+void CameraDeviceClient::notifyShutter(const CaptureResultExtras& resultExtras,
nsecs_t timestamp) {
// Thread safe. Don't bother locking.
sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
if (remoteCb != 0) {
- remoteCb->onCaptureStarted(requestId, timestamp);
+ remoteCb->onCaptureStarted(resultExtras, timestamp);
}
}
@@ -552,16 +595,14 @@ void CameraDeviceClient::detachDevice() {
}
/** Device-related methods */
-void CameraDeviceClient::onFrameAvailable(int32_t requestId,
- const CameraMetadata& frame) {
+void CameraDeviceClient::onResultAvailable(const CaptureResult& result) {
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);
+ remoteCb->onResultReceived(result.mMetadata, result.mResultExtras);
}
}
@@ -620,61 +661,8 @@ bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
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;
+ return CameraUtils::getRotationTransform(staticInfo, transform);
}
} // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index b9c16aa..9981dfe 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -63,9 +63,22 @@ public:
*/
// 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);
+ virtual status_t submitRequest(sp<CaptureRequest> request,
+ bool streaming = false,
+ /*out*/
+ int64_t* lastFrameNumber = NULL);
+ // List of requests are copied.
+ virtual status_t submitRequestList(List<sp<CaptureRequest> > requests,
+ bool streaming = false,
+ /*out*/
+ int64_t* lastFrameNumber = NULL);
+ virtual status_t cancelRequest(int requestId,
+ /*out*/
+ int64_t* lastFrameNumber = NULL);
+
+ virtual status_t beginConfigure();
+
+ virtual status_t endConfigure();
// Returns -EBUSY if device is not idle
virtual status_t deleteStream(int streamId);
@@ -89,7 +102,8 @@ public:
virtual status_t waitUntilIdle();
// Flush all active and pending requests as fast as possible
- virtual status_t flush();
+ virtual status_t flush(/*out*/
+ int64_t* lastFrameNumber = NULL);
/**
* Interface used by CameraService
@@ -114,16 +128,16 @@ public:
*/
virtual void notifyIdle();
- virtual void notifyError();
- virtual void notifyShutter(int requestId, nsecs_t timestamp);
+ virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
+ virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp);
/**
* Interface used by independent components of CameraDeviceClient.
*/
protected:
/** FilteredListener implementation **/
- virtual void onFrameAvailable(int32_t requestId,
- const CameraMetadata& frame);
+ virtual void onResultAvailable(const CaptureResult& result);
virtual void detachDevice();
// Calculate the ANativeWindow transform from android.sensor.orientation
diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
index 1a7a7a7..2ea460f 100644
--- a/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.cpp
@@ -280,7 +280,7 @@ status_t ProCamera2Client::createStream(int width, int height, int format,
window = new Surface(bufferProducer);
}
- return mDevice->createStream(window, width, height, format, /*size*/1,
+ return mDevice->createStream(window, width, height, format,
streamId);
}
@@ -336,11 +336,11 @@ status_t ProCamera2Client::dump(int fd, const Vector<String16>& args) {
mCameraId,
getRemoteCallback()->asBinder().get(),
mClientPid);
- result.append(" State: ");
+ result.append(" State:\n");
+ write(fd, result.string(), result.size());
// TODO: print dynamic/request section from most recent requests
mFrameProcessor->dump(fd, args);
-
return dumpDevice(fd, args);
}
@@ -373,9 +373,7 @@ void ProCamera2Client::detachDevice() {
Camera2ClientBase::detachDevice();
}
-/** Device-related methods */
-void ProCamera2Client::onFrameAvailable(int32_t requestId,
- const CameraMetadata& frame) {
+void ProCamera2Client::onResultAvailable(const CaptureResult& result) {
ATRACE_CALL();
ALOGV("%s", __FUNCTION__);
@@ -383,13 +381,12 @@ void ProCamera2Client::onFrameAvailable(int32_t requestId,
SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
if (mRemoteCallback != NULL) {
- CameraMetadata tmp(frame);
+ CameraMetadata tmp(result.mMetadata);
camera_metadata_t* meta = tmp.release();
ALOGV("%s: meta = %p ", __FUNCTION__, meta);
- mRemoteCallback->onResultReceived(requestId, meta);
+ mRemoteCallback->onResultReceived(result.mResultExtras.requestId, meta);
tmp.acquire(meta);
}
-
}
bool ProCamera2Client::enforceRequestPermissions(CameraMetadata& metadata) {
diff --git a/services/camera/libcameraservice/api_pro/ProCamera2Client.h b/services/camera/libcameraservice/api_pro/ProCamera2Client.h
index 8a0f547..9d83122 100644
--- a/services/camera/libcameraservice/api_pro/ProCamera2Client.h
+++ b/services/camera/libcameraservice/api_pro/ProCamera2Client.h
@@ -21,6 +21,7 @@
#include "common/FrameProcessorBase.h"
#include "common/Camera2ClientBase.h"
#include "device2/Camera2Device.h"
+#include "camera/CaptureResult.h"
namespace android {
@@ -97,8 +98,8 @@ public:
protected:
/** FilteredListener implementation **/
- virtual void onFrameAvailable(int32_t requestId,
- const CameraMetadata& frame);
+ virtual void onResultAvailable(const CaptureResult& result);
+
virtual void detachDevice();
private:
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 6a88c87..d6db151 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -54,10 +54,13 @@ Camera2ClientBase<TClientBase>::Camera2ClientBase(
int servicePid):
TClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
- mSharedCameraCallbacks(remoteCallback)
+ mSharedCameraCallbacks(remoteCallback),
+ mDeviceVersion(cameraService->getDeviceVersion(cameraId))
{
- ALOGI("Camera %d: Opened", cameraId);
+ ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId,
+ String8(clientPackageName).string(), clientPid, clientUid);
+ mInitialClientPid = clientPid;
mDevice = CameraDeviceFactory::createDevice(cameraId);
LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
@@ -111,11 +114,12 @@ Camera2ClientBase<TClientBase>::~Camera2ClientBase() {
TClientBase::mDestructionStarted = true;
- TClientBase::finishCameraOps();
-
disconnect();
- ALOGI("Closed Camera %d", TClientBase::mCameraId);
+ ALOGI("Closed Camera %d. Client was: %s (PID %d, UID %u)",
+ TClientBase::mCameraId,
+ String8(TClientBase::mClientPackageName).string(),
+ mInitialClientPid, TClientBase::mClientUid);
}
template <typename TClientBase>
@@ -221,10 +225,11 @@ status_t Camera2ClientBase<TClientBase>::connect(
/** Device-related methods */
template <typename TClientBase>
-void Camera2ClientBase<TClientBase>::notifyError(int errorCode, int arg1,
- int arg2) {
- ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode,
- arg1, arg2);
+void Camera2ClientBase<TClientBase>::notifyError(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ ALOGE("Error condition %d reported by HAL, requestId %" PRId32, errorCode,
+ resultExtras.requestId);
}
template <typename TClientBase>
@@ -233,13 +238,13 @@ void Camera2ClientBase<TClientBase>::notifyIdle() {
}
template <typename TClientBase>
-void Camera2ClientBase<TClientBase>::notifyShutter(int requestId,
+void Camera2ClientBase<TClientBase>::notifyShutter(const CaptureResultExtras& resultExtras,
nsecs_t timestamp) {
- (void)requestId;
+ (void)resultExtras;
(void)timestamp;
- ALOGV("%s: Shutter notification for request id %d at time %" PRId64,
- __FUNCTION__, requestId, timestamp);
+ ALOGV("%s: Shutter notification for request id %" PRId32 " at time %" PRId64,
+ __FUNCTION__, resultExtras.requestId, timestamp);
}
template <typename TClientBase>
@@ -279,6 +284,11 @@ int Camera2ClientBase<TClientBase>::getCameraId() const {
}
template <typename TClientBase>
+int Camera2ClientBase<TClientBase>::getCameraDeviceVersion() const {
+ return mDeviceVersion;
+}
+
+template <typename TClientBase>
const sp<CameraDeviceBase>& Camera2ClientBase<TClientBase>::getCameraDevice() {
return mDevice;
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 61e44f0..d198e4e 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -18,6 +18,7 @@
#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
#include "common/CameraDeviceBase.h"
+#include "camera/CaptureResult.h"
namespace android {
@@ -61,9 +62,11 @@ public:
* CameraDeviceBase::NotificationListener implementation
*/
- virtual void notifyError(int errorCode, int arg1, int arg2);
+ virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
virtual void notifyIdle();
- virtual void notifyShutter(int requestId, nsecs_t timestamp);
+ virtual void notifyShutter(const CaptureResultExtras& resultExtras,
+ 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,
@@ -73,6 +76,7 @@ public:
int getCameraId() const;
const sp<CameraDeviceBase>&
getCameraDevice();
+ int getCameraDeviceVersion() const;
const sp<CameraService>&
getCameraService();
@@ -103,6 +107,9 @@ public:
protected:
+ // The PID provided in the constructor call
+ pid_t mInitialClientPid;
+
virtual sp<IBinder> asBinderWrapper() {
return IInterface::asBinder();
}
@@ -119,6 +126,7 @@ protected:
/** CameraDeviceBase instance wrapping HAL2+ entry */
+ const int mDeviceVersion;
sp<CameraDeviceBase> mDevice;
/** Utility members */
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index e80abf1..d26e20c 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -22,9 +22,13 @@
#include <utils/String16.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
+#include <utils/List.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
#include "hardware/camera2.h"
+#include "hardware/camera3.h"
#include "camera/CameraMetadata.h"
+#include "camera/CaptureResult.h"
namespace android {
@@ -44,7 +48,7 @@ class CameraDeviceBase : public virtual RefBase {
virtual status_t initialize(camera_module_t *module) = 0;
virtual status_t disconnect() = 0;
- virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+ virtual status_t dump(int fd, const Vector<String16> &args) = 0;
/**
* The device's static characteristics metadata buffer
@@ -54,19 +58,37 @@ class CameraDeviceBase : public virtual RefBase {
/**
* Submit request for capture. The CameraDevice takes ownership of the
* passed-in buffer.
+ * Output lastFrameNumber is the expected frame number of this request.
*/
- virtual status_t capture(CameraMetadata &request) = 0;
+ virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL) = 0;
+
+ /**
+ * Submit a list of requests.
+ * Output lastFrameNumber is the expected last frame number of the list of requests.
+ */
+ virtual status_t captureList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber = NULL) = 0;
/**
* Submit request for streaming. The CameraDevice makes a copy of the
* passed-in buffer and the caller retains ownership.
+ * Output lastFrameNumber is the last frame number of the previous streaming request.
+ */
+ virtual status_t setStreamingRequest(const CameraMetadata &request,
+ int64_t *lastFrameNumber = NULL) = 0;
+
+ /**
+ * Submit a list of requests for streaming.
+ * Output lastFrameNumber is the last frame number of the previous streaming request.
*/
- virtual status_t setStreamingRequest(const CameraMetadata &request) = 0;
+ virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber = NULL) = 0;
/**
* Clear the streaming request slot.
+ * Output lastFrameNumber is the last frame number of the previous streaming request.
*/
- virtual status_t clearStreamingRequest() = 0;
+ virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL) = 0;
/**
* Wait until a request with the given ID has been dequeued by the
@@ -87,8 +109,7 @@ class CameraDeviceBase : public virtual RefBase {
* other formats, the size parameter is ignored.
*/
virtual status_t createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size,
- int *id) = 0;
+ uint32_t width, uint32_t height, int format, int *id) = 0;
/**
* Create an input reprocess stream that uses buffers from an existing
@@ -120,6 +141,18 @@ class CameraDeviceBase : public virtual RefBase {
virtual status_t deleteReprocessStream(int id) = 0;
/**
+ * Take the currently-defined set of streams and configure the HAL to use
+ * them. This is a long-running operation (may be several hundered ms).
+ *
+ * The device must be idle (see waitUntilDrained) before calling this.
+ *
+ * Returns OK on success; otherwise on error:
+ * - BAD_VALUE if the set of streams was invalid (e.g. fmts or sizes)
+ * - INVALID_OPERATION if the device was in the wrong state
+ */
+ virtual status_t configureStreams() = 0;
+
+ /**
* Create a metadata buffer with fields that the HAL device believes are
* best for the given use case
*/
@@ -134,6 +167,12 @@ class CameraDeviceBase : public virtual RefBase {
virtual status_t waitUntilDrained() = 0;
/**
+ * Get Jpeg buffer size for a given jpeg resolution.
+ * Negative values are error codes.
+ */
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+
+ /**
* Abstract class for HAL notification listeners
*/
class NotificationListener {
@@ -142,11 +181,12 @@ class CameraDeviceBase : public virtual RefBase {
// API1 and API2.
// Required for API 1 and 2
- virtual void notifyError(int errorCode, int arg1, int arg2) = 0;
+ virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras &resultExtras) = 0;
// Required only for API2
virtual void notifyIdle() = 0;
- virtual void notifyShutter(int requestId,
+ virtual void notifyShutter(const CaptureResultExtras &resultExtras,
nsecs_t timestamp) = 0;
// Required only for API1
@@ -179,11 +219,12 @@ class CameraDeviceBase : public virtual RefBase {
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
+ * Get next capture result frame from the result queue. Returns NOT_ENOUGH_DATA
+ * if the queue is empty; caller takes ownership of the metadata buffer inside
+ * the capture result object's metadata field.
+ * May be called concurrently to most methods, except for waitForNextFrame.
*/
- virtual status_t getNextFrame(CameraMetadata *frame) = 0;
+ virtual status_t getNextResult(CaptureResult *frame) = 0;
/**
* Trigger auto-focus. The latest ID used in a trigger autofocus or cancel
@@ -224,9 +265,14 @@ class CameraDeviceBase : public virtual RefBase {
/**
* Flush all pending and in-flight requests. Blocks until flush is
* complete.
+ * Output lastFrameNumber is the last frame number of the previous streaming request.
*/
- virtual status_t flush() = 0;
+ virtual status_t flush(int64_t *lastFrameNumber = NULL) = 0;
+ /**
+ * Get the HAL device version.
+ */
+ virtual uint32_t getDeviceVersion() = 0;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.cpp b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
index 4d31667..29eb78f 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.cpp
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.cpp
@@ -29,7 +29,17 @@ namespace camera2 {
FrameProcessorBase::FrameProcessorBase(wp<CameraDeviceBase> device) :
Thread(/*canCallJava*/false),
- mDevice(device) {
+ mDevice(device),
+ mNumPartialResults(1) {
+ sp<CameraDeviceBase> cameraDevice = device.promote();
+ if (cameraDevice != 0 &&
+ cameraDevice->getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
+ CameraMetadata staticInfo = cameraDevice->info();
+ camera_metadata_entry_t entry = staticInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+ if (entry.count > 0) {
+ mNumPartialResults = entry.data.i32[0];
+ }
+ }
}
FrameProcessorBase::~FrameProcessorBase() {
@@ -37,11 +47,23 @@ FrameProcessorBase::~FrameProcessorBase() {
}
status_t FrameProcessorBase::registerListener(int32_t minId,
- int32_t maxId, wp<FilteredListener> listener, bool quirkSendPartials) {
+ int32_t maxId, wp<FilteredListener> listener, bool sendPartials) {
Mutex::Autolock l(mInputMutex);
+ List<RangeListener>::iterator item = mRangeListeners.begin();
+ while (item != mRangeListeners.end()) {
+ if (item->minId == minId &&
+ item->maxId == maxId &&
+ item->listener == listener) {
+ // already registered, just return
+ ALOGV("%s: Attempt to register the same client twice, ignoring",
+ __FUNCTION__);
+ return OK;
+ }
+ item++;
+ }
ALOGV("%s: Registering listener for frame id range %d - %d",
__FUNCTION__, minId, maxId);
- RangeListener rListener = { minId, maxId, listener, quirkSendPartials };
+ RangeListener rListener = { minId, maxId, listener, sendPartials };
mRangeListeners.push_back(rListener);
return OK;
}
@@ -99,15 +121,17 @@ bool FrameProcessorBase::threadLoop() {
void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) {
status_t res;
ATRACE_CALL();
- CameraMetadata frame;
+ CaptureResult result;
ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId());
- while ( (res = device->getNextFrame(&frame)) == OK) {
+ while ( (res = device->getNextResult(&result)) == OK) {
+ // TODO: instead of getting frame number from metadata, we should read
+ // this from result.mResultExtras when CameraDeviceBase interface is fixed.
camera_metadata_entry_t entry;
- entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
+ entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
if (entry.count == 0) {
ALOGE("%s: Camera %d: Error reading frame number",
__FUNCTION__, device->getId());
@@ -115,13 +139,13 @@ void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) {
}
ATRACE_INT("cam2_frame", entry.data.i32[0]);
- if (!processSingleFrame(frame, device)) {
+ if (!processSingleFrame(result, device)) {
break;
}
- if (!frame.isEmpty()) {
+ if (!result.mMetadata.isEmpty()) {
Mutex::Autolock al(mLastFrameMutex);
- mLastFrame.acquire(frame);
+ mLastFrame.acquire(result.mMetadata);
}
}
if (res != NOT_ENOUGH_DATA) {
@@ -133,32 +157,40 @@ void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) {
return;
}
-bool FrameProcessorBase::processSingleFrame(CameraMetadata &frame,
- const sp<CameraDeviceBase> &device) {
+bool FrameProcessorBase::processSingleFrame(CaptureResult &result,
+ const sp<CameraDeviceBase> &device) {
ALOGV("%s: Camera %d: Process single frame (is empty? %d)",
- __FUNCTION__, device->getId(), frame.isEmpty());
- return processListeners(frame, device) == OK;
+ __FUNCTION__, device->getId(), result.mMetadata.isEmpty());
+ return processListeners(result, device) == OK;
}
-status_t FrameProcessorBase::processListeners(const CameraMetadata &frame,
+status_t FrameProcessorBase::processListeners(const CaptureResult &result,
const sp<CameraDeviceBase> &device) {
ATRACE_CALL();
+
camera_metadata_ro_entry_t entry;
- // Quirks: Don't deliver partial results to listeners that don't want them
- bool quirkIsPartial = false;
- entry = frame.find(ANDROID_QUIRKS_PARTIAL_RESULT);
- if (entry.count != 0 &&
- entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
- ALOGV("%s: Camera %d: Not forwarding partial result to listeners",
- __FUNCTION__, device->getId());
- quirkIsPartial = true;
+ // Check if this result is partial.
+ bool isPartialResult = false;
+ if (device->getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
+ isPartialResult = result.mResultExtras.partialResultCount < mNumPartialResults;
+ } else {
+ entry = result.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT);
+ if (entry.count != 0 &&
+ entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
+ ALOGV("%s: Camera %d: This is a partial result",
+ __FUNCTION__, device->getId());
+ isPartialResult = true;
+ }
}
- entry = frame.find(ANDROID_REQUEST_ID);
+ // TODO: instead of getting requestID from CameraMetadata, we should get it
+ // from CaptureResultExtras. This will require changing Camera2Device.
+ // Currently Camera2Device uses MetadataQueue to store results, which does not
+ // include CaptureResultExtras.
+ entry = result.mMetadata.find(ANDROID_REQUEST_ID);
if (entry.count == 0) {
- ALOGE("%s: Camera %d: Error reading frame id",
- __FUNCTION__, device->getId());
+ ALOGE("%s: Camera %d: Error reading frame id", __FUNCTION__, device->getId());
return BAD_VALUE;
}
int32_t requestId = entry.data.i32[0];
@@ -168,10 +200,10 @@ status_t FrameProcessorBase::processListeners(const CameraMetadata &frame,
Mutex::Autolock l(mInputMutex);
List<RangeListener>::iterator item = mRangeListeners.begin();
+ // Don't deliver partial results to listeners that don't want them
while (item != mRangeListeners.end()) {
- if (requestId >= item->minId &&
- requestId < item->maxId &&
- (!quirkIsPartial || item->quirkSendPartials) ) {
+ if (requestId >= item->minId && requestId < item->maxId &&
+ (!isPartialResult || item->sendPartials)) {
sp<FilteredListener> listener = item->listener.promote();
if (listener == 0) {
item = mRangeListeners.erase(item);
@@ -183,10 +215,12 @@ status_t FrameProcessorBase::processListeners(const CameraMetadata &frame,
item++;
}
}
- ALOGV("Got %zu range listeners out of %zu", listeners.size(), mRangeListeners.size());
+ ALOGV("%s: Camera %d: Got %zu range listeners out of %zu", __FUNCTION__,
+ device->getId(), listeners.size(), mRangeListeners.size());
+
List<sp<FilteredListener> >::iterator item = listeners.begin();
for (; item != listeners.end(); item++) {
- (*item)->onFrameAvailable(requestId, frame);
+ (*item)->onResultAvailable(result);
}
return OK;
}
diff --git a/services/camera/libcameraservice/common/FrameProcessorBase.h b/services/camera/libcameraservice/common/FrameProcessorBase.h
index 89b608a..a618d84 100644
--- a/services/camera/libcameraservice/common/FrameProcessorBase.h
+++ b/services/camera/libcameraservice/common/FrameProcessorBase.h
@@ -23,6 +23,7 @@
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <camera/CameraMetadata.h>
+#include <camera/CaptureResult.h>
namespace android {
@@ -39,16 +40,16 @@ class FrameProcessorBase: public Thread {
virtual ~FrameProcessorBase();
struct FilteredListener: virtual public RefBase {
- virtual void onFrameAvailable(int32_t requestId,
- const CameraMetadata &frame) = 0;
+ virtual void onResultAvailable(const CaptureResult &result) = 0;
};
// Register a listener for a range of IDs [minId, maxId). Multiple listeners
- // can be listening to the same range.
- // QUIRK: sendPartials controls whether partial results will be sent.
+ // can be listening to the same range. Registering the same listener with
+ // the same range of IDs has no effect.
+ // sendPartials controls whether partial results will be sent.
status_t registerListener(int32_t minId, int32_t maxId,
wp<FilteredListener> listener,
- bool quirkSendPartials = true);
+ bool sendPartials = true);
status_t removeListener(int32_t minId, int32_t maxId,
wp<FilteredListener> listener);
@@ -66,16 +67,19 @@ class FrameProcessorBase: public Thread {
int32_t minId;
int32_t maxId;
wp<FilteredListener> listener;
- bool quirkSendPartials;
+ bool sendPartials;
};
List<RangeListener> mRangeListeners;
+ // Number of partial result the HAL will potentially send.
+ int32_t mNumPartialResults;
+
void processNewFrames(const sp<CameraDeviceBase> &device);
- virtual bool processSingleFrame(CameraMetadata &frame,
+ virtual bool processSingleFrame(CaptureResult &result,
const sp<CameraDeviceBase> &device);
- status_t processListeners(const CameraMetadata &frame,
+ status_t processListeners(const CaptureResult &result,
const sp<CameraDeviceBase> &device);
CameraMetadata mLastFrame;
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 87b2807..6386838 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -92,8 +92,22 @@ public:
status_t initialize(hw_module_t *module)
{
ALOGI("Opening camera %s", mName.string());
- int rc = module->methods->open(module, mName.string(),
- (hw_device_t **)&mDevice);
+ camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module);
+ camera_info info;
+ status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info);
+ if (res != OK) return res;
+
+ int rc = OK;
+ if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
+ info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
+ // Open higher version camera device as HAL1.0 device.
+ rc = cameraModule->open_legacy(module, mName.string(),
+ CAMERA_DEVICE_API_VERSION_1_0,
+ (hw_device_t **)&mDevice);
+ } else {
+ rc = CameraService::filterOpenErrorCode(module->methods->open(
+ module, mName.string(), (hw_device_t **)&mDevice));
+ }
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
@@ -611,9 +625,14 @@ private:
static int __set_buffers_geometry(struct preview_stream_ops* w,
int width, int height, int format)
{
+ int rc;
ANativeWindow *a = anw(w);
- return native_window_set_buffers_geometry(a,
- width, height, format);
+
+ rc = native_window_set_buffers_dimensions(a, width, height);
+ if (!rc) {
+ rc = native_window_set_buffers_format(a, format);
+ }
+ return rc;
}
static int __set_crop(struct preview_stream_ops *w,
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index 2966d82..8caadd6 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -30,6 +30,7 @@
#include <utils/Trace.h>
#include <utils/Timers.h>
#include "Camera2Device.h"
+#include "CameraService.h"
namespace android {
@@ -67,8 +68,8 @@ status_t Camera2Device::initialize(camera_module_t *module)
camera2_device_t *device;
- res = module->common.methods->open(&module->common, name,
- reinterpret_cast<hw_device_t**>(&device));
+ res = CameraService::filterOpenErrorCode(module->common.methods->open(
+ &module->common, name, reinterpret_cast<hw_device_t**>(&device)));
if (res != OK) {
ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
@@ -112,20 +113,6 @@ status_t Camera2Device::initialize(camera_module_t *module)
return res;
}
- res = device->ops->get_metadata_vendor_tag_ops(device, &mVendorTagOps);
- if (res != OK ) {
- ALOGE("%s: Camera %d: Unable to retrieve tag ops from device: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
- res = set_camera_metadata_vendor_tag_ops(mVendorTagOps);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
res = device->ops->set_notify_callback(device, notificationCallback,
NULL);
if (res != OK) {
@@ -137,6 +124,7 @@ status_t Camera2Device::initialize(camera_module_t *module)
mDeviceInfo = info.static_camera_characteristics;
mHal2Device = device;
+ mDeviceVersion = device->common.version;
return OK;
}
@@ -213,7 +201,7 @@ const CameraMetadata& Camera2Device::info() const {
return mDeviceInfo;
}
-status_t Camera2Device::capture(CameraMetadata &request) {
+status_t Camera2Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) {
ATRACE_CALL();
ALOGV("%s: E", __FUNCTION__);
@@ -221,15 +209,29 @@ status_t Camera2Device::capture(CameraMetadata &request) {
return OK;
}
+status_t Camera2Device::captureList(const List<const CameraMetadata> &requests,
+ int64_t* /*lastFrameNumber*/) {
+ ATRACE_CALL();
+ ALOGE("%s: Camera2Device burst capture not implemented", __FUNCTION__);
+ return INVALID_OPERATION;
+}
-status_t Camera2Device::setStreamingRequest(const CameraMetadata &request) {
+status_t Camera2Device::setStreamingRequest(const CameraMetadata &request,
+ int64_t* /*lastFrameNumber*/) {
ATRACE_CALL();
ALOGV("%s: E", __FUNCTION__);
CameraMetadata streamRequest(request);
return mRequestQueue.setStreamSlot(streamRequest.release());
}
-status_t Camera2Device::clearStreamingRequest() {
+status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests,
+ int64_t* /*lastFrameNumber*/) {
+ ATRACE_CALL();
+ ALOGE("%s, Camera2Device streaming burst not implemented", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+
+status_t Camera2Device::clearStreamingRequest(int64_t* /*lastFrameNumber*/) {
ATRACE_CALL();
return mRequestQueue.setStreamSlot(NULL);
}
@@ -240,13 +242,16 @@ status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t time
}
status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size, int *id) {
+ uint32_t width, uint32_t height, int format, int *id) {
ATRACE_CALL();
status_t res;
ALOGV("%s: E", __FUNCTION__);
sp<StreamAdapter> stream = new StreamAdapter(mHal2Device);
-
+ size_t size = 0;
+ if (format == HAL_PIXEL_FORMAT_BLOB) {
+ size = getJpegBufferSize(width, height);
+ }
res = stream->connectToDevice(consumer, width, height, format, size);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
@@ -261,6 +266,17 @@ status_t Camera2Device::createStream(sp<ANativeWindow> consumer,
return OK;
}
+ssize_t Camera2Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
+ // Always give the max jpeg buffer size regardless of the actual jpeg resolution.
+ camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
+ if (jpegBufMaxSize.count == 0) {
+ ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
+ return BAD_VALUE;
+ }
+
+ return jpegBufMaxSize.data.i32[0];
+}
+
status_t Camera2Device::createReprocessStreamFromStream(int outputId, int *id) {
ATRACE_CALL();
status_t res;
@@ -399,6 +415,19 @@ status_t Camera2Device::deleteReprocessStream(int id) {
return OK;
}
+status_t Camera2Device::configureStreams() {
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+
+ /**
+ * HAL2 devices do not need to configure streams;
+ * streams are created on the fly.
+ */
+ ALOGW("%s: No-op for HAL2 devices", __FUNCTION__);
+
+ return OK;
+}
+
status_t Camera2Device::createDefaultRequest(int templateId,
CameraMetadata *request) {
@@ -462,7 +491,13 @@ void Camera2Device::notificationCallback(int32_t msg_type,
if (listener != NULL) {
switch (msg_type) {
case CAMERA2_MSG_ERROR:
- listener->notifyError(ext1, ext2, ext3);
+ // TODO: This needs to be fixed. ext2 and ext3 need to be considered.
+ listener->notifyError(
+ ((ext1 == CAMERA2_MSG_ERROR_DEVICE)
+ || (ext1 == CAMERA2_MSG_ERROR_HARDWARE)) ?
+ ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE :
+ ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE,
+ CaptureResultExtras());
break;
case CAMERA2_MSG_SHUTTER: {
// TODO: Only needed for camera2 API, which is unsupported
@@ -491,16 +526,22 @@ status_t Camera2Device::waitForNextFrame(nsecs_t timeout) {
return mFrameQueue.waitForBuffer(timeout);
}
-status_t Camera2Device::getNextFrame(CameraMetadata *frame) {
+status_t Camera2Device::getNextResult(CaptureResult *result) {
ATRACE_CALL();
+ ALOGV("%s: get CaptureResult", __FUNCTION__);
+ if (result == NULL) {
+ ALOGE("%s: result pointer is NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
status_t res;
camera_metadata_t *rawFrame;
res = mFrameQueue.dequeue(&rawFrame);
- if (rawFrame == NULL) {
+ if (rawFrame == NULL) {
return NOT_ENOUGH_DATA;
} else if (res == OK) {
- frame->acquire(rawFrame);
+ result->mMetadata.acquire(rawFrame);
}
+
return res;
}
@@ -570,13 +611,18 @@ status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId,
return res;
}
-status_t Camera2Device::flush() {
+status_t Camera2Device::flush(int64_t* /*lastFrameNumber*/) {
ATRACE_CALL();
mRequestQueue.clear();
return waitUntilDrained();
}
+uint32_t Camera2Device::getDeviceVersion() {
+ ATRACE_CALL();
+ return mDeviceVersion;
+}
+
/**
* Camera2Device::MetadataQueue
*/
@@ -1069,25 +1115,33 @@ status_t Camera2Device::StreamAdapter::connectToDevice(
}
if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
- res = native_window_set_buffers_geometry(mConsumerInterface.get(),
- mSize, 1, mFormat);
+ res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
+ mSize, 1);
if (res != OK) {
- ALOGE("%s: Unable to configure compressed stream buffer geometry"
+ ALOGE("%s: Unable to configure compressed stream buffer dimensions"
" %d x %d, size %zu for stream %d",
__FUNCTION__, mWidth, mHeight, mSize, mId);
return res;
}
} else {
- res = native_window_set_buffers_geometry(mConsumerInterface.get(),
- mWidth, mHeight, mFormat);
+ res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
+ mWidth, mHeight);
if (res != OK) {
- ALOGE("%s: Unable to configure stream buffer geometry"
- " %d x %d, format 0x%x for stream %d",
- __FUNCTION__, mWidth, mHeight, mFormat, mId);
+ ALOGE("%s: Unable to configure stream buffer dimensions"
+ " %d x %d for stream %d",
+ __FUNCTION__, mWidth, mHeight, mId);
return res;
}
}
+ res = native_window_set_buffers_format(mConsumerInterface.get(), mFormat);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure stream buffer format"
+ " %#x for stream %d",
+ __FUNCTION__, mFormat, mId);
+ return res;
+ }
+
int maxConsumerBuffers;
res = mConsumerInterface->query(mConsumerInterface.get(),
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 1f53c56..2a3f1d9 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -47,38 +47,48 @@ class Camera2Device: public CameraDeviceBase {
virtual status_t disconnect();
virtual status_t dump(int fd, const Vector<String16>& args);
virtual const CameraMetadata& info() const;
- virtual status_t capture(CameraMetadata &request);
- virtual status_t setStreamingRequest(const CameraMetadata &request);
- virtual status_t clearStreamingRequest();
+ virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL);
+ virtual status_t captureList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber = NULL);
+ virtual status_t setStreamingRequest(const CameraMetadata &request,
+ int64_t *lastFrameNumber = NULL);
+ virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber = NULL);
+ virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
virtual status_t createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size,
- int *id);
+ uint32_t width, uint32_t height, int format, int *id);
virtual status_t createReprocessStreamFromStream(int outputId, int *id);
virtual status_t getStreamInfo(int id,
uint32_t *width, uint32_t *height, uint32_t *format);
virtual status_t setStreamTransform(int id, int transform);
virtual status_t deleteStream(int id);
virtual status_t deleteReprocessStream(int id);
+ // No-op on HAL2 devices
+ virtual status_t configureStreams();
virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
virtual status_t waitUntilDrained();
virtual status_t setNotifyCallback(NotificationListener *listener);
virtual bool willNotify3A();
virtual status_t waitForNextFrame(nsecs_t timeout);
- virtual status_t getNextFrame(CameraMetadata *frame);
+ virtual status_t getNextResult(CaptureResult *frame);
virtual status_t triggerAutofocus(uint32_t id);
virtual status_t triggerCancelAutofocus(uint32_t id);
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();
+ virtual status_t flush(int64_t *lastFrameNumber = NULL);
+ virtual uint32_t getDeviceVersion();
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+
private:
const int mId;
camera2_device_t *mHal2Device;
CameraMetadata mDeviceInfo;
- vendor_tag_query_ops_t *mVendorTagOps;
+
+ uint32_t mDeviceVersion;
/**
* Queue class for both sending requests to a camera2 device, and for
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 1d4768c..6a7f9e7 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -48,6 +48,8 @@
#include "device3/Camera3OutputStream.h"
#include "device3/Camera3InputStream.h"
#include "device3/Camera3ZslStream.h"
+#include "device3/Camera3DummyStream.h"
+#include "CameraService.h"
using namespace android::camera3;
@@ -57,7 +59,8 @@ Camera3Device::Camera3Device(int id):
mId(id),
mHal3Device(NULL),
mStatus(STATUS_UNINITIALIZED),
- mUsePartialResultQuirk(false),
+ mUsePartialResult(false),
+ mNumPartialResults(1),
mNextResultFrameNumber(0),
mNextShutterFrameNumber(0),
mListener(NULL)
@@ -102,8 +105,11 @@ status_t Camera3Device::initialize(camera_module_t *module)
camera3_device_t *device;
- res = module->common.methods->open(&module->common, deviceName.string(),
- reinterpret_cast<hw_device_t**>(&device));
+ ATRACE_BEGIN("camera3->open");
+ res = CameraService::filterOpenErrorCode(module->common.methods->open(
+ &module->common, deviceName.string(),
+ reinterpret_cast<hw_device_t**>(&device)));
+ ATRACE_END();
if (res != OK) {
SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);
@@ -111,10 +117,9 @@ status_t Camera3Device::initialize(camera_module_t *module)
}
/** Cross-check device version */
-
- if (device->common.version != CAMERA_DEVICE_API_VERSION_3_0) {
+ if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) {
SET_ERR_L("Could not open camera: "
- "Camera device is not version %x, reports %x instead",
+ "Camera device should be at least %x, reports %x instead",
CAMERA_DEVICE_API_VERSION_3_0,
device->common.version);
device->common.close(&device->common);
@@ -122,13 +127,14 @@ status_t Camera3Device::initialize(camera_module_t *module)
}
camera_info info;
- res = module->get_camera_info(mId, &info);
+ res = CameraService::filterGetInfoErrorCode(module->get_camera_info(
+ mId, &info));
if (res != OK) return res;
if (info.device_version != device->common.version) {
SET_ERR_L("HAL reporting mismatched camera_info version (%x)"
" and device version (%x).",
- device->common.version, info.device_version);
+ info.device_version, device->common.version);
device->common.close(&device->common);
return BAD_VALUE;
}
@@ -146,24 +152,6 @@ status_t Camera3Device::initialize(camera_module_t *module)
return BAD_VALUE;
}
- /** Get vendor metadata tags */
-
- 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);
- if (res != OK) {
- SET_ERR_L("Unable to set tag ops: %s (%d)",
- strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
- }
-
/** Start up status tracker thread */
mStatusTracker = new StatusTracker(this);
res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());
@@ -189,20 +177,29 @@ status_t Camera3Device::initialize(camera_module_t *module)
/** Everything is good to go */
+ mDeviceVersion = device->common.version;
mDeviceInfo = info.static_camera_characteristics;
mHal3Device = device;
mStatus = STATUS_UNCONFIGURED;
mNextStreamId = 0;
+ mDummyStreamId = NO_STREAM;
mNeedConfig = true;
mPauseStateNotify = false;
- /** Check for quirks */
-
// Will the HAL be sending in early partial result metadata?
- camera_metadata_entry partialResultsQuirk =
- mDeviceInfo.find(ANDROID_QUIRKS_USE_PARTIAL_RESULT);
- if (partialResultsQuirk.count > 0 && partialResultsQuirk.data.u8[0] == 1) {
- mUsePartialResultQuirk = true;
+ if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ camera_metadata_entry partialResultsCount =
+ mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+ if (partialResultsCount.count > 0) {
+ mNumPartialResults = partialResultsCount.data.i32[0];
+ mUsePartialResult = (mNumPartialResults > 1);
+ }
+ } else {
+ camera_metadata_entry partialResultsQuirk =
+ mDeviceInfo.find(ANDROID_QUIRKS_USE_PARTIAL_RESULT);
+ if (partialResultsQuirk.count > 0 && partialResultsQuirk.data.u8[0] == 1) {
+ mUsePartialResult = true;
+ }
}
return OK;
@@ -271,7 +268,9 @@ status_t Camera3Device::disconnect() {
mStatusTracker.clear();
if (mHal3Device != NULL) {
+ ATRACE_BEGIN("camera3->close");
mHal3Device->common.close(&mHal3Device->common);
+ ATRACE_END();
mHal3Device = NULL;
}
@@ -298,6 +297,85 @@ bool Camera3Device::tryLockSpinRightRound(Mutex& lock) {
return gotLock;
}
+Camera3Device::Size Camera3Device::getMaxJpegResolution() const {
+ int32_t maxJpegWidth = 0, maxJpegHeight = 0;
+ if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ camera_metadata_ro_entry_t availableStreamConfigs =
+ mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ if (availableStreamConfigs.count == 0 ||
+ availableStreamConfigs.count % STREAM_CONFIGURATION_SIZE != 0) {
+ return Size(0, 0);
+ }
+
+ // Get max jpeg size (area-wise).
+ for (size_t i=0; i < availableStreamConfigs.count; i+= STREAM_CONFIGURATION_SIZE) {
+ int32_t format = availableStreamConfigs.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = availableStreamConfigs.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = availableStreamConfigs.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = availableStreamConfigs.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT
+ && format == HAL_PIXEL_FORMAT_BLOB &&
+ (width * height > maxJpegWidth * maxJpegHeight)) {
+ maxJpegWidth = width;
+ maxJpegHeight = height;
+ }
+ }
+ } else {
+ camera_metadata_ro_entry availableJpegSizes =
+ mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
+ if (availableJpegSizes.count == 0 || availableJpegSizes.count % 2 != 0) {
+ return Size(0, 0);
+ }
+
+ // Get max jpeg size (area-wise).
+ for (size_t i = 0; i < availableJpegSizes.count; i += 2) {
+ if ((availableJpegSizes.data.i32[i] * availableJpegSizes.data.i32[i + 1])
+ > (maxJpegWidth * maxJpegHeight)) {
+ maxJpegWidth = availableJpegSizes.data.i32[i];
+ maxJpegHeight = availableJpegSizes.data.i32[i + 1];
+ }
+ }
+ }
+ return Size(maxJpegWidth, maxJpegHeight);
+}
+
+ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
+ // Get max jpeg size (area-wise).
+ Size maxJpegResolution = getMaxJpegResolution();
+ if (maxJpegResolution.width == 0) {
+ ALOGE("%s: Camera %d: Can't find find valid available jpeg sizes in static metadata!",
+ __FUNCTION__, mId);
+ return BAD_VALUE;
+ }
+
+ // Get max jpeg buffer size
+ ssize_t maxJpegBufferSize = 0;
+ camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
+ if (jpegBufMaxSize.count == 0) {
+ ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
+ return BAD_VALUE;
+ }
+ maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
+
+ // Calculate final jpeg buffer size for the given resolution.
+ float scaleFactor = ((float) (width * height)) /
+ (maxJpegResolution.width * maxJpegResolution.height);
+ ssize_t jpegBufferSize = scaleFactor * maxJpegBufferSize;
+ // Bound the buffer size to [MIN_JPEG_BUFFER_SIZE, maxJpegBufferSize].
+ if (jpegBufferSize > maxJpegBufferSize) {
+ jpegBufferSize = maxJpegBufferSize;
+ } else if (jpegBufferSize < kMinJpegBufferSize) {
+ jpegBufferSize = kMinJpegBufferSize;
+ }
+
+ return jpegBufferSize;
+}
+
status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
ATRACE_CALL();
(void)args;
@@ -386,14 +464,7 @@ const CameraMetadata& Camera3Device::info() const {
return mDeviceInfo;
}
-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
-
+status_t Camera3Device::checkStatusOkToCaptureLocked() {
switch (mStatus) {
case STATUS_ERROR:
CLOGE("Device has encountered a serious error");
@@ -402,7 +473,6 @@ status_t Camera3Device::capture(CameraMetadata &request) {
CLOGE("Device not initialized");
return INVALID_OPERATION;
case STATUS_UNCONFIGURED:
- // May be lazily configuring streams, will check during setup
case STATUS_CONFIGURED:
case STATUS_ACTIVE:
// OK
@@ -411,71 +481,119 @@ status_t Camera3Device::capture(CameraMetadata &request) {
SET_ERR_L("Unexpected status: %d", mStatus);
return INVALID_OPERATION;
}
+ return OK;
+}
- sp<CaptureRequest> newRequest = setUpRequestLocked(request);
- if (newRequest == NULL) {
- CLOGE("Can't create capture request");
+status_t Camera3Device::convertMetadataListToRequestListLocked(
+ const List<const CameraMetadata> &metadataList, RequestList *requestList) {
+ if (requestList == NULL) {
+ CLOGE("requestList cannot be NULL.");
return BAD_VALUE;
}
- 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);
+ int32_t burstId = 0;
+ for (List<const CameraMetadata>::const_iterator it = metadataList.begin();
+ it != metadataList.end(); ++it) {
+ sp<CaptureRequest> newRequest = setUpRequestLocked(*it);
+ if (newRequest == 0) {
+ CLOGE("Can't create capture request");
+ return BAD_VALUE;
+ }
+
+ // Setup burst Id and request Id
+ newRequest->mResultExtras.burstId = burstId++;
+ if (it->exists(ANDROID_REQUEST_ID)) {
+ if (it->find(ANDROID_REQUEST_ID).count == 0) {
+ CLOGE("RequestID entry exists; but must not be empty in metadata");
+ return BAD_VALUE;
+ }
+ newRequest->mResultExtras.requestId = it->find(ANDROID_REQUEST_ID).data.i32[0];
+ } else {
+ CLOGE("RequestID does not exist in metadata");
+ return BAD_VALUE;
}
- ALOGV("Camera %d: Capture request enqueued", mId);
+
+ requestList->push_back(newRequest);
+
+ ALOGV("%s: requestId = %" PRId32, __FUNCTION__, newRequest->mResultExtras.requestId);
}
- return res;
+ return OK;
}
+status_t Camera3Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) {
+ ATRACE_CALL();
-status_t Camera3Device::setStreamingRequest(const CameraMetadata &request) {
+ List<const CameraMetadata> requests;
+ requests.push_back(request);
+ return captureList(requests, /*lastFrameNumber*/NULL);
+}
+
+status_t Camera3Device::submitRequestsHelper(
+ const List<const CameraMetadata> &requests, bool repeating,
+ /*out*/
+ int64_t *lastFrameNumber) {
ATRACE_CALL();
- status_t res;
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
- switch (mStatus) {
- case STATUS_ERROR:
- CLOGE("Device has encountered a serious error");
- return INVALID_OPERATION;
- case STATUS_UNINITIALIZED:
- CLOGE("Device not initialized");
- return INVALID_OPERATION;
- case STATUS_UNCONFIGURED:
- // May be lazily configuring streams, will check during setup
- case STATUS_CONFIGURED:
- case STATUS_ACTIVE:
- // OK
- break;
- default:
- SET_ERR_L("Unexpected status: %d", mStatus);
- return INVALID_OPERATION;
+ status_t res = checkStatusOkToCaptureLocked();
+ if (res != OK) {
+ // error logged by previous call
+ return res;
}
- sp<CaptureRequest> newRepeatingRequest = setUpRequestLocked(request);
- if (newRepeatingRequest == NULL) {
- CLOGE("Can't create repeating request");
- return BAD_VALUE;
+ RequestList requestList;
+
+ res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList);
+ if (res != OK) {
+ // error logged by previous call
+ return res;
}
- RequestList newRepeatingRequests;
- newRepeatingRequests.push_back(newRepeatingRequest);
+ if (repeating) {
+ res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);
+ } else {
+ res = mRequestThread->queueRequestList(requestList, lastFrameNumber);
+ }
- res = mRequestThread->setRepeatingRequests(newRepeatingRequests);
if (res == OK) {
- waitUntilStateThenRelock(/*active*/ true, kActiveTimeout);
+ 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);
+ ALOGV("Camera %d: Capture request %" PRId32 " enqueued", mId,
+ (*(requestList.begin()))->mResultExtras.requestId);
+ } else {
+ CLOGE("Cannot queue request. Impossible.");
+ return BAD_VALUE;
}
+
return res;
}
+status_t Camera3Device::captureList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber) {
+ ATRACE_CALL();
+
+ return submitRequestsHelper(requests, /*repeating*/false, lastFrameNumber);
+}
+
+status_t Camera3Device::setStreamingRequest(const CameraMetadata &request,
+ int64_t* /*lastFrameNumber*/) {
+ ATRACE_CALL();
+
+ List<const CameraMetadata> requests;
+ requests.push_back(request);
+ return setStreamingRequestList(requests, /*lastFrameNumber*/NULL);
+}
+
+status_t Camera3Device::setStreamingRequestList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber) {
+ ATRACE_CALL();
+
+ return submitRequestsHelper(requests, /*repeating*/true, lastFrameNumber);
+}
sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
const CameraMetadata &request) {
@@ -483,10 +601,18 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
if (mStatus == STATUS_UNCONFIGURED || mNeedConfig) {
res = configureStreamsLocked();
+ // Stream configuration failed due to unsupported configuration.
+ // Device back to unconfigured state. Client might try other configuraitons
+ if (res == BAD_VALUE && mStatus == STATUS_UNCONFIGURED) {
+ CLOGE("No streams configured");
+ return NULL;
+ }
+ // Stream configuration failed for other reason. Fatal.
if (res != OK) {
SET_ERR_L("Can't set up streams: %s (%d)", strerror(-res), res);
return NULL;
}
+ // Stream configuration successfully configure to empty stream configuration.
if (mStatus == STATUS_UNCONFIGURED) {
CLOGE("No streams configured");
return NULL;
@@ -497,7 +623,7 @@ sp<Camera3Device::CaptureRequest> Camera3Device::setUpRequestLocked(
return newRequest;
}
-status_t Camera3Device::clearStreamingRequest() {
+status_t Camera3Device::clearStreamingRequest(int64_t *lastFrameNumber) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
@@ -519,7 +645,8 @@ status_t Camera3Device::clearStreamingRequest() {
return INVALID_OPERATION;
}
ALOGV("Camera %d: Clearing repeating request", mId);
- return mRequestThread->clearRepeatingRequests();
+
+ return mRequestThread->clearRepeatingRequests(lastFrameNumber);
}
status_t Camera3Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
@@ -676,12 +803,12 @@ status_t Camera3Device::createZslStream(
}
status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size, int *id) {
+ 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 stream %d: %d x %d, format %d, size %zu",
- mId, mNextStreamId, width, height, format, size);
+ ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d",
+ mId, mNextStreamId, width, height, format);
status_t res;
bool wasActive = false;
@@ -714,8 +841,14 @@ status_t Camera3Device::createStream(sp<ANativeWindow> consumer,
sp<Camera3OutputStream> newStream;
if (format == HAL_PIXEL_FORMAT_BLOB) {
+ ssize_t jpegBufferSize = getJpegBufferSize(width, height);
+ if (jpegBufferSize <= 0) {
+ SET_ERR_L("Invalid jpeg buffer size %zd", jpegBufferSize);
+ return BAD_VALUE;
+ }
+
newStream = new Camera3OutputStream(mNextStreamId, consumer,
- width, height, size, format);
+ width, height, jpegBufferSize, format);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, format);
@@ -840,16 +973,20 @@ status_t Camera3Device::deleteStream(int id) {
}
sp<Camera3StreamInterface> deletedStream;
+ ssize_t outputStreamIdx = mOutputStreams.indexOfKey(id);
if (mInputStream != NULL && id == mInputStream->getId()) {
deletedStream = mInputStream;
mInputStream.clear();
} else {
- ssize_t idx = mOutputStreams.indexOfKey(id);
- if (idx == NAME_NOT_FOUND) {
+ if (outputStreamIdx == NAME_NOT_FOUND) {
CLOGE("Stream %d does not exist", id);
return BAD_VALUE;
}
- deletedStream = mOutputStreams.editValueAt(idx);
+ }
+
+ // Delete output stream or the output part of a bi-directional stream.
+ if (outputStreamIdx != NAME_NOT_FOUND) {
+ deletedStream = mOutputStreams.editValueAt(outputStreamIdx);
mOutputStreams.removeItem(id);
}
@@ -873,6 +1010,15 @@ status_t Camera3Device::deleteReprocessStream(int id) {
return INVALID_OPERATION;
}
+status_t Camera3Device::configureStreams() {
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ return configureStreamsLocked();
+}
status_t Camera3Device::createDefaultRequest(int templateId,
CameraMetadata *request) {
@@ -898,6 +1044,11 @@ status_t Camera3Device::createDefaultRequest(int templateId,
return INVALID_OPERATION;
}
+ if (!mRequestTemplateCache[templateId].isEmpty()) {
+ *request = mRequestTemplateCache[templateId];
+ return OK;
+ }
+
const camera_metadata_t *rawRequest;
ATRACE_BEGIN("camera3->construct_default_request_settings");
rawRequest = mHal3Device->ops->construct_default_request_settings(
@@ -909,6 +1060,7 @@ status_t Camera3Device::createDefaultRequest(int templateId,
return DEAD_OBJECT;
}
*request = rawRequest;
+ mRequestTemplateCache[templateId] = rawRequest;
return OK;
}
@@ -918,6 +1070,10 @@ status_t Camera3Device::waitUntilDrained() {
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
+ return waitUntilDrainedLocked();
+}
+
+status_t Camera3Device::waitUntilDrainedLocked() {
switch (mStatus) {
case STATUS_UNINITIALIZED:
case STATUS_UNCONFIGURED:
@@ -936,6 +1092,10 @@ status_t Camera3Device::waitUntilDrained() {
ALOGV("%s: Camera %d: Waiting until idle", __FUNCTION__, mId);
status_t res = waitUntilStateThenRelock(/*active*/ false, kShutdownTimeout);
+ if (res != OK) {
+ SET_ERR_L("Error waiting for HAL to drain: %s (%d)", strerror(-res),
+ res);
+ }
return res;
}
@@ -1005,6 +1165,7 @@ status_t Camera3Device::setNotifyCallback(NotificationListener *listener) {
ALOGW("%s: Replacing old callback listener", __FUNCTION__);
}
mListener = listener;
+ mRequestThread->setNotifyCallback(listener);
return OK;
}
@@ -1030,7 +1191,7 @@ status_t Camera3Device::waitForNextFrame(nsecs_t timeout) {
return OK;
}
-status_t Camera3Device::getNextFrame(CameraMetadata *frame) {
+status_t Camera3Device::getNextResult(CaptureResult *frame) {
ATRACE_CALL();
Mutex::Autolock l(mOutputLock);
@@ -1038,8 +1199,14 @@ status_t Camera3Device::getNextFrame(CameraMetadata *frame) {
return NOT_ENOUGH_DATA;
}
- CameraMetadata &result = *(mResultQueue.begin());
- frame->acquire(result);
+ if (frame == NULL) {
+ ALOGE("%s: argument cannot be NULL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ CaptureResult &result = *(mResultQueue.begin());
+ frame->mResultExtras = result.mResultExtras;
+ frame->mMetadata.acquire(result.mMetadata);
mResultQueue.erase(mResultQueue.begin());
return OK;
@@ -1059,7 +1226,7 @@ status_t Camera3Device::triggerAutofocus(uint32_t id) {
{
ANDROID_CONTROL_AF_TRIGGER_ID,
static_cast<int32_t>(id)
- },
+ }
};
return mRequestThread->queueTrigger(trigger,
@@ -1080,7 +1247,7 @@ status_t Camera3Device::triggerCancelAutofocus(uint32_t id) {
{
ANDROID_CONTROL_AF_TRIGGER_ID,
static_cast<int32_t>(id)
- },
+ }
};
return mRequestThread->queueTrigger(trigger,
@@ -1101,7 +1268,7 @@ status_t Camera3Device::triggerPrecaptureMetering(uint32_t id) {
{
ANDROID_CONTROL_AE_PRECAPTURE_ID,
static_cast<int32_t>(id)
- },
+ }
};
return mRequestThread->queueTrigger(trigger,
@@ -1117,14 +1284,37 @@ status_t Camera3Device::pushReprocessBuffer(int reprocessStreamId,
return INVALID_OPERATION;
}
-status_t Camera3Device::flush() {
+status_t Camera3Device::flush(int64_t *frameNumber) {
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);
+ NotificationListener* listener;
+ {
+ Mutex::Autolock l(mOutputLock);
+ listener = mListener;
+ }
+
+ {
+ Mutex::Autolock l(mLock);
+ mRequestThread->clear(listener, /*out*/frameNumber);
+ }
+
+ status_t res;
+ if (mHal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_1) {
+ res = mHal3Device->ops->flush(mHal3Device);
+ } else {
+ Mutex::Autolock l(mLock);
+ res = waitUntilDrainedLocked();
+ }
+
+ return res;
+}
+
+uint32_t Camera3Device::getDeviceVersion() {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ return mDeviceVersion;
}
/**
@@ -1248,6 +1438,15 @@ status_t Camera3Device::configureStreamsLocked() {
return OK;
}
+ // Workaround for device HALv3.2 or older spec bug - zero streams requires
+ // adding a dummy stream instead.
+ // TODO: Bug: 17321404 for fixing the HAL spec and removing this workaround.
+ if (mOutputStreams.size() == 0) {
+ addDummyStreamLocked();
+ } else {
+ tryRemoveDummyStreamLocked();
+ }
+
// Start configuring the streams
ALOGV("%s: Camera %d: Starting stream configuration", __FUNCTION__, mId);
@@ -1295,7 +1494,42 @@ status_t Camera3Device::configureStreamsLocked() {
res = mHal3Device->ops->configure_streams(mHal3Device, &config);
ATRACE_END();
- if (res != OK) {
+ if (res == BAD_VALUE) {
+ // HAL rejected this set of streams as unsupported, clean up config
+ // attempt and return to unconfigured state
+ if (mInputStream != NULL && mInputStream->isConfiguring()) {
+ res = mInputStream->cancelConfiguration();
+ if (res != OK) {
+ SET_ERR_L("Can't cancel configuring input stream %d: %s (%d)",
+ mInputStream->getId(), strerror(-res), res);
+ return res;
+ }
+ }
+
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ sp<Camera3OutputStreamInterface> outputStream =
+ mOutputStreams.editValueAt(i);
+ if (outputStream->isConfiguring()) {
+ res = outputStream->cancelConfiguration();
+ if (res != OK) {
+ SET_ERR_L(
+ "Can't cancel configuring output stream %d: %s (%d)",
+ outputStream->getId(), strerror(-res), res);
+ return res;
+ }
+ }
+ }
+
+ // Return state to that at start of call, so that future configures
+ // properly clean things up
+ mStatus = STATUS_UNCONFIGURED;
+ mNeedConfig = true;
+
+ ALOGV("%s: Camera %d: Stream configuration failed", __FUNCTION__, mId);
+ return BAD_VALUE;
+ } else if (res != OK) {
+ // Some other kind of error from configure_streams - this is not
+ // expected
SET_ERR_L("Unable to configure streams with HAL: %s (%d)",
strerror(-res), res);
return res;
@@ -1335,7 +1569,7 @@ status_t Camera3Device::configureStreamsLocked() {
mNeedConfig = false;
- if (config.num_streams > 0) {
+ if (mDummyStreamId == NO_STREAM) {
mStatus = STATUS_CONFIGURED;
} else {
mStatus = STATUS_UNCONFIGURED;
@@ -1343,9 +1577,75 @@ status_t Camera3Device::configureStreamsLocked() {
ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);
+ // tear down the deleted streams after configure streams.
+ mDeletedStreams.clear();
+
return OK;
}
+status_t Camera3Device::addDummyStreamLocked() {
+ ATRACE_CALL();
+ status_t res;
+
+ if (mDummyStreamId != NO_STREAM) {
+ // Should never be adding a second dummy stream when one is already
+ // active
+ SET_ERR_L("%s: Camera %d: A dummy stream already exists!",
+ __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("%s: Camera %d: Adding a dummy stream", __FUNCTION__, mId);
+
+ sp<Camera3OutputStreamInterface> dummyStream =
+ new Camera3DummyStream(mNextStreamId);
+
+ res = mOutputStreams.add(mNextStreamId, dummyStream);
+ if (res < 0) {
+ SET_ERR_L("Can't add dummy stream to set: %s (%d)", strerror(-res), res);
+ return res;
+ }
+
+ mDummyStreamId = mNextStreamId;
+ mNextStreamId++;
+
+ return OK;
+}
+
+status_t Camera3Device::tryRemoveDummyStreamLocked() {
+ ATRACE_CALL();
+ status_t res;
+
+ if (mDummyStreamId == NO_STREAM) return OK;
+ if (mOutputStreams.size() == 1) return OK;
+
+ ALOGV("%s: Camera %d: Removing the dummy stream", __FUNCTION__, mId);
+
+ // Ok, have a dummy stream and there's at least one other output stream,
+ // so remove the dummy
+
+ sp<Camera3StreamInterface> deletedStream;
+ ssize_t outputStreamIdx = mOutputStreams.indexOfKey(mDummyStreamId);
+ if (outputStreamIdx == NAME_NOT_FOUND) {
+ SET_ERR_L("Dummy stream %d does not appear to exist", mDummyStreamId);
+ return INVALID_OPERATION;
+ }
+
+ deletedStream = mOutputStreams.editValueAt(outputStreamIdx);
+ mOutputStreams.removeItemsAt(outputStreamIdx);
+
+ // Free up the stream endpoint so that it can be used by some other stream
+ res = deletedStream->disconnect();
+ if (res != OK) {
+ SET_ERR_L("Can't disconnect deleted dummy stream %d", mDummyStreamId);
+ // fall through since we want to still list the stream as deleted.
+ }
+ mDeletedStreams.add(deletedStream);
+ mDummyStreamId = NO_STREAM;
+
+ return res;
+}
+
void Camera3Device::setErrorState(const char *fmt, ...) {
Mutex::Autolock l(mLock);
va_list args;
@@ -1378,40 +1678,45 @@ void Camera3Device::setErrorStateLockedV(const char *fmt, va_list args) {
// But only do error state transition steps for the first error
if (mStatus == STATUS_ERROR || mStatus == STATUS_UNINITIALIZED) return;
- // Save stack trace. View by dumping it later.
- CameraTraces::saveTrace();
- // TODO: consider adding errorCause and client pid/procname
-
mErrorCause = errorCause;
mRequestThread->setPaused(true);
mStatus = STATUS_ERROR;
+
+ // Notify upstream about a device error
+ if (mListener != NULL) {
+ mListener->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ CaptureResultExtras());
+ }
+
+ // Save stack trace. View by dumping it later.
+ CameraTraces::saveTrace();
+ // TODO: consider adding errorCause and client pid/procname
}
/**
* In-flight request management
*/
-status_t Camera3Device::registerInFlight(int32_t frameNumber,
- int32_t requestId, int32_t numBuffers) {
+status_t Camera3Device::registerInFlight(uint32_t frameNumber,
+ int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput) {
ATRACE_CALL();
Mutex::Autolock l(mInFlightLock);
ssize_t res;
- res = mInFlightMap.add(frameNumber, InFlightRequest(requestId, numBuffers));
+ res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput));
if (res < 0) return res;
return OK;
}
/**
- * QUIRK(partial results)
* Check if all 3A fields are ready, and send off a partial 3A-only result
* to the output frame queue
*/
-bool Camera3Device::processPartial3AQuirk(
- int32_t frameNumber, int32_t requestId,
- const CameraMetadata& partial) {
+bool Camera3Device::processPartial3AResult(
+ uint32_t frameNumber,
+ const CameraMetadata& partial, const CaptureResultExtras& resultExtras) {
// Check if all 3A states are present
// The full list of fields is
@@ -1431,8 +1736,6 @@ bool Camera3Device::processPartial3AQuirk(
uint8_t aeState;
uint8_t afState;
uint8_t awbState;
- int32_t afTriggerId;
- int32_t aeTriggerId;
gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AF_MODE,
&afMode, frameNumber);
@@ -1449,88 +1752,92 @@ bool Camera3Device::processPartial3AQuirk(
gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AWB_STATE,
&awbState, frameNumber);
- gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AF_TRIGGER_ID,
- &afTriggerId, frameNumber);
-
- gotAllStates &= get3AResult(partial, ANDROID_CONTROL_AE_PRECAPTURE_ID,
- &aeTriggerId, frameNumber);
-
if (!gotAllStates) return false;
ALOGVV("%s: Camera %d: Frame %d, Request ID %d: AF mode %d, AWB mode %d, "
"AF state %d, AE state %d, AWB state %d, "
"AF trigger %d, AE precapture trigger %d",
- __FUNCTION__, mId, frameNumber, requestId,
+ __FUNCTION__, mId, frameNumber, resultExtras.requestId,
afMode, awbMode,
afState, aeState, awbState,
- afTriggerId, aeTriggerId);
+ resultExtras.afTriggerId, resultExtras.precaptureTriggerId);
// Got all states, so construct a minimal result to send
// In addition to the above fields, this means adding in
// android.request.frameCount
// android.request.requestId
- // android.quirks.partialResult
+ // android.quirks.partialResult (for HAL version below HAL3.2)
const size_t kMinimal3AResultEntries = 10;
Mutex::Autolock l(mOutputLock);
- CameraMetadata& min3AResult =
- *mResultQueue.insert(
- mResultQueue.end(),
- CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0));
-
- if (!insert3AResult(min3AResult, ANDROID_REQUEST_FRAME_COUNT,
- &frameNumber, frameNumber)) {
+ CaptureResult captureResult;
+ captureResult.mResultExtras = resultExtras;
+ captureResult.mMetadata = CameraMetadata(kMinimal3AResultEntries, /*dataCapacity*/ 0);
+ // TODO: change this to sp<CaptureResult>. This will need other changes, including,
+ // but not limited to CameraDeviceBase::getNextResult
+ CaptureResult& min3AResult =
+ *mResultQueue.insert(mResultQueue.end(), captureResult);
+
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_REQUEST_FRAME_COUNT,
+ // TODO: This is problematic casting. Need to fix CameraMetadata.
+ reinterpret_cast<int32_t*>(&frameNumber), frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_REQUEST_ID,
+ int32_t requestId = resultExtras.requestId;
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_REQUEST_ID,
&requestId, frameNumber)) {
return false;
}
- static const uint8_t partialResult = ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL;
- if (!insert3AResult(min3AResult, ANDROID_QUIRKS_PARTIAL_RESULT,
- &partialResult, frameNumber)) {
- return false;
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ static const uint8_t partialResult = ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL;
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_QUIRKS_PARTIAL_RESULT,
+ &partialResult, frameNumber)) {
+ return false;
+ }
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_MODE,
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_MODE,
&afMode, frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_MODE,
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AWB_MODE,
&awbMode, frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_STATE,
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AE_STATE,
&aeState, frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_STATE,
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_STATE,
&afState, frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AWB_STATE,
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AWB_STATE,
&awbState, frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AF_TRIGGER_ID,
- &afTriggerId, frameNumber)) {
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AF_TRIGGER_ID,
+ &resultExtras.afTriggerId, frameNumber)) {
return false;
}
- if (!insert3AResult(min3AResult, ANDROID_CONTROL_AE_PRECAPTURE_ID,
- &aeTriggerId, frameNumber)) {
+ if (!insert3AResult(min3AResult.mMetadata, ANDROID_CONTROL_AE_PRECAPTURE_ID,
+ &resultExtras.precaptureTriggerId, frameNumber)) {
return false;
}
+ // We only send the aggregated partial when all 3A related metadata are available
+ // For both API1 and API2.
+ // TODO: we probably should pass through all partials to API2 unconditionally.
mResultSignal.signal();
return true;
@@ -1538,7 +1845,7 @@ bool Camera3Device::processPartial3AQuirk(
template<typename T>
bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag,
- T* value, int32_t frameNumber) {
+ T* value, uint32_t frameNumber) {
(void) frameNumber;
camera_metadata_ro_entry_t entry;
@@ -1563,7 +1870,7 @@ bool Camera3Device::get3AResult(const CameraMetadata& result, int32_t tag,
template<typename T>
bool Camera3Device::insert3AResult(CameraMetadata& result, int32_t tag,
- const T* value, int32_t frameNumber) {
+ const T* value, uint32_t frameNumber) {
if (result.update(tag, value, 1) != NO_ERROR) {
mResultQueue.erase(--mResultQueue.end(), mResultQueue.end());
SET_ERR("Frame %d: Failed to set %s in partial metadata",
@@ -1583,18 +1890,34 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
status_t res;
uint32_t frameNumber = result->frame_number;
- if (result->result == NULL && result->num_output_buffers == 0) {
+ if (result->result == NULL && result->num_output_buffers == 0 &&
+ result->input_buffer == NULL) {
SET_ERR("No result data provided by HAL for frame %d",
frameNumber);
return;
}
- bool partialResultQuirk = false;
- CameraMetadata collectedQuirkResult;
- // Get capture timestamp from list of in-flight requests, where it was added
- // by the shutter notification for this frame. Then update the in-flight
- // status and remove the in-flight entry if all result data has been
- // received.
+ // For HAL3.2 or above, If HAL doesn't support partial, it must always set
+ // partial_result to 1 when metadata is included in this result.
+ if (!mUsePartialResult &&
+ mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
+ result->result != NULL &&
+ result->partial_result != 1) {
+ SET_ERR("Result is malformed for frame %d: partial_result %u must be 1"
+ " if partial result is not supported",
+ frameNumber, result->partial_result);
+ return;
+ }
+
+ bool isPartialResult = false;
+ CameraMetadata collectedPartialResult;
+ CaptureResultExtras resultExtras;
+ bool hasInputBufferInRequest = false;
+
+ // Get capture timestamp and resultExtras from list of in-flight requests,
+ // where it was added by the shutter notification for this frame.
+ // Then update the in-flight status and remove the in-flight entry if
+ // all result data has been received.
nsecs_t timestamp = 0;
{
Mutex::Autolock l(mInFlightLock);
@@ -1605,71 +1928,108 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
return;
}
InFlightRequest &request = mInFlightMap.editValueAt(idx);
+ ALOGVV("%s: got InFlightRequest requestId = %" PRId32 ", frameNumber = %" PRId64
+ ", burstId = %" PRId32,
+ __FUNCTION__, request.resultExtras.requestId, request.resultExtras.frameNumber,
+ request.resultExtras.burstId);
+ // Always update the partial count to the latest one. When framework aggregates adjacent
+ // partial results into one, the latest partial count will be used.
+ request.resultExtras.partialResultCount = result->partial_result;
// Check if this result carries only partial metadata
- if (mUsePartialResultQuirk && result->result != NULL) {
- camera_metadata_ro_entry_t partialResultEntry;
- res = find_camera_metadata_ro_entry(result->result,
- ANDROID_QUIRKS_PARTIAL_RESULT, &partialResultEntry);
- if (res != NAME_NOT_FOUND &&
- partialResultEntry.count > 0 &&
- partialResultEntry.data.u8[0] ==
- ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
- // A partial result. Flag this as such, and collect this
- // set of metadata into the in-flight entry.
- partialResultQuirk = true;
- request.partialResultQuirk.collectedResult.append(
- result->result);
- request.partialResultQuirk.collectedResult.erase(
- ANDROID_QUIRKS_PARTIAL_RESULT);
+ if (mUsePartialResult && result->result != NULL) {
+ if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ if (result->partial_result > mNumPartialResults || result->partial_result < 1) {
+ SET_ERR("Result is malformed for frame %d: partial_result %u must be in"
+ " the range of [1, %d] when metadata is included in the result",
+ frameNumber, result->partial_result, mNumPartialResults);
+ return;
+ }
+ isPartialResult = (result->partial_result < mNumPartialResults);
+ if (isPartialResult) {
+ request.partialResult.collectedResult.append(result->result);
+ }
+ } else {
+ camera_metadata_ro_entry_t partialResultEntry;
+ res = find_camera_metadata_ro_entry(result->result,
+ ANDROID_QUIRKS_PARTIAL_RESULT, &partialResultEntry);
+ if (res != NAME_NOT_FOUND &&
+ partialResultEntry.count > 0 &&
+ partialResultEntry.data.u8[0] ==
+ ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
+ // A partial result. Flag this as such, and collect this
+ // set of metadata into the in-flight entry.
+ isPartialResult = true;
+ request.partialResult.collectedResult.append(
+ result->result);
+ request.partialResult.collectedResult.erase(
+ ANDROID_QUIRKS_PARTIAL_RESULT);
+ }
+ }
+
+ if (isPartialResult) {
// Fire off a 3A-only result if possible
- if (!request.partialResultQuirk.haveSent3A) {
- request.partialResultQuirk.haveSent3A =
- processPartial3AQuirk(frameNumber,
- request.requestId,
- request.partialResultQuirk.collectedResult);
+ if (!request.partialResult.haveSent3A) {
+ request.partialResult.haveSent3A =
+ processPartial3AResult(frameNumber,
+ request.partialResult.collectedResult,
+ request.resultExtras);
}
}
}
timestamp = request.captureTimestamp;
+ resultExtras = request.resultExtras;
+ hasInputBufferInRequest = request.hasInputBuffer;
+
/**
* One of the following must happen before it's legal to call process_capture_result,
* unless partial metadata is being provided:
* - CAMERA3_MSG_SHUTTER (expected during normal operation)
* - CAMERA3_MSG_ERROR (expected during flush)
*/
- if (request.requestStatus == OK && timestamp == 0 && !partialResultQuirk) {
+ if (request.requestStatus == OK && timestamp == 0 && !isPartialResult) {
SET_ERR("Called before shutter notify for frame %d",
frameNumber);
return;
}
// Did we get the (final) result metadata for this capture?
- if (result->result != NULL && !partialResultQuirk) {
+ if (result->result != NULL && !isPartialResult) {
if (request.haveResultMetadata) {
SET_ERR("Called multiple times with metadata for frame %d",
frameNumber);
return;
}
- if (mUsePartialResultQuirk &&
- !request.partialResultQuirk.collectedResult.isEmpty()) {
- collectedQuirkResult.acquire(
- request.partialResultQuirk.collectedResult);
+ if (mUsePartialResult &&
+ !request.partialResult.collectedResult.isEmpty()) {
+ collectedPartialResult.acquire(
+ request.partialResult.collectedResult);
}
request.haveResultMetadata = true;
}
- request.numBuffersLeft -= result->num_output_buffers;
-
+ uint32_t numBuffersReturned = result->num_output_buffers;
+ if (result->input_buffer != NULL) {
+ if (hasInputBufferInRequest) {
+ numBuffersReturned += 1;
+ } else {
+ ALOGW("%s: Input buffer should be NULL if there is no input"
+ " buffer sent in the request",
+ __FUNCTION__);
+ }
+ }
+ request.numBuffersLeft -= numBuffersReturned;
if (request.numBuffersLeft < 0) {
SET_ERR("Too many buffers returned for frame %d",
frameNumber);
return;
}
- // Check if everything has arrived for this result (buffers and metadata)
- if (request.haveResultMetadata && request.numBuffersLeft == 0) {
+ // Check if everything has arrived for this result (buffers and metadata), remove it from
+ // InFlightMap if both arrived or HAL reports error for this request (i.e. during flush).
+ if ((request.requestStatus != OK) ||
+ (request.haveResultMetadata && request.numBuffersLeft == 0)) {
ATRACE_ASYNC_END("frame capture", frameNumber);
mInFlightMap.removeItemsAt(idx, 1);
}
@@ -1684,24 +2044,26 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
// Process the result metadata, if provided
bool gotResult = false;
- if (result->result != NULL && !partialResultQuirk) {
+ if (result->result != NULL && !isPartialResult) {
Mutex::Autolock l(mOutputLock);
gotResult = true;
- if (frameNumber != mNextResultFrameNumber) {
+ // TODO: need to track errors for tighter bounds on expected frame number
+ if (frameNumber < mNextResultFrameNumber) {
SET_ERR("Out-of-order capture result metadata submitted! "
"(got frame number %d, expecting %d)",
frameNumber, mNextResultFrameNumber);
return;
}
- mNextResultFrameNumber++;
+ mNextResultFrameNumber = frameNumber + 1;
- CameraMetadata captureResult;
- captureResult = result->result;
+ CaptureResult captureResult;
+ captureResult.mResultExtras = resultExtras;
+ captureResult.mMetadata = result->result;
- if (captureResult.update(ANDROID_REQUEST_FRAME_COUNT,
- (int32_t*)&frameNumber, 1) != OK) {
+ if (captureResult.mMetadata.update(ANDROID_REQUEST_FRAME_COUNT,
+ (int32_t*)&frameNumber, 1) != OK) {
SET_ERR("Failed to set frame# in metadata (%d)",
frameNumber);
gotResult = false;
@@ -1711,16 +2073,16 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
// Append any previous partials to form a complete result
- if (mUsePartialResultQuirk && !collectedQuirkResult.isEmpty()) {
- captureResult.append(collectedQuirkResult);
+ if (mUsePartialResult && !collectedPartialResult.isEmpty()) {
+ captureResult.mMetadata.append(collectedPartialResult);
}
- captureResult.sort();
+ captureResult.mMetadata.sort();
// Check that there's a timestamp in the result metadata
camera_metadata_entry entry =
- captureResult.find(ANDROID_SENSOR_TIMESTAMP);
+ captureResult.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
if (entry.count == 0) {
SET_ERR("No timestamp provided by HAL for frame %d!",
frameNumber);
@@ -1734,9 +2096,13 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
if (gotResult) {
// Valid result, insert into queue
- CameraMetadata& queuedResult =
- *mResultQueue.insert(mResultQueue.end(), CameraMetadata());
- queuedResult.swap(captureResult);
+ List<CaptureResult>::iterator queuedResult =
+ mResultQueue.insert(mResultQueue.end(), CaptureResult(captureResult));
+ ALOGVV("%s: result requestId = %" PRId32 ", frameNumber = %" PRId64
+ ", burstId = %" PRId32, __FUNCTION__,
+ queuedResult->mResultExtras.requestId,
+ queuedResult->mResultExtras.frameNumber,
+ queuedResult->mResultExtras.burstId);
}
} // scope for mOutputLock
@@ -1754,6 +2120,25 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
}
+ if (result->input_buffer != NULL) {
+ if (hasInputBufferInRequest) {
+ Camera3Stream *stream =
+ Camera3Stream::cast(result->input_buffer->stream);
+ res = stream->returnInputBuffer(*(result->input_buffer));
+ // Note: stream may be deallocated at this point, if this buffer was the
+ // last reference to it.
+ if (res != OK) {
+ ALOGE("%s: RequestThread: Can't return input buffer for frame %d to"
+ " its stream:%s (%d)", __FUNCTION__,
+ frameNumber, strerror(-res), res);
+ }
+ } else {
+ ALOGW("%s: Input buffer should be NULL if there is no input"
+ " buffer sent in the request, skipping input buffer return.",
+ __FUNCTION__);
+ }
+ }
+
// Finally, signal any waiters for new frames
if (gotResult) {
@@ -1762,8 +2147,6 @@ void Camera3Device::processCaptureResult(const camera3_capture_result *result) {
}
-
-
void Camera3Device::notify(const camera3_notify_msg *msg) {
ATRACE_CALL();
NotificationListener *listener;
@@ -1779,80 +2162,134 @@ void Camera3Device::notify(const camera3_notify_msg *msg) {
switch (msg->type) {
case CAMERA3_MSG_ERROR: {
- int streamId = 0;
- if (msg->message.error.error_stream != NULL) {
- Camera3Stream *stream =
- Camera3Stream::cast(
- 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);
- }
+ notifyError(msg->message.error, listener);
break;
}
case CAMERA3_MSG_SHUTTER: {
- ssize_t idx;
- uint32_t frameNumber = msg->message.shutter.frame_number;
- nsecs_t timestamp = msg->message.shutter.timestamp;
- // Verify ordering of shutter notifications
- {
- Mutex::Autolock l(mOutputLock);
- if (frameNumber != mNextShutterFrameNumber) {
- SET_ERR("Shutter notification out-of-order. Expected "
- "notification for frame %d, got frame %d",
- mNextShutterFrameNumber, frameNumber);
- break;
- }
- mNextShutterFrameNumber++;
- }
+ notifyShutter(msg->message.shutter, listener);
+ break;
+ }
+ default:
+ SET_ERR("Unknown notify message from HAL: %d",
+ msg->type);
+ }
+}
+
+void Camera3Device::notifyError(const camera3_error_msg_t &msg,
+ NotificationListener *listener) {
+
+ // Map camera HAL error codes to ICameraDeviceCallback error codes
+ // Index into this with the HAL error code
+ static const ICameraDeviceCallbacks::CameraErrorCode
+ halErrorMap[CAMERA3_MSG_NUM_ERRORS] = {
+ // 0 = Unused error code
+ ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR,
+ // 1 = CAMERA3_MSG_ERROR_DEVICE
+ ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE,
+ // 2 = CAMERA3_MSG_ERROR_REQUEST
+ ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ // 3 = CAMERA3_MSG_ERROR_RESULT
+ ICameraDeviceCallbacks::ERROR_CAMERA_RESULT,
+ // 4 = CAMERA3_MSG_ERROR_BUFFER
+ ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER
+ };
- int32_t requestId = -1;
+ ICameraDeviceCallbacks::CameraErrorCode errorCode =
+ ((msg.error_code >= 0) &&
+ (msg.error_code < CAMERA3_MSG_NUM_ERRORS)) ?
+ halErrorMap[msg.error_code] :
+ ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR;
- // Set timestamp for the request in the in-flight tracking
- // and get the request ID to send upstream
+ int streamId = 0;
+ if (msg.error_stream != NULL) {
+ Camera3Stream *stream =
+ Camera3Stream::cast(msg.error_stream);
+ streamId = stream->getId();
+ }
+ ALOGV("Camera %d: %s: HAL error, frame %d, stream %d: %d",
+ mId, __FUNCTION__, msg.frame_number,
+ streamId, msg.error_code);
+
+ CaptureResultExtras resultExtras;
+ switch (errorCode) {
+ case ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE:
+ // SET_ERR calls notifyError
+ SET_ERR("Camera HAL reported serious device error");
+ break;
+ case ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
+ case ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
+ case ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
{
Mutex::Autolock l(mInFlightLock);
- idx = mInFlightMap.indexOfKey(frameNumber);
+ ssize_t idx = mInFlightMap.indexOfKey(msg.frame_number);
if (idx >= 0) {
InFlightRequest &r = mInFlightMap.editValueAt(idx);
- r.captureTimestamp = timestamp;
- requestId = r.requestId;
+ r.requestStatus = msg.error_code;
+ resultExtras = r.resultExtras;
+ } else {
+ resultExtras.frameNumber = msg.frame_number;
+ ALOGE("Camera %d: %s: cannot find in-flight request on "
+ "frame %" PRId64 " error", mId, __FUNCTION__,
+ resultExtras.frameNumber);
}
}
- if (idx < 0) {
- SET_ERR("Shutter notification for non-existent frame number %d",
- frameNumber);
- break;
- }
- ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64,
- mId, __FUNCTION__, frameNumber, requestId, timestamp);
- // Call listener, if any
if (listener != NULL) {
- listener->notifyShutter(requestId, timestamp);
+ listener->notifyError(errorCode, resultExtras);
+ } else {
+ ALOGE("Camera %d: %s: no listener available", mId, __FUNCTION__);
}
break;
- }
default:
- SET_ERR("Unknown notify message from HAL: %d",
- msg->type);
+ // SET_ERR calls notifyError
+ SET_ERR("Unknown error message from HAL: %d", msg.error_code);
+ break;
+ }
+}
+
+void Camera3Device::notifyShutter(const camera3_shutter_msg_t &msg,
+ NotificationListener *listener) {
+ ssize_t idx;
+ // Verify ordering of shutter notifications
+ {
+ Mutex::Autolock l(mOutputLock);
+ // TODO: need to track errors for tighter bounds on expected frame number.
+ if (msg.frame_number < mNextShutterFrameNumber) {
+ SET_ERR("Shutter notification out-of-order. Expected "
+ "notification for frame %d, got frame %d",
+ mNextShutterFrameNumber, msg.frame_number);
+ return;
+ }
+ mNextShutterFrameNumber = msg.frame_number + 1;
+ }
+
+ CaptureResultExtras resultExtras;
+
+ // 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(msg.frame_number);
+ if (idx >= 0) {
+ InFlightRequest &r = mInFlightMap.editValueAt(idx);
+ r.captureTimestamp = msg.timestamp;
+ resultExtras = r.resultExtras;
+ }
+ }
+ if (idx < 0) {
+ SET_ERR("Shutter notification for non-existent frame number %d",
+ msg.frame_number);
+ return;
+ }
+ ALOGVV("Camera %d: %s: Shutter fired for frame %d (id %d) at %" PRId64,
+ mId, __FUNCTION__,
+ msg.frame_number, resultExtras.requestId, msg.timestamp);
+ // Call listener, if any
+ if (listener != NULL) {
+ listener->notifyShutter(resultExtras, msg.timestamp);
}
}
+
CameraMetadata Camera3Device::getLatestRequestLocked() {
ALOGV("%s", __FUNCTION__);
@@ -1865,6 +2302,7 @@ CameraMetadata Camera3Device::getLatestRequestLocked() {
return retVal;
}
+
/**
* RequestThread inner class methods
*/
@@ -1881,19 +2319,40 @@ Camera3Device::RequestThread::RequestThread(wp<Camera3Device> parent,
mDoPause(false),
mPaused(true),
mFrameNumber(0),
- mLatestRequestId(NAME_NOT_FOUND) {
+ mLatestRequestId(NAME_NOT_FOUND),
+ mCurrentAfTriggerId(0),
+ mCurrentPreCaptureTriggerId(0),
+ mRepeatingLastFrameNumber(NO_IN_FLIGHT_REPEATING_FRAMES) {
mStatusId = statusTracker->addComponent();
}
+void Camera3Device::RequestThread::setNotifyCallback(
+ NotificationListener *listener) {
+ Mutex::Autolock l(mRequestLock);
+ mListener = listener;
+}
+
void Camera3Device::RequestThread::configurationComplete() {
Mutex::Autolock l(mRequestLock);
mReconfigured = true;
}
-status_t Camera3Device::RequestThread::queueRequest(
- sp<CaptureRequest> request) {
+status_t Camera3Device::RequestThread::queueRequestList(
+ List<sp<CaptureRequest> > &requests,
+ /*out*/
+ int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
- mRequestQueue.push_back(request);
+ for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end();
+ ++it) {
+ mRequestQueue.push_back(*it);
+ }
+
+ if (lastFrameNumber != NULL) {
+ *lastFrameNumber = mFrameNumber + mRequestQueue.size() - 1;
+ ALOGV("%s: requestId %d, mFrameNumber %" PRId32 ", lastFrameNumber %" PRId64 ".",
+ __FUNCTION__, (*(requests.begin()))->mResultExtras.requestId, mFrameNumber,
+ *lastFrameNumber);
+ }
unpauseForNewRequests();
@@ -1957,28 +2416,72 @@ status_t Camera3Device::RequestThread::queueTriggerLocked(
}
status_t Camera3Device::RequestThread::setRepeatingRequests(
- const RequestList &requests) {
+ const RequestList &requests,
+ /*out*/
+ int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
+ if (lastFrameNumber != NULL) {
+ *lastFrameNumber = mRepeatingLastFrameNumber;
+ }
mRepeatingRequests.clear();
mRepeatingRequests.insert(mRepeatingRequests.begin(),
requests.begin(), requests.end());
unpauseForNewRequests();
+ mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES;
return OK;
}
-status_t Camera3Device::RequestThread::clearRepeatingRequests() {
+bool Camera3Device::RequestThread::isRepeatingRequestLocked(const sp<CaptureRequest> requestIn) {
+ if (mRepeatingRequests.empty()) {
+ return false;
+ }
+ int32_t requestId = requestIn->mResultExtras.requestId;
+ const RequestList &repeatRequests = mRepeatingRequests;
+ // All repeating requests are guaranteed to have same id so only check first quest
+ const sp<CaptureRequest> firstRequest = *repeatRequests.begin();
+ return (firstRequest->mResultExtras.requestId == requestId);
+}
+
+status_t Camera3Device::RequestThread::clearRepeatingRequests(/*out*/int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
mRepeatingRequests.clear();
+ if (lastFrameNumber != NULL) {
+ *lastFrameNumber = mRepeatingLastFrameNumber;
+ }
+ mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES;
return OK;
}
-status_t Camera3Device::RequestThread::clear() {
+status_t Camera3Device::RequestThread::clear(
+ NotificationListener *listener,
+ /*out*/int64_t *lastFrameNumber) {
Mutex::Autolock l(mRequestLock);
+ ALOGV("RequestThread::%s:", __FUNCTION__);
+
mRepeatingRequests.clear();
+
+ // Send errors for all requests pending in the request queue, including
+ // pending repeating requests
+ if (listener != NULL) {
+ for (RequestList::iterator it = mRequestQueue.begin();
+ it != mRequestQueue.end(); ++it) {
+ // Set the frame number this request would have had, if it
+ // had been submitted; this frame number will not be reused.
+ // The requestId and burstId fields were set when the request was
+ // submitted originally (in convertMetadataListToRequestListLocked)
+ (*it)->mResultExtras.frameNumber = mFrameNumber++;
+ listener->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ (*it)->mResultExtras);
+ }
+ }
mRequestQueue.clear();
mTriggerMap.clear();
+ if (lastFrameNumber != NULL) {
+ *lastFrameNumber = mRepeatingLastFrameNumber;
+ }
+ mRepeatingLastFrameNumber = NO_IN_FLIGHT_REPEATING_FRAMES;
return OK;
}
@@ -2030,6 +2533,7 @@ bool Camera3Device::RequestThread::threadLoop() {
// Create request to HAL
camera3_capture_request_t request = camera3_capture_request_t();
+ request.frame_number = nextRequest->mResultExtras.frameNumber;
Vector<camera3_stream_buffer_t> outputBuffers;
// Get the request ID, if any
@@ -2050,7 +2554,7 @@ bool Camera3Device::RequestThread::threadLoop() {
if (res < 0) {
SET_ERR("RequestThread: Unable to insert triggers "
"(capture request %d, HAL device: %s (%d)",
- (mFrameNumber+1), strerror(-res), res);
+ request.frame_number, strerror(-res), res);
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return false;
}
@@ -2068,7 +2572,7 @@ bool Camera3Device::RequestThread::threadLoop() {
if (res != OK) {
SET_ERR("RequestThread: Unable to insert dummy trigger IDs "
"(capture request %d, HAL device: %s (%d)",
- (mFrameNumber+1), strerror(-res), res);
+ request.frame_number, strerror(-res), res);
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return false;
}
@@ -2092,7 +2596,7 @@ bool Camera3Device::RequestThread::threadLoop() {
if (e.count > 0) {
ALOGV("%s: Request (frame num %d) had AF trigger 0x%x",
__FUNCTION__,
- mFrameNumber+1,
+ request.frame_number,
e.data.u8[0]);
}
}
@@ -2103,6 +2607,7 @@ bool Camera3Device::RequestThread::threadLoop() {
}
camera3_stream_buffer_t inputBuffer;
+ uint32_t totalNumBuffers = 0;
// Fill in buffers
@@ -2110,11 +2615,21 @@ bool Camera3Device::RequestThread::threadLoop() {
request.input_buffer = &inputBuffer;
res = nextRequest->mInputStream->getInputBuffer(&inputBuffer);
if (res != OK) {
+ // Can't get input buffer from gralloc queue - this could be due to
+ // disconnected queue or other producer misbehavior, so not a fatal
+ // error
ALOGE("RequestThread: Can't get input buffer, skipping request:"
" %s (%d)", strerror(-res), res);
+ Mutex::Autolock l(mRequestLock);
+ if (mListener != NULL) {
+ mListener->notifyError(
+ ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ nextRequest->mResultExtras);
+ }
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return true;
}
+ totalNumBuffers += 1;
} else {
request.input_buffer = NULL;
}
@@ -2126,26 +2641,41 @@ bool Camera3Device::RequestThread::threadLoop() {
res = nextRequest->mOutputStreams.editItemAt(i)->
getBuffer(&outputBuffers.editItemAt(i));
if (res != OK) {
+ // Can't get output buffer from gralloc queue - this could be due to
+ // abandoned queue or other consumer misbehavior, so not a fatal
+ // error
ALOGE("RequestThread: Can't get output buffer, skipping request:"
" %s (%d)", strerror(-res), res);
+ Mutex::Autolock l(mRequestLock);
+ if (mListener != NULL) {
+ mListener->notifyError(
+ ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ nextRequest->mResultExtras);
+ }
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return true;
}
request.num_output_buffers++;
}
-
- request.frame_number = mFrameNumber++;
+ totalNumBuffers += request.num_output_buffers;
// Log request in the in-flight queue
sp<Camera3Device> parent = mParent.promote();
if (parent == NULL) {
+ // Should not happen, and nowhere to send errors to, so just log it
CLOGE("RequestThread: Parent is gone");
cleanUpFailedRequest(request, nextRequest, outputBuffers);
return false;
}
- res = parent->registerInFlight(request.frame_number, requestId,
- request.num_output_buffers);
+ res = parent->registerInFlight(request.frame_number,
+ totalNumBuffers, nextRequest->mResultExtras,
+ /*hasInput*/request.input_buffer != NULL);
+ ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
+ ", burstId = %" PRId32 ".",
+ __FUNCTION__,
+ nextRequest->mResultExtras.requestId, nextRequest->mResultExtras.frameNumber,
+ nextRequest->mResultExtras.burstId);
if (res != OK) {
SET_ERR("RequestThread: Unable to register new in-flight request:"
" %s (%d)", strerror(-res), res);
@@ -2168,6 +2698,9 @@ bool Camera3Device::RequestThread::threadLoop() {
ATRACE_END();
if (res != OK) {
+ // Should only get a failure here for malformed requests or device-level
+ // errors, so consider all errors fatal. Bad metadata failures should
+ // come through notify.
SET_ERR("RequestThread: Unable to submit capture request %d to HAL"
" device: %s (%d)", request.frame_number, strerror(-res), res);
cleanUpFailedRequest(request, nextRequest, outputBuffers);
@@ -2196,21 +2729,6 @@ bool Camera3Device::RequestThread::threadLoop() {
}
mPrevTriggers = triggerCount;
- // Return input buffer back to framework
- if (request.input_buffer != NULL) {
- Camera3Stream *stream =
- Camera3Stream::cast(request.input_buffer->stream);
- res = stream->returnInputBuffer(*(request.input_buffer));
- // Note: stream may be deallocated at this point, if this buffer was the
- // last reference to it.
- if (res != OK) {
- ALOGE("%s: RequestThread: Can't return input buffer for frame %d to"
- " its stream:%s (%d)", __FUNCTION__,
- request.frame_number, strerror(-res), res);
- // TODO: Report error upstream
- }
- }
-
return true;
}
@@ -2222,6 +2740,7 @@ CameraMetadata Camera3Device::RequestThread::getLatestRequest() const {
return mLatestRequest;
}
+
void Camera3Device::RequestThread::cleanUpFailedRequest(
camera3_capture_request_t &request,
sp<CaptureRequest> &nextRequest,
@@ -2263,6 +2782,9 @@ sp<Camera3Device::CaptureRequest>
++firstRequest,
requests.end());
// No need to wait any longer
+
+ mRepeatingLastFrameNumber = mFrameNumber + requests.size() - 1;
+
break;
}
@@ -2314,6 +2836,11 @@ sp<Camera3Device::CaptureRequest>
mReconfigured = false;
}
+ if (nextRequest != NULL) {
+ nextRequest->mResultExtras.frameNumber = mFrameNumber++;
+ nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId;
+ nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId;
+ }
return nextRequest;
}
@@ -2376,13 +2903,34 @@ status_t Camera3Device::RequestThread::insertTriggers(
Mutex::Autolock al(mTriggerMutex);
+ sp<Camera3Device> parent = mParent.promote();
+ if (parent == NULL) {
+ CLOGE("RequestThread: Parent is gone");
+ return DEAD_OBJECT;
+ }
+
CameraMetadata &metadata = request->mSettings;
size_t count = mTriggerMap.size();
for (size_t i = 0; i < count; ++i) {
RequestTrigger trigger = mTriggerMap.valueAt(i);
-
uint32_t tag = trigger.metadataTag;
+
+ if (tag == ANDROID_CONTROL_AF_TRIGGER_ID || tag == ANDROID_CONTROL_AE_PRECAPTURE_ID) {
+ bool isAeTrigger = (trigger.metadataTag == ANDROID_CONTROL_AE_PRECAPTURE_ID);
+ uint32_t triggerId = static_cast<uint32_t>(trigger.entryValue);
+ if (isAeTrigger) {
+ request->mResultExtras.precaptureTriggerId = triggerId;
+ mCurrentPreCaptureTriggerId = triggerId;
+ } else {
+ request->mResultExtras.afTriggerId = triggerId;
+ mCurrentAfTriggerId = triggerId;
+ }
+ if (parent->mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
+ continue; // Trigger ID tag is deprecated since device HAL 3.2
+ }
+ }
+
camera_metadata_entry entry = metadata.find(tag);
if (entry.count > 0) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 468f641..ec6bba1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -24,6 +24,8 @@
#include <utils/Thread.h>
#include <utils/KeyedVector.h>
#include <hardware/camera3.h>
+#include <camera/CaptureResult.h>
+#include <camera/camera2/ICameraDeviceUser.h>
#include "common/CameraDeviceBase.h"
#include "device3/StatusTracker.h"
@@ -54,7 +56,7 @@ class Camera3StreamInterface;
}
/**
- * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0
+ * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
*/
class Camera3Device :
public CameraDeviceBase,
@@ -78,9 +80,14 @@ class Camera3Device :
// Capture and setStreamingRequest will configure streams if currently in
// idle state
- virtual status_t capture(CameraMetadata &request);
- virtual status_t setStreamingRequest(const CameraMetadata &request);
- virtual status_t clearStreamingRequest();
+ virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL);
+ virtual status_t captureList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber = NULL);
+ virtual status_t setStreamingRequest(const CameraMetadata &request,
+ int64_t *lastFrameNumber = NULL);
+ virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
+ int64_t *lastFrameNumber = NULL);
+ virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
@@ -88,8 +95,7 @@ class Camera3Device :
// If adding streams while actively capturing, will pause device before adding
// stream, reconfiguring device, and unpausing.
virtual status_t createStream(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size,
- int *id);
+ uint32_t width, uint32_t height, int format, int *id);
virtual status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id);
@@ -108,6 +114,8 @@ class Camera3Device :
virtual status_t deleteStream(int id);
virtual status_t deleteReprocessStream(int id);
+ virtual status_t configureStreams();
+
virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
// Transitions to the idle state on success
@@ -116,7 +124,7 @@ class Camera3Device :
virtual status_t setNotifyCallback(NotificationListener *listener);
virtual bool willNotify3A();
virtual status_t waitForNextFrame(nsecs_t timeout);
- virtual status_t getNextFrame(CameraMetadata *frame);
+ virtual status_t getNextResult(CaptureResult *frame);
virtual status_t triggerAutofocus(uint32_t id);
virtual status_t triggerCancelAutofocus(uint32_t id);
@@ -125,7 +133,11 @@ class Camera3Device :
virtual status_t pushReprocessBuffer(int reprocessStreamId,
buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
- virtual status_t flush();
+ virtual status_t flush(int64_t *lastFrameNumber = NULL);
+
+ virtual uint32_t getDeviceVersion();
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
@@ -137,6 +149,10 @@ class Camera3Device :
static const nsecs_t kShutdownTimeout = 5000000000; // 5 sec
static const nsecs_t kActiveTimeout = 500000000; // 500 ms
struct RequestTrigger;
+ // minimal jpeg buffer size: 256KB + blob header
+ static const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(camera3_jpeg_blob);
+ // Constant to use for stream ID when one doesn't exist
+ static const int NO_STREAM = -1;
// A lock to enforce serialization on the input/configure side
// of the public interface.
@@ -157,7 +173,10 @@ class Camera3Device :
camera3_device_t *mHal3Device;
CameraMetadata mDeviceInfo;
- vendor_tag_query_ops_t mVendorTagOps;
+
+ CameraMetadata mRequestTemplateCache[CAMERA3_TEMPLATE_COUNT];
+
+ uint32_t mDeviceVersion;
enum Status {
STATUS_ERROR,
@@ -181,6 +200,8 @@ class Camera3Device :
int mNextStreamId;
bool mNeedConfig;
+ int mDummyStreamId;
+
// Whether to send state updates upstream
// Pause when doing transparent reconfiguration
bool mPauseStateNotify;
@@ -188,8 +209,11 @@ class Camera3Device :
// Need to hold on to stream references until configure completes.
Vector<sp<camera3::Camera3StreamInterface> > mDeletedStreams;
- // Whether quirk ANDROID_QUIRKS_USE_PARTIAL_RESULT is enabled
- bool mUsePartialResultQuirk;
+ // Whether the HAL will send partial result
+ bool mUsePartialResult;
+
+ // Number of partial results that will be delivered by the HAL.
+ uint32_t mNumPartialResults;
/**** End scope for mLock ****/
@@ -199,9 +223,20 @@ class Camera3Device :
sp<camera3::Camera3Stream> mInputStream;
Vector<sp<camera3::Camera3OutputStreamInterface> >
mOutputStreams;
+ CaptureResultExtras mResultExtras;
};
typedef List<sp<CaptureRequest> > RequestList;
+ status_t checkStatusOkToCaptureLocked();
+
+ status_t convertMetadataListToRequestListLocked(
+ const List<const CameraMetadata> &metadataList,
+ /*out*/
+ RequestList *requestList);
+
+ status_t submitRequestsHelper(const List<const CameraMetadata> &requests, bool repeating,
+ int64_t *lastFrameNumber = NULL);
+
/**
* Get the last request submitted to the hal by the request thread.
*
@@ -237,6 +272,13 @@ class Camera3Device :
status_t waitUntilStateThenRelock(bool active, nsecs_t timeout);
/**
+ * Implementation of waitUntilDrained. On success, will transition to IDLE state.
+ *
+ * Need to be called with mLock and mInterfaceLock held.
+ */
+ status_t waitUntilDrainedLocked();
+
+ /**
* Do common work for setting up a streaming or single capture request.
* On success, will transition to ACTIVE if in IDLE.
*/
@@ -255,6 +297,17 @@ class Camera3Device :
status_t configureStreamsLocked();
/**
+ * Add a dummy stream to the current stream set as a workaround for
+ * not allowing 0 streams in the camera HAL spec.
+ */
+ status_t addDummyStreamLocked();
+
+ /**
+ * Remove a dummy stream if the current config includes real streams.
+ */
+ status_t tryRemoveDummyStreamLocked();
+
+ /**
* Set device into an error state due to some fatal failure, and set an
* error message to indicate why. Only the first call's message will be
* used. The message is also sent to the log.
@@ -270,6 +323,18 @@ class Camera3Device :
*/
bool tryLockSpinRightRound(Mutex& lock);
+ struct Size {
+ int width;
+ int height;
+ Size(int w, int h) : width(w), height(h){}
+ };
+
+ /**
+ * Helper function to get the largest Jpeg resolution (in area)
+ * Return Size(0, 0) if static metatdata is invalid
+ */
+ Size getMaxJpegResolution() const;
+
struct RequestTrigger {
// Metadata tag number, e.g. android.control.aePrecaptureTrigger
uint32_t metadataTag;
@@ -298,6 +363,8 @@ class Camera3Device :
sp<camera3::StatusTracker> statusTracker,
camera3_device_t *hal3Device);
+ void setNotifyCallback(NotificationListener *listener);
+
/**
* Call after stream (re)-configuration is completed.
*/
@@ -308,15 +375,22 @@ class Camera3Device :
* on either. Use waitUntilPaused to wait until request queue
* has emptied out.
*/
- status_t setRepeatingRequests(const RequestList& requests);
- status_t clearRepeatingRequests();
+ status_t setRepeatingRequests(const RequestList& requests,
+ /*out*/
+ int64_t *lastFrameNumber = NULL);
+ status_t clearRepeatingRequests(/*out*/
+ int64_t *lastFrameNumber = NULL);
- status_t queueRequest(sp<CaptureRequest> request);
+ status_t queueRequestList(List<sp<CaptureRequest> > &requests,
+ /*out*/
+ int64_t *lastFrameNumber = NULL);
/**
* Remove all queued and repeating requests, and pending triggers
*/
- status_t clear();
+ status_t clear(NotificationListener *listener,
+ /*out*/
+ int64_t *lastFrameNumber = NULL);
/**
* Queue a trigger to be dispatched with the next outgoing
@@ -391,10 +465,15 @@ class Camera3Device :
// Relay error to parent device object setErrorState
void setErrorState(const char *fmt, ...);
+ // If the input request is in mRepeatingRequests. Must be called with mRequestLock hold
+ bool isRepeatingRequestLocked(const sp<CaptureRequest>);
+
wp<Camera3Device> mParent;
wp<camera3::StatusTracker> mStatusTracker;
camera3_device_t *mHal3Device;
+ NotificationListener *mListener;
+
const int mId; // The camera ID
int mStatusId; // The RequestThread's component ID for
// status tracking
@@ -429,6 +508,10 @@ class Camera3Device :
TriggerMap mTriggerMap;
TriggerMap mTriggerRemovedMap;
TriggerMap mTriggerReplacedMap;
+ uint32_t mCurrentAfTriggerId;
+ uint32_t mCurrentPreCaptureTriggerId;
+
+ int64_t mRepeatingLastFrameNumber;
};
sp<RequestThread> mRequestThread;
@@ -437,71 +520,90 @@ 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
+ // and input buffers
int numBuffersLeft;
+ CaptureResultExtras resultExtras;
+ // If this request has any input buffer
+ bool hasInputBuffer;
- // Fields used by the partial result quirk only
- struct PartialResultQuirkInFlight {
+ // Fields used by the partial result only
+ struct PartialResultInFlight {
// Set by process_capture_result once 3A has been sent to clients
bool haveSent3A;
// Result metadata collected so far, when partial results are in use
CameraMetadata collectedResult;
- PartialResultQuirkInFlight():
+ PartialResultInFlight():
haveSent3A(false) {
}
- } partialResultQuirk;
+ } partialResult;
// Default constructor needed by KeyedVector
InFlightRequest() :
- requestId(0),
captureTimestamp(0),
requestStatus(OK),
haveResultMetadata(false),
- numBuffersLeft(0) {
+ numBuffersLeft(0),
+ hasInputBuffer(false){
}
- InFlightRequest(int id, int numBuffers) :
- requestId(id),
+ InFlightRequest(int numBuffers) :
captureTimestamp(0),
requestStatus(OK),
haveResultMetadata(false),
- numBuffersLeft(numBuffers) {
+ numBuffersLeft(numBuffers),
+ hasInputBuffer(false){
}
- };
+
+ InFlightRequest(int numBuffers, CaptureResultExtras extras) :
+ captureTimestamp(0),
+ requestStatus(OK),
+ haveResultMetadata(false),
+ numBuffersLeft(numBuffers),
+ resultExtras(extras),
+ hasInputBuffer(false){
+ }
+
+ InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput) :
+ captureTimestamp(0),
+ requestStatus(OK),
+ haveResultMetadata(false),
+ numBuffersLeft(numBuffers),
+ resultExtras(extras),
+ hasInputBuffer(hasInput){
+ }
+};
// Map from frame number to the in-flight request state
typedef KeyedVector<uint32_t, InFlightRequest> InFlightMap;
Mutex mInFlightLock; // Protects mInFlightMap
InFlightMap mInFlightMap;
- status_t registerInFlight(int32_t frameNumber, int32_t requestId,
- int32_t numBuffers);
+ status_t registerInFlight(uint32_t frameNumber,
+ int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput);
/**
- * For the partial result quirk, check if all 3A state fields are available
+ * For the partial result, check if all 3A state fields are available
* and if so, queue up 3A-only result to the client. Returns true if 3A
* is sent.
*/
- bool processPartial3AQuirk(int32_t frameNumber, int32_t requestId,
- const CameraMetadata& partial);
+ bool processPartial3AResult(uint32_t frameNumber,
+ const CameraMetadata& partial, const CaptureResultExtras& resultExtras);
// Helpers for reading and writing 3A metadata into to/from partial results
template<typename T>
bool get3AResult(const CameraMetadata& result, int32_t tag,
- T* value, int32_t frameNumber);
+ T* value, uint32_t frameNumber);
template<typename T>
bool insert3AResult(CameraMetadata &result, int32_t tag, const T* value,
- int32_t frameNumber);
+ uint32_t frameNumber);
/**
* Tracking for idle detection
*/
@@ -518,7 +620,7 @@ class Camera3Device :
uint32_t mNextResultFrameNumber;
uint32_t mNextShutterFrameNumber;
- List<CameraMetadata> mResultQueue;
+ List<CaptureResult> mResultQueue;
Condition mResultSignal;
NotificationListener *mListener;
@@ -531,6 +633,12 @@ class Camera3Device :
void notify(const camera3_notify_msg *msg);
+ // Specific notify handlers
+ void notifyError(const camera3_error_msg_t &msg,
+ NotificationListener *listener);
+ void notifyShutter(const camera3_shutter_msg_t &msg,
+ NotificationListener *listener);
+
/**
* Static callback forwarding methods from HAL to instance
*/
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
new file mode 100644
index 0000000..6656b09
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2014 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-DummyStream"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include "Camera3DummyStream.h"
+
+namespace android {
+
+namespace camera3 {
+
+Camera3DummyStream::Camera3DummyStream(int id) :
+ Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, DUMMY_WIDTH, DUMMY_HEIGHT,
+ /*maxSize*/0, DUMMY_FORMAT) {
+
+}
+
+Camera3DummyStream::~Camera3DummyStream() {
+
+}
+
+status_t Camera3DummyStream::getBufferLocked(camera3_stream_buffer *buffer) {
+ ATRACE_CALL();
+ ALOGE("%s: Stream %d: Dummy stream cannot produce buffers!", mId);
+ return INVALID_OPERATION;
+}
+
+status_t Camera3DummyStream::returnBufferLocked(
+ const camera3_stream_buffer &buffer,
+ nsecs_t timestamp) {
+ ATRACE_CALL();
+ ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId);
+ return INVALID_OPERATION;
+}
+
+status_t Camera3DummyStream::returnBufferCheckedLocked(
+ const camera3_stream_buffer &buffer,
+ nsecs_t timestamp,
+ bool output,
+ /*out*/
+ sp<Fence> *releaseFenceOut) {
+ ATRACE_CALL();
+ ALOGE("%s: Stream %d: Dummy stream cannot return buffers!", mId);
+ return INVALID_OPERATION;
+}
+
+void Camera3DummyStream::dump(int fd, const Vector<String16> &args) const {
+ (void) args;
+ String8 lines;
+ lines.appendFormat(" Stream[%d]: Dummy\n", mId);
+ write(fd, lines.string(), lines.size());
+
+ Camera3IOStreamBase::dump(fd, args);
+}
+
+status_t Camera3DummyStream::setTransform(int transform) {
+ ATRACE_CALL();
+ // Do nothing
+ return OK;
+}
+
+status_t Camera3DummyStream::configureQueueLocked() {
+ // Do nothing
+ return OK;
+}
+
+status_t Camera3DummyStream::disconnectLocked() {
+ mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG
+ : STATE_CONSTRUCTED;
+ return OK;
+}
+
+status_t Camera3DummyStream::getEndpointUsage(uint32_t *usage) {
+ *usage = DUMMY_USAGE;
+ return OK;
+}
+
+}; // namespace camera3
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
new file mode 100644
index 0000000..3e42623
--- /dev/null
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2014 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_DUMMY_STREAM_H
+#define ANDROID_SERVERS_CAMERA3_DUMMY_STREAM_H
+
+#include <utils/RefBase.h>
+#include <gui/Surface.h>
+
+#include "Camera3Stream.h"
+#include "Camera3IOStreamBase.h"
+#include "Camera3OutputStreamInterface.h"
+
+namespace android {
+namespace camera3 {
+
+/**
+ * A dummy output stream class, to be used as a placeholder when no valid
+ * streams are configured by the client.
+ * This is necessary because camera HAL v3.2 or older disallow configuring
+ * 0 output streams, while the public camera2 API allows for it.
+ */
+class Camera3DummyStream :
+ public Camera3IOStreamBase,
+ public Camera3OutputStreamInterface {
+
+ public:
+ /**
+ * Set up a dummy stream; doesn't actually connect to anything, and uses
+ * a default dummy format and size.
+ */
+ Camera3DummyStream(int id);
+
+ virtual ~Camera3DummyStream();
+
+ /**
+ * Camera3Stream interface
+ */
+
+ virtual void dump(int fd, const Vector<String16> &args) const;
+
+ status_t setTransform(int transform);
+
+ protected:
+
+ /**
+ * Note that we release the lock briefly in this function
+ */
+ virtual status_t returnBufferCheckedLocked(
+ const camera3_stream_buffer &buffer,
+ nsecs_t timestamp,
+ bool output,
+ /*out*/
+ sp<Fence> *releaseFenceOut);
+
+ virtual status_t disconnectLocked();
+
+ private:
+
+ // Default dummy parameters; 320x240 is a required size for all devices,
+ // otherwise act like a SurfaceView would.
+ static const int DUMMY_WIDTH = 320;
+ static const int DUMMY_HEIGHT = 240;
+ static const int DUMMY_FORMAT = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ static const uint32_t DUMMY_USAGE = GRALLOC_USAGE_HW_COMPOSER;
+
+ /**
+ * Internal Camera3Stream interface
+ */
+ virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
+ virtual status_t returnBufferLocked(
+ const camera3_stream_buffer &buffer,
+ nsecs_t timestamp);
+
+ virtual status_t configureQueueLocked();
+
+ virtual status_t getEndpointUsage(uint32_t *usage);
+
+}; // class Camera3DummyStream
+
+} // namespace camera3
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index d662cc2..cc66459 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -34,7 +34,8 @@ Camera3IOStreamBase::Camera3IOStreamBase(int id, camera3_stream_type_t type,
Camera3Stream(id, type,
width, height, maxSize, format),
mTotalBufferCount(0),
- mDequeuedBufferCount(0),
+ mHandoutTotalBufferCount(0),
+ mHandoutOutputBufferCount(0),
mFrameCount(0),
mLastTimestamp(0) {
@@ -55,8 +56,8 @@ bool Camera3IOStreamBase::hasOutstandingBuffersLocked() const {
nsecs_t signalTime = mCombinedFence->getSignalTime();
ALOGV("%s: Stream %d: Has %zu outstanding buffers,"
" buffer signal time is %" PRId64,
- __FUNCTION__, mId, mDequeuedBufferCount, signalTime);
- if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) {
+ __FUNCTION__, mId, mHandoutTotalBufferCount, signalTime);
+ if (mHandoutTotalBufferCount > 0 || signalTime == INT64_MAX) {
return true;
}
return false;
@@ -75,7 +76,7 @@ void Camera3IOStreamBase::dump(int fd, const Vector<String16> &args) const {
lines.appendFormat(" Frames produced: %d, last timestamp: %" PRId64 " ns\n",
mFrameCount, mLastTimestamp);
lines.appendFormat(" Total buffers: %zu, currently dequeued: %zu\n",
- mTotalBufferCount, mDequeuedBufferCount);
+ mTotalBufferCount, mHandoutTotalBufferCount);
write(fd, lines.string(), lines.size());
}
@@ -104,6 +105,14 @@ size_t Camera3IOStreamBase::getBufferCountLocked() {
return mTotalBufferCount;
}
+size_t Camera3IOStreamBase::getHandoutOutputBufferCountLocked() {
+ return mHandoutOutputBufferCount;
+}
+
+size_t Camera3IOStreamBase::getHandoutInputBufferCountLocked() {
+ return (mHandoutTotalBufferCount - mHandoutOutputBufferCount);
+}
+
status_t Camera3IOStreamBase::disconnectLocked() {
switch (mState) {
case STATE_IN_RECONFIG:
@@ -117,9 +126,9 @@ status_t Camera3IOStreamBase::disconnectLocked() {
return -ENOTCONN;
}
- if (mDequeuedBufferCount > 0) {
+ if (mHandoutTotalBufferCount > 0) {
ALOGE("%s: Can't disconnect with %zu buffers still dequeued!",
- __FUNCTION__, mDequeuedBufferCount);
+ __FUNCTION__, mHandoutTotalBufferCount);
return INVALID_OPERATION;
}
@@ -130,7 +139,8 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer,
buffer_handle_t *handle,
int acquireFence,
int releaseFence,
- camera3_buffer_status_t status) {
+ camera3_buffer_status_t status,
+ bool output) {
/**
* Note that all fences are now owned by HAL.
*/
@@ -144,14 +154,25 @@ void Camera3IOStreamBase::handoutBufferLocked(camera3_stream_buffer &buffer,
buffer.status = status;
// Inform tracker about becoming busy
- if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG &&
+ if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG &&
mState != STATE_IN_RECONFIG) {
+ /**
+ * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers
+ * before/after register_stream_buffers during initial configuration
+ * or re-configuration.
+ *
+ * TODO: IN_CONFIG and IN_RECONFIG checks only make sense for <HAL3.2
+ */
sp<StatusTracker> statusTracker = mStatusTracker.promote();
if (statusTracker != 0) {
statusTracker->markComponentActive(mStatusId);
}
}
- mDequeuedBufferCount++;
+ mHandoutTotalBufferCount++;
+
+ if (output) {
+ mHandoutOutputBufferCount++;
+ }
}
status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const {
@@ -163,15 +184,6 @@ status_t Camera3IOStreamBase::getBufferPreconditionCheckLocked() const {
return INVALID_OPERATION;
}
- // Only limit dequeue amount when fully configured
- if (mState == STATE_CONFIGURED &&
- mDequeuedBufferCount == camera3_stream::max_buffers) {
- ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous"
- " buffers (%d)", __FUNCTION__, mId,
- camera3_stream::max_buffers);
- return INVALID_OPERATION;
- }
-
return OK;
}
@@ -183,7 +195,7 @@ status_t Camera3IOStreamBase::returnBufferPreconditionCheckLocked() const {
__FUNCTION__, mId, mState);
return INVALID_OPERATION;
}
- if (mDequeuedBufferCount == 0) {
+ if (mHandoutTotalBufferCount == 0) {
ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__,
mId);
return INVALID_OPERATION;
@@ -221,9 +233,20 @@ status_t Camera3IOStreamBase::returnAnyBufferLocked(
mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence);
}
- mDequeuedBufferCount--;
- if (mDequeuedBufferCount == 0 && mState != STATE_IN_CONFIG &&
+ if (output) {
+ mHandoutOutputBufferCount--;
+ }
+
+ mHandoutTotalBufferCount--;
+ if (mHandoutTotalBufferCount == 0 && mState != STATE_IN_CONFIG &&
mState != STATE_IN_RECONFIG) {
+ /**
+ * Avoid a spurious IDLE->ACTIVE->IDLE transition when using buffers
+ * before/after register_stream_buffers during initial configuration
+ * or re-configuration.
+ *
+ * TODO: IN_CONFIG and IN_RECONFIG checks only make sense for <HAL3.2
+ */
ALOGV("%s: Stream %d: All buffers returned; now idle", __FUNCTION__,
mId);
sp<StatusTracker> statusTracker = mStatusTracker.promote();
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
index fcb9d04..a35c290 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.h
@@ -48,7 +48,10 @@ class Camera3IOStreamBase :
protected:
size_t mTotalBufferCount;
// sum of input and output buffers that are currently acquired by HAL
- size_t mDequeuedBufferCount;
+ size_t mHandoutTotalBufferCount;
+ // number of output buffers that are currently acquired by HAL. This will be
+ // Redundant when camera3 streams are no longer bidirectional streams.
+ size_t mHandoutOutputBufferCount;
Condition mBufferReturnedSignal;
uint32_t mFrameCount;
// Last received output buffer's timestamp
@@ -76,6 +79,10 @@ class Camera3IOStreamBase :
virtual size_t getBufferCountLocked();
+ virtual size_t getHandoutOutputBufferCountLocked();
+
+ virtual size_t getHandoutInputBufferCountLocked();
+
virtual status_t getEndpointUsage(uint32_t *usage) = 0;
status_t getBufferPreconditionCheckLocked() const;
@@ -92,7 +99,8 @@ class Camera3IOStreamBase :
buffer_handle_t *handle,
int acquire_fence,
int release_fence,
- camera3_buffer_status_t status);
+ camera3_buffer_status_t status,
+ bool output);
}; // class Camera3IOStreamBase
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 5aa9a3e..319be1d 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -81,7 +81,7 @@ status_t Camera3InputStream::getInputBufferLocked(
* in which case we reassign it to acquire_fence
*/
handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
- /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK);
+ /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
mBuffersInFlight.push_back(bufferItem);
return OK;
@@ -199,14 +199,36 @@ status_t Camera3InputStream::configureQueueLocked() {
assert(mMaxSize == 0);
assert(camera3_stream::format != HAL_PIXEL_FORMAT_BLOB);
- mTotalBufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS +
- camera3_stream::max_buffers;
- mDequeuedBufferCount = 0;
+ mHandoutTotalBufferCount = 0;
mFrameCount = 0;
if (mConsumer.get() == 0) {
- sp<BufferQueue> bq = new BufferQueue();
- mConsumer = new BufferItemConsumer(bq, camera3_stream::usage,
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ int minUndequeuedBuffers = 0;
+ res = producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
+ if (res != OK || minUndequeuedBuffers < 0) {
+ ALOGE("%s: Stream %d: Could not query min undequeued buffers (error %d, bufCount %d)",
+ __FUNCTION__, mId, res, minUndequeuedBuffers);
+ return res;
+ }
+ size_t minBufs = static_cast<size_t>(minUndequeuedBuffers);
+ /*
+ * We promise never to 'acquire' more than camera3_stream::max_buffers
+ * at any one time.
+ *
+ * Boost the number up to meet the minimum required buffer count.
+ *
+ * (Note that this sets consumer-side buffer count only,
+ * and not the sum of producer+consumer side as in other camera streams).
+ */
+ mTotalBufferCount = camera3_stream::max_buffers > minBufs ?
+ camera3_stream::max_buffers : minBufs;
+ // TODO: somehow set the total buffer count when producer connects?
+
+ mConsumer = new BufferItemConsumer(consumer, camera3_stream::usage,
mTotalBufferCount);
mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
}
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index 681d684..ae49467 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -44,6 +44,8 @@ class Camera3InputStream : public Camera3IOStreamBase {
virtual void dump(int fd, const Vector<String16> &args) const;
+ // TODO: expose an interface to get the IGraphicBufferProducer
+
private:
typedef BufferItemConsumer::BufferItem BufferItem;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 682755d..77ad503 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -37,7 +37,8 @@ Camera3OutputStream::Camera3OutputStream(int id,
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
/*maxSize*/0, format),
mConsumer(consumer),
- mTransform(0) {
+ mTransform(0),
+ mTraceFirstBuffer(true) {
if (mConsumer == NULL) {
ALOGE("%s: Consumer is NULL!", __FUNCTION__);
@@ -51,7 +52,8 @@ Camera3OutputStream::Camera3OutputStream(int id,
Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height, maxSize,
format),
mConsumer(consumer),
- mTransform(0) {
+ mTransform(0),
+ mTraceFirstBuffer(true) {
if (format != HAL_PIXEL_FORMAT_BLOB) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
@@ -119,7 +121,7 @@ status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
* in which case we reassign it to acquire_fence
*/
handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
- /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK);
+ /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/true);
return OK;
}
@@ -202,6 +204,15 @@ status_t Camera3OutputStream::returnBufferCheckedLocked(
" %s (%d)", __FUNCTION__, mId, strerror(-res), res);
}
} else {
+ if (mTraceFirstBuffer && (stream_type == CAMERA3_STREAM_OUTPUT)) {
+ {
+ char traceLog[48];
+ snprintf(traceLog, sizeof(traceLog), "Stream %d: first full buffer\n", mId);
+ ATRACE_NAME(traceLog);
+ }
+ mTraceFirstBuffer = false;
+ }
+
res = currentConsumer->queueBuffer(currentConsumer.get(),
container_of(buffer.buffer, ANativeWindowBuffer, handle),
anwReleaseFence);
@@ -257,6 +268,7 @@ status_t Camera3OutputStream::setTransformLocked(int transform) {
status_t Camera3OutputStream::configureQueueLocked() {
status_t res;
+ mTraceFirstBuffer = true;
if ((res = Camera3IOStreamBase::configureQueueLocked()) != OK) {
return res;
}
@@ -289,20 +301,25 @@ status_t Camera3OutputStream::configureQueueLocked() {
if (mMaxSize == 0) {
// For buffers of known size
- res = native_window_set_buffers_geometry(mConsumer.get(),
- camera3_stream::width, camera3_stream::height,
- camera3_stream::format);
+ res = native_window_set_buffers_dimensions(mConsumer.get(),
+ camera3_stream::width, camera3_stream::height);
} else {
// For buffers with bounded size
- res = native_window_set_buffers_geometry(mConsumer.get(),
- mMaxSize, 1,
- camera3_stream::format);
+ res = native_window_set_buffers_dimensions(mConsumer.get(),
+ mMaxSize, 1);
}
if (res != OK) {
- ALOGE("%s: Unable to configure stream buffer geometry"
- " %d x %d, format %x for stream %d",
+ ALOGE("%s: Unable to configure stream buffer dimensions"
+ " %d x %d (maxSize %zu) for stream %d",
__FUNCTION__, camera3_stream::width, camera3_stream::height,
- camera3_stream::format, mId);
+ mMaxSize, mId);
+ return res;
+ }
+ res = native_window_set_buffers_format(mConsumer.get(),
+ camera3_stream::format);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure stream buffer format %#x for stream %d",
+ __FUNCTION__, camera3_stream::format, mId);
return res;
}
@@ -324,7 +341,7 @@ status_t Camera3OutputStream::configureQueueLocked() {
}
mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers;
- mDequeuedBufferCount = 0;
+ mHandoutTotalBufferCount = 0;
mFrameCount = 0;
mLastTimestamp = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 6cbb9f4..be278c5 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -76,12 +76,16 @@ class Camera3OutputStream :
/*out*/
sp<Fence> *releaseFenceOut);
+ virtual status_t disconnectLocked();
+
sp<ANativeWindow> mConsumer;
private:
int mTransform;
virtual status_t setTransformLocked(int transform);
+ bool mTraceFirstBuffer;
+
/**
* Internal Camera3Stream interface
*/
@@ -91,7 +95,6 @@ class Camera3OutputStream :
nsecs_t timestamp);
virtual status_t configureQueueLocked();
- virtual status_t disconnectLocked();
virtual status_t getEndpointUsage(uint32_t *usage);
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 70406f1..3c0e908 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -23,6 +23,8 @@
#include "device3/Camera3Stream.h"
#include "device3/StatusTracker.h"
+#include <cutils/properties.h>
+
namespace android {
namespace camera3 {
@@ -137,6 +139,7 @@ camera3_stream* Camera3Stream::startConfiguration() {
if (mState == STATE_CONSTRUCTED) {
mState = STATE_IN_CONFIG;
} else { // mState == STATE_CONFIGURED
+ LOG_ALWAYS_FATAL_IF(mState != STATE_CONFIGURED, "Invalid state: 0x%x", mState);
mState = STATE_IN_RECONFIG;
}
@@ -206,11 +209,61 @@ status_t Camera3Stream::finishConfiguration(camera3_device *hal3Device) {
return res;
}
+status_t Camera3Stream::cancelConfiguration() {
+ ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+ switch (mState) {
+ case STATE_ERROR:
+ ALOGE("%s: In error state", __FUNCTION__);
+ return INVALID_OPERATION;
+ case STATE_IN_CONFIG:
+ case STATE_IN_RECONFIG:
+ // OK
+ break;
+ case STATE_CONSTRUCTED:
+ case STATE_CONFIGURED:
+ ALOGE("%s: Cannot cancel configuration that hasn't been started",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ default:
+ ALOGE("%s: Unknown state", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ camera3_stream::usage = oldUsage;
+ camera3_stream::max_buffers = oldMaxBuffers;
+
+ mState = (mState == STATE_IN_RECONFIG) ? STATE_CONFIGURED : STATE_CONSTRUCTED;
+ return OK;
+}
+
status_t Camera3Stream::getBuffer(camera3_stream_buffer *buffer) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
+ status_t res = OK;
+
+ // This function should be only called when the stream is configured already.
+ if (mState != STATE_CONFIGURED) {
+ ALOGE("%s: Stream %d: Can't get buffers if stream is not in CONFIGURED state %d",
+ __FUNCTION__, mId, mState);
+ return INVALID_OPERATION;
+ }
+
+ // Wait for new buffer returned back if we are running into the limit.
+ if (getHandoutOutputBufferCountLocked() == camera3_stream::max_buffers) {
+ ALOGV("%s: Already dequeued max output buffers (%d), wait for next returned one.",
+ __FUNCTION__, camera3_stream::max_buffers);
+ res = mOutputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
+ if (res != OK) {
+ if (res == TIMED_OUT) {
+ ALOGE("%s: wait for output buffer return timed out after %lldms", __FUNCTION__,
+ kWaitForBufferDuration / 1000000LL);
+ }
+ return res;
+ }
+ }
- status_t res = getBufferLocked(buffer);
+ res = getBufferLocked(buffer);
if (res == OK) {
fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/true);
}
@@ -223,9 +276,18 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
ATRACE_CALL();
Mutex::Autolock l(mLock);
+ /**
+ * TODO: Check that the state is valid first.
+ *
+ * <HAL3.2 IN_CONFIG and IN_RECONFIG in addition to CONFIGURED.
+ * >= HAL3.2 CONFIGURED only
+ *
+ * Do this for getBuffer as well.
+ */
status_t res = returnBufferLocked(buffer, timestamp);
if (res == OK) {
fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/true);
+ mOutputBufferReturnedSignal.signal();
}
return res;
@@ -234,8 +296,30 @@ status_t Camera3Stream::returnBuffer(const camera3_stream_buffer &buffer,
status_t Camera3Stream::getInputBuffer(camera3_stream_buffer *buffer) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
+ status_t res = OK;
+
+ // This function should be only called when the stream is configured already.
+ if (mState != STATE_CONFIGURED) {
+ ALOGE("%s: Stream %d: Can't get input buffers if stream is not in CONFIGURED state %d",
+ __FUNCTION__, mId, mState);
+ return INVALID_OPERATION;
+ }
+
+ // Wait for new buffer returned back if we are running into the limit.
+ if (getHandoutInputBufferCountLocked() == camera3_stream::max_buffers) {
+ ALOGV("%s: Already dequeued max input buffers (%d), wait for next returned one.",
+ __FUNCTION__, camera3_stream::max_buffers);
+ res = mInputBufferReturnedSignal.waitRelative(mLock, kWaitForBufferDuration);
+ if (res != OK) {
+ if (res == TIMED_OUT) {
+ ALOGE("%s: wait for input buffer return timed out after %lldms", __FUNCTION__,
+ kWaitForBufferDuration / 1000000LL);
+ }
+ return res;
+ }
+ }
- status_t res = getInputBufferLocked(buffer);
+ res = getInputBufferLocked(buffer);
if (res == OK) {
fireBufferListenersLocked(*buffer, /*acquired*/true, /*output*/false);
}
@@ -250,6 +334,7 @@ status_t Camera3Stream::returnInputBuffer(const camera3_stream_buffer &buffer) {
status_t res = returnInputBufferLocked(buffer);
if (res == OK) {
fireBufferListenersLocked(buffer, /*acquired*/false, /*output*/false);
+ mInputBufferReturnedSignal.signal();
}
return res;
}
@@ -314,12 +399,35 @@ status_t Camera3Stream::disconnect() {
status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) {
ATRACE_CALL();
+
+ /**
+ * >= CAMERA_DEVICE_API_VERSION_3_2:
+ *
+ * camera3_device_t->ops->register_stream_buffers() is not called and must
+ * be NULL.
+ */
+ if (hal3Device->common.version >= CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGV("%s: register_stream_buffers unused as of HAL3.2", __FUNCTION__);
+
+ if (hal3Device->ops->register_stream_buffers != NULL) {
+ ALOGE("%s: register_stream_buffers is deprecated in HAL3.2; "
+ "must be set to NULL in camera3_device::ops", __FUNCTION__);
+ return INVALID_OPERATION;
+ } else {
+ ALOGD("%s: Skipping NULL check for deprecated register_stream_buffers", __FUNCTION__);
+ }
+
+ return OK;
+ } else {
+ ALOGV("%s: register_stream_buffers using deprecated code path", __FUNCTION__);
+ }
+
status_t res;
size_t bufferCount = getBufferCountLocked();
Vector<buffer_handle_t*> buffers;
- buffers.insertAt(NULL, 0, bufferCount);
+ buffers.insertAt(/*prototype_item*/NULL, /*index*/0, bufferCount);
camera3_stream_buffer_set bufferSet = camera3_stream_buffer_set();
bufferSet.stream = this;
@@ -327,7 +435,7 @@ status_t Camera3Stream::registerBuffersLocked(camera3_device *hal3Device) {
bufferSet.buffers = buffers.editArray();
Vector<camera3_stream_buffer_t> streamBuffers;
- streamBuffers.insertAt(camera3_stream_buffer_t(), 0, bufferCount);
+ streamBuffers.insertAt(camera3_stream_buffer_t(), /*index*/0, bufferCount);
// Register all buffers with the HAL. This means getting all the buffers
// from the stream, providing them to the HAL with the
@@ -394,6 +502,18 @@ status_t Camera3Stream::returnInputBufferLocked(
void Camera3Stream::addBufferListener(
wp<Camera3StreamBufferListener> listener) {
Mutex::Autolock l(mLock);
+
+ List<wp<Camera3StreamBufferListener> >::iterator it, end;
+ for (it = mBufferListenerList.begin(), end = mBufferListenerList.end();
+ it != end;
+ ) {
+ if (*it == listener) {
+ ALOGE("%s: Try to add the same listener twice, ignoring...", __FUNCTION__);
+ return;
+ }
+ it++;
+ }
+
mBufferListenerList.push_back(listener);
}
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 6eeb721..d0e1337 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -82,6 +82,23 @@ namespace camera3 {
* STATE_CONFIGURED => STATE_CONSTRUCTED:
* When disconnect() is called after making sure stream is idle with
* waitUntilIdle().
+ *
+ * Status Tracking:
+ * Each stream is tracked by StatusTracker as a separate component,
+ * depending on the handed out buffer count. The state must be STATE_CONFIGURED
+ * in order for the component to be marked.
+ *
+ * It's marked in one of two ways:
+ *
+ * - ACTIVE: One or more buffers have been handed out (with #getBuffer).
+ * - IDLE: All buffers have been returned (with #returnBuffer), and their
+ * respective release_fence(s) have been signaled.
+ *
+ * A typical use case is output streams. When the HAL has any buffers
+ * dequeued, the stream is marked ACTIVE. When the HAL returns all buffers
+ * (e.g. if no capture requests are active), the stream is marked IDLE.
+ * In this use case, the app consumer does not affect the component status.
+ *
*/
class Camera3Stream :
protected camera3_stream,
@@ -142,6 +159,13 @@ class Camera3Stream :
status_t finishConfiguration(camera3_device *hal3Device);
/**
+ * Cancels the stream configuration process. This returns the stream to the
+ * initial state, allowing it to be configured again later.
+ * This is done if the HAL rejects the proposed combined stream configuration
+ */
+ status_t cancelConfiguration();
+
+ /**
* Fill in the camera3_stream_buffer with the next valid buffer for this
* stream, to hand over to the HAL.
*
@@ -209,8 +233,17 @@ class Camera3Stream :
*/
virtual void dump(int fd, const Vector<String16> &args) const = 0;
+ /**
+ * Add a camera3 buffer listener. Adding the same listener twice has
+ * no effect.
+ */
void addBufferListener(
wp<Camera3StreamBufferListener> listener);
+
+ /**
+ * Remove a camera3 buffer listener. Removing the same listener twice
+ * or the listener that was never added has no effect.
+ */
void removeBufferListener(
const sp<Camera3StreamBufferListener>& listener);
@@ -262,6 +295,12 @@ class Camera3Stream :
// Get the total number of buffers in the queue
virtual size_t getBufferCountLocked() = 0;
+ // Get handout output buffer count.
+ virtual size_t getHandoutOutputBufferCountLocked() = 0;
+
+ // Get handout input buffer count.
+ virtual size_t getHandoutInputBufferCountLocked() = 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;
@@ -274,6 +313,9 @@ class Camera3Stream :
private:
uint32_t oldUsage;
uint32_t oldMaxBuffers;
+ Condition mOutputBufferReturnedSignal;
+ Condition mInputBufferReturnedSignal;
+ static const nsecs_t kWaitForBufferDuration = 3000000000LL; // 3000 ms
// Gets all buffers from endpoint and registers them with the HAL.
status_t registerBuffersLocked(camera3_device *hal3Device);
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index c93ae15..da989cd 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -82,6 +82,13 @@ class Camera3StreamInterface : public virtual RefBase {
virtual status_t finishConfiguration(camera3_device *hal3Device) = 0;
/**
+ * Cancels the stream configuration process. This returns the stream to the
+ * initial state, allowing it to be configured again later.
+ * This is done if the HAL rejects the proposed combined stream configuration
+ */
+ virtual status_t cancelConfiguration() = 0;
+
+ /**
* Fill in the camera3_stream_buffer with the next valid buffer for this
* stream, to hand over to the HAL.
*
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index 44d8188..81330ea 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -111,15 +111,17 @@ struct TimestampFinder : public RingBufferConsumer::RingBufferComparator {
} // namespace anonymous
Camera3ZslStream::Camera3ZslStream(int id, uint32_t width, uint32_t height,
- int depth) :
+ int bufferCount) :
Camera3OutputStream(id, CAMERA3_STREAM_BIDIRECTIONAL,
width, height,
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mDepth(depth) {
+ mDepth(bufferCount) {
- sp<BufferQueue> bq = new BufferQueue();
- mProducer = new RingBufferConsumer(bq, GRALLOC_USAGE_HW_CAMERA_ZSL, depth);
- mConsumer = new Surface(bq);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
+ mConsumer = new Surface(producer);
}
Camera3ZslStream::~Camera3ZslStream() {
@@ -174,7 +176,7 @@ status_t Camera3ZslStream::getInputBufferLocked(camera3_stream_buffer *buffer) {
* in which case we reassign it to acquire_fence
*/
handoutBufferLocked(*buffer, &(anb->handle), /*acquireFence*/fenceFd,
- /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK);
+ /*releaseFence*/-1, CAMERA3_BUFFER_STATUS_OK, /*output*/false);
mBuffersInFlight.push_back(bufferItem);
@@ -298,6 +300,7 @@ status_t Camera3ZslStream::enqueueInputBufferByTimestamp(
nsecs_t actual = pinnedBuffer->getBufferItem().mTimestamp;
if (actual != timestamp) {
+ // TODO: this is problematic, we'll end up with using wrong result for this pinned buffer.
ALOGW("%s: ZSL buffer candidate search didn't find an exact match --"
" requested timestamp = %" PRId64 ", actual timestamp = %" PRId64,
__FUNCTION__, timestamp, actual);
@@ -312,14 +315,28 @@ status_t Camera3ZslStream::enqueueInputBufferByTimestamp(
return OK;
}
-status_t Camera3ZslStream::clearInputRingBuffer() {
+status_t Camera3ZslStream::clearInputRingBuffer(nsecs_t* latestTimestamp) {
Mutex::Autolock l(mLock);
+ return clearInputRingBufferLocked(latestTimestamp);
+}
+
+status_t Camera3ZslStream::clearInputRingBufferLocked(nsecs_t* latestTimestamp) {
+
+ if (latestTimestamp) {
+ *latestTimestamp = mProducer->getLatestTimestamp();
+ }
mInputBufferQueue.clear();
return mProducer->clear();
}
+status_t Camera3ZslStream::disconnectLocked() {
+ clearInputRingBufferLocked(NULL);
+
+ return Camera3OutputStream::disconnectLocked();
+}
+
status_t Camera3ZslStream::setTransform(int /*transform*/) {
ALOGV("%s: Not implemented", __FUNCTION__);
return INVALID_OPERATION;
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.h b/services/camera/libcameraservice/device3/Camera3ZslStream.h
index c7f4490..5323a49 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.h
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.h
@@ -37,10 +37,10 @@ class Camera3ZslStream :
public Camera3OutputStream {
public:
/**
- * Set up a ZSL stream of a given resolution. Depth is the number of buffers
+ * Set up a ZSL stream of a given resolution. bufferCount is the number of buffers
* cached within the stream that can be retrieved for input.
*/
- Camera3ZslStream(int id, uint32_t width, uint32_t height, int depth);
+ Camera3ZslStream(int id, uint32_t width, uint32_t height, int bufferCount);
~Camera3ZslStream();
virtual void dump(int fd, const Vector<String16> &args) const;
@@ -59,8 +59,10 @@ class Camera3ZslStream :
/**
* Clears the buffers that can be used by enqueueInputBufferByTimestamp
+ * latestTimestamp will be filled with the largest timestamp of buffers
+ * being cleared, 0 if there is no buffer being clear.
*/
- status_t clearInputRingBuffer();
+ status_t clearInputRingBuffer(nsecs_t* latestTimestamp);
protected:
@@ -96,6 +98,12 @@ class Camera3ZslStream :
bool output,
/*out*/
sp<Fence> *releaseFenceOut);
+
+ // Disconnet the Camera3ZslStream specific bufferQueues.
+ virtual status_t disconnectLocked();
+
+ status_t clearInputRingBufferLocked(nsecs_t* latestTimestamp);
+
}; // class Camera3ZslStream
}; // namespace camera3
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index e4ec5fd..f8562ec 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -41,7 +41,8 @@ RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consume
uint32_t consumerUsage,
int bufferCount) :
ConsumerBase(consumer),
- mBufferCount(bufferCount)
+ mBufferCount(bufferCount),
+ mLatestTimestamp(0)
{
mConsumer->setConsumerUsageBits(consumerUsage);
mConsumer->setMaxAcquiredBufferCount(bufferCount);
@@ -152,6 +153,14 @@ status_t RingBufferConsumer::clear() {
return OK;
}
+nsecs_t RingBufferConsumer::getLatestTimestamp() {
+ Mutex::Autolock _l(mMutex);
+ if (mBufferItemList.size() == 0) {
+ return 0;
+ }
+ return mLatestTimestamp;
+}
+
void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
List<RingBufferItem>::iterator it, end;
@@ -302,6 +311,13 @@ void RingBufferConsumer::onFrameAvailable() {
item.mTimestamp,
mBufferItemList.size(), mBufferCount);
+ if (item.mTimestamp < mLatestTimestamp) {
+ BI_LOGE("Timestamp decreases from %" PRId64 " to %" PRId64,
+ mLatestTimestamp, item.mTimestamp);
+ }
+
+ mLatestTimestamp = item.mTimestamp;
+
item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
} // end of mMutex lock
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index b4ad824..da97a11 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -64,7 +64,7 @@ class RingBufferConsumer : public ConsumerBase,
// bufferCount parameter specifies how many buffers can be pinned for user
// access at the same time.
RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, uint32_t consumerUsage,
- int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS);
+ int bufferCount);
virtual ~RingBufferConsumer();
@@ -159,6 +159,9 @@ class RingBufferConsumer : public ConsumerBase,
// Release all the non-pinned buffers in the ring buffer
status_t clear();
+ // Return 0 if RingBuffer is empty, otherwise return timestamp of latest buffer.
+ nsecs_t getLatestTimestamp();
+
private:
// Override ConsumerBase::onFrameAvailable
@@ -180,6 +183,9 @@ class RingBufferConsumer : public ConsumerBase,
// List of acquired buffers in our ring buffer
List<RingBufferItem> mBufferItemList;
const int mBufferCount;
+
+ // Timestamp of latest buffer
+ nsecs_t mLatestTimestamp;
};
} // namespace android