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

Commit c2ad9c85 authored by Cliff Wu's avatar Cliff Wu
Browse files

DynamicCamera: Injection camera switching mechanism in Camera3Device

- When injectCamera() is called, it will first initialize the injection and generate the hal interface, wait until the internal camera creates output streams and configure it, and then continues to replace internal camera and configure the injection stream.
- When stopInjection is called or Device3Camera is disconnected, will close injection and delete the hal interface.

Bug: 181735245
Test: Manual
Change-Id: Ib7209c25e3d2cb9b8d717941660590e68c9435ef
parent 6dbb5fe9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ cc_library_shared {
        "device3/RotateAndCropMapper.cpp",
        "device3/Camera3OutputStreamInterface.cpp",
        "device3/Camera3OutputUtils.cpp",
        "device3/Camera3DeviceInjectionMethods.cpp",
        "gui/RingBufferConsumer.cpp",
        "hidl/AidlCameraDeviceCallbacks.cpp",
        "hidl/AidlCameraServiceListener.cpp",
+226 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include <utils/Timers.h>
#include <cutils/properties.h>

#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>

#include "utils/CameraTraces.h"
@@ -358,6 +359,8 @@ status_t Camera3Device::initializeCommonLocked() {
        }
    }

    mInjectionMethods = new Camera3DeviceInjectionMethods(this);

    return OK;
}

@@ -431,6 +434,10 @@ status_t Camera3Device::disconnectImpl() {
            mStatusTracker->join();
        }

        if (mInjectionMethods->isInjecting()) {
            mInjectionMethods->stopInjection();
        }

        HalInterface* interface;
        {
            Mutex::Autolock l(mLock);
@@ -1829,7 +1836,6 @@ status_t Camera3Device::waitUntilDrainedLocked(nsecs_t maxExpectedDuration) {
    return res;
}


void Camera3Device::internalUpdateStatusLocked(Status status) {
    mStatus = status;
    mRecentStatusUpdates.add(mStatus);
@@ -2820,6 +2826,19 @@ status_t Camera3Device::configureStreamsLocked(int operatingMode,
        mRequestBufferSM.onStreamsConfigured();
    }

    // Since the streams configuration of the injection camera is based on the internal camera, we
    // must wait until the internal camera configure streams before calling injectCamera() to
    // configure the injection streams.
    if (mInjectionMethods->isInjecting()) {
        ALOGV("%s: Injection camera %s: Start to configure streams.",
              __FUNCTION__, mInjectionMethods->getInjectedCamId().string());
        res = mInjectionMethods->injectCamera(config, bufferSizes);
        if (res != OK) {
            ALOGE("Can't finish inject camera process!");
            return res;
        }
    }

    return OK;
}

@@ -3524,6 +3543,146 @@ status_t Camera3Device::HalInterface::configureStreams(const camera_metadata_t *
    return res;
}

status_t Camera3Device::HalInterface::configureInjectedStreams(
        const camera_metadata_t* sessionParams, camera_stream_configuration* config,
        const std::vector<uint32_t>& bufferSizes,
        const CameraMetadata& cameraCharacteristics) {
    ATRACE_NAME("InjectionCameraHal::configureStreams");
    if (!valid()) return INVALID_OPERATION;
    status_t res = OK;

    if (config->input_is_multi_resolution) {
        ALOGE("%s: Injection camera device doesn't support multi-resolution input "
                "stream", __FUNCTION__);
        return BAD_VALUE;
    }

    // Convert stream config to HIDL
    std::set<int> activeStreams;
    device::V3_2::StreamConfiguration requestedConfiguration3_2;
    device::V3_4::StreamConfiguration requestedConfiguration3_4;
    device::V3_7::StreamConfiguration requestedConfiguration3_7;
    requestedConfiguration3_2.streams.resize(config->num_streams);
    requestedConfiguration3_4.streams.resize(config->num_streams);
    requestedConfiguration3_7.streams.resize(config->num_streams);
    for (size_t i = 0; i < config->num_streams; i++) {
        device::V3_2::Stream& dst3_2 = requestedConfiguration3_2.streams[i];
        device::V3_4::Stream& dst3_4 = requestedConfiguration3_4.streams[i];
        device::V3_7::Stream& dst3_7 = requestedConfiguration3_7.streams[i];
        camera3::camera_stream_t* src = config->streams[i];

        Camera3Stream* cam3stream = Camera3Stream::cast(src);
        cam3stream->setBufferFreedListener(this);
        int streamId = cam3stream->getId();
        StreamType streamType;
        switch (src->stream_type) {
            case CAMERA_STREAM_OUTPUT:
                streamType = StreamType::OUTPUT;
                break;
            case CAMERA_STREAM_INPUT:
                streamType = StreamType::INPUT;
                break;
            default:
                ALOGE("%s: Stream %d: Unsupported stream type %d", __FUNCTION__,
                        streamId, config->streams[i]->stream_type);
            return BAD_VALUE;
        }
        dst3_2.id = streamId;
        dst3_2.streamType = streamType;
        dst3_2.width = src->width;
        dst3_2.height = src->height;
        dst3_2.usage = mapToConsumerUsage(cam3stream->getUsage());
        dst3_2.rotation =
                mapToStreamRotation((camera_stream_rotation_t)src->rotation);
        // For HidlSession version 3.5 or newer, the format and dataSpace sent
        // to HAL are original, not the overridden ones.
        if (mHidlSession_3_5 != nullptr) {
            dst3_2.format = mapToPixelFormat(cam3stream->isFormatOverridden()
                                            ? cam3stream->getOriginalFormat()
                                            : src->format);
            dst3_2.dataSpace =
                    mapToHidlDataspace(cam3stream->isDataSpaceOverridden()
                                    ? cam3stream->getOriginalDataSpace()
                                    : src->data_space);
        } else {
            dst3_2.format = mapToPixelFormat(src->format);
            dst3_2.dataSpace = mapToHidlDataspace(src->data_space);
        }
        dst3_4.v3_2 = dst3_2;
        dst3_4.bufferSize = bufferSizes[i];
        if (src->physical_camera_id != nullptr) {
            dst3_4.physicalCameraId = src->physical_camera_id;
        }
        dst3_7.v3_4 = dst3_4;
        dst3_7.groupId = cam3stream->getHalStreamGroupId();
        dst3_7.sensorPixelModesUsed.resize(src->sensor_pixel_modes_used.size());
        size_t j = 0;
        for (int mode : src->sensor_pixel_modes_used) {
            dst3_7.sensorPixelModesUsed[j++] =
                    static_cast<CameraMetadataEnumAndroidSensorPixelMode>(mode);
        }
        activeStreams.insert(streamId);
        // Create Buffer ID map if necessary
        mBufferRecords.tryCreateBufferCache(streamId);
    }
    // remove BufferIdMap for deleted streams
    mBufferRecords.removeInactiveBufferCaches(activeStreams);

    StreamConfigurationMode operationMode;
    res = mapToStreamConfigurationMode(
            (camera_stream_configuration_mode_t)config->operation_mode,
            /*out*/ &operationMode);
    if (res != OK) {
        return res;
    }
    requestedConfiguration3_7.operationMode = operationMode;
    size_t sessionParamSize = get_camera_metadata_size(sessionParams);
    requestedConfiguration3_7.operationMode = operationMode;
    requestedConfiguration3_7.sessionParams.setToExternal(
            reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(sessionParams)),
            sessionParamSize);

    // See which version of HAL we have
    if (mHidlSession_3_7 != nullptr) {
        requestedConfiguration3_7.streamConfigCounter = mNextStreamConfigCounter++;
        requestedConfiguration3_7.multiResolutionInputImage =
                config->input_is_multi_resolution;

        const camera_metadata_t* rawMetadata = cameraCharacteristics.getAndLock();
        ::android::hardware::camera::device::V3_2::CameraMetadata hidlChars = {};
        hidlChars.setToExternal(
                reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(rawMetadata)),
                get_camera_metadata_size(rawMetadata));
        cameraCharacteristics.unlock(rawMetadata);

        sp<hardware::camera::device::V3_7::ICameraInjectionSession>
                hidlInjectionSession_3_7;
        auto castInjectionResult_3_7 =
                device::V3_7::ICameraInjectionSession::castFrom(mHidlSession_3_7);
        if (castInjectionResult_3_7.isOk()) {
            hidlInjectionSession_3_7 = castInjectionResult_3_7;
        } else {
            ALOGE("%s: Transaction error: %s", __FUNCTION__,
                    castInjectionResult_3_7.description().c_str());
            return DEAD_OBJECT;
        }

        auto err = hidlInjectionSession_3_7->configureInjectionStreams(
                requestedConfiguration3_7, hidlChars);
        if (!err.isOk()) {
            ALOGE("%s: Transaction error: %s", __FUNCTION__,
                    err.description().c_str());
            return DEAD_OBJECT;
        }
    } else {
        ALOGE("%s: mHidlSession_3_7 does not exist, the lowest version of injection "
                "session is 3.7", __FUNCTION__);
        return DEAD_OBJECT;
    }

    return res;
}

status_t Camera3Device::HalInterface::wrapAsHidlRequest(camera_capture_request_t* request,
        /*out*/device::V3_2::CaptureRequest* captureRequest,
        /*out*/std::vector<native_handle_t*>* handlesCreated,
@@ -5724,6 +5883,18 @@ bool Camera3Device::RequestThread::overrideTestPattern(
    return changed;
}

status_t Camera3Device::RequestThread::setHalInterface(
        sp<HalInterface> newHalInterface) {
    if (newHalInterface.get() == nullptr) {
        ALOGE("%s: The newHalInterface does not exist!", __FUNCTION__);
        return DEAD_OBJECT;
    }

    mInterface = newHalInterface;

    return OK;
}

/**
 * PreparerThread inner class methods
 */
@@ -6367,4 +6538,58 @@ status_t Camera3Device::setCameraMute(bool enabled) {
    return mRequestThread->setCameraMute(enabled);
}

status_t Camera3Device::injectCamera(const String8& injectedCamId,
                                     sp<CameraProviderManager> manager) {
    ALOGI("%s Injection camera: injectedCamId = %s", __FUNCTION__, injectedCamId.string());
    ATRACE_CALL();
    Mutex::Autolock il(mInterfaceLock);

    status_t res = NO_ERROR;
    if (mInjectionMethods->isInjecting()) {
        if (injectedCamId == mInjectionMethods->getInjectedCamId()) {
            return OK;
        } else {
            res = mInjectionMethods->stopInjection();
            if (res != OK) {
                ALOGE("%s: Failed to stop the injection camera! ret != NO_ERROR: %d",
                        __FUNCTION__, res);
                return res;
            }
        }
    }

    res = mInjectionMethods->injectionInitialize(injectedCamId, manager, this);
    if (res != OK) {
        ALOGE("%s: Failed to initialize the injection camera! ret != NO_ERROR: %d",
                __FUNCTION__, res);
        return res;
    }

    camera3::camera_stream_configuration injectionConfig;
    std::vector<uint32_t> injectionBufferSizes;
    mInjectionMethods->getInjectionConfig(&injectionConfig, &injectionBufferSizes);
    // When the second display of android is cast to the remote device, and the opened camera is
    // also cast to the second display, in this case, because the camera has configured the streams
    // at this time, we can directly call injectCamera() to replace the internal camera with
    // injection camera.
    if (mOperatingMode >= 0 && injectionConfig.num_streams > 0
                && injectionBufferSizes.size() > 0) {
        ALOGV("%s: The opened camera is directly cast to the remote device.", __FUNCTION__);
        res = mInjectionMethods->injectCamera(
                injectionConfig, injectionBufferSizes);
        if (res != OK) {
            ALOGE("Can't finish inject camera process!");
            return res;
        }
    }

    return OK;
}

status_t Camera3Device::stopInjection() {
    ALOGI("%s: Injection camera: stopInjection", __FUNCTION__);
    Mutex::Autolock il(mInterfaceLock);
    return mInjectionMethods->stopInjection();
}

}; // namespace android
+91 −0
Original line number Diff line number Diff line
@@ -262,6 +262,18 @@ class Camera3Device :
    // Get the status trackeer for the camera device
    wp<camera3::StatusTracker> getStatusTracker() { return mStatusTracker; }

    /**
     * The injection camera session to replace the internal camera
     * session.
     */
    status_t injectCamera(const String8& injectedCamId,
                          sp<CameraProviderManager> manager);

    /**
     * Stop the injection camera and restore to internal camera session.
     */
    status_t stopInjection();

    /**
     * Helper functions to map between framework and HIDL values
     */
@@ -363,6 +375,13 @@ class Camera3Device :
                /*inout*/ camera_stream_configuration_t *config,
                const std::vector<uint32_t>& bufferSizes);

        // The injection camera configures the streams to hal.
        status_t configureInjectedStreams(
                const camera_metadata_t* sessionParams,
                /*inout*/ camera_stream_configuration_t* config,
                const std::vector<uint32_t>& bufferSizes,
                const CameraMetadata& cameraCharacteristics);

        // When the call succeeds, the ownership of acquire fences in requests is transferred to
        // HalInterface. More specifically, the current implementation will send the fence to
        // HAL process and close the FD in cameraserver process. When the call fails, the ownership
@@ -900,6 +919,9 @@ class Camera3Device :
                camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue);

        status_t setCameraMute(bool enabled);

        status_t setHalInterface(sp<HalInterface> newHalInterface);

      protected:

        virtual bool threadLoop();
@@ -1321,6 +1343,75 @@ class Camera3Device :
    // Whether the HAL supports camera muting via test pattern
    bool mSupportCameraMute = false;

    // Injection camera related methods.
    class Camera3DeviceInjectionMethods : public virtual RefBase {
      public:
        Camera3DeviceInjectionMethods(wp<Camera3Device> parent);

        ~Camera3DeviceInjectionMethods();

        // Initialize the injection camera and generate an hal interface.
        status_t injectionInitialize(
                const String8& injectedCamId, sp<CameraProviderManager> manager,
                const sp<
                    android::hardware::camera::device::V3_2 ::ICameraDeviceCallback>&
                    callback);

        // Injection camera will replace the internal camera and configure streams
        // when device is IDLE and request thread is paused.
        status_t injectCamera(
                camera3::camera_stream_configuration& injectionConfig,
                std::vector<uint32_t>& injectionBufferSizes);

        // Stop the injection camera and switch back to backup hal interface.
        status_t stopInjection();

        bool isInjecting();

        const String8& getInjectedCamId() const;

        void getInjectionConfig(/*out*/ camera3::camera_stream_configuration* injectionConfig,
                /*out*/ std::vector<uint32_t>* injectionBufferSizes);

      private:
        // Configure the streams of injection camera, it need wait until the
        // output streams are created and configured to the original camera before
        // proceeding.
        status_t injectionConfigureStreams(
                camera3::camera_stream_configuration& injectionConfig,
                std::vector<uint32_t>& injectionBufferSizes);

        // Disconnect the injection camera and delete the hal interface.
        void injectionDisconnectImpl();

        // Use injection camera hal interface to replace and backup original
        // camera hal interface.
        status_t replaceHalInterface(sp<HalInterface> newHalInterface,
                bool keepBackup);

        wp<Camera3Device> mParent;

        // Backup of the original camera hal interface.
        sp<HalInterface> mBackupHalInterface;

        // Generated injection camera hal interface.
        sp<HalInterface> mInjectedCamHalInterface;

        // Copy the configuration of the internal camera.
        camera3::camera_stream_configuration mInjectionConfig;

        // Copy the bufferSizes of the output streams of the internal camera.
        std::vector<uint32_t> mInjectionBufferSizes;

        // Synchronizes access to injection camera between initialize and
        // disconnect.
        Mutex mInjectionLock;

        // The injection camera ID.
        String8 mInjectedCamId;
    };
    sp<Camera3DeviceInjectionMethods> mInjectionMethods;

}; // class Camera3Device

}; // namespace android
+393 −0

File added.

Preview size limit exceeded, changes collapsed.