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

Commit d2958597 authored by Zhijun He's avatar Zhijun He Committed by Android (Google) Code Review
Browse files

Merge "Camera3: add deferred surface support" into nyc-mr1-dev

parents f217613a 5d677d1f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -121,4 +121,6 @@ interface ICameraDeviceUser
    void tearDown(int streamId);

    void prepare2(int maxCount, int streamId);

    void setDeferredConfiguration(int streamId, in OutputConfiguration outputConfiguration);
}
+59 −5
Original line number Diff line number Diff line
@@ -42,9 +42,24 @@ int OutputConfiguration::getSurfaceSetID() const {
    return mSurfaceSetID;
}

int OutputConfiguration::getSurfaceType() const {
    return mSurfaceType;
}

int OutputConfiguration::getWidth() const {
    return mWidth;
}

int OutputConfiguration::getHeight() const {
    return mHeight;
}

OutputConfiguration::OutputConfiguration() :
        mRotation(INVALID_ROTATION),
        mSurfaceSetID(INVALID_SET_ID) {
        mSurfaceSetID(INVALID_SET_ID),
        mSurfaceType(SURFACE_TYPE_UNKNOWN),
        mWidth(0),
        mHeight(0) {
}

OutputConfiguration::OutputConfiguration(const Parcel& parcel) :
@@ -70,18 +85,48 @@ status_t OutputConfiguration::readFromParcel(const Parcel* parcel) {
        return err;
    }

    int surfaceType = SURFACE_TYPE_UNKNOWN;
    if ((err = parcel->readInt32(&surfaceType)) != OK) {
        ALOGE("%s: Failed to read surface type from parcel", __FUNCTION__);
        return err;
    }

    int width = 0;
    if ((err = parcel->readInt32(&width)) != OK) {
        ALOGE("%s: Failed to read surface width from parcel", __FUNCTION__);
        return err;
    }

    int height = 0;
    if ((err = parcel->readInt32(&height)) != OK) {
        ALOGE("%s: Failed to read surface height from parcel", __FUNCTION__);
        return err;
    }

    view::Surface surfaceShim;
    if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
        // Read surface failure for deferred surface configuration is expected.
        if (surfaceType == SURFACE_TYPE_SURFACE_VIEW ||
                surfaceType == SURFACE_TYPE_SURFACE_TEXTURE) {
            ALOGV("%s: Get null surface from a deferred surface configuration (%dx%d)",
                    __FUNCTION__, width, height);
            err = OK;
        } else {
            ALOGE("%s: Failed to read surface from parcel", __FUNCTION__);
            return err;
        }
    }

    mGbp = surfaceShim.graphicBufferProducer;
    mRotation = rotation;
    mSurfaceSetID = setID;
    mSurfaceType = surfaceType;
    mWidth = width;
    mHeight = height;

    ALOGV("%s: OutputConfiguration: bp = %p, name = %s, rotation = %d, setId = %d", __FUNCTION__,
            mGbp.get(), String8(surfaceShim.name).string(), mRotation, mSurfaceSetID);
    ALOGV("%s: OutputConfiguration: bp = %p, name = %s, rotation = %d, setId = %d,"
            "surfaceType = %d", __FUNCTION__, mGbp.get(), String8(surfaceShim.name).string(),
            mRotation, mSurfaceSetID, mSurfaceType);

    return err;
}
@@ -104,6 +149,15 @@ status_t OutputConfiguration::writeToParcel(Parcel* parcel) const {
    err = parcel->writeInt32(mSurfaceSetID);
    if (err != OK) return err;

    err = parcel->writeInt32(mSurfaceType);
    if (err != OK) return err;

    err = parcel->writeInt32(mWidth);
    if (err != OK) return err;

    err = parcel->writeInt32(mHeight);
    if (err != OK) return err;

    view::Surface surfaceShim;
    surfaceShim.name = String16("unknown_name"); // name of surface
    surfaceShim.graphicBufferProducer = mGbp;
+25 −2
Original line number Diff line number Diff line
@@ -33,10 +33,17 @@ public:

    static const int INVALID_ROTATION;
    static const int INVALID_SET_ID;
    enum SurfaceType{
        SURFACE_TYPE_UNKNOWN = -1,
        SURFACE_TYPE_SURFACE_VIEW = 0,
        SURFACE_TYPE_SURFACE_TEXTURE = 1
    };
    sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
    int                        getRotation() const;
    int                        getSurfaceSetID() const;

    int                        getSurfaceType() const;
    int                        getWidth() const;
    int                        getHeight() const;
    /**
     * Keep impl up-to-date with OutputConfiguration.java in frameworks/base
     */
@@ -60,7 +67,10 @@ public:
    bool operator == (const OutputConfiguration& other) const {
        return (mGbp == other.mGbp &&
                mRotation == other.mRotation &&
                mSurfaceSetID == other.mSurfaceSetID);
                mSurfaceSetID == other.mSurfaceSetID &&
                mSurfaceType == other.mSurfaceType &&
                mWidth == other.mWidth &&
                mHeight == other.mHeight);
    }
    bool operator != (const OutputConfiguration& other) const {
        return !(*this == other);
@@ -71,6 +81,16 @@ public:
        if (mSurfaceSetID != other.mSurfaceSetID) {
            return mSurfaceSetID < other.mSurfaceSetID;
        }
        if (mSurfaceType != other.mSurfaceType) {
            return mSurfaceType < other.mSurfaceType;
        }
        if (mWidth != other.mWidth) {
            return mWidth < other.mWidth;
        }
        if (mHeight != other.mHeight) {
            return mHeight < other.mHeight;
        }

        return mRotation < other.mRotation;
    }
    bool operator > (const OutputConfiguration& other) const {
@@ -81,6 +101,9 @@ private:
    sp<IGraphicBufferProducer> mGbp;
    int                        mRotation;
    int                        mSurfaceSetID;
    int                        mSurfaceType;
    int                        mWidth;
    int                        mHeight;
    // helper function
    static String16 readMaybeEmptyString16(const Parcel* parcel);
};
+200 −40
Original line number Diff line number Diff line
@@ -338,13 +338,15 @@ binder::Status CameraDeviceClient::endConfigure(bool isConstrainedHighSpeed) {

    status_t err = mDevice->configureStreams(isConstrainedHighSpeed);
    if (err == BAD_VALUE) {
        res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
                "Camera %d: Unsupported set of inputs/outputs provided",
        String8 msg = String8::format("Camera %d: Unsupported set of inputs/outputs provided",
                mCameraId);
        ALOGE("%s: %s", __FUNCTION__, msg.string());
        res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
    } else if (err != OK) {
        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
                "Camera %d: Error configuring streams: %s (%d)",
        String8 msg = String8::format("Camera %d: Error configuring streams: %s (%d)",
                mCameraId, strerror(-err), err);
        ALOGE("%s: %s", __FUNCTION__, msg.string());
        res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
    }

    return res;
@@ -365,6 +367,7 @@ binder::Status CameraDeviceClient::deleteStream(int streamId) {

    bool isInput = false;
    ssize_t index = NAME_NOT_FOUND;
    ssize_t dIndex = NAME_NOT_FOUND;

    if (mInputStream.configured && mInputStream.id == streamId) {
        isInput = true;
@@ -378,12 +381,21 @@ binder::Status CameraDeviceClient::deleteStream(int streamId) {
        }

        if (index == NAME_NOT_FOUND) {
            // See if this stream is one of the deferred streams.
            for (size_t i = 0; i < mDeferredStreams.size(); ++i) {
                if (streamId == mDeferredStreams[i]) {
                    dIndex = i;
                    break;
                }
            }
            if (dIndex == NAME_NOT_FOUND) {
                String8 msg = String8::format("Camera %d: Invalid stream ID (%d) specified, no such"
                        " stream created yet", mCameraId, streamId);
                ALOGW("%s: %s", __FUNCTION__, msg.string());
                return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
            }
        }
    }

    // Also returns BAD_VALUE if stream ID was not valid
    status_t err = mDevice->deleteStream(streamId);
@@ -396,8 +408,10 @@ binder::Status CameraDeviceClient::deleteStream(int streamId) {
    } else {
        if (isInput) {
            mInputStream.configured = false;
        } else {
        } else if (index != NAME_NOT_FOUND) {
            mStreamMap.removeItemsAt(index);
        } else {
            mDeferredStreams.removeItemsAt(dIndex);
        }
    }

@@ -416,14 +430,30 @@ binder::Status CameraDeviceClient::createStream(
    Mutex::Autolock icl(mBinderSerializationLock);

    sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer();
    if (bufferProducer == NULL) {
        ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
    bool deferredConsumer = bufferProducer == NULL;
    int surfaceType = outputConfiguration.getSurfaceType();
    bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
            (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
    if (deferredConsumer && !validSurfaceType) {
        ALOGE("%s: Target surface is invalid: bufferProducer = %p, surfaceType = %d.",
                __FUNCTION__, bufferProducer.get(), surfaceType);
        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
    }

    if (!mDevice.get()) {
        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
    }

    int width, height, format;
    int32_t consumerUsage;
    android_dataspace dataSpace;
    status_t err;

    // Create stream for deferred surface case.
    if (deferredConsumer) {
        return createDeferredSurfaceStreamLocked(outputConfiguration, newStreamId);
    }

    // Don't create multiple streams for the same target surface
    {
        ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -435,13 +465,10 @@ binder::Status CameraDeviceClient::createStream(
        }
    }

    status_t err;

    // HACK b/10949105
    // Query consumer usage bits to set async operation mode for
    // GLConsumer using controlledByApp parameter.
    bool useAsync = false;
    int32_t consumerUsage;
    if ((err = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
            &consumerUsage)) != OK) {
        String8 msg = String8::format("Camera %d: Failed to query Surface consumer usage: %s (%d)",
@@ -450,8 +477,8 @@ binder::Status CameraDeviceClient::createStream(
        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
    }
    if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
        ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
                __FUNCTION__, mCameraId);
        ALOGW("%s: Camera %d with consumer usage flag: 0x%x: Forcing asynchronous mode for stream",
                __FUNCTION__, mCameraId, consumerUsage);
        useAsync = true;
    }

@@ -467,9 +494,6 @@ binder::Status CameraDeviceClient::createStream(
    sp<Surface> surface = new Surface(bufferProducer, useAsync);
    ANativeWindow *anw = surface.get();

    int width, height, format;
    android_dataspace dataSpace;

    if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
        String8 msg = String8::format("Camera %d: Failed to query Surface width: %s (%d)",
                mCameraId, strerror(-err), err);
@@ -526,16 +550,81 @@ binder::Status CameraDeviceClient::createStream(
    } else {
        mStreamMap.add(binder, streamId);

        ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
              __FUNCTION__, mCameraId, streamId);
        ALOGV("%s: Camera %d: Successfully created a new stream ID %d for output surface"
                " (%d x %d) with format 0x%x.",
              __FUNCTION__, mCameraId, streamId, width, height, format);

        /**
         * Set the stream transform flags to automatically
         * rotate the camera stream for preview use cases.
         */
        // Set transform flags to ensure preview to be rotated correctly.
        res = setStreamTransformLocked(streamId);

        *newStreamId = streamId;
    }

    return res;
}

binder::Status CameraDeviceClient::createDeferredSurfaceStreamLocked(
        const hardware::camera2::params::OutputConfiguration &outputConfiguration,
        /*out*/
        int* newStreamId) {
    int width, height, format, surfaceType;
    int32_t consumerUsage;
    android_dataspace dataSpace;
    status_t err;
    binder::Status res;

    if (!mDevice.get()) {
        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
    }

    // Infer the surface info for deferred surface stream creation.
    width = outputConfiguration.getWidth();
    height = outputConfiguration.getHeight();
    surfaceType = outputConfiguration.getSurfaceType();
    format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
    dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
    // Hardcode consumer usage flags: SurfaceView--0x900, SurfaceTexture--0x100.
    consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
    if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
        consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
    }
    int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
    err = mDevice->createStream(/*surface*/nullptr, width, height, format, dataSpace,
            static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
            &streamId, outputConfiguration.getSurfaceSetID(), consumerUsage);

    if (err != OK) {
        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
                "Camera %d: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
                mCameraId, width, height, format, dataSpace, strerror(-err), err);
    } else {
        // Can not add streamId to mStreamMap here, as the surface is deferred. Add it to
        // a separate list to track. Once the deferred surface is set, this id will be
        // relocated to mStreamMap.
        mDeferredStreams.push_back(streamId);

        ALOGV("%s: Camera %d: Successfully created a new stream ID %d for a deferred surface"
                " (%d x %d) stream with format 0x%x.",
              __FUNCTION__, mCameraId, streamId, width, height, format);

        // Set transform flags to ensure preview to be rotated correctly.
        res = setStreamTransformLocked(streamId);

        *newStreamId = streamId;
    }
    return res;
}

binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId) {
    int32_t transform = 0;
        err = getRotationTransformLocked(&transform);
    status_t err;
    binder::Status res;

    if (!mDevice.get()) {
        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
    }

    err = getRotationTransformLocked(&transform);
    if (err != OK) {
        // Error logged by getRotationTransformLocked.
        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
@@ -550,13 +639,9 @@ binder::Status CameraDeviceClient::createStream(
        return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
    }

        *newStreamId = streamId;
    }

    return res;
}


binder::Status CameraDeviceClient::createInputStream(
        int width, int height, int format,
        /*out*/
@@ -934,6 +1019,76 @@ binder::Status CameraDeviceClient::tearDown(int streamId) {
    return res;
}

binder::Status CameraDeviceClient::setDeferredConfiguration(int32_t streamId,
        const hardware::camera2::params::OutputConfiguration &outputConfiguration) {
    ATRACE_CALL();

    binder::Status res;
    if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;

    Mutex::Autolock icl(mBinderSerializationLock);

    sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer();

    // Client code should guarantee that the surface is from SurfaceView or SurfaceTexture.
    if (bufferProducer == NULL) {
        ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
    }
    // Check if this stram id is one of the deferred streams
    ssize_t index = NAME_NOT_FOUND;
    for (size_t i = 0; i < mDeferredStreams.size(); i++) {
        if (streamId == mDeferredStreams[i]) {
            index = i;
            break;
        }
    }
    if (index == NAME_NOT_FOUND) {
        String8 msg = String8::format("Camera %d: deferred surface is set to a unknown stream"
                "(ID %d)", mCameraId, streamId);
        ALOGW("%s: %s", __FUNCTION__, msg.string());
        return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
    }

    if (!mDevice.get()) {
        return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
    }

    // Don't create multiple streams for the same target surface
    {
        ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
        if (index != NAME_NOT_FOUND) {
            String8 msg = String8::format("Camera %d: Surface already has a stream created "
                    " for it (ID %zd)", mCameraId, index);
            ALOGW("%s: %s", __FUNCTION__, msg.string());
            return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
        }
    }

    status_t err;

    // Always set to async, as we know the deferred surface is for preview streaming.
    sp<Surface> consumerSurface = new Surface(bufferProducer, /*useAsync*/true);

    // Finish the deferred stream configuration with the surface.
    err = mDevice->setConsumerSurface(streamId, consumerSurface);
    if (err == OK) {
        sp<IBinder> binder = IInterface::asBinder(bufferProducer);
        mStreamMap.add(binder, streamId);
        mDeferredStreams.removeItemsAt(index);
    } else if (err == NO_INIT) {
        res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
                "Camera %d: Deferred surface is invalid: %s (%d)",
                mCameraId, strerror(-err), err);
    } else {
        res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
                "Camera %d: Error setting output stream deferred surface: %s (%d)",
                mCameraId, strerror(-err), err);
    }

    return res;
}

status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
    return BasicClient::dump(fd, args);
}
@@ -959,6 +1114,11 @@ status_t CameraDeviceClient::dumpClient(int fd, const Vector<String16>& args) {
        for (size_t i = 0; i < mStreamMap.size(); i++) {
            result.appendFormat("      Stream %d\n", mStreamMap.valueAt(i));
        }
    } else if (!mDeferredStreams.isEmpty()) {
        result.append("    Current deferred surface output stream IDs:\n");
        for (auto& streamId : mDeferredStreams) {
            result.appendFormat("      Stream %d\n", streamId);
        }
    } else {
        result.append("    No output streams configured.\n");
    }
+17 −0
Original line number Diff line number Diff line
@@ -131,6 +131,10 @@ public:
    // Prepare stream by preallocating up to maxCount of its buffers
    virtual binder::Status prepare2(int32_t maxCount, int32_t streamId);

    // Set the deferred surface for a stream.
    virtual binder::Status setDeferredConfiguration(int32_t streamId,
            const hardware::camera2::params::OutputConfiguration &outputConfiguration);

    /**
     * Interface used by CameraService
     */
@@ -188,6 +192,15 @@ private:
    // Find the square of the euclidean distance between two points
    static int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1);

    // Create an output stream with surface deferred for future.
    binder::Status createDeferredSurfaceStreamLocked(
            const hardware::camera2::params::OutputConfiguration &outputConfiguration,
            int* newStreamId = NULL);

    // Set the stream transform flags to automatically rotate the camera stream for preview use
    // cases.
    binder::Status setStreamTransformLocked(int streamId);

    // Find the closest dimensions for a given format in available stream configurations with
    // a width <= ROUNDING_WIDTH_CAP
    static const int32_t ROUNDING_WIDTH_CAP = 1920;
@@ -213,6 +226,10 @@ private:

    int32_t mRequestIdCounter;

    // The list of output streams whose surfaces are deferred. We have to track them separately
    // as there are no surfaces available and can not be put into mStreamMap. Once the deferred
    // Surface is configured, the stream id will be moved to mStreamMap.
    Vector<int32_t> mDeferredStreams;
};

}; // namespace android
Loading