Camera NDK library: first draft
Bug: 23012001
Change-Id: I06d834421289d4dead1c87301a6ee94487ccf023
diff --git a/camera/ndk/Android.mk b/camera/ndk/Android.mk
new file mode 100644
index 0000000..b693995
--- /dev/null
+++ b/camera/ndk/Android.mk
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+ifneq ($(TARGET_BUILD_PDK), true)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ NdkCameraManager.cpp \
+ NdkCameraMetadata.cpp \
+ NdkCameraDevice.cpp \
+ NdkCaptureRequest.cpp \
+ NdkCameraCaptureSession.cpp \
+ impl/ACameraManager.cpp \
+ impl/ACameraMetadata.cpp \
+ impl/ACameraDevice.cpp \
+
+LOCAL_MODULE:= libcamera2ndk
+
+LOCAL_C_INCLUDES := \
+ system/media/camera/include \
+ frameworks/av/include/camera/ndk
+
+LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ liblog \
+ libutils \
+ libandroid_runtime \
+ libcamera_client \
+ libstagefright_foundation \
+ libcutils \
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
new file mode 100644
index 0000000..26380c4
--- /dev/null
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 "NdkCameraCaptureSession"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Trace.h>
+
+#include "NdkCameraDevice.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraCaptureSession_close(ACameraCaptureSession*) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_getDevice(
+ ACameraCaptureSession*, ACameraDevice **device) {
+ ATRACE_CALL();
+ // Make sure don't do return garbage if device has been closed
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_capture(
+ ACameraCaptureSession*, /*optional*/ACameraCaptureSession_captureCallbacks*,
+ int numRequests, const ACaptureRequest* requests) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_setRepeatingRequest(
+ ACameraCaptureSession*, /*optional*/ACameraCaptureSession_captureCallbacks*,
+ int numRequests, const ACaptureRequest* requests) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_stopRepeating(ACameraCaptureSession*) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraCaptureSession_abortCaptures(ACameraCaptureSession*) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
new file mode 100644
index 0000000..c747c1b
--- /dev/null
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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 "NdkCameraDevice"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <NdkCameraDevice.h>
+#include "impl/ACameraDevice.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraDevice_close(ACameraDevice* device) {
+ ATRACE_CALL();
+ if (device == nullptr) {
+ ALOGE("%s: invalid argument! device is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ delete device;
+ return ACAMERA_OK;
+}
+
+EXPORT
+const char* ACameraDevice_getId(const ACameraDevice* device) {
+ ATRACE_CALL();
+ if (device == nullptr) {
+ ALOGE("%s: invalid argument! device is null", __FUNCTION__);
+ return nullptr;
+ }
+ return device->getId();
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureRequest(
+ const ACameraDevice* device,
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) {
+ ATRACE_CALL();
+ if (device == nullptr || request == nullptr) {
+ ALOGE("%s: invalid argument! device 0x%p request 0x%p",
+ __FUNCTION__, device, request);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ switch (templateId) {
+ case TEMPLATE_PREVIEW:
+ case TEMPLATE_STILL_CAPTURE:
+ case TEMPLATE_RECORD:
+ case TEMPLATE_VIDEO_SNAPSHOT:
+ case TEMPLATE_ZERO_SHUTTER_LAG:
+ case TEMPLATE_MANUAL:
+ break;
+ default:
+ ALOGE("%s: unknown template ID %d", __FUNCTION__, templateId);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return device->createCaptureRequest(templateId, request);
+}
+
+struct ACaptureSessionOutputContainer;
+
+struct ACaptureSessionOutput;
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_create(/*out*/ACaptureSessionOutputContainer**) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer*) {
+ ATRACE_CALL();
+ return;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutput_create(ANativeWindow*, /*out*/ACaptureSessionOutput**) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+void ACaptureSessionOutput_free(ACaptureSessionOutput*) {
+ ATRACE_CALL();
+ return;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_add(
+ ACaptureSessionOutputContainer*, const ACaptureSessionOutput*) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureSessionOutputContainer_remove(
+ ACaptureSessionOutputContainer*, const ACaptureSessionOutput*) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraDevice_createCaptureSession(
+ ACameraDevice*,
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* callbacks) {
+ ATRACE_CALL();
+ return ACAMERA_OK;
+}
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
new file mode 100644
index 0000000..3293af0
--- /dev/null
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 "NdkCameraManager"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <NdkCameraManager.h>
+#include "impl/ACameraManager.h"
+
+EXPORT
+ACameraManager* ACameraManager_create() {
+ ATRACE_CALL();
+ return new ACameraManager();
+}
+
+EXPORT
+void ACameraManager_delete(ACameraManager* manager) {
+ ATRACE_CALL();
+ if (manager != nullptr) {
+ delete manager;
+ }
+}
+
+EXPORT
+camera_status_t ACameraManager_getCameraIdList(
+ ACameraManager* manager, ACameraIdList** cameraIdList) {
+ ATRACE_CALL();
+ if (manager == nullptr || cameraIdList == nullptr) {
+ ALOGE("%s: invalid argument! manager 0x%p, cameraIdList 0x%p",
+ __FUNCTION__, manager, cameraIdList);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return manager->getCameraIdList(cameraIdList);
+}
+
+EXPORT
+void ACameraManager_deleteCameraIdList(ACameraIdList* cameraIdList) {
+ ATRACE_CALL();
+ if (cameraIdList != nullptr) {
+ ACameraManager::deleteCameraIdList(cameraIdList);
+ }
+}
+
+EXPORT
+camera_status_t ACameraManager_registerAvailabilityCallback(
+ ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (callback->onCameraAvailable == nullptr || callback->onCameraUnavailable == nullptr) {
+ ALOGE("%s: invalid argument! callback 0x%p, "
+ "onCameraAvailable 0x%p, onCameraUnavailable 0x%p",
+ __FUNCTION__, callback,
+ callback->onCameraAvailable, callback->onCameraUnavailable);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().registerAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_unregisterAvailabilityCallback(
+ ACameraManager*, const ACameraManager_AvailabilityCallbacks *callback) {
+ ATRACE_CALL();
+ if (callback == nullptr) {
+ ALOGE("%s: invalid argument! callback is null!", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (callback->onCameraAvailable == nullptr || callback->onCameraUnavailable == nullptr) {
+ ALOGE("%s: invalid argument! callback 0x%p, "
+ "onCameraAvailable 0x%p, onCameraUnavailable 0x%p",
+ __FUNCTION__, callback,
+ callback->onCameraAvailable, callback->onCameraUnavailable);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ CameraManagerGlobal::getInstance().unregisterAvailabilityCallback(callback);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACameraManager_getCameraCharacteristics(
+ ACameraManager* mgr, const char* cameraId, ACameraMetadata** chars){
+ ATRACE_CALL();
+ if (mgr == nullptr || cameraId == nullptr || chars == nullptr) {
+ ALOGE("%s: invalid argument! mgr 0x%p cameraId 0x%p chars 0x%p",
+ __FUNCTION__, mgr, cameraId, chars);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->getCameraCharacteristics(cameraId, chars);
+}
+
+EXPORT
+camera_status_t ACameraManager_openCamera(
+ ACameraManager* mgr, const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device) {
+ ATRACE_CALL();
+ if (mgr == nullptr || cameraId == nullptr || callback == nullptr || device == nullptr) {
+ ALOGE("%s: invalid argument! mgr 0x%p cameraId 0x%p callback 0x%p device 0x%p",
+ __FUNCTION__, mgr, cameraId, callback, device);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return mgr->openCamera(cameraId, callback, device);
+}
diff --git a/camera/ndk/NdkCameraMetadata.cpp b/camera/ndk/NdkCameraMetadata.cpp
new file mode 100644
index 0000000..9d68c50
--- /dev/null
+++ b/camera/ndk/NdkCameraMetadata.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "NdkCameraMetadata"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "NdkCameraMetadata.h"
+#include "impl/ACameraMetadata.h"
+
+using namespace android;
+
+EXPORT
+camera_status_t ACameraMetadata_getConstEntry(
+ const ACameraMetadata* acm, uint32_t tag, ACameraMetadata_const_entry* entry) {
+ ATRACE_CALL();
+ if (acm == nullptr || entry == nullptr) {
+ ALOGE("%s: invalid argument! metadata 0x%p, tag 0x%x, entry 0x%p",
+ __FUNCTION__, acm, tag, entry);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return acm->getConstEntry(tag, entry);
+}
+
+EXPORT
+ACameraMetadata* ACameraMetadata_copy(const ACameraMetadata* src) {
+ ATRACE_CALL();
+ if (src == nullptr) {
+ ALOGE("%s: src is null!", __FUNCTION__);
+ return nullptr;
+ }
+ return new ACameraMetadata(*src);
+}
+
+EXPORT
+void ACameraMetadata_free(ACameraMetadata* metadata) {
+ ATRACE_CALL();
+ if (metadata != nullptr) {
+ delete metadata;
+ }
+}
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
new file mode 100644
index 0000000..e5f7cf3
--- /dev/null
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 "NdkCaptureRequest"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include "NdkCaptureRequest.h"
+#include "impl/ACameraMetadata.h"
+#include "impl/ACaptureRequest.h"
+
+EXPORT
+camera_status_t ACameraOutputTarget_create(
+ ANativeWindow* window, ACameraOutputTarget** out) {
+ ATRACE_CALL();
+ if (window == nullptr) {
+ ALOGE("%s: Error: input window is null", __FUNCTION__);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ *out = new ACameraOutputTarget(window);
+ return ACAMERA_OK;
+}
+
+EXPORT
+void ACameraOutputTarget_free(ACameraOutputTarget* target) {
+ ATRACE_CALL();
+ if (target != nullptr) {
+ delete target;
+ }
+ return;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_addTarget(
+ ACaptureRequest* req, const ACameraOutputTarget* target) {
+ ATRACE_CALL();
+ if (req == nullptr || req->targets == nullptr || target == nullptr) {
+ ALOGE("%s: Error: invalid input: req 0x%p, req-targets 0x%p, target 0x%p",
+ __FUNCTION__, req, req->targets, target);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ auto pair = req->targets->mOutputs.insert(*target);
+ if (!pair.second) {
+ ALOGW("%s: target 0x%p already exists!", __FUNCTION__, target);
+ }
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_removeTarget(
+ ACaptureRequest* req, const ACameraOutputTarget* target) {
+ ATRACE_CALL();
+ if (req == nullptr || req->targets == nullptr || target == nullptr) {
+ ALOGE("%s: Error: invalid input: req 0x%p, req-targets 0x%p, target 0x%p",
+ __FUNCTION__, req, req->targets, target);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ req->targets->mOutputs.erase(*target);
+ return ACAMERA_OK;
+}
+
+EXPORT
+camera_status_t ACaptureRequest_getConstEntry(
+ const ACaptureRequest* req, uint32_t tag, ACameraMetadata_const_entry* entry) {
+ ATRACE_CALL();
+ if (req == nullptr || entry == nullptr) {
+ ALOGE("%s: invalid argument! req 0x%p, tag 0x%x, entry 0x%p",
+ __FUNCTION__, req, tag, entry);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ return req->settings->getConstEntry(tag, entry);
+}
+
+#define SET_ENTRY(NAME,NDK_TYPE) \
+EXPORT \
+camera_status_t ACaptureRequest_setEntry_##NAME( \
+ ACaptureRequest* req, uint32_t tag, uint32_t count, const NDK_TYPE* data) { \
+ ATRACE_CALL(); \
+ if (req == nullptr || (count > 0 && data == nullptr)) { \
+ ALOGE("%s: invalid argument! req %p, tag 0x%x, count %d, data 0x%p", \
+ __FUNCTION__, req, tag, count, data); \
+ return ACAMERA_ERROR_INVALID_PARAMETER; \
+ } \
+ return req->settings->update(tag, count, data); \
+}
+
+SET_ENTRY(u8,uint8_t)
+SET_ENTRY(i32,int32_t)
+SET_ENTRY(float,float)
+SET_ENTRY(double,double)
+SET_ENTRY(i64,int64_t)
+SET_ENTRY(rational,ACameraMetadata_rational)
+
+#undef SET_ENTRY
+
+EXPORT
+void ACaptureRequest_free(ACaptureRequest* request) {
+ ATRACE_CALL();
+ if (request == nullptr) {
+ return;
+ }
+ delete request->settings;
+ delete request->targets;
+ delete request;
+ return;
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
new file mode 100644
index 0000000..0c6f8af
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -0,0 +1,300 @@
+/*
+ * 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 "ACameraDevice"
+
+#include <inttypes.h>
+#include "ACameraDevice.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+
+using namespace android;
+
+namespace android {
+// Static member definitions
+const char* CameraDevice::kContextKey = "Context";
+const char* CameraDevice::kDeviceKey = "Device";
+const char* CameraDevice::kErrorCodeKey = "ErrorCode";
+const char* CameraDevice::kCallbackKey = "Callback";
+
+/**
+ * CameraDevice Implementation
+ */
+CameraDevice::CameraDevice(
+ const char* id,
+ ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars,
+ ACameraDevice* wrapper) :
+ mCameraId(id),
+ mAppCallbacks(*cb),
+ mChars(std::move(chars)),
+ mServiceCallback(new ServiceCallback(this)),
+ mWrapper(wrapper),
+ mInError(false),
+ mError(ACAMERA_OK),
+ mIdle(true) {
+ mClosing = false;
+ // Setup looper thread to perfrom device callbacks to app
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-dev-looper");
+ status_t ret = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_FOREGROUND);
+ mHandler = new CallbackHandler();
+ mCbLooper->registerHandler(mHandler);
+}
+
+CameraDevice::~CameraDevice() {
+ Mutex::Autolock _l(mDeviceLock);
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+ if (!isClosed()) {
+ disconnectLocked();
+ }
+}
+
+// TODO: cached created request?
+camera_status_t
+CameraDevice::createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const {
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+ if (mRemote == nullptr) {
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawRequest;
+ status_t remoteRet = mRemote->createDefaultRequest(templateId, &rawRequest);
+ if (remoteRet == BAD_VALUE) {
+ ALOGW("Create capture request failed! template %d is not supported on this device",
+ templateId);
+ return ACAMERA_ERROR_UNSUPPORTED;
+ } else if (remoteRet != OK) {
+ ALOGE("Create capture request failed! error %d", remoteRet);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ ACaptureRequest* outReq = new ACaptureRequest();
+ outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ outReq->targets = new ACameraOutputTargets();
+ *request = outReq;
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::disconnectLocked() {
+ if (mClosing.exchange(true)) {
+ // Already closing, just return
+ ALOGW("Camera device %s is already closing.", getId());
+ return;
+ }
+
+ if (mRemote != nullptr) {
+ mRemote->disconnect();
+ }
+ mRemote = nullptr;
+}
+
+void
+CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ Mutex::Autolock _l(mDeviceLock);
+ mRemote = remote;
+}
+
+camera_status_t
+CameraDevice::checkCameraClosedOrErrorLocked() const {
+ if (mRemote == nullptr) {
+ ALOGE("%s: camera device already closed", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ if (mInError) {// triggered by onDeviceError
+ ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
+ return mError;
+ }
+ return ACAMERA_OK;
+}
+
+void
+CameraDevice::onCaptureErrorLocked(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ // TODO: implement!
+}
+
+void CameraDevice::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ case kWhatOnError:
+ break;
+ default:
+ ALOGE("%s:Error: unknown device callback %d", __FUNCTION__, msg->what());
+ return;
+ }
+ // Check the common part of all message
+ void* context;
+ bool found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ {
+ ACameraDevice_StateCallback onDisconnected;
+ found = msg->findPointer(kCallbackKey, (void**) &onDisconnected);
+ if (!found) {
+ ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
+ return;
+ }
+ (*onDisconnected)(context, dev);
+ break;
+ }
+ case kWhatOnError:
+ {
+ ACameraDevice_ErrorStateCallback onError;
+ found = msg->findPointer(kCallbackKey, (void**) &onError);
+ if (!found) {
+ ALOGE("%s: Cannot find onError!", __FUNCTION__);
+ return;
+ }
+ int errorCode;
+ found = msg->findInt32(kErrorCodeKey, &errorCode);
+ if (!found) {
+ ALOGE("%s: Cannot find error code!", __FUNCTION__);
+ return;
+ }
+ (*onError)(context, dev, errorCode);
+ }
+ }
+}
+
+/**
+ * Camera service callback implementation
+ */
+void
+CameraDevice::ServiceCallback::onDeviceError(
+ CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d",
+ errorCode, resultExtras.frameNumber, resultExtras.requestId, resultExtras.burstId);
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return; // device has been disconnected
+ }
+ switch (errorCode) {
+ case ERROR_CAMERA_DISCONNECTED:
+ {
+ // should be clear mRemote here?
+ // TODO: close current session
+ sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackKey, (void*) dev->mAppCallbacks.onDisconnected);
+ msg->post();
+ break;
+ }
+ default:
+ ALOGE("Unknown error from camera device: %d", errorCode);
+ // no break
+ case ERROR_CAMERA_DEVICE:
+ case ERROR_CAMERA_SERVICE:
+ {
+ dev->mInError = true;
+ switch (errorCode) {
+ case ERROR_CAMERA_DEVICE:
+ dev->mError = ACAMERA_ERROR_CAMERA_DEVICE;
+ break;
+ case ERROR_CAMERA_SERVICE:
+ dev->mError = ACAMERA_ERROR_CAMERA_SERVICE;
+ break;
+ default:
+ dev->mError = ACAMERA_ERROR_UNKNOWN;
+ break;
+ }
+ sp<AMessage> msg = new AMessage(kWhatOnError, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackKey, (void*) dev->mAppCallbacks.onError);
+ msg->setInt32(kErrorCodeKey, errorCode);
+ msg->post();
+ break;
+ }
+ case ERROR_CAMERA_REQUEST:
+ case ERROR_CAMERA_RESULT:
+ case ERROR_CAMERA_BUFFER:
+ dev->onCaptureErrorLocked(errorCode, resultExtras);
+ break;
+ }
+}
+
+void
+CameraDevice::ServiceCallback::onDeviceIdle() {
+ ALOGV("Camera is now idle");
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return; // device has been disconnected
+ }
+ if (!dev->mIdle) {
+ // TODO: send idle callback to current session
+ }
+ dev->mIdle = true;
+}
+
+void
+CameraDevice::ServiceCallback::onCaptureStarted(
+ const CaptureResultExtras& resultExtras,
+ int64_t timestamp) {
+}
+
+void
+CameraDevice::ServiceCallback::onResultReceived(
+ const CameraMetadata& metadata,
+ const CaptureResultExtras& resultExtras) {
+}
+
+void
+CameraDevice::ServiceCallback::onPrepared(int) {
+ // Prepare not yet implemented in NDK
+ return;
+}
+
+} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
new file mode 100644
index 0000000..061175c
--- /dev/null
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ACAMERA_DEVICE_H
+#define _ACAMERA_DEVICE_H
+
+#include <memory>
+#include <atomic>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <camera/camera2/ICameraDeviceCallbacks.h>
+#include <camera/camera2/ICameraDeviceUser.h>
+
+#include <NdkCameraDevice.h>
+#include "ACameraMetadata.h"
+
+
+using namespace android;
+
+namespace android {
+
+struct CameraDevice final : public RefBase {
+ public:
+ CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars,
+ ACameraDevice* wrapper);
+ ~CameraDevice();
+
+ inline const char* getId() const { return mCameraId.string(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const;
+
+ // Callbacks from camera service
+ class ServiceCallback : public BnCameraDeviceCallbacks {
+ public:
+ ServiceCallback(CameraDevice* device) : mDevice(device) {}
+ void onDeviceError(CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) override;
+ void onDeviceIdle() override;
+ void onCaptureStarted(const CaptureResultExtras& resultExtras,
+ int64_t timestamp) override;
+ void onResultReceived(const CameraMetadata& metadata,
+ const CaptureResultExtras& resultExtras) override;
+ void onPrepared(int streamId) override;
+ private:
+ const wp<CameraDevice> mDevice;
+ };
+ inline sp<ICameraDeviceCallbacks> getServiceCallback() { return mServiceCallback; };
+
+ // Camera device is only functional after remote being set
+ void setRemoteDevice(sp<ICameraDeviceUser> remote);
+
+ private:
+ void disconnectLocked(); // disconnect from camera service
+ camera_status_t checkCameraClosedOrErrorLocked() const;
+
+
+ mutable Mutex mDeviceLock;
+ const String8 mCameraId; // Camera ID
+ const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
+ const std::unique_ptr<ACameraMetadata> mChars; // Camera characteristics
+ const sp<ServiceCallback> mServiceCallback;
+ ACameraDevice* mWrapper;
+
+ // TODO: maybe a bool will suffice for synchronous implementation?
+ std::atomic_bool mClosing;
+ inline bool isClosed() { return mClosing; }
+
+ bool mInError;
+ camera_status_t mError;
+ void onCaptureErrorLocked(
+ ICameraDeviceCallbacks::CameraErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
+
+ bool mIdle;
+
+ sp<ICameraDeviceUser> mRemote;
+
+ // Looper thread to handle callback to app
+ sp<ALooper> mCbLooper;
+ // definition of handler and message
+ enum {
+ kWhatOnDisconnected,
+ kWhatOnError
+ };
+ static const char* kContextKey;
+ static const char* kDeviceKey;
+ static const char* kErrorCodeKey;
+ static const char* kCallbackKey;
+ class CallbackHandler : public AHandler {
+ public:
+ CallbackHandler() {}
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ };
+ sp<CallbackHandler> mHandler;
+
+ inline ACameraDevice* getWrapper() { return mWrapper; };
+
+ // TODO: might need another looper/handler to handle callbacks from service
+
+
+};
+
+} // namespace android;
+
+/**
+ * ACameraDevice opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraDevice {
+ ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ std::unique_ptr<ACameraMetadata> chars) :
+ mDevice(new CameraDevice(id, cb, std::move(chars), this)) {}
+
+ ~ACameraDevice() {};
+
+ inline const char* getId() const { return mDevice->getId(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const {
+ return mDevice->createCaptureRequest(templateId, request);
+ }
+
+ inline sp<ICameraDeviceCallbacks> getServiceCallback() {
+ return mDevice->getServiceCallback();
+ };
+
+ // Camera device is only functional after remote being set
+ inline void setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ mDevice->setRemoteDevice(remote);
+ }
+
+ private:
+ // TODO: might need an API to give wp of mDevice to capture session
+ sp<CameraDevice> mDevice;
+};
+
+#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
new file mode 100644
index 0000000..4014fd2
--- /dev/null
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -0,0 +1,478 @@
+/*
+ * 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 "ACameraManager"
+
+#include <memory>
+#include "ACameraManager.h"
+#include "ACameraMetadata.h"
+#include "ACameraDevice.h"
+#include <utils/Vector.h>
+#include <stdlib.h>
+#include <camera/VendorTagDescriptor.h>
+
+using namespace android;
+
+//constants shared between ACameraManager and CameraManagerGlobal
+namespace {
+ const int kMaxCameraIdLen = 32;
+}
+
+namespace android {
+// Static member definitions
+const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
+const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
+const char* CameraManagerGlobal::kContextKey = "CallbackContext";
+Mutex CameraManagerGlobal::sLock;
+CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
+
+CameraManagerGlobal&
+CameraManagerGlobal::getInstance() {
+ Mutex::Autolock _l(sLock);
+ CameraManagerGlobal* instance = sInstance;
+ if (instance == nullptr) {
+ instance = new CameraManagerGlobal();
+ sInstance = instance;
+ }
+ return *instance;
+}
+
+CameraManagerGlobal::~CameraManagerGlobal() {
+ // clear sInstance so next getInstance call knows to create a new one
+ Mutex::Autolock _sl(sLock);
+ sInstance = nullptr;
+ Mutex::Autolock _l(mLock);
+ if (mCameraService != nullptr) {
+ IInterface::asBinder(mCameraService)->unlinkToDeath(mDeathNotifier);
+ }
+ mDeathNotifier.clear();
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+ mCameraServiceListener.clear();
+ mCameraService.clear();
+}
+
+sp<ICameraService> CameraManagerGlobal::getCameraService() {
+ Mutex::Autolock _l(mLock);
+ if (mCameraService.get() == nullptr) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16(kCameraServiceName));
+ if (binder != nullptr) {
+ break;
+ }
+ ALOGW("CameraService not published, waiting...");
+ usleep(kCameraServicePollDelay);
+ } while(true);
+ if (mDeathNotifier == nullptr) {
+ mDeathNotifier = new DeathNotifier(this);
+ }
+ binder->linkToDeath(mDeathNotifier);
+ mCameraService = interface_cast<ICameraService>(binder);
+
+ // Setup looper thread to perfrom availiability callbacks
+ if (mCbLooper == nullptr) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-mgr-looper");
+ status_t ret = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_FOREGROUND);
+ if (mHandler == nullptr) {
+ mHandler = new CallbackHandler();
+ }
+ mCbLooper->registerHandler(mHandler);
+ }
+
+ // register ICameraServiceListener
+ if (mCameraServiceListener == nullptr) {
+ mCameraServiceListener = new CameraServiceListener(this);
+ }
+ mCameraService->addListener(mCameraServiceListener);
+
+ // setup vendor tags
+ sp<VendorTagDescriptor> desc;
+ status_t ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc);
+
+ if (ret == OK) {
+ ret = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+ if (ret != OK) {
+ ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
+ __FUNCTION__, strerror(-ret), ret);
+ }
+ } else if (ret == -EOPNOTSUPP) {
+ ALOGW("%s: Camera HAL too old; does not support vendor tags",
+ __FUNCTION__);
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ } else {
+ ALOGE("%s: Failed to get vendor tag descriptors, received error %s (%d)",
+ __FUNCTION__, strerror(-ret), ret);
+ }
+ }
+ ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
+ return mCameraService;
+}
+
+void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
+{
+ ALOGE("Camera service binderDied!");
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ AutoMutex lock(cm->mLock);
+ for (auto pair : cm->mDeviceStatusMap) {
+ int32_t cameraId = pair.first;
+ cm->onStatusChangedLocked(
+ ICameraServiceListener::STATUS_NOT_PRESENT, cameraId);
+ }
+ cm->mCameraService.clear();
+ // TODO: consider adding re-connect call here?
+ }
+}
+
+void CameraManagerGlobal::registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ auto pair = mCallbacks.insert(cb);
+ // Send initial callbacks if callback is newly registered
+ if (pair.second) {
+ for (auto pair : mDeviceStatusMap) {
+ int32_t cameraId = pair.first;
+ Status status = pair.second;
+
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cb = isStatusAvailable(status) ?
+ callback->onCameraAvailable : callback->onCameraUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cb);
+ msg->setPointer(kContextKey, callback->context);
+ msg->setInt32(kCameraIdKey, cameraId);
+ msg->post();
+ }
+ }
+}
+
+void CameraManagerGlobal::unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
+bool CameraManagerGlobal::validStatus(Status status) {
+ switch (status) {
+ case ICameraServiceListener::STATUS_NOT_PRESENT:
+ case ICameraServiceListener::STATUS_PRESENT:
+ case ICameraServiceListener::STATUS_ENUMERATING:
+ case ICameraServiceListener::STATUS_NOT_AVAILABLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CameraManagerGlobal::isStatusAvailable(Status status) {
+ switch (status) {
+ case ICameraServiceListener::STATUS_PRESENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void CameraManagerGlobal::CallbackHandler::sendSingleCallback(
+ int32_t cameraId, void* context,
+ ACameraManager_AvailabilityCallback cb) const {
+ char cameraIdStr[kMaxCameraIdLen];
+ snprintf(cameraIdStr, sizeof(cameraIdStr), "%d", cameraId);
+ (*cb)(context, cameraIdStr);
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatSendSingleCallback:
+ {
+ ACameraManager_AvailabilityCallback cb;
+ void* context;
+ int32_t cameraId;
+ bool found = msg->findPointer(kCallbackFpKey, (void**) &cb);
+ if (!found) {
+ ALOGE("%s: Cannot find camera callback fp!", __FUNCTION__);
+ return;
+ }
+ found = msg->findPointer(kContextKey, &context);
+ if (!found) {
+ ALOGE("%s: Cannot find callback context!", __FUNCTION__);
+ return;
+ }
+ found = msg->findInt32(kCameraIdKey, &cameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+ return;
+ }
+ sendSingleCallback(cameraId, context, cb);
+ break;
+ }
+ default:
+ ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+ break;
+ }
+}
+
+void CameraManagerGlobal::CameraServiceListener::onStatusChanged(
+ Status status, int32_t cameraId) {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm == nullptr) {
+ ALOGE("Cannot deliver status change. Camera service died");
+ return;
+ }
+ cm->onStatusChanged(status, cameraId);
+}
+
+void CameraManagerGlobal::onStatusChanged(
+ Status status, int32_t cameraId) {
+ Mutex::Autolock _l(mLock);
+ onStatusChangedLocked(status, cameraId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+ Status status, int32_t cameraId) {
+ if (!validStatus(status)) {
+ ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ return;
+ }
+
+ bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
+ Status oldStatus = firstStatus ?
+ status : // first status
+ mDeviceStatusMap[cameraId];
+
+ if (!firstStatus &&
+ isStatusAvailable(status) == isStatusAvailable(oldStatus)) {
+ // No status update. No need to send callback
+ return;
+ }
+
+ // Iterate through all registered callbacks
+ mDeviceStatusMap[cameraId] = status;
+ for (auto cb : mCallbacks) {
+ sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
+ ACameraManager_AvailabilityCallback cbFp = isStatusAvailable(status) ?
+ cb.mAvailable : cb.mUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFp);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setInt32(kCameraIdKey, cameraId);
+ msg->post();
+ }
+}
+
+} // namespace android
+
+/**
+ * ACameraManger Implementation
+ */
+camera_status_t
+ACameraManager::getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList) {
+ if (mCachedCameraIdList.numCameras == kCameraIdListNotInit) {
+ int numCameras = 0;
+ Vector<char *> cameraIds;
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ // Get number of cameras
+ int numAllCameras = cs->getNumberOfCameras(ICameraService::CAMERA_TYPE_ALL);
+ // Filter API2 compatible cameras and push to cameraIds
+ for (int i = 0; i < numAllCameras; i++) {
+ // TODO: Only suppot HALs that supports API2 directly now
+ status_t camera2Support = cs->supportsCameraApi(i, ICameraService::API_VERSION_2);
+ char buf[kMaxCameraIdLen];
+ if (camera2Support == OK) {
+ numCameras++;
+ mCameraIds.insert(i);
+ snprintf(buf, sizeof(buf), "%d", i);
+ size_t cameraIdSize = strlen(buf) + 1;
+ char *cameraId = new char[cameraIdSize];
+ if (!cameraId) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ strlcpy(cameraId, buf, cameraIdSize);
+ cameraIds.push(cameraId);
+ }
+ }
+ mCachedCameraIdList.numCameras = numCameras;
+ mCachedCameraIdList.cameraIds = new const char*[numCameras];
+ if (!mCachedCameraIdList.cameraIds) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ for (int i = 0; i < numCameras; i++) {
+ mCachedCameraIdList.cameraIds[i] = cameraIds[i];
+ }
+ }
+ *cameraIdList = &mCachedCameraIdList;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
+ Mutex::Autolock _l(mLock);
+ ACameraIdList* cachedList;
+ camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Get camera ID list failed! err: %d", ret);
+ return ret;
+ }
+
+ int numCameras = cachedList->numCameras;
+ ACameraIdList *out = new ACameraIdList;
+ if (!out) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ out->numCameras = numCameras;
+ out->cameraIds = new const char*[numCameras];
+ if (!out->cameraIds) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ for (int i = 0; i < numCameras; i++) {
+ const char* src = cachedList->cameraIds[i];
+ size_t dstSize = strlen(src) + 1;
+ char* dst = new char[dstSize];
+ if (!dst) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ strlcpy(dst, src, dstSize);
+ out->cameraIds[i] = dst;
+ }
+ *cameraIdList = out;
+ return ACAMERA_OK;
+}
+
+void
+ACameraManager::deleteCameraIdList(ACameraIdList* cameraIdList) {
+ if (cameraIdList != nullptr) {
+ if (cameraIdList->cameraIds != nullptr) {
+ for (int i = 0; i < cameraIdList->numCameras; i ++) {
+ delete[] cameraIdList->cameraIds[i];
+ }
+ delete[] cameraIdList->cameraIds;
+ }
+ delete cameraIdList;
+ }
+}
+
+camera_status_t ACameraManager::getCameraCharacteristics(
+ const char *cameraIdStr, ACameraMetadata **characteristics) {
+ Mutex::Autolock _l(mLock);
+ ACameraIdList* cachedList;
+ // Make sure mCameraIds is initialized
+ camera_status_t ret = getOrCreateCameraIdListLocked(&cachedList);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: Get camera ID list failed! err: %d", __FUNCTION__, ret);
+ return ret;
+ }
+ int cameraId = atoi(cameraIdStr);
+ if (mCameraIds.count(cameraId) == 0) {
+ ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, cameraIdStr);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawMetadata;
+ status_t serviceRet = cs->getCameraCharacteristics(cameraId, &rawMetadata);
+ if (serviceRet != OK) {
+ ALOGE("Get camera characteristics from camera service failed! Err %d", ret);
+ return ACAMERA_ERROR_UNKNOWN; // should not reach here
+ }
+
+ *characteristics = new ACameraMetadata(
+ rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraManager::openCamera(
+ const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** outDevice) {
+ ACameraMetadata* rawChars;
+ camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
+ Mutex::Autolock _l(mLock);
+ if (ret != ACAMERA_OK) {
+ ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
+ __FUNCTION__, cameraId, ret);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ std::unique_ptr<ACameraMetadata> chars(rawChars);
+ rawChars = nullptr;
+
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(chars));
+
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+
+ int id = atoi(cameraId);
+ sp<ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
+ sp<ICameraDeviceUser> deviceRemote;
+ // No way to get package name from native.
+ // Send a zero length package name and let camera service figure it out from UID
+ status_t serviceRet = cs->connectDevice(
+ callbacks, id, String16(""),
+ ICameraService::USE_CALLING_UID, /*out*/deviceRemote);
+
+ if (serviceRet != OK) {
+ ALOGE("%s: connect camera device failed! err %d", __FUNCTION__, serviceRet);
+ // TODO: generate better error message here
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ if (deviceRemote == nullptr) {
+ ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ device->setRemoteDevice(deviceRemote);
+ *outDevice = device;
+ return ACAMERA_OK;
+}
+
+ACameraManager::~ACameraManager() {
+ Mutex::Autolock _l(mLock);
+ if (mCachedCameraIdList.numCameras != kCameraIdListNotInit) {
+ for (int i = 0; i < mCachedCameraIdList.numCameras; i++) {
+ delete[] mCachedCameraIdList.cameraIds[i];
+ }
+ delete[] mCachedCameraIdList.cameraIds;
+ }
+}
+
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
new file mode 100644
index 0000000..b68685d
--- /dev/null
+++ b/camera/ndk/impl/ACameraManager.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ACAMERA_MANAGER_H
+#define _ACAMERA_MANAGER_H
+
+#include "NdkCameraManager.h"
+
+#include <camera/CameraMetadata.h>
+#include <camera/ICameraService.h>
+#include <camera/ICameraServiceListener.h>
+#include <binder/IServiceManager.h>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <set>
+#include <map>
+
+using namespace android;
+
+namespace android {
+
+/**
+ * Per-process singleton instance of CameraManger. Shared by all ACameraManager
+ * instances. Created when first ACameraManager is created and destroyed when
+ * all ACameraManager instances are deleted.
+ *
+ * TODO: maybe CameraManagerGlobal is better sutied in libcameraclient?
+ */
+class CameraManagerGlobal final : public RefBase {
+ public:
+ static CameraManagerGlobal& getInstance();
+ sp<ICameraService> getCameraService();
+
+ void registerAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback);
+ void unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback);
+
+ private:
+ sp<ICameraService> mCameraService;
+ const int kCameraServicePollDelay = 500000; // 0.5s
+ const char* kCameraServiceName = "media.camera";
+ Mutex mLock;
+
+ class DeathNotifier : public IBinder::DeathRecipient {
+ public:
+ DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ protected:
+ // IBinder::DeathRecipient implementation
+ virtual void binderDied(const wp<IBinder>& who);
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<DeathNotifier> mDeathNotifier;
+
+ class CameraServiceListener final : public BnCameraServiceListener {
+ public:
+ CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ virtual void onStatusChanged(Status status, int32_t cameraId);
+
+ // Torch API not implemented yet
+ virtual void onTorchStatusChanged(TorchStatus, const String16&) {};
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<CameraServiceListener> mCameraServiceListener;
+
+ // Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
+ struct Callback {
+ Callback(const ACameraManager_AvailabilityCallbacks *callback) :
+ mAvailable(callback->onCameraAvailable),
+ mUnavailable(callback->onCameraUnavailable),
+ mContext(callback->context) {}
+
+ bool operator == (const Callback& other) const {
+ return (mAvailable == other.mAvailable &&
+ mUnavailable == other.mUnavailable &&
+ mContext == other.mContext);
+ }
+ bool operator != (const Callback& other) const {
+ return !(*this == other);
+ }
+ bool operator < (const Callback& other) const {
+ if (*this == other) return false;
+ if (mContext != other.mContext) return mContext < other.mContext;
+ if (mAvailable != other.mAvailable) return mAvailable < other.mAvailable;
+ return mUnavailable < other.mUnavailable;
+ }
+ bool operator > (const Callback& other) const {
+ return (*this != other && !(*this < other));
+ }
+ ACameraManager_AvailabilityCallback mAvailable;
+ ACameraManager_AvailabilityCallback mUnavailable;
+ void* mContext;
+ };
+ std::set<Callback> mCallbacks;
+
+ // definition of handler and message
+ enum {
+ kWhatSendSingleCallback
+ };
+ static const char* kCameraIdKey;
+ static const char* kCallbackFpKey;
+ static const char* kContextKey;
+ class CallbackHandler : public AHandler {
+ public:
+ CallbackHandler() {}
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ private:
+ inline void sendSingleCallback(
+ int32_t cameraId, void* context,
+ ACameraManager_AvailabilityCallback cb) const;
+ };
+ sp<CallbackHandler> mHandler;
+ sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+
+ typedef ICameraServiceListener::Status Status;
+ void onStatusChanged(Status status, int32_t cameraId);
+ void onStatusChangedLocked(Status status, int32_t cameraId);
+ // Utils for status
+ static bool validStatus(Status status);
+ static bool isStatusAvailable(Status status);
+
+ // Map camera_id -> status
+ std::map<int32_t, Status> mDeviceStatusMap;
+
+ // For the singleton instance
+ static Mutex sLock;
+ static CameraManagerGlobal* sInstance;
+ CameraManagerGlobal() {};
+ ~CameraManagerGlobal();
+};
+
+} // namespace android;
+
+/**
+ * ACameraManager opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraManager {
+ ACameraManager() :
+ mCachedCameraIdList({kCameraIdListNotInit, nullptr}),
+ mGlobalManager(&(CameraManagerGlobal::getInstance())) {}
+ ~ACameraManager();
+ camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
+ static void deleteCameraIdList(ACameraIdList* cameraIdList);
+
+ camera_status_t getCameraCharacteristics(
+ const char *cameraId, ACameraMetadata **characteristics);
+ camera_status_t openCamera(const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device);
+
+ private:
+ camera_status_t getOrCreateCameraIdListLocked(ACameraIdList** cameraIdList);
+
+ enum {
+ kCameraIdListNotInit = -1
+ };
+ Mutex mLock;
+ std::set<int> mCameraIds; // Init by getOrCreateCameraIdListLocked
+ ACameraIdList mCachedCameraIdList; // Init by getOrCreateCameraIdListLocked
+ sp<CameraManagerGlobal> mGlobalManager;
+};
+
+#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
new file mode 100644
index 0000000..25571c5
--- /dev/null
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 "ACameraMetadata"
+
+#include "ACameraMetadata.h"
+#include <utils/Vector.h>
+
+using namespace android;
+
+/**
+ * ACameraMetadata Implementation
+ */
+ACameraMetadata::ACameraMetadata(camera_metadata_t* buffer, ACAMERA_METADATA_TYPE type) :
+ mData(buffer), mType(type) {
+ filterUnsupportedFeatures();
+}
+
+bool
+ACameraMetadata::isNdkSupportedCapability(int32_t capability) {
+ switch (capability) {
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT:
+ return true;
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING:
+ case ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO:
+ return false;
+ default:
+ // Newly defined capabilities will be unsupported by default (blacklist)
+ // TODO: Should we do whitelist or blacklist here?
+ ALOGE("%s: Unknonwn capability %d", __FUNCTION__, capability);
+ return false;
+ }
+}
+
+void
+ACameraMetadata::filterUnsupportedFeatures() {
+ // Hide unsupported capabilities (reprocessing)
+ camera_metadata_entry entry = mData.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ if (entry.count == 0 || entry.type != ACAMERA_TYPE_BYTE) {
+ ALOGE("%s: malformed available capability key! count %zu, type %d",
+ __FUNCTION__, entry.count, entry.type);
+ return;
+ }
+
+ Vector<uint8_t> capabilities;
+ capabilities.setCapacity(entry.count);
+ for (size_t i = 0; i < entry.count; i++) {
+ uint8_t capability = entry.data.u8[i];
+ if (isNdkSupportedCapability(capability)) {
+ capabilities.push(capability);
+ }
+ }
+ mData.update(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capabilities);
+ // TODO: Hide unsupported streams (input/bidirectional streams)
+}
+
+bool
+ACameraMetadata::isVendorTag(const uint32_t tag) {
+ uint32_t tag_section = tag >> 16;
+ if (tag_section >= VENDOR_SECTION) {
+ return true;
+ }
+ return false;
+}
+
+camera_status_t
+ACameraMetadata::getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const {
+ if (entry == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ camera_metadata_ro_entry rawEntry = mData.find(tag);
+ if (rawEntry.count == 0) {
+ ALOGE("%s: cannot find metadata tag %d", __FUNCTION__, tag);
+ return ACAMERA_ERROR_METADATA_NOT_FOUND;
+ }
+ entry->tag = tag;
+ entry->type = rawEntry.type;
+ entry->count = rawEntry.count;
+ entry->data.u8 = rawEntry.data.u8;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const uint8_t* data) {
+ return updateImpl<uint8_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const int32_t* data) {
+ return updateImpl<int32_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const float* data) {
+ return updateImpl<float>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const double* data) {
+ return updateImpl<double>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const int64_t* data) {
+ return updateImpl<int64_t>(tag, count, data);
+}
+
+camera_status_t
+ACameraMetadata::update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data) {
+ return updateImpl<camera_metadata_rational_t>(tag, count, data);
+}
+
+
+// TODO: some of key below should be hidden from user
+// ex: ACAMERA_REQUEST_ID and ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR
+/*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+ * The key entries below this point are generated from metadata
+ * definitions in /system/media/camera/docs. Do not modify by hand or
+ * modify the comment blocks at the start or end.
+ *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
+
+bool
+ACameraMetadata::isCaptureRequestTag(const uint32_t tag) {
+ // Skip check for vendor keys
+ if (isVendorTag(tag)) {
+ return true;
+ }
+
+ switch (tag) {
+ case ACAMERA_COLOR_CORRECTION_MODE:
+ case ACAMERA_COLOR_CORRECTION_TRANSFORM:
+ case ACAMERA_COLOR_CORRECTION_GAINS:
+ case ACAMERA_COLOR_CORRECTION_ABERRATION_MODE:
+ case ACAMERA_CONTROL_AE_ANTIBANDING_MODE:
+ case ACAMERA_CONTROL_AE_EXPOSURE_COMPENSATION:
+ case ACAMERA_CONTROL_AE_LOCK:
+ case ACAMERA_CONTROL_AE_MODE:
+ case ACAMERA_CONTROL_AE_REGIONS:
+ case ACAMERA_CONTROL_AE_TARGET_FPS_RANGE:
+ case ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER:
+ case ACAMERA_CONTROL_AF_MODE:
+ case ACAMERA_CONTROL_AF_REGIONS:
+ case ACAMERA_CONTROL_AF_TRIGGER:
+ case ACAMERA_CONTROL_AWB_LOCK:
+ case ACAMERA_CONTROL_AWB_MODE:
+ case ACAMERA_CONTROL_AWB_REGIONS:
+ case ACAMERA_CONTROL_CAPTURE_INTENT:
+ case ACAMERA_CONTROL_EFFECT_MODE:
+ case ACAMERA_CONTROL_MODE:
+ case ACAMERA_CONTROL_SCENE_MODE:
+ case ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE:
+ case ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST:
+ case ACAMERA_EDGE_MODE:
+ case ACAMERA_FLASH_MODE:
+ case ACAMERA_HOT_PIXEL_MODE:
+ case ACAMERA_JPEG_GPS_COORDINATES:
+ case ACAMERA_JPEG_GPS_PROCESSING_METHOD:
+ case ACAMERA_JPEG_GPS_TIMESTAMP:
+ case ACAMERA_JPEG_ORIENTATION:
+ case ACAMERA_JPEG_QUALITY:
+ case ACAMERA_JPEG_THUMBNAIL_QUALITY:
+ case ACAMERA_JPEG_THUMBNAIL_SIZE:
+ case ACAMERA_LENS_APERTURE:
+ case ACAMERA_LENS_FILTER_DENSITY:
+ case ACAMERA_LENS_FOCAL_LENGTH:
+ case ACAMERA_LENS_FOCUS_DISTANCE:
+ case ACAMERA_LENS_OPTICAL_STABILIZATION_MODE:
+ case ACAMERA_NOISE_REDUCTION_MODE:
+ case ACAMERA_REQUEST_ID:
+ case ACAMERA_SCALER_CROP_REGION:
+ case ACAMERA_SENSOR_EXPOSURE_TIME:
+ case ACAMERA_SENSOR_FRAME_DURATION:
+ case ACAMERA_SENSOR_SENSITIVITY:
+ case ACAMERA_SENSOR_TEST_PATTERN_DATA:
+ case ACAMERA_SENSOR_TEST_PATTERN_MODE:
+ case ACAMERA_SHADING_MODE:
+ case ACAMERA_STATISTICS_FACE_DETECT_MODE:
+ case ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE:
+ case ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE:
+ case ACAMERA_TONEMAP_CURVE_BLUE:
+ case ACAMERA_TONEMAP_CURVE_GREEN:
+ case ACAMERA_TONEMAP_CURVE_RED:
+ case ACAMERA_TONEMAP_MODE:
+ case ACAMERA_TONEMAP_GAMMA:
+ case ACAMERA_TONEMAP_PRESET_CURVE:
+ case ACAMERA_LED_TRANSMIT:
+ case ACAMERA_BLACK_LEVEL_LOCK:
+ case ACAMERA_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
+ * End generated code
+ *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
new file mode 100644
index 0000000..36a9a9a
--- /dev/null
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ACAMERA_METADATA_H
+#define _ACAMERA_METADATA_H
+
+#include <sys/types.h>
+#include <camera/CameraMetadata.h>
+
+#include "NdkCameraMetadata.h"
+
+using namespace android;
+
+/**
+ * ACameraMetadata opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraMetadata {
+ public:
+ typedef enum {
+ ACM_CHARACTERISTICS, // Read only
+ ACM_REQUEST, // Read/Write
+ ACM_RESULT, // Read only
+ } ACAMERA_METADATA_TYPE;
+
+ // Takes ownership of pass-in buffer
+ ACameraMetadata(camera_metadata_t *buffer, ACAMERA_METADATA_TYPE type);
+ // Clone
+ ACameraMetadata(const ACameraMetadata& other) :
+ mData(other.mData), mType(other.mType) {};
+
+ camera_status_t getConstEntry(uint32_t tag, ACameraMetadata_const_entry* entry) const;
+
+ camera_status_t update(uint32_t tag, uint32_t count, const uint8_t* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const int32_t* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const float* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const double* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const int64_t* data);
+ camera_status_t update(uint32_t tag, uint32_t count, const ACameraMetadata_rational* data);
+
+ private:
+ bool isNdkSupportedCapability(const int32_t capability);
+ inline bool isVendorTag(const uint32_t tag);
+ bool isCaptureRequestTag(const uint32_t tag);
+ void filterUnsupportedFeatures(); // Hide features not yet supported by NDK
+
+ template<typename INTERNAL_T, typename NDK_T>
+ camera_status_t updateImpl(uint32_t tag, uint32_t count, const NDK_T* data) {
+ if (mType != ACM_REQUEST) {
+ ALOGE("Error: Write to metadata is only allowed for capture request!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ if (!isCaptureRequestTag(tag)) {
+ ALOGE("Error: tag %d is not writable!", tag);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ // Here we have to use reinterpret_cast because the NDK data type is
+ // exact copy of internal data type but they do not inherit from each other
+ status_t ret = mData.update(tag, reinterpret_cast<const INTERNAL_T*>(data), count);
+ if (ret == OK) {
+ return ACAMERA_OK;
+ } else {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ CameraMetadata mData;
+ const ACAMERA_METADATA_TYPE mType;
+};
+
+#endif // _ACAMERA_METADATA_H
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
new file mode 100644
index 0000000..6bd8406
--- /dev/null
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef _ACAPTURE_REQUEST_H
+#define _ACAPTURE_REQUEST_H
+
+#include "NdkCaptureRequest.h"
+#include <set>
+
+using namespace android;
+
+struct ACameraOutputTarget {
+ ACameraOutputTarget(ANativeWindow* window) : mWindow(window) {};
+
+ bool operator == (const ACameraOutputTarget& other) const {
+ return mWindow == other.mWindow;
+ }
+ bool operator != (const ACameraOutputTarget& other) const {
+ return mWindow != other.mWindow;
+ }
+ bool operator < (const ACameraOutputTarget& other) const {
+ return mWindow < other.mWindow;
+ }
+ bool operator > (const ACameraOutputTarget& other) const {
+ return mWindow > other.mWindow;
+ }
+
+ ANativeWindow* mWindow;
+};
+
+struct ACameraOutputTargets {
+ std::set<ACameraOutputTarget> mOutputs;
+};
+
+struct ACaptureRequest {
+ ACameraMetadata* settings;
+ ACameraOutputTargets* targets;
+};
+
+#endif // _ACAPTURE_REQUEST_H
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 78a1b58..a36d2f9 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -243,16 +243,36 @@
};
+namespace {
+ Mutex gLock;
+ class DeathNotifier : public IBinder::DeathRecipient
+ {
+ public:
+ DeathNotifier() {}
+
+ virtual void binderDied(const wp<IBinder>& /*who*/) {
+ ALOGV("binderDied");
+ Mutex::Autolock _l(gLock);
+ ALOGW("Camera service died!");
+ }
+ };
+ sp<DeathNotifier> gDeathNotifier;
+}; // anonymous namespace
+
// 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);
+ if (gDeathNotifier == NULL) {
+ gDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(gDeathNotifier);
sp<ICameraService> service = interface_cast<ICameraService>(binder);
- int32_t numCameras = service->getNumberOfCameras();
+ int32_t numCameras = service->getNumberOfCameras(ICameraService::CAMERA_TYPE_ALL);
EXPECT_LE(0, numCameras);
// Check listener binder calls