Create a vendor available version of libcamera2ndk.
Bug: 110364143
Test: mm -j64
Test: AImageReaderVendorTest
Change-Id: Ic9343cc7fb10eb374197945b72be59e7ce8282fe
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index e84eeef..60c9f85 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -70,3 +70,81 @@
],
version_script: "libcamera2ndk.map.txt",
}
+
+cc_library_shared {
+ name: "libcamera2ndk_vendor",
+ vendor_available: true,
+ srcs: [
+ "ndk_vendor/impl/ACameraDevice.cpp",
+ "ndk_vendor/impl/ACameraManager.cpp",
+ "ndk_vendor/impl/utils.cpp",
+ "impl/ACameraMetadata.cpp",
+ "impl/ACameraCaptureSession.cpp",
+ "NdkCameraMetadata.cpp",
+ "NdkCameraCaptureSession.cpp",
+ "NdkCameraManager.cpp",
+ "NdkCameraDevice.cpp",
+ "NdkCaptureRequest.cpp",
+ ],
+
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "libcutils",
+ ],
+ local_include_dirs: [
+ ".",
+ "include",
+ "impl",
+ ],
+ cflags: [
+ "-fvisibility=hidden",
+ "-DEXPORT=__attribute__((visibility(\"default\")))",
+ "-D__ANDROID_VNDK__",
+ ],
+
+ shared_libs: [
+ "libhwbinder",
+ "libfmq",
+ "libhidlbase",
+ "libhardware",
+ "libnativewindow",
+ "liblog",
+ "libutils",
+ "libstagefright_foundation",
+ "libcutils",
+ "libcamera_metadata",
+ "libmediandk",
+ "android.frameworks.cameraservice.device@2.0",
+ "android.frameworks.cameraservice.common@2.0",
+ "android.frameworks.cameraservice.service@2.0",
+ ],
+
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper",
+ "libarect",
+ ],
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test {
+ name: "AImageReaderVendorTest",
+ vendor: true,
+ srcs: ["ndk_vendor/tests/AImageReaderVendorTest.cpp"],
+ shared_libs: [
+ "libhwbinder",
+ "libcamera2ndk_vendor",
+ "libmediandk",
+ "libnativewindow",
+ "libutils",
+ "libui",
+ "libcutils",
+ "liblog",
+ ],
+ cflags: [
+ "-D__ANDROID_VNDK__",
+ ],
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 812a312..ef05e0b 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -24,7 +24,15 @@
#include <camera/NdkCameraDevice.h>
#include "impl/ACameraCaptureSession.h"
-using namespace android;
+using namespace android::acam;
+
+bool areWindowTypesEqual(ACameraWindowType *a, ACameraWindowType *b) {
+#ifdef __ANDROID_VNDK__
+ return utils::isWindowNativeHandleEqual(a, b);
+#else
+ return a == b;
+#endif
+}
EXPORT
camera_status_t ACameraDevice_close(ACameraDevice* device) {
@@ -96,7 +104,7 @@
EXPORT
camera_status_t ACaptureSessionOutput_create(
- ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+ ACameraWindowType* window, /*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -109,7 +117,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_create(
- ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
+ ACameraWindowType* window, /*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -122,7 +130,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
- ANativeWindow* window) {
+ ACameraWindowType* window) {
ATRACE_CALL();
if ((window == nullptr) || (out == nullptr)) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -134,7 +142,7 @@
__FUNCTION__);
return ACAMERA_ERROR_INVALID_OPERATION;
}
- if (out->mWindow == window) {
+ if (areWindowTypesEqual(out->mWindow, window)) {
ALOGE("%s: Error trying to add the same window associated with the output configuration",
__FUNCTION__);
return ACAMERA_ERROR_INVALID_PARAMETER;
@@ -147,7 +155,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *out,
- ANativeWindow* window) {
+ ACameraWindowType* window) {
ATRACE_CALL();
if ((window == nullptr) || (out == nullptr)) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -159,7 +167,7 @@
__FUNCTION__);
return ACAMERA_ERROR_INVALID_OPERATION;
}
- if (out->mWindow == window) {
+ if (areWindowTypesEqual(out->mWindow, window)) {
ALOGE("%s: Error trying to remove the same window associated with the output configuration",
__FUNCTION__);
return ACAMERA_ERROR_INVALID_PARAMETER;
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index f14a4c9..8742d9c 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -22,10 +22,15 @@
#include <utils/Trace.h>
#include <camera/NdkCameraManager.h>
+
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACameraManager.h"
+#else
#include "impl/ACameraManager.h"
+#endif
#include "impl/ACameraMetadata.h"
-using namespace android;
+using namespace android::acam;
EXPORT
ACameraManager* ACameraManager_create() {
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index ddb69d7..c64de3e 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -27,7 +27,7 @@
EXPORT
camera_status_t ACameraOutputTarget_create(
- ANativeWindow* window, ACameraOutputTarget** out) {
+ ACameraWindowType* window, ACameraOutputTarget** out) {
ATRACE_CALL();
if (window == nullptr) {
ALOGE("%s: Error: input window is null", __FUNCTION__);
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index f60e5fd..fb72bdb 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -23,7 +23,7 @@
ACameraCaptureSession::~ACameraCaptureSession() {
ALOGV("~ACameraCaptureSession: %p notify device end of life", this);
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev != nullptr && !dev->isClosed()) {
dev->lockDeviceForSessionOps();
{
@@ -48,7 +48,7 @@
mClosedByApp = true;
}
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev != nullptr) {
dev->lockDeviceForSessionOps();
}
@@ -73,7 +73,7 @@
camera_status_t
ACameraCaptureSession::stopRepeating() {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -91,7 +91,7 @@
camera_status_t
ACameraCaptureSession::abortCaptures() {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -112,7 +112,7 @@
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -133,7 +133,7 @@
/*optional*/ACameraCaptureSession_captureCallbacks* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -149,7 +149,7 @@
}
camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -168,7 +168,7 @@
ACameraDevice*
ACameraCaptureSession::getDevice() {
Mutex::Autolock _l(mSessionLock);
- sp<CameraDevice> dev = getDeviceSp();
+ sp<acam::CameraDevice> dev = getDeviceSp();
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return nullptr;
@@ -182,9 +182,9 @@
mIsClosed = true;
}
-sp<CameraDevice>
+sp<acam::CameraDevice>
ACameraCaptureSession::getDeviceSp() {
- sp<CameraDevice> device = mDevice.promote();
+ sp<acam::CameraDevice> device = mDevice.promote();
if (device == nullptr || device->isClosed()) {
ALOGW("Device is closed but session %d is not notified", mId);
return nullptr;
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index a2068e7..133c2c8 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -19,12 +19,17 @@
#include <set>
#include <hardware/camera3.h>
#include <camera/NdkCameraDevice.h>
+
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "ndk_vendor/impl/ACameraCaptureSessionVendor.h"
+#else
#include "ACameraDevice.h"
using namespace android;
struct ACaptureSessionOutput {
- explicit ACaptureSessionOutput(ANativeWindow* window, bool isShared = false) :
+ explicit ACaptureSessionOutput(ACameraWindowType* window, bool isShared = false) :
mWindow(window), mIsShared(isShared) {};
bool operator == (const ACaptureSessionOutput& other) const {
@@ -40,11 +45,12 @@
return mWindow > other.mWindow;
}
- ANativeWindow* mWindow;
- std::set<ANativeWindow *> mSharedWindows;
+ ACameraWindowType* mWindow;
+ std::set<ACameraWindowType *> mSharedWindows;
bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
};
+#endif
struct ACaptureSessionOutputContainer {
std::set<ACaptureSessionOutput> mOutputs;
@@ -60,7 +66,7 @@
int id,
const ACaptureSessionOutputContainer* outputs,
const ACameraCaptureSession_stateCallbacks* cb,
- CameraDevice* device) :
+ android::acam::CameraDevice* device) :
mId(id), mOutput(*outputs), mUserSessionCallback(*cb),
mDevice(device) {}
@@ -97,18 +103,18 @@
ACameraDevice* getDevice();
private:
- friend class CameraDevice;
+ friend class android::acam::CameraDevice;
// Close session because app close camera device, camera device got ERROR_DISCONNECTED,
// or a new session is replacing this session.
void closeByDevice();
- sp<CameraDevice> getDeviceSp();
+ sp<android::acam::CameraDevice> getDeviceSp();
const int mId;
const ACaptureSessionOutputContainer mOutput;
const ACameraCaptureSession_stateCallbacks mUserSessionCallback;
- const wp<CameraDevice> mDevice;
+ const wp<android::acam::CameraDevice> mDevice;
bool mIsClosed = false;
bool mClosedByApp = false;
Mutex mSessionLock;
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index ac3be25..00da54e 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -27,9 +27,9 @@
#include "ACaptureRequest.h"
#include "ACameraCaptureSession.h"
-using namespace android;
-
namespace android {
+namespace acam {
+
// Static member definitions
const char* CameraDevice::kContextKey = "Context";
const char* CameraDevice::kDeviceKey = "Device";
@@ -1513,5 +1513,5 @@
return ret;
}
-
+} // namespace acam
} // namespace android
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 7d64081..8f56d3f 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -41,6 +41,7 @@
#include "ACameraMetadata.h"
namespace android {
+namespace acam {
// Wrap ACameraCaptureFailure so it can be ref-counted
struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure {};
@@ -286,6 +287,7 @@
};
+} // namespace acam;
} // namespace android;
/**
@@ -295,7 +297,7 @@
struct ACameraDevice {
ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars) :
- mDevice(new CameraDevice(id, cb, chars, this)) {}
+ mDevice(new android::acam::CameraDevice(id, cb, chars, this)) {}
~ACameraDevice() {};
@@ -331,7 +333,7 @@
}
private:
- android::sp<android::CameraDevice> mDevice;
+ android::sp<android::acam::CameraDevice> mDevice;
};
#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index ee67677..7d6ecac 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -26,9 +26,10 @@
#include <stdlib.h>
#include <camera/VendorTagDescriptor.h>
-using namespace android;
+using namespace android::acam;
namespace android {
+namespace acam {
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
const char* CameraManagerGlobal::kCallbackFpKey = "CallbackFp";
@@ -345,6 +346,7 @@
}
}
+} // namespace acam
} // namespace android
/**
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index ce65769..55bfa7e 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -35,6 +35,7 @@
#include <map>
namespace android {
+namespace acam {
/**
* Per-process singleton instance of CameraManger. Shared by all ACameraManager
@@ -172,6 +173,7 @@
~CameraManagerGlobal();
};
+} // namespace acam;
} // namespace android;
/**
@@ -180,7 +182,7 @@
*/
struct ACameraManager {
ACameraManager() :
- mGlobalManager(&(android::CameraManagerGlobal::getInstance())) {}
+ mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
~ACameraManager();
camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
static void deleteCameraIdList(ACameraIdList* cameraIdList);
@@ -196,7 +198,7 @@
kCameraIdListNotInit = -1
};
android::Mutex mLock;
- android::sp<android::CameraManagerGlobal> mGlobalManager;
+ android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
};
#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/impl/ACameraMetadata.h b/camera/ndk/impl/ACameraMetadata.h
index e76b80c..f21dbaf 100644
--- a/camera/ndk/impl/ACameraMetadata.h
+++ b/camera/ndk/impl/ACameraMetadata.h
@@ -22,7 +22,13 @@
#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
+
+#ifdef __ANDROID_VNDK__
+#include <CameraMetadata.h>
+using CameraMetadata = android::hardware::camera::common::V1_0::helper::CameraMetadata;
+#else
#include <camera/CameraMetadata.h>
+#endif
#include <camera/NdkCameraMetadata.h>
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index b11dafb..5c82ab7 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -21,8 +21,11 @@
using namespace android;
+#ifdef __ANDROID_VNDK__
+#include "ndk_vendor/impl/ACaptureRequestVendor.h"
+#else
struct ACameraOutputTarget {
- explicit ACameraOutputTarget(ANativeWindow* window) : mWindow(window) {};
+ explicit ACameraOutputTarget(ACameraWindowType* window) : mWindow(window) {};
bool operator == (const ACameraOutputTarget& other) const {
return mWindow == other.mWindow;
@@ -37,8 +40,9 @@
return mWindow > other.mWindow;
}
- ANativeWindow* mWindow;
+ ACameraWindowType* mWindow;
};
+#endif
struct ACameraOutputTargets {
std::set<ACameraOutputTarget> mOutputs;
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 5e0db60..1244582 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -35,10 +35,10 @@
#include <sys/cdefs.h>
#include <stdbool.h>
-#include <android/native_window.h>
#include "NdkCameraError.h"
#include "NdkCameraMetadata.h"
#include "NdkCaptureRequest.h"
+#include "NdkCameraWindowType.h"
#ifndef _NDK_CAMERA_CAPTURE_SESSION_H
#define _NDK_CAMERA_CAPTURE_SESSION_H
@@ -246,7 +246,7 @@
*/
typedef void (*ACameraCaptureSession_captureCallback_bufferLost)(
void* context, ACameraCaptureSession* session,
- ACaptureRequest* request, ANativeWindow* window, int64_t frameNumber);
+ ACaptureRequest* request, ACameraWindowType* window, int64_t frameNumber);
typedef struct ACameraCaptureSession_captureCallbacks {
/// optional application context.
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 7c13b34..4fe43d5 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -34,10 +34,10 @@
*/
#include <sys/cdefs.h>
-#include <android/native_window.h>
#include "NdkCameraError.h"
#include "NdkCaptureRequest.h"
#include "NdkCameraCaptureSession.h"
+#include "NdkCameraWindowType.h"
#ifndef _NDK_CAMERA_DEVICE_H
#define _NDK_CAMERA_DEVICE_H
@@ -345,7 +345,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionOutput_create(
- ANativeWindow* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(24);
+ ACameraWindowType* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(24);
/**
* Free a ACaptureSessionOutput object.
@@ -694,7 +694,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionSharedOutput_create(
- ANativeWindow* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(28);
+ ACameraWindowType* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(28);
/**
* Add a native window to shared ACaptureSessionOutput.
@@ -712,7 +712,7 @@
* ACaptureSessionOutput.</li></ul>
*/
camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output,
- ANativeWindow *anw) __INTRODUCED_IN(28);
+ ACameraWindowType *anw) __INTRODUCED_IN(28);
/**
* Remove a native window from shared ACaptureSessionOutput.
@@ -728,7 +728,7 @@
* ACaptureSessionOutput.</li></ul>
*/
camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *output,
- ANativeWindow* anw) __INTRODUCED_IN(28);
+ ACameraWindowType* anw) __INTRODUCED_IN(28);
/**
* Create a new camera capture session similar to {@link ACameraDevice_createCaptureSession}. This
diff --git a/camera/ndk/include/camera/NdkCameraWindowType.h b/camera/ndk/include/camera/NdkCameraWindowType.h
new file mode 100644
index 0000000..99f67e9
--- /dev/null
+++ b/camera/ndk/include/camera/NdkCameraWindowType.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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 _NDK_CAMERA_WINDOW_TYPE_H
+#define _NDK_CAMERA_WINDOW_TYPE_H
+
+/**
+ * @addtogroup Camera
+ * @{
+ */
+
+/**
+ * @file NdkCameraWindowType.h
+ */
+
+/*
+ * This file defines an NDK API.
+ * Do not remove methods.
+ * Do not change method signatures.
+ * Do not change the value of constants.
+ * Do not change the size of any of the classes defined in here.
+ * Do not reference types that are not part of the NDK.
+ * Do not #include files that aren't part of the NDK.
+ */
+
+/**
+ * This file defines the window type used by NDK and the VNDK variants of the
+ * camera2 NDK. This enables us to share the api definition headers and avoid
+ * code duplication (since the VNDK variant doesn't use ANativeWindow unlike the
+ * NDK variant).
+ */
+#ifdef __ANDROID_VNDK__
+#include <cutils/native_handle.h>
+typedef native_handle_t ACameraWindowType;
+#else
+#include <android/native_window.h>
+typedef ANativeWindow ACameraWindowType;
+#endif
+
+#endif //_NDK_CAMERA_WINDOW_TYPE_H
diff --git a/camera/ndk/include/camera/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h
index 5340e76..136989a 100644
--- a/camera/ndk/include/camera/NdkCaptureRequest.h
+++ b/camera/ndk/include/camera/NdkCaptureRequest.h
@@ -35,9 +35,9 @@
#include <sys/cdefs.h>
-#include <android/native_window.h>
#include "NdkCameraError.h"
#include "NdkCameraMetadata.h"
+#include "NdkCameraWindowType.h"
#ifndef _NDK_CAPTURE_REQUEST_H
#define _NDK_CAPTURE_REQUEST_H
@@ -101,7 +101,7 @@
*
* @see ACaptureRequest_addTarget
*/
-camera_status_t ACameraOutputTarget_create(ANativeWindow* window,
+camera_status_t ACameraOutputTarget_create(ACameraWindowType* window,
ACameraOutputTarget** output) __INTRODUCED_IN(24);
/**
diff --git a/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
new file mode 100644
index 0000000..8d9e90c
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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 "utils.h"
+
+struct ACaptureSessionOutput {
+ explicit ACaptureSessionOutput(native_handle_t* window, bool isShared = false) :
+ mWindow(window), mIsShared(isShared) {};
+
+ bool operator == (const ACaptureSessionOutput& other) const {
+ return (mWindow == other.mWindow);
+ }
+
+ bool operator != (const ACaptureSessionOutput& other) const {
+ return mWindow != other.mWindow;
+ }
+
+ bool operator < (const ACaptureSessionOutput& other) const {
+ return mWindow < other.mWindow;
+ }
+
+ bool operator > (const ACaptureSessionOutput& other) const {
+ return mWindow > other.mWindow;
+ }
+
+ android::acam::utils::native_handle_ptr_wrapper mWindow;
+ std::set<android::acam::utils::native_handle_ptr_wrapper> mSharedWindows;
+ bool mIsShared;
+ int mRotation = CAMERA3_STREAM_ROTATION_0;
+};
+
+
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
new file mode 100644
index 0000000..b86f854
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -0,0 +1,1594 @@
+/*
+ * Copyright (C) 2018 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 "ACameraDeviceVendor"
+
+#include <vector>
+#include <inttypes.h>
+#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <CameraMetadata.h>
+
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "ACameraCaptureSession.h"
+#include "ACameraMetadata.h"
+#include "ACaptureRequest.h"
+#include "utils.h"
+
+using namespace android;
+
+namespace android {
+namespace acam {
+
+using HCameraMetadata = frameworks::cameraservice::device::V2_0::CameraMetadata;
+using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
+using hardware::Void;
+
+// Static member definitions
+const char* CameraDevice::kContextKey = "Context";
+const char* CameraDevice::kDeviceKey = "Device";
+const char* CameraDevice::kErrorCodeKey = "ErrorCode";
+const char* CameraDevice::kCallbackFpKey = "Callback";
+const char* CameraDevice::kSessionSpKey = "SessionSp";
+const char* CameraDevice::kCaptureRequestKey = "CaptureRequest";
+const char* CameraDevice::kTimeStampKey = "TimeStamp";
+const char* CameraDevice::kCaptureResultKey = "CaptureResult";
+const char* CameraDevice::kCaptureFailureKey = "CaptureFailure";
+const char* CameraDevice::kSequenceIdKey = "SequenceId";
+const char* CameraDevice::kFrameNumberKey = "FrameNumber";
+const char* CameraDevice::kAnwKey = "Anw";
+
+/**
+ * CameraDevice Implementation
+ */
+CameraDevice::CameraDevice(
+ const char* id,
+ ACameraDevice_StateCallbacks* cb,
+ sp<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),
+ mCurrentSession(nullptr) {
+ mClosing = false;
+ // Setup looper thread to perfrom device callbacks to app
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-dev-looper");
+ status_t err = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (err != OK) {
+ ALOGE("%s: Unable to start camera device callback looper: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ }
+ mHandler = new CallbackHandler();
+ mCbLooper->registerHandler(mHandler);
+
+ const CameraMetadata& metadata = mChars->getInternalData();
+ camera_metadata_ro_entry entry = metadata.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
+ if (entry.count != 1) {
+ ALOGW("%s: bad count %zu for partial result count", __FUNCTION__, entry.count);
+ mPartialResultCount = 1;
+ } else {
+ mPartialResultCount = entry.data.i32[0];
+ }
+
+ entry = metadata.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+ if (entry.count != 2) {
+ ALOGW("%s: bad count %zu for shading map size", __FUNCTION__, entry.count);
+ mShadingMapSize[0] = 0;
+ mShadingMapSize[1] = 0;
+ } else {
+ mShadingMapSize[0] = entry.data.i32[0];
+ mShadingMapSize[1] = entry.data.i32[1];
+ }
+}
+
+// Device close implementaiton
+CameraDevice::~CameraDevice() {
+ sp<ACameraCaptureSession> session = mCurrentSession.promote();
+ {
+ Mutex::Autolock _l(mDeviceLock);
+ if (!isClosed()) {
+ disconnectLocked(session);
+ }
+ mCurrentSession = nullptr;
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+}
+
+void
+CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
+ msg->post();
+ msg.clear();
+ sp<AMessage> cleanupMsg = new AMessage(kWhatCleanUpSessions, mHandler);
+ cleanupMsg->post();
+}
+
+// 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 status = Status::NO_ERROR;
+ auto remoteRet = mRemote->createDefaultRequest(
+ utils::convertToHidl(templateId),
+ [&status, &rawRequest](auto s, const hidl_vec<uint8_t> &metadata) {
+ status = s;
+ if (status == Status::NO_ERROR && utils::convertFromHidlCloned(metadata, &rawRequest)) {
+ } else {
+ ALOGE("%s: Couldn't create default request", __FUNCTION__);
+ }
+ });
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Transaction error while trying to create default request %s", __FUNCTION__,
+ remoteRet.description().c_str());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ if (status != Status::NO_ERROR) {
+ return utils::convertFromHidl(status);
+ }
+ ACaptureRequest* outReq = new ACaptureRequest();
+ outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ outReq->targets = new ACameraOutputTargets();
+ *request = outReq;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ sp<ACameraCaptureSession> currentSession = mCurrentSession.promote();
+ Mutex::Autolock _l(mDeviceLock);
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (currentSession != nullptr) {
+ currentSession->closeByDevice();
+ stopRepeatingLocked();
+ }
+
+ // Create new session
+ ret = configureStreamsLocked(outputs, sessionParameters);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Fail to create new session. cannot configure streams");
+ return ret;
+ }
+
+ ACameraCaptureSession* newSession = new ACameraCaptureSession(
+ mNextSessionId++, outputs, callbacks, this);
+
+ // set new session as current session
+ newSession->incStrong((void *) ACameraDevice_createCaptureSession);
+ mCurrentSession = newSession;
+ mFlushing = false;
+ *session = newSession;
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::captureLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
+}
+
+camera_status_t
+CameraDevice::setRepeatingRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId) {
+ return submitRequestsLocked(
+ session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
+}
+
+void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
+ sp<CaptureRequest> &req) {
+ CameraMetadata metadataCopy = aCaptureRequest->settings->getInternalData();
+ const camera_metadata_t *camera_metadata = metadataCopy.getAndLock();
+ HCameraMetadata hCameraMetadata;
+ utils::convertToHidl(camera_metadata, &hCameraMetadata);
+ metadataCopy.unlock(camera_metadata);
+ req->mPhysicalCameraSettings.resize(1);
+ req->mPhysicalCameraSettings[0].settings.metadata(std::move(hCameraMetadata));
+}
+
+camera_status_t
+CameraDevice::submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId,
+ bool isRepeating) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Form two vectors of capture request, one for internal tracking
+ std::vector<frameworks::cameraservice::device::V2_0::CaptureRequest> requestList;
+ Vector<sp<CaptureRequest>> requestsV;
+ requestsV.setCapacity(numRequests);
+ for (int i = 0; i < numRequests; i++) {
+ sp<CaptureRequest> req;
+ ret = allocateCaptureRequest(requests[i], req);
+ // We need to call this method since after submitRequestList is called,
+ // the request metadata queue might have removed the capture request
+ // metadata. Therefore we simply add the metadata to its wrapper class,
+ // so that it can be retrived later.
+ addRequestSettingsMetadata(requests[i], req);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Convert capture request to internal format failure! ret %d", ret);
+ return ret;
+ }
+ if (req->mCaptureRequest.streamAndWindowIds.size() == 0) {
+ ALOGE("Capture request without output target cannot be submitted!");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ requestList.push_back(utils::convertToHidl(req.get()));
+ requestsV.push_back(req);
+ }
+ if (isRepeating) {
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ }
+
+ SubmitInfo info;
+ Status status;
+ auto remoteRet = mRemote->submitRequestList(requestList, isRepeating,
+ [&status, &info](auto s, auto &submitInfo) {
+ status = s;
+ info = submitInfo;
+ });
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Transaction error for submitRequestList call: %s", __FUNCTION__,
+ remoteRet.description().c_str());
+ }
+ if (status != Status::NO_ERROR) {
+ return utils::convertFromHidl(status);
+ }
+ int32_t sequenceId = info.requestId;
+ int64_t lastFrameNumber = info.lastFrameNumber;
+ if (sequenceId < 0) {
+ ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ CallbackHolder cbHolder(session, requestsV, isRepeating, cbs);
+ mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+
+ if (isRepeating) {
+ // stopRepeating above should have cleanup repeating sequence id
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ mRepeatingSequenceId = sequenceId;
+ } else {
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+ }
+
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = false;
+ mBusySession = session;
+
+ if (captureSequenceId) {
+ *captureSequenceId = sequenceId;
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ if (output == nullptr) {
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!output->mIsShared) {
+ ALOGE("Error output configuration is not shared");
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ int32_t streamId = -1;
+ for (auto& kvPair : mConfiguredOutputs) {
+ if (utils::isWindowNativeHandleEqual(kvPair.second.first, output->mWindow)) {
+ streamId = kvPair.first;
+ break;
+ }
+ }
+ if (streamId < 0) {
+ ALOGE("Error: Invalid output configuration");
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+
+ OutputConfigurationWrapper outConfigW;
+ OutputConfiguration &outConfig = outConfigW.mOutputConfiguration;
+ outConfig.rotation = utils::convertToHidl(output->mRotation);
+ outConfig.windowGroupId = -1; // ndk doesn't support inter OutputConfiguration buffer sharing.
+ outConfig.windowHandles.resize(output->mSharedWindows.size() + 1);
+ outConfig.windowHandles[0] = output->mWindow;
+ int i = 1;
+ for (auto& anw : output->mSharedWindows) {
+ outConfig.windowHandles[i++] = anw;
+ }
+
+ auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Transaction error in updating OutputConfiguration: %s", __FUNCTION__,
+ remoteRet.description().c_str());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ switch (remoteRet) {
+ case Status::NO_ERROR:
+ break;
+ case Status::INVALID_OPERATION:
+ ALOGE("Camera device %s invalid operation", getId());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ case Status::ALREADY_EXISTS:
+ ALOGE("Camera device %s output surface already exists", getId());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ case Status::ILLEGAL_ARGUMENT:
+ ALOGE("Camera device %s invalid input argument", getId());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ default:
+ ALOGE("Camera device %s failed to add shared output", getId());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+
+ mConfiguredOutputs[streamId] = std::make_pair(output->mWindow, outConfigW);
+
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::allocateCaptureRequest(
+ const ACaptureRequest* request, /*out*/sp<CaptureRequest> &outReq) {
+ sp<CaptureRequest> req(new CaptureRequest());
+ req->mCaptureRequest.physicalCameraSettings.resize(1);
+ req->mCaptureRequest.physicalCameraSettings[0].id = mCameraId;
+ // TODO: Do we really need to copy the metadata here ?
+ CameraMetadata metadataCopy = request->settings->getInternalData();
+ const camera_metadata_t *cameraMetadata = metadataCopy.getAndLock();
+ HCameraMetadata hCameraMetadata;
+ utils::convertToHidl(cameraMetadata, &hCameraMetadata);
+ metadataCopy.unlock(cameraMetadata);
+ if (request->settings != nullptr) {
+ if (hCameraMetadata.data() != nullptr &&
+ mCaptureRequestMetadataQueue != nullptr &&
+ mCaptureRequestMetadataQueue->write(
+ reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
+ hCameraMetadata.size())) {
+ // The metadata field of the union would've been destructued, so no need
+ // to re-size it.
+ req->mCaptureRequest.physicalCameraSettings[0].settings.fmqMetadataSize(
+ hCameraMetadata.size());
+ } else {
+ ALOGE("Fmq write capture result failed, falling back to hwbinder");
+ req->mCaptureRequest.physicalCameraSettings[0].settings.metadata(
+ std::move(hCameraMetadata));
+ }
+ }
+
+ std::vector<int32_t> requestStreamIdxList;
+ std::vector<int32_t> requestSurfaceIdxList;
+ for (auto outputTarget : request->targets->mOutputs) {
+ native_handle_t* anw = outputTarget.mWindow;
+ bool found = false;
+ req->mSurfaceList.push_back(anw);
+ // lookup stream/surface ID
+ for (const auto& kvPair : mConfiguredOutputs) {
+ int streamId = kvPair.first;
+ const OutputConfigurationWrapper& outConfig = kvPair.second.second;
+ const auto& windowHandles = outConfig.mOutputConfiguration.windowHandles;
+ for (int surfaceId = 0; surfaceId < (int) windowHandles.size(); surfaceId++) {
+ // If two native handles are equivalent, so are their surfaces.
+ if (utils::isWindowNativeHandleEqual(windowHandles[surfaceId].getNativeHandle(),
+ anw)) {
+ found = true;
+ requestStreamIdxList.push_back(streamId);
+ requestSurfaceIdxList.push_back(surfaceId);
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (!found) {
+ ALOGE("Unconfigured output target %p in capture request!", anw);
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ }
+ }
+ req->mCaptureRequest.streamAndWindowIds.resize(requestStreamIdxList.size());
+ for (int i = 0; i < requestStreamIdxList.size(); i++) {
+ req->mCaptureRequest.streamAndWindowIds[i].streamId = requestStreamIdxList[i];
+ req->mCaptureRequest.streamAndWindowIds[i].windowId = requestSurfaceIdxList[i];
+ }
+ outReq = req;
+ return ACAMERA_OK;
+}
+
+ACaptureRequest*
+CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
+ ACaptureRequest* pRequest = new ACaptureRequest();
+ CameraMetadata clone;
+ utils::convertFromHidlCloned(req->mPhysicalCameraSettings[0].settings.metadata(), &clone);
+ pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
+ pRequest->targets = new ACameraOutputTargets();
+ for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
+ native_handle_t* anw = req->mSurfaceList[i];
+ ACameraOutputTarget outputTarget(anw);
+ pRequest->targets->mOutputs.insert(outputTarget);
+ }
+ return pRequest;
+}
+
+void
+CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
+ if (req == nullptr) {
+ return;
+ }
+ req->settings.clear();
+ delete req->targets;
+ delete req;
+}
+
+void
+CameraDevice::notifySessionEndOfLifeLocked(ACameraCaptureSession* session) {
+ if (isClosed()) {
+ // Device is closing already. do nothing
+ return;
+ }
+
+ if (mCurrentSession != session) {
+ // Session has been replaced by other seesion or device is closed
+ return;
+ }
+ mCurrentSession = nullptr;
+
+ // Should not happen
+ if (!session->mIsClosed) {
+ ALOGE("Error: unclosed session %p reaches end of life!", session);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return;
+ }
+
+ // No new session, unconfigure now
+ camera_status_t ret = configureStreamsLocked(nullptr, nullptr);
+ if (ret != ACAMERA_OK) {
+ ALOGE("Unconfigure stream failed. Device might still be configured! ret %d", ret);
+ }
+}
+
+void
+CameraDevice::disconnectLocked(sp<ACameraCaptureSession>& session) {
+ if (mClosing.exchange(true)) {
+ // Already closing, just return
+ ALOGW("Camera device %s is already closing.", getId());
+ return;
+ }
+
+ if (mRemote != nullptr) {
+ auto ret = mRemote->disconnect();
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
+ ret.description().c_str());
+ }
+ }
+ mRemote = nullptr;
+
+ if (session != nullptr) {
+ session->closeByDevice();
+ }
+}
+
+camera_status_t
+CameraDevice::stopRepeatingLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+ return ret;
+ }
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ int repeatingSequenceId = mRepeatingSequenceId;
+ mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ int64_t lastFrameNumber;
+ Status status = Status::NO_ERROR;
+ auto remoteRet = mRemote->cancelRepeatingRequest(
+ [&status, &lastFrameNumber](Status s, auto frameNumber) {
+ status = s;
+ lastFrameNumber = frameNumber;
+ });
+ if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("%s: Unable to cancel active repeating request", __FUNCTION__);
+ return utils::convertFromHidl(status);
+ }
+ checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::flushLocked(ACameraCaptureSession* session) {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera %s abort captures failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ // This should never happen because creating a new session will close
+ // previous one and thus reject any API call from previous session.
+ // But still good to check here in case something unexpected happen.
+ if (mCurrentSession != session) {
+ ALOGE("Camera %s session %p is not current active session!", getId(), session);
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ if (mFlushing) {
+ ALOGW("Camera %s is already aborting captures", getId());
+ return ACAMERA_OK;
+ }
+
+ mFlushing = true;
+
+ // Send onActive callback to guarantee there is always active->ready transition
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+ postSessionMsgAndCleanup(msg);
+
+ // If device is already idling, send callback and exit early
+ if (mIdle) {
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onReady);
+ postSessionMsgAndCleanup(msg);
+ mFlushing = false;
+ return ACAMERA_OK;
+ }
+
+ int64_t lastFrameNumber;
+ Status status;
+ auto remoteRet = mRemote->flush([&status, &lastFrameNumber](auto s, auto frameNumber) {
+ status = s;
+ lastFrameNumber = frameNumber;
+ });
+ if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("%s: Abort captures failed", __FUNCTION__);
+ return utils::convertFromHidl(status);
+ }
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ checkRepeatingSequenceCompleteLocked(mRepeatingSequenceId, lastFrameNumber);
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::waitUntilIdleLocked() {
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Wait until camera %s idle failed! ret %d", getId(), ret);
+ return ret;
+ }
+
+ if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+ ALOGE("Camera device %s won't go to idle when there is repeating request!", getId());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ }
+
+ auto remoteRet = mRemote->waitUntilIdle();
+ if (!remoteRet.isOk()) {
+ ALOGE("%s: Transaction waitUntilIdle failed", __FUNCTION__);
+ return utils::convertFromHidl(remoteRet);
+ }
+ return ACAMERA_OK;
+}
+
+camera_status_t
+CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters) {
+ ACaptureSessionOutputContainer emptyOutput;
+ if (outputs == nullptr) {
+ outputs = &emptyOutput;
+ }
+
+ camera_status_t ret = checkCameraClosedOrErrorLocked();
+ if (ret != ACAMERA_OK) {
+ return ret;
+ }
+
+ std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> outputSet;
+ for (auto outConfig : outputs->mOutputs) {
+ native_handle_t* anw = outConfig.mWindow;
+ OutputConfigurationWrapper outConfigInsertW;
+ OutputConfiguration &outConfigInsert = outConfigInsertW.mOutputConfiguration;
+ outConfigInsert.rotation = utils::convertToHidl(outConfig.mRotation);
+ outConfigInsert.windowGroupId = -1;
+ outConfigInsert.windowHandles.resize(outConfig.mSharedWindows.size() + 1);
+ outConfigInsert.windowHandles[0] = anw;
+ native_handle_ptr_wrapper wrap(anw);
+ outputSet.insert(std::make_pair(anw, outConfigInsertW));
+ }
+ std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> addSet = outputSet;
+ std::vector<int32_t> deleteList;
+
+ // Determine which streams need to be created, which to be deleted
+ for (auto& kvPair : mConfiguredOutputs) {
+ int32_t streamId = kvPair.first;
+ auto& outputPair = kvPair.second;
+ if (outputSet.count(outputPair)) {
+ deleteList.push_back(streamId); // Need to delete a no longer needed stream
+ } else {
+ addSet.erase(outputPair); // No need to add already existing stream
+ }
+ }
+
+ ret = stopRepeatingLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s stop repeating failed, ret %d", getId(), ret);
+ return ret;
+ }
+
+ ret = waitUntilIdleLocked();
+ if (ret != ACAMERA_OK) {
+ ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
+ return ret;
+ }
+
+ // Send onReady to previous session
+ // CurrentSession will be updated after configureStreamLocked, so here
+ // mCurrentSession is the session to be replaced by a new session
+ if (!mIdle && mCurrentSession != nullptr) {
+ if (mBusySession != mCurrentSession) {
+ ALOGE("Current session != busy session");
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ACAMERA_ERROR_CAMERA_DEVICE;
+ }
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+ msg->setPointer(kContextKey, mBusySession->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, mBusySession);
+ msg->setPointer(kCallbackFpKey, (void*) mBusySession->mUserSessionCallback.onReady);
+ mBusySession.clear();
+ postSessionMsgAndCleanup(msg);
+ }
+ mIdle = true;
+
+ auto remoteRet = mRemote->beginConfigure();
+ if (!remoteRet.isOk()|| remoteRet != Status::NO_ERROR) {
+ ALOGE("Camera device %s begin configure failed", getId());
+ return utils::convertFromHidl(remoteRet);
+ }
+
+ // delete to-be-deleted streams
+ for (auto streamId : deleteList) {
+ remoteRet = mRemote->deleteStream(streamId);
+ if (!remoteRet.isOk() || remoteRet != Status::NO_ERROR) {
+ ALOGE("Camera device %s failed to remove stream %d", getId(), streamId);
+ return utils::convertFromHidl(remoteRet);
+ }
+ mConfiguredOutputs.erase(streamId);
+ }
+
+ // add new streams
+ for (auto outputPair : addSet) {
+ int streamId;
+ Status status;
+ auto ret = mRemote->createStream(outputPair.second,
+ [&status, &streamId](Status s, auto stream_id) {
+ status = s;
+ streamId = stream_id;
+ });
+ if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("Camera device %s failed to create stream", getId());
+ return utils::convertFromHidl(status);
+ }
+ mConfiguredOutputs.insert(std::make_pair(streamId, outputPair));
+ }
+
+ CameraMetadata params;
+ HCameraMetadata hidlParams;
+ if ((sessionParameters != nullptr) && (sessionParameters->settings != nullptr)) {
+ params.append(sessionParameters->settings->getInternalData());
+ const camera_metadata_t *params_metadata = params.getAndLock();
+ utils::convertToHidl(params_metadata, &hidlParams);
+ params.unlock(params_metadata);
+ remoteRet = mRemote->endConfigure(StreamConfigurationMode::NORMAL_MODE, hidlParams);
+ }
+ if (!remoteRet.isOk()) {
+ ALOGE("Transaction error: endConfigure failed %s", remoteRet.description().c_str());
+ }
+
+ return utils::convertFromHidl(remoteRet);
+}
+
+void
+CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+ Mutex::Autolock _l(mDeviceLock);
+ mRemote = remote;
+}
+
+bool
+CameraDevice::setDeviceMetadataQueues() {
+ if (mRemote == nullptr) {
+ ALOGE("mRemote must not be null while trying to fetch metadata queues");
+ return false;
+ }
+ std::shared_ptr<RequestMetadataQueue> &reqQueue = mCaptureRequestMetadataQueue;
+ auto ret =
+ mRemote->getCaptureRequestMetadataQueue(
+ [&reqQueue](const auto &mqDescriptor) {
+ reqQueue = std::make_shared<RequestMetadataQueue>(mqDescriptor);
+ if (!reqQueue->isValid() || reqQueue->availableToWrite() <=0) {
+ ALOGE("Empty fmq from cameraserver");
+ reqQueue = nullptr;
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("Transaction error trying to get capture request metadata queue");
+ return false;
+ }
+ std::shared_ptr<ResultMetadataQueue> &resQueue = mCaptureResultMetadataQueue;
+ ret =
+ mRemote->getCaptureResultMetadataQueue(
+ [&resQueue](const auto &mqDescriptor) {
+ resQueue = std::make_shared<ResultMetadataQueue>(mqDescriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <=0) {
+ ALOGE("Empty fmq from cameraserver");
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("Transaction error trying to get capture result metadata queue");
+ return false;
+ }
+ return true;
+}
+
+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::setCameraDeviceErrorLocked(camera_status_t error) {
+ mInError = true;
+ mError = error;
+ return;
+}
+
+void
+CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
+ ALOGV("updateTracker frame %" PRId64 " isError %d", frameNumber, isError);
+ if (isError) {
+ mFutureErrorSet.insert(frameNumber);
+ } else if (frameNumber <= mCompletedFrameNumber) {
+ ALOGE("Frame number %" PRId64 " decreased! current fn %" PRId64,
+ frameNumber, mCompletedFrameNumber);
+ return;
+ } else {
+ if (frameNumber != mCompletedFrameNumber + 1) {
+ ALOGE("Frame number out of order. Expect %" PRId64 " but get %" PRId64,
+ mCompletedFrameNumber + 1, frameNumber);
+ // Do not assert as in java implementation
+ }
+ mCompletedFrameNumber = frameNumber;
+ }
+ update();
+}
+
+void
+CameraDevice::FrameNumberTracker::update() {
+ for (auto it = mFutureErrorSet.begin(); it != mFutureErrorSet.end();) {
+ int64_t errorFrameNumber = *it;
+ if (errorFrameNumber == mCompletedFrameNumber + 1) {
+ mCompletedFrameNumber++;
+ it = mFutureErrorSet.erase(it);
+ } else if (errorFrameNumber <= mCompletedFrameNumber) {
+ // This should not happen, but deal with it anyway
+ ALOGE("Completd frame number passed through current frame number!");
+ // erase the old error since it's no longer useful
+ it = mFutureErrorSet.erase(it);
+ } else {
+ // Normal requests hasn't catched up error frames, just break
+ break;
+ }
+ }
+ ALOGV("Update complete frame %" PRId64, mCompletedFrameNumber);
+}
+
+void
+CameraDevice::onCaptureErrorLocked(
+ ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
+ int sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+ auto it = mSequenceCallbackMap.find(sequenceId);
+ if (it == mSequenceCallbackMap.end()) {
+ ALOGE("%s: Error: capture sequence index %d not found!",
+ __FUNCTION__, sequenceId);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+
+ CallbackHolder cbh = (*it).second;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+
+ // Handle buffer error
+ if (errorCode == ErrorCode::CAMERA_BUFFER) {
+ int32_t streamId = resultExtras.errorStreamId;
+ ACameraCaptureSession_captureCallback_bufferLost onBufferLost =
+ cbh.mCallbacks.onCaptureBufferLost;
+ auto outputPairIt = mConfiguredOutputs.find(streamId);
+ if (outputPairIt == mConfiguredOutputs.end()) {
+ ALOGE("%s: Error: stream id %d does not exist", __FUNCTION__, streamId);
+ setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ return;
+ }
+
+ const auto& windowHandles = outputPairIt->second.second.mOutputConfiguration.windowHandles;
+ for (const auto& outHandle : windowHandles) {
+ for (auto streamAndWindowId : request->mCaptureRequest.streamAndWindowIds) {
+ int32_t windowId = streamAndWindowId.windowId;
+ if (utils::isWindowNativeHandleEqual(windowHandles[windowId],outHandle)) {
+ native_handle_t* anw =
+ const_cast<native_handle_t *>(windowHandles[windowId].getNativeHandle());
+ ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
+ getId(), anw, frameNumber);
+
+ sp<AMessage> msg = new AMessage(kWhatCaptureBufferLost, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onBufferLost);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setPointer(kAnwKey, (void*) anw);
+ msg->setInt64(kFrameNumberKey, frameNumber);
+ postSessionMsgAndCleanup(msg);
+ }
+ }
+ }
+ } else { // Handle other capture failures
+ // Fire capture failure callback if there is one registered
+ ACameraCaptureSession_captureCallback_failed onError = cbh.mCallbacks.onCaptureFailed;
+ sp<CameraCaptureFailure> failure(new CameraCaptureFailure());
+ failure->frameNumber = frameNumber;
+ // TODO: refine this when implementing flush
+ failure->reason = CAPTURE_FAILURE_REASON_ERROR;
+ failure->sequenceId = sequenceId;
+ failure->wasImageCaptured = (errorCode == ErrorCode::CAMERA_RESULT);
+
+ sp<AMessage> msg = new AMessage(kWhatCaptureFail, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onError);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setObject(kCaptureFailureKey, failure);
+ postSessionMsgAndCleanup(msg);
+
+ // Update tracker
+ mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
+ checkAndFireSequenceCompleteLocked();
+ }
+ return;
+}
+
+void CameraDevice::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ case kWhatOnError:
+ case kWhatSessionStateCb:
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatCaptureSeqEnd:
+ case kWhatCaptureSeqAbort:
+ case kWhatCaptureBufferLost:
+ ALOGV("%s: Received msg %d", __FUNCTION__, msg->what());
+ break;
+ case kWhatCleanUpSessions:
+ mCachedSessions.clear();
+ return;
+ 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;
+ }
+ switch (msg->what()) {
+ case kWhatOnDisconnected:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_StateCallback onDisconnected;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onDisconnected);
+ if (!found) {
+ ALOGE("%s: Cannot find onDisconnected!", __FUNCTION__);
+ return;
+ }
+ if (onDisconnected == nullptr) {
+ return;
+ }
+ (*onDisconnected)(context, dev);
+ break;
+ }
+ case kWhatOnError:
+ {
+ ACameraDevice* dev;
+ found = msg->findPointer(kDeviceKey, (void**) &dev);
+ if (!found || dev == nullptr) {
+ ALOGE("%s: Cannot find device pointer!", __FUNCTION__);
+ return;
+ }
+ ACameraDevice_ErrorStateCallback onError;
+ found = msg->findPointer(kCallbackFpKey, (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;
+ }
+ if (onError == nullptr) {
+ return;
+ }
+ (*onError)(context, dev, errorCode);
+ break;
+ }
+ case kWhatSessionStateCb:
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatCaptureSeqEnd:
+ case kWhatCaptureSeqAbort:
+ case kWhatCaptureBufferLost:
+ {
+ sp<RefBase> obj;
+ found = msg->findObject(kSessionSpKey, &obj);
+ if (!found || obj == nullptr) {
+ ALOGE("%s: Cannot find session pointer!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
+ mCachedSessions.push(session);
+ sp<CaptureRequest> requestSp = nullptr;
+ switch (msg->what()) {
+ case kWhatCaptureStart:
+ case kWhatCaptureResult:
+ case kWhatCaptureFail:
+ case kWhatCaptureBufferLost:
+ found = msg->findObject(kCaptureRequestKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture request!", __FUNCTION__);
+ return;
+ }
+ requestSp = static_cast<CaptureRequest*>(obj.get());
+ break;
+ }
+
+ switch (msg->what()) {
+ case kWhatSessionStateCb:
+ {
+ ACameraCaptureSession_stateCallback onState;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onState);
+ if (!found) {
+ ALOGE("%s: Cannot find state callback!", __FUNCTION__);
+ return;
+ }
+ if (onState == nullptr) {
+ return;
+ }
+ (*onState)(context, session.get());
+ break;
+ }
+ case kWhatCaptureStart:
+ {
+ ACameraCaptureSession_captureCallback_start onStart;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onStart);
+ if (!found) {
+ ALOGE("%s: Cannot find capture start callback!", __FUNCTION__);
+ return;
+ }
+ if (onStart == nullptr) {
+ return;
+ }
+ int64_t timestamp;
+ found = msg->findInt64(kTimeStampKey, ×tamp);
+ if (!found) {
+ ALOGE("%s: Cannot find timestamp!", __FUNCTION__);
+ return;
+ }
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onStart)(context, session.get(), request, timestamp);
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureResult:
+ {
+ ACameraCaptureSession_captureCallback_result onResult;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onResult);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result callback!", __FUNCTION__);
+ return;
+ }
+ if (onResult == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureResultKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture result!", __FUNCTION__);
+ return;
+ }
+ sp<ACameraMetadata> result(static_cast<ACameraMetadata*>(obj.get()));
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onResult)(context, session.get(), request, result.get());
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureFail:
+ {
+ ACameraCaptureSession_captureCallback_failed onFail;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onFail);
+ if (!found) {
+ ALOGE("%s: Cannot find capture fail callback!", __FUNCTION__);
+ return;
+ }
+ if (onFail == nullptr) {
+ return;
+ }
+
+ found = msg->findObject(kCaptureFailureKey, &obj);
+ if (!found) {
+ ALOGE("%s: Cannot find capture failure!", __FUNCTION__);
+ return;
+ }
+ sp<CameraCaptureFailure> failureSp(
+ static_cast<CameraCaptureFailure*>(obj.get()));
+ ACameraCaptureFailure* failure =
+ static_cast<ACameraCaptureFailure*>(failureSp.get());
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onFail)(context, session.get(), request, failure);
+ freeACaptureRequest(request);
+ break;
+ }
+ case kWhatCaptureSeqEnd:
+ {
+ ACameraCaptureSession_captureCallback_sequenceEnd onSeqEnd;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onSeqEnd);
+ if (!found) {
+ ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+ return;
+ }
+ if (onSeqEnd == nullptr) {
+ return;
+ }
+ int seqId;
+ found = msg->findInt32(kSequenceIdKey, &seqId);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ (*onSeqEnd)(context, session.get(), seqId, frameNumber);
+ break;
+ }
+ case kWhatCaptureSeqAbort:
+ {
+ ACameraCaptureSession_captureCallback_sequenceAbort onSeqAbort;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onSeqAbort);
+ if (!found) {
+ ALOGE("%s: Cannot find sequence end callback!", __FUNCTION__);
+ return;
+ }
+ if (onSeqAbort == nullptr) {
+ return;
+ }
+ int seqId;
+ found = msg->findInt32(kSequenceIdKey, &seqId);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+ (*onSeqAbort)(context, session.get(), seqId);
+ break;
+ }
+ case kWhatCaptureBufferLost:
+ {
+ ACameraCaptureSession_captureCallback_bufferLost onBufferLost;
+ found = msg->findPointer(kCallbackFpKey, (void**) &onBufferLost);
+ if (!found) {
+ ALOGE("%s: Cannot find buffer lost callback!", __FUNCTION__);
+ return;
+ }
+ if (onBufferLost == nullptr) {
+ return;
+ }
+
+ native_handle_t* anw;
+ found = msg->findPointer(kAnwKey, (void**) &anw);
+ if (!found) {
+ ALOGE("%s: Cannot find native_handle_t!", __FUNCTION__);
+ return;
+ }
+
+ int64_t frameNumber;
+ found = msg->findInt64(kFrameNumberKey, &frameNumber);
+ if (!found) {
+ ALOGE("%s: Cannot find frame number!", __FUNCTION__);
+ return;
+ }
+
+ ACaptureRequest* request = allocateACaptureRequest(requestSp);
+ (*onBufferLost)(context, session.get(), request, anw, frameNumber);
+ freeACaptureRequest(request);
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+CameraDevice::CallbackHolder::CallbackHolder(
+ sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest> >& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs) :
+ mSession(session), mRequests(requests),
+ mIsRepeating(isRepeating), mCallbacks(fillCb(cbs)) {}
+
+void
+CameraDevice::checkRepeatingSequenceCompleteLocked(
+ const int sequenceId, const int64_t lastFrameNumber) {
+ ALOGV("Repeating seqId %d lastFrameNumer %" PRId64, sequenceId, lastFrameNumber);
+ if (lastFrameNumber == NO_FRAMES_CAPTURED) {
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ return;
+ }
+ // remove callback holder from callback map
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+ mSequenceCallbackMap.erase(cbIt);
+ // send seq aborted callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqAbort, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceAborted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ postSessionMsgAndCleanup(msg);
+ } else {
+ // Use mSequenceLastFrameNumberMap to track
+ mSequenceLastFrameNumberMap.insert(std::make_pair(sequenceId, lastFrameNumber));
+
+ // Last frame might have arrived. Check now
+ checkAndFireSequenceCompleteLocked();
+ }
+}
+
+void
+CameraDevice::checkAndFireSequenceCompleteLocked() {
+ int64_t completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+ auto it = mSequenceLastFrameNumberMap.begin();
+ while (it != mSequenceLastFrameNumberMap.end()) {
+ int sequenceId = it->first;
+ int64_t lastFrameNumber = it->second;
+ bool seqCompleted = false;
+ bool hasCallback = true;
+
+ if (mRemote == nullptr) {
+ ALOGW("Camera %s closed while checking sequence complete", getId());
+ return;
+ }
+
+ // Check if there is callback for this sequence
+ // This should not happen because we always register callback (with nullptr inside)
+ if (mSequenceCallbackMap.count(sequenceId) == 0) {
+ ALOGW("No callback found for sequenceId %d", sequenceId);
+ hasCallback = false;
+ }
+
+ if (lastFrameNumber <= completedFrameNumber) {
+ ALOGV("seq %d reached last frame %" PRId64 ", completed %" PRId64,
+ sequenceId, lastFrameNumber, completedFrameNumber);
+ seqCompleted = true;
+ }
+
+ if (seqCompleted && hasCallback) {
+ // remove callback holder from callback map
+ auto cbIt = mSequenceCallbackMap.find(sequenceId);
+ CallbackHolder cbh = cbIt->second;
+ mSequenceCallbackMap.erase(cbIt);
+ // send seq complete callback
+ sp<AMessage> msg = new AMessage(kWhatCaptureSeqEnd, mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, cbh.mSession);
+ msg->setPointer(kCallbackFpKey, (void*) cbh.mCallbacks.onCaptureSequenceCompleted);
+ msg->setInt32(kSequenceIdKey, sequenceId);
+ msg->setInt64(kFrameNumberKey, lastFrameNumber);
+
+ // Clear the session sp before we send out the message
+ // This will guarantee the rare case where the message is processed
+ // before cbh goes out of scope and causing we call the session
+ // destructor while holding device lock
+ cbh.mSession.clear();
+ postSessionMsgAndCleanup(msg);
+ }
+
+ // No need to track sequence complete if there is no callback registered
+ if (seqCompleted || !hasCallback) {
+ it = mSequenceLastFrameNumberMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+/**
+ * Camera service callback implementation
+ */
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onDeviceError(
+ ErrorCode 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);
+ auto ret = Void();
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return ret; // device has been closed
+ }
+ switch (errorCode) {
+ case ErrorCode::CAMERA_DISCONNECTED:
+ {
+ // Camera is disconnected, close the session and expect no more callbacks
+ if (session != nullptr) {
+ session->closeByDevice();
+ }
+ dev->mCurrentSession = nullptr;
+ sp<AMessage> msg = new AMessage(kWhatOnDisconnected, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mAppCallbacks.context);
+ msg->setPointer(kDeviceKey, (void*) dev->getWrapper());
+ msg->setPointer(kCallbackFpKey, (void*) dev->mAppCallbacks.onDisconnected);
+ msg->post();
+ break;
+ }
+ default:
+ ALOGE("Unknown error from camera device: %d", errorCode);
+ [[fallthrough]];
+ case ErrorCode::CAMERA_DEVICE:
+ case ErrorCode::CAMERA_SERVICE:
+ {
+ int32_t errorVal = ::ERROR_CAMERA_DEVICE;
+ // We keep this switch since this block might be encountered with
+ // more than just 2 states. The default fallthrough could have us
+ // handling more unmatched error cases.
+ switch (errorCode) {
+ case ErrorCode::CAMERA_DEVICE:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ break;
+ case ErrorCode::CAMERA_SERVICE:
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ errorVal = ::ERROR_CAMERA_SERVICE;
+ break;
+ default:
+ dev->setCameraDeviceErrorLocked(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(kCallbackFpKey, (void*) dev->mAppCallbacks.onError);
+ msg->setInt32(kErrorCodeKey, errorVal);
+ msg->post();
+ break;
+ }
+ case ErrorCode::CAMERA_REQUEST:
+ case ErrorCode::CAMERA_RESULT:
+ case ErrorCode::CAMERA_BUFFER:
+ dev->onCaptureErrorLocked(errorCode, resultExtras);
+ break;
+ }
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onDeviceIdle() {
+ ALOGV("Camera is now idle");
+ auto ret = Void();
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+
+ if (dev->mIdle) {
+ // Already in idle state. Possibly other thread did waitUntilIdle
+ return ret;
+ }
+
+ if (dev->mCurrentSession != nullptr) {
+ ALOGE("onDeviceIdle sending state cb");
+ if (dev->mBusySession != dev->mCurrentSession) {
+ ALOGE("Current session != busy session");
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+ return ret;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
+ msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
+ msg->setObject(kSessionSpKey, dev->mBusySession);
+ msg->setPointer(kCallbackFpKey, (void*) dev->mBusySession->mUserSessionCallback.onReady);
+ // Make sure we clear the sp first so the session destructor can
+ // only happen on handler thread (where we don't hold device/session lock)
+ dev->mBusySession.clear();
+ dev->postSessionMsgAndCleanup(msg);
+ }
+ dev->mIdle = true;
+ dev->mFlushing = false;
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onCaptureStarted(
+ const CaptureResultExtras& resultExtras,
+ uint64_t timestamp) {
+ auto ret = Void();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->isClosed() || dev->mRemote == nullptr) {
+ return ret;
+ }
+
+ int32_t sequenceId = resultExtras.requestId;
+ int32_t burstId = resultExtras.burstId;
+
+ auto it = dev->mSequenceCallbackMap.find(sequenceId);
+ if (it != dev->mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ ACameraCaptureSession_captureCallback_start onStart = cbh.mCallbacks.onCaptureStarted;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<AMessage> msg = new AMessage(kWhatCaptureStart, dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onStart);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setInt64(kTimeStampKey, timestamp);
+ dev->postSessionMsgAndCleanup(msg);
+ }
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onResultReceived(
+ const FmqSizeOrMetadata& resultMetadata,
+ const CaptureResultExtras& resultExtras,
+ const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) {
+ (void) physicalResultInfos;
+ auto ret = Void();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+ int32_t sequenceId = resultExtras.requestId;
+ int64_t frameNumber = resultExtras.frameNumber;
+ int32_t burstId = resultExtras.burstId;
+ bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
+
+ if (!isPartialResult) {
+ ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+ if (dev->mRemote == nullptr) {
+ return ret; // device has been disconnected
+ }
+
+ if (dev->isClosed()) {
+ if (!isPartialResult) {
+ dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+ }
+ // early return to avoid callback sent to closed devices
+ return ret;
+ }
+
+ CameraMetadata metadataCopy;
+ HCameraMetadata hCameraMetadata;
+ bool converted = false;
+ if (resultMetadata.getDiscriminator() ==
+ FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
+ hCameraMetadata.resize(resultMetadata.fmqMetadataSize());
+ bool read = dev->mCaptureResultMetadataQueue->read(hCameraMetadata.data(),
+ resultMetadata.fmqMetadataSize());
+ if (!read) {
+ ALOGE("%s capture request settings could't be read from fmq",
+ __FUNCTION__);
+ return ret;
+ }
+ // TODO: Do we actually need to clone here ?
+ converted = utils::convertFromHidlCloned(hCameraMetadata, &metadataCopy);
+
+ } else {
+ converted = utils::convertFromHidlCloned(resultMetadata.metadata(), &metadataCopy);
+ }
+
+ if (!converted) {
+ ALOGE("%s result metadata couldn't be converted", __FUNCTION__);
+ return ret;
+ }
+
+ metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
+ metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
+
+ auto it = dev->mSequenceCallbackMap.find(sequenceId);
+ if (it != dev->mSequenceCallbackMap.end()) {
+ CallbackHolder cbh = (*it).second;
+ ACameraCaptureSession_captureCallback_result onResult = isPartialResult ?
+ cbh.mCallbacks.onCaptureProgressed :
+ cbh.mCallbacks.onCaptureCompleted;
+ sp<ACameraCaptureSession> session = cbh.mSession;
+ if ((size_t) burstId >= cbh.mRequests.size()) {
+ ALOGE("%s: Error: request index %d out of bound (size %zu)",
+ __FUNCTION__, burstId, cbh.mRequests.size());
+ dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
+ }
+ sp<CaptureRequest> request = cbh.mRequests[burstId];
+ sp<ACameraMetadata> result(new ACameraMetadata(
+ metadataCopy.release(), ACameraMetadata::ACM_RESULT));
+
+ sp<AMessage> msg = new AMessage(kWhatCaptureResult, dev->mHandler);
+ msg->setPointer(kContextKey, cbh.mCallbacks.context);
+ msg->setObject(kSessionSpKey, session);
+ msg->setPointer(kCallbackFpKey, (void*) onResult);
+ msg->setObject(kCaptureRequestKey, request);
+ msg->setObject(kCaptureResultKey, result);
+ dev->postSessionMsgAndCleanup(msg);
+ }
+
+ if (!isPartialResult) {
+ dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
+ dev->checkAndFireSequenceCompleteLocked();
+ }
+
+ return ret;
+}
+
+android::hardware::Return<void>
+CameraDevice::ServiceCallback::onRepeatingRequestError(
+ uint64_t lastFrameNumber, int32_t stoppedSequenceId) {
+ auto ret = Void();
+
+ sp<CameraDevice> dev = mDevice.promote();
+ if (dev == nullptr) {
+ return ret; // device has been closed
+ }
+
+ Mutex::Autolock _l(dev->mDeviceLock);
+
+ int repeatingSequenceId = dev->mRepeatingSequenceId;
+ if (stoppedSequenceId == repeatingSequenceId) {
+ dev->mRepeatingSequenceId = REQUEST_ID_NONE;
+ }
+
+ dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
+
+ return ret;
+}
+
+} // namespace acam
+} // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
new file mode 100644
index 0000000..01a219f
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2018 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 <map>
+#include <set>
+#include <atomic>
+#include <utility>
+#include <utils/StrongPointer.h>
+#include <utils/Mutex.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
+#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceCallback.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <camera/NdkCameraManager.h>
+#include <camera/NdkCameraCaptureSession.h>
+#include "ACameraMetadata.h"
+#include "utils.h"
+
+namespace android {
+namespace acam {
+
+using ICameraDeviceCallback = frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
+using ICameraDeviceUser = frameworks::cameraservice::device::V2_0::ICameraDeviceUser;
+using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
+using PhysicalCaptureResultInfo = frameworks::cameraservice::device::V2_0::PhysicalCaptureResultInfo;
+using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
+using SubmitInfo = frameworks::cameraservice::device::V2_0::SubmitInfo;
+using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
+using ErrorCode = frameworks::cameraservice::device::V2_0::ErrorCode;
+using FmqSizeOrMetadata = frameworks::cameraservice::device::V2_0::FmqSizeOrMetadata;
+using StreamConfigurationMode = frameworks::cameraservice::device::V2_0::StreamConfigurationMode;
+using Status = frameworks::cameraservice::common::V2_0::Status;
+using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
+using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+
+using hardware::hidl_vec;
+using hardware::hidl_string;
+using utils::native_handle_ptr_wrapper;
+using utils::CaptureRequest;
+using utils::OutputConfigurationWrapper;
+
+// Wrap ACameraCaptureFailure so it can be ref-counted
+struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure { };
+
+class CameraDevice final : public RefBase {
+ public:
+ CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
+ sp<ACameraMetadata> chars,
+ ACameraDevice* wrapper);
+ ~CameraDevice();
+
+ inline const char* getId() const { return mCameraId.c_str(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const;
+
+ camera_status_t createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session);
+
+ // Callbacks from camera service
+ class ServiceCallback : public ICameraDeviceCallback {
+ public:
+ explicit ServiceCallback(CameraDevice* device) : mDevice(device) {}
+ android::hardware::Return<void> onDeviceError(ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) override;
+ android::hardware::Return<void> onDeviceIdle() override;
+ android::hardware::Return<void> onCaptureStarted(const CaptureResultExtras& resultExtras,
+ uint64_t timestamp) override;
+ android::hardware::Return<void> onResultReceived(const FmqSizeOrMetadata& result,
+ const CaptureResultExtras& resultExtras,
+ const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) override;
+ android::hardware::Return<void> onRepeatingRequestError(uint64_t lastFrameNumber,
+ int32_t stoppedSequenceId) override;
+ private:
+ const wp<CameraDevice> mDevice;
+ };
+ inline sp<ICameraDeviceCallback> getServiceCallback() {
+ return mServiceCallback;
+ };
+
+ // Camera device is only functional after remote being set
+ void setRemoteDevice(sp<ICameraDeviceUser> remote);
+
+ bool setDeviceMetadataQueues();
+ inline ACameraDevice* getWrapper() const { return mWrapper; };
+
+ private:
+ friend ACameraCaptureSession;
+
+ camera_status_t checkCameraClosedOrErrorLocked() const;
+
+ // device goes into fatal error state after this
+ void setCameraDeviceErrorLocked(camera_status_t error);
+
+ void disconnectLocked(sp<ACameraCaptureSession>& session); // disconnect from camera service
+
+ camera_status_t stopRepeatingLocked();
+
+ camera_status_t flushLocked(ACameraCaptureSession*);
+
+ camera_status_t waitUntilIdleLocked();
+
+
+ camera_status_t captureLocked(sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ camera_status_t setRepeatingRequestsLocked(sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*optional*/int* captureSequenceId);
+
+ camera_status_t submitRequestsLocked(
+ sp<ACameraCaptureSession> session,
+ /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
+ int numRequests, ACaptureRequest** requests,
+ /*out*/int* captureSequenceId,
+ bool isRepeating);
+
+ camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
+
+ camera_status_t allocateCaptureRequest(
+ const ACaptureRequest* request, sp<CaptureRequest>& outReq);
+
+ static ACaptureRequest* allocateACaptureRequest(sp<CaptureRequest>& req);
+ static void freeACaptureRequest(ACaptureRequest*);
+
+ // only For session to hold device lock
+ // Always grab device lock before grabbing session lock
+ void lockDeviceForSessionOps() const { mDeviceLock.lock(); };
+ void unlockDevice() const { mDeviceLock.unlock(); };
+
+ // For capture session to notify its end of life
+ void notifySessionEndOfLifeLocked(ACameraCaptureSession* session);
+
+ camera_status_t configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters);
+
+ // Input message will be posted and cleared after this returns
+ void postSessionMsgAndCleanup(sp<AMessage>& msg);
+
+ mutable Mutex mDeviceLock;
+ const hidl_string mCameraId; // Camera ID
+ const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
+ const sp<ACameraMetadata> mChars; // Camera characteristics
+ const sp<ServiceCallback> mServiceCallback;
+ ACameraDevice* mWrapper;
+
+ // stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
+ // camera service)
+ std::map<int, std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> mConfiguredOutputs;
+
+ // TODO: maybe a bool will suffice for synchronous implementation?
+ std::atomic_bool mClosing;
+ inline bool isClosed() { return mClosing; }
+
+ bool mInError = false;
+ camera_status_t mError = ACAMERA_OK;
+ void onCaptureErrorLocked(
+ ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras);
+
+ bool mIdle = true;
+ // This will avoid a busy session being deleted before it's back to idle state
+ sp<ACameraCaptureSession> mBusySession;
+
+ sp<ICameraDeviceUser> mRemote;
+
+ // Looper thread to handle callback to app
+ sp<ALooper> mCbLooper;
+ // definition of handler and message
+ enum {
+ // Device state callbacks
+ kWhatOnDisconnected, // onDisconnected
+ kWhatOnError, // onError
+ // Session state callbacks
+ kWhatSessionStateCb, // onReady, onActive
+ // Capture callbacks
+ kWhatCaptureStart, // onCaptureStarted
+ kWhatCaptureResult, // onCaptureProgressed, onCaptureCompleted
+ kWhatCaptureFail, // onCaptureFailed
+ kWhatCaptureSeqEnd, // onCaptureSequenceCompleted
+ kWhatCaptureSeqAbort, // onCaptureSequenceAborted
+ kWhatCaptureBufferLost,// onCaptureBufferLost
+ // Internal cleanup
+ kWhatCleanUpSessions // Cleanup cached sp<ACameraCaptureSession>
+ };
+ static const char* kContextKey;
+ static const char* kDeviceKey;
+ static const char* kErrorCodeKey;
+ static const char* kCallbackFpKey;
+ static const char* kSessionSpKey;
+ static const char* kCaptureRequestKey;
+ static const char* kTimeStampKey;
+ static const char* kCaptureResultKey;
+ static const char* kCaptureFailureKey;
+ static const char* kSequenceIdKey;
+ static const char* kFrameNumberKey;
+ static const char* kAnwKey;
+
+ class CallbackHandler : public AHandler {
+ public:
+ void onMessageReceived(const sp<AMessage> &msg) override;
+
+ private:
+ // This handler will cache all capture session sp until kWhatCleanUpSessions
+ // is processed. This is used to guarantee the last session reference is always
+ // being removed in callback thread without holding camera device lock
+ Vector<sp<ACameraCaptureSession>> mCachedSessions;
+ };
+ sp<CallbackHandler> mHandler;
+
+ /***********************************
+ * Capture session related members *
+ ***********************************/
+ // The current active session
+ wp<ACameraCaptureSession> mCurrentSession;
+ bool mFlushing = false;
+
+ int mNextSessionId = 0;
+ // TODO: might need another looper/handler to handle callbacks from service
+
+ static const int REQUEST_ID_NONE = -1;
+ int mRepeatingSequenceId = REQUEST_ID_NONE;
+
+ // sequence id -> last frame number map
+ std::map<int32_t, int64_t> mSequenceLastFrameNumberMap;
+
+ struct CallbackHolder {
+ CallbackHolder(sp<ACameraCaptureSession> session,
+ const Vector<sp<CaptureRequest>>& requests,
+ bool isRepeating,
+ ACameraCaptureSession_captureCallbacks* cbs);
+
+ static ACameraCaptureSession_captureCallbacks fillCb(
+ ACameraCaptureSession_captureCallbacks* cbs) {
+ if (cbs != nullptr) {
+ return *cbs;
+ }
+ return { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
+ }
+
+ sp<ACameraCaptureSession> mSession;
+ Vector<sp<CaptureRequest>> mRequests;
+ const bool mIsRepeating;
+ ACameraCaptureSession_captureCallbacks mCallbacks;
+ };
+ // sequence id -> callbacks map
+ std::map<int, CallbackHolder> mSequenceCallbackMap;
+
+ static const int64_t NO_FRAMES_CAPTURED = -1;
+ class FrameNumberTracker {
+ public:
+ // TODO: Called in onResultReceived and onCaptureErrorLocked
+ void updateTracker(int64_t frameNumber, bool isError);
+ inline int64_t getCompletedFrameNumber() { return mCompletedFrameNumber; }
+ private:
+ void update();
+ void updateCompletedFrameNumber(int64_t frameNumber);
+
+ int64_t mCompletedFrameNumber = NO_FRAMES_CAPTURED;
+ List<int64_t> mSkippedFrameNumbers;
+ std::set<int64_t> mFutureErrorSet;
+ };
+ FrameNumberTracker mFrameNumberTracker;
+
+ void checkRepeatingSequenceCompleteLocked(const int sequenceId, const int64_t lastFrameNumber);
+ void checkAndFireSequenceCompleteLocked();
+
+ // Misc variables
+ int32_t mShadingMapSize[2]; // const after constructor
+ int32_t mPartialResultCount; // const after constructor
+ std::shared_ptr<ResultMetadataQueue> mCaptureRequestMetadataQueue = nullptr;
+ std::shared_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
+};
+
+} // namespace acam;
+} // 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,
+ sp<ACameraMetadata> chars) :
+ mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {}
+
+ ~ACameraDevice() {};
+
+ /*******************
+ * NDK public APIs *
+ *******************/
+ inline const char* getId() const { return mDevice->getId(); }
+
+ camera_status_t createCaptureRequest(
+ ACameraDevice_request_template templateId,
+ ACaptureRequest** request) const {
+ return mDevice->createCaptureRequest(templateId, request);
+ }
+
+ camera_status_t createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ const ACameraCaptureSession_stateCallbacks* callbacks,
+ /*out*/ACameraCaptureSession** session) {
+ return mDevice->createCaptureSession(outputs, sessionParameters, callbacks, session);
+ }
+
+ /***********************
+ * Device interal APIs *
+ ***********************/
+ inline android::sp<android::acam::ICameraDeviceCallback> getServiceCallback() {
+ return mDevice->getServiceCallback();
+ };
+
+ // Camera device is only functional after remote being set
+ inline void setRemoteDevice(android::sp<android::acam::ICameraDeviceUser> remote) {
+ mDevice->setRemoteDevice(remote);
+ }
+ inline bool setDeviceMetadataQueues() {
+ return mDevice->setDeviceMetadataQueues();
+ }
+ private:
+ android::sp<android::acam::CameraDevice> mDevice;
+};
+
+#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
new file mode 100644
index 0000000..f395b44
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2018 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 "ACameraManagerVendor"
+
+#include <memory>
+#include "ndk_vendor/impl/ACameraManager.h"
+#include "ACameraMetadata.h"
+#include "ndk_vendor/impl/ACameraDevice.h"
+#include "utils.h"
+
+#include <utils/Vector.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+
+#include <VendorTagDescriptor.h>
+
+using namespace android::acam;
+
+namespace android {
+namespace acam {
+
+using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+
+// 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) {
+ mCameraService->unlinkToDeath(mDeathNotifier);
+ mCameraService->removeListener(mCameraServiceListener);
+ }
+ mDeathNotifier.clear();
+ if (mCbLooper != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+ mCameraServiceListener.clear();
+ mCameraService.clear();
+}
+
+static bool isCameraServiceDisabled() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("config.disable_cameraservice", value, "0");
+ return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
+}
+
+// TODO: Add back when vendor tags are supported for libcamera2ndk_vendor when
+// the HIDL interface supports querying by vendor id.
+
+sp<ICameraService> CameraManagerGlobal::getCameraService() {
+ Mutex::Autolock _l(mLock);
+ if (mCameraService.get() == nullptr) {
+ if (isCameraServiceDisabled()) {
+ return mCameraService;
+ }
+
+ sp<ICameraService> cameraServiceBinder;
+ do {
+ cameraServiceBinder = ICameraService::getService();
+ if (cameraServiceBinder != nullptr) {
+ break;
+ }
+ ALOGW("CameraService not published, waiting...");
+ usleep(kCameraServicePollDelay);
+ } while(true);
+ if (mDeathNotifier == nullptr) {
+ mDeathNotifier = new DeathNotifier(this);
+ }
+ cameraServiceBinder->linkToDeath(mDeathNotifier, 0);
+ mCameraService = cameraServiceBinder;
+
+ // Setup looper thread to perfrom availiability callbacks
+ if (mCbLooper == nullptr) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-mgr-looper");
+ status_t err = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (err != OK) {
+ ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ mCbLooper.clear();
+ return nullptr;
+ }
+ if (mHandler == nullptr) {
+ mHandler = new CallbackHandler();
+ }
+ mCbLooper->registerHandler(mHandler);
+ }
+
+ // register ICameraServiceListener
+ if (mCameraServiceListener == nullptr) {
+ mCameraServiceListener = new CameraServiceListener(this);
+ }
+ hidl_vec<CameraStatusAndId> cameraStatuses{};
+ Status status = Status::NO_ERROR;
+ auto remoteRet = mCameraService->addListener(mCameraServiceListener,
+ [&status, &cameraStatuses](Status s,
+ auto &retStatuses) {
+ status = s;
+ cameraStatuses = retStatuses;
+ });
+ if (!remoteRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("Failed to add listener to camera service %s", remoteRet.description().c_str());
+ }
+ for (auto& c : cameraStatuses) {
+ onStatusChangedLocked(c);
+ }
+ }
+ return mCameraService;
+}
+
+void CameraManagerGlobal::DeathNotifier::serviceDied(uint64_t cookie, const wp<IBase> &who) {
+ (void) cookie;
+ (void) who;
+ ALOGE("Camera service binderDied!");
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ AutoMutex lock(cm->mLock);
+ for (auto& pair : cm->mDeviceStatusMap) {
+ CameraStatusAndId cameraStatusAndId;
+ cameraStatusAndId.cameraId = pair.first;
+ cameraStatusAndId.deviceStatus = pair.second;
+ cm->onStatusChangedLocked(cameraStatusAndId);
+ }
+ 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) {
+ const hidl_string& cameraId = pair.first;
+ CameraDeviceStatus 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->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->post();
+ }
+ }
+}
+
+void CameraManagerGlobal::unregisterAvailabilityCallback(
+ const ACameraManager_AvailabilityCallbacks *callback) {
+ Mutex::Autolock _l(mLock);
+ Callback cb(callback);
+ mCallbacks.erase(cb);
+}
+
+void CameraManagerGlobal::getCameraIdList(std::vector<hidl_string>* cameraIds) {
+ // Ensure that we have initialized/refreshed the list of available devices
+ auto cs = getCameraService();
+ Mutex::Autolock _l(mLock);
+
+ for(auto& deviceStatus : mDeviceStatusMap) {
+ if (deviceStatus.second == CameraDeviceStatus::STATUS_NOT_PRESENT ||
+ deviceStatus.second == CameraDeviceStatus::STATUS_ENUMERATING) {
+ continue;
+ }
+ cameraIds->push_back(deviceStatus.first);
+ }
+}
+
+bool CameraManagerGlobal::validStatus(CameraDeviceStatus status) {
+ switch (status) {
+ case CameraDeviceStatus::STATUS_NOT_PRESENT:
+ case CameraDeviceStatus::STATUS_PRESENT:
+ case CameraDeviceStatus::STATUS_ENUMERATING:
+ case CameraDeviceStatus::STATUS_NOT_AVAILABLE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CameraManagerGlobal::isStatusAvailable(CameraDeviceStatus status) {
+ switch (status) {
+ case CameraDeviceStatus::STATUS_PRESENT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void CameraManagerGlobal::CallbackHandler::onMessageReceived(
+ const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatSendSingleCallback:
+ {
+ ACameraManager_AvailabilityCallback cb;
+ void* context;
+ AString 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->findString(kCameraIdKey, &cameraId);
+ if (!found) {
+ ALOGE("%s: Cannot find camera ID!", __FUNCTION__);
+ return;
+ }
+ (*cb)(context, cameraId.c_str());
+ break;
+ }
+ default:
+ ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
+ break;
+ }
+}
+
+hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onStatusChanged(
+ const CameraStatusAndId &statusAndId) {
+ sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ if (cm != nullptr) {
+ cm->onStatusChanged(statusAndId);
+ } else {
+ ALOGE("Cannot deliver status change. Global camera manager died");
+ }
+ return Void();
+}
+
+void CameraManagerGlobal::onStatusChanged(
+ const CameraStatusAndId &statusAndId) {
+ Mutex::Autolock _l(mLock);
+ onStatusChangedLocked(statusAndId);
+}
+
+void CameraManagerGlobal::onStatusChangedLocked(
+ const CameraStatusAndId &statusAndId) {
+ hidl_string cameraId = statusAndId.cameraId;
+ CameraDeviceStatus status = statusAndId.deviceStatus;
+ if (!validStatus(status)) {
+ ALOGE("%s: Invalid status %d", __FUNCTION__, status);
+ return;
+ }
+
+ bool firstStatus = (mDeviceStatusMap.count(cameraId) == 0);
+ CameraDeviceStatus 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->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->post();
+ }
+ if (status == CameraDeviceStatus::STATUS_NOT_PRESENT) {
+ mDeviceStatusMap.erase(cameraId);
+ }
+}
+
+} // namespace acam
+} // namespace android
+
+/**
+ * ACameraManger Implementation
+ */
+camera_status_t
+ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
+ Mutex::Autolock _l(mLock);
+
+ std::vector<hidl_string> idList;
+ CameraManagerGlobal::getInstance().getCameraIdList(&idList);
+
+ int numCameras = idList.size();
+ 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!");
+ deleteCameraIdList(out);
+ return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
+ }
+ for (int i = 0; i < numCameras; i++) {
+ const char* src = idList[i].c_str();
+ size_t dstSize = strlen(src) + 1;
+ char* dst = new char[dstSize];
+ if (!dst) {
+ ALOGE("Allocate memory for ACameraIdList failed!");
+ deleteCameraIdList(out);
+ 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 ++) {
+ if (cameraIdList->cameraIds[i] != nullptr) {
+ delete[] cameraIdList->cameraIds[i];
+ }
+ }
+ delete[] cameraIdList->cameraIds;
+ }
+ delete cameraIdList;
+ }
+}
+
+camera_status_t ACameraManager::getCameraCharacteristics(
+ const char *cameraIdStr, sp<ACameraMetadata> *characteristics) {
+ Mutex::Autolock _l(mLock);
+
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ CameraMetadata rawMetadata;
+ Status status = Status::NO_ERROR;
+ auto serviceRet =
+ cs->getCameraCharacteristics(cameraIdStr,
+ [&status, &rawMetadata] (auto s ,
+ const hidl_vec<uint8_t> &metadata) {
+ status = s;
+ if (status == Status::NO_ERROR) {
+ utils::convertFromHidlCloned(metadata, &rawMetadata);
+ }
+ });
+ if (!serviceRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("Get camera characteristics from camera service failed");
+ 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) {
+ sp<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;
+ }
+
+ ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));
+
+ sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ if (cs == nullptr) {
+ ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+
+ sp<ICameraDeviceCallback> 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 status = Status::NO_ERROR;
+ auto serviceRet = cs->connectDevice(
+ callbacks, cameraId, [&status, &deviceRemote](auto s, auto &device) {
+ status = s;
+ deviceRemote = device;
+ });
+
+ if (!serviceRet.isOk() || status != Status::NO_ERROR) {
+ ALOGE("%s: connect camera device failed", __FUNCTION__);
+ // TODO: Convert serviceRet to camera_status_t
+ delete device;
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ if (deviceRemote == nullptr) {
+ ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
+ delete device;
+ return ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ }
+ device->setRemoteDevice(deviceRemote);
+ device->setDeviceMetadataQueues();
+ *outDevice = device;
+ return ACAMERA_OK;
+}
+
+ACameraManager::~ACameraManager() {
+
+}
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
new file mode 100644
index 0000000..c8d640f
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2018 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 <camera/NdkCameraManager.h>
+
+#include <android-base/parseint.h>
+#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+
+#include <CameraMetadata.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>
+
+namespace android {
+namespace acam {
+
+using ICameraService = frameworks::cameraservice::service::V2_0::ICameraService;
+using CameraDeviceStatus = frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
+using ICameraServiceListener = frameworks::cameraservice::service::V2_0::ICameraServiceListener;
+using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using Status = frameworks::cameraservice::common::V2_0::Status;
+using VendorTagSection = frameworks::cameraservice::common::V2_0::VendorTagSection;
+using VendorTag = frameworks::cameraservice::common::V2_0::VendorTag;
+using IBase = android::hidl::base::V1_0::IBase;
+using android::hardware::hidl_string;
+using hardware::Void;
+
+/**
+ * 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 suited 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);
+
+ /**
+ * Return camera IDs that support camera2
+ */
+ void getCameraIdList(std::vector<hidl_string> *cameraIds);
+
+ private:
+ sp<ICameraService> mCameraService;
+ const int kCameraServicePollDelay = 500000; // 0.5s
+ Mutex mLock;
+ class DeathNotifier : public android::hardware::hidl_death_recipient {
+ public:
+ explicit DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ protected:
+ // IBinder::DeathRecipient implementation
+ virtual void serviceDied(uint64_t cookie, const wp<IBase> &who);
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<DeathNotifier> mDeathNotifier;
+
+ class CameraServiceListener final : public ICameraServiceListener {
+ public:
+ explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
+ android::hardware::Return<void> onStatusChanged(
+ const CameraStatusAndId &statusAndId) override;
+
+ private:
+ const wp<CameraManagerGlobal> mCameraManager;
+ };
+ sp<CameraServiceListener> mCameraServiceListener;
+
+ // Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
+ struct Callback {
+ explicit 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;
+ };
+ sp<CallbackHandler> mHandler;
+ sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
+
+ void onStatusChanged(const CameraStatusAndId &statusAndId);
+ void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
+ // Utils for status
+ static bool validStatus(CameraDeviceStatus status);
+ static bool isStatusAvailable(CameraDeviceStatus status);
+
+ // The sort logic must match the logic in
+ // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
+ struct CameraIdComparator {
+ bool operator()(const hidl_string& a, const hidl_string& b) const {
+ uint32_t aUint = 0, bUint = 0;
+ bool aIsUint = base::ParseUint(a.c_str(), &aUint);
+ bool bIsUint = base::ParseUint(b.c_str(), &bUint);
+
+ // Uint device IDs first
+ if (aIsUint && bIsUint) {
+ return aUint < bUint;
+ } else if (aIsUint) {
+ return true;
+ } else if (bIsUint) {
+ return false;
+ }
+ // Simple string compare if both id are not uint
+ return a < b;
+ }
+ };
+
+ // Map camera_id -> status
+ std::map<hidl_string, CameraDeviceStatus, CameraIdComparator> mDeviceStatusMap;
+
+ // For the singleton instance
+ static Mutex sLock;
+ static CameraManagerGlobal* sInstance;
+ CameraManagerGlobal() {};
+ ~CameraManagerGlobal();
+};
+
+} // namespace acam;
+} // namespace android;
+
+/**
+ * ACameraManager opaque struct definition
+ * Leave outside of android namespace because it's NDK struct
+ */
+struct ACameraManager {
+ ACameraManager() :
+ mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
+ ~ACameraManager();
+ camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
+ static void deleteCameraIdList(ACameraIdList* cameraIdList);
+
+ camera_status_t getCameraCharacteristics(
+ const char* cameraId, android::sp<ACameraMetadata>* characteristics);
+
+ camera_status_t openCamera(const char* cameraId,
+ ACameraDevice_StateCallbacks* callback,
+ /*out*/ACameraDevice** device);
+
+ private:
+ enum {
+ kCameraIdListNotInit = -1
+ };
+ android::Mutex mLock;
+ android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
+};
+
+#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
new file mode 100644
index 0000000..ed67615
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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 "utils.h"
+
+struct ACameraOutputTarget {
+ explicit ACameraOutputTarget(native_handle_t* 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;
+ }
+
+ android::acam::utils::native_handle_ptr_wrapper mWindow;
+};
diff --git a/camera/ndk/ndk_vendor/impl/utils.cpp b/camera/ndk/ndk_vendor/impl/utils.cpp
new file mode 100644
index 0000000..7193006
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/utils.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 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 "ACameraVendorUtils"
+
+#include <utils/Log.h>
+
+#include "utils.h"
+
+namespace android {
+namespace acam {
+namespace utils {
+
+// Convert CaptureRequest wrappable by sp<> to hidl CaptureRequest.
+frameworks::cameraservice::device::V2_0::CaptureRequest
+convertToHidl(const CaptureRequest *captureRequest) {
+ frameworks::cameraservice::device::V2_0::CaptureRequest hCaptureRequest;
+ hCaptureRequest.physicalCameraSettings = captureRequest->mCaptureRequest.physicalCameraSettings;
+ hCaptureRequest.streamAndWindowIds = captureRequest->mCaptureRequest.streamAndWindowIds;
+ return hCaptureRequest;
+}
+
+HRotation convertToHidl(int rotation) {
+ HRotation hRotation = HRotation::R0;
+ switch(rotation) {
+ case CAMERA3_STREAM_ROTATION_90:
+ hRotation = HRotation::R90;
+ break;
+ case CAMERA3_STREAM_ROTATION_180:
+ hRotation = HRotation::R180;
+ break;
+ case CAMERA3_STREAM_ROTATION_270:
+ hRotation = HRotation::R270;
+ break;
+ default:
+ break;
+ }
+ return hRotation;
+}
+
+bool convertFromHidlCloned(const HCameraMetadata &metadata, CameraMetadata *rawMetadata) {
+ const camera_metadata *buffer = (camera_metadata_t*)(metadata.data());
+ size_t expectedSize = metadata.size();
+ int ret = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *rawMetadata = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from caller", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst) {
+ if (src == nullptr) {
+ return;
+ }
+ size_t size = get_camera_metadata_size(src);
+ ALOGE("Converting metadata size: %d", (int)size);
+ dst->setToExternal((uint8_t *) src, size);
+ return;
+}
+
+TemplateId convertToHidl(ACameraDevice_request_template templateId) {
+ switch(templateId) {
+ case TEMPLATE_STILL_CAPTURE:
+ return TemplateId::STILL_CAPTURE;
+ case TEMPLATE_RECORD:
+ return TemplateId::RECORD;
+ case TEMPLATE_VIDEO_SNAPSHOT:
+ return TemplateId::VIDEO_SNAPSHOT;
+ case TEMPLATE_ZERO_SHUTTER_LAG:
+ return TemplateId::ZERO_SHUTTER_LAG;
+ case TEMPLATE_MANUAL:
+ return TemplateId::MANUAL;
+ default:
+ return TemplateId::PREVIEW;
+ }
+}
+
+camera_status_t convertFromHidl(Status status) {
+ camera_status_t ret = ACAMERA_OK;
+ switch(status) {
+ case Status::NO_ERROR:
+ break;
+ case Status::DISCONNECTED:
+ ret = ACAMERA_ERROR_CAMERA_DISCONNECTED;
+ break;
+ case Status::CAMERA_IN_USE:
+ ret = ACAMERA_ERROR_CAMERA_IN_USE;
+ break;
+ case Status::MAX_CAMERAS_IN_USE:
+ ret = ACAMERA_ERROR_MAX_CAMERA_IN_USE;
+ break;
+ case Status::ILLEGAL_ARGUMENT:
+ ret = ACAMERA_ERROR_INVALID_PARAMETER;
+ break;
+ case Status::DEPRECATED_HAL:
+ // Should not reach here since we filtered legacy HALs earlier
+ ret = ACAMERA_ERROR_INVALID_PARAMETER;
+ break;
+ case Status::DISABLED:
+ ret = ACAMERA_ERROR_CAMERA_DISABLED;
+ break;
+ case Status::PERMISSION_DENIED:
+ ret = ACAMERA_ERROR_PERMISSION_DENIED;
+ break;
+ case Status::INVALID_OPERATION:
+ ret = ACAMERA_ERROR_INVALID_OPERATION;
+ break;
+ default:
+ ret = ACAMERA_ERROR_UNKNOWN;
+ break;
+ }
+ return ret;
+}
+
+bool isWindowNativeHandleEqual(const native_handle_t *nh1, const native_handle_t *nh2) {
+ if (nh1->numFds !=0 || nh2->numFds !=0) {
+ ALOGE("Invalid window native handles being compared");
+ return false;
+ }
+ if (nh1->version != nh2->version || nh1->numFds != nh2->numFds ||
+ nh1->numInts != nh2->numInts) {
+ return false;
+ }
+ for (int i = 0; i < nh1->numInts; i++) {
+ if(nh1->data[i] != nh2->data[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool isWindowNativeHandleLessThan(const native_handle_t *nh1, const native_handle_t *nh2) {
+ if (isWindowNativeHandleEqual(nh1, nh2)) {
+ return false;
+ }
+ if (nh1->numInts != nh2->numInts) {
+ return nh1->numInts < nh2->numInts;
+ }
+
+ for (int i = 0; i < nh1->numInts; i++) {
+ if (nh1->data[i] != nh2->data[i]) {
+ return nh1->data[i] < nh2->data[i];
+ }
+ }
+ return false;
+}
+
+bool isWindowNativeHandleGreaterThan(const native_handle_t *nh1, const native_handle_t *nh2) {
+ return !isWindowNativeHandleLessThan(nh1, nh2) && !isWindowNativeHandleEqual(nh1, nh2);
+}
+
+bool areWindowNativeHandlesEqual(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle> handles2) {
+ if (handles1.size() != handles2.size()) {
+ return false;
+ }
+ for (int i = 0; i < handles1.size(); i++) {
+ if (!isWindowNativeHandleEqual(handles1[i], handles2[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool areWindowNativeHandlesLessThan(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2) {
+ if (handles1.size() != handles2.size()) {
+ return handles1.size() < handles2.size();
+ }
+ for (int i = 0; i < handles1.size(); i++) {
+ const native_handle_t *handle1 = handles1[i].getNativeHandle();
+ const native_handle_t *handle2 = handles2[i].getNativeHandle();
+ if (!isWindowNativeHandleEqual(handle1, handle2)) {
+ return isWindowNativeHandleLessThan(handle1, handle2);
+ }
+ }
+ return false;
+}
+
+} // namespace utils
+} // namespace acam
+} // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/utils.h b/camera/ndk/ndk_vendor/impl/utils.h
new file mode 100644
index 0000000..2f1006d
--- /dev/null
+++ b/camera/ndk/ndk_vendor/impl/utils.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 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 <android/frameworks/cameraservice/service/2.0/ICameraService.h>
+#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
+#include <android/frameworks/cameraservice/device/2.0/types.h>
+#include <camera/NdkCameraDevice.h>
+#include <CameraMetadata.h>
+#include <hardware/camera3.h>
+
+#ifndef CAMERA_NDK_VENDOR_H
+#define CAMERA_NDK_VENDOR_H
+
+using android::hardware::hidl_vec;
+using android::hardware::hidl_handle;
+
+namespace android {
+namespace acam {
+namespace utils {
+
+using CameraMetadata = hardware::camera::common::V1_0::helper::CameraMetadata;
+using HCameraMetadata = frameworks::cameraservice::service::V2_0::CameraMetadata;
+using Status = frameworks::cameraservice::common::V2_0::Status;
+using TemplateId = frameworks::cameraservice::device::V2_0::TemplateId;
+using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
+using HRotation = frameworks::cameraservice::device::V2_0::OutputConfiguration::Rotation;
+using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
+
+// Utility class so that CaptureRequest can be stored by sp<>
+struct CaptureRequest : public RefBase {
+ frameworks::cameraservice::device::V2_0::CaptureRequest mCaptureRequest;
+ std::vector<native_handle_t *> mSurfaceList;
+ //Physical camera settings metadata is stored here, since the capture request
+ //might not contain it. That's since, fmq might have consumed it.
+ hidl_vec<PhysicalCameraSettings> mPhysicalCameraSettings;
+};
+
+bool areWindowNativeHandlesEqual(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2);
+
+bool areWindowNativeHandlesLessThan(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2);
+
+bool isWindowNativeHandleEqual(const native_handle_t *nh1, const native_handle_t *nh2);
+
+bool isWindowNativeHandleLessThan(const native_handle_t *nh1, const native_handle_t *nh2);
+
+// Convenience wrapper over isWindowNativeHandleLessThan and isWindowNativeHandleEqual
+bool isWindowNativeHandleGreaterThan(const native_handle_t *nh1, const native_handle_t *nh2);
+
+// Utility class so the native_handle_t can be compared with its contents instead
+// of just raw pointer comparisons.
+struct native_handle_ptr_wrapper {
+ native_handle_t *mWindow = nullptr;
+
+ native_handle_ptr_wrapper(native_handle_t *nh) : mWindow(nh) { }
+
+ native_handle_ptr_wrapper() = default;
+
+ operator native_handle_t *() const { return mWindow; }
+
+ bool operator ==(const native_handle_ptr_wrapper other) const {
+ return isWindowNativeHandleEqual(mWindow, other.mWindow);
+ }
+
+ bool operator != (const native_handle_ptr_wrapper& other) const {
+ return !isWindowNativeHandleEqual(mWindow, other.mWindow);
+ }
+
+ bool operator < (const native_handle_ptr_wrapper& other) const {
+ return isWindowNativeHandleLessThan(mWindow, other.mWindow);
+ }
+
+ bool operator > (const native_handle_ptr_wrapper& other) const {
+ return !isWindowNativeHandleGreaterThan(mWindow, other.mWindow);
+ }
+
+};
+
+// Wrapper around OutputConfiguration. This is needed since HIDL
+// OutputConfiguration is auto-generated and marked final. Therefore, operator
+// overloads outside the class, will not get picked by clang while trying to
+// store OutputConfiguration in maps/sets.
+struct OutputConfigurationWrapper {
+ OutputConfiguration mOutputConfiguration;
+
+ operator const OutputConfiguration &() const {
+ return mOutputConfiguration;
+ }
+
+ OutputConfigurationWrapper() = default;
+
+ OutputConfigurationWrapper(OutputConfiguration &outputConfiguration)
+ : mOutputConfiguration((outputConfiguration)) { }
+
+ bool operator ==(const OutputConfiguration &other) const {
+ const OutputConfiguration &self = mOutputConfiguration;
+ return self.rotation == other.rotation && self.windowGroupId == other.windowGroupId &&
+ self.physicalCameraId == other.physicalCameraId && self.width == other.width &&
+ self.height == other.height && self.isDeferred == other.isDeferred &&
+ areWindowNativeHandlesEqual(self.windowHandles, other.windowHandles);
+ }
+
+ bool operator < (const OutputConfiguration &other) const {
+ if (*this == other) {
+ return false;
+ }
+ const OutputConfiguration &self = mOutputConfiguration;
+ if (self.windowGroupId != other.windowGroupId) {
+ return self.windowGroupId < other.windowGroupId;
+ }
+
+ if (self.width != other.width) {
+ return self.width < other.width;
+ }
+
+ if (self.height != other.height) {
+ return self.height < other.height;
+ }
+
+ if (self.rotation != other.rotation) {
+ return static_cast<uint32_t>(self.rotation) < static_cast<uint32_t>(other.rotation);
+ }
+
+ if (self.isDeferred != other.isDeferred) {
+ return self.isDeferred < other.isDeferred;
+ }
+
+ if (self.physicalCameraId != other.physicalCameraId) {
+ return self.physicalCameraId < other.physicalCameraId;
+ }
+ return areWindowNativeHandlesLessThan(self.windowHandles, other.windowHandles);
+ }
+
+ bool operator != (const OutputConfiguration &other) const {
+ return !(*this == other);
+ }
+
+ bool operator > (const OutputConfiguration &other) const {
+ return (*this != other) && !(*this < other);
+ }
+};
+
+// Convert CaptureRequest wrappable by sp<> to hidl CaptureRequest.
+frameworks::cameraservice::device::V2_0::CaptureRequest convertToHidl(
+ const CaptureRequest *captureRequest);
+
+HRotation convertToHidl(int rotation);
+
+bool convertFromHidlCloned(const HCameraMetadata &metadata, CameraMetadata *rawMetadata);
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst);
+
+TemplateId convertToHidl(ACameraDevice_request_template templateId);
+
+camera_status_t convertFromHidl(Status status);
+
+} // namespace utils
+} // namespace acam
+} // namespace android
+
+#endif // CAMERA_NDK_VENDOR_H
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
new file mode 100644
index 0000000..b1e501b
--- /dev/null
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2018 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 "AImageReaderVendorTest"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+#include <unistd.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <mutex>
+#include <string>
+#include <vector>
+#include <stdio.h>
+#include <stdio.h>
+#include <stdio.h>
+
+#include <android/log.h>
+#include <camera/NdkCameraError.h>
+#include <camera/NdkCameraManager.h>
+#include <camera/NdkCameraDevice.h>
+#include <camera/NdkCameraCaptureSession.h>
+#include <media/NdkImage.h>
+#include <media/NdkImageReader.h>
+#include <cutils/native_handle.h>
+
+//#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+//#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+namespace {
+
+static constexpr int kDummyFenceFd = -1;
+static constexpr int kCaptureWaitUs = 100 * 1000;
+static constexpr int kCaptureWaitRetry = 10;
+static constexpr int kTestImageWidth = 640;
+static constexpr int kTestImageHeight = 480;
+static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
+
+class CameraHelper {
+ public:
+ CameraHelper(native_handle_t* imgReaderAnw) : mImgReaderAnw(imgReaderAnw) {}
+ ~CameraHelper() { closeCamera(); }
+
+ int initCamera() {
+ if (mImgReaderAnw == nullptr) {
+ ALOGE("Cannot initialize camera before image reader get initialized.");
+ return -1;
+ }
+ int ret;
+
+ mCameraManager = ACameraManager_create();
+ if (mCameraManager == nullptr) {
+ ALOGE("Failed to create ACameraManager.");
+ return -1;
+ }
+
+ ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
+ if (ret != AMEDIA_OK) {
+ ALOGE("Failed to get cameraIdList: ret=%d", ret);
+ return ret;
+ }
+ if (mCameraIdList->numCameras < 1) {
+ ALOGW("Device has no camera on board.");
+ return 0;
+ }
+
+ // We always use the first camera.
+ mCameraId = mCameraIdList->cameraIds[0];
+ if (mCameraId == nullptr) {
+ ALOGE("Failed to get cameraId.");
+ return -1;
+ }
+
+ ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
+ if (ret != AMEDIA_OK || mDevice == nullptr) {
+ ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice);
+ return -1;
+ }
+
+ ret = ACameraManager_getCameraCharacteristics(mCameraManager, mCameraId, &mCameraMetadata);
+ if (ret != ACAMERA_OK || mCameraMetadata == nullptr) {
+ ALOGE("Get camera %s characteristics failure. ret %d, metadata %p", mCameraId, ret,
+ mCameraMetadata);
+ return -1;
+ }
+
+ if (!isCapabilitySupported(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) {
+ ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
+ return 0;
+ }
+
+ // Create capture session
+ ret = ACaptureSessionOutputContainer_create(&mOutputs);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutputContainer_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutput_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureSessionOutputContainer_add(mOutputs, mImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
+ return ret;
+ }
+
+ // Create capture request
+ ret = ACameraDevice_createCaptureRequest(mDevice, TEMPLATE_STILL_CAPTURE, &mStillRequest);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
+ return ret;
+ }
+ ret = ACaptureRequest_addTarget(mStillRequest, mReqImgReaderOutput);
+ if (ret != AMEDIA_OK) {
+ ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
+ return ret;
+ }
+
+ mIsCameraReady = true;
+ return 0;
+ }
+
+ bool isCapabilitySupported(acamera_metadata_enum_android_request_available_capabilities_t cap) {
+ ACameraMetadata_const_entry entry;
+ ACameraMetadata_getConstEntry(
+ mCameraMetadata, ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ for (uint32_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == cap) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool isCameraReady() { return mIsCameraReady; }
+
+ void closeCamera() {
+ // Destroy capture request
+ if (mReqImgReaderOutput) {
+ ACameraOutputTarget_free(mReqImgReaderOutput);
+ mReqImgReaderOutput = nullptr;
+ }
+ if (mStillRequest) {
+ ACaptureRequest_free(mStillRequest);
+ mStillRequest = nullptr;
+ }
+ // Destroy capture session
+ if (mSession != nullptr) {
+ ACameraCaptureSession_close(mSession);
+ mSession = nullptr;
+ }
+ if (mImgReaderOutput) {
+ ACaptureSessionOutput_free(mImgReaderOutput);
+ mImgReaderOutput = nullptr;
+ }
+ if (mOutputs) {
+ ACaptureSessionOutputContainer_free(mOutputs);
+ mOutputs = nullptr;
+ }
+ // Destroy camera device
+ if (mDevice) {
+ ACameraDevice_close(mDevice);
+ mDevice = nullptr;
+ }
+ if (mCameraMetadata) {
+ ACameraMetadata_free(mCameraMetadata);
+ mCameraMetadata = nullptr;
+ }
+ // Destroy camera manager
+ if (mCameraIdList) {
+ ACameraManager_deleteCameraIdList(mCameraIdList);
+ mCameraIdList = nullptr;
+ }
+ if (mCameraManager) {
+ ACameraManager_delete(mCameraManager);
+ mCameraManager = nullptr;
+ }
+ mIsCameraReady = false;
+ }
+
+ int takePicture() {
+ int seqId;
+ return ACameraCaptureSession_capture(mSession, nullptr, 1, &mStillRequest, &seqId);
+ }
+
+ static void onDeviceDisconnected(void* /*obj*/, ACameraDevice* /*device*/) {}
+
+ static void onDeviceError(void* /*obj*/, ACameraDevice* /*device*/, int /*errorCode*/) {}
+
+ static void onSessionClosed(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
+
+ static void onSessionReady(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
+
+ static void onSessionActive(void* /*obj*/, ACameraCaptureSession* /*session*/) {}
+
+ private:
+ ACameraDevice_StateCallbacks mDeviceCb{this, onDeviceDisconnected,
+ onDeviceError};
+ ACameraCaptureSession_stateCallbacks mSessionCb{
+ this, onSessionClosed, onSessionReady, onSessionActive};
+
+ native_handle_t* mImgReaderAnw = nullptr; // not owned by us.
+
+ // Camera manager
+ ACameraManager* mCameraManager = nullptr;
+ ACameraIdList* mCameraIdList = nullptr;
+ // Camera device
+ ACameraMetadata* mCameraMetadata = nullptr;
+ ACameraDevice* mDevice = nullptr;
+ // Capture session
+ ACaptureSessionOutputContainer* mOutputs = nullptr;
+ ACaptureSessionOutput* mImgReaderOutput = nullptr;
+ ACameraCaptureSession* mSession = nullptr;
+ // Capture request
+ ACaptureRequest* mStillRequest = nullptr;
+ ACameraOutputTarget* mReqImgReaderOutput = nullptr;
+
+ bool mIsCameraReady = false;
+ const char* mCameraId;
+};
+
+class ImageReaderTestCase {
+ public:
+ ImageReaderTestCase(int32_t width,
+ int32_t height,
+ int32_t format,
+ uint64_t usage,
+ int32_t maxImages,
+ bool async)
+ : mWidth(width),
+ mHeight(height),
+ mFormat(format),
+ mUsage(usage),
+ mMaxImages(maxImages),
+ mAsync(async) {}
+
+ ~ImageReaderTestCase() {
+ if (mImgReaderAnw) {
+ AImageReader_delete(mImgReader);
+ // No need to call native_handle_t_release on imageReaderAnw
+ }
+ }
+
+ int initImageReader() {
+ if (mImgReader != nullptr || mImgReaderAnw != nullptr) {
+ ALOGE("Cannot re-initalize image reader, mImgReader=%p, mImgReaderAnw=%p", mImgReader,
+ mImgReaderAnw);
+ return -1;
+ }
+
+ media_status_t ret = AImageReader_newWithUsage(
+ mWidth, mHeight, mFormat, mUsage, mMaxImages, &mImgReader);
+ if (ret != AMEDIA_OK || mImgReader == nullptr) {
+ ALOGE("Failed to create new AImageReader, ret=%d, mImgReader=%p", ret, mImgReader);
+ return -1;
+ }
+
+ ret = AImageReader_setImageListener(mImgReader, &mReaderAvailableCb);
+ if (ret != AMEDIA_OK) {
+ ALOGE("Failed to set image available listener, ret=%d.", ret);
+ return ret;
+ }
+
+ ret = AImageReader_setBufferRemovedListener(mImgReader, &mReaderDetachedCb);
+ if (ret != AMEDIA_OK) {
+ ALOGE("Failed to set buffer detaching listener, ret=%d.", ret);
+ return ret;
+ }
+
+ ret = AImageReader_getWindowNativeHandle(mImgReader, &mImgReaderAnw);
+ if (ret != AMEDIA_OK || mImgReaderAnw == nullptr) {
+ ALOGE("Failed to get native_handle_t from AImageReader, ret=%d, mImgReaderAnw=%p.", ret,
+ mImgReaderAnw);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ native_handle_t* getNativeWindow() { return mImgReaderAnw; }
+
+ int getAcquiredImageCount() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mAcquiredImageCount;
+ }
+
+ void HandleImageAvailable(AImageReader* reader) {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ AImage* outImage = nullptr;
+ media_status_t ret;
+
+ // Make sure AImage will be deleted automatically when it goes out of
+ // scope.
+ auto imageDeleter = [this](AImage* img) {
+ if (mAsync) {
+ AImage_deleteAsync(img, kDummyFenceFd);
+ } else {
+ AImage_delete(img);
+ }
+ };
+ std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
+
+ if (mAsync) {
+ int outFenceFd = 0;
+ // Verity that outFenceFd's value will be changed by
+ // AImageReader_acquireNextImageAsync.
+ ret = AImageReader_acquireNextImageAsync(reader, &outImage, &outFenceFd);
+ if (ret != AMEDIA_OK || outImage == nullptr || outFenceFd == 0) {
+ ALOGE("Failed to acquire image, ret=%d, outIamge=%p, outFenceFd=%d.", ret, outImage,
+ outFenceFd);
+ return;
+ }
+ img.reset(outImage);
+ } else {
+ ret = AImageReader_acquireNextImage(reader, &outImage);
+ if (ret != AMEDIA_OK || outImage == nullptr) {
+ ALOGE("Failed to acquire image, ret=%d, outIamge=%p.", ret, outImage);
+ return;
+ }
+ img.reset(outImage);
+ }
+
+ AHardwareBuffer* outBuffer = nullptr;
+ ret = AImage_getHardwareBuffer(img.get(), &outBuffer);
+ if (ret != AMEDIA_OK || outBuffer == nullptr) {
+ ALOGE("Faild to get hardware buffer, ret=%d, outBuffer=%p.", ret, outBuffer);
+ return;
+ }
+
+ // No need to release AHardwareBuffer, since we don't acquire additional
+ // reference to it.
+ AHardwareBuffer_Desc outDesc;
+ AHardwareBuffer_describe(outBuffer, &outDesc);
+ int32_t imageWidth = 0;
+ int32_t imageHeight = 0;
+ int32_t bufferWidth = static_cast<int32_t>(outDesc.width);
+ int32_t bufferHeight = static_cast<int32_t>(outDesc.height);
+
+ AImage_getWidth(outImage, &imageWidth);
+ AImage_getHeight(outImage, &imageHeight);
+ if (imageWidth != mWidth || imageHeight != mHeight) {
+ ALOGE("Mismatched output image dimension: expected=%dx%d, actual=%dx%d", mWidth,
+ mHeight, imageWidth, imageHeight);
+ return;
+ }
+
+ if (mFormat == AIMAGE_FORMAT_RGBA_8888 ||
+ mFormat == AIMAGE_FORMAT_RGBX_8888 ||
+ mFormat == AIMAGE_FORMAT_RGB_888 ||
+ mFormat == AIMAGE_FORMAT_RGB_565 ||
+ mFormat == AIMAGE_FORMAT_RGBA_FP16 ||
+ mFormat == AIMAGE_FORMAT_YUV_420_888 ||
+ mFormat == AIMAGE_FORMAT_Y8) {
+ // Check output buffer dimension for certain formats. Don't do this for blob based
+ // formats.
+ if (bufferWidth != mWidth || bufferHeight != mHeight) {
+ ALOGE("Mismatched output buffer dimension: expected=%dx%d, actual=%dx%d", mWidth,
+ mHeight, bufferWidth, bufferHeight);
+ return;
+ }
+ }
+
+ if ((outDesc.usage & mUsage) != mUsage) {
+ ALOGE("Mismatched output buffer usage: actual (%" PRIu64 "), expected (%" PRIu64 ")",
+ outDesc.usage, mUsage);
+ return;
+ }
+
+ uint8_t* data = nullptr;
+ int dataLength = 0;
+ ret = AImage_getPlaneData(img.get(), 0, &data, &dataLength);
+ if (mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) {
+ // When we have CPU_READ_OFTEN usage bits, we can lock the image.
+ if (ret != AMEDIA_OK || data == nullptr || dataLength < 0) {
+ ALOGE("Failed to access CPU data, ret=%d, data=%p, dataLength=%d", ret, data,
+ dataLength);
+ return;
+ }
+ } else {
+ if (ret != AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE || data != nullptr || dataLength != 0) {
+ ALOGE("Shouldn't be able to access CPU data, ret=%d, data=%p, dataLength=%d", ret,
+ data, dataLength);
+ return;
+ }
+ }
+ // Only increase mAcquiredImageCount if all checks pass.
+ mAcquiredImageCount++;
+ }
+
+ static void onImageAvailable(void* obj, AImageReader* reader) {
+ ImageReaderTestCase* thiz = reinterpret_cast<ImageReaderTestCase*>(obj);
+ thiz->HandleImageAvailable(reader);
+ }
+
+ static void
+ onBufferRemoved(void* /*obj*/, AImageReader* /*reader*/, AHardwareBuffer* /*buffer*/) {
+ // No-op, just to check the listener can be set properly.
+ }
+
+ private:
+ int32_t mWidth;
+ int32_t mHeight;
+ int32_t mFormat;
+ uint64_t mUsage;
+ int32_t mMaxImages;
+ bool mAsync;
+
+ std::mutex mMutex;
+ int mAcquiredImageCount{0};
+
+ AImageReader* mImgReader = nullptr;
+ native_handle_t* mImgReaderAnw = nullptr;
+
+ AImageReader_ImageListener mReaderAvailableCb{this, onImageAvailable};
+ AImageReader_BufferRemovedListener mReaderDetachedCb{this, onBufferRemoved};
+};
+
+int takePictures(uint64_t readerUsage, int readerMaxImages, bool readerAsync, int pictureCount) {
+ int ret = 0;
+
+ ImageReaderTestCase testCase(
+ kTestImageWidth, kTestImageHeight, kTestImageFormat, readerUsage, readerMaxImages,
+ readerAsync);
+ ret = testCase.initImageReader();
+ if (ret < 0) {
+ return ret;
+ }
+
+ CameraHelper cameraHelper(testCase.getNativeWindow());
+ ret = cameraHelper.initCamera();
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (!cameraHelper.isCameraReady()) {
+ ALOGW("Camera is not ready after successful initialization. It's either due to camera on "
+ "board lacks BACKWARDS_COMPATIBLE capability or the device does not have camera on "
+ "board.");
+ return 0;
+ }
+
+ for (int i = 0; i < pictureCount; i++) {
+ ret = cameraHelper.takePicture();
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ // Sleep until all capture finished
+ for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
+ usleep(kCaptureWaitUs);
+ if (testCase.getAcquiredImageCount() == pictureCount) {
+ ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
+ pictureCount);
+ break;
+ }
+ }
+ return testCase.getAcquiredImageCount() == pictureCount ? 0 : -1;
+}
+
+class AImageReaderWindowHandleTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ }
+ void TearDown() override {
+
+ }
+
+};
+
+bool testTakePicturesNative() {
+ for (auto& readerUsage :
+ {AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN}) {
+ for (auto& readerMaxImages : {1, 4, 8}) {
+ for (auto& readerAsync : {true, false}) {
+ for (auto& pictureCount : {1, 4, 8}) {
+ if (takePictures(readerUsage, readerMaxImages, readerAsync, pictureCount)) {
+ ALOGE("Test takePictures failed for test case usage=%" PRIu64 ", maxImages=%d, "
+ "async=%d, pictureCount=%d",
+ readerUsage, readerMaxImages, readerAsync, pictureCount);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+
+TEST_F(AImageReaderWindowHandleTest, CreateWindowNativeHandle) {
+ EXPECT_TRUE(testTakePicturesNative());
+}
+
+} // namespace