Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aebbe414 authored by Emilian Peev's avatar Emilian Peev
Browse files

camera: Support multiple physical camera requests

Capture requests could include settings for different physical
cameras. Camera service should always check whether such
extended requests refer to valid physical devices and process
them accordingly.
Fix some stability issues in the camera native tests.

Test: Basic camera sanity using camera application,
camera_client_test, Camera CTS
Bug: 64691172

Change-Id: I68b81e983dd0b7caebfa03e4f0cf283f2a91dc7a
parent c28189a6
Loading
Loading
Loading
Loading
+42 −5
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "CameraRequest"
#include <utils/Log.h>
#include <utils/String16.h>

#include <camera/camera2/CaptureRequest.h>

@@ -42,18 +43,39 @@ status_t CaptureRequest::readFromParcel(const android::Parcel* parcel) {
        return BAD_VALUE;
    }

    mMetadata.clear();
    mSurfaceList.clear();
    mStreamIdxList.clear();
    mSurfaceIdxList.clear();
    mPhysicalCameraSettings.clear();

    status_t err = OK;

    if ((err = mMetadata.readFromParcel(parcel)) != OK) {
    int32_t settingsCount;
    if ((err = parcel->readInt32(&settingsCount)) != OK) {
        ALOGE("%s: Failed to read the settings count from parcel: %d", __FUNCTION__, err);
        return err;
    }

    if (settingsCount <= 0) {
        ALOGE("%s: Settings count %d should always be positive!", __FUNCTION__, settingsCount);
        return BAD_VALUE;
    }

    for (int32_t i = 0; i < settingsCount; i++) {
        String16 id;
        if ((err = parcel->readString16(&id)) != OK) {
            ALOGE("%s: Failed to read camera id!", __FUNCTION__);
            return BAD_VALUE;
        }

        CameraMetadata settings;
        if ((err = settings.readFromParcel(parcel)) != OK) {
            ALOGE("%s: Failed to read metadata from parcel", __FUNCTION__);
            return err;
        }
        ALOGV("%s: Read metadata from parcel", __FUNCTION__);
        mPhysicalCameraSettings.push_back({std::string(String8(id).string()), settings});
    }

    int isReprocess = 0;
    if ((err = parcel->readInt32(&isReprocess)) != OK) {
@@ -135,10 +157,25 @@ status_t CaptureRequest::writeToParcel(android::Parcel* parcel) const {

    status_t err = OK;

    if ((err = mMetadata.writeToParcel(parcel)) != OK) {
    int32_t settingsCount = static_cast<int32_t>(mPhysicalCameraSettings.size());

    if ((err = parcel->writeInt32(settingsCount)) != OK) {
        ALOGE("%s: Failed to write settings count!", __FUNCTION__);
        return err;
    }

    for (const auto &it : mPhysicalCameraSettings) {
        if ((err = parcel->writeString16(String16(it.id.c_str()))) != OK) {
            ALOGE("%s: Failed to camera id!", __FUNCTION__);
            return err;
        }

        if ((err = it.settings.writeToParcel(parcel)) != OK) {
            ALOGE("%s: Failed to write settings!", __FUNCTION__);
            return err;
        }
    }

    parcel->writeInt32(mIsReprocess ? 1 : 0);

    if (mSurfaceConverted) {
+5 −1
Original line number Diff line number Diff line
@@ -40,7 +40,11 @@ struct CaptureRequest : public Parcelable {
    CaptureRequest(CaptureRequest&& rhs) noexcept;
    virtual ~CaptureRequest();

    CameraMetadata          mMetadata;
    struct PhysicalCameraSettings {
        std::string id;
        CameraMetadata settings;
    };
    std::vector<PhysicalCameraSettings> mPhysicalCameraSettings;

    // Used by NDK client to pass surfaces by stream/surface index.
    bool                    mSurfaceConverted = false;
+3 −2
Original line number Diff line number Diff line
@@ -372,7 +372,8 @@ CameraDevice::allocateCaptureRequest(
        const ACaptureRequest* request, /*out*/sp<CaptureRequest>& outReq) {
    camera_status_t ret;
    sp<CaptureRequest> req(new CaptureRequest());
    req->mMetadata = request->settings->getInternalData();
    req->mPhysicalCameraSettings.push_back({std::string(mCameraId.string()),
            request->settings->getInternalData()});
    req->mIsReprocess = false; // NDK does not support reprocessing yet
    req->mContext = request->context;
    req->mSurfaceConverted = true; // set to true, and fill in stream/surface idx to speed up IPC
@@ -418,7 +419,7 @@ CameraDevice::allocateCaptureRequest(
ACaptureRequest*
CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req) {
    ACaptureRequest* pRequest = new ACaptureRequest();
    CameraMetadata clone = req->mMetadata;
    CameraMetadata clone = req->mPhysicalCameraSettings.begin()->settings;
    pRequest->settings = new ACameraMetadata(clone.release(), ACameraMetadata::ACM_REQUEST);
    pRequest->targets  = new ACameraOutputTargets();
    for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
+71 −5
Original line number Diff line number Diff line
@@ -317,6 +317,9 @@ TEST(CameraServiceBinderTest, CheckBinderCameraService) {
    EXPECT_TRUE(res.isOk()) << res;

    EXPECT_EQ(numCameras, static_cast<const int>(statuses.size()));
    for (const auto &it : statuses) {
        listener->onStatusChanged(it.status, String16(it.cameraId));
    }

    for (int32_t i = 0; i < numCameras; i++) {
        String16 cameraId = String16(String8::format("%d", i));
@@ -421,6 +424,9 @@ protected:
        serviceListener = new TestCameraServiceListener();
        std::vector<hardware::CameraStatus> statuses;
        service->addListener(serviceListener, &statuses);
        for (const auto &it : statuses) {
            serviceListener->onStatusChanged(it.status, String16(it.cameraId));
        }
        service->getNumberOfCameras(hardware::ICameraService::CAMERA_TYPE_BACKWARD_COMPATIBLE,
                &numCameras);
    }
@@ -439,8 +445,9 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
    ASSERT_NOT_NULL(service);
    EXPECT_TRUE(serviceListener->waitForNumCameras(numCameras));
    for (int32_t i = 0; i < numCameras; i++) {
        String8 cameraId8 = String8::format("%d", i);
        // Make sure we're available, or skip device tests otherwise
        String16 cameraId(String8::format("%d",i));
        String16 cameraId(cameraId8);
        int32_t s = serviceListener->getStatus(cameraId);
        EXPECT_EQ(hardware::ICameraServiceListener::STATUS_PRESENT, s);
        if (s != hardware::ICameraServiceListener::STATUS_PRESENT) {
@@ -488,7 +495,7 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
        EXPECT_TRUE(res.isOk()) << res;

        hardware::camera2::CaptureRequest request;
        request.mMetadata = requestTemplate;
        request.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate});
        request.mSurfaceList.add(surface);
        request.mIsReprocess = false;
        int64_t lastFrameNumber = 0;
@@ -515,7 +522,7 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
                /*out*/&requestTemplate);
        EXPECT_TRUE(res.isOk()) << res;
        hardware::camera2::CaptureRequest request2;
        request2.mMetadata = requestTemplate;
        request2.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate});
        request2.mSurfaceList.add(surface);
        request2.mIsReprocess = false;
        callbacks->clearStatus();
@@ -548,10 +555,10 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
        EXPECT_TRUE(res.isOk()) << res;
        android::hardware::camera2::CaptureRequest request3;
        android::hardware::camera2::CaptureRequest request4;
        request3.mMetadata = requestTemplate;
        request3.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate});
        request3.mSurfaceList.add(surface);
        request3.mIsReprocess = false;
        request4.mMetadata = requestTemplate2;
        request4.mPhysicalCameraSettings.push_back({cameraId8.string(), requestTemplate2});
        request4.mSurfaceList.add(surface);
        request4.mIsReprocess = false;
        std::vector<hardware::camera2::CaptureRequest> requestList;
@@ -585,3 +592,62 @@ TEST_F(CameraClientBinderTest, CheckBinderCameraDeviceUser) {
    }

};

TEST_F(CameraClientBinderTest, CheckBinderCaptureRequest) {
    sp<CaptureRequest> requestOriginal, requestParceled;
    sp<IGraphicBufferProducer> gbProducer;
    sp<IGraphicBufferConsumer> gbConsumer;
    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
    sp<Surface> surface(new Surface(gbProducer, /*controlledByApp*/false));
    Vector<sp<Surface>> surfaceList;
    surfaceList.push_back(surface);
    std::string physicalDeviceId1 = "0";
    std::string physicalDeviceId2 = "1";
    CameraMetadata physicalDeviceSettings1, physicalDeviceSettings2;
    uint8_t intent1 = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
    uint8_t intent2 = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
    EXPECT_EQ(OK, physicalDeviceSettings1.update(ANDROID_CONTROL_CAPTURE_INTENT, &intent1, 1));
    EXPECT_EQ(OK, physicalDeviceSettings2.update(ANDROID_CONTROL_CAPTURE_INTENT, &intent2, 1));

    requestParceled = new CaptureRequest();
    Parcel p;
    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
    p.writeInt32(0);
    p.setDataPosition(0);
    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
    p.freeData();
    p.writeInt32(-1);
    p.setDataPosition(0);
    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);
    p.freeData();
    p.writeInt32(1);
    p.setDataPosition(0);
    EXPECT_TRUE(requestParceled->readFromParcel(&p) != OK);

    requestOriginal = new CaptureRequest();
    requestOriginal->mPhysicalCameraSettings.push_back({physicalDeviceId1,
            physicalDeviceSettings1});
    requestOriginal->mPhysicalCameraSettings.push_back({physicalDeviceId2,
            physicalDeviceSettings2});
    requestOriginal->mSurfaceList.push_back(surface);
    requestOriginal->mIsReprocess = false;
    requestOriginal->mSurfaceConverted = false;

    p.freeData();
    EXPECT_TRUE(requestOriginal->writeToParcel(&p) == OK);
    p.setDataPosition(0);
    EXPECT_TRUE(requestParceled->readFromParcel(&p) == OK);
    EXPECT_EQ(requestParceled->mIsReprocess, false);
    EXPECT_FALSE(requestParceled->mSurfaceList.empty());
    EXPECT_EQ(2u, requestParceled->mPhysicalCameraSettings.size());
    auto it = requestParceled->mPhysicalCameraSettings.begin();
    EXPECT_EQ(physicalDeviceId1, it->id);
    EXPECT_TRUE(it->settings.exists(ANDROID_CONTROL_CAPTURE_INTENT));
    auto entry = it->settings.find(ANDROID_CONTROL_CAPTURE_INTENT);
    EXPECT_EQ(entry.data.u8[0], intent1);
    it++;
    EXPECT_EQ(physicalDeviceId2, it->id);
    EXPECT_TRUE(it->settings.exists(ANDROID_CONTROL_CAPTURE_INTENT));
    entry = it->settings.find(ANDROID_CONTROL_CAPTURE_INTENT);
    EXPECT_EQ(entry.data.u8[0], intent2);
};
+1 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ TEST(VendorTagDescriptorTest, ConsistentAcrossParcel) {
    EXPECT_EQ(OK, vDescOriginal->writeToParcel(&p));
    p.setDataPosition(0);

    vDescParceled = new VendorTagDescriptor();
    ASSERT_EQ(OK, vDescParceled->readFromParcel(&p));

    // Ensure consistent tag count
Loading