diff options
Diffstat (limited to 'camera')
-rw-r--r-- | camera/Android.mk | 5 | ||||
-rw-r--r-- | camera/Camera.cpp | 3 | ||||
-rw-r--r-- | camera/CameraBase.cpp | 2 | ||||
-rw-r--r-- | camera/CameraMetadata.cpp | 15 | ||||
-rw-r--r-- | camera/CameraParameters.cpp | 6 | ||||
-rw-r--r-- | camera/ICameraService.cpp | 129 | ||||
-rw-r--r-- | camera/ICameraServiceListener.cpp | 37 | ||||
-rw-r--r-- | camera/ICameraServiceProxy.cpp | 55 | ||||
-rw-r--r-- | camera/IProCameraCallbacks.cpp | 125 | ||||
-rw-r--r-- | camera/IProCameraUser.cpp | 324 | ||||
-rw-r--r-- | camera/ProCamera.cpp | 436 | ||||
-rw-r--r-- | camera/camera2/CaptureRequest.cpp | 9 | ||||
-rw-r--r-- | camera/camera2/ICameraDeviceCallbacks.cpp | 22 | ||||
-rw-r--r-- | camera/camera2/ICameraDeviceUser.cpp | 171 | ||||
-rw-r--r-- | camera/camera2/OutputConfiguration.cpp | 84 | ||||
-rw-r--r-- | camera/tests/Android.mk | 4 | ||||
-rw-r--r-- | camera/tests/CameraBinderTests.cpp | 484 | ||||
-rw-r--r-- | camera/tests/ProCameraTests.cpp | 1278 | ||||
-rw-r--r-- | camera/tests/VendorTagDescriptorTests.cpp | 9 |
19 files changed, 928 insertions, 2270 deletions
diff --git a/camera/Android.mk b/camera/Android.mk index da5ac59..471cb0d 100644 --- a/camera/Android.mk +++ b/camera/Android.mk @@ -28,14 +28,13 @@ LOCAL_SRC_FILES:= \ ICameraClient.cpp \ ICameraService.cpp \ ICameraServiceListener.cpp \ + ICameraServiceProxy.cpp \ ICameraRecordingProxy.cpp \ ICameraRecordingProxyListener.cpp \ - IProCameraUser.cpp \ - IProCameraCallbacks.cpp \ camera2/ICameraDeviceUser.cpp \ camera2/ICameraDeviceCallbacks.cpp \ camera2/CaptureRequest.cpp \ - ProCamera.cpp \ + camera2/OutputConfiguration.cpp \ CameraBase.cpp \ CameraUtils.cpp \ VendorTagDescriptor.cpp diff --git a/camera/Camera.cpp b/camera/Camera.cpp index 3a9fb4c..9bf3134 100644 --- a/camera/Camera.cpp +++ b/camera/Camera.cpp @@ -97,7 +97,8 @@ status_t Camera::connectLegacy(int cameraId, int halVersion, c->mStatus = NO_ERROR; camera = c; } else { - ALOGW("An error occurred while connecting to camera: %d", cameraId); + ALOGW("An error occurred while connecting to camera %d: %d (%s)", + cameraId, status, strerror(-status)); c.clear(); } return status; diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp index 65a1a47..5d50aa8 100644 --- a/camera/CameraBase.cpp +++ b/camera/CameraBase.cpp @@ -29,7 +29,6 @@ #include <camera/ICameraService.h> // needed to instantiate -#include <camera/ProCamera.h> #include <camera/Camera.h> #include <system/camera_metadata.h> @@ -217,7 +216,6 @@ status_t CameraBase<TCam, TCamTraits>::removeServiceListener( return cs->removeListener(listener); } -template class CameraBase<ProCamera>; template class CameraBase<Camera>; } // namespace android diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp index 043437f..46bcc1d 100644 --- a/camera/CameraMetadata.cpp +++ b/camera/CameraMetadata.cpp @@ -74,7 +74,7 @@ CameraMetadata::~CameraMetadata() { clear(); } -const camera_metadata_t* CameraMetadata::getAndLock() { +const camera_metadata_t* CameraMetadata::getAndLock() const { mLocked = true; return mBuffer; } @@ -289,6 +289,17 @@ status_t CameraMetadata::updateImpl(uint32_t tag, const void *data, ALOGE("%s: Tag %d not found", __FUNCTION__, tag); return BAD_VALUE; } + // Safety check - ensure that data isn't pointing to this metadata, since + // that would get invalidated if a resize is needed + size_t bufferSize = get_camera_metadata_size(mBuffer); + uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer); + uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data); + if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) { + ALOGE("%s: Update attempted with data from the same metadata buffer!", + __FUNCTION__); + return INVALID_OPERATION; + } + size_t data_size = calculate_camera_metadata_entry_data_size(type, data_count); @@ -583,7 +594,7 @@ status_t CameraMetadata::writeToParcel(Parcel& data, */ WritableBlob blob; do { - res = data.writeBlob(blobSize, &blob); + res = data.writeBlob(blobSize, false, &blob); if (res != OK) { break; } diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index e5e4e90..68969cf 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -526,8 +526,12 @@ int CameraParameters::previewFormatToEnum(const char* format) { !strcmp(format, PIXEL_FORMAT_RGBA8888) ? HAL_PIXEL_FORMAT_RGBA_8888 : // RGB8888 !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ? - HAL_PIXEL_FORMAT_RAW_SENSOR : // Raw sensor data + HAL_PIXEL_FORMAT_RAW16 : // Raw sensor data -1; } +bool CameraParameters::isEmpty() const { + return mMap.isEmpty(); +} + }; // namespace android diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index fc3e437..7c9720f 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -2,16 +2,16 @@ ** ** Copyright 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 +** 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 +** 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 +** 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. */ @@ -20,6 +20,7 @@ #include <utils/Errors.h> #include <utils/String16.h> +#include <inttypes.h> #include <stdint.h> #include <sys/types.h> @@ -29,8 +30,6 @@ #include <camera/ICameraService.h> #include <camera/ICameraServiceListener.h> -#include <camera/IProCameraUser.h> -#include <camera/IProCameraCallbacks.h> #include <camera/ICamera.h> #include <camera/ICameraClient.h> #include <camera/camera2/ICameraDeviceUser.h> @@ -176,10 +175,13 @@ public: data.writeInt32(cameraId); data.writeString16(clientPackageName); data.writeInt32(clientUid); - remote()->transact(BnCameraService::CONNECT, data, &reply); + + status_t status; + status = remote()->transact(BnCameraService::CONNECT, data, &reply); + if (status != OK) return status; if (readExceptionCode(reply)) return -EPROTO; - status_t status = reply.readInt32(); + status = reply.readInt32(); if (reply.readInt32() != 0) { device = interface_cast<ICamera>(reply.readStrongBinder()); } @@ -199,36 +201,31 @@ public: data.writeInt32(halVersion); data.writeString16(clientPackageName); data.writeInt32(clientUid); - remote()->transact(BnCameraService::CONNECT_LEGACY, data, &reply); + + status_t status; + status = remote()->transact(BnCameraService::CONNECT_LEGACY, data, &reply); + if (status != OK) return status; if (readExceptionCode(reply)) return -EPROTO; - status_t status = reply.readInt32(); + status = reply.readInt32(); if (reply.readInt32() != 0) { device = interface_cast<ICamera>(reply.readStrongBinder()); } return status; } - // connect to camera service (pro client) - virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId, - const String16 &clientPackageName, int clientUid, - /*out*/ - sp<IProCameraUser>& device) + virtual status_t setTorchMode(const String16& cameraId, bool enabled, + const sp<IBinder>& clientBinder) { Parcel data, reply; data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(cameraCb)); - data.writeInt32(cameraId); - data.writeString16(clientPackageName); - data.writeInt32(clientUid); - remote()->transact(BnCameraService::CONNECT_PRO, data, &reply); + data.writeString16(cameraId); + data.writeInt32(enabled ? 1 : 0); + data.writeStrongBinder(clientBinder); + remote()->transact(BnCameraService::SET_TORCH_MODE, data, &reply); if (readExceptionCode(reply)) return -EPROTO; - status_t status = reply.readInt32(); - if (reply.readInt32() != 0) { - device = interface_cast<IProCameraUser>(reply.readStrongBinder()); - } - return status; + return reply.readInt32(); } // connect to camera service (android.hardware.camera2.CameraDevice) @@ -246,10 +243,13 @@ public: data.writeInt32(cameraId); data.writeString16(clientPackageName); data.writeInt32(clientUid); - remote()->transact(BnCameraService::CONNECT_DEVICE, data, &reply); + + status_t status; + status = remote()->transact(BnCameraService::CONNECT_DEVICE, data, &reply); + if (status != OK) return status; if (readExceptionCode(reply)) return -EPROTO; - status_t status = reply.readInt32(); + status = reply.readInt32(); if (reply.readInt32() != 0) { device = interface_cast<ICameraDeviceUser>(reply.readStrongBinder()); } @@ -285,6 +285,7 @@ public: } Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeInt32(cameraId); remote()->transact(BnCameraService::GET_LEGACY_PARAMETERS, data, &reply); @@ -304,6 +305,7 @@ public: virtual status_t supportsCameraApi(int cameraId, int apiVersion) { Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeInt32(cameraId); data.writeInt32(apiVersion); remote()->transact(BnCameraService::SUPPORTS_CAMERA_API, data, &reply); @@ -312,6 +314,16 @@ public: status_t res = data.readInt32(); return res; } + + virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t len) { + Parcel data, reply; + data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); + data.writeInt32(eventId); + data.writeInt32Array(len, args); + remote()->transact(BnCameraService::NOTIFY_SYSTEM_EVENT, data, &reply, + IBinder::FLAG_ONEWAY); + } + }; IMPLEMENT_META_INTERFACE(CameraService, "android.hardware.ICameraService"); @@ -390,26 +402,6 @@ status_t BnCameraService::onTransact( } return NO_ERROR; } break; - case CONNECT_PRO: { - CHECK_INTERFACE(ICameraService, data, reply); - sp<IProCameraCallbacks> cameraClient = - interface_cast<IProCameraCallbacks>(data.readStrongBinder()); - int32_t cameraId = data.readInt32(); - const String16 clientName = data.readString16(); - int32_t clientUid = data.readInt32(); - sp<IProCameraUser> camera; - status_t status = connectPro(cameraClient, cameraId, - clientName, clientUid, /*out*/camera); - reply->writeNoException(); - reply->writeInt32(status); - if (camera != NULL) { - reply->writeInt32(1); - reply->writeStrongBinder(IInterface::asBinder(camera)); - } else { - reply->writeInt32(0); - } - return NO_ERROR; - } break; case CONNECT_DEVICE: { CHECK_INTERFACE(ICameraService, data, reply); sp<ICameraDeviceCallbacks> cameraClient = @@ -490,6 +482,41 @@ status_t BnCameraService::onTransact( } return NO_ERROR; } break; + case SET_TORCH_MODE: { + CHECK_INTERFACE(ICameraService, data, reply); + String16 cameraId = data.readString16(); + bool enabled = data.readInt32() != 0 ? true : false; + const sp<IBinder> clientBinder = data.readStrongBinder(); + status_t status = setTorchMode(cameraId, enabled, clientBinder); + reply->writeNoException(); + reply->writeInt32(status); + return NO_ERROR; + } break; + case NOTIFY_SYSTEM_EVENT: { + CHECK_INTERFACE(ICameraService, data, reply); + int32_t eventId = data.readInt32(); + int32_t len = data.readInt32(); + if (len < 0) { + ALOGE("%s: Received poorly formatted length in binder request: notifySystemEvent.", + __FUNCTION__); + return FAILED_TRANSACTION; + } + if (len > 512) { + ALOGE("%s: Length %" PRIi32 " too long in binder request: notifySystemEvent.", + __FUNCTION__, len); + return FAILED_TRANSACTION; + } + int32_t events[len]; + memset(events, 0, sizeof(int32_t) * len); + status_t status = data.read(events, sizeof(int32_t) * len); + if (status != NO_ERROR) { + ALOGE("%s: Received poorly formatted binder request: notifySystemEvent.", + __FUNCTION__); + return FAILED_TRANSACTION; + } + notifySystemEvent(eventId, events, len); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp index b2f1729..0010325 100644 --- a/camera/ICameraServiceListener.cpp +++ b/camera/ICameraServiceListener.cpp @@ -29,6 +29,7 @@ namespace android { namespace { enum { STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION, + TORCH_STATUS_CHANGED, }; }; // namespace anonymous @@ -44,8 +45,7 @@ public: virtual void onStatusChanged(Status status, int32_t cameraId) { Parcel data, reply; - data.writeInterfaceToken( - ICameraServiceListener::getInterfaceDescriptor()); + data.writeInterfaceToken(ICameraServiceListener::getInterfaceDescriptor()); data.writeInt32(static_cast<int32_t>(status)); data.writeInt32(cameraId); @@ -54,19 +54,29 @@ public: data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onTorchStatusChanged(TorchStatus status, const String16 &cameraId) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraServiceListener::getInterfaceDescriptor()); - reply.readExceptionCode(); + data.writeInt32(static_cast<int32_t>(status)); + data.writeString16(cameraId); + + remote()->transact(TORCH_STATUS_CHANGED, + data, + &reply, + IBinder::FLAG_ONEWAY); } }; -IMPLEMENT_META_INTERFACE(CameraServiceListener, - "android.hardware.ICameraServiceListener"); +IMPLEMENT_META_INTERFACE(CameraServiceListener, "android.hardware.ICameraServiceListener"); // ---------------------------------------------------------------------- -status_t BnCameraServiceListener::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ +status_t BnCameraServiceListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { switch(code) { case STATUS_CHANGED: { CHECK_INTERFACE(ICameraServiceListener, data, reply); @@ -75,7 +85,16 @@ status_t BnCameraServiceListener::onTransact( int32_t cameraId = data.readInt32(); onStatusChanged(status, cameraId); - reply->writeNoException(); + + return NO_ERROR; + } break; + case TORCH_STATUS_CHANGED: { + CHECK_INTERFACE(ICameraServiceListener, data, reply); + + TorchStatus status = static_cast<TorchStatus>(data.readInt32()); + String16 cameraId = data.readString16(); + + onTorchStatusChanged(status, cameraId); return NO_ERROR; } break; diff --git a/camera/ICameraServiceProxy.cpp b/camera/ICameraServiceProxy.cpp new file mode 100644 index 0000000..06a5afb --- /dev/null +++ b/camera/ICameraServiceProxy.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "BpCameraServiceProxy" + +#include <stdint.h> + +#include <binder/Parcel.h> + +#include <camera/ICameraServiceProxy.h> + +namespace android { + +class BpCameraServiceProxy: public BpInterface<ICameraServiceProxy> { +public: + BpCameraServiceProxy(const sp<IBinder>& impl) : BpInterface<ICameraServiceProxy>(impl) {} + + virtual void pingForUserUpdate() { + Parcel data, reply; + data.writeInterfaceToken(ICameraServiceProxy::getInterfaceDescriptor()); + remote()->transact(BnCameraServiceProxy::PING_FOR_USER_UPDATE, data, &reply, + IBinder::FLAG_ONEWAY); + } +}; + + +IMPLEMENT_META_INTERFACE(CameraServiceProxy, "android.hardware.ICameraServiceProxy"); + +status_t BnCameraServiceProxy::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + switch(code) { + case PING_FOR_USER_UPDATE: { + CHECK_INTERFACE(ICameraServiceProxy, data, reply); + pingForUserUpdate(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} +}; // namespace android + diff --git a/camera/IProCameraCallbacks.cpp b/camera/IProCameraCallbacks.cpp deleted file mode 100644 index bd3d420..0000000 --- a/camera/IProCameraCallbacks.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -** -** Copyright 2013, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "IProCameraCallbacks" -#include <utils/Log.h> -#include <stdint.h> -#include <sys/types.h> - -#include <binder/Parcel.h> -#include <gui/IGraphicBufferProducer.h> -#include <gui/Surface.h> -#include <utils/Mutex.h> - -#include <camera/IProCameraCallbacks.h> - -#include "camera/CameraMetadata.h" - -namespace android { - -enum { - NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION, - LOCK_STATUS_CHANGED, - RESULT_RECEIVED, -}; - -class BpProCameraCallbacks: public BpInterface<IProCameraCallbacks> -{ -public: - BpProCameraCallbacks(const sp<IBinder>& impl) - : BpInterface<IProCameraCallbacks>(impl) - { - } - - // generic callback from camera service to app - void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) - { - ALOGV("notifyCallback"); - Parcel data, reply; - data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); - data.writeInt32(msgType); - data.writeInt32(ext1); - data.writeInt32(ext2); - remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY); - } - - void onLockStatusChanged(LockStatus newLockStatus) { - ALOGV("onLockStatusChanged"); - Parcel data, reply; - data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); - data.writeInt32(newLockStatus); - remote()->transact(LOCK_STATUS_CHANGED, data, &reply, - IBinder::FLAG_ONEWAY); - } - - void onResultReceived(int32_t requestId, camera_metadata* result) { - ALOGV("onResultReceived"); - Parcel data, reply; - data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor()); - data.writeInt32(requestId); - CameraMetadata::writeToParcel(data, result); - remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY); - } -}; - -IMPLEMENT_META_INTERFACE(ProCameraCallbacks, - "android.hardware.IProCameraCallbacks"); - -// ---------------------------------------------------------------------- - -status_t BnProCameraCallbacks::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - ALOGV("onTransact - code = %d", code); - switch(code) { - case NOTIFY_CALLBACK: { - ALOGV("NOTIFY_CALLBACK"); - CHECK_INTERFACE(IProCameraCallbacks, data, reply); - int32_t msgType = data.readInt32(); - int32_t ext1 = data.readInt32(); - int32_t ext2 = data.readInt32(); - notifyCallback(msgType, ext1, ext2); - return NO_ERROR; - } break; - case LOCK_STATUS_CHANGED: { - ALOGV("LOCK_STATUS_CHANGED"); - CHECK_INTERFACE(IProCameraCallbacks, data, reply); - LockStatus newLockStatus - = static_cast<LockStatus>(data.readInt32()); - onLockStatusChanged(newLockStatus); - return NO_ERROR; - } break; - case RESULT_RECEIVED: { - ALOGV("RESULT_RECEIVED"); - CHECK_INTERFACE(IProCameraCallbacks, data, reply); - int32_t requestId = data.readInt32(); - camera_metadata_t *result = NULL; - CameraMetadata::readFromParcel(data, &result); - onResultReceived(requestId, result); - return NO_ERROR; - break; - } - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android - diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp deleted file mode 100644 index 9bd7597..0000000 --- a/camera/IProCameraUser.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* -** -** Copyright 2013, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "IProCameraUser" -#include <utils/Log.h> -#include <stdint.h> -#include <sys/types.h> -#include <binder/Parcel.h> -#include <camera/IProCameraUser.h> -#include <gui/IGraphicBufferProducer.h> -#include <gui/Surface.h> -#include "camera/CameraMetadata.h" - -namespace android { - -enum { - DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, - CONNECT, - EXCLUSIVE_TRY_LOCK, - EXCLUSIVE_LOCK, - EXCLUSIVE_UNLOCK, - HAS_EXCLUSIVE_LOCK, - SUBMIT_REQUEST, - CANCEL_REQUEST, - DELETE_STREAM, - CREATE_STREAM, - CREATE_DEFAULT_REQUEST, - GET_CAMERA_INFO, -}; - -class BpProCameraUser: public BpInterface<IProCameraUser> -{ -public: - BpProCameraUser(const sp<IBinder>& impl) - : BpInterface<IProCameraUser>(impl) - { - } - - // disconnect from camera service - void disconnect() - { - ALOGV("disconnect"); - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - remote()->transact(DISCONNECT, data, &reply); - reply.readExceptionCode(); - } - - virtual status_t connect(const sp<IProCameraCallbacks>& cameraClient) - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(cameraClient)); - remote()->transact(CONNECT, data, &reply); - return reply.readInt32(); - } - - /* Shared ProCameraUser */ - - virtual status_t exclusiveTryLock() - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - remote()->transact(EXCLUSIVE_TRY_LOCK, data, &reply); - return reply.readInt32(); - } - virtual status_t exclusiveLock() - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - remote()->transact(EXCLUSIVE_LOCK, data, &reply); - return reply.readInt32(); - } - - virtual status_t exclusiveUnlock() - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - remote()->transact(EXCLUSIVE_UNLOCK, data, &reply); - return reply.readInt32(); - } - - virtual bool hasExclusiveLock() - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - remote()->transact(HAS_EXCLUSIVE_LOCK, data, &reply); - return !!reply.readInt32(); - } - - virtual int submitRequest(camera_metadata_t* metadata, bool streaming) - { - - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - - // arg0+arg1 - CameraMetadata::writeToParcel(data, metadata); - - // arg2 = streaming (bool) - data.writeInt32(streaming); - - remote()->transact(SUBMIT_REQUEST, data, &reply); - return reply.readInt32(); - } - - virtual status_t cancelRequest(int requestId) - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - data.writeInt32(requestId); - - remote()->transact(CANCEL_REQUEST, data, &reply); - return reply.readInt32(); - } - - virtual status_t deleteStream(int streamId) - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - data.writeInt32(streamId); - - remote()->transact(DELETE_STREAM, data, &reply); - return reply.readInt32(); - } - - virtual status_t createStream(int width, int height, int format, - const sp<IGraphicBufferProducer>& bufferProducer, - /*out*/ - int* streamId) - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - data.writeInt32(width); - data.writeInt32(height); - data.writeInt32(format); - - sp<IBinder> b(IInterface::asBinder(bufferProducer)); - data.writeStrongBinder(b); - - remote()->transact(CREATE_STREAM, data, &reply); - - int sId = reply.readInt32(); - if (streamId) { - *streamId = sId; - } - return reply.readInt32(); - } - - // Create a request object from a template. - virtual status_t createDefaultRequest(int templateId, - /*out*/ - camera_metadata** request) - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - data.writeInt32(templateId); - remote()->transact(CREATE_DEFAULT_REQUEST, data, &reply); - CameraMetadata::readFromParcel(reply, /*out*/request); - return reply.readInt32(); - } - - - virtual status_t getCameraInfo(int cameraId, camera_metadata** info) - { - Parcel data, reply; - data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor()); - data.writeInt32(cameraId); - remote()->transact(GET_CAMERA_INFO, data, &reply); - CameraMetadata::readFromParcel(reply, /*out*/info); - return reply.readInt32(); - } - - -private: - - -}; - -IMPLEMENT_META_INTERFACE(ProCameraUser, "android.hardware.IProCameraUser"); - -// ---------------------------------------------------------------------- - -status_t BnProCameraUser::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case DISCONNECT: { - ALOGV("DISCONNECT"); - CHECK_INTERFACE(IProCameraUser, data, reply); - disconnect(); - reply->writeNoException(); - return NO_ERROR; - } break; - case CONNECT: { - CHECK_INTERFACE(IProCameraUser, data, reply); - sp<IProCameraCallbacks> cameraClient = - interface_cast<IProCameraCallbacks>(data.readStrongBinder()); - reply->writeInt32(connect(cameraClient)); - return NO_ERROR; - } break; - - /* Shared ProCameraUser */ - case EXCLUSIVE_TRY_LOCK: { - CHECK_INTERFACE(IProCameraUser, data, reply); - reply->writeInt32(exclusiveTryLock()); - return NO_ERROR; - } break; - case EXCLUSIVE_LOCK: { - CHECK_INTERFACE(IProCameraUser, data, reply); - reply->writeInt32(exclusiveLock()); - return NO_ERROR; - } break; - case EXCLUSIVE_UNLOCK: { - CHECK_INTERFACE(IProCameraUser, data, reply); - reply->writeInt32(exclusiveUnlock()); - return NO_ERROR; - } break; - case HAS_EXCLUSIVE_LOCK: { - CHECK_INTERFACE(IProCameraUser, data, reply); - reply->writeInt32(hasExclusiveLock()); - return NO_ERROR; - } break; - case SUBMIT_REQUEST: { - CHECK_INTERFACE(IProCameraUser, data, reply); - camera_metadata_t* metadata; - CameraMetadata::readFromParcel(data, /*out*/&metadata); - - // arg2 = streaming (bool) - bool streaming = data.readInt32(); - - // return code: requestId (int32) - reply->writeInt32(submitRequest(metadata, streaming)); - - return NO_ERROR; - } break; - case CANCEL_REQUEST: { - CHECK_INTERFACE(IProCameraUser, data, reply); - int requestId = data.readInt32(); - reply->writeInt32(cancelRequest(requestId)); - return NO_ERROR; - } break; - case DELETE_STREAM: { - CHECK_INTERFACE(IProCameraUser, data, reply); - int streamId = data.readInt32(); - reply->writeInt32(deleteStream(streamId)); - return NO_ERROR; - } break; - case CREATE_STREAM: { - CHECK_INTERFACE(IProCameraUser, data, reply); - int width, height, format; - - width = data.readInt32(); - height = data.readInt32(); - format = data.readInt32(); - - sp<IGraphicBufferProducer> bp = - interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); - - int streamId = -1; - status_t ret; - ret = createStream(width, height, format, bp, &streamId); - - reply->writeInt32(streamId); - reply->writeInt32(ret); - - return NO_ERROR; - } break; - - case CREATE_DEFAULT_REQUEST: { - CHECK_INTERFACE(IProCameraUser, data, reply); - - int templateId = data.readInt32(); - - camera_metadata_t* request = NULL; - status_t ret; - ret = createDefaultRequest(templateId, &request); - - CameraMetadata::writeToParcel(*reply, request); - reply->writeInt32(ret); - - free_camera_metadata(request); - - return NO_ERROR; - } break; - case GET_CAMERA_INFO: { - CHECK_INTERFACE(IProCameraUser, data, reply); - - int cameraId = data.readInt32(); - - camera_metadata_t* info = NULL; - status_t ret; - ret = getCameraInfo(cameraId, &info); - - CameraMetadata::writeToParcel(*reply, info); - reply->writeInt32(ret); - - free_camera_metadata(info); - - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp deleted file mode 100644 index 48f8e8e..0000000 --- a/camera/ProCamera.cpp +++ /dev/null @@ -1,436 +0,0 @@ -/* -** -** Copyright (C) 2013, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "ProCamera" -#include <utils/Log.h> -#include <utils/threads.h> -#include <utils/Mutex.h> - -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/IMemory.h> - -#include <camera/ProCamera.h> -#include <camera/IProCameraUser.h> -#include <camera/IProCameraCallbacks.h> - -#include <gui/IGraphicBufferProducer.h> - -#include <system/camera_metadata.h> - -namespace android { - -sp<ProCamera> ProCamera::connect(int cameraId) -{ - return CameraBaseT::connect(cameraId, String16(), - ICameraService::USE_CALLING_UID); -} - -ProCamera::ProCamera(int cameraId) - : CameraBase(cameraId) -{ -} - -CameraTraits<ProCamera>::TCamConnectService CameraTraits<ProCamera>::fnConnectService = - &ICameraService::connectPro; - -ProCamera::~ProCamera() -{ - -} - -/* IProCameraUser's implementation */ - -// callback from camera service -void ProCamera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) -{ - return CameraBaseT::notifyCallback(msgType, ext1, ext2); -} - -void ProCamera::onLockStatusChanged( - IProCameraCallbacks::LockStatus newLockStatus) -{ - ALOGV("%s: newLockStatus = %d", __FUNCTION__, newLockStatus); - - sp<ProCameraListener> listener; - { - Mutex::Autolock _l(mLock); - listener = mListener; - } - if (listener != NULL) { - switch (newLockStatus) { - case IProCameraCallbacks::LOCK_ACQUIRED: - listener->onLockAcquired(); - break; - case IProCameraCallbacks::LOCK_RELEASED: - listener->onLockReleased(); - break; - case IProCameraCallbacks::LOCK_STOLEN: - listener->onLockStolen(); - break; - default: - ALOGE("%s: Unknown lock status: %d", - __FUNCTION__, newLockStatus); - } - } -} - -void ProCamera::onResultReceived(int32_t requestId, camera_metadata* result) { - ALOGV("%s: requestId = %d, result = %p", __FUNCTION__, requestId, result); - - sp<ProCameraListener> listener; - { - Mutex::Autolock _l(mLock); - listener = mListener; - } - - CameraMetadata tmp(result); - - // Unblock waitForFrame(id) callers - { - Mutex::Autolock al(mWaitMutex); - mMetadataReady = true; - mLatestMetadata = tmp; // make copy - mWaitCondition.broadcast(); - } - - result = tmp.release(); - - if (listener != NULL) { - listener->onResultReceived(requestId, result); - } else { - free_camera_metadata(result); - } - -} - -status_t ProCamera::exclusiveTryLock() -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->exclusiveTryLock(); -} -status_t ProCamera::exclusiveLock() -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->exclusiveLock(); -} -status_t ProCamera::exclusiveUnlock() -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->exclusiveUnlock(); -} -bool ProCamera::hasExclusiveLock() -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->hasExclusiveLock(); -} - -// Note that the callee gets a copy of the metadata. -int ProCamera::submitRequest(const struct camera_metadata* metadata, - bool streaming) -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->submitRequest(const_cast<struct camera_metadata*>(metadata), - streaming); -} - -status_t ProCamera::cancelRequest(int requestId) -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->cancelRequest(requestId); -} - -status_t ProCamera::deleteStream(int streamId) -{ - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - status_t s = c->deleteStream(streamId); - - mStreams.removeItem(streamId); - - return s; -} - -status_t ProCamera::createStream(int width, int height, int format, - const sp<Surface>& surface, - /*out*/ - int* streamId) -{ - *streamId = -1; - - ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height, - format); - - if (surface == 0) { - return BAD_VALUE; - } - - return createStream(width, height, format, - surface->getIGraphicBufferProducer(), - streamId); -} - -status_t ProCamera::createStream(int width, int height, int format, - const sp<IGraphicBufferProducer>& bufferProducer, - /*out*/ - int* streamId) { - *streamId = -1; - - ALOGV("%s: createStreamT %dx%d (fmt=0x%x)", __FUNCTION__, width, height, - format); - - if (bufferProducer == 0) { - return BAD_VALUE; - } - - sp <IProCameraUser> c = mCamera; - status_t stat = c->createStream(width, height, format, bufferProducer, - streamId); - - if (stat == OK) { - StreamInfo s(*streamId); - - mStreams.add(*streamId, s); - } - - return stat; -} - -status_t ProCamera::createStreamCpu(int width, int height, int format, - int heapCount, - /*out*/ - sp<CpuConsumer>* cpuConsumer, - int* streamId) { - return createStreamCpu(width, height, format, heapCount, - /*synchronousMode*/true, - cpuConsumer, streamId); -} - -status_t ProCamera::createStreamCpu(int width, int height, int format, - int heapCount, - bool synchronousMode, - /*out*/ - sp<CpuConsumer>* cpuConsumer, - int* streamId) -{ - ALOGV("%s: createStreamW %dx%d (fmt=0x%x)", __FUNCTION__, width, height, - format); - - *cpuConsumer = NULL; - - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount - /*, synchronousMode*/); - cc->setName(String8("ProCamera::mCpuConsumer")); - - sp<Surface> stc = new Surface(producer); - - status_t s = createStream(width, height, format, - stc->getIGraphicBufferProducer(), - streamId); - - if (s != OK) { - ALOGE("%s: Failure to create stream %dx%d (fmt=0x%x)", __FUNCTION__, - width, height, format); - return s; - } - - sp<ProFrameListener> frameAvailableListener = - new ProFrameListener(this, *streamId); - - getStreamInfo(*streamId).cpuStream = true; - getStreamInfo(*streamId).cpuConsumer = cc; - getStreamInfo(*streamId).synchronousMode = synchronousMode; - getStreamInfo(*streamId).stc = stc; - // for lifetime management - getStreamInfo(*streamId).frameAvailableListener = frameAvailableListener; - - cc->setFrameAvailableListener(frameAvailableListener); - - *cpuConsumer = cc; - - return s; -} - -camera_metadata* ProCamera::getCameraInfo(int cameraId) { - ALOGV("%s: cameraId = %d", __FUNCTION__, cameraId); - - sp <IProCameraUser> c = mCamera; - if (c == 0) return NULL; - - camera_metadata* ptr = NULL; - status_t status = c->getCameraInfo(cameraId, &ptr); - - if (status != OK) { - ALOGE("%s: Failed to get camera info, error = %d", __FUNCTION__, status); - } - - return ptr; -} - -status_t ProCamera::createDefaultRequest(int templateId, - camera_metadata** request) const { - ALOGV("%s: templateId = %d", __FUNCTION__, templateId); - - sp <IProCameraUser> c = mCamera; - if (c == 0) return NO_INIT; - - return c->createDefaultRequest(templateId, request); -} - -void ProCamera::onFrameAvailable(int streamId) { - ALOGV("%s: streamId = %d", __FUNCTION__, streamId); - - sp<ProCameraListener> listener = mListener; - StreamInfo& stream = getStreamInfo(streamId); - - if (listener.get() != NULL) { - listener->onFrameAvailable(streamId, stream.cpuConsumer); - } - - // Unblock waitForFrame(id) callers - { - Mutex::Autolock al(mWaitMutex); - getStreamInfo(streamId).frameReady++; - mWaitCondition.broadcast(); - } -} - -int ProCamera::waitForFrameBuffer(int streamId) { - status_t stat = BAD_VALUE; - Mutex::Autolock al(mWaitMutex); - - StreamInfo& si = getStreamInfo(streamId); - - if (si.frameReady > 0) { - int numFrames = si.frameReady; - si.frameReady = 0; - return numFrames; - } else { - while (true) { - stat = mWaitCondition.waitRelative(mWaitMutex, - mWaitTimeout); - if (stat != OK) { - ALOGE("%s: Error while waiting for frame buffer: %d", - __FUNCTION__, stat); - return stat; - } - - if (si.frameReady > 0) { - int numFrames = si.frameReady; - si.frameReady = 0; - return numFrames; - } - // else it was some other stream that got unblocked - } - } - - return stat; -} - -int ProCamera::dropFrameBuffer(int streamId, int count) { - StreamInfo& si = getStreamInfo(streamId); - - if (!si.cpuStream) { - return BAD_VALUE; - } else if (count < 0) { - return BAD_VALUE; - } - - if (!si.synchronousMode) { - ALOGW("%s: No need to drop frames on asynchronous streams," - " as asynchronous mode only keeps 1 latest frame around.", - __FUNCTION__); - return BAD_VALUE; - } - - int numDropped = 0; - for (int i = 0; i < count; ++i) { - CpuConsumer::LockedBuffer buffer; - if (si.cpuConsumer->lockNextBuffer(&buffer) != OK) { - break; - } - - si.cpuConsumer->unlockBuffer(buffer); - numDropped++; - } - - return numDropped; -} - -status_t ProCamera::waitForFrameMetadata() { - status_t stat = BAD_VALUE; - Mutex::Autolock al(mWaitMutex); - - if (mMetadataReady) { - return OK; - } else { - while (true) { - stat = mWaitCondition.waitRelative(mWaitMutex, - mWaitTimeout); - - if (stat != OK) { - ALOGE("%s: Error while waiting for metadata: %d", - __FUNCTION__, stat); - return stat; - } - - if (mMetadataReady) { - mMetadataReady = false; - return OK; - } - // else it was some other stream or metadata - } - } - - return stat; -} - -CameraMetadata ProCamera::consumeFrameMetadata() { - Mutex::Autolock al(mWaitMutex); - - // Destructive: Subsequent calls return empty metadatas - CameraMetadata tmp = mLatestMetadata; - mLatestMetadata.clear(); - - return tmp; -} - -ProCamera::StreamInfo& ProCamera::getStreamInfo(int streamId) { - return mStreams.editValueFor(streamId); -} - -}; // namespace android diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp index 66d6913..4217bc6 100644 --- a/camera/camera2/CaptureRequest.cpp +++ b/camera/camera2/CaptureRequest.cpp @@ -81,6 +81,13 @@ status_t CaptureRequest::readFromParcel(Parcel* parcel) { mSurfaceList.push_back(surface); } + int isReprocess = 0; + if ((err = parcel->readInt32(&isReprocess)) != OK) { + ALOGE("%s: Failed to read reprocessing from parcel", __FUNCTION__); + return err; + } + mIsReprocess = (isReprocess != 0); + return OK; } @@ -118,6 +125,8 @@ status_t CaptureRequest::writeToParcel(Parcel* parcel) const { parcel->writeStrongBinder(binder); } + parcel->writeInt32(mIsReprocess ? 1 : 0); + return OK; } diff --git a/camera/camera2/ICameraDeviceCallbacks.cpp b/camera/camera2/ICameraDeviceCallbacks.cpp index 4cc7b5d..f599879 100644 --- a/camera/camera2/ICameraDeviceCallbacks.cpp +++ b/camera/camera2/ICameraDeviceCallbacks.cpp @@ -37,6 +37,7 @@ enum { CAMERA_IDLE, CAPTURE_STARTED, RESULT_RECEIVED, + PREPARED }; class BpCameraDeviceCallbacks: public BpInterface<ICameraDeviceCallbacks> @@ -80,7 +81,6 @@ public: data.writeNoException(); } - void onResultReceived(const CameraMetadata& metadata, const CaptureResultExtras& resultExtras) { ALOGV("onResultReceived"); @@ -93,6 +93,17 @@ public: remote()->transact(RESULT_RECEIVED, data, &reply, IBinder::FLAG_ONEWAY); data.writeNoException(); } + + void onPrepared(int streamId) + { + ALOGV("onPrepared"); + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceCallbacks::getInterfaceDescriptor()); + data.writeInt32(streamId); + remote()->transact(PREPARED, data, &reply, IBinder::FLAG_ONEWAY); + data.writeNoException(); + } + }; IMPLEMENT_META_INTERFACE(CameraDeviceCallbacks, @@ -160,6 +171,15 @@ status_t BnCameraDeviceCallbacks::onTransact( data.readExceptionCode(); return NO_ERROR; } break; + case PREPARED: { + ALOGV("onPrepared"); + CHECK_INTERFACE(ICameraDeviceCallbacks, data, reply); + CaptureResultExtras result; + int streamId = data.readInt32(); + onPrepared(streamId); + data.readExceptionCode(); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/camera2/ICameraDeviceUser.cpp b/camera/camera2/ICameraDeviceUser.cpp index 277b5db..d2dc200 100644 --- a/camera/camera2/ICameraDeviceUser.cpp +++ b/camera/camera2/ICameraDeviceUser.cpp @@ -26,6 +26,7 @@ #include <gui/Surface.h> #include <camera/CameraMetadata.h> #include <camera/camera2/CaptureRequest.h> +#include <camera/camera2/OutputConfiguration.h> namespace android { @@ -41,10 +42,14 @@ enum { END_CONFIGURE, DELETE_STREAM, CREATE_STREAM, + CREATE_INPUT_STREAM, + GET_INPUT_SURFACE, CREATE_DEFAULT_REQUEST, GET_CAMERA_INFO, WAIT_UNTIL_IDLE, - FLUSH + FLUSH, + PREPARE, + TEAR_DOWN }; namespace { @@ -78,7 +83,7 @@ public: reply.readExceptionCode(); } - virtual status_t submitRequest(sp<CaptureRequest> request, bool repeating, + virtual int submitRequest(sp<CaptureRequest> request, bool repeating, int64_t *lastFrameNumber) { Parcel data, reply; @@ -107,13 +112,13 @@ public: } } - if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) { + if (res < 0 || (resFrameNumber != NO_ERROR)) { res = FAILED_TRANSACTION; } return res; } - virtual status_t submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating, + virtual int submitRequestList(List<sp<CaptureRequest> > requestList, bool repeating, int64_t *lastFrameNumber) { Parcel data, reply; @@ -147,7 +152,7 @@ public: resFrameNumber = reply.readInt64(lastFrameNumber); } } - if ((res < NO_ERROR) || (resFrameNumber != NO_ERROR)) { + if (res < 0 || (resFrameNumber != NO_ERROR)) { res = FAILED_TRANSACTION; } return res; @@ -186,11 +191,13 @@ public: return reply.readInt32(); } - virtual status_t endConfigure() + virtual status_t endConfigure(bool isConstrainedHighSpeed) { ALOGV("endConfigure"); Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + data.writeInt32(isConstrainedHighSpeed); + remote()->transact(END_CONFIGURE, data, &reply); reply.readExceptionCode(); return reply.readInt32(); @@ -208,8 +215,23 @@ public: return reply.readInt32(); } - virtual status_t createStream(int width, int height, int format, - const sp<IGraphicBufferProducer>& bufferProducer) + virtual status_t createStream(const OutputConfiguration& outputConfiguration) + { + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + if (outputConfiguration.getGraphicBufferProducer() != NULL) { + data.writeInt32(1); // marker that OutputConfiguration is not null. Mimic aidl behavior + outputConfiguration.writeToParcel(data); + } else { + data.writeInt32(0); + } + remote()->transact(CREATE_STREAM, data, &reply); + + reply.readExceptionCode(); + return reply.readInt32(); + } + + virtual status_t createInputStream(int width, int height, int format) { Parcel data, reply; data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); @@ -217,17 +239,42 @@ public: data.writeInt32(height); data.writeInt32(format); - data.writeInt32(1); // marker that bufferProducer is not null - data.writeString16(String16("unknown_name")); // name of surface - sp<IBinder> b(IInterface::asBinder(bufferProducer)); - data.writeStrongBinder(b); - - remote()->transact(CREATE_STREAM, data, &reply); + remote()->transact(CREATE_INPUT_STREAM, data, &reply); reply.readExceptionCode(); return reply.readInt32(); } + // get the buffer producer of the input stream + virtual status_t getInputBufferProducer( + sp<IGraphicBufferProducer> *producer) { + if (producer == NULL) { + return BAD_VALUE; + } + + Parcel data, reply; + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + + remote()->transact(GET_INPUT_SURFACE, data, &reply); + + reply.readExceptionCode(); + status_t result = reply.readInt32() ; + if (result != OK) { + return result; + } + + sp<IGraphicBufferProducer> bp = NULL; + if (reply.readInt32() != 0) { + String16 name = readMaybeEmptyString16(reply); + bp = interface_cast<IGraphicBufferProducer>( + reply.readStrongBinder()); + } + + *producer = bp; + + return *producer == NULL ? INVALID_OPERATION : OK; + } + // Create a request object from a template. virtual status_t createDefaultRequest(int templateId, /*out*/ @@ -305,6 +352,34 @@ public: return res; } + virtual status_t prepare(int streamId) + { + ALOGV("prepare"); + Parcel data, reply; + + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + data.writeInt32(streamId); + + remote()->transact(PREPARE, data, &reply); + + reply.readExceptionCode(); + return reply.readInt32(); + } + + virtual status_t tearDown(int streamId) + { + ALOGV("tearDown"); + Parcel data, reply; + + data.writeInterfaceToken(ICameraDeviceUser::getInterfaceDescriptor()); + data.writeInt32(streamId); + + remote()->transact(TEAR_DOWN, data, &reply); + + reply.readExceptionCode(); + return reply.readInt32(); + } + private: @@ -396,39 +471,51 @@ status_t BnCameraDeviceUser::onTransact( } break; case CREATE_STREAM: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); + + status_t ret = BAD_VALUE; + if (data.readInt32() != 0) { + OutputConfiguration outputConfiguration(data); + ret = createStream(outputConfiguration); + } else { + ALOGE("%s: cannot take an empty OutputConfiguration", __FUNCTION__); + } + + reply->writeNoException(); + ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__); + reply->writeInt32(ret); + ALOGV("%s: CREATE_STREAM: write ret = %d", __FUNCTION__, ret); + + return NO_ERROR; + } break; + case CREATE_INPUT_STREAM: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); int width, height, format; width = data.readInt32(); - ALOGV("%s: CREATE_STREAM: width = %d", __FUNCTION__, width); height = data.readInt32(); - ALOGV("%s: CREATE_STREAM: height = %d", __FUNCTION__, height); format = data.readInt32(); - ALOGV("%s: CREATE_STREAM: format = %d", __FUNCTION__, format); + status_t ret = createInputStream(width, height, format); - sp<IGraphicBufferProducer> bp; - if (data.readInt32() != 0) { - String16 name = readMaybeEmptyString16(data); - bp = interface_cast<IGraphicBufferProducer>( - data.readStrongBinder()); + reply->writeNoException(); + reply->writeInt32(ret); + return NO_ERROR; - ALOGV("%s: CREATE_STREAM: bp = %p, name = %s", __FUNCTION__, - bp.get(), String8(name).string()); - } else { - ALOGV("%s: CREATE_STREAM: bp = unset, name = unset", - __FUNCTION__); - } + } break; + case GET_INPUT_SURFACE: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); - status_t ret; - ret = createStream(width, height, format, bp); + sp<IGraphicBufferProducer> bp; + status_t ret = getInputBufferProducer(&bp); + sp<IBinder> b(IInterface::asBinder(ret == OK ? bp : NULL)); reply->writeNoException(); - ALOGV("%s: CREATE_STREAM: write noException", __FUNCTION__); reply->writeInt32(ret); - ALOGV("%s: CREATE_STREAM: write ret = %d", __FUNCTION__, ret); + reply->writeInt32(1); + reply->writeString16(String16("camera input")); // name of surface + reply->writeStrongBinder(b); return NO_ERROR; } break; - case CREATE_DEFAULT_REQUEST: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); @@ -486,10 +573,26 @@ status_t BnCameraDeviceUser::onTransact( } break; case END_CONFIGURE: { CHECK_INTERFACE(ICameraDeviceUser, data, reply); + bool isConstrainedHighSpeed = data.readInt32(); reply->writeNoException(); - reply->writeInt32(endConfigure()); + reply->writeInt32(endConfigure(isConstrainedHighSpeed)); return NO_ERROR; } break; + case PREPARE: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + int streamId = data.readInt32(); + reply->writeNoException(); + reply->writeInt32(prepare(streamId)); + return NO_ERROR; + } break; + case TEAR_DOWN: { + CHECK_INTERFACE(ICameraDeviceUser, data, reply); + int streamId = data.readInt32(); + reply->writeNoException(); + reply->writeInt32(tearDown(streamId)); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp new file mode 100644 index 0000000..20a23e0 --- /dev/null +++ b/camera/camera2/OutputConfiguration.cpp @@ -0,0 +1,84 @@ +/* +** +** Copyright 2015, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "OutputConfiguration" +#include <utils/Log.h> + +#include <camera/camera2/OutputConfiguration.h> +#include <binder/Parcel.h> + +namespace android { + + +const int OutputConfiguration::INVALID_ROTATION = -1; + +// Read empty strings without printing a false error message. +String16 OutputConfiguration::readMaybeEmptyString16(const Parcel& parcel) { + size_t len; + const char16_t* str = parcel.readString16Inplace(&len); + if (str != NULL) { + return String16(str, len); + } else { + return String16(); + } +} + +sp<IGraphicBufferProducer> OutputConfiguration::getGraphicBufferProducer() const { + return mGbp; +} + +int OutputConfiguration::getRotation() const { + return mRotation; +} + +OutputConfiguration::OutputConfiguration(const Parcel& parcel) { + status_t err; + int rotation = 0; + if ((err = parcel.readInt32(&rotation)) != OK) { + ALOGE("%s: Failed to read rotation from parcel", __FUNCTION__); + mGbp = NULL; + mRotation = INVALID_ROTATION; + return; + } + + String16 name = readMaybeEmptyString16(parcel); + const sp<IGraphicBufferProducer>& gbp = + interface_cast<IGraphicBufferProducer>(parcel.readStrongBinder()); + mGbp = gbp; + mRotation = rotation; + + ALOGV("%s: OutputConfiguration: bp = %p, name = %s", __FUNCTION__, + gbp.get(), String8(name).string()); +} + +OutputConfiguration::OutputConfiguration(sp<IGraphicBufferProducer>& gbp, int rotation) { + mGbp = gbp; + mRotation = rotation; +} + +status_t OutputConfiguration::writeToParcel(Parcel& parcel) const { + + parcel.writeInt32(mRotation); + parcel.writeString16(String16("unknown_name")); // name of surface + sp<IBinder> b(IInterface::asBinder(mGbp)); + parcel.writeStrongBinder(b); + + return OK; +} + +}; // namespace android + diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk index 2db4c14..3777d94 100644 --- a/camera/tests/Android.mk +++ b/camera/tests/Android.mk @@ -17,8 +17,8 @@ include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_SRC_FILES:= \ - ProCameraTests.cpp \ - VendorTagDescriptorTests.cpp + VendorTagDescriptorTests.cpp \ + CameraBinderTests.cpp LOCAL_SHARED_LIBRARIES := \ libutils \ diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp new file mode 100644 index 0000000..572fb72 --- /dev/null +++ b/camera/tests/CameraBinderTests.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "CameraBinderTests" + +#include <binder/IInterface.h> +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/List.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <system/graphics.h> +#include <hardware/gralloc.h> + +#include <camera/CameraMetadata.h> +#include <camera/ICameraService.h> +#include <camera/ICameraServiceListener.h> +#include <camera/camera2/CaptureRequest.h> +#include <camera/camera2/ICameraDeviceUser.h> +#include <camera/camera2/ICameraDeviceCallbacks.h> +#include <camera/camera2/OutputConfiguration.h> + +#include <gui/BufferItemConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> + +#include <gtest/gtest.h> +#include <unistd.h> +#include <stdint.h> +#include <utility> +#include <vector> +#include <map> +#include <algorithm> + +using namespace android; + +#define ASSERT_NOT_NULL(x) \ + ASSERT_TRUE((x) != nullptr) + +#define SETUP_TIMEOUT 2000000000 // ns +#define IDLE_TIMEOUT 2000000000 // ns + +// Stub listener implementation +class TestCameraServiceListener : public BnCameraServiceListener { + std::map<String16, TorchStatus> mCameraTorchStatuses; + std::map<int32_t, Status> mCameraStatuses; + mutable Mutex mLock; + mutable Condition mCondition; + mutable Condition mTorchCondition; +public: + virtual ~TestCameraServiceListener() {}; + + virtual void onStatusChanged(Status status, int32_t cameraId) { + Mutex::Autolock l(mLock); + mCameraStatuses[cameraId] = status; + mCondition.broadcast(); + }; + + virtual void onTorchStatusChanged(TorchStatus status, const String16& cameraId) { + Mutex::Autolock l(mLock); + mCameraTorchStatuses[cameraId] = status; + mTorchCondition.broadcast(); + }; + + bool waitForNumCameras(size_t num) const { + Mutex::Autolock l(mLock); + + if (mCameraStatuses.size() == num) { + return true; + } + + while (mCameraStatuses.size() < num) { + if (mCondition.waitRelative(mLock, SETUP_TIMEOUT) != OK) { + return false; + } + } + return true; + }; + + bool waitForTorchState(TorchStatus status, int32_t cameraId) const { + Mutex::Autolock l(mLock); + + const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); + if (iter != mCameraTorchStatuses.end() && iter->second == status) { + return true; + } + + bool foundStatus = false; + while (!foundStatus) { + if (mTorchCondition.waitRelative(mLock, SETUP_TIMEOUT) != OK) { + return false; + } + const auto& iter = + mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); + foundStatus = (iter != mCameraTorchStatuses.end() && iter->second == status); + } + return true; + }; + + TorchStatus getTorchStatus(int32_t cameraId) const { + Mutex::Autolock l(mLock); + const auto& iter = mCameraTorchStatuses.find(String16(String8::format("%d", cameraId))); + if (iter == mCameraTorchStatuses.end()) { + return ICameraServiceListener::TORCH_STATUS_UNKNOWN; + } + return iter->second; + }; + + Status getStatus(int32_t cameraId) const { + Mutex::Autolock l(mLock); + const auto& iter = mCameraStatuses.find(cameraId); + if (iter == mCameraStatuses.end()) { + return ICameraServiceListener::STATUS_UNKNOWN; + } + return iter->second; + }; +}; + +// Callback implementation +class TestCameraDeviceCallbacks : public BnCameraDeviceCallbacks { +public: + enum Status { + IDLE, + ERROR, + PREPARED, + RUNNING, + SENT_RESULT, + UNINITIALIZED + }; + +protected: + bool mError; + Status mLastStatus; + mutable std::vector<Status> mStatusesHit; + mutable Mutex mLock; + mutable Condition mStatusCondition; +public: + TestCameraDeviceCallbacks() : mError(false), mLastStatus(UNINITIALIZED) {} + + virtual ~TestCameraDeviceCallbacks() {} + + virtual void onDeviceError(CameraErrorCode errorCode, + const CaptureResultExtras& resultExtras) { + ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode)); + Mutex::Autolock l(mLock); + mError = true; + mLastStatus = ERROR; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + virtual void onDeviceIdle() { + Mutex::Autolock l(mLock); + mLastStatus = IDLE; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + virtual void onCaptureStarted(const CaptureResultExtras& resultExtras, + int64_t timestamp) { + Mutex::Autolock l(mLock); + mLastStatus = RUNNING; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + + virtual void onResultReceived(const CameraMetadata& metadata, + const CaptureResultExtras& resultExtras) { + Mutex::Autolock l(mLock); + mLastStatus = SENT_RESULT; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + virtual void onPrepared(int streamId) { + Mutex::Autolock l(mLock); + mLastStatus = PREPARED; + mStatusesHit.push_back(mLastStatus); + mStatusCondition.broadcast(); + } + + // Test helper functions: + + bool hadError() const { + Mutex::Autolock l(mLock); + return mError; + } + + bool waitForStatus(Status status) const { + Mutex::Autolock l(mLock); + if (mLastStatus == status) { + return true; + } + + while (std::find(mStatusesHit.begin(), mStatusesHit.end(), status) + == mStatusesHit.end()) { + + if (mStatusCondition.waitRelative(mLock, IDLE_TIMEOUT) != OK) { + mStatusesHit.clear(); + return false; + } + } + mStatusesHit.clear(); + + return true; + + } + + void clearStatus() const { + Mutex::Autolock l(mLock); + mStatusesHit.clear(); + } + + bool waitForIdle() const { + return waitForStatus(IDLE); + } + +}; + +// Exercise basic binder calls for the camera service +TEST(CameraServiceBinderTest, CheckBinderCameraService) { + ProcessState::self()->startThreadPool(); + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.camera")); + ASSERT_NOT_NULL(binder); + sp<ICameraService> service = interface_cast<ICameraService>(binder); + + + int32_t numCameras = service->getNumberOfCameras(); + EXPECT_LE(0, numCameras); + + // Check listener binder calls + sp<TestCameraServiceListener> listener(new TestCameraServiceListener()); + EXPECT_EQ(OK, service->addListener(listener)); + + EXPECT_TRUE(listener->waitForNumCameras(numCameras)); + + for (int32_t i = 0; i < numCameras; i++) { + // We only care about binder calls for the Camera2 API. Camera1 is deprecated. + status_t camera2Support = service->supportsCameraApi(i, ICameraService::API_VERSION_2); + if (camera2Support != OK) { + EXPECT_EQ(-EOPNOTSUPP, camera2Support); + continue; + } + + // Check metadata binder call + CameraMetadata metadata; + EXPECT_EQ(OK, service->getCameraCharacteristics(i, &metadata)); + EXPECT_FALSE(metadata.isEmpty()); + + // Make sure we're available, or skip device tests otherwise + ICameraServiceListener::Status s = listener->getStatus(i); + EXPECT_EQ(ICameraServiceListener::STATUS_AVAILABLE, s); + if (s != ICameraServiceListener::STATUS_AVAILABLE) { + continue; + } + + // Check connect binder calls + sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks()); + sp<ICameraDeviceUser> device; + EXPECT_EQ(OK, service->connectDevice(callbacks, i, String16("meeeeeeeee!"), + ICameraService::USE_CALLING_UID, /*out*/device)); + ASSERT_NE(nullptr, device.get()); + device->disconnect(); + EXPECT_FALSE(callbacks->hadError()); + + ICameraServiceListener::TorchStatus torchStatus = listener->getTorchStatus(i); + if (torchStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF) { + // Check torch calls + EXPECT_EQ(OK, service->setTorchMode(String16(String8::format("%d", i)), + /*enabled*/true, callbacks)); + EXPECT_TRUE(listener->waitForTorchState( + ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON, i)); + EXPECT_EQ(OK, service->setTorchMode(String16(String8::format("%d", i)), + /*enabled*/false, callbacks)); + EXPECT_TRUE(listener->waitForTorchState( + ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF, i)); + } + } + + EXPECT_EQ(OK, service->removeListener(listener)); +} + +// Test fixture for client focused binder tests +class CameraClientBinderTest : public testing::Test { +protected: + sp<ICameraService> service; + int32_t numCameras; + std::vector<std::pair<sp<TestCameraDeviceCallbacks>, sp<ICameraDeviceUser>>> openDeviceList; + sp<TestCameraServiceListener> serviceListener; + + std::pair<sp<TestCameraDeviceCallbacks>, sp<ICameraDeviceUser>> openNewDevice(int deviceId) { + + sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks()); + sp<ICameraDeviceUser> device; + { + SCOPED_TRACE("openNewDevice"); + EXPECT_EQ(OK, service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"), + ICameraService::USE_CALLING_UID, /*out*/device)); + } + auto p = std::make_pair(callbacks, device); + openDeviceList.push_back(p); + return p; + } + + void closeDevice(std::pair<sp<TestCameraDeviceCallbacks>, sp<ICameraDeviceUser>>& p) { + if (p.second.get() != nullptr) { + p.second->disconnect(); + { + SCOPED_TRACE("closeDevice"); + EXPECT_FALSE(p.first->hadError()); + } + } + auto iter = std::find(openDeviceList.begin(), openDeviceList.end(), p); + if (iter != openDeviceList.end()) { + openDeviceList.erase(iter); + } + } + + virtual void SetUp() { + ProcessState::self()->startThreadPool(); + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.camera")); + service = interface_cast<ICameraService>(binder); + serviceListener = new TestCameraServiceListener(); + service->addListener(serviceListener); + numCameras = service->getNumberOfCameras(); + } + + virtual void TearDown() { + service = nullptr; + numCameras = 0; + for (auto& p : openDeviceList) { + closeDevice(p); + } + } + +}; + +TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) { + ASSERT_NOT_NULL(service); + + EXPECT_TRUE(serviceListener->waitForNumCameras(numCameras)); + for (int32_t i = 0; i < numCameras; i++) { + // Make sure we're available, or skip device tests otherwise + ICameraServiceListener::Status s = serviceListener->getStatus(i); + EXPECT_EQ(ICameraServiceListener::STATUS_AVAILABLE, s); + if (s != ICameraServiceListener::STATUS_AVAILABLE) { + continue; + } + + auto p = openNewDevice(i); + sp<TestCameraDeviceCallbacks> callbacks = p.first; + sp<ICameraDeviceUser> device = p.second; + + // Setup a buffer queue; I'm just using the vendor opaque format here as that is + // guaranteed to be present + sp<IGraphicBufferProducer> gbProducer; + sp<IGraphicBufferConsumer> gbConsumer; + BufferQueue::createBufferQueue(&gbProducer, &gbConsumer); + sp<BufferItemConsumer> opaqueConsumer = new BufferItemConsumer(gbConsumer, + GRALLOC_USAGE_SW_READ_NEVER, /*maxImages*/2, /*controlledByApp*/true); + EXPECT_TRUE(opaqueConsumer.get() != nullptr); + opaqueConsumer->setName(String8("nom nom nom")); + + // Set to VGA dimens for default, as that is guaranteed to be present + EXPECT_EQ(OK, gbConsumer->setDefaultBufferSize(640, 480)); + EXPECT_EQ(OK, gbConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)); + + sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false)); + + OutputConfiguration output(gbProducer, /*rotation*/0); + + // Can we configure? + EXPECT_EQ(OK, device->beginConfigure()); + status_t streamId = device->createStream(output); + EXPECT_LE(0, streamId); + EXPECT_EQ(OK, device->endConfigure()); + EXPECT_FALSE(callbacks->hadError()); + + // Can we make requests? + CameraMetadata requestTemplate; + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate)); + sp<CaptureRequest> request(new CaptureRequest()); + request->mMetadata = requestTemplate; + request->mSurfaceList.add(surface); + request->mIsReprocess = false; + int64_t lastFrameNumber = 0; + int64_t lastFrameNumberPrev = 0; + callbacks->clearStatus(); + int requestId = device->submitRequest(request, /*streaming*/true, /*out*/&lastFrameNumber); + EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); + EXPECT_LE(0, requestId); + + // Can we stop requests? + EXPECT_EQ(OK, device->cancelRequest(requestId, /*out*/&lastFrameNumber)); + EXPECT_TRUE(callbacks->waitForIdle()); + EXPECT_FALSE(callbacks->hadError()); + + // Can we do it again? + lastFrameNumberPrev = lastFrameNumber; + lastFrameNumber = 0; + requestTemplate.clear(); + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate)); + sp<CaptureRequest> request2(new CaptureRequest()); + request2->mMetadata = requestTemplate; + request2->mSurfaceList.add(surface); + request2->mIsReprocess = false; + callbacks->clearStatus(); + int requestId2 = device->submitRequest(request2, /*streaming*/true, + /*out*/&lastFrameNumber); + EXPECT_EQ(-1, lastFrameNumber); + lastFrameNumber = 0; + EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); + EXPECT_LE(0, requestId2); + EXPECT_EQ(OK, device->cancelRequest(requestId2, /*out*/&lastFrameNumber)); + EXPECT_TRUE(callbacks->waitForIdle()); + EXPECT_LE(lastFrameNumberPrev, lastFrameNumber); + sleep(/*second*/1); // allow some time for errors to show up, if any + EXPECT_FALSE(callbacks->hadError()); + + // Can we do it with a request list? + lastFrameNumberPrev = lastFrameNumber; + lastFrameNumber = 0; + requestTemplate.clear(); + CameraMetadata requestTemplate2; + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate)); + EXPECT_EQ(OK, device->createDefaultRequest(/*preview template*/1, + /*out*/&requestTemplate2)); + sp<CaptureRequest> request3(new CaptureRequest()); + sp<CaptureRequest> request4(new CaptureRequest()); + request3->mMetadata = requestTemplate; + request3->mSurfaceList.add(surface); + request3->mIsReprocess = false; + request4->mMetadata = requestTemplate2; + request4->mSurfaceList.add(surface); + request4->mIsReprocess = false; + List<sp<CaptureRequest>> requestList; + requestList.push_back(request3); + requestList.push_back(request4); + + callbacks->clearStatus(); + int requestId3 = device->submitRequestList(requestList, /*streaming*/false, + /*out*/&lastFrameNumber); + EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT)); + EXPECT_TRUE(callbacks->waitForIdle()); + EXPECT_LE(lastFrameNumberPrev, lastFrameNumber); + sleep(/*second*/1); // allow some time for errors to show up, if any + EXPECT_FALSE(callbacks->hadError()); + + // Can we unconfigure? + EXPECT_EQ(OK, device->beginConfigure()); + EXPECT_EQ(OK, device->deleteStream(streamId)); + EXPECT_EQ(OK, device->endConfigure()); + sleep(/*second*/1); // allow some time for errors to show up, if any + EXPECT_FALSE(callbacks->hadError()); + + closeDevice(p); + } + +}; diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp deleted file mode 100644 index 1f5867a..0000000 --- a/camera/tests/ProCameraTests.cpp +++ /dev/null @@ -1,1278 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <gtest/gtest.h> -#include <iostream> - -#include <binder/IPCThreadState.h> -#include <utils/Thread.h> - -#include "Camera.h" -#include "ProCamera.h" -#include <utils/Vector.h> -#include <utils/Mutex.h> -#include <utils/Condition.h> - -#include <gui/SurfaceComposerClient.h> -#include <gui/Surface.h> - -#include <system/camera_metadata.h> -#include <hardware/camera2.h> // for CAMERA2_TEMPLATE_PREVIEW only -#include <camera/CameraMetadata.h> - -#include <camera/ICameraServiceListener.h> - -namespace android { -namespace camera2 { -namespace tests { -namespace client { - -#define CAMERA_ID 0 -#define TEST_DEBUGGING 0 - -#define TEST_LISTENER_TIMEOUT 1000000000 // 1 second listener timeout -#define TEST_FORMAT HAL_PIXEL_FORMAT_Y16 //TODO: YUY2 instead - -#define TEST_FORMAT_MAIN HAL_PIXEL_FORMAT_Y8 -#define TEST_FORMAT_DEPTH HAL_PIXEL_FORMAT_Y16 - -// defaults for display "test" -#define TEST_DISPLAY_FORMAT HAL_PIXEL_FORMAT_Y8 -#define TEST_DISPLAY_WIDTH 320 -#define TEST_DISPLAY_HEIGHT 240 - -#define TEST_CPU_FRAME_COUNT 2 -#define TEST_CPU_HEAP_COUNT 5 - -#define TEST_FRAME_PROCESSING_DELAY_US 200000 // 200 ms - -#if TEST_DEBUGGING -#define dout std::cerr -#else -#define dout if (0) std::cerr -#endif - -#define EXPECT_OK(x) EXPECT_EQ(OK, (x)) -#define ASSERT_OK(x) ASSERT_EQ(OK, (x)) - -class ProCameraTest; - -struct ServiceListener : public BnCameraServiceListener { - - ServiceListener() : - mLatestStatus(STATUS_UNKNOWN), - mPrevStatus(STATUS_UNKNOWN) - { - } - - void onStatusChanged(Status status, int32_t cameraId) { - dout << "On status changed: 0x" << std::hex - << (unsigned int) status << " cameraId " << cameraId - << std::endl; - - Mutex::Autolock al(mMutex); - - mLatestStatus = status; - mCondition.broadcast(); - } - - status_t waitForStatusChange(Status& newStatus) { - Mutex::Autolock al(mMutex); - - if (mLatestStatus != mPrevStatus) { - newStatus = mLatestStatus; - mPrevStatus = mLatestStatus; - return OK; - } - - status_t stat = mCondition.waitRelative(mMutex, - TEST_LISTENER_TIMEOUT); - - if (stat == OK) { - newStatus = mLatestStatus; - mPrevStatus = mLatestStatus; - } - - return stat; - } - - Condition mCondition; - Mutex mMutex; - - Status mLatestStatus; - Status mPrevStatus; -}; - -enum ProEvent { - UNKNOWN, - ACQUIRED, - RELEASED, - STOLEN, - FRAME_RECEIVED, - RESULT_RECEIVED, -}; - -inline int ProEvent_Mask(ProEvent e) { - return (1 << static_cast<int>(e)); -} - -typedef Vector<ProEvent> EventList; - -class ProCameraTestThread : public Thread -{ -public: - ProCameraTestThread() { - } - - virtual bool threadLoop() { - mProc = ProcessState::self(); - mProc->startThreadPool(); - - IPCThreadState *ptr = IPCThreadState::self(); - - ptr->joinThreadPool(); - - return false; - } - - sp<ProcessState> mProc; -}; - -class ProCameraTestListener : public ProCameraListener { - -public: - static const int EVENT_MASK_ALL = 0xFFFFFFFF; - - ProCameraTestListener() { - mEventMask = EVENT_MASK_ALL; - mDropFrames = false; - } - - status_t WaitForEvent() { - Mutex::Autolock cal(mConditionMutex); - - { - Mutex::Autolock al(mListenerMutex); - - if (mProEventList.size() > 0) { - return OK; - } - } - - return mListenerCondition.waitRelative(mConditionMutex, - TEST_LISTENER_TIMEOUT); - } - - /* Read events into out. Existing queue is flushed */ - void ReadEvents(EventList& out) { - Mutex::Autolock al(mListenerMutex); - - for (size_t i = 0; i < mProEventList.size(); ++i) { - out.push(mProEventList[i]); - } - - mProEventList.clear(); - } - - /** - * Dequeue 1 event from the event queue. - * Returns UNKNOWN if queue is empty - */ - ProEvent ReadEvent() { - Mutex::Autolock al(mListenerMutex); - - if (mProEventList.size() == 0) { - return UNKNOWN; - } - - ProEvent ev = mProEventList[0]; - mProEventList.removeAt(0); - - return ev; - } - - void SetEventMask(int eventMask) { - Mutex::Autolock al(mListenerMutex); - mEventMask = eventMask; - } - - // Automatically acquire/release frames as they are available - void SetDropFrames(bool dropFrames) { - Mutex::Autolock al(mListenerMutex); - mDropFrames = dropFrames; - } - -private: - void QueueEvent(ProEvent ev) { - bool eventAdded = false; - { - Mutex::Autolock al(mListenerMutex); - - // Drop events not part of mask - if (ProEvent_Mask(ev) & mEventMask) { - mProEventList.push(ev); - eventAdded = true; - } - } - - if (eventAdded) { - mListenerCondition.broadcast(); - } - } - -protected: - - ////////////////////////////////////////////////// - ///////// ProCameraListener ////////////////////// - ////////////////////////////////////////////////// - - - // Lock has been acquired. Write operations now available. - virtual void onLockAcquired() { - QueueEvent(ACQUIRED); - } - // Lock has been released with exclusiveUnlock - virtual void onLockReleased() { - QueueEvent(RELEASED); - } - - // Lock has been stolen by another client. - virtual void onLockStolen() { - QueueEvent(STOLEN); - } - - // Lock free. - virtual void onTriggerNotify(int32_t ext1, int32_t ext2, int32_t ext3) { - - dout << "Trigger notify: " << ext1 << " " << ext2 - << " " << ext3 << std::endl; - } - - virtual void onFrameAvailable(int streamId, - const sp<CpuConsumer>& consumer) { - - QueueEvent(FRAME_RECEIVED); - - Mutex::Autolock al(mListenerMutex); - if (mDropFrames) { - CpuConsumer::LockedBuffer buf; - status_t ret; - - if (OK == (ret = consumer->lockNextBuffer(&buf))) { - - dout << "Frame received on streamId = " << streamId << - ", dataPtr = " << (void*)buf.data << - ", timestamp = " << buf.timestamp << std::endl; - - EXPECT_OK(consumer->unlockBuffer(buf)); - } - } else { - dout << "Frame received on streamId = " << streamId << std::endl; - } - } - - virtual void onResultReceived(int32_t requestId, - camera_metadata* request) { - dout << "Result received requestId = " << requestId - << ", requestPtr = " << (void*)request << std::endl; - QueueEvent(RESULT_RECEIVED); - free_camera_metadata(request); - } - - virtual void notify(int32_t msg, int32_t ext1, int32_t ext2) { - dout << "Notify received: msg " << std::hex << msg - << ", ext1: " << std::hex << ext1 << ", ext2: " << std::hex << ext2 - << std::endl; - } - - Vector<ProEvent> mProEventList; - Mutex mListenerMutex; - Mutex mConditionMutex; - Condition mListenerCondition; - int mEventMask; - bool mDropFrames; -}; - -class ProCameraTest : public ::testing::Test { - -public: - ProCameraTest() { - char* displaySecsEnv = getenv("TEST_DISPLAY_SECS"); - if (displaySecsEnv != NULL) { - mDisplaySecs = atoi(displaySecsEnv); - if (mDisplaySecs < 0) { - mDisplaySecs = 0; - } - } else { - mDisplaySecs = 0; - } - - char* displayFmtEnv = getenv("TEST_DISPLAY_FORMAT"); - if (displayFmtEnv != NULL) { - mDisplayFmt = FormatFromString(displayFmtEnv); - } else { - mDisplayFmt = TEST_DISPLAY_FORMAT; - } - - char* displayWidthEnv = getenv("TEST_DISPLAY_WIDTH"); - if (displayWidthEnv != NULL) { - mDisplayW = atoi(displayWidthEnv); - if (mDisplayW < 0) { - mDisplayW = 0; - } - } else { - mDisplayW = TEST_DISPLAY_WIDTH; - } - - char* displayHeightEnv = getenv("TEST_DISPLAY_HEIGHT"); - if (displayHeightEnv != NULL) { - mDisplayH = atoi(displayHeightEnv); - if (mDisplayH < 0) { - mDisplayH = 0; - } - } else { - mDisplayH = TEST_DISPLAY_HEIGHT; - } - } - - static void SetUpTestCase() { - // Binder Thread Pool Initialization - mTestThread = new ProCameraTestThread(); - mTestThread->run("ProCameraTestThread"); - } - - virtual void SetUp() { - mCamera = ProCamera::connect(CAMERA_ID); - ASSERT_NE((void*)NULL, mCamera.get()); - - mListener = new ProCameraTestListener(); - mCamera->setListener(mListener); - } - - virtual void TearDown() { - ASSERT_NE((void*)NULL, mCamera.get()); - mCamera->disconnect(); - } - -protected: - sp<ProCamera> mCamera; - sp<ProCameraTestListener> mListener; - - static sp<Thread> mTestThread; - - int mDisplaySecs; - int mDisplayFmt; - int mDisplayW; - int mDisplayH; - - sp<SurfaceComposerClient> mComposerClient; - sp<SurfaceControl> mSurfaceControl; - - sp<SurfaceComposerClient> mDepthComposerClient; - sp<SurfaceControl> mDepthSurfaceControl; - - int getSurfaceWidth() { - return 512; - } - int getSurfaceHeight() { - return 512; - } - - void createOnScreenSurface(sp<Surface>& surface) { - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - - mSurfaceControl = mComposerClient->createSurface( - String8("ProCameraTest StreamingImage Surface"), - getSurfaceWidth(), getSurfaceHeight(), - PIXEL_FORMAT_RGB_888, 0); - - mSurfaceControl->setPosition(0, 0); - - ASSERT_TRUE(mSurfaceControl != NULL); - ASSERT_TRUE(mSurfaceControl->isValid()); - - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF)); - ASSERT_EQ(NO_ERROR, mSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); - - sp<ANativeWindow> window = mSurfaceControl->getSurface(); - surface = mSurfaceControl->getSurface(); - - ASSERT_NE((void*)NULL, surface.get()); - } - - void createDepthOnScreenSurface(sp<Surface>& surface) { - mDepthComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_ERROR, mDepthComposerClient->initCheck()); - - mDepthSurfaceControl = mDepthComposerClient->createSurface( - String8("ProCameraTest StreamingImage Surface"), - getSurfaceWidth(), getSurfaceHeight(), - PIXEL_FORMAT_RGB_888, 0); - - mDepthSurfaceControl->setPosition(640, 0); - - ASSERT_TRUE(mDepthSurfaceControl != NULL); - ASSERT_TRUE(mDepthSurfaceControl->isValid()); - - SurfaceComposerClient::openGlobalTransaction(); - ASSERT_EQ(NO_ERROR, mDepthSurfaceControl->setLayer(0x7FFFFFFF)); - ASSERT_EQ(NO_ERROR, mDepthSurfaceControl->show()); - SurfaceComposerClient::closeGlobalTransaction(); - - sp<ANativeWindow> window = mDepthSurfaceControl->getSurface(); - surface = mDepthSurfaceControl->getSurface(); - - ASSERT_NE((void*)NULL, surface.get()); - } - - template <typename T> - static bool ExistsItem(T needle, T* array, size_t count) { - if (!array) { - return false; - } - - for (size_t i = 0; i < count; ++i) { - if (array[i] == needle) { - return true; - } - } - return false; - } - - - static int FormatFromString(const char* str) { - std::string s(str); - -#define CMP_STR(x, y) \ - if (s == #x) return HAL_PIXEL_FORMAT_ ## y; -#define CMP_STR_SAME(x) CMP_STR(x, x) - - CMP_STR_SAME( Y16); - CMP_STR_SAME( Y8); - CMP_STR_SAME( YV12); - CMP_STR(NV16, YCbCr_422_SP); - CMP_STR(NV21, YCrCb_420_SP); - CMP_STR(YUY2, YCbCr_422_I); - CMP_STR(RAW, RAW_SENSOR); - CMP_STR(RGBA, RGBA_8888); - - std::cerr << "Unknown format string " << str << std::endl; - return -1; - - } - - /** - * Creating a streaming request for these output streams from a template, - * and submit it - */ - void createSubmitRequestForStreams(int32_t* streamIds, size_t count, int requestCount=-1) { - - ASSERT_NE((void*)NULL, streamIds); - ASSERT_LT(0u, count); - - camera_metadata_t *requestTmp = NULL; - EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, - /*out*/&requestTmp)); - ASSERT_NE((void*)NULL, requestTmp); - CameraMetadata request(requestTmp); - - // set the output streams. default is empty - - uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS); - request.update(tag, streamIds, count); - - requestTmp = request.release(); - - if (requestCount < 0) { - EXPECT_OK(mCamera->submitRequest(requestTmp, /*streaming*/true)); - } else { - for (int i = 0; i < requestCount; ++i) { - EXPECT_OK(mCamera->submitRequest(requestTmp, - /*streaming*/false)); - } - } - request.acquire(requestTmp); - } -}; - -sp<Thread> ProCameraTest::mTestThread; - -TEST_F(ProCameraTest, AvailableFormats) { - if (HasFatalFailure()) { - return; - } - - CameraMetadata staticInfo = mCamera->getCameraInfo(CAMERA_ID); - ASSERT_FALSE(staticInfo.isEmpty()); - - uint32_t tag = static_cast<uint32_t>(ANDROID_SCALER_AVAILABLE_FORMATS); - EXPECT_TRUE(staticInfo.exists(tag)); - camera_metadata_entry_t entry = staticInfo.find(tag); - - EXPECT_TRUE(ExistsItem<int32_t>(HAL_PIXEL_FORMAT_YV12, - entry.data.i32, entry.count)); - EXPECT_TRUE(ExistsItem<int32_t>(HAL_PIXEL_FORMAT_YCrCb_420_SP, - entry.data.i32, entry.count)); -} - -// test around exclusiveTryLock (immediate locking) -TEST_F(ProCameraTest, LockingImmediate) { - - if (HasFatalFailure()) { - return; - } - - mListener->SetEventMask(ProEvent_Mask(ACQUIRED) | - ProEvent_Mask(STOLEN) | - ProEvent_Mask(RELEASED)); - - EXPECT_FALSE(mCamera->hasExclusiveLock()); - EXPECT_EQ(OK, mCamera->exclusiveTryLock()); - // at this point we definitely have the lock - - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(ACQUIRED, mListener->ReadEvent()); - - EXPECT_TRUE(mCamera->hasExclusiveLock()); - EXPECT_EQ(OK, mCamera->exclusiveUnlock()); - - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(RELEASED, mListener->ReadEvent()); - - EXPECT_FALSE(mCamera->hasExclusiveLock()); -} - -// test around exclusiveLock (locking at some future point in time) -TEST_F(ProCameraTest, LockingAsynchronous) { - - if (HasFatalFailure()) { - return; - } - - - mListener->SetEventMask(ProEvent_Mask(ACQUIRED) | - ProEvent_Mask(STOLEN) | - ProEvent_Mask(RELEASED)); - - // TODO: Add another procamera that has a lock here. - // then we can be test that the lock wont immediately be acquired - - EXPECT_FALSE(mCamera->hasExclusiveLock()); - EXPECT_EQ(OK, mCamera->exclusiveTryLock()); - // at this point we definitely have the lock - - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(ACQUIRED, mListener->ReadEvent()); - - EXPECT_TRUE(mCamera->hasExclusiveLock()); - EXPECT_EQ(OK, mCamera->exclusiveUnlock()); - - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(RELEASED, mListener->ReadEvent()); - - EXPECT_FALSE(mCamera->hasExclusiveLock()); -} - -// Stream directly to the screen. -TEST_F(ProCameraTest, DISABLED_StreamingImageSingle) { - if (HasFatalFailure()) { - return; - } - - sp<Surface> surface; - if (mDisplaySecs > 0) { - createOnScreenSurface(/*out*/surface); - } - else { - dout << "Skipping, will not render to screen" << std::endl; - return; - } - - int depthStreamId = -1; - - sp<ServiceListener> listener = new ServiceListener(); - EXPECT_OK(ProCamera::addServiceListener(listener)); - - ServiceListener::Status currentStatus; - - // when subscribing a new listener, - // we immediately get a callback to the current status - while (listener->waitForStatusChange(/*out*/currentStatus) != OK); - EXPECT_EQ(ServiceListener::STATUS_PRESENT, currentStatus); - - dout << "Will now stream and resume infinitely..." << std::endl; - while (true) { - - if (currentStatus == ServiceListener::STATUS_PRESENT) { - - ASSERT_OK(mCamera->createStream(mDisplayW, mDisplayH, mDisplayFmt, - surface, - &depthStreamId)); - EXPECT_NE(-1, depthStreamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - - int32_t streams[] = { depthStreamId }; - ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams( - streams, - /*count*/1)); - } - - ServiceListener::Status stat = ServiceListener::STATUS_UNKNOWN; - - // TODO: maybe check for getch every once in a while? - while (listener->waitForStatusChange(/*out*/stat) != OK); - - if (currentStatus != stat) { - if (stat == ServiceListener::STATUS_PRESENT) { - dout << "Reconnecting to camera" << std::endl; - mCamera = ProCamera::connect(CAMERA_ID); - } else if (stat == ServiceListener::STATUS_NOT_AVAILABLE) { - dout << "Disconnecting from camera" << std::endl; - mCamera->disconnect(); - } else if (stat == ServiceListener::STATUS_NOT_PRESENT) { - dout << "Camera unplugged" << std::endl; - mCamera = NULL; - } else { - dout << "Unknown status change " - << std::hex << stat << std::endl; - } - - currentStatus = stat; - } - } - - EXPECT_OK(ProCamera::removeServiceListener(listener)); - EXPECT_OK(mCamera->deleteStream(depthStreamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -// Stream directly to the screen. -TEST_F(ProCameraTest, DISABLED_StreamingImageDual) { - if (HasFatalFailure()) { - return; - } - sp<Surface> surface; - sp<Surface> depthSurface; - if (mDisplaySecs > 0) { - createOnScreenSurface(/*out*/surface); - createDepthOnScreenSurface(/*out*/depthSurface); - } - - int streamId = -1; - EXPECT_OK(mCamera->createStream(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, surface, &streamId)); - EXPECT_NE(-1, streamId); - - int depthStreamId = -1; - EXPECT_OK(mCamera->createStream(/*width*/320, /*height*/240, - TEST_FORMAT_DEPTH, depthSurface, &depthStreamId)); - EXPECT_NE(-1, depthStreamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - /* - */ - /* iterate in a loop submitting requests every frame. - * what kind of requests doesnt really matter, just whatever. - */ - - // it would probably be better to use CameraMetadata from camera service. - camera_metadata_t *request = NULL; - EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, - /*out*/&request)); - EXPECT_NE((void*)NULL, request); - - /*FIXME: dont need this later, at which point the above should become an - ASSERT_NE*/ - if(request == NULL) request = allocate_camera_metadata(10, 100); - - // set the output streams to just this stream ID - - // wow what a verbose API. - int32_t allStreams[] = { streamId, depthStreamId }; - // IMPORTANT. bad things will happen if its not a uint8. - size_t streamCount = sizeof(allStreams) / sizeof(allStreams[0]); - camera_metadata_entry_t entry; - uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS); - int find = find_camera_metadata_entry(request, tag, &entry); - if (find == -ENOENT) { - if (add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/streamCount) != OK) { - camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000); - ASSERT_OK(append_camera_metadata(tmp, request)); - free_camera_metadata(request); - request = tmp; - - ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/streamCount)); - } - } else { - ASSERT_OK(update_camera_metadata_entry(request, entry.index, - &allStreams, /*data_count*/streamCount, &entry)); - } - - EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); - - dout << "will sleep now for " << mDisplaySecs << std::endl; - sleep(mDisplaySecs); - - free_camera_metadata(request); - - for (size_t i = 0; i < streamCount; ++i) { - EXPECT_OK(mCamera->deleteStream(allStreams[i])); - } - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -TEST_F(ProCameraTest, CpuConsumerSingle) { - if (HasFatalFailure()) { - return; - } - - mListener->SetEventMask(ProEvent_Mask(ACQUIRED) | - ProEvent_Mask(STOLEN) | - ProEvent_Mask(RELEASED) | - ProEvent_Mask(FRAME_RECEIVED)); - mListener->SetDropFrames(true); - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240, - TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(ACQUIRED, mListener->ReadEvent()); - /* iterate in a loop submitting requests every frame. - * what kind of requests doesnt really matter, just whatever. - */ - - // it would probably be better to use CameraMetadata from camera service. - camera_metadata_t *request = NULL; - EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, - /*out*/&request)); - EXPECT_NE((void*)NULL, request); - - /*FIXME: dont need this later, at which point the above should become an - ASSERT_NE*/ - if(request == NULL) request = allocate_camera_metadata(10, 100); - - // set the output streams to just this stream ID - - int32_t allStreams[] = { streamId }; - camera_metadata_entry_t entry; - uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS); - int find = find_camera_metadata_entry(request, tag, &entry); - if (find == -ENOENT) { - if (add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/1) != OK) { - camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000); - ASSERT_OK(append_camera_metadata(tmp, request)); - free_camera_metadata(request); - request = tmp; - - ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/1)); - } - } else { - ASSERT_OK(update_camera_metadata_entry(request, entry.index, - &allStreams, /*data_count*/1, &entry)); - } - - EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); - - // Consume a couple of frames - for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) { - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(FRAME_RECEIVED, mListener->ReadEvent()); - } - - // Done: clean up - free_camera_metadata(request); - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -TEST_F(ProCameraTest, CpuConsumerDual) { - if (HasFatalFailure()) { - return; - } - - mListener->SetEventMask(ProEvent_Mask(FRAME_RECEIVED)); - mListener->SetDropFrames(true); - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - int depthStreamId = -1; - EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240, - TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &consumer, &depthStreamId)); - EXPECT_NE(-1, depthStreamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - /* - */ - /* iterate in a loop submitting requests every frame. - * what kind of requests doesnt really matter, just whatever. - */ - - // it would probably be better to use CameraMetadata from camera service. - camera_metadata_t *request = NULL; - EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, - /*out*/&request)); - EXPECT_NE((void*)NULL, request); - - if(request == NULL) request = allocate_camera_metadata(10, 100); - - // set the output streams to just this stream ID - - // wow what a verbose API. - int32_t allStreams[] = { streamId, depthStreamId }; - size_t streamCount = 2; - camera_metadata_entry_t entry; - uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS); - int find = find_camera_metadata_entry(request, tag, &entry); - if (find == -ENOENT) { - if (add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/streamCount) != OK) { - camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000); - ASSERT_OK(append_camera_metadata(tmp, request)); - free_camera_metadata(request); - request = tmp; - - ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/streamCount)); - } - } else { - ASSERT_OK(update_camera_metadata_entry(request, entry.index, - &allStreams, /*data_count*/streamCount, &entry)); - } - - EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); - - // Consume a couple of frames - for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) { - // stream id 1 - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(FRAME_RECEIVED, mListener->ReadEvent()); - - // stream id 2 - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(FRAME_RECEIVED, mListener->ReadEvent()); - - //TODO: events should be a struct with some data like the stream id - } - - // Done: clean up - free_camera_metadata(request); - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -TEST_F(ProCameraTest, ResultReceiver) { - if (HasFatalFailure()) { - return; - } - - mListener->SetEventMask(ProEvent_Mask(RESULT_RECEIVED)); - mListener->SetDropFrames(true); - //FIXME: if this is run right after the previous test we get FRAME_RECEIVED - // need to filter out events at read time - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - /* - */ - /* iterate in a loop submitting requests every frame. - * what kind of requests doesnt really matter, just whatever. - */ - - camera_metadata_t *request = NULL; - EXPECT_OK(mCamera->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW, - /*out*/&request)); - EXPECT_NE((void*)NULL, request); - - /*FIXME*/ - if(request == NULL) request = allocate_camera_metadata(10, 100); - - // set the output streams to just this stream ID - - int32_t allStreams[] = { streamId }; - size_t streamCount = 1; - camera_metadata_entry_t entry; - uint32_t tag = static_cast<uint32_t>(ANDROID_REQUEST_OUTPUT_STREAMS); - int find = find_camera_metadata_entry(request, tag, &entry); - if (find == -ENOENT) { - if (add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/streamCount) != OK) { - camera_metadata_t *tmp = allocate_camera_metadata(1000, 10000); - ASSERT_OK(append_camera_metadata(tmp, request)); - free_camera_metadata(request); - request = tmp; - - ASSERT_OK(add_camera_metadata_entry(request, tag, &allStreams, - /*data_count*/streamCount)); - } - } else { - ASSERT_OK(update_camera_metadata_entry(request, entry.index, - &allStreams, /*data_count*/streamCount, &entry)); - } - - EXPECT_OK(mCamera->submitRequest(request, /*streaming*/true)); - - // Consume a couple of results - for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) { - EXPECT_EQ(OK, mListener->WaitForEvent()); - EXPECT_EQ(RESULT_RECEIVED, mListener->ReadEvent()); - } - - // Done: clean up - free_camera_metadata(request); - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -// FIXME: This is racy and sometimes fails on waitForFrameMetadata -TEST_F(ProCameraTest, DISABLED_WaitForResult) { - if (HasFatalFailure()) { - return; - } - - mListener->SetDropFrames(true); - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - - int32_t streams[] = { streamId }; - ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1)); - - // Consume a couple of results - for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) { - EXPECT_OK(mCamera->waitForFrameMetadata()); - CameraMetadata meta = mCamera->consumeFrameMetadata(); - EXPECT_FALSE(meta.isEmpty()); - } - - // Done: clean up - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -TEST_F(ProCameraTest, WaitForSingleStreamBuffer) { - if (HasFatalFailure()) { - return; - } - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - - int32_t streams[] = { streamId }; - ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1, - /*requests*/TEST_CPU_FRAME_COUNT)); - - // Consume a couple of results - for (int i = 0; i < TEST_CPU_FRAME_COUNT; ++i) { - EXPECT_EQ(1, mCamera->waitForFrameBuffer(streamId)); - - CpuConsumer::LockedBuffer buf; - EXPECT_OK(consumer->lockNextBuffer(&buf)); - - dout << "Buffer synchronously received on streamId = " << streamId << - ", dataPtr = " << (void*)buf.data << - ", timestamp = " << buf.timestamp << std::endl; - - EXPECT_OK(consumer->unlockBuffer(buf)); - } - - // Done: clean up - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -// FIXME: This is racy and sometimes fails on waitForFrameMetadata -TEST_F(ProCameraTest, DISABLED_WaitForDualStreamBuffer) { - if (HasFatalFailure()) { - return; - } - - const int REQUEST_COUNT = TEST_CPU_FRAME_COUNT * 10; - - // 15 fps - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - // 30 fps - int depthStreamId = -1; - sp<CpuConsumer> depthConsumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/320, /*height*/240, - TEST_FORMAT_DEPTH, TEST_CPU_HEAP_COUNT, &depthConsumer, &depthStreamId)); - EXPECT_NE(-1, depthStreamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - - int32_t streams[] = { streamId, depthStreamId }; - ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/2, - /*requests*/REQUEST_COUNT)); - - int depthFrames = 0; - int greyFrames = 0; - - // Consume two frames simultaneously. Unsynchronized by timestamps. - for (int i = 0; i < REQUEST_COUNT; ++i) { - - // Exhaust event queue so it doesn't keep growing - while (mListener->ReadEvent() != UNKNOWN); - - // Get the metadata - EXPECT_OK(mCamera->waitForFrameMetadata()); - CameraMetadata meta = mCamera->consumeFrameMetadata(); - EXPECT_FALSE(meta.isEmpty()); - - // Get the buffers - - EXPECT_EQ(1, mCamera->waitForFrameBuffer(depthStreamId)); - - /** - * Guaranteed to be able to consume the depth frame, - * since we waited on it. - */ - CpuConsumer::LockedBuffer depthBuffer; - EXPECT_OK(depthConsumer->lockNextBuffer(&depthBuffer)); - - dout << "Depth Buffer synchronously received on streamId = " << - streamId << - ", dataPtr = " << (void*)depthBuffer.data << - ", timestamp = " << depthBuffer.timestamp << std::endl; - - EXPECT_OK(depthConsumer->unlockBuffer(depthBuffer)); - - depthFrames++; - - - /** Consume Greyscale frames if there are any. - * There may not be since it runs at half FPS */ - CpuConsumer::LockedBuffer greyBuffer; - while (consumer->lockNextBuffer(&greyBuffer) == OK) { - - dout << "GRAY Buffer synchronously received on streamId = " << - streamId << - ", dataPtr = " << (void*)greyBuffer.data << - ", timestamp = " << greyBuffer.timestamp << std::endl; - - EXPECT_OK(consumer->unlockBuffer(greyBuffer)); - - greyFrames++; - } - } - - dout << "Done, summary: depth frames " << std::dec << depthFrames - << ", grey frames " << std::dec << greyFrames << std::endl; - - // Done: clean up - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFramesSync) { - if (HasFatalFailure()) { - return; - } - - const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT; - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, - /*synchronousMode*/true, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - - int32_t streams[] = { streamId }; - ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1, - /*requests*/NUM_REQUESTS)); - - // Consume a couple of results - for (int i = 0; i < NUM_REQUESTS; ++i) { - int numFrames; - EXPECT_TRUE((numFrames = mCamera->waitForFrameBuffer(streamId)) > 0); - - // Drop all but the newest framebuffer - EXPECT_EQ(numFrames-1, mCamera->dropFrameBuffer(streamId, numFrames-1)); - - dout << "Dropped " << (numFrames - 1) << " frames" << std::endl; - - // Skip the counter ahead, don't try to consume these frames again - i += numFrames-1; - - // "Consume" the buffer - CpuConsumer::LockedBuffer buf; - EXPECT_OK(consumer->lockNextBuffer(&buf)); - - dout << "Buffer synchronously received on streamId = " << streamId << - ", dataPtr = " << (void*)buf.data << - ", timestamp = " << buf.timestamp << std::endl; - - // Process at 10fps, stream is at 15fps. - // This means we will definitely fill up the buffer queue with - // extra buffers and need to drop them. - usleep(TEST_FRAME_PROCESSING_DELAY_US); - - EXPECT_OK(consumer->unlockBuffer(buf)); - } - - // Done: clean up - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - -TEST_F(ProCameraTest, WaitForSingleStreamBufferAndDropFramesAsync) { - if (HasFatalFailure()) { - return; - } - - const int NUM_REQUESTS = 20 * TEST_CPU_FRAME_COUNT; - - int streamId = -1; - sp<CpuConsumer> consumer; - EXPECT_OK(mCamera->createStreamCpu(/*width*/1280, /*height*/960, - TEST_FORMAT_MAIN, TEST_CPU_HEAP_COUNT, - /*synchronousMode*/false, &consumer, &streamId)); - EXPECT_NE(-1, streamId); - - EXPECT_OK(mCamera->exclusiveTryLock()); - - int32_t streams[] = { streamId }; - ASSERT_NO_FATAL_FAILURE(createSubmitRequestForStreams(streams, /*count*/1, - /*requests*/NUM_REQUESTS)); - - uint64_t lastFrameNumber = 0; - int numFrames; - - // Consume a couple of results - int i; - for (i = 0; i < NUM_REQUESTS && lastFrameNumber < NUM_REQUESTS; ++i) { - EXPECT_LT(0, (numFrames = mCamera->waitForFrameBuffer(streamId))); - - dout << "Dropped " << (numFrames - 1) << " frames" << std::endl; - - // Skip the counter ahead, don't try to consume these frames again - i += numFrames-1; - - // "Consume" the buffer - CpuConsumer::LockedBuffer buf; - - EXPECT_EQ(OK, consumer->lockNextBuffer(&buf)); - - lastFrameNumber = buf.frameNumber; - - dout << "Buffer asynchronously received on streamId = " << streamId << - ", dataPtr = " << (void*)buf.data << - ", timestamp = " << buf.timestamp << - ", framenumber = " << buf.frameNumber << std::endl; - - // Process at 10fps, stream is at 15fps. - // This means we will definitely fill up the buffer queue with - // extra buffers and need to drop them. - usleep(TEST_FRAME_PROCESSING_DELAY_US); - - EXPECT_OK(consumer->unlockBuffer(buf)); - } - - dout << "Done after " << i << " iterations " << std::endl; - - // Done: clean up - EXPECT_OK(mCamera->deleteStream(streamId)); - EXPECT_OK(mCamera->exclusiveUnlock()); -} - - - -//TODO: refactor into separate file -TEST_F(ProCameraTest, ServiceListenersSubscribe) { - - ASSERT_EQ(4u, sizeof(ServiceListener::Status)); - - sp<ServiceListener> listener = new ServiceListener(); - - EXPECT_EQ(BAD_VALUE, ProCamera::removeServiceListener(listener)); - EXPECT_OK(ProCamera::addServiceListener(listener)); - - EXPECT_EQ(ALREADY_EXISTS, ProCamera::addServiceListener(listener)); - EXPECT_OK(ProCamera::removeServiceListener(listener)); - - EXPECT_EQ(BAD_VALUE, ProCamera::removeServiceListener(listener)); -} - -//TODO: refactor into separate file -TEST_F(ProCameraTest, ServiceListenersFunctional) { - - sp<ServiceListener> listener = new ServiceListener(); - - EXPECT_OK(ProCamera::addServiceListener(listener)); - - sp<Camera> cam = Camera::connect(CAMERA_ID, - /*clientPackageName*/String16(), - -1); - EXPECT_NE((void*)NULL, cam.get()); - - ServiceListener::Status stat = ServiceListener::STATUS_UNKNOWN; - EXPECT_OK(listener->waitForStatusChange(/*out*/stat)); - - EXPECT_EQ(ServiceListener::STATUS_NOT_AVAILABLE, stat); - - if (cam.get()) { - cam->disconnect(); - } - - EXPECT_OK(listener->waitForStatusChange(/*out*/stat)); - EXPECT_EQ(ServiceListener::STATUS_PRESENT, stat); - - EXPECT_OK(ProCamera::removeServiceListener(listener)); -} - - - -} -} -} -} diff --git a/camera/tests/VendorTagDescriptorTests.cpp b/camera/tests/VendorTagDescriptorTests.cpp index 6624e79..9082dbf 100644 --- a/camera/tests/VendorTagDescriptorTests.cpp +++ b/camera/tests/VendorTagDescriptorTests.cpp @@ -53,6 +53,10 @@ static bool ContainsTag(uint32_t* tagArray, size_t size, uint32_t tag) { extern "C" { +static int zero_get_tag_count(const vendor_tag_ops_t* vOps) { + return 0; +} + static int default_get_tag_count(const vendor_tag_ops_t* vOps) { return VENDOR_TAG_COUNT_ERR; } @@ -173,10 +177,13 @@ TEST(VendorTagDescriptorTest, ErrorConditions) { vendor_tag_ops_t vOps; FillWithDefaults(&vOps); + // Make empty tag count + vOps.get_tag_count = zero_get_tag_count; + // Ensure create fails when using null vOps EXPECT_EQ(BAD_VALUE, VendorTagDescriptor::createDescriptorFromOps(/*vOps*/NULL, vDesc)); - // Ensure create works when there are no vtags defined in a well-formed vOps + // Ensure creat succeeds for empty vendor tag ops ASSERT_EQ(OK, VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc)); // Ensure defaults are returned when no vtags are defined, or tag is unknown |