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>
gugelfrei
Jayant Chowdhary 6 years ago
parent dcfd26eeac
commit 6df26071a5

@ -70,3 +70,81 @@ cc_library_shared {
],
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__",
],
}

@ -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 @@ void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContainer* contain
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 @@ camera_status_t ACaptureSessionOutput_create(
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 @@ camera_status_t ACaptureSessionSharedOutput_create(
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 @@ camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
__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 @@ camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
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 @@ camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *out,
__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;

@ -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() {

@ -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__);

@ -23,7 +23,7 @@ using namespace android;
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 @@ ACameraCaptureSession::closeByApp() {
mClosedByApp = true;
}
sp<CameraDevice> dev = getDeviceSp();
sp<acam::CameraDevice> dev = getDeviceSp();
if (dev != nullptr) {
dev->lockDeviceForSessionOps();
}
@ -73,7 +73,7 @@ ACameraCaptureSession::closeByApp() {
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 @@ ACameraCaptureSession::stopRepeating() {
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 @@ ACameraCaptureSession::setRepeatingRequest(
/*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 @@ camera_status_t ACameraCaptureSession::capture(
/*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::capture(
}
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 @@ camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSession
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 @@ ACameraCaptureSession::closeByDevice() {
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;

@ -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 @@ struct ACaptureSessionOutput {
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 @@ struct ACameraCaptureSession : public RefBase {
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 @@ struct ACameraCaptureSession : public RefBase {
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;

@ -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 @@ CameraDevice::ServiceCallback::onRepeatingRequestError(
return ret;
}
} // namespace acam
} // namespace android

@ -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 @@ class CameraDevice final : public RefBase {
};
} // namespace acam;
} // namespace android;
/**
@ -295,7 +297,7 @@ class CameraDevice final : public RefBase {
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 @@ struct ACameraDevice {
}
private:
android::sp<android::CameraDevice> mDevice;
android::sp<android::acam::CameraDevice> mDevice;
};
#endif // _ACAMERA_DEVICE_H

@ -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 @@ void CameraManagerGlobal::onStatusChangedLocked(
}
}
} // namespace acam
} // namespace android
/**

@ -35,6 +35,7 @@
#include <map>
namespace android {
namespace acam {
/**
* Per-process singleton instance of CameraManger. Shared by all ACameraManager
@ -172,6 +173,7 @@ class CameraManagerGlobal final : public RefBase {
~CameraManagerGlobal();
};
} // namespace acam;
} // namespace android;
/**
@ -180,7 +182,7 @@ class CameraManagerGlobal final : public RefBase {
*/
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 @@ struct ACameraManager {
kCameraIdListNotInit = -1
};
android::Mutex mLock;
android::sp<android::CameraManagerGlobal> mGlobalManager;
android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
};
#endif //_ACAMERA_MANAGER_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>

@ -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 @@ struct ACameraOutputTarget {
return mWindow > other.mWindow;
}
ANativeWindow* mWindow;
ACameraWindowType* mWindow;
};
#endif
struct ACameraOutputTargets {
std::set<ACameraOutputTarget> mOutputs;

@ -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_sequenceAbort)(
*/
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.

@ -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 @@ void ACaptureSessionOutputContainer_free(ACaptureSessionOutputContain
* @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 @@ camera_status_t ACameraDevice_createCaptureSession(
* @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 @@ camera_status_t ACaptureSessionSharedOutput_create(
* 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 @@ camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output,
* 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

@ -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

@ -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 @@ typedef struct ACaptureRequest ACaptureRequest;
*
* @see ACaptureRequest_addTarget
*/
camera_status_t ACameraOutputTarget_create(ANativeWindow* window,
camera_status_t ACameraOutputTarget_create(ACameraWindowType* window,
ACameraOutputTarget** output) __INTRODUCED_IN(24);
/**

@ -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;
};

File diff suppressed because it is too large Load Diff

@ -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

@ -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() {
}

@ -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

@ -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;
};

@ -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

@ -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

@ -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
Loading…
Cancel
Save